3 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
5 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
7 * Portions Copyright (c) 2001 Matrox Graphics Inc.
9 * Version: 1.65 2002/08/14
11 * See matroxfb_base.c for contributors.
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 <linux/slab.h>
21 #include <asm/div64.h>
26 static const struct maven_gamma
{
37 { 131, 57, 223, 15, 117, 212, 251, 91, 156},
38 { 133, 61, 128, 63, 180, 147, 195, 100, 180},
39 { 131, 19, 63, 31, 50, 66, 171, 64, 176},
40 { 0, 0, 0, 31, 16, 16, 16, 100, 200},
41 { 8, 23, 47, 73, 147, 244, 220, 80, 195},
42 { 22, 43, 64, 80, 147, 115, 58, 85, 168},
43 { 34, 60, 80, 214, 147, 212, 188, 85, 167},
44 { 45, 77, 96, 216, 147, 99, 91, 85, 159},
45 { 56, 76, 112, 107, 147, 212, 148, 64, 144},
46 { 65, 91, 128, 137, 147, 196, 17, 69, 148},
47 { 72, 104, 136, 138, 147, 180, 245, 73, 147},
48 { 87, 116, 143, 126, 16, 83, 229, 77, 144},
49 { 95, 119, 152, 254, 244, 83, 221, 77, 151},
50 { 100, 129, 159, 156, 244, 148, 197, 77, 160},
51 { 105, 141, 167, 247, 244, 132, 181, 84, 166},
52 { 105, 147, 168, 247, 244, 245, 181, 90, 170},
53 { 120, 153, 175, 248, 212, 229, 165, 90, 180},
54 { 119, 156, 176, 248, 244, 229, 84, 74, 160},
55 { 119, 158, 183, 248, 244, 229, 149, 78, 165}
58 /* Definition of the various controls */
60 struct v4l2_queryctrl desc
;
67 static const struct mctl maven_controls
[] =
68 { { { V4L2_CID_BRIGHTNESS
, V4L2_CTRL_TYPE_INTEGER
,
70 0, WLMAX
- BLMIN
, 1, 379 - BLMIN
,
72 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.brightness
) },
73 { { V4L2_CID_CONTRAST
, V4L2_CTRL_TYPE_INTEGER
,
77 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.contrast
) },
78 { { V4L2_CID_SATURATION
, V4L2_CTRL_TYPE_INTEGER
,
82 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.saturation
) },
83 { { V4L2_CID_HUE
, V4L2_CTRL_TYPE_INTEGER
,
87 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.hue
) },
88 { { V4L2_CID_GAMMA
, V4L2_CTRL_TYPE_INTEGER
,
90 0, ARRAY_SIZE(maven_gamma
) - 1, 1, 3,
92 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.gamma
) },
93 { { MATROXFB_CID_TESTOUT
, V4L2_CTRL_TYPE_BOOLEAN
,
97 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.testout
) },
98 { { MATROXFB_CID_DEFLICKER
, V4L2_CTRL_TYPE_INTEGER
,
102 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.deflicker
) },
106 #define MAVCTRLS ARRAY_SIZE(maven_controls)
108 /* Return: positive number: id found
109 -EINVAL: id not found, return failure
110 -ENOENT: id not found, create fake disabled control */
111 static int get_ctrl_id(__u32 v4l2_id
) {
114 for (i
= 0; i
< MAVCTRLS
; i
++) {
115 if (v4l2_id
< maven_controls
[i
].desc
.id
) {
116 if (maven_controls
[i
].desc
.id
== 0x08000000) {
121 if (v4l2_id
== maven_controls
[i
].desc
.id
) {
129 struct matrox_fb_info
* primary_head
;
130 struct i2c_client
*client
;
134 static int* get_ctrl_ptr(struct maven_data
* md
, int idx
) {
135 return (int*)((char*)(md
->primary_head
) + maven_controls
[idx
].control
);
138 static int maven_get_reg(struct i2c_client
* c
, char reg
) {
140 struct i2c_msg msgs
[] = {
143 .flags
= I2C_M_REV_DIR_ADDR
,
149 .flags
= I2C_M_RD
| I2C_M_NOSTART
,
156 err
= i2c_transfer(c
->adapter
, msgs
, 2);
158 printk(KERN_INFO
"ReadReg(%d) failed\n", reg
);
162 static int maven_set_reg(struct i2c_client
* c
, int reg
, int val
) {
165 err
= i2c_smbus_write_byte_data(c
, reg
, val
);
167 printk(KERN_INFO
"WriteReg(%d) failed\n", reg
);
171 static int maven_set_reg_pair(struct i2c_client
* c
, int reg
, int val
) {
174 err
= i2c_smbus_write_word_data(c
, reg
, val
);
176 printk(KERN_INFO
"WriteRegPair(%d) failed\n", reg
);
180 static const struct matrox_pll_features maven_pll
= {
188 struct matrox_pll_features2
{
189 unsigned int vco_freq_min
;
190 unsigned int vco_freq_max
;
191 unsigned int feed_div_min
;
192 unsigned int feed_div_max
;
193 unsigned int in_div_min
;
194 unsigned int in_div_max
;
195 unsigned int post_shift_max
;
198 struct matrox_pll_ctl
{
199 unsigned int ref_freq
;
203 static const struct matrox_pll_features2 maven1000_pll
= {
204 .vco_freq_min
= 50000000,
205 .vco_freq_max
= 300000000,
213 static const struct matrox_pll_ctl maven_PAL
= {
218 static const struct matrox_pll_ctl maven_NTSC
= {
219 .ref_freq
= 450450, /* 27027000/60 == 27000000/59.94005994 */
223 static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2
* pll
,
224 const struct matrox_pll_ctl
* ctl
,
225 unsigned int htotal
, unsigned int vtotal
,
226 unsigned int* in
, unsigned int* feed
, unsigned int* post
,
228 unsigned int besth2
= 0;
229 unsigned int fxtal
= ctl
->ref_freq
;
230 unsigned int fmin
= pll
->vco_freq_min
/ ctl
->den
;
238 scrlen
= htotal
* (vtotal
- 1);
239 fwant
= htotal
* vtotal
;
240 fmax
= pll
->vco_freq_max
/ ctl
->den
;
242 dprintk(KERN_DEBUG
"want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
243 fwant
, fxtal
, htotal
, vtotal
, fmax
);
244 for (p
= 1; p
<= pll
->post_shift_max
; p
++) {
245 if (fwant
* 2 > fmax
)
251 for (; p
-- > 0; fwant
>>= 1) {
254 if (fwant
< fmin
) break;
255 for (m
= pll
->in_div_min
; m
<= pll
->in_div_max
; m
++) {
260 n
= (fwant
* m
) / fxtal
;
261 if (n
< pll
->feed_div_min
)
263 if (n
> pll
->feed_div_max
)
278 dprintk(KERN_DEBUG
"Match: %u / %u / %u / %u\n", n
, m
, p
, ln
);
280 dprintk(KERN_DEBUG
"Better...\n");
289 /* if h2/post/in/feed have not been assigned, return zero (error) */
293 dprintk(KERN_ERR
"clk: %02X %02X %02X %d %d\n", *in
, *feed
, *post
, fxtal
, fwant
);
294 return fxtal
* (*feed
) / (*in
) * ctl
->den
;
297 static int matroxfb_mavenclock(const struct matrox_pll_ctl
*ctl
,
298 unsigned int htotal
, unsigned int vtotal
,
299 unsigned int* in
, unsigned int* feed
, unsigned int* post
,
300 unsigned int* htotal2
) {
302 unsigned int uninitialized_var(p
);
304 fvco
= matroxfb_PLL_mavenclock(&maven1000_pll
, ctl
, htotal
, vtotal
, in
, feed
, &p
, htotal2
);
308 if (fvco
<= 100000000)
310 else if (fvco
<= 140000000)
312 else if (fvco
<= 180000000)
320 static void DAC1064_calcclock(unsigned int freq
, unsigned int fmax
,
321 unsigned int* in
, unsigned int* feed
, unsigned int* post
) {
325 fvco
= matroxfb_PLL_calcclock(&maven_pll
, freq
, fmax
, in
, feed
, &p
);
329 else if (fvco
<= 140000)
331 else if (fvco
<= 180000)
339 static unsigned char maven_compute_deflicker (const struct maven_data
* md
) {
342 df
= (md
->version
== MGATVO_B
?0x40:0x00);
343 switch (md
->primary_head
->altout
.tvo_params
.deflicker
) {
357 static void maven_compute_bwlevel (const struct maven_data
* md
,
359 const int b
= md
->primary_head
->altout
.tvo_params
.brightness
+ BLMIN
;
360 const int c
= md
->primary_head
->altout
.tvo_params
.contrast
;
362 *bl
= max(b
- c
, BLMIN
);
363 *wl
= min(b
+ c
, WLMAX
);
366 static const struct maven_gamma
* maven_compute_gamma (const struct maven_data
* md
) {
367 return maven_gamma
+ md
->primary_head
->altout
.tvo_params
.gamma
;
371 static void maven_init_TVdata(const struct maven_data
* md
, struct mavenregs
* data
) {
372 static struct mavenregs palregs
= { {
373 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
375 0x00, /* ? not written */
376 0x00, /* modified by code (F9 written...) */
377 0x00, /* ? not written */
383 0x00, /* ? not written */
384 0x3F, 0x03, /* 0E-0F */
385 0x3F, 0x03, /* 10-11 */
388 0x1C, 0x3D, 0x14, /* 14-16 */
389 0x9C, 0x01, /* 17-18 */
395 0x89, 0x03, /* 1E-1F */
406 0x55, 0x01, /* 2A-2B */
408 0x07, 0x7E, /* 2D-2E */
409 0x02, 0x54, /* 2F-30 */
410 0xB0, 0x00, /* 31-32 */
413 0x00, /* 35 written multiple times */
414 0x00, /* 36 not written */
420 0x3F, 0x03, /* 3C-3D */
421 0x00, /* 3E written multiple times */
422 0x00, /* 3F not written */
423 }, MATROXFB_OUTPUT_MODE_PAL
, 625, 50 };
424 static struct mavenregs ntscregs
= { {
425 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
427 0x00, /* ? not written */
428 0x00, /* modified by code (F9 written...) */
429 0x00, /* ? not written */
435 0x00, /* ? not written */
436 0x41, 0x00, /* 0E-0F */
437 0x3C, 0x00, /* 10-11 */
440 0x1B, 0x1B, 0x24, /* 14-16 */
441 0x83, 0x01, /* 17-18 */
447 0x89, 0x02, /* 1E-1F */
458 0xFF, 0x03, /* 2A-2B */
460 0x0F, 0x78, /* 2D-2E */
461 0x00, 0x00, /* 2F-30 */
462 0xB2, 0x04, /* 31-32 */
465 0x00, /* 35 written multiple times */
466 0x00, /* 36 not written */
472 0x3C, 0x00, /* 3C-3D */
473 0x00, /* 3E written multiple times */
474 0x00, /* never written */
475 }, MATROXFB_OUTPUT_MODE_NTSC
, 525, 60 };
476 struct matrox_fb_info
*minfo
= md
->primary_head
;
478 if (minfo
->outputs
[1].mode
== MATROXFB_OUTPUT_MODE_PAL
)
484 data
->regs
[0x93] = maven_compute_deflicker(md
);
488 const struct maven_gamma
* g
;
489 g
= maven_compute_gamma(md
);
490 data
->regs
[0x83] = g
->reg83
;
491 data
->regs
[0x84] = g
->reg84
;
492 data
->regs
[0x85] = g
->reg85
;
493 data
->regs
[0x86] = g
->reg86
;
494 data
->regs
[0x87] = g
->reg87
;
495 data
->regs
[0x88] = g
->reg88
;
496 data
->regs
[0x89] = g
->reg89
;
497 data
->regs
[0x8A] = g
->reg8a
;
498 data
->regs
[0x8B] = g
->reg8b
;
501 /* Set contrast / brightness */
504 maven_compute_bwlevel (md
, &bl
, &wl
);
505 data
->regs
[0x0e] = bl
>> 2;
506 data
->regs
[0x0f] = bl
& 3;
507 data
->regs
[0x1e] = wl
>> 2;
508 data
->regs
[0x1f] = wl
& 3;
514 data
->regs
[0x22] = minfo
->altout
.tvo_params
.saturation
;
518 data
->regs
[0x25] = minfo
->altout
.tvo_params
.hue
;
522 #define LR(x) maven_set_reg(c, (x), m->regs[(x)])
523 #define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
524 static void maven_init_TV(struct i2c_client
* c
, const struct mavenregs
* m
) {
528 maven_set_reg(c
, 0x3E, 0x01);
529 maven_get_reg(c
, 0x82); /* fetch oscillator state? */
530 maven_set_reg(c
, 0x8C, 0x00);
531 maven_get_reg(c
, 0x94); /* get 0x82 */
532 maven_set_reg(c
, 0x94, 0xA2);
535 maven_set_reg_pair(c
, 0x8E, 0x1EFF);
536 maven_set_reg(c
, 0xC6, 0x01);
538 /* removed code... */
540 maven_get_reg(c
, 0x06);
541 maven_set_reg(c
, 0x06, 0xF9); /* or read |= 0xF0 ? */
543 /* removed code here... */
545 /* real code begins here? */
546 /* chroma subcarrier */
547 LR(0x00); LR(0x01); LR(0x02); LR(0x03);
560 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
) {
561 maven_set_reg(c
, 0x35, 0x10); /* ... */
563 maven_set_reg(c
, 0x35, 0x0F); /* ... */
571 LR(0x20); /* saturation #1 */
572 LR(0x22); /* saturation #2 */
598 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
)
599 maven_set_reg(c
, 0x35, 0x1D); /* ... */
601 maven_set_reg(c
, 0x35, 0x1C);
606 maven_set_reg(c
, 0xB3, 0x01);
608 maven_get_reg(c
, 0xB0); /* read 0x80 */
609 maven_set_reg(c
, 0xB0, 0x08); /* ugh... */
610 maven_get_reg(c
, 0xB9); /* read 0x7C */
611 maven_set_reg(c
, 0xB9, 0x78);
612 maven_get_reg(c
, 0xBF); /* read 0x00 */
613 maven_set_reg(c
, 0xBF, 0x02);
614 maven_get_reg(c
, 0x94); /* read 0x82 */
615 maven_set_reg(c
, 0x94, 0xB3);
617 LR(0x80); /* 04 1A 91 or 05 21 91 */
621 maven_set_reg(c
, 0x8C, 0x20);
622 maven_get_reg(c
, 0x8D);
623 maven_set_reg(c
, 0x8D, 0x10);
625 LR(0x90); /* 4D 50 52 or 4E 05 45 */
629 LRP(0x9A); /* 0049 or 004F */
630 LRP(0x9C); /* 0004 or 0004 */
631 LRP(0x9E); /* 0458 or 045E */
632 LRP(0xA0); /* 05DA or 051B */
633 LRP(0xA2); /* 00CC or 00CF */
634 LRP(0xA4); /* 007D or 007F */
635 LRP(0xA6); /* 007C or 007E */
636 LRP(0xA8); /* 03CB or 03CE */
637 LRP(0x98); /* 0000 or 0000 */
638 LRP(0xAE); /* 0044 or 003A */
639 LRP(0x96); /* 05DA or 051B */
640 LRP(0xAA); /* 04BC or 046A */
641 LRP(0xAC); /* 004D or 004E */
646 maven_get_reg(c
, 0x8D);
647 maven_set_reg(c
, 0x8D, 0x04);
649 LR(0x20); /* saturation #1 */
650 LR(0x22); /* saturation #2 */
651 LR(0x93); /* whoops */
652 LR(0x20); /* oh, saturation #1 again */
653 LR(0x22); /* oh, saturation #2 again */
657 LRP(0x0E); /* problems with memory? */
658 LRP(0x1E); /* yes, matrox must have problems in memory area... */
660 /* load gamma correction stuff */
671 val
= maven_get_reg(c
, 0x8D);
672 val
&= 0x14; /* 0x10 or anything ored with it */
673 maven_set_reg(c
, 0x8D, val
);
698 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
)
699 maven_set_reg(c
, 0x35, 0x1D);
701 maven_set_reg(c
, 0x35, 0x1C);
706 maven_get_reg(c
, 0xB0);
707 LR(0xB0); /* output mode */
718 maven_set_reg(c
, 0x3E, 0x00);
719 maven_set_reg(c
, 0x95, 0x20);
722 static int maven_find_exact_clocks(unsigned int ht
, unsigned int vt
,
723 struct mavenregs
* m
) {
725 unsigned int err
= ~0;
728 m
->regs
[0x80] = 0x0F;
729 m
->regs
[0x81] = 0x07;
730 m
->regs
[0x82] = 0x81;
732 for (x
= 0; x
< 8; x
++) {
734 unsigned int uninitialized_var(a
), uninitialized_var(b
),
735 uninitialized_var(h2
);
736 unsigned int h
= ht
+ 2 + x
;
738 if (!matroxfb_mavenclock((m
->mode
== MATROXFB_OUTPUT_MODE_PAL
) ? &maven_PAL
: &maven_NTSC
, h
, vt
, &a
, &b
, &c
, &h2
)) {
739 unsigned int diff
= h
- h2
;
743 m
->regs
[0x80] = a
- 1;
744 m
->regs
[0x81] = b
- 1;
745 m
->regs
[0x82] = c
| 0x80;
754 static inline int maven_compute_timming(struct maven_data
* md
,
755 struct my_timming
* mt
,
756 struct mavenregs
* m
) {
758 unsigned int a
, bv
, c
;
759 struct matrox_fb_info
*minfo
= md
->primary_head
;
761 m
->mode
= minfo
->outputs
[1].mode
;
762 if (m
->mode
!= MATROXFB_OUTPUT_MODE_MONITOR
) {
763 unsigned int lmargin
;
764 unsigned int umargin
;
769 maven_init_TVdata(md
, m
);
771 if (maven_find_exact_clocks(mt
->HTotal
, mt
->VTotal
, m
) == 0)
774 lmargin
= mt
->HTotal
- mt
->HSyncEnd
;
775 slen
= mt
->HSyncEnd
- mt
->HSyncStart
;
776 hcrt
= mt
->HTotal
- slen
- mt
->delay
;
777 umargin
= mt
->VTotal
- mt
->VSyncEnd
;
778 vslen
= mt
->VSyncEnd
- mt
->VSyncStart
;
780 if (m
->hcorr
< mt
->HTotal
)
782 if (hcrt
> mt
->HTotal
)
784 if (hcrt
+ 2 > mt
->HTotal
)
785 hcrt
= 0; /* or issue warning? */
787 /* last (first? middle?) line in picture can have different length */
789 m
->regs
[0x96] = m
->hcorr
;
790 m
->regs
[0x97] = m
->hcorr
>> 8;
792 m
->regs
[0x98] = 0x00; m
->regs
[0x99] = 0x00;
794 m
->regs
[0x9A] = lmargin
; /* 100% */
795 m
->regs
[0x9B] = lmargin
>> 8; /* 100% */
797 m
->regs
[0x9C] = 0x04;
798 m
->regs
[0x9D] = 0x00;
800 m
->regs
[0xA0] = m
->htotal
;
801 m
->regs
[0xA1] = m
->htotal
>> 8;
803 m
->regs
[0xA2] = mt
->VTotal
- mt
->VSyncStart
- 1; /* stop vblanking */
804 m
->regs
[0xA3] = (mt
->VTotal
- mt
->VSyncStart
- 1) >> 8;
805 /* something end... [A6]+1..[A8] */
806 if (md
->version
== MGATVO_B
) {
807 m
->regs
[0xA4] = 0x04;
808 m
->regs
[0xA5] = 0x00;
810 m
->regs
[0xA4] = 0x01;
811 m
->regs
[0xA5] = 0x00;
813 /* something start... 0..[A4]-1 */
814 m
->regs
[0xA6] = 0x00;
815 m
->regs
[0xA7] = 0x00;
816 /* vertical line count - 1 */
817 m
->regs
[0xA8] = mt
->VTotal
- 1;
818 m
->regs
[0xA9] = (mt
->VTotal
- 1) >> 8;
819 /* horizontal vidrst pos */
820 m
->regs
[0xAA] = hcrt
; /* 0 <= hcrt <= htotal - 2 */
821 m
->regs
[0xAB] = hcrt
>> 8;
822 /* vertical vidrst pos */
823 m
->regs
[0xAC] = mt
->VTotal
- 2;
824 m
->regs
[0xAD] = (mt
->VTotal
- 2) >> 8;
825 /* moves picture up/down and so on... */
826 m
->regs
[0xAE] = 0x01; /* Fix this... 0..VTotal */
827 m
->regs
[0xAF] = 0x00;
831 unsigned int ibmin
= 4 + lmargin
+ mt
->HDisplay
;
836 /* Where 94208 came from? */
838 hdec
= 94208 / (mt
->HTotal
);
846 hlen
= 98304 - 128 - ((lmargin
+ mt
->HDisplay
- 8) * hdec
);
852 /* Now we have to compute input buffer length.
853 If you want any picture, it must be between
857 If you want perfect picture even on the top
858 of screen, it must be also
859 0x3C0000 * i / hdec + Q - R / hdec
869 ib
= ((0x3C0000 * i
- 0x8000)/ hdec
+ 0x05E7) >> 8;
871 } while (ib
< ibmin
);
872 if (ib
>= m
->htotal
+ 2) {
876 m
->regs
[0x90] = hdec
; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
877 m
->regs
[0xC2] = hlen
;
878 /* 'valid' input line length */
880 m
->regs
[0x9F] = ib
>> 8;
886 #define MATROX_USE64BIT_DIVIDE
888 #ifdef MATROX_USE64BIT_DIVIDE
893 a
= m
->vlines
* (m
->htotal
+ 2);
894 b
= (mt
->VTotal
- 1) * (m
->htotal
+ 2) + m
->hcorr
+ 2;
896 f1
= ((u64
)a
) << 15; /* *32768 */
900 vdec
= m
->vlines
* 32768 / mt
->VTotal
;
906 vlen
= (vslen
+ umargin
+ mt
->VDisplay
) * vdec
;
907 vlen
= (vlen
>> 16) - 146; /* FIXME: 146?! */
913 m
->regs
[0x91] = vdec
;
914 m
->regs
[0x92] = vdec
>> 8;
915 m
->regs
[0xBE] = vlen
;
917 m
->regs
[0xB0] = 0x08; /* output: SVideo/Composite */
921 DAC1064_calcclock(mt
->pixclock
, 450000, &a
, &bv
, &c
);
924 m
->regs
[0x82] = c
| 0x80;
926 m
->regs
[0xB3] = 0x01;
927 m
->regs
[0x94] = 0xB2;
930 m
->regs
[0x96] = mt
->HTotal
;
931 m
->regs
[0x97] = mt
->HTotal
>> 8;
933 m
->regs
[0x98] = 0x00;
934 m
->regs
[0x99] = 0x00;
936 tmpi
= mt
->HSyncEnd
- mt
->HSyncStart
;
937 m
->regs
[0x9A] = tmpi
;
938 m
->regs
[0x9B] = tmpi
>> 8;
940 tmpi
= mt
->HTotal
- mt
->HSyncStart
;
941 m
->regs
[0x9C] = tmpi
;
942 m
->regs
[0x9D] = tmpi
>> 8;
944 tmpi
+= mt
->HDisplay
;
945 m
->regs
[0x9E] = tmpi
;
946 m
->regs
[0x9F] = tmpi
>> 8;
948 tmpi
= mt
->HTotal
+ 1;
949 m
->regs
[0xA0] = tmpi
;
950 m
->regs
[0xA1] = tmpi
>> 8;
952 tmpi
= mt
->VSyncEnd
- mt
->VSyncStart
- 1;
953 m
->regs
[0xA2] = tmpi
;
954 m
->regs
[0xA3] = tmpi
>> 8;
956 tmpi
= mt
->VTotal
- mt
->VSyncStart
;
957 m
->regs
[0xA4] = tmpi
;
958 m
->regs
[0xA5] = tmpi
>> 8;
960 tmpi
= mt
->VTotal
- 1;
961 m
->regs
[0xA6] = tmpi
;
962 m
->regs
[0xA7] = tmpi
>> 8;
964 m
->regs
[0xA8] = tmpi
;
965 m
->regs
[0xA9] = tmpi
>> 8;
967 tmpi
= mt
->HTotal
- mt
->delay
;
968 m
->regs
[0xAA] = tmpi
;
969 m
->regs
[0xAB] = tmpi
>> 8;
971 tmpi
= mt
->VTotal
- 2;
972 m
->regs
[0xAC] = tmpi
;
973 m
->regs
[0xAD] = tmpi
>> 8;
975 m
->regs
[0xAE] = 0x00;
976 m
->regs
[0xAF] = 0x00;
978 m
->regs
[0xB0] = 0x03; /* output: monitor */
979 m
->regs
[0xB1] = 0xA0; /* ??? */
980 m
->regs
[0x8C] = 0x20; /* must be set... */
981 m
->regs
[0x8D] = 0x04; /* defaults to 0x10: test signal */
982 m
->regs
[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
983 m
->regs
[0xBF] = 0x22; /* makes picture stable */
988 static int maven_program_timming(struct maven_data
* md
,
989 const struct mavenregs
* m
) {
990 struct i2c_client
*c
= md
->client
;
992 if (m
->mode
== MATROXFB_OUTPUT_MODE_MONITOR
) {
1014 LR(0xB0); /* output: monitor */
1016 LR(0x8C); /* must be set... */
1017 LR(0x8D); /* defaults to 0x10: test signal */
1018 LR(0xB9); /* defaults to 0x2C: too bright */
1019 LR(0xBF); /* makes picture stable */
1021 maven_init_TV(c
, m
);
1026 static inline int maven_resync(struct maven_data
* md
) {
1027 struct i2c_client
*c
= md
->client
;
1028 maven_set_reg(c
, 0x95, 0x20); /* start whole thing */
1032 static int maven_get_queryctrl (struct maven_data
* md
,
1033 struct v4l2_queryctrl
*p
) {
1036 i
= get_ctrl_id(p
->id
);
1038 *p
= maven_controls
[i
].desc
;
1042 static const struct v4l2_queryctrl disctrl
=
1043 { .flags
= V4L2_CTRL_FLAG_DISABLED
};
1048 sprintf(p
->name
, "Ctrl #%08X", i
);
1054 static int maven_set_control (struct maven_data
* md
,
1055 struct v4l2_control
*p
) {
1058 i
= get_ctrl_id(p
->id
);
1059 if (i
< 0) return -EINVAL
;
1064 if (p
->value
== *get_ctrl_ptr(md
, i
)) return 0;
1069 if (p
->value
> maven_controls
[i
].desc
.maximum
) return -EINVAL
;
1070 if (p
->value
< maven_controls
[i
].desc
.minimum
) return -EINVAL
;
1075 *get_ctrl_ptr(md
, i
) = p
->value
;
1078 case V4L2_CID_BRIGHTNESS
:
1079 case V4L2_CID_CONTRAST
:
1081 int blacklevel
, whitelevel
;
1082 maven_compute_bwlevel(md
, &blacklevel
, &whitelevel
);
1083 blacklevel
= (blacklevel
>> 2) | ((blacklevel
& 3) << 8);
1084 whitelevel
= (whitelevel
>> 2) | ((whitelevel
& 3) << 8);
1085 maven_set_reg_pair(md
->client
, 0x0e, blacklevel
);
1086 maven_set_reg_pair(md
->client
, 0x1e, whitelevel
);
1089 case V4L2_CID_SATURATION
:
1091 maven_set_reg(md
->client
, 0x20, p
->value
);
1092 maven_set_reg(md
->client
, 0x22, p
->value
);
1097 maven_set_reg(md
->client
, 0x25, p
->value
);
1100 case V4L2_CID_GAMMA
:
1102 const struct maven_gamma
* g
;
1103 g
= maven_compute_gamma(md
);
1104 maven_set_reg(md
->client
, 0x83, g
->reg83
);
1105 maven_set_reg(md
->client
, 0x84, g
->reg84
);
1106 maven_set_reg(md
->client
, 0x85, g
->reg85
);
1107 maven_set_reg(md
->client
, 0x86, g
->reg86
);
1108 maven_set_reg(md
->client
, 0x87, g
->reg87
);
1109 maven_set_reg(md
->client
, 0x88, g
->reg88
);
1110 maven_set_reg(md
->client
, 0x89, g
->reg89
);
1111 maven_set_reg(md
->client
, 0x8a, g
->reg8a
);
1112 maven_set_reg(md
->client
, 0x8b, g
->reg8b
);
1115 case MATROXFB_CID_TESTOUT
:
1118 = maven_get_reg(md
->client
, 0x8d);
1119 if (p
->value
) val
|= 0x10;
1121 maven_set_reg(md
->client
, 0x8d, val
);
1124 case MATROXFB_CID_DEFLICKER
:
1126 maven_set_reg(md
->client
, 0x93, maven_compute_deflicker(md
));
1135 static int maven_get_control (struct maven_data
* md
,
1136 struct v4l2_control
*p
) {
1139 i
= get_ctrl_id(p
->id
);
1140 if (i
< 0) return -EINVAL
;
1141 p
->value
= *get_ctrl_ptr(md
, i
);
1145 /******************************************************/
1147 static int maven_out_compute(void* md
, struct my_timming
* mt
) {
1148 #define mdinfo ((struct maven_data*)md)
1149 #define minfo (mdinfo->primary_head)
1150 return maven_compute_timming(md
, mt
, &minfo
->hw
.maven
);
1155 static int maven_out_program(void* md
) {
1156 #define mdinfo ((struct maven_data*)md)
1157 #define minfo (mdinfo->primary_head)
1158 return maven_program_timming(md
, &minfo
->hw
.maven
);
1163 static int maven_out_start(void* md
) {
1164 return maven_resync(md
);
1167 static int maven_out_verify_mode(void* md
, u_int32_t arg
) {
1169 case MATROXFB_OUTPUT_MODE_PAL
:
1170 case MATROXFB_OUTPUT_MODE_NTSC
:
1171 case MATROXFB_OUTPUT_MODE_MONITOR
:
1177 static int maven_out_get_queryctrl(void* md
, struct v4l2_queryctrl
* p
) {
1178 return maven_get_queryctrl(md
, p
);
1181 static int maven_out_get_ctrl(void* md
, struct v4l2_control
* p
) {
1182 return maven_get_control(md
, p
);
1185 static int maven_out_set_ctrl(void* md
, struct v4l2_control
* p
) {
1186 return maven_set_control(md
, p
);
1189 static struct matrox_altout maven_altout
= {
1190 .name
= "Secondary output",
1191 .compute
= maven_out_compute
,
1192 .program
= maven_out_program
,
1193 .start
= maven_out_start
,
1194 .verifymode
= maven_out_verify_mode
,
1195 .getqueryctrl
= maven_out_get_queryctrl
,
1196 .getctrl
= maven_out_get_ctrl
,
1197 .setctrl
= maven_out_set_ctrl
,
1200 static int maven_init_client(struct i2c_client
* clnt
) {
1201 struct maven_data
* md
= i2c_get_clientdata(clnt
);
1202 struct matrox_fb_info
*minfo
= container_of(clnt
->adapter
,
1203 struct i2c_bit_adapter
,
1206 md
->primary_head
= minfo
;
1208 down_write(&minfo
->altout
.lock
);
1209 minfo
->outputs
[1].output
= &maven_altout
;
1210 minfo
->outputs
[1].src
= minfo
->outputs
[1].default_src
;
1211 minfo
->outputs
[1].data
= md
;
1212 minfo
->outputs
[1].mode
= MATROXFB_OUTPUT_MODE_MONITOR
;
1213 up_write(&minfo
->altout
.lock
);
1214 if (maven_get_reg(clnt
, 0xB2) < 0x14) {
1215 md
->version
= MGATVO_B
;
1216 /* Tweak some things for this old chip */
1218 md
->version
= MGATVO_C
;
1221 * Set all parameters to its initial values.
1226 for (i
= 0; i
< MAVCTRLS
; ++i
) {
1227 *get_ctrl_ptr(md
, i
) = maven_controls
[i
].desc
.default_value
;
1234 static int maven_shutdown_client(struct i2c_client
* clnt
) {
1235 struct maven_data
* md
= i2c_get_clientdata(clnt
);
1237 if (md
->primary_head
) {
1238 struct matrox_fb_info
*minfo
= md
->primary_head
;
1240 down_write(&minfo
->altout
.lock
);
1241 minfo
->outputs
[1].src
= MATROXFB_SRC_NONE
;
1242 minfo
->outputs
[1].output
= NULL
;
1243 minfo
->outputs
[1].data
= NULL
;
1244 minfo
->outputs
[1].mode
= MATROXFB_OUTPUT_MODE_MONITOR
;
1245 up_write(&minfo
->altout
.lock
);
1246 md
->primary_head
= NULL
;
1251 static int maven_probe(struct i2c_client
*client
,
1252 const struct i2c_device_id
*id
)
1254 struct i2c_adapter
*adapter
= client
->adapter
;
1256 struct maven_data
* data
;
1258 if (!i2c_check_functionality(adapter
, I2C_FUNC_SMBUS_WRITE_WORD_DATA
|
1259 I2C_FUNC_SMBUS_BYTE_DATA
|
1261 I2C_FUNC_PROTOCOL_MANGLING
))
1263 if (!(data
= kzalloc(sizeof(*data
), GFP_KERNEL
))) {
1267 i2c_set_clientdata(client
, data
);
1268 err
= maven_init_client(client
);
1278 static int maven_remove(struct i2c_client
*client
)
1280 maven_shutdown_client(client
);
1281 kfree(i2c_get_clientdata(client
));
1285 static const struct i2c_device_id maven_id
[] = {
1289 MODULE_DEVICE_TABLE(i2c
, maven_id
);
1291 static struct i2c_driver maven_driver
={
1295 .probe
= maven_probe
,
1296 .remove
= maven_remove
,
1297 .id_table
= maven_id
,
1300 module_i2c_driver(maven_driver
);
1301 MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1302 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1303 MODULE_LICENSE("GPL");