1 // SPDX-License-Identifier: GPL-2.0-only
4 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
6 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
8 * Portions Copyright (c) 2001 Matrox Graphics Inc.
10 * Version: 1.65 2002/08/14
12 * See matroxfb_base.c for contributors.
16 #include "matroxfb_maven.h"
17 #include "matroxfb_misc.h"
18 #include "matroxfb_DAC1064.h"
19 #include <linux/i2c.h>
20 #include <linux/matroxfb.h>
21 #include <linux/slab.h>
22 #include <asm/div64.h>
27 static const struct maven_gamma
{
38 { 131, 57, 223, 15, 117, 212, 251, 91, 156},
39 { 133, 61, 128, 63, 180, 147, 195, 100, 180},
40 { 131, 19, 63, 31, 50, 66, 171, 64, 176},
41 { 0, 0, 0, 31, 16, 16, 16, 100, 200},
42 { 8, 23, 47, 73, 147, 244, 220, 80, 195},
43 { 22, 43, 64, 80, 147, 115, 58, 85, 168},
44 { 34, 60, 80, 214, 147, 212, 188, 85, 167},
45 { 45, 77, 96, 216, 147, 99, 91, 85, 159},
46 { 56, 76, 112, 107, 147, 212, 148, 64, 144},
47 { 65, 91, 128, 137, 147, 196, 17, 69, 148},
48 { 72, 104, 136, 138, 147, 180, 245, 73, 147},
49 { 87, 116, 143, 126, 16, 83, 229, 77, 144},
50 { 95, 119, 152, 254, 244, 83, 221, 77, 151},
51 { 100, 129, 159, 156, 244, 148, 197, 77, 160},
52 { 105, 141, 167, 247, 244, 132, 181, 84, 166},
53 { 105, 147, 168, 247, 244, 245, 181, 90, 170},
54 { 120, 153, 175, 248, 212, 229, 165, 90, 180},
55 { 119, 156, 176, 248, 244, 229, 84, 74, 160},
56 { 119, 158, 183, 248, 244, 229, 149, 78, 165}
59 /* Definition of the various controls */
61 struct v4l2_queryctrl desc
;
68 static const struct mctl maven_controls
[] =
69 { { { V4L2_CID_BRIGHTNESS
, V4L2_CTRL_TYPE_INTEGER
,
71 0, WLMAX
- BLMIN
, 1, 379 - BLMIN
,
73 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.brightness
) },
74 { { V4L2_CID_CONTRAST
, V4L2_CTRL_TYPE_INTEGER
,
78 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.contrast
) },
79 { { V4L2_CID_SATURATION
, V4L2_CTRL_TYPE_INTEGER
,
83 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.saturation
) },
84 { { V4L2_CID_HUE
, V4L2_CTRL_TYPE_INTEGER
,
88 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.hue
) },
89 { { V4L2_CID_GAMMA
, V4L2_CTRL_TYPE_INTEGER
,
91 0, ARRAY_SIZE(maven_gamma
) - 1, 1, 3,
93 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.gamma
) },
94 { { MATROXFB_CID_TESTOUT
, V4L2_CTRL_TYPE_BOOLEAN
,
98 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.testout
) },
99 { { MATROXFB_CID_DEFLICKER
, V4L2_CTRL_TYPE_INTEGER
,
103 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.deflicker
) },
107 #define MAVCTRLS ARRAY_SIZE(maven_controls)
109 /* Return: positive number: id found
110 -EINVAL: id not found, return failure
111 -ENOENT: id not found, create fake disabled control */
112 static int get_ctrl_id(__u32 v4l2_id
) {
115 for (i
= 0; i
< MAVCTRLS
; i
++) {
116 if (v4l2_id
< maven_controls
[i
].desc
.id
) {
117 if (maven_controls
[i
].desc
.id
== 0x08000000) {
122 if (v4l2_id
== maven_controls
[i
].desc
.id
) {
130 struct matrox_fb_info
* primary_head
;
131 struct i2c_client
*client
;
135 static int* get_ctrl_ptr(struct maven_data
* md
, int idx
) {
136 return (int*)((char*)(md
->primary_head
) + maven_controls
[idx
].control
);
139 static int maven_get_reg(struct i2c_client
* c
, char reg
) {
141 struct i2c_msg msgs
[] = {
144 .flags
= I2C_M_REV_DIR_ADDR
,
150 .flags
= I2C_M_RD
| I2C_M_NOSTART
,
157 err
= i2c_transfer(c
->adapter
, msgs
, 2);
159 printk(KERN_INFO
"ReadReg(%d) failed\n", reg
);
163 static int maven_set_reg(struct i2c_client
* c
, int reg
, int val
) {
166 err
= i2c_smbus_write_byte_data(c
, reg
, val
);
168 printk(KERN_INFO
"WriteReg(%d) failed\n", reg
);
172 static int maven_set_reg_pair(struct i2c_client
* c
, int reg
, int val
) {
175 err
= i2c_smbus_write_word_data(c
, reg
, val
);
177 printk(KERN_INFO
"WriteRegPair(%d) failed\n", reg
);
181 static const struct matrox_pll_features maven_pll
= {
189 struct matrox_pll_features2
{
190 unsigned int vco_freq_min
;
191 unsigned int vco_freq_max
;
192 unsigned int feed_div_min
;
193 unsigned int feed_div_max
;
194 unsigned int in_div_min
;
195 unsigned int in_div_max
;
196 unsigned int post_shift_max
;
199 struct matrox_pll_ctl
{
200 unsigned int ref_freq
;
204 static const struct matrox_pll_features2 maven1000_pll
= {
205 .vco_freq_min
= 50000000,
206 .vco_freq_max
= 300000000,
214 static const struct matrox_pll_ctl maven_PAL
= {
219 static const struct matrox_pll_ctl maven_NTSC
= {
220 .ref_freq
= 450450, /* 27027000/60 == 27000000/59.94005994 */
224 static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2
* pll
,
225 const struct matrox_pll_ctl
* ctl
,
226 unsigned int htotal
, unsigned int vtotal
,
227 unsigned int* in
, unsigned int* feed
, unsigned int* post
,
229 unsigned int besth2
= 0;
230 unsigned int fxtal
= ctl
->ref_freq
;
231 unsigned int fmin
= pll
->vco_freq_min
/ ctl
->den
;
239 scrlen
= htotal
* (vtotal
- 1);
240 fwant
= htotal
* vtotal
;
241 fmax
= pll
->vco_freq_max
/ ctl
->den
;
243 dprintk(KERN_DEBUG
"want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
244 fwant
, fxtal
, htotal
, vtotal
, fmax
);
245 for (p
= 1; p
<= pll
->post_shift_max
; p
++) {
246 if (fwant
* 2 > fmax
)
252 for (; p
-- > 0; fwant
>>= 1) {
255 if (fwant
< fmin
) break;
256 for (m
= pll
->in_div_min
; m
<= pll
->in_div_max
; m
++) {
261 n
= (fwant
* m
) / fxtal
;
262 if (n
< pll
->feed_div_min
)
264 if (n
> pll
->feed_div_max
)
279 dprintk(KERN_DEBUG
"Match: %u / %u / %u / %u\n", n
, m
, p
, ln
);
281 dprintk(KERN_DEBUG
"Better...\n");
290 /* if h2/post/in/feed have not been assigned, return zero (error) */
294 dprintk(KERN_ERR
"clk: %02X %02X %02X %d %d\n", *in
, *feed
, *post
, fxtal
, fwant
);
295 return fxtal
* (*feed
) / (*in
) * ctl
->den
;
298 static int matroxfb_mavenclock(const struct matrox_pll_ctl
*ctl
,
299 unsigned int htotal
, unsigned int vtotal
,
300 unsigned int* in
, unsigned int* feed
, unsigned int* post
,
301 unsigned int* htotal2
) {
305 fvco
= matroxfb_PLL_mavenclock(&maven1000_pll
, ctl
, htotal
, vtotal
, in
, feed
, &p
, htotal2
);
309 if (fvco
<= 100000000)
311 else if (fvco
<= 140000000)
313 else if (fvco
<= 180000000)
321 static void DAC1064_calcclock(unsigned int freq
, unsigned int fmax
,
322 unsigned int* in
, unsigned int* feed
, unsigned int* post
) {
326 fvco
= matroxfb_PLL_calcclock(&maven_pll
, freq
, fmax
, in
, feed
, &p
);
330 else if (fvco
<= 140000)
332 else if (fvco
<= 180000)
340 static unsigned char maven_compute_deflicker (const struct maven_data
* md
) {
343 df
= (md
->version
== MGATVO_B
?0x40:0x00);
344 switch (md
->primary_head
->altout
.tvo_params
.deflicker
) {
358 static void maven_compute_bwlevel (const struct maven_data
* md
,
360 const int b
= md
->primary_head
->altout
.tvo_params
.brightness
+ BLMIN
;
361 const int c
= md
->primary_head
->altout
.tvo_params
.contrast
;
363 *bl
= max(b
- c
, BLMIN
);
364 *wl
= min(b
+ c
, WLMAX
);
367 static const struct maven_gamma
* maven_compute_gamma (const struct maven_data
* md
) {
368 return maven_gamma
+ md
->primary_head
->altout
.tvo_params
.gamma
;
372 static void maven_init_TVdata(const struct maven_data
* md
, struct mavenregs
* data
) {
373 static struct mavenregs palregs
= { {
374 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
376 0x00, /* ? not written */
377 0x00, /* modified by code (F9 written...) */
378 0x00, /* ? not written */
384 0x00, /* ? not written */
385 0x3F, 0x03, /* 0E-0F */
386 0x3F, 0x03, /* 10-11 */
389 0x1C, 0x3D, 0x14, /* 14-16 */
390 0x9C, 0x01, /* 17-18 */
396 0x89, 0x03, /* 1E-1F */
407 0x55, 0x01, /* 2A-2B */
409 0x07, 0x7E, /* 2D-2E */
410 0x02, 0x54, /* 2F-30 */
411 0xB0, 0x00, /* 31-32 */
414 0x00, /* 35 written multiple times */
415 0x00, /* 36 not written */
421 0x3F, 0x03, /* 3C-3D */
422 0x00, /* 3E written multiple times */
423 0x00, /* 3F not written */
424 }, MATROXFB_OUTPUT_MODE_PAL
, 625, 50 };
425 static struct mavenregs ntscregs
= { {
426 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
428 0x00, /* ? not written */
429 0x00, /* modified by code (F9 written...) */
430 0x00, /* ? not written */
436 0x00, /* ? not written */
437 0x41, 0x00, /* 0E-0F */
438 0x3C, 0x00, /* 10-11 */
441 0x1B, 0x1B, 0x24, /* 14-16 */
442 0x83, 0x01, /* 17-18 */
448 0x89, 0x02, /* 1E-1F */
459 0xFF, 0x03, /* 2A-2B */
461 0x0F, 0x78, /* 2D-2E */
462 0x00, 0x00, /* 2F-30 */
463 0xB2, 0x04, /* 31-32 */
466 0x00, /* 35 written multiple times */
467 0x00, /* 36 not written */
473 0x3C, 0x00, /* 3C-3D */
474 0x00, /* 3E written multiple times */
475 0x00, /* never written */
476 }, MATROXFB_OUTPUT_MODE_NTSC
, 525, 60 };
477 struct matrox_fb_info
*minfo
= md
->primary_head
;
479 if (minfo
->outputs
[1].mode
== MATROXFB_OUTPUT_MODE_PAL
)
485 data
->regs
[0x93] = maven_compute_deflicker(md
);
489 const struct maven_gamma
* g
;
490 g
= maven_compute_gamma(md
);
491 data
->regs
[0x83] = g
->reg83
;
492 data
->regs
[0x84] = g
->reg84
;
493 data
->regs
[0x85] = g
->reg85
;
494 data
->regs
[0x86] = g
->reg86
;
495 data
->regs
[0x87] = g
->reg87
;
496 data
->regs
[0x88] = g
->reg88
;
497 data
->regs
[0x89] = g
->reg89
;
498 data
->regs
[0x8A] = g
->reg8a
;
499 data
->regs
[0x8B] = g
->reg8b
;
502 /* Set contrast / brightness */
505 maven_compute_bwlevel (md
, &bl
, &wl
);
506 data
->regs
[0x0e] = bl
>> 2;
507 data
->regs
[0x0f] = bl
& 3;
508 data
->regs
[0x1e] = wl
>> 2;
509 data
->regs
[0x1f] = wl
& 3;
515 data
->regs
[0x22] = minfo
->altout
.tvo_params
.saturation
;
519 data
->regs
[0x25] = minfo
->altout
.tvo_params
.hue
;
523 #define LR(x) maven_set_reg(c, (x), m->regs[(x)])
524 #define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
525 static void maven_init_TV(struct i2c_client
* c
, const struct mavenregs
* m
) {
529 maven_set_reg(c
, 0x3E, 0x01);
530 maven_get_reg(c
, 0x82); /* fetch oscillator state? */
531 maven_set_reg(c
, 0x8C, 0x00);
532 maven_get_reg(c
, 0x94); /* get 0x82 */
533 maven_set_reg(c
, 0x94, 0xA2);
536 maven_set_reg_pair(c
, 0x8E, 0x1EFF);
537 maven_set_reg(c
, 0xC6, 0x01);
539 /* removed code... */
541 maven_get_reg(c
, 0x06);
542 maven_set_reg(c
, 0x06, 0xF9); /* or read |= 0xF0 ? */
544 /* removed code here... */
546 /* real code begins here? */
547 /* chroma subcarrier */
548 LR(0x00); LR(0x01); LR(0x02); LR(0x03);
561 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
) {
562 maven_set_reg(c
, 0x35, 0x10); /* ... */
564 maven_set_reg(c
, 0x35, 0x0F); /* ... */
572 LR(0x20); /* saturation #1 */
573 LR(0x22); /* saturation #2 */
599 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
)
600 maven_set_reg(c
, 0x35, 0x1D); /* ... */
602 maven_set_reg(c
, 0x35, 0x1C);
607 maven_set_reg(c
, 0xB3, 0x01);
609 maven_get_reg(c
, 0xB0); /* read 0x80 */
610 maven_set_reg(c
, 0xB0, 0x08); /* ugh... */
611 maven_get_reg(c
, 0xB9); /* read 0x7C */
612 maven_set_reg(c
, 0xB9, 0x78);
613 maven_get_reg(c
, 0xBF); /* read 0x00 */
614 maven_set_reg(c
, 0xBF, 0x02);
615 maven_get_reg(c
, 0x94); /* read 0x82 */
616 maven_set_reg(c
, 0x94, 0xB3);
618 LR(0x80); /* 04 1A 91 or 05 21 91 */
622 maven_set_reg(c
, 0x8C, 0x20);
623 maven_get_reg(c
, 0x8D);
624 maven_set_reg(c
, 0x8D, 0x10);
626 LR(0x90); /* 4D 50 52 or 4E 05 45 */
630 LRP(0x9A); /* 0049 or 004F */
631 LRP(0x9C); /* 0004 or 0004 */
632 LRP(0x9E); /* 0458 or 045E */
633 LRP(0xA0); /* 05DA or 051B */
634 LRP(0xA2); /* 00CC or 00CF */
635 LRP(0xA4); /* 007D or 007F */
636 LRP(0xA6); /* 007C or 007E */
637 LRP(0xA8); /* 03CB or 03CE */
638 LRP(0x98); /* 0000 or 0000 */
639 LRP(0xAE); /* 0044 or 003A */
640 LRP(0x96); /* 05DA or 051B */
641 LRP(0xAA); /* 04BC or 046A */
642 LRP(0xAC); /* 004D or 004E */
647 maven_get_reg(c
, 0x8D);
648 maven_set_reg(c
, 0x8D, 0x04);
650 LR(0x20); /* saturation #1 */
651 LR(0x22); /* saturation #2 */
652 LR(0x93); /* whoops */
653 LR(0x20); /* oh, saturation #1 again */
654 LR(0x22); /* oh, saturation #2 again */
658 LRP(0x0E); /* problems with memory? */
659 LRP(0x1E); /* yes, matrox must have problems in memory area... */
661 /* load gamma correction stuff */
672 val
= maven_get_reg(c
, 0x8D);
673 val
&= 0x14; /* 0x10 or anything ored with it */
674 maven_set_reg(c
, 0x8D, val
);
699 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
)
700 maven_set_reg(c
, 0x35, 0x1D);
702 maven_set_reg(c
, 0x35, 0x1C);
707 maven_get_reg(c
, 0xB0);
708 LR(0xB0); /* output mode */
719 maven_set_reg(c
, 0x3E, 0x00);
720 maven_set_reg(c
, 0x95, 0x20);
723 static int maven_find_exact_clocks(unsigned int ht
, unsigned int vt
,
724 struct mavenregs
* m
) {
726 unsigned int err
= ~0;
729 m
->regs
[0x80] = 0x0F;
730 m
->regs
[0x81] = 0x07;
731 m
->regs
[0x82] = 0x81;
733 for (x
= 0; x
< 8; x
++) {
737 unsigned int h
= ht
+ 2 + x
;
739 if (!matroxfb_mavenclock((m
->mode
== MATROXFB_OUTPUT_MODE_PAL
) ? &maven_PAL
: &maven_NTSC
, h
, vt
, &a
, &b
, &c
, &h2
)) {
740 unsigned int diff
= h
- h2
;
744 m
->regs
[0x80] = a
- 1;
745 m
->regs
[0x81] = b
- 1;
746 m
->regs
[0x82] = c
| 0x80;
755 static inline int maven_compute_timming(struct maven_data
* md
,
756 struct my_timming
* mt
,
757 struct mavenregs
* m
) {
759 unsigned int a
, bv
, c
;
760 struct matrox_fb_info
*minfo
= md
->primary_head
;
762 m
->mode
= minfo
->outputs
[1].mode
;
763 if (m
->mode
!= MATROXFB_OUTPUT_MODE_MONITOR
) {
764 unsigned int lmargin
;
765 unsigned int umargin
;
770 maven_init_TVdata(md
, m
);
772 if (maven_find_exact_clocks(mt
->HTotal
, mt
->VTotal
, m
) == 0)
775 lmargin
= mt
->HTotal
- mt
->HSyncEnd
;
776 slen
= mt
->HSyncEnd
- mt
->HSyncStart
;
777 hcrt
= mt
->HTotal
- slen
- mt
->delay
;
778 umargin
= mt
->VTotal
- mt
->VSyncEnd
;
779 vslen
= mt
->VSyncEnd
- mt
->VSyncStart
;
781 if (m
->hcorr
< mt
->HTotal
)
783 if (hcrt
> mt
->HTotal
)
785 if (hcrt
+ 2 > mt
->HTotal
)
786 hcrt
= 0; /* or issue warning? */
788 /* last (first? middle?) line in picture can have different length */
790 m
->regs
[0x96] = m
->hcorr
;
791 m
->regs
[0x97] = m
->hcorr
>> 8;
793 m
->regs
[0x98] = 0x00; m
->regs
[0x99] = 0x00;
795 m
->regs
[0x9A] = lmargin
; /* 100% */
796 m
->regs
[0x9B] = lmargin
>> 8; /* 100% */
798 m
->regs
[0x9C] = 0x04;
799 m
->regs
[0x9D] = 0x00;
801 m
->regs
[0xA0] = m
->htotal
;
802 m
->regs
[0xA1] = m
->htotal
>> 8;
804 m
->regs
[0xA2] = mt
->VTotal
- mt
->VSyncStart
- 1; /* stop vblanking */
805 m
->regs
[0xA3] = (mt
->VTotal
- mt
->VSyncStart
- 1) >> 8;
806 /* something end... [A6]+1..[A8] */
807 if (md
->version
== MGATVO_B
) {
808 m
->regs
[0xA4] = 0x04;
809 m
->regs
[0xA5] = 0x00;
811 m
->regs
[0xA4] = 0x01;
812 m
->regs
[0xA5] = 0x00;
814 /* something start... 0..[A4]-1 */
815 m
->regs
[0xA6] = 0x00;
816 m
->regs
[0xA7] = 0x00;
817 /* vertical line count - 1 */
818 m
->regs
[0xA8] = mt
->VTotal
- 1;
819 m
->regs
[0xA9] = (mt
->VTotal
- 1) >> 8;
820 /* horizontal vidrst pos */
821 m
->regs
[0xAA] = hcrt
; /* 0 <= hcrt <= htotal - 2 */
822 m
->regs
[0xAB] = hcrt
>> 8;
823 /* vertical vidrst pos */
824 m
->regs
[0xAC] = mt
->VTotal
- 2;
825 m
->regs
[0xAD] = (mt
->VTotal
- 2) >> 8;
826 /* moves picture up/down and so on... */
827 m
->regs
[0xAE] = 0x01; /* Fix this... 0..VTotal */
828 m
->regs
[0xAF] = 0x00;
832 unsigned int ibmin
= 4 + lmargin
+ mt
->HDisplay
;
837 /* Where 94208 came from? */
839 hdec
= 94208 / (mt
->HTotal
);
847 hlen
= 98304 - 128 - ((lmargin
+ mt
->HDisplay
- 8) * hdec
);
853 /* Now we have to compute input buffer length.
854 If you want any picture, it must be between
858 If you want perfect picture even on the top
859 of screen, it must be also
860 0x3C0000 * i / hdec + Q - R / hdec
870 ib
= ((0x3C0000 * i
- 0x8000)/ hdec
+ 0x05E7) >> 8;
872 } while (ib
< ibmin
);
873 if (ib
>= m
->htotal
+ 2) {
877 m
->regs
[0x90] = hdec
; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
878 m
->regs
[0xC2] = hlen
;
879 /* 'valid' input line length */
881 m
->regs
[0x9F] = ib
>> 8;
887 #define MATROX_USE64BIT_DIVIDE
889 #ifdef MATROX_USE64BIT_DIVIDE
894 a
= m
->vlines
* (m
->htotal
+ 2);
895 b
= (mt
->VTotal
- 1) * (m
->htotal
+ 2) + m
->hcorr
+ 2;
897 f1
= ((u64
)a
) << 15; /* *32768 */
901 vdec
= m
->vlines
* 32768 / mt
->VTotal
;
907 vlen
= (vslen
+ umargin
+ mt
->VDisplay
) * vdec
;
908 vlen
= (vlen
>> 16) - 146; /* FIXME: 146?! */
914 m
->regs
[0x91] = vdec
;
915 m
->regs
[0x92] = vdec
>> 8;
916 m
->regs
[0xBE] = vlen
;
918 m
->regs
[0xB0] = 0x08; /* output: SVideo/Composite */
922 DAC1064_calcclock(mt
->pixclock
, 450000, &a
, &bv
, &c
);
925 m
->regs
[0x82] = c
| 0x80;
927 m
->regs
[0xB3] = 0x01;
928 m
->regs
[0x94] = 0xB2;
931 m
->regs
[0x96] = mt
->HTotal
;
932 m
->regs
[0x97] = mt
->HTotal
>> 8;
934 m
->regs
[0x98] = 0x00;
935 m
->regs
[0x99] = 0x00;
937 tmpi
= mt
->HSyncEnd
- mt
->HSyncStart
;
938 m
->regs
[0x9A] = tmpi
;
939 m
->regs
[0x9B] = tmpi
>> 8;
941 tmpi
= mt
->HTotal
- mt
->HSyncStart
;
942 m
->regs
[0x9C] = tmpi
;
943 m
->regs
[0x9D] = tmpi
>> 8;
945 tmpi
+= mt
->HDisplay
;
946 m
->regs
[0x9E] = tmpi
;
947 m
->regs
[0x9F] = tmpi
>> 8;
949 tmpi
= mt
->HTotal
+ 1;
950 m
->regs
[0xA0] = tmpi
;
951 m
->regs
[0xA1] = tmpi
>> 8;
953 tmpi
= mt
->VSyncEnd
- mt
->VSyncStart
- 1;
954 m
->regs
[0xA2] = tmpi
;
955 m
->regs
[0xA3] = tmpi
>> 8;
957 tmpi
= mt
->VTotal
- mt
->VSyncStart
;
958 m
->regs
[0xA4] = tmpi
;
959 m
->regs
[0xA5] = tmpi
>> 8;
961 tmpi
= mt
->VTotal
- 1;
962 m
->regs
[0xA6] = tmpi
;
963 m
->regs
[0xA7] = tmpi
>> 8;
965 m
->regs
[0xA8] = tmpi
;
966 m
->regs
[0xA9] = tmpi
>> 8;
968 tmpi
= mt
->HTotal
- mt
->delay
;
969 m
->regs
[0xAA] = tmpi
;
970 m
->regs
[0xAB] = tmpi
>> 8;
972 tmpi
= mt
->VTotal
- 2;
973 m
->regs
[0xAC] = tmpi
;
974 m
->regs
[0xAD] = tmpi
>> 8;
976 m
->regs
[0xAE] = 0x00;
977 m
->regs
[0xAF] = 0x00;
979 m
->regs
[0xB0] = 0x03; /* output: monitor */
980 m
->regs
[0xB1] = 0xA0; /* ??? */
981 m
->regs
[0x8C] = 0x20; /* must be set... */
982 m
->regs
[0x8D] = 0x04; /* defaults to 0x10: test signal */
983 m
->regs
[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
984 m
->regs
[0xBF] = 0x22; /* makes picture stable */
989 static int maven_program_timming(struct maven_data
* md
,
990 const struct mavenregs
* m
) {
991 struct i2c_client
*c
= md
->client
;
993 if (m
->mode
== MATROXFB_OUTPUT_MODE_MONITOR
) {
1015 LR(0xB0); /* output: monitor */
1017 LR(0x8C); /* must be set... */
1018 LR(0x8D); /* defaults to 0x10: test signal */
1019 LR(0xB9); /* defaults to 0x2C: too bright */
1020 LR(0xBF); /* makes picture stable */
1022 maven_init_TV(c
, m
);
1027 static inline int maven_resync(struct maven_data
* md
) {
1028 struct i2c_client
*c
= md
->client
;
1029 maven_set_reg(c
, 0x95, 0x20); /* start whole thing */
1033 static int maven_get_queryctrl (struct maven_data
* md
,
1034 struct v4l2_queryctrl
*p
) {
1037 i
= get_ctrl_id(p
->id
);
1039 *p
= maven_controls
[i
].desc
;
1043 static const struct v4l2_queryctrl disctrl
=
1044 { .flags
= V4L2_CTRL_FLAG_DISABLED
};
1049 sprintf(p
->name
, "Ctrl #%08X", i
);
1055 static int maven_set_control (struct maven_data
* md
,
1056 struct v4l2_control
*p
) {
1059 i
= get_ctrl_id(p
->id
);
1060 if (i
< 0) return -EINVAL
;
1065 if (p
->value
== *get_ctrl_ptr(md
, i
)) return 0;
1070 if (p
->value
> maven_controls
[i
].desc
.maximum
) return -EINVAL
;
1071 if (p
->value
< maven_controls
[i
].desc
.minimum
) return -EINVAL
;
1076 *get_ctrl_ptr(md
, i
) = p
->value
;
1079 case V4L2_CID_BRIGHTNESS
:
1080 case V4L2_CID_CONTRAST
:
1082 int blacklevel
, whitelevel
;
1083 maven_compute_bwlevel(md
, &blacklevel
, &whitelevel
);
1084 blacklevel
= (blacklevel
>> 2) | ((blacklevel
& 3) << 8);
1085 whitelevel
= (whitelevel
>> 2) | ((whitelevel
& 3) << 8);
1086 maven_set_reg_pair(md
->client
, 0x0e, blacklevel
);
1087 maven_set_reg_pair(md
->client
, 0x1e, whitelevel
);
1090 case V4L2_CID_SATURATION
:
1092 maven_set_reg(md
->client
, 0x20, p
->value
);
1093 maven_set_reg(md
->client
, 0x22, p
->value
);
1098 maven_set_reg(md
->client
, 0x25, p
->value
);
1101 case V4L2_CID_GAMMA
:
1103 const struct maven_gamma
* g
;
1104 g
= maven_compute_gamma(md
);
1105 maven_set_reg(md
->client
, 0x83, g
->reg83
);
1106 maven_set_reg(md
->client
, 0x84, g
->reg84
);
1107 maven_set_reg(md
->client
, 0x85, g
->reg85
);
1108 maven_set_reg(md
->client
, 0x86, g
->reg86
);
1109 maven_set_reg(md
->client
, 0x87, g
->reg87
);
1110 maven_set_reg(md
->client
, 0x88, g
->reg88
);
1111 maven_set_reg(md
->client
, 0x89, g
->reg89
);
1112 maven_set_reg(md
->client
, 0x8a, g
->reg8a
);
1113 maven_set_reg(md
->client
, 0x8b, g
->reg8b
);
1116 case MATROXFB_CID_TESTOUT
:
1119 = maven_get_reg(md
->client
, 0x8d);
1120 if (p
->value
) val
|= 0x10;
1122 maven_set_reg(md
->client
, 0x8d, val
);
1125 case MATROXFB_CID_DEFLICKER
:
1127 maven_set_reg(md
->client
, 0x93, maven_compute_deflicker(md
));
1136 static int maven_get_control (struct maven_data
* md
,
1137 struct v4l2_control
*p
) {
1140 i
= get_ctrl_id(p
->id
);
1141 if (i
< 0) return -EINVAL
;
1142 p
->value
= *get_ctrl_ptr(md
, i
);
1146 /******************************************************/
1148 static int maven_out_compute(void* md
, struct my_timming
* mt
) {
1149 #define mdinfo ((struct maven_data*)md)
1150 #define minfo (mdinfo->primary_head)
1151 return maven_compute_timming(md
, mt
, &minfo
->hw
.maven
);
1156 static int maven_out_program(void* md
) {
1157 #define mdinfo ((struct maven_data*)md)
1158 #define minfo (mdinfo->primary_head)
1159 return maven_program_timming(md
, &minfo
->hw
.maven
);
1164 static int maven_out_start(void* md
) {
1165 return maven_resync(md
);
1168 static int maven_out_verify_mode(void* md
, u_int32_t arg
) {
1170 case MATROXFB_OUTPUT_MODE_PAL
:
1171 case MATROXFB_OUTPUT_MODE_NTSC
:
1172 case MATROXFB_OUTPUT_MODE_MONITOR
:
1178 static int maven_out_get_queryctrl(void* md
, struct v4l2_queryctrl
* p
) {
1179 return maven_get_queryctrl(md
, p
);
1182 static int maven_out_get_ctrl(void* md
, struct v4l2_control
* p
) {
1183 return maven_get_control(md
, p
);
1186 static int maven_out_set_ctrl(void* md
, struct v4l2_control
* p
) {
1187 return maven_set_control(md
, p
);
1190 static struct matrox_altout maven_altout
= {
1191 .name
= "Secondary output",
1192 .compute
= maven_out_compute
,
1193 .program
= maven_out_program
,
1194 .start
= maven_out_start
,
1195 .verifymode
= maven_out_verify_mode
,
1196 .getqueryctrl
= maven_out_get_queryctrl
,
1197 .getctrl
= maven_out_get_ctrl
,
1198 .setctrl
= maven_out_set_ctrl
,
1201 static int maven_init_client(struct i2c_client
* clnt
) {
1202 struct maven_data
* md
= i2c_get_clientdata(clnt
);
1203 struct matrox_fb_info
*minfo
= container_of(clnt
->adapter
,
1204 struct i2c_bit_adapter
,
1207 md
->primary_head
= minfo
;
1209 down_write(&minfo
->altout
.lock
);
1210 minfo
->outputs
[1].output
= &maven_altout
;
1211 minfo
->outputs
[1].src
= minfo
->outputs
[1].default_src
;
1212 minfo
->outputs
[1].data
= md
;
1213 minfo
->outputs
[1].mode
= MATROXFB_OUTPUT_MODE_MONITOR
;
1214 up_write(&minfo
->altout
.lock
);
1215 if (maven_get_reg(clnt
, 0xB2) < 0x14) {
1216 md
->version
= MGATVO_B
;
1217 /* Tweak some things for this old chip */
1219 md
->version
= MGATVO_C
;
1222 * Set all parameters to its initial values.
1227 for (i
= 0; i
< MAVCTRLS
; ++i
) {
1228 *get_ctrl_ptr(md
, i
) = maven_controls
[i
].desc
.default_value
;
1235 static int maven_shutdown_client(struct i2c_client
* clnt
) {
1236 struct maven_data
* md
= i2c_get_clientdata(clnt
);
1238 if (md
->primary_head
) {
1239 struct matrox_fb_info
*minfo
= md
->primary_head
;
1241 down_write(&minfo
->altout
.lock
);
1242 minfo
->outputs
[1].src
= MATROXFB_SRC_NONE
;
1243 minfo
->outputs
[1].output
= NULL
;
1244 minfo
->outputs
[1].data
= NULL
;
1245 minfo
->outputs
[1].mode
= MATROXFB_OUTPUT_MODE_MONITOR
;
1246 up_write(&minfo
->altout
.lock
);
1247 md
->primary_head
= NULL
;
1252 static int maven_probe(struct i2c_client
*client
,
1253 const struct i2c_device_id
*id
)
1255 struct i2c_adapter
*adapter
= client
->adapter
;
1257 struct maven_data
* data
;
1259 if (!i2c_check_functionality(adapter
, I2C_FUNC_SMBUS_WRITE_WORD_DATA
|
1260 I2C_FUNC_SMBUS_BYTE_DATA
|
1262 I2C_FUNC_PROTOCOL_MANGLING
))
1264 if (!(data
= kzalloc(sizeof(*data
), GFP_KERNEL
))) {
1268 i2c_set_clientdata(client
, data
);
1269 err
= maven_init_client(client
);
1279 static int maven_remove(struct i2c_client
*client
)
1281 maven_shutdown_client(client
);
1282 kfree(i2c_get_clientdata(client
));
1286 static const struct i2c_device_id maven_id
[] = {
1290 MODULE_DEVICE_TABLE(i2c
, maven_id
);
1292 static struct i2c_driver maven_driver
={
1296 .probe
= maven_probe
,
1297 .remove
= maven_remove
,
1298 .id_table
= maven_id
,
1301 module_i2c_driver(maven_driver
);
1302 MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1303 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1304 MODULE_LICENSE("GPL");