1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include "matroxfb_maven.h"
16#include "matroxfb_misc.h"
17#include "matroxfb_DAC1064.h"
18#include <linux/i2c.h>
19#include <linux/matroxfb.h>
20#include <asm/div64.h>
21#include <asm/uaccess.h>
22
23#define MAVEN_I2CID (0x1B)
24
25#define MGATVO_B 1
26#define MGATVO_C 2
27
28static const struct maven_gamma {
29 unsigned char reg83;
30 unsigned char reg84;
31 unsigned char reg85;
32 unsigned char reg86;
33 unsigned char reg87;
34 unsigned char reg88;
35 unsigned char reg89;
36 unsigned char reg8a;
37 unsigned char reg8b;
38} maven_gamma[] = {
39 { 131, 57, 223, 15, 117, 212, 251, 91, 156},
40 { 133, 61, 128, 63, 180, 147, 195, 100, 180},
41 { 131, 19, 63, 31, 50, 66, 171, 64, 176},
42 { 0, 0, 0, 31, 16, 16, 16, 100, 200},
43 { 8, 23, 47, 73, 147, 244, 220, 80, 195},
44 { 22, 43, 64, 80, 147, 115, 58, 85, 168},
45 { 34, 60, 80, 214, 147, 212, 188, 85, 167},
46 { 45, 77, 96, 216, 147, 99, 91, 85, 159},
47 { 56, 76, 112, 107, 147, 212, 148, 64, 144},
48 { 65, 91, 128, 137, 147, 196, 17, 69, 148},
49 { 72, 104, 136, 138, 147, 180, 245, 73, 147},
50 { 87, 116, 143, 126, 16, 83, 229, 77, 144},
51 { 95, 119, 152, 254, 244, 83, 221, 77, 151},
52 { 100, 129, 159, 156, 244, 148, 197, 77, 160},
53 { 105, 141, 167, 247, 244, 132, 181, 84, 166},
54 { 105, 147, 168, 247, 244, 245, 181, 90, 170},
55 { 120, 153, 175, 248, 212, 229, 165, 90, 180},
56 { 119, 156, 176, 248, 244, 229, 84, 74, 160},
57 { 119, 158, 183, 248, 244, 229, 149, 78, 165}
58};
59
60
61struct mctl {
62 struct v4l2_queryctrl desc;
63 size_t control;
64};
65
66#define BLMIN 0x0FF
67#define WLMAX 0x3FF
68
69static const struct mctl maven_controls[] =
70{ { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
71 "brightness",
72 0, WLMAX - BLMIN, 1, 379 - BLMIN,
73 0,
74 }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
75 { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
76 "contrast",
77 0, 1023, 1, 127,
78 0,
79 }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
80 { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
81 "saturation",
82 0, 255, 1, 155,
83 0,
84 }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
85 { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
86 "hue",
87 0, 255, 1, 0,
88 0,
89 }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
90 { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER,
91 "gamma",
92 0, ARRAY_SIZE(maven_gamma) - 1, 1, 3,
93 0,
94 }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
95 { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
96 "test output",
97 0, 1, 1, 0,
98 0,
99 }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
100 { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER,
101 "deflicker mode",
102 0, 2, 1, 0,
103 0,
104 }, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) },
105
106};
107
108#define MAVCTRLS ARRAY_SIZE(maven_controls)
109
110
111
112
113static int get_ctrl_id(__u32 v4l2_id) {
114 int i;
115
116 for (i = 0; i < MAVCTRLS; i++) {
117 if (v4l2_id < maven_controls[i].desc.id) {
118 if (maven_controls[i].desc.id == 0x08000000) {
119 return -EINVAL;
120 }
121 return -ENOENT;
122 }
123 if (v4l2_id == maven_controls[i].desc.id) {
124 return i;
125 }
126 }
127 return -EINVAL;
128}
129
130struct maven_data {
131 struct matrox_fb_info* primary_head;
132 struct i2c_client client;
133 int version;
134};
135
136static int* get_ctrl_ptr(struct maven_data* md, int idx) {
137 return (int*)((char*)(md->primary_head) + maven_controls[idx].control);
138}
139
140static int maven_get_reg(struct i2c_client* c, char reg) {
141 char dst;
142 struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), ® },
143 { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }};
144 s32 err;
145
146 err = i2c_transfer(c->adapter, msgs, 2);
147 if (err < 0)
148 printk(KERN_INFO "ReadReg(%d) failed\n", reg);
149 return dst & 0xFF;
150}
151
152static int maven_set_reg(struct i2c_client* c, int reg, int val) {
153 s32 err;
154
155 err = i2c_smbus_write_byte_data(c, reg, val);
156 if (err)
157 printk(KERN_INFO "WriteReg(%d) failed\n", reg);
158 return err;
159}
160
161static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) {
162 s32 err;
163
164 err = i2c_smbus_write_word_data(c, reg, val);
165 if (err)
166 printk(KERN_INFO "WriteRegPair(%d) failed\n", reg);
167 return err;
168}
169
170static const struct matrox_pll_features maven_pll = {
171 50000,
172 27000,
173 4, 127,
174 2, 31,
175 3
176};
177
178struct matrox_pll_features2 {
179 unsigned int vco_freq_min;
180 unsigned int vco_freq_max;
181 unsigned int feed_div_min;
182 unsigned int feed_div_max;
183 unsigned int in_div_min;
184 unsigned int in_div_max;
185 unsigned int post_shift_max;
186};
187
188struct matrox_pll_ctl {
189 unsigned int ref_freq;
190 unsigned int den;
191};
192
193static const struct matrox_pll_features2 maven1000_pll = {
194 50000000,
195 300000000,
196 5, 128,
197 3, 32,
198 3
199};
200
201static const struct matrox_pll_ctl maven_PAL = {
202 540000,
203 50
204};
205
206static const struct matrox_pll_ctl maven_NTSC = {
207 450450,
208 60
209};
210
211static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
212 const struct matrox_pll_ctl* ctl,
213 unsigned int htotal, unsigned int vtotal,
214 unsigned int* in, unsigned int* feed, unsigned int* post,
215 unsigned int* h2) {
216 unsigned int besth2 = 0;
217 unsigned int fxtal = ctl->ref_freq;
218 unsigned int fmin = pll->vco_freq_min / ctl->den;
219 unsigned int fwant;
220 unsigned int p;
221 unsigned int scrlen;
222 unsigned int fmax;
223
224 DBG(__FUNCTION__)
225
226 scrlen = htotal * (vtotal - 1);
227 fwant = htotal * vtotal;
228 fmax = pll->vco_freq_max / ctl->den;
229
230 dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
231 fwant, fxtal, htotal, vtotal, fmax);
232 for (p = 1; p <= pll->post_shift_max; p++) {
233 if (fwant * 2 > fmax)
234 break;
235 fwant *= 2;
236 }
237 if (fwant > fmax)
238 return 0;
239 for (; p-- > 0; fwant >>= 1) {
240 unsigned int m;
241
242 if (fwant < fmin) break;
243 for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
244 unsigned int n;
245 unsigned int dvd;
246 unsigned int ln;
247
248 n = (fwant * m) / fxtal;
249 if (n < pll->feed_div_min)
250 continue;
251 if (n > pll->feed_div_max)
252 break;
253
254 ln = fxtal * n;
255 dvd = m << p;
256
257 if (ln % dvd)
258 continue;
259 ln = ln / dvd;
260
261 if (ln < scrlen + 2)
262 continue;
263 ln = ln - scrlen;
264 if (ln > htotal)
265 continue;
266 dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
267 if (ln > besth2) {
268 dprintk(KERN_DEBUG "Better...\n");
269 *h2 = besth2 = ln;
270 *post = p;
271 *in = m;
272 *feed = n;
273 }
274 }
275 }
276 if (besth2 < 2)
277 return 0;
278 dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
279 return fxtal * (*feed) / (*in) * ctl->den;
280}
281
282static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
283 unsigned int htotal, unsigned int vtotal,
284 unsigned int* in, unsigned int* feed, unsigned int* post,
285 unsigned int* htotal2) {
286 unsigned int fvco;
287 unsigned int p;
288
289 fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
290 if (!fvco)
291 return -EINVAL;
292 p = (1 << p) - 1;
293 if (fvco <= 100000000)
294 ;
295 else if (fvco <= 140000000)
296 p |= 0x08;
297 else if (fvco <= 180000000)
298 p |= 0x10;
299 else
300 p |= 0x18;
301 *post = p;
302 return 0;
303}
304
305static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
306 unsigned int* in, unsigned int* feed, unsigned int* post) {
307 unsigned int fvco;
308 unsigned int p;
309
310 fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
311 p = (1 << p) - 1;
312 if (fvco <= 100000)
313 ;
314 else if (fvco <= 140000)
315 p |= 0x08;
316 else if (fvco <= 180000)
317 p |= 0x10;
318 else
319 p |= 0x18;
320 *post = p;
321 return;
322}
323
324static unsigned char maven_compute_deflicker (const struct maven_data* md) {
325 unsigned char df;
326
327 df = (md->version == MGATVO_B?0x40:0x00);
328 switch (md->primary_head->altout.tvo_params.deflicker) {
329 case 0:
330
331 break;
332 case 1:
333 df |= 0xB1;
334 break;
335 case 2:
336 df |= 0xA2;
337 break;
338 }
339 return df;
340}
341
342static void maven_compute_bwlevel (const struct maven_data* md,
343 int *bl, int *wl) {
344 const int b = md->primary_head->altout.tvo_params.brightness + BLMIN;
345 const int c = md->primary_head->altout.tvo_params.contrast;
346
347 *bl = max(b - c, BLMIN);
348 *wl = min(b + c, WLMAX);
349}
350
351static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) {
352 return maven_gamma + md->primary_head->altout.tvo_params.gamma;
353}
354
355
356static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
357 static struct mavenregs palregs = { {
358 0x2A, 0x09, 0x8A, 0xCB,
359 0x00,
360 0x00,
361 0x00,
362 0x00,
363 0x7E,
364 0x44,
365 0x9C,
366 0x2E,
367 0x21,
368 0x00,
369 0x3F, 0x03,
370 0x3F, 0x03,
371 0x1A,
372 0x2A,
373 0x1C, 0x3D, 0x14,
374 0x9C, 0x01,
375 0x00,
376 0xFE,
377 0x7E,
378 0x60,
379 0x05,
380 0x89, 0x03,
381 0x72,
382 0x07,
383 0x72,
384 0x00,
385 0x00,
386 0x00,
387 0x08,
388 0x04,
389 0x00,
390 0x1A,
391 0x55, 0x01,
392 0x26,
393 0x07, 0x7E,
394 0x02, 0x54,
395 0xB0, 0x00,
396 0x14,
397 0x49,
398 0x00,
399 0x00,
400 0xA3,
401 0xC8,
402 0x22,
403 0x02,
404 0x22,
405 0x3F, 0x03,
406 0x00,
407 0x00,
408 }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
409 static struct mavenregs ntscregs = { {
410 0x21, 0xF0, 0x7C, 0x1F,
411 0x00,
412 0x00,
413 0x00,
414 0x00,
415 0x7E,
416 0x43,
417 0x7E,
418 0x3D,
419 0x00,
420 0x00,
421 0x41, 0x00,
422 0x3C, 0x00,
423 0x17,
424 0x21,
425 0x1B, 0x1B, 0x24,
426 0x83, 0x01,
427 0x00,
428 0x0F,
429 0x0F,
430 0x60,
431 0x05,
432 0x89, 0x02,
433 0x5F,
434 0x04,
435 0x5F,
436 0x01,
437 0x02,
438 0x00,
439 0x0A,
440 0x05,
441 0x00,
442 0x10,
443 0xFF, 0x03,
444 0x24,
445 0x0F, 0x78,
446 0x00, 0x00,
447 0xB2, 0x04,
448 0x14,
449 0x02,
450 0x00,
451 0x00,
452 0xA3,
453 0xC8,
454 0x15,
455 0x05,
456 0x3B,
457 0x3C, 0x00,
458 0x00,
459 0x00,
460 }, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 };
461 MINFO_FROM(md->primary_head);
462
463 if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_PAL)
464 *data = palregs;
465 else
466 *data = ntscregs;
467
468
469 data->regs[0x93] = maven_compute_deflicker(md);
470
471
472 {
473 const struct maven_gamma* g;
474 g = maven_compute_gamma(md);
475 data->regs[0x83] = g->reg83;
476 data->regs[0x84] = g->reg84;
477 data->regs[0x85] = g->reg85;
478 data->regs[0x86] = g->reg86;
479 data->regs[0x87] = g->reg87;
480 data->regs[0x88] = g->reg88;
481 data->regs[0x89] = g->reg89;
482 data->regs[0x8A] = g->reg8a;
483 data->regs[0x8B] = g->reg8b;
484 }
485
486
487 {
488 int bl, wl;
489 maven_compute_bwlevel (md, &bl, &wl);
490 data->regs[0x0e] = bl >> 2;
491 data->regs[0x0f] = bl & 3;
492 data->regs[0x1e] = wl >> 2;
493 data->regs[0x1f] = wl & 3;
494 }
495
496
497 {
498 data->regs[0x20] =
499 data->regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
500 }
501
502
503 data->regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
504 return;
505}
506
507#define LR(x) maven_set_reg(c, (x), m->regs[(x)])
508#define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
509static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
510 int val;
511
512
513 maven_set_reg(c, 0x3E, 0x01);
514 maven_get_reg(c, 0x82);
515 maven_set_reg(c, 0x8C, 0x00);
516 maven_get_reg(c, 0x94);
517 maven_set_reg(c, 0x94, 0xA2);
518
519
520 maven_set_reg_pair(c, 0x8E, 0x1EFF);
521 maven_set_reg(c, 0xC6, 0x01);
522
523
524
525 maven_get_reg(c, 0x06);
526 maven_set_reg(c, 0x06, 0xF9);
527
528
529
530
531
532 LR(0x00); LR(0x01); LR(0x02); LR(0x03);
533
534 LR(0x04);
535
536 LR(0x2C);
537 LR(0x08);
538 LR(0x0A);
539 LR(0x09);
540 LR(0x29);
541 LRP(0x31);
542 LRP(0x17);
543 LR(0x0B);
544 LR(0x0C);
545 if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
546 maven_set_reg(c, 0x35, 0x10);
547 } else {
548 maven_set_reg(c, 0x35, 0x0F);
549 }
550
551 LRP(0x10);
552
553 LRP(0x0E);
554 LRP(0x1E);
555
556 LR(0x20);
557 LR(0x22);
558 LR(0x25);
559 LR(0x34);
560 LR(0x33);
561 LR(0x19);
562 LR(0x12);
563 LR(0x3B);
564 LR(0x13);
565 LR(0x39);
566 LR(0x1D);
567 LR(0x3A);
568 LR(0x24);
569 LR(0x14);
570 LR(0x15);
571 LR(0x16);
572 LRP(0x2D);
573 LRP(0x2F);
574 LR(0x1A);
575 LR(0x1B);
576 LR(0x1C);
577 LR(0x23);
578 LR(0x26);
579 LR(0x28);
580 LR(0x27);
581 LR(0x21);
582 LRP(0x2A);
583 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
584 maven_set_reg(c, 0x35, 0x1D);
585 else
586 maven_set_reg(c, 0x35, 0x1C);
587
588 LRP(0x3C);
589 LR(0x37);
590 LR(0x38);
591 maven_set_reg(c, 0xB3, 0x01);
592
593 maven_get_reg(c, 0xB0);
594 maven_set_reg(c, 0xB0, 0x08);
595 maven_get_reg(c, 0xB9);
596 maven_set_reg(c, 0xB9, 0x78);
597 maven_get_reg(c, 0xBF);
598 maven_set_reg(c, 0xBF, 0x02);
599 maven_get_reg(c, 0x94);
600 maven_set_reg(c, 0x94, 0xB3);
601
602 LR(0x80);
603 LR(0x81);
604 LR(0x82);
605
606 maven_set_reg(c, 0x8C, 0x20);
607 maven_get_reg(c, 0x8D);
608 maven_set_reg(c, 0x8D, 0x10);
609
610 LR(0x90);
611 LR(0x91);
612 LR(0x92);
613
614 LRP(0x9A);
615 LRP(0x9C);
616 LRP(0x9E);
617 LRP(0xA0);
618 LRP(0xA2);
619 LRP(0xA4);
620 LRP(0xA6);
621 LRP(0xA8);
622 LRP(0x98);
623 LRP(0xAE);
624 LRP(0x96);
625 LRP(0xAA);
626 LRP(0xAC);
627
628 LR(0xBE);
629 LR(0xC2);
630
631 maven_get_reg(c, 0x8D);
632 maven_set_reg(c, 0x8D, 0x04);
633
634 LR(0x20);
635 LR(0x22);
636 LR(0x93);
637 LR(0x20);
638 LR(0x22);
639 LR(0x25);
640 LRP(0x0E);
641 LRP(0x1E);
642 LRP(0x0E);
643 LRP(0x1E);
644
645
646 LR(0x83);
647 LR(0x84);
648 LR(0x85);
649 LR(0x86);
650 LR(0x87);
651 LR(0x88);
652 LR(0x89);
653 LR(0x8A);
654 LR(0x8B);
655
656 val = maven_get_reg(c, 0x8D);
657 val &= 0x14;
658 maven_set_reg(c, 0x8D, val);
659
660 LR(0x33);
661 LR(0x19);
662 LR(0x12);
663 LR(0x3B);
664 LR(0x13);
665 LR(0x39);
666 LR(0x1D);
667 LR(0x3A);
668 LR(0x24);
669 LR(0x14);
670 LR(0x15);
671 LR(0x16);
672 LRP(0x2D);
673 LRP(0x2F);
674 LR(0x1A);
675 LR(0x1B);
676 LR(0x1C);
677 LR(0x23);
678 LR(0x26);
679 LR(0x28);
680 LR(0x27);
681 LR(0x21);
682 LRP(0x2A);
683 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
684 maven_set_reg(c, 0x35, 0x1D);
685 else
686 maven_set_reg(c, 0x35, 0x1C);
687 LRP(0x3C);
688 LR(0x37);
689 LR(0x38);
690
691 maven_get_reg(c, 0xB0);
692 LR(0xB0);
693 LR(0x90);
694 LR(0xBE);
695 LR(0xC2);
696
697 LRP(0x9A);
698 LRP(0xA2);
699 LRP(0x9E);
700 LRP(0xA6);
701 LRP(0xAA);
702 LRP(0xAC);
703 maven_set_reg(c, 0x3E, 0x00);
704 maven_set_reg(c, 0x95, 0x20);
705}
706
707static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
708 struct mavenregs* m) {
709 unsigned int x;
710 unsigned int err = ~0;
711
712
713 m->regs[0x80] = 0x0F;
714 m->regs[0x81] = 0x07;
715 m->regs[0x82] = 0x81;
716
717 for (x = 0; x < 8; x++) {
718 unsigned int a, b, c, h2;
719 unsigned int h = ht + 2 + x;
720
721 if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
722 unsigned int diff = h - h2;
723
724 if (diff < err) {
725 err = diff;
726 m->regs[0x80] = a - 1;
727 m->regs[0x81] = b - 1;
728 m->regs[0x82] = c | 0x80;
729 m->hcorr = h2 - 2;
730 m->htotal = h - 2;
731 }
732 }
733 }
734 return err != ~0U;
735}
736
737static inline int maven_compute_timming(struct maven_data* md,
738 struct my_timming* mt,
739 struct mavenregs* m) {
740 unsigned int tmpi;
741 unsigned int a, bv, c;
742 MINFO_FROM(md->primary_head);
743
744 m->mode = ACCESS_FBINFO(outputs[1]).mode;
745 if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
746 unsigned int lmargin;
747 unsigned int umargin;
748 unsigned int vslen;
749 unsigned int hcrt;
750 unsigned int slen;
751
752 maven_init_TVdata(md, m);
753
754 if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
755 return -EINVAL;
756
757 lmargin = mt->HTotal - mt->HSyncEnd;
758 slen = mt->HSyncEnd - mt->HSyncStart;
759 hcrt = mt->HTotal - slen - mt->delay;
760 umargin = mt->VTotal - mt->VSyncEnd;
761 vslen = mt->VSyncEnd - mt->VSyncStart;
762
763 if (m->hcorr < mt->HTotal)
764 hcrt += m->hcorr;
765 if (hcrt > mt->HTotal)
766 hcrt -= mt->HTotal;
767 if (hcrt + 2 > mt->HTotal)
768 hcrt = 0;
769
770
771
772 m->regs[0x96] = m->hcorr;
773 m->regs[0x97] = m->hcorr >> 8;
774
775 m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
776
777 m->regs[0x9A] = lmargin;
778 m->regs[0x9B] = lmargin >> 8;
779
780 m->regs[0x9C] = 0x04;
781 m->regs[0x9D] = 0x00;
782
783 m->regs[0xA0] = m->htotal;
784 m->regs[0xA1] = m->htotal >> 8;
785
786 m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1;
787 m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
788
789 if (md->version == MGATVO_B) {
790 m->regs[0xA4] = 0x04;
791 m->regs[0xA5] = 0x00;
792 } else {
793 m->regs[0xA4] = 0x01;
794 m->regs[0xA5] = 0x00;
795 }
796
797 m->regs[0xA6] = 0x00;
798 m->regs[0xA7] = 0x00;
799
800 m->regs[0xA8] = mt->VTotal - 1;
801 m->regs[0xA9] = (mt->VTotal - 1) >> 8;
802
803 m->regs[0xAA] = hcrt;
804 m->regs[0xAB] = hcrt >> 8;
805
806 m->regs[0xAC] = mt->VTotal - 2;
807 m->regs[0xAD] = (mt->VTotal - 2) >> 8;
808
809 m->regs[0xAE] = 0x01;
810 m->regs[0xAF] = 0x00;
811 {
812 int hdec;
813 int hlen;
814 unsigned int ibmin = 4 + lmargin + mt->HDisplay;
815 unsigned int ib;
816 int i;
817
818
819
820 if (mt->HTotal)
821 hdec = 94208 / (mt->HTotal);
822 else
823 hdec = 0x81;
824 if (hdec > 0x81)
825 hdec = 0x81;
826 if (hdec < 0x41)
827 hdec = 0x41;
828 hdec--;
829 hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
830 if (hlen < 0)
831 hlen = 0;
832 hlen = hlen >> 8;
833 if (hlen > 0xFF)
834 hlen = 0xFF;
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850 i = 1;
851 do {
852 ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
853 i++;
854 } while (ib < ibmin);
855 if (ib >= m->htotal + 2) {
856 ib = ibmin;
857 }
858
859 m->regs[0x90] = hdec;
860 m->regs[0xC2] = hlen;
861
862 m->regs[0x9E] = ib;
863 m->regs[0x9F] = ib >> 8;
864 }
865 {
866 int vdec;
867 int vlen;
868
869#define MATROX_USE64BIT_DIVIDE
870 if (mt->VTotal) {
871#ifdef MATROX_USE64BIT_DIVIDE
872 u64 f1;
873 u32 a;
874 u32 b;
875
876 a = m->vlines * (m->htotal + 2);
877 b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
878
879 f1 = ((u64)a) << 15;
880 do_div(f1, b);
881 vdec = f1;
882#else
883 vdec = m->vlines * 32768 / mt->VTotal;
884#endif
885 } else
886 vdec = 0x8000;
887 if (vdec > 0x8000)
888 vdec = 0x8000;
889 vlen = (vslen + umargin + mt->VDisplay) * vdec;
890 vlen = (vlen >> 16) - 146;
891 if (vlen < 0)
892 vlen = 0;
893 if (vlen > 0xFF)
894 vlen = 0xFF;
895 vdec--;
896 m->regs[0x91] = vdec;
897 m->regs[0x92] = vdec >> 8;
898 m->regs[0xBE] = vlen;
899 }
900 m->regs[0xB0] = 0x08;
901 return 0;
902 }
903
904 DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
905 m->regs[0x80] = a;
906 m->regs[0x81] = bv;
907 m->regs[0x82] = c | 0x80;
908
909 m->regs[0xB3] = 0x01;
910 m->regs[0x94] = 0xB2;
911
912
913 m->regs[0x96] = mt->HTotal;
914 m->regs[0x97] = mt->HTotal >> 8;
915
916 m->regs[0x98] = 0x00;
917 m->regs[0x99] = 0x00;
918
919 tmpi = mt->HSyncEnd - mt->HSyncStart;
920 m->regs[0x9A] = tmpi;
921 m->regs[0x9B] = tmpi >> 8;
922
923 tmpi = mt->HTotal - mt->HSyncStart;
924 m->regs[0x9C] = tmpi;
925 m->regs[0x9D] = tmpi >> 8;
926
927 tmpi += mt->HDisplay;
928 m->regs[0x9E] = tmpi;
929 m->regs[0x9F] = tmpi >> 8;
930
931 tmpi = mt->HTotal + 1;
932 m->regs[0xA0] = tmpi;
933 m->regs[0xA1] = tmpi >> 8;
934
935 tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
936 m->regs[0xA2] = tmpi;
937 m->regs[0xA3] = tmpi >> 8;
938
939 tmpi = mt->VTotal - mt->VSyncStart;
940 m->regs[0xA4] = tmpi;
941 m->regs[0xA5] = tmpi >> 8;
942
943 tmpi = mt->VTotal - 1;
944 m->regs[0xA6] = tmpi;
945 m->regs[0xA7] = tmpi >> 8;
946
947 m->regs[0xA8] = tmpi;
948 m->regs[0xA9] = tmpi >> 8;
949
950 tmpi = mt->HTotal - mt->delay;
951 m->regs[0xAA] = tmpi;
952 m->regs[0xAB] = tmpi >> 8;
953
954 tmpi = mt->VTotal - 2;
955 m->regs[0xAC] = tmpi;
956 m->regs[0xAD] = tmpi >> 8;
957
958 m->regs[0xAE] = 0x00;
959 m->regs[0xAF] = 0x00;
960
961 m->regs[0xB0] = 0x03;
962 m->regs[0xB1] = 0xA0;
963 m->regs[0x8C] = 0x20;
964 m->regs[0x8D] = 0x04;
965 m->regs[0xB9] = 0x1A;
966 m->regs[0xBF] = 0x22;
967
968 return 0;
969}
970
971static int maven_program_timming(struct maven_data* md,
972 const struct mavenregs* m) {
973 struct i2c_client* c = &md->client;
974
975 if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
976 LR(0x80);
977 LR(0x81);
978 LR(0x82);
979
980 LR(0xB3);
981 LR(0x94);
982
983 LRP(0x96);
984 LRP(0x98);
985 LRP(0x9A);
986 LRP(0x9C);
987 LRP(0x9E);
988 LRP(0xA0);
989 LRP(0xA2);
990 LRP(0xA4);
991 LRP(0xA6);
992 LRP(0xA8);
993 LRP(0xAA);
994 LRP(0xAC);
995 LRP(0xAE);
996
997 LR(0xB0);
998 LR(0xB1);
999 LR(0x8C);
1000 LR(0x8D);
1001 LR(0xB9);
1002 LR(0xBF);
1003 } else {
1004 maven_init_TV(c, m);
1005 }
1006 return 0;
1007}
1008
1009static inline int maven_resync(struct maven_data* md) {
1010 struct i2c_client* c = &md->client;
1011 maven_set_reg(c, 0x95, 0x20);
1012 return 0;
1013}
1014
1015static int maven_get_queryctrl (struct maven_data* md,
1016 struct v4l2_queryctrl *p) {
1017 int i;
1018
1019 i = get_ctrl_id(p->id);
1020 if (i >= 0) {
1021 *p = maven_controls[i].desc;
1022 return 0;
1023 }
1024 if (i == -ENOENT) {
1025 static const struct v4l2_queryctrl disctrl =
1026 { .flags = V4L2_CTRL_FLAG_DISABLED };
1027
1028 i = p->id;
1029 *p = disctrl;
1030 p->id = i;
1031 sprintf(p->name, "Ctrl #%08X", i);
1032 return 0;
1033 }
1034 return -EINVAL;
1035}
1036
1037static int maven_set_control (struct maven_data* md,
1038 struct v4l2_control *p) {
1039 int i;
1040
1041 i = get_ctrl_id(p->id);
1042 if (i < 0) return -EINVAL;
1043
1044
1045
1046
1047 if (p->value == *get_ctrl_ptr(md, i)) return 0;
1048
1049
1050
1051
1052 if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
1053 if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
1054
1055
1056
1057
1058 *get_ctrl_ptr(md, i) = p->value;
1059
1060 switch (p->id) {
1061 case V4L2_CID_BRIGHTNESS:
1062 case V4L2_CID_CONTRAST:
1063 {
1064 int blacklevel, whitelevel;
1065 maven_compute_bwlevel(md, &blacklevel, &whitelevel);
1066 blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
1067 whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
1068 maven_set_reg_pair(&md->client, 0x0e, blacklevel);
1069 maven_set_reg_pair(&md->client, 0x1e, whitelevel);
1070 }
1071 break;
1072 case V4L2_CID_SATURATION:
1073 {
1074 maven_set_reg(&md->client, 0x20, p->value);
1075 maven_set_reg(&md->client, 0x22, p->value);
1076 }
1077 break;
1078 case V4L2_CID_HUE:
1079 {
1080 maven_set_reg(&md->client, 0x25, p->value);
1081 }
1082 break;
1083 case V4L2_CID_GAMMA:
1084 {
1085 const struct maven_gamma* g;
1086 g = maven_compute_gamma(md);
1087 maven_set_reg(&md->client, 0x83, g->reg83);
1088 maven_set_reg(&md->client, 0x84, g->reg84);
1089 maven_set_reg(&md->client, 0x85, g->reg85);
1090 maven_set_reg(&md->client, 0x86, g->reg86);
1091 maven_set_reg(&md->client, 0x87, g->reg87);
1092 maven_set_reg(&md->client, 0x88, g->reg88);
1093 maven_set_reg(&md->client, 0x89, g->reg89);
1094 maven_set_reg(&md->client, 0x8a, g->reg8a);
1095 maven_set_reg(&md->client, 0x8b, g->reg8b);
1096 }
1097 break;
1098 case MATROXFB_CID_TESTOUT:
1099 {
1100 unsigned char val
1101 = maven_get_reg(&md->client,0x8d);
1102 if (p->value) val |= 0x10;
1103 else val &= ~0x10;
1104 maven_set_reg(&md->client, 0x8d, val);
1105 }
1106 break;
1107 case MATROXFB_CID_DEFLICKER:
1108 {
1109 maven_set_reg(&md->client, 0x93, maven_compute_deflicker(md));
1110 }
1111 break;
1112 }
1113
1114
1115 return 0;
1116}
1117
1118static int maven_get_control (struct maven_data* md,
1119 struct v4l2_control *p) {
1120 int i;
1121
1122 i = get_ctrl_id(p->id);
1123 if (i < 0) return -EINVAL;
1124 p->value = *get_ctrl_ptr(md, i);
1125 return 0;
1126}
1127
1128
1129
1130static int maven_out_compute(void* md, struct my_timming* mt) {
1131#define mdinfo ((struct maven_data*)md)
1132#define minfo (mdinfo->primary_head)
1133 return maven_compute_timming(md, mt, &ACCESS_FBINFO(hw).maven);
1134#undef minfo
1135#undef mdinfo
1136}
1137
1138static int maven_out_program(void* md) {
1139#define mdinfo ((struct maven_data*)md)
1140#define minfo (mdinfo->primary_head)
1141 return maven_program_timming(md, &ACCESS_FBINFO(hw).maven);
1142#undef minfo
1143#undef mdinfo
1144}
1145
1146static int maven_out_start(void* md) {
1147 return maven_resync(md);
1148}
1149
1150static int maven_out_verify_mode(void* md, u_int32_t arg) {
1151 switch (arg) {
1152 case MATROXFB_OUTPUT_MODE_PAL:
1153 case MATROXFB_OUTPUT_MODE_NTSC:
1154 case MATROXFB_OUTPUT_MODE_MONITOR:
1155 return 0;
1156 }
1157 return -EINVAL;
1158}
1159
1160static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) {
1161 return maven_get_queryctrl(md, p);
1162}
1163
1164static int maven_out_get_ctrl(void* md, struct v4l2_control* p) {
1165 return maven_get_control(md, p);
1166}
1167
1168static int maven_out_set_ctrl(void* md, struct v4l2_control* p) {
1169 return maven_set_control(md, p);
1170}
1171
1172static struct matrox_altout maven_altout = {
1173 .name = "Secondary output",
1174 .compute = maven_out_compute,
1175 .program = maven_out_program,
1176 .start = maven_out_start,
1177 .verifymode = maven_out_verify_mode,
1178 .getqueryctrl = maven_out_get_queryctrl,
1179 .getctrl = maven_out_get_ctrl,
1180 .setctrl = maven_out_set_ctrl,
1181};
1182
1183static int maven_init_client(struct i2c_client* clnt) {
1184 struct maven_data* md = i2c_get_clientdata(clnt);
1185 MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo);
1186
1187 md->primary_head = MINFO;
1188 down_write(&ACCESS_FBINFO(altout.lock));
1189 ACCESS_FBINFO(outputs[1]).output = &maven_altout;
1190 ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
1191 ACCESS_FBINFO(outputs[1]).data = md;
1192 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1193 up_write(&ACCESS_FBINFO(altout.lock));
1194 if (maven_get_reg(clnt, 0xB2) < 0x14) {
1195 md->version = MGATVO_B;
1196
1197 } else {
1198 md->version = MGATVO_C;
1199 }
1200
1201
1202
1203 {
1204 unsigned int i;
1205
1206 for (i = 0; i < MAVCTRLS; ++i) {
1207 *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
1208 }
1209 }
1210
1211 return 0;
1212}
1213
1214static int maven_shutdown_client(struct i2c_client* clnt) {
1215 struct maven_data* md = i2c_get_clientdata(clnt);
1216
1217 if (md->primary_head) {
1218 MINFO_FROM(md->primary_head);
1219
1220 down_write(&ACCESS_FBINFO(altout.lock));
1221 ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
1222 ACCESS_FBINFO(outputs[1]).output = NULL;
1223 ACCESS_FBINFO(outputs[1]).data = NULL;
1224 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1225 up_write(&ACCESS_FBINFO(altout.lock));
1226 md->primary_head = NULL;
1227 }
1228 return 0;
1229}
1230
1231static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
1232I2C_CLIENT_INSMOD;
1233
1234static struct i2c_driver maven_driver;
1235
1236static int maven_detect_client(struct i2c_adapter* adapter, int address, int kind) {
1237 int err = 0;
1238 struct i2c_client* new_client;
1239 struct maven_data* data;
1240
1241 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA |
1242 I2C_FUNC_SMBUS_BYTE_DATA |
1243 I2C_FUNC_PROTOCOL_MANGLING))
1244 goto ERROR0;
1245 if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
1246 err = -ENOMEM;
1247 goto ERROR0;
1248 }
1249 new_client = &data->client;
1250 i2c_set_clientdata(new_client, data);
1251 new_client->addr = address;
1252 new_client->adapter = adapter;
1253 new_client->driver = &maven_driver;
1254 new_client->flags = 0;
1255 strlcpy(new_client->name, "maven", I2C_NAME_SIZE);
1256 if ((err = i2c_attach_client(new_client)))
1257 goto ERROR3;
1258 err = maven_init_client(new_client);
1259 if (err)
1260 goto ERROR4;
1261 return 0;
1262ERROR4:;
1263 i2c_detach_client(new_client);
1264ERROR3:;
1265 kfree(new_client);
1266ERROR0:;
1267 return err;
1268}
1269
1270static int maven_attach_adapter(struct i2c_adapter* adapter) {
1271 if (adapter->id == I2C_HW_B_G400)
1272 return i2c_probe(adapter, &addr_data, &maven_detect_client);
1273 return 0;
1274}
1275
1276static int maven_detach_client(struct i2c_client* client) {
1277 int err;
1278
1279 if ((err = i2c_detach_client(client)))
1280 return err;
1281 maven_shutdown_client(client);
1282 kfree(i2c_get_clientdata(client));
1283 return 0;
1284}
1285
1286static struct i2c_driver maven_driver={
1287 .driver = {
1288 .name = "maven",
1289 },
1290 .id = I2C_DRIVERID_MGATVO,
1291 .attach_adapter = maven_attach_adapter,
1292 .detach_client = maven_detach_client,
1293};
1294
1295static int __init matroxfb_maven_init(void)
1296{
1297 return i2c_add_driver(&maven_driver);
1298}
1299
1300static void __exit matroxfb_maven_exit(void)
1301{
1302 i2c_del_driver(&maven_driver);
1303}
1304
1305MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1306MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1307MODULE_LICENSE("GPL");
1308module_init(matroxfb_maven_init);
1309module_exit(matroxfb_maven_exit);
1310
1311