File: /usr/src/linux/drivers/video/matrox/matroxfb_maven.c

1     #include "matroxfb_maven.h"
2     #include "matroxfb_misc.h"
3     #include "matroxfb_DAC1064.h"
4     #include <linux/i2c.h>
5     #include <linux/matroxfb.h>
6     #include <asm/div64.h>
7     #include <asm/uaccess.h>
8     
9     #define MAVEN_I2CID	(0x1B)
10     
11     #define MODE_PAL	MATROXFB_OUTPUT_MODE_PAL
12     #define MODE_NTSC	MATROXFB_OUTPUT_MODE_NTSC
13     #define MODE_TV(x)	(((x) == MODE_PAL) || ((x) == MODE_NTSC))
14     #define MODE_MONITOR	MATROXFB_OUTPUT_MODE_MONITOR
15     
16     struct maven_data {
17     	struct matrox_fb_info*		primary_head;
18     	struct i2c_client*		client;
19     	int				mode;
20     };
21     
22     static int maven_get_reg(struct i2c_client* c, char reg) {
23     	char dst;
24     	struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), &reg },
25     				 { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }};
26     	s32 err;
27     
28     	err = i2c_transfer(c->adapter, msgs, 2);
29     	if (err < 0)
30     		printk(KERN_INFO "ReadReg(%d) failed\n", reg);
31     	return dst & 0xFF;
32     }
33     
34     static int maven_set_reg(struct i2c_client* c, int reg, int val) {
35     	s32 err;
36     
37     	err = i2c_smbus_write_byte_data(c, reg, val);
38     	if (err)
39     		printk(KERN_INFO "WriteReg(%d) failed\n", reg);
40     	return err;
41     }
42     
43     static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) {
44     	s32 err;
45     
46     	err = i2c_smbus_write_word_data(c, reg, val);
47     	if (err)
48     		printk(KERN_INFO "WriteRegPair(%d) failed\n", reg);
49     	return err;
50     }
51     
52     static const struct matrox_pll_features maven_pll = {
53     	50000,
54     	27000,
55     	4, 127,
56     	2, 31,
57     	3
58     };
59     
60     struct matrox_pll_features2 {
61     	unsigned int	vco_freq_min;
62     	unsigned int	vco_freq_max;
63     	unsigned int	feed_div_min;
64     	unsigned int	feed_div_max;
65     	unsigned int	in_div_min;
66     	unsigned int	in_div_max;
67     	unsigned int	post_shift_max;
68     };
69     
70     struct matrox_pll_ctl {
71     	unsigned int	ref_freq;
72     	unsigned int	den;
73     };
74     
75     static const struct matrox_pll_features2 maven1000_pll = {
76     	 50000000,
77     	300000000,
78     	 5, 128,
79     	 3,  32,
80     	 3
81     };
82     
83     static const struct matrox_pll_ctl maven_PAL = {
84     	540000,
85     	    50
86     };
87     
88     static const struct matrox_pll_ctl maven_NTSC = {
89     	450450,	/* 27027000/60 == 27000000/59.94005994 */
90     	    60
91     };
92     
93     static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
94     		const struct matrox_pll_ctl* ctl,
95     		unsigned int htotal, unsigned int vtotal,
96     		unsigned int* in, unsigned int* feed, unsigned int* post,
97     		unsigned int* h2) {
98     	unsigned int besth2 = 0;
99     	unsigned int fxtal = ctl->ref_freq;
100     	unsigned int fmin = pll->vco_freq_min / ctl->den;
101     	unsigned int fwant;
102     	unsigned int p;
103     	unsigned int scrlen;
104     	unsigned int fmax;
105     
106     	DBG("PLL_calcclock")
107     
108     	scrlen = htotal * (vtotal - 1);
109     	fwant = htotal * vtotal;
110     	fmax = pll->vco_freq_max / ctl->den;
111     
112     	printk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
113     		fwant, fxtal, htotal, vtotal, fmax);
114     	for (p = 1; p <= pll->post_shift_max; p++) {
115     		if (fwant * 2 > fmax)
116     			break;
117     		fwant *= 2;
118     	}
119     	if (fwant > fmax)
120     		return 0;
121     	for (; p-- > 0; fwant >>= 1) {
122     		unsigned int m;
123     
124     		if (fwant < fmin) break;
125     		for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
126     			unsigned int n;
127     			unsigned int dvd;
128     			unsigned int ln;
129     
130     			n = (fwant * m) / fxtal;
131     			if (n < pll->feed_div_min)
132     				continue;
133     			if (n > pll->feed_div_max)
134     				break;
135     
136     			ln = fxtal * n;
137     			dvd = m << p;
138     
139     			if (ln % dvd)
140     				continue;
141     			ln = ln / dvd;
142     
143     			if (ln < scrlen + 2)
144     				continue;
145     			ln = ln - scrlen;
146     			if (ln > htotal)
147     				continue;
148     			printk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
149     			if (ln > besth2) {
150     				printk(KERN_DEBUG "Better...\n");
151     				*h2 = besth2 = ln;
152     				*post = p;
153     				*in = m;
154     				*feed = n;
155     			}
156     		}
157     	}
158     	if (besth2 < 2)
159     		return 0;
160     	dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
161     	return fxtal * (*feed) / (*in) * ctl->den;
162     }
163     
164     static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
165     		unsigned int htotal, unsigned int vtotal,
166     		unsigned int* in, unsigned int* feed, unsigned int* post,
167     		unsigned int* htotal2) {
168     	unsigned int fvco;
169     	unsigned int p;
170     
171     	fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
172     	if (!fvco)
173     		return -EINVAL;
174     	p = (1 << p) - 1;
175     	if (fvco <= 100000000)
176     		;
177     	else if (fvco <= 140000000)
178     		p |= 0x08;
179     	else if (fvco <= 180000000)
180     		p |= 0x10;
181     	else
182     		p |= 0x18;
183     	*post = p;
184     	return 0;
185     }
186     
187     static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
188     		unsigned int* in, unsigned int* feed, unsigned int* post) {
189     	unsigned int fvco;
190     	unsigned int p;
191     
192     	fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
193     	p = (1 << p) - 1;
194     	if (fvco <= 100000)
195     		;
196     	else if (fvco <= 140000)
197     		p |= 0x08;
198     	else if (fvco <= 180000)
199     		p |= 0x10;
200     	else
201     		p |= 0x18;
202     	*post = p;
203     	return;
204     }
205     
206     static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
207     	static struct mavenregs palregs = { {
208     		0x2A, 0x09, 0x8A, 0xCB,	/* 00: chroma subcarrier */
209     		0x00,
210     		0x00,	/* ? not written */
211     		0x00,	/* modified by code (F9 written...) */
212     		0x00,	/* ? not written */
213     		0x7E,	/* 08 */
214     		0x44,	/* 09 */
215     		0x9C,	/* 0A */
216     		0x2E,	/* 0B */
217     		0x21,	/* 0C */
218     		0x00,	/* ? not written */
219     		0x3F, 0x03, /* 0E-0F */
220     		0x3F, 0x03, /* 10-11 */
221     		0x1A,	/* 12 */
222     		0x2A,	/* 13 */
223     		0x1C, 0x3D, 0x14, /* 14-16 */
224     		0x9C, 0x01, /* 17-18 */
225     		0x00,	/* 19 */
226     		0xFE,	/* 1A */
227     		0x7E,	/* 1B */
228     		0x60,	/* 1C */
229     		0x05,	/* 1D */
230     		0x89, 0x03, /* 1E-1F */
231     		0x72,	/* 20 */
232     		0x07,	/* 21 */
233     		0x72,	/* 22 */
234     		0x00,	/* 23 */
235     		0x00,	/* 24 */
236     		0x00,	/* 25 */
237     		0x08,	/* 26 */
238     		0x04,	/* 27 */
239     		0x00,	/* 28 */
240     		0x1A,	/* 29 */
241     		0x55, 0x01, /* 2A-2B */
242     		0x26,	/* 2C */
243     		0x07, 0x7E, /* 2D-2E */
244     		0x02, 0x54, /* 2F-30 */
245     		0xB0, 0x00, /* 31-32 */
246     		0x14,	/* 33 */
247     		0x49,	/* 34 */
248     		0x00,	/* 35 written multiple times */
249     		0x00,	/* 36 not written */
250     		0xA3,	/* 37 */
251     		0xC8,	/* 38 */
252     		0x22,	/* 39 */
253     		0x02,	/* 3A */
254     		0x22,	/* 3B */
255     		0x3F, 0x03, /* 3C-3D */
256     		0x00,	/* 3E written multiple times */
257     		0x00,	/* 3F not written */
258     	}, MODE_PAL, 625, 50 };
259     	static struct mavenregs ntscregs = { {
260     		0x21, 0xF0, 0x7C, 0x1F,	/* 00: chroma subcarrier */
261     		0x00,
262     		0x00,	/* ? not written */
263     		0x00,	/* modified by code (F9 written...) */
264     		0x00,	/* ? not written */
265     		0x7E,	/* 08 */
266     		0x43,	/* 09 */
267     		0x7E,	/* 0A */
268     		0x3D,	/* 0B */
269     		0x00,	/* 0C */
270     		0x00,	/* ? not written */
271     		0x41, 0x00, /* 0E-0F */
272     		0x3C, 0x00, /* 10-11 */
273     		0x17,	/* 12 */
274     		0x21,	/* 13 */
275     		0x1B, 0x1B, 0x24, /* 14-16 */
276     		0x83, 0x01, /* 17-18 */
277     		0x00,	/* 19 */
278     		0x0F,	/* 1A */
279     		0x0F,	/* 1B */
280     		0x60,	/* 1C */
281     		0x05,	/* 1D */
282     		0x89, 0x02, /* 1E-1F */
283     		0x5F,	/* 20 */
284     		0x04,	/* 21 */
285     		0x5F,	/* 22 */
286     		0x01,	/* 23 */
287     		0x02,	/* 24 */
288     		0x00,	/* 25 */
289     		0x0A,	/* 26 */
290     		0x05,	/* 27 */
291     		0x00,	/* 28 */
292     		0x10,	/* 29 */
293     		0xFF, 0x03, /* 2A-2B */
294     		0x24,	/* 2C */
295     		0x0F, 0x78, /* 2D-2E */
296     		0x00, 0x00, /* 2F-30 */
297     		0xB2, 0x04, /* 31-32 */
298     		0x14,	/* 33 */
299     		0x02,	/* 34 */
300     		0x00,	/* 35 written multiple times */
301     		0x00,	/* 36 not written */
302     		0xA3,	/* 37 */
303     		0xC8,	/* 38 */
304     		0x15,	/* 39 */
305     		0x05,	/* 3A */
306     		0x3B,	/* 3B */
307     		0x3C, 0x00, /* 3C-3D */
308     		0x00,	/* 3E written multiple times */
309     		0x00,	/* never written */
310     	}, MODE_NTSC, 525, 60 };
311     
312     	if (md->mode & MODE_PAL)
313     		*data = palregs;
314     	else
315     		*data = ntscregs;
316     
317     	data->regs[0x93] = 0xA2;
318     
319     	/* gamma correction registers */
320     	data->regs[0x83] = 0x00;
321     	data->regs[0x84] = 0x00;
322     	data->regs[0x85] = 0x00;
323     	data->regs[0x86] = 0x1F;
324     	data->regs[0x87] = 0x10;
325     	data->regs[0x88] = 0x10;
326     	data->regs[0x89] = 0x10;
327     	data->regs[0x8A] = 0x64;	/* 100 */
328     	data->regs[0x8B] = 0xC8;	/* 200 */
329     
330     	return;
331     }
332     
333     #define LR(x) maven_set_reg(c, (x), m->regs[(x)])
334     #define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
335     static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
336     	int val;
337     
338     
339     	maven_set_reg(c, 0x3E, 0x01);
340     	maven_get_reg(c, 0x82);	/* fetch oscillator state? */
341     	maven_set_reg(c, 0x8C, 0x00);
342     	maven_get_reg(c, 0x94);	/* get 0x82 */
343     	maven_set_reg(c, 0x94, 0xA2);
344     	/* xmiscctrl */
345     
346     	maven_set_reg_pair(c, 0x8E, 0x1EFF);
347     	maven_set_reg(c, 0xC6, 0x01);
348     
349     	/* removed code... */
350     
351     	maven_get_reg(c, 0x06);
352     	maven_set_reg(c, 0x06, 0xF9);	/* or read |= 0xF0 ? */
353     
354     	/* removed code here... */
355     
356     	/* real code begins here? */
357     	/* chroma subcarrier */
358     	LR(0x00); LR(0x01); LR(0x02); LR(0x03);
359     
360     	LR(0x04);
361     
362     	LR(0x2C);
363     	LR(0x08);
364     	LR(0x0A);
365     	LR(0x09);
366     	LR(0x29);
367     	LRP(0x31);
368     	LRP(0x17);
369     	LR(0x0B);
370     	LR(0x0C);
371     	if (m->mode & MODE_PAL) {
372     		maven_set_reg(c, 0x35, 0x10); /* ... */
373     	} else {
374     		maven_set_reg(c, 0x35, 0x0F); /* ... */
375     	}
376     
377     	LRP(0x10);
378     
379     	LRP(0x0E);
380     	LRP(0x1E);
381     
382     	LR(0x20);	/* saturation #1 */
383     	LR(0x22);	/* saturation #2 */
384     	LR(0x25);	/* hue */
385     	LR(0x34);
386     	LR(0x33);
387     	LR(0x19);
388     	LR(0x12);
389     	LR(0x3B);
390     	LR(0x13);
391     	LR(0x39);
392     	LR(0x1D);
393     	LR(0x3A);
394     	LR(0x24);
395     	LR(0x14);
396     	LR(0x15);
397     	LR(0x16);
398     	LRP(0x2D);
399     	LRP(0x2F);
400     	LR(0x1A);
401     	LR(0x1B);
402     	LR(0x1C);
403     	LR(0x23);
404     	LR(0x26);
405     	LR(0x28);
406     	LR(0x27);
407     	LR(0x21);
408     	LRP(0x2A);
409     	if (m->mode & MODE_PAL)
410     		maven_set_reg(c, 0x35, 0x1D);	/* ... */
411     	else
412     		maven_set_reg(c, 0x35, 0x1C);
413     
414     	LRP(0x3C);
415     	LR(0x37);
416     	LR(0x38);
417     	maven_set_reg(c, 0xB3, 0x01);
418     
419     	maven_get_reg(c, 0xB0);	/* read 0x80 */
420     	maven_set_reg(c, 0xB0, 0x08);	/* ugh... */
421     	maven_get_reg(c, 0xB9);	/* read 0x7C */
422     	maven_set_reg(c, 0xB9, 0x78);
423     	maven_get_reg(c, 0xBF);	/* read 0x00 */
424     	maven_set_reg(c, 0xBF, 0x02);
425     	maven_get_reg(c, 0x94);	/* read 0x82 */
426     	maven_set_reg(c, 0x94, 0xB3);
427     
428     	LR(0x80); /* 04 1A 91 or 05 21 91 */
429     	LR(0x81);
430     	LR(0x82);
431     
432     	maven_set_reg(c, 0x8C, 0x20);
433     	maven_get_reg(c, 0x8D);
434     	maven_set_reg(c, 0x8D, 0x10);
435     
436     	LR(0x90); /* 4D 50 52 or 4E 05 45 */
437     	LR(0x91);
438     	LR(0x92);
439     
440     	LRP(0x9A); /* 0049 or 004F */
441     	LRP(0x9C); /* 0004 or 0004 */
442     	LRP(0x9E); /* 0458 or 045E */
443     	LRP(0xA0); /* 05DA or 051B */
444     	LRP(0xA2); /* 00CC or 00CF */
445     	LRP(0xA4); /* 007D or 007F */
446     	LRP(0xA6); /* 007C or 007E */
447     	LRP(0xA8); /* 03CB or 03CE */
448     	LRP(0x98); /* 0000 or 0000 */
449     	LRP(0xAE); /* 0044 or 003A */
450     	LRP(0x96); /* 05DA or 051B */
451     	LRP(0xAA); /* 04BC or 046A */
452     	LRP(0xAC); /* 004D or 004E */
453     
454     	LR(0xBE);
455     	LR(0xC2);
456     
457     	maven_get_reg(c, 0x8D);
458     	maven_set_reg(c, 0x8D, 0x00);
459     
460     	LR(0x20);	/* saturation #1 */
461     	LR(0x22);	/* saturation #2 */
462     	LR(0x93);	/* whoops */
463     	LR(0x20);	/* oh, saturation #1 again */
464     	LR(0x22);	/* oh, saturation #2 again */
465     	LR(0x25);	/* hue */
466     	LRP(0x0E);
467     	LRP(0x1E);
468     	LRP(0x0E);	/* problems with memory? */
469     	LRP(0x1E);	/* yes, matrox must have problems in memory area... */
470     
471     	/* load gamma correction stuff */
472     	LR(0x83);
473     	LR(0x84);
474     	LR(0x85);
475     	LR(0x86);
476     	LR(0x87);
477     	LR(0x88);
478     	LR(0x89);
479     	LR(0x8A);
480     	LR(0x8B);
481     
482     	val = maven_get_reg(c, 0x8D);
483     	val &= 0x10;			/* 0x10 or anything ored with it */
484     	maven_set_reg(c, 0x8D, val);
485     
486     	LR(0x33);
487     	LR(0x19);
488     	LR(0x12);
489     	LR(0x3B);
490     	LR(0x13);
491     	LR(0x39);
492     	LR(0x1D);
493     	LR(0x3A);
494     	LR(0x24);
495     	LR(0x14);
496     	LR(0x15);
497     	LR(0x16);
498     	LRP(0x2D);
499     	LRP(0x2F);
500     	LR(0x1A);
501     	LR(0x1B);
502     	LR(0x1C);
503     	LR(0x23);
504     	LR(0x26);
505     	LR(0x28);
506     	LR(0x27);
507     	LR(0x21);
508     	LRP(0x2A);
509     	if (m->mode & MODE_PAL)
510     		maven_set_reg(c, 0x35, 0x1D);
511     	else
512     		maven_set_reg(c, 0x35, 0x1C);
513     	LRP(0x3C);
514     	LR(0x37);
515     	LR(0x38);
516     
517     	maven_get_reg(c, 0xB0);
518     	LR(0xB0);	/* output mode */
519     	LR(0x90);
520     	LR(0xBE);
521     	LR(0xC2);
522     
523     	LRP(0x9A);
524     	LRP(0xA2);
525     	LRP(0x9E);
526     	LRP(0xA6);
527     	LRP(0xAA);
528     	LRP(0xAC);
529     	maven_set_reg(c, 0x3E, 0x00);
530     	maven_set_reg(c, 0x95, 0x20);
531     }
532     
533     static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
534     		struct mavenregs* m) {
535     	unsigned int x;
536     	unsigned int err = ~0;
537     
538     	/* 1:1 */
539     	m->regs[0x80] = 0x0F;
540     	m->regs[0x81] = 0x07;
541     	m->regs[0x82] = 0x81;
542     
543     	for (x = 0; x < 8; x++) {
544     		unsigned int a, b, c, h2;
545     		unsigned int h = ht + 2 + x;
546     
547     		if (!matroxfb_mavenclock((m->mode & MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
548     			unsigned int diff = h - h2;
549     
550     			if (diff < err) {
551     				err = diff;
552     				m->regs[0x80] = a - 1;
553     				m->regs[0x81] = b - 1;
554     				m->regs[0x82] = c | 0x80;
555     				m->hcorr = h2 - 2;
556     				m->htotal = h - 2;
557     			}
558     		}
559     	}
560     	return err != ~0U;
561     }
562     
563     static inline int maven_compute_timming(struct maven_data* md,
564     		struct my_timming* mt,
565     		struct mavenregs* m) {
566     	unsigned int tmpi;
567     	unsigned int a, bv, c;
568     
569     	m->mode = md->mode;
570     	if (MODE_TV(md->mode)) {
571     		unsigned int lmargin;
572     		unsigned int umargin;
573     		unsigned int vslen;
574     		unsigned int hcrt;
575     		unsigned int slen;
576     
577     		maven_init_TVdata(md, m);
578     
579     		if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
580     			return -EINVAL;
581     
582     		lmargin = mt->HTotal - mt->HSyncEnd;
583     		slen = mt->HSyncEnd - mt->HSyncStart;
584     		hcrt = mt->HTotal - slen - mt->delay;
585     		umargin = mt->VTotal - mt->VSyncEnd;
586     		vslen = mt->VSyncEnd - mt->VSyncStart;
587     
588     		if (m->hcorr < mt->HTotal)
589     			hcrt += m->hcorr;
590     		if (hcrt > mt->HTotal)
591     			hcrt -= mt->HTotal;
592     		if (hcrt + 2 > mt->HTotal)
593     			hcrt = 0;	/* or issue warning? */
594     
595     		/* last (first? middle?) line in picture can have different length */
596     		/* hlen - 2 */
597     		m->regs[0x96] = m->hcorr;
598     		m->regs[0x97] = m->hcorr >> 8;
599     		/* ... */
600     		m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
601     		/* hblanking end */
602     		m->regs[0x9A] = lmargin;	/* 100% */
603     		m->regs[0x9B] = lmargin >> 8;	/* 100% */
604     		/* who knows */
605     		m->regs[0x9C] = 0x04;
606     		m->regs[0x9D] = 0x00;
607     		/* htotal - 2 */
608     		m->regs[0xA0] = m->htotal;
609     		m->regs[0xA1] = m->htotal >> 8;
610     		/* vblanking end */
611     		m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1;	/* stop vblanking */
612     		m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
613     		/* something end... [A6]+1..[A8] */
614     		m->regs[0xA4] = 0x01;
615     		m->regs[0xA5] = 0x00;
616     		/* something start... 0..[A4]-1 */
617     		m->regs[0xA6] = 0x00;
618     		m->regs[0xA7] = 0x00;
619     		/* vertical line count - 1 */
620     		m->regs[0xA8] = mt->VTotal - 1;
621     		m->regs[0xA9] = (mt->VTotal - 1) >> 8;
622     		/* horizontal vidrst pos */
623     		m->regs[0xAA] = hcrt;		/* 0 <= hcrt <= htotal - 2 */
624     		m->regs[0xAB] = hcrt >> 8;
625     		/* vertical vidrst pos */
626     		m->regs[0xAC] = mt->VTotal - 2;
627     		m->regs[0xAD] = (mt->VTotal - 2) >> 8;
628     		/* moves picture up/down and so on... */
629     		m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */
630     		m->regs[0xAF] = 0x00;
631     		{
632     			int hdec;
633     			int hlen;
634     			unsigned int ibmin = 4 + lmargin + mt->HDisplay;
635     			unsigned int ib;
636     			int i;
637     
638     			/* Verify! */
639     			/* Where 94208 came from? */
640     			if (mt->HTotal)
641     				hdec = 94208 / (mt->HTotal);
642     			else
643     				hdec = 0x81;
644     			if (hdec > 0x81)
645     				hdec = 0x81;
646     			if (hdec < 0x41)
647     				hdec = 0x41;
648     			hdec--;
649     			hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
650     			if (hlen < 0)
651     				hlen = 0;
652     			hlen = hlen >> 8;
653     			if (hlen > 0xFF)
654     				hlen = 0xFF;
655     			/* Now we have to compute input buffer length.
656     			   If you want any picture, it must be between
657     			     4 + lmargin + xres
658     			   and
659     			     94208 / hdec
660     			   If you want perfect picture even on the top
661     			   of screen, it must be also
662     			     0x3C0000 * i / hdec + Q - R / hdec
663     			   where
664     			        R      Qmin   Qmax
665     			     0x07000   0x5AE  0x5BF
666     			     0x08000   0x5CF  0x5FF
667     			     0x0C000   0x653  0x67F
668     			     0x10000   0x6F8  0x6FF
669     			 */
670     			i = 1;
671     			do {
672     				ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
673     				i++;
674     			} while (ib < ibmin);
675     			if (ib >= m->htotal + 2) {
676     				ib = ibmin;
677     			}
678     
679     			m->regs[0x90] = hdec;	/* < 0x40 || > 0x80 is bad... 0x80 is questionable */
680     			m->regs[0xC2] = hlen;
681     			/* 'valid' input line length */
682     			m->regs[0x9E] = ib;
683     			m->regs[0x9F] = ib >> 8;
684     		}
685     		{
686     			int vdec;
687     			int vlen;
688     
689     #define MATROX_USE64BIT_DIVIDE
690     			if (mt->VTotal) {
691     #ifdef MATROX_USE64BIT_DIVIDE
692     				u64 f1;
693     				u32 a;
694     				u32 b;
695     
696     				a = m->vlines * (m->htotal + 2);
697     				b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
698     
699     				f1 = ((u64)a) << 15;	/* *32768 */
700     				do_div(f1, b);
701     				vdec = f1;
702     #else
703     				vdec = m->vlines * 32768 / mt->VTotal;
704     #endif
705     			} else
706     				vdec = 0x8000;
707     			if (vdec > 0x8000)
708     				vdec = 0x8000;
709     			vlen = (vslen + umargin + mt->VDisplay) * vdec;
710     			vlen = (vlen >> 16) - 146; /* FIXME: 146?! */
711     			if (vlen < 0)
712     				vlen = 0;
713     			if (vlen > 0xFF)
714     				vlen = 0xFF;
715     			vdec--;
716     			m->regs[0x91] = vdec;
717     			m->regs[0x92] = vdec >> 8;
718     			m->regs[0xBE] = vlen;
719     		}
720     		m->regs[0xB0] = 0x08;	/* output: SVideo/Composite */
721     		return 0;
722     	}
723     
724     	DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
725     	m->regs[0x80] = a;
726     	m->regs[0x81] = bv;
727     	m->regs[0x82] = c | 0x80;
728     
729     	m->regs[0xB3] = 0x01;
730     	m->regs[0x94] = 0xB2;
731     
732     	/* htotal... */
733     	m->regs[0x96] = mt->HTotal;
734     	m->regs[0x97] = mt->HTotal >> 8;
735     	/* ?? */
736     	m->regs[0x98] = 0x00;
737     	m->regs[0x99] = 0x00;
738     	/* hsync len */
739     	tmpi = mt->HSyncEnd - mt->HSyncStart;
740     	m->regs[0x9A] = tmpi;
741     	m->regs[0x9B] = tmpi >> 8;
742     	/* hblank end */
743     	tmpi = mt->HTotal - mt->HSyncStart;
744     	m->regs[0x9C] = tmpi;
745     	m->regs[0x9D] = tmpi >> 8;
746     	/* hblank start */
747     	tmpi += mt->HDisplay;
748     	m->regs[0x9E] = tmpi;
749     	m->regs[0x9F] = tmpi >> 8;
750     	/* htotal + 1 */
751     	tmpi = mt->HTotal + 1;
752     	m->regs[0xA0] = tmpi;
753     	m->regs[0xA1] = tmpi >> 8;
754     	/* vsync?! */
755     	tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
756     	m->regs[0xA2] = tmpi;
757     	m->regs[0xA3] = tmpi >> 8;
758     	/* ignored? */
759     	tmpi = mt->VTotal - mt->VSyncStart;
760     	m->regs[0xA4] = tmpi;
761     	m->regs[0xA5] = tmpi >> 8;
762     	/* ignored? */
763     	tmpi = mt->VTotal - 1;
764     	m->regs[0xA6] = tmpi;
765     	m->regs[0xA7] = tmpi >> 8;
766     	/* vtotal - 1 */
767     	m->regs[0xA8] = tmpi;
768     	m->regs[0xA9] = tmpi >> 8;
769     	/* hor vidrst */
770     	tmpi = mt->HTotal - mt->delay;
771     	m->regs[0xAA] = tmpi;
772     	m->regs[0xAB] = tmpi >> 8;
773     	/* vert vidrst */
774     	tmpi = mt->VTotal - 2;
775     	m->regs[0xAC] = tmpi;
776     	m->regs[0xAD] = tmpi >> 8;
777     	/* ignored? */
778     	m->regs[0xAE] = 0x00;
779     	m->regs[0xAF] = 0x00;
780     
781     	m->regs[0xB0] = 0x03;	/* output: monitor */
782     	m->regs[0xB1] = 0xA0;	/* ??? */
783     	m->regs[0x8C] = 0x20;	/* must be set... */
784     	m->regs[0x8D] = 0x00;	/* defaults to 0x10: test signal */
785     	m->regs[0xB9] = 0x1A;	/* defaults to 0x2C: too bright */
786     	m->regs[0xBF] = 0x22;	/* makes picture stable */
787     
788     	return 0;
789     }
790     
791     static inline int maven_program_timming(struct maven_data* md,
792     		const struct mavenregs* m) {
793     	struct i2c_client* c = md->client;
794     
795     	if (m->mode & MODE_MONITOR) {
796     		LR(0x80);
797     		LR(0x81);
798     		LR(0x82);
799     
800     		LR(0xB3);
801     		LR(0x94);
802     
803     		LRP(0x96);
804     		LRP(0x98);
805     		LRP(0x9A);
806     		LRP(0x9C);
807     		LRP(0x9E);
808     		LRP(0xA0);
809     		LRP(0xA2);
810     		LRP(0xA4);
811     		LRP(0xA6);
812     		LRP(0xA8);
813     		LRP(0xAA);
814     		LRP(0xAC);
815     		LRP(0xAE);
816     
817     		LR(0xB0);	/* output: monitor */
818     		LR(0xB1);	/* ??? */
819     		LR(0x8C);	/* must be set... */
820     		LR(0x8D);	/* defaults to 0x10: test signal */
821     		LR(0xB9);	/* defaults to 0x2C: too bright */
822     		LR(0xBF);	/* makes picture stable */
823     	} else {
824     		maven_init_TV(c, m);
825     	}
826     	return 0;
827     }
828     
829     static inline int maven_resync(struct maven_data* md) {
830     	struct i2c_client* c = md->client;
831     	maven_set_reg(c, 0x95, 0x20);	/* start whole thing */
832     	return 0;
833     }
834     
835     static int maven_set_output_mode(struct maven_data* md, u_int32_t arg) {
836     	switch (arg) {
837     		case MATROXFB_OUTPUT_MODE_PAL:
838     		case MATROXFB_OUTPUT_MODE_NTSC:
839     		case MATROXFB_OUTPUT_MODE_MONITOR:
840     			md->mode = arg;
841     			return 1;
842     	}
843     	return -EINVAL;
844     }
845     
846     static int maven_get_output_mode(struct maven_data* md, u_int32_t *arg) {
847     	*arg = md->mode;
848     	return 0;
849     }
850     
851     /******************************************************/
852     
853     static int maven_out_compute(void* md, struct my_timming* mt, struct matrox_hw_state* mr) {
854     	return maven_compute_timming(md, mt, &mr->maven);
855     }
856     
857     static int maven_out_program(void* md, const struct matrox_hw_state* mr) {
858     	return maven_program_timming(md, &mr->maven);
859     }
860     
861     static int maven_out_start(void* md) {
862     	return maven_resync(md);
863     }
864     
865     static void maven_out_incuse(void* md) {
866     	if (md)
867     		i2c_inc_use_client(((struct maven_data*)md)->client);
868     }
869     
870     static void maven_out_decuse(void* md) {
871     	if (md)
872     		i2c_dec_use_client(((struct maven_data*)md)->client);
873     }
874     
875     static int maven_out_set_mode(void* md, u_int32_t arg) {
876     	return maven_set_output_mode(md, arg);
877     }
878     
879     static int maven_out_get_mode(void* md, u_int32_t* arg) {
880     	return maven_get_output_mode(md, arg);
881     }
882     
883     static struct matrox_altout maven_altout = {
884     	maven_out_compute,
885     	maven_out_program,
886     	maven_out_start,
887     	maven_out_incuse,
888     	maven_out_decuse,
889     	maven_out_set_mode,
890     	maven_out_get_mode
891     };
892     
893     static int maven_init_client(struct i2c_client* clnt) {
894     	struct i2c_adapter* a = clnt->adapter;
895     	struct maven_data* md = clnt->data;
896     	struct matroxfb_dh_maven_info* m2info __attribute__((unused)) = ((struct i2c_bit_adapter*)a)->minfo;
897     	MINFO_FROM(m2info->primary_dev);
898     
899     	md->mode = MODE_MONITOR;
900     	md->primary_head = MINFO;
901     	md->client = clnt;
902     	down_write(&ACCESS_FBINFO(altout.lock));
903     	ACCESS_FBINFO(altout.device) = md;
904     	ACCESS_FBINFO(altout.output) = &maven_altout;
905     	up_write(&ACCESS_FBINFO(altout.lock));
906     	ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
907     	return 0;
908     }
909     
910     static int maven_shutdown_client(struct i2c_client* clnt) {
911     	struct maven_data* md = clnt->data;
912     
913     	if (md->primary_head) {
914     		md->primary_head->output.all &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
915     		md->primary_head->output.ph &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
916     		md->primary_head->output.sh &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
917     		down_write(&md->primary_head->altout.lock);
918     		md->primary_head->altout.device = NULL;
919     		md->primary_head->altout.output = NULL;
920     		up_write(&md->primary_head->altout.lock);
921     		md->primary_head = NULL;
922     	}
923     	return 0;
924     }
925     
926     static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
927     static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END };
928     I2C_CLIENT_INSMOD;
929     
930     static void maven_inc_use(struct i2c_client* clnt) {
931     	MOD_INC_USE_COUNT;
932     }
933     
934     static void maven_dec_use(struct i2c_client* clnt) {
935     	MOD_DEC_USE_COUNT;
936     }
937     
938     static struct i2c_driver maven_driver;
939     
940     static int maven_detect_client(struct i2c_adapter* adapter, int address, unsigned short flags,
941     		int kind) {
942     	int err = 0;
943     	struct i2c_client* new_client;
944     	struct maven_data* data;
945     
946     	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA |
947     					      I2C_FUNC_SMBUS_BYTE_DATA |
948     					      I2C_FUNC_PROTOCOL_MANGLING))
949     		goto ERROR0;
950     	if (!(new_client = (struct i2c_client*)kmalloc(sizeof(struct i2c_client) + sizeof(struct maven_data),
951     			GFP_KERNEL))) {
952     		err = -ENOMEM;
953     		goto ERROR0;
954     	}
955     	data = (struct maven_data*)(new_client + 1);
956     	new_client->data = data;
957     	new_client->addr = address;
958     	new_client->adapter = adapter;
959     	new_client->driver = &maven_driver;
960     	new_client->flags = 0;
961     	if (kind < 0) {
962     		;
963     	}
964     	strcpy(new_client->name, "maven client");
965     	if ((err = i2c_attach_client(new_client)))
966     		goto ERROR3;
967     	err = maven_init_client(new_client);
968     	if (err)
969     		goto ERROR4;
970     	return 0;
971     ERROR4:;
972     	i2c_detach_client(new_client);
973     ERROR3:;
974     	kfree(new_client);
975     ERROR0:;
976     	return err;
977     }
978     
979     static int maven_attach_adapter(struct i2c_adapter* adapter) {
980     	if (adapter->id == (I2C_ALGO_BIT | I2C_HW_B_G400))
981     		return i2c_probe(adapter, &addr_data, &maven_detect_client);
982     	return 0;
983     }
984     
985     static int maven_detach_client(struct i2c_client* client) {
986     	int err;
987     
988     	if ((err = i2c_detach_client(client))) {
989     		printk(KERN_ERR "maven: Cannot deregister client\n");
990     		return err;
991     	}
992     	maven_shutdown_client(client);
993     	kfree(client);
994     	return 0;
995     }
996     
997     static int maven_command(struct i2c_client* client, unsigned int cmd, void* arg) {
998     	return -ENOIOCTLCMD;	/* or -EINVAL, depends on who will call this */
999     }
1000     
1001     static int maven_driver_registered = 0;
1002     
1003     static struct i2c_driver maven_driver={
1004     	"maven",
1005     	I2C_DRIVERID_MGATVO,
1006     	I2C_DF_NOTIFY,
1007     	maven_attach_adapter,
1008     	maven_detach_client,
1009     	maven_command,
1010     	maven_inc_use,
1011     	maven_dec_use
1012     };
1013     
1014     /* ************************** */
1015     
1016     static int matroxfb_maven_init(void) {
1017     	int err;
1018     
1019     	err = i2c_add_driver(&maven_driver);
1020     	if (err) {
1021     		printk(KERN_ERR "maven: Maven driver failed to register (%d).\n", err);
1022     		return err;
1023     	}
1024     	maven_driver_registered = 1;
1025     	return 0;
1026     }
1027     
1028     static void matroxfb_maven_exit(void) {
1029     	if (maven_driver_registered)
1030     		i2c_del_driver(&maven_driver);
1031     }
1032     
1033     MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>");
1034     MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1035     module_init(matroxfb_maven_init);
1036     module_exit(matroxfb_maven_exit);
1037     /* we do not have __setup() yet */
1038