xref: /plan9/sys/src/cmd/aux/vga/mach64xx.c (revision a84536681645e23c630ce4ef2e5c3b284d4c590b)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 
5 #include "pci.h"
6 #include "vga.h"
7 
8 /*
9  * ATI Mach64 family.
10  */
11 enum {
12 	HTotalDisp,
13 	HSyncStrtWid,
14 	VTotalDisp,
15 	VSyncStrtWid,
16 	VlineCrntVline,
17 	OffPitch,
18 	IntCntl,
19 	CrtcGenCntl,
20 
21 	OvrClr,
22 	OvrWidLR,
23 	OvrWidTB,
24 
25 	CurClr0,
26 	CurClr1,
27 	CurOffset,
28 	CurHVposn,
29 	CurHVoff,
30 
31 	ScratchReg0,
32 	ScratchReg1,	/* Scratch Register (BIOS info) */
33 	ClockCntl,
34 	BusCntl,
35 	MemCntl,
36 	ExtMemCntl,
37 	MemVgaWpSel,
38 	MemVgaRpSel,
39 	DacRegs,
40 	DacCntl,
41 	GenTestCntl,
42 	ConfigCntl,	/* Configuration control */
43 	ConfigChipId,
44 	ConfigStat0,	/* Configuration status 0 */
45 	ConfigStat1,	/* Configuration status 1 */
46 	ConfigStat2,
47 	DspConfig,	/* Rage */
48 	DspOnOff,	/* Rage */
49 
50 	DpBkgdClr,
51 	DpChainMsk,
52 	DpFrgdClr,
53 	DpMix,
54 	DpPixWidth,
55 	DpSrc,
56 	DpWriteMsk,
57 
58 	LcdIndex,
59 	LcdData,
60 
61 	Nreg,
62 
63 	TvIndex = 0x1D,
64 	TvData = 0x27,
65 
66 	LCD_ConfigPanel = 0,
67 	LCD_GenCtrl,
68 	LCD_DstnCntl,
69 	LCD_HfbPitchAddr,
70 	LCD_HorzStretch,
71 	LCD_VertStretch,
72 	LCD_ExtVertStretch,
73 	LCD_LtGio,
74 	LCD_PowerMngmnt,
75 	LCD_ZvgPio,
76 	Nlcd,
77 };
78 
79 static char* iorname[Nreg] = {
80 	"HTotalDisp",
81 	"HSyncStrtWid",
82 	"VTotalDisp",
83 	"VSyncStrtWid",
84 	"VlineCrntVline",
85 	"OffPitch",
86 	"IntCntl",
87 	"CrtcGenCntl",
88 
89 	"OvrClr",
90 	"OvrWidLR",
91 	"OvrWidTB",
92 
93 	"CurClr0",
94 	"CurClr1",
95 	"CurOffset",
96 	"CurHVposn",
97 	"CurHVoff",
98 
99 	"ScratchReg0",
100 	"ScratchReg1",
101 	"ClockCntl",
102 	"BusCntl",
103 	"MemCntl",
104 	"ExtMemCntl",
105 	"MemVgaWpSel",
106 	"MemVgaRpSel",
107 	"DacRegs",
108 	"DacCntl",
109 	"GenTestCntl",
110 	"ConfigCntl",
111 	"ConfigChipId",
112 	"ConfigStat0",
113 	"ConfigStat1",
114 	"ConfigStat2",
115 	"DspConfig",
116 	"DspOnOff",
117 
118 	"DpBkgdClr",
119 	"DpChainMsk",
120 	"DpFrgdClr",
121 	"DpMix",
122 	"DpPixWidth",
123 	"DpSrc",
124 	"DpWriteMsk",
125 
126 	"LcdIndex",
127 	"LcdData",
128 };
129 
130 static char* lcdname[Nlcd] = {
131 	"LCD ConfigPanel",
132 	"LCD GenCntl",
133 	"LCD DstnCntl",
134 	"LCD HfbPitchAddr",
135 	"LCD HorzStretch",
136 	"LCD VertStretch",
137 	"LCD ExtVertStretch",
138 	"LCD LtGio",
139 	"LCD PowerMngmnt",
140 	"LCD ZvgPio"
141 };
142 
143 /*
144  * Crummy hack: all io register offsets
145  * here get IOREG or'ed in, so that we can
146  * tell the difference between an uninitialized
147  * array entry and HTotalDisp.
148  */
149 enum {
150 	IOREG = 0x10000,
151 };
152 static ushort ioregs[Nreg] = {
153  [HTotalDisp]		IOREG|0x0000,
154  [HSyncStrtWid]	IOREG|0x0100,
155  [VTotalDisp]		IOREG|0x0200,
156  [VSyncStrtWid]		IOREG|0x0300,
157  [VlineCrntVline]	IOREG|0x0400,
158  [OffPitch]			IOREG|0x0500,
159  [IntCntl]			IOREG|0x0600,
160  [CrtcGenCntl]		IOREG|0x0700,
161  [OvrClr]			IOREG|0x0800,
162  [OvrWidLR]		IOREG|0x0900,
163  [OvrWidTB]		IOREG|0x0A00,
164  [CurClr0]			IOREG|0x0B00,
165  [CurClr1]			IOREG|0x0C00,
166  [CurOffset]		IOREG|0x0D00,
167  [CurHVposn]		IOREG|0x0E00,
168  [CurHVoff]		IOREG|0x0F00,
169  [ScratchReg0]		IOREG|0x1000,
170  [ScratchReg1]		IOREG|0x1100,
171  [ClockCntl]		IOREG|0x1200,
172  [BusCntl]			IOREG|0x1300,
173  [MemCntl]		IOREG|0x1400,
174  [MemVgaWpSel]	IOREG|0x1500,
175  [MemVgaRpSel]	IOREG|0x1600,
176  [DacRegs]		IOREG|0x1700,
177  [DacCntl]			IOREG|0x1800,
178  [GenTestCntl]		IOREG|0x1900,
179  [ConfigCntl]		IOREG|0x1A00,
180  [ConfigChipId]		IOREG|0x1B00,
181  [ConfigStat0]		IOREG|0x1C00,
182  [ConfigStat1]		IOREG|0x1D00,
183 /* [GpIo]				IOREG|0x1E00, */
184 /* [HTotalDisp]			IOREG|0x1F00, 	duplicate, says XFree86 */
185 };
186 
187 static ushort pciregs[Nreg] = {
188   [HTotalDisp]		0x00,
189   [HSyncStrtWid]	0x01,
190   [VTotalDisp]		0x02,
191   [VSyncStrtWid]        0x03,
192   [VlineCrntVline]      0x04,
193   [OffPitch]		0x05,
194   [IntCntl]		0x06,
195   [CrtcGenCntl]		0x07,
196   [DspConfig]		0x08,
197   [DspOnOff]		0x09,
198   [OvrClr]		0x10,
199   [OvrWidLR]		0x11,
200   [OvrWidTB]		0x12,
201   [CurClr0]		0x18,
202   [CurClr1]		0x19,
203   [CurOffset]		0x1A,
204   [CurHVposn]		0x1B,
205   [CurHVoff]		0x1C,
206   [ScratchReg0]		0x20,
207   [ScratchReg1]		0x21,
208   [ClockCntl]		0x24,
209   [BusCntl]		0x28,
210   [LcdIndex]		0x29,
211   [LcdData]		0x2A,
212   [ExtMemCntl]		0x2B,
213   [MemCntl]		0x2C,
214   [MemVgaWpSel]		0x2D,
215   [MemVgaRpSel]		0x2E,
216   [DacRegs]		0x30,
217   [DacCntl]		0x31,
218   [GenTestCntl]		0x34,
219   [ConfigCntl]		0x37,
220   [ConfigChipId]	0x38,
221   [ConfigStat0]		0x39,
222   [ConfigStat1]		0x25,	/* rsc: was 0x3A, but that's not what the LT manual says */
223   [ConfigStat2]		0x26,
224   [DpBkgdClr]		0xB0,
225   [DpChainMsk]		0xB3,
226   [DpFrgdClr]		0xB1,
227   [DpMix]		0xB5,
228   [DpPixWidth]		0xB4,
229   [DpSrc]		0xB6,
230   [DpWriteMsk]		0xB2,
231 };
232 
233 enum {
234 	PLLm		= 0x02,
235 	PLLp		= 0x06,
236 	PLLn0		= 0x07,
237 	PLLn1		= 0x08,
238 	PLLn2		= 0x09,
239 	PLLn3		= 0x0A,
240 	PLLx            = 0x0B,         /* external divisor (Rage) */
241 
242 	Npll		= 32,
243 	Ntv		= 1,		/* actually 256, but not used */
244 };
245 
246 typedef struct Mach64xx	Mach64xx;
247 struct Mach64xx {
248 	ulong	io;
249 	Pcidev*	pci;
250 	int	bigmem;
251 	int	lcdon;
252 	int	lcdpanelid;
253 
254 	ulong	reg[Nreg];
255 	ulong	lcd[Nlcd];
256 	ulong	tv[Ntv];
257 	uchar	pll[Npll];
258 
259 	ulong	(*ior32)(Mach64xx*, int);
260 	void	(*iow32)(Mach64xx*, int, ulong);
261 };
262 
263 static ulong
portior32(Mach64xx * mp,int r)264 portior32(Mach64xx* mp, int r)
265 {
266 	if((ioregs[r] & IOREG) == 0)
267 		return ~0;
268 
269 	return inportl(((ioregs[r] & ~IOREG)<<2)+mp->io);
270 }
271 
272 static void
portiow32(Mach64xx * mp,int r,ulong l)273 portiow32(Mach64xx* mp, int r, ulong l)
274 {
275 	if((ioregs[r] & IOREG) == 0)
276 		return;
277 
278 	outportl(((ioregs[r] & ~IOREG)<<2)+mp->io, l);
279 }
280 
281 static ulong
pciior32(Mach64xx * mp,int r)282 pciior32(Mach64xx* mp, int r)
283 {
284 	return inportl((pciregs[r]<<2)+mp->io);
285 }
286 
287 static void
pciiow32(Mach64xx * mp,int r,ulong l)288 pciiow32(Mach64xx* mp, int r, ulong l)
289 {
290 	outportl((pciregs[r]<<2)+mp->io, l);
291 }
292 
293 static uchar
pllr(Mach64xx * mp,int r)294 pllr(Mach64xx* mp, int r)
295 {
296 	int io;
297 
298 	if(mp->ior32 == portior32)
299 		io = ((ioregs[ClockCntl]&~IOREG)<<2)+mp->io;
300 	else
301 		io = (pciregs[ClockCntl]<<2)+mp->io;
302 
303 	outportb(io+1, r<<2);
304 	return inportb(io+2);
305 }
306 
307 static void
pllw(Mach64xx * mp,int r,uchar b)308 pllw(Mach64xx* mp, int r, uchar b)
309 {
310 	int io;
311 
312 	if(mp->ior32 == portior32)
313 		io = ((ioregs[ClockCntl]&~IOREG)<<2)+mp->io;
314 	else
315 		io = (pciregs[ClockCntl]<<2)+mp->io;
316 
317 	outportb(io+1, (r<<2)|0x02);
318 	outportb(io+2, b);
319 }
320 
321 static ulong
lcdr32(Mach64xx * mp,ulong r)322 lcdr32(Mach64xx *mp, ulong r)
323 {
324 	ulong or;
325 
326 	or = mp->ior32(mp, LcdIndex);
327 	mp->iow32(mp, LcdIndex, (or&~0x0F) | (r&0x0F));
328 	return mp->ior32(mp, LcdData);
329 }
330 
331 static void
lcdw32(Mach64xx * mp,ulong r,ulong v)332 lcdw32(Mach64xx *mp, ulong r, ulong v)
333 {
334 	ulong or;
335 
336 	or = mp->ior32(mp, LcdIndex);
337 	mp->iow32(mp, LcdIndex, (or&~0x0F) | (r&0x0F));
338 	mp->iow32(mp, LcdData, v);
339 }
340 
341 static ulong
tvr32(Mach64xx * mp,ulong r)342 tvr32(Mach64xx *mp, ulong r)
343 {
344 	outportb(mp->io+(TvIndex<<2), r&0x0F);
345 	return inportl(mp->io+(TvData<<2));
346 }
347 
348 static void
tvw32(Mach64xx * mp,ulong r,ulong v)349 tvw32(Mach64xx *mp, ulong r, ulong v)
350 {
351 	outportb(mp->io+(TvIndex<<2), r&0x0F);
352 	outportl(mp->io+(TvData<<2), v);
353 }
354 
355 static int smallmem[] = {
356 	   512*1024,	  1024*1024,	 2*1024*1024,	 4*1024*1024,
357 	6*1024*1024,	8*1024*1024,	12*1024*1024,	16*1024*1024,
358 };
359 
360 static int bigmem[] = {
361 	    512*1024,	  2*512*1024,	  3*512*1024,	  4*512*1024,
362 	  5*512*1024,	  6*512*1024,	  7*512*1024,	  8*512*1024,
363 	 5*1024*1024,	 6*1024*1024,	 7*1024*1024,	 8*1024*1024,
364 	10*1024*1024,	12*1024*1024,	14*1024*1024,	16*1024*1024,
365 };
366 
367 static void
snarf(Vga * vga,Ctlr * ctlr)368 snarf(Vga* vga, Ctlr* ctlr)
369 {
370 	Mach64xx *mp;
371 	int i;
372 	ulong v;
373 
374 	if(vga->private == nil){
375 		vga->private = alloc(sizeof(Mach64xx));
376 		mp = vga->private;
377 		mp->io = 0x2EC;
378 		mp->ior32 = portior32;
379 		mp->iow32 = portiow32;
380 		mp->pci = pcimatch(0, 0x1002, 0);
381 		if (mp->pci) {
382 			if(v = mp->pci->mem[1].bar & ~0x3) {
383 				mp->io = v;
384 				mp->ior32 = pciior32;
385 				mp->iow32 = pciiow32;
386 			}
387 		}
388 	}
389 
390 	mp = vga->private;
391 	for(i = 0; i < Nreg; i++)
392 		mp->reg[i] = mp->ior32(mp, i);
393 
394 	for(i = 0; i < Npll; i++)
395 		mp->pll[i] = pllr(mp, i);
396 
397 	switch(mp->reg[ConfigChipId] & 0xFFFF){
398 	default:
399 		mp->lcdpanelid = 0;
400 		break;
401 	case ('L'<<8)|'B':		/* 4C42: Rage LTPro AGP */
402 	case ('L'<<8)|'I':		/* 4C49: Rage 3D LTPro */
403 	case ('L'<<8)|'M':		/* 4C4D: Rage Mobility */
404 	case ('L'<<8)|'P':		/* 4C50: Rage 3D LTPro */
405 		for(i = 0; i < Nlcd; i++)
406 			mp->lcd[i] = lcdr32(mp, i);
407 		if(mp->lcd[LCD_GenCtrl] & 0x02)
408 			mp->lcdon = 1;
409 		mp->lcdpanelid = ((mp->reg[ConfigStat2]>>14) & 0x1F);
410 		break;
411 	}
412 
413 	/*
414 	 * Check which memory size map we are using.
415 	 */
416 	mp->bigmem = 0;
417 	switch(mp->reg[ConfigChipId] & 0xFFFF){
418 		case ('G'<<8)|'B':	/* 4742: 264GT PRO */
419 		case ('G'<<8)|'D':	/* 4744: 264GT PRO */
420 		case ('G'<<8)|'I':	/* 4749: 264GT PRO */
421 		case ('G'<<8)|'M':	/* 474D: Rage XL */
422 		case ('G'<<8)|'P':	/* 4750: 264GT PRO */
423 		case ('G'<<8)|'Q':	/* 4751: 264GT PRO */
424 		case ('G'<<8)|'R':	/* 4752: */
425 		case ('G'<<8)|'U':	/* 4755: 264GT DVD */
426 		case ('G'<<8)|'V':	/* 4756: Rage2C */
427 		case ('G'<<8)|'Z':	/* 475A: Rage2C */
428 		case ('V'<<8)|'U':	/* 5655: 264VT3 */
429 		case ('V'<<8)|'V':	/* 5656: 264VT4 */
430 		case ('L'<<8)|'B':	/* 4C42: Rage LTPro AGP */
431 		case ('L'<<8)|'I':	/* 4C49: Rage 3D LTPro */
432 		case ('L'<<8)|'M':	/* 4C4D: Rage Mobility */
433 		case ('L'<<8)|'P':	/* 4C50: Rage 3D LTPro */
434 			mp->bigmem = 1;
435 			break;
436 		case ('G'<<8)|'T':	/* 4754: 264GT[B] */
437 		case ('V'<<8)|'T':	/* 5654: 264VT/GT/VTB */
438 			/*
439 			 * Only the VTB and GTB use the new memory encoding,
440 			 * and they are identified by a nonzero ChipVersion,
441 			 * apparently.
442 			 */
443 			if((mp->reg[ConfigChipId] >> 24) & 0x7)
444 				mp->bigmem = 1;
445 			break;
446 	}
447 
448 	/*
449 	 * Memory size and aperture. It's recommended
450 	 * to use an 8Mb aperture on a 16Mb boundary.
451 	 */
452 	if(mp->bigmem)
453 		vga->vmz = bigmem[mp->reg[MemCntl] & 0x0F];
454 	else
455 		vga->vmz = smallmem[mp->reg[MemCntl] & 0x07];
456 	vga->vma = 16*1024*1024;
457 
458 	switch(mp->reg[ConfigCntl]&0x3){
459 	case 0:
460 		vga->apz = 16*1024*1024;	/* empirical -rsc */
461 		break;
462 	case 1:
463 		vga->apz = 4*1024*1024;
464 		break;
465 	case 2:
466 		vga->apz = 8*1024*1024;
467 		break;
468 	case 3:
469 		vga->apz = 2*1024*1024;	/* empirical: mach64GX -rsc */
470 		break;
471 	}
472 
473 	ctlr->flag |= Fsnarf;
474 }
475 
476 static void
options(Vga *,Ctlr * ctlr)477 options(Vga*, Ctlr* ctlr)
478 {
479 	ctlr->flag |= Hlinear|Foptions;
480 }
481 
482 static void
clock(Vga * vga,Ctlr * ctlr)483 clock(Vga* vga, Ctlr* ctlr)
484 {
485 	int clk, m, n, p;
486 	double f, q;
487 	Mach64xx *mp;
488 
489 	mp = vga->private;
490 
491 	/*
492 	 * Don't compute clock timings for LCD panels.
493 	 * Just use what's already there.  We can't just use
494 	 * the frequency in the vgadb for this because
495 	 * the frequency being programmed into the PLLs
496 	 * is not the frequency being used to compute the DSP
497 	 * settings.  The DSP-relevant frequency is the one
498 	 * we keep in /lib/vgadb.
499 	 */
500 	if(mp->lcdon){
501 		clk = mp->reg[ClockCntl] & 0x03;
502 		n = mp->pll[7+clk];
503 		p = (mp->pll[6]>>(clk*2)) & 0x03;
504 		p |= (mp->pll[11]>>(2+clk)) & 0x04;
505 		switch(p){
506 		case 0:
507 		case 1:
508 		case 2:
509 		case 3:
510 			p = 1<<p;
511 			break;
512 		case 4+0:
513 			p = 3;
514 			break;
515 		case 4+2:
516 			p = 6;
517 			break;
518 		case 4+3:
519 			p = 12;
520 			break;
521 
522 		default:
523 		case 4+1:
524 			p = -1;
525 			break;
526 		}
527 		m = mp->pll[PLLm];
528 		f = (2.0*RefFreq*n)/(m*p) + 0.5;
529 
530 		vga->m[0] = m;
531 		vga->p[0] = p;
532 		vga->n[0] = n;
533 		vga->f[0] = f;
534 		return;
535 	}
536 
537 	if(vga->f[0] == 0)
538 		vga->f[0] = vga->mode->frequency;
539 	f = vga->f[0];
540 
541 	/*
542 	 * To generate a specific output frequency, the reference (m),
543 	 * feedback (n), and post dividers (p) must be loaded with the
544 	 * appropriate divide-down ratios. In the following r is the
545 	 * XTALIN frequency (usually RefFreq) and t is the target frequency
546 	 * (vga->f).
547 	 *
548 	 * Use the maximum reference divider left by the BIOS for now,
549 	 * otherwise MCLK might be a concern. It can be calculated as
550 	 * follows:
551 	 * 			    Upper Limit of PLL Lock Range
552 	 *	Minimum PLLREFCLK = -----------------------------
553 	 *				      (2*255)
554 	 *
555 	 *				       XTALIN
556 	 *			m = Floor[-----------------]
557 	 *				  Minimum PLLREFCLK
558 	 *
559 	 * For an upper limit of 135MHz and XTALIN of 14.318MHz m
560 	 * would be 54.
561 	 */
562 	m = mp->pll[PLLm];
563 	vga->m[0] = m;
564 
565 	/*
566 	 * The post divider may be 1, 2, 4 or 8 and is determined by
567 	 * calculating
568 	 *		 t*m
569 	 *	    q = -----
570 	 *		(2*r)
571 	 * and using the result to look-up p.
572 	 */
573 	q = (f*m)/(2*RefFreq);
574 	if(ctlr->flag&Uenhanced){
575 	  if(q > 255 || q < 10.6666666667)
576 		error("%s: vclk %lud out of range\n", ctlr->name, vga->f[0]);
577 	  if(q > 127.5)
578 		p = 1;
579 	  else if(q > 85)
580 		p = 2;
581 	  else if(q > 63.75)
582 		p = 3;
583 	  else if(q > 42.5)
584 		p = 4;
585 	  else if(q > 31.875)
586 		p = 6;
587 	  else if(q > 21.25)
588 		p = 8;
589 	  else
590 		p = 12;
591 	}else{
592 	  if(q > 255 || q < 16)
593 		error("%s: vclk %lud out of range\n", ctlr->name, vga->f[0]);
594 	  if(q >= 127.5)
595 		p = 1;
596 	  else if(q >= 63.5)
597 		p = 2;
598 	  else if(q >= 31.5)
599 		p = 4;
600 	  else
601 		p = 8;
602 	}
603 	vga->p[0] = p;
604 
605 	/*
606 	 * The feedback divider should be kept in the range 0x80 to 0xFF
607 	 * and is found from
608 	 *	n = q*p
609 	 * rounded to the nearest whole number.
610 	 */
611 	vga->n[0] = (q*p)+0.5;
612 }
613 
614 typedef struct Meminfo	Meminfo;
615 struct Meminfo {
616 	int latency;
617 	int latch;
618 	int trp;		/* filled in from card */
619 	int trcd;		/* filled in from card */
620 	int tcrd;		/* filled in from card */
621 	int tras;		/* filled in from card */
622 };
623 
624 enum {
625 	Mdram,
626 	Medo,
627 	Msdram,
628 	Mwram,
629 };
630 
631 /*
632  * The manuals and documentation are silent on which settings
633  * to use for Mwdram, or how to tell which to use.
634  */
635 static Meminfo meminfo[] = {
636 [Mdram]		{ 1, 0 },
637 [Medo]		{ 1, 2 },
638 [Msdram]	{ 3, 1 },
639 [Mwram]		{ 1, 3 },	/* non TYPE_A */
640 };
641 
642 static ushort looplatencytab[2][2] = {
643 	{ 8, 6 },		/* DRAM: ≤1M, > 1M */
644 	{ 9, 8 },		/* SDRAM: ≤1M, > 1M */
645 };
646 
647 static ushort cyclesperqwordtab[2][2] = {
648 	{ 3, 2 },		/* DRAM: ≤1M, > 1M */
649 	{ 2, 1 },		/* SDRAM: ≤1M, > 1M */
650 };
651 
652 static int memtype[] = {
653 	-1,			/* disable memory access */
654 	Mdram,			/* basic DRAM */
655 	Medo,			/* EDO */
656 	Medo,			/* hyper page DRAM or EDO */
657 	Msdram,			/* SDRAM */
658 	Msdram,			/* SGRAM */
659 	Mwram,
660 	Mwram
661 };
662 
663 /*
664  * Calculate various memory parameters so that the card
665  * fetches the right bytes at the right time.  I don't claim to
666  * understand the actual calculations very well.
667  *
668  * This is remarkably useful on laptops, since knowledge of
669  * x lets us find the frequency that the screen is really running
670  * at, which is not necessarily in the VCLKs.
671  */
672 static void
setdsp(Vga * vga,Ctlr *)673 setdsp(Vga* vga, Ctlr*)
674 {
675 	Mach64xx *mp;
676 	Meminfo *mem;
677 	ushort table, memclk, memtyp;
678 	int i, prec, xprec, fprec;
679 	ulong t;
680 	double pw, x, fifosz, fifoon, fifooff;
681 	ushort dspon, dspoff;
682 	int afifosz, lat, ncycle, pfc, rcc;
683 
684 	mp = vga->private;
685 
686 	/*
687 	 * Get video ram configuration from BIOS and chip
688 	 */
689 	table = *(ushort*)readbios(sizeof table, 0xc0048);
690 	trace("rom table offset %uX\n", table);
691 	table = *(ushort*)readbios(sizeof table, 0xc0000+table+16);
692 	trace("freq table offset %uX\n", table);
693 	memclk = *(ushort*)readbios(sizeof memclk, 0xc0000+table+18);
694 	trace("memclk %ud\n", memclk);
695 	memtyp = memtype[mp->reg[ConfigStat0]&07];
696 	mem = &meminfo[memtyp];
697 
698 	/*
699 	 * First we need to calculate x, the number of
700 	 * XCLKs that one QWORD occupies in the display FIFO.
701 	 *
702 	 * For some reason, x gets stretched out if LCD stretching
703 	 * is turned on.
704 	 */
705 
706 	x = ((double)memclk*640000.0) /
707 		((double)vga->mode->frequency * (double)vga->mode->z);
708 	if(mp->lcd[LCD_HorzStretch] & (1<<31))
709 		x *= 4096.0 / (double)(mp->lcd[LCD_HorzStretch] & 0xFFFF);
710 
711 	trace("memclk %d... x %f...", memclk, x);
712 	/*
713 	 * We have 14 bits to specify x in.  Decide where to
714 	 * put the decimal (err, binary) point by counting how
715 	 * many significant bits are in the integer portion of x.
716 	 */
717 	t = x;
718 	for(i=31; i>=0; i--)
719 		if(t & (1<<i))
720 			break;
721 	xprec = i+1;
722 	trace("t %lud... xprec %d...", t, xprec);
723 
724 	/*
725 	 * The maximum FIFO size is the number of XCLKs per QWORD
726 	 * multiplied by 32, for some reason.  We have 11 bits to
727 	 * specify fifosz.
728 	 */
729 	fifosz = x * 32.0;
730 	trace("fifosz %f...", fifosz);
731 	t = fifosz;
732 	for(i=31; i>=0; i--)
733 		if(t & (1<<i))
734 			break;
735 	fprec = i+1;
736 	trace("fprec %d...", fprec);
737 
738 	/*
739 	 * Precision is specified as 3 less than the number of bits
740 	 * in the integer part of x, and 5 less than the number of bits
741 	 * in the integer part of fifosz.
742 	 *
743 	 * It is bounded by zero and seven.
744 	 */
745 	prec = (xprec-3 > fprec-5) ? xprec-3 : fprec-5;
746 	if(prec < 0)
747 		prec = 0;
748 	if(prec > 7)
749 		prec = 7;
750 
751 	xprec = prec+3;
752 	fprec = prec+5;
753 	trace("prec %d...", prec);
754 
755 	/*
756 	 * Actual fifo size
757 	 */
758 	afifosz = (1<<fprec) / x;
759 	if(afifosz > 32)
760 		afifosz = 32;
761 
762 	fifooff = ceil(x*(afifosz-1));
763 
764 	/*
765 	 * I am suspicious of this table, lifted from ATI docs,
766 	 * because it doesn't agree with the Windows drivers.
767 	 * We always get 0x0A for lat+2 while Windows uses 0x08.
768 	 */
769 	lat = looplatencytab[memtyp > 1][vga->vmz > 1*1024*1024];
770 	trace("afifosz %d...fifooff %f...", afifosz, fifooff);
771 
772 	/*
773 	 * Page fault clock
774 	 */
775 	t = mp->reg[MemCntl];
776 	mem->trp = (t>>8)&3;	/* RAS precharge time */
777 	mem->trcd = (t>>10)&3;	/* RAS to CAS delay */
778 	mem->tcrd = (t>>12)&1;	/* CAS to RAS delay */
779 	mem->tras = (t>>16)&7;	/* RAS low minimum pulse width */
780 	pfc = mem->trp + 1 + mem->trcd + 1 + mem->tcrd;
781 	trace("pfc %d...", pfc);
782 
783 	/*
784 	 * Maximum random access cycle clock.
785 	 */
786 	ncycle = cyclesperqwordtab[memtyp > 1][vga->vmz > 1*1024*1024];
787 	rcc = mem->trp + 1 + mem->tras + 1;
788 	if(rcc < pfc+ncycle)
789 		rcc = pfc+ncycle;
790 	trace("rcc %d...", rcc);
791 
792 	fifoon = (rcc > floor(x)) ? rcc : floor(x);
793 	fifoon += (3.0 * rcc) - 1 + pfc + ncycle;
794 	trace("fifoon %f...\n", fifoon);
795 	/*
796 	 * Now finally put the bits together.
797 	 * x is stored in a 14 bit field with xprec bits of integer.
798 	 */
799 	pw = x * (1<<(14-xprec));
800 	mp->reg[DspConfig] = (ulong)pw | (((lat+2)&0xF)<<16) | ((prec&7)<<20);
801 
802 	/*
803 	 * These are stored in an 11 bit field with fprec bits of integer.
804 	 */
805 	dspon  = (ushort)fifoon << (11-fprec);
806 	dspoff = (ushort)fifooff << (11-fprec);
807 	mp->reg[DspOnOff] = ((dspon&0x7ff) << 16) | (dspoff&0x7ff);
808 }
809 
810 static void
init(Vga * vga,Ctlr * ctlr)811 init(Vga* vga, Ctlr* ctlr)
812 {
813 	Mode *mode;
814 	Mach64xx *mp;
815 	int p, x, y;
816 
817 	mode = vga->mode;
818 	if((mode->x > 640 || mode->y > 480) && mode->z == 1)
819 		error("%s: no support for 1-bit mode other than 640x480x1\n",
820 			ctlr->name);
821 
822 	mp = vga->private;
823 	if(mode->z > 8 && mp->pci == nil)
824 		error("%s: no support for >8-bit color without PCI\n",
825 			ctlr->name);
826 
827 	/*
828 	 * Check for Rage chip
829 	 */
830 	switch (mp->reg[ConfigChipId]&0xffff) {
831 		case ('G'<<8)|'B':	/* 4742: 264GT PRO */
832 		case ('G'<<8)|'D':	/* 4744: 264GT PRO */
833 		case ('G'<<8)|'I':	/* 4749: 264GT PRO */
834 		case ('G'<<8)|'M':	/* 474D: Rage XL */
835 		case ('G'<<8)|'P':	/* 4750: 264GT PRO */
836 		case ('G'<<8)|'Q':	/* 4751: 264GT PRO */
837 		case ('G'<<8)|'R':	/* 4752: */
838 		case ('G'<<8)|'U':	/* 4755: 264GT DVD */
839 		case ('G'<<8)|'V':	/* 4756: Rage2C */
840 		case ('G'<<8)|'Z':	/* 475A: Rage2C */
841 		case ('V'<<8)|'U':	/* 5655: 264VT3 */
842 		case ('V'<<8)|'V':	/* 5656: 264VT4 */
843 		case ('G'<<8)|'T':	/* 4754: 264GT[B] */
844 		case ('V'<<8)|'T':	/* 5654: 264VT/GT/VTB */
845 		case ('L'<<8)|'B':	/* 4C42: Rage LTPro AGP */
846 		case ('L'<<8)|'I':	/* 4C49: 264LT PRO */
847 		case ('L'<<8)|'M':	/* 4C4D: Rage Mobility */
848 		case ('L'<<8)|'P':	/* 4C50: 264LT PRO */
849 			ctlr->flag |= Uenhanced;
850 			break;
851 	}
852 
853 	/*
854 	 * Always use VCLK2.
855 	 */
856 	clock(vga, ctlr);
857 	mp->pll[PLLn2] = vga->n[0];
858 	mp->pll[PLLp] &= ~(0x03<<(2*2));
859 	switch(vga->p[0]){
860 	case 1:
861 	case 3:
862 		p = 0;
863 		break;
864 
865 	case 2:
866 		p = 1;
867 		break;
868 
869 	case 4:
870 	case 6:
871 		p = 2;
872 		break;
873 
874 	case 8:
875 	case 12:
876 		p = 3;
877 		break;
878 
879 	default:
880 		p = 3;
881 		break;
882 	}
883 	mp->pll[PLLp] |= p<<(2*2);
884 	if ((1<<p) != vga->p[0])
885 		mp->pll[PLLx] |= 1<<(4+2);
886 	else
887 		mp->pll[PLLx] &= ~(1<<(4+2));
888 	mp->reg[ClockCntl] = 2;
889 
890 	mp->reg[ConfigCntl] = 0;
891 
892 	mp->reg[CrtcGenCntl] = 0x02000000|(mp->reg[CrtcGenCntl] & ~0x01400700);
893 	switch(mode->z){
894 	default:
895 	case 1:
896 		mp->reg[CrtcGenCntl] |= 0x00000100;
897 		mp->reg[DpPixWidth] = 0x00000000;
898 		break;
899 	case 8:
900 		mp->reg[CrtcGenCntl] |= 0x01000200;
901 		mp->reg[DpPixWidth] = 0x00020202;
902 		break;
903 	case 15:
904 		mp->reg[CrtcGenCntl] |= 0x01000300;
905 		mp->reg[DpPixWidth] = 0x00030303;
906 		break;
907 	case 16:
908 		mp->reg[CrtcGenCntl] |= 0x01000400;
909 		mp->reg[DpPixWidth] = 0x00040404;
910 		break;
911 	case 24:
912 		mp->reg[CrtcGenCntl] |= 0x01000500;
913 		mp->reg[DpPixWidth] = 0x00050505;
914 		break;
915 	case 32:
916 		mp->reg[CrtcGenCntl] |= 0x01000600;
917 		mp->reg[DpPixWidth] = 0x00060606;
918 		break;
919 	}
920 
921 	mp->reg[HTotalDisp] = (((mode->x>>3)-1)<<16)|((mode->ht>>3)-1);
922 	mp->reg[HSyncStrtWid] = (((mode->ehs - mode->shs)>>3)<<16)
923 				|((mode->shs>>3)-1);
924 	if(mode->hsync == '-')
925 		mp->reg[HSyncStrtWid] |= 0x00200000;
926 	mp->reg[VTotalDisp] = ((mode->y-1)<<16)|(mode->vt-1);
927 	mp->reg[VSyncStrtWid] = ((mode->vre - mode->vrs)<<16)|(mode->vrs-1);
928 	if(mode->vsync == '-')
929 		mp->reg[VSyncStrtWid] |= 0x00200000;
930 	mp->reg[IntCntl] = 0;
931 
932 	/*
933 	 * This used to set it to (mode->x/(8*2))<<22 for depths < 8,
934 	 * but from the manual that seems wrong to me.  -rsc
935 	 */
936 	mp->reg[OffPitch] = (vga->virtx/8)<<22;
937 
938 	mp->reg[OvrClr] = Pblack;
939 
940 	if(vga->linear && mode->z != 1)
941 		ctlr->flag |= Ulinear;
942 
943 	/*
944 	 * Heuristic fiddling on LT PRO.
945 	 * Do this before setdsp so the stretching is right.
946 	 */
947 	if(mp->lcdon){
948 		/* use non-shadowed registers */
949 		mp->lcd[LCD_GenCtrl] &= ~0x00000404;
950 		mp->lcd[LCD_ConfigPanel] |= 0x00004000;
951 
952 		mp->lcd[LCD_VertStretch] = 0;
953 		y = ((mp->lcd[LCD_ExtVertStretch]>>11) & 0x7FF)+1;
954 		if(mode->y < y){
955 			x = (mode->y*1024)/y;
956 			mp->lcd[LCD_VertStretch] = 0xC0000000|x;
957 		}
958 		mp->lcd[LCD_ExtVertStretch] &= ~0x00400400;
959 
960 		/*
961 		 * The x value doesn't seem to be available on all
962 		 * chips so intuit it from the y value which seems to
963 		 * be reliable.
964 		 */
965 		mp->lcd[LCD_HorzStretch] &= ~0xC00000FF;
966 		x = (mp->lcd[LCD_HorzStretch]>>20) & 0xFF;
967 		if(x == 0){
968 			switch(y){
969 			default:
970 				break;
971 			case 480:
972 				x = 640;
973 				break;
974 			case 600:
975 				x = 800;
976 				break;
977 			case 768:
978 				x = 1024;
979 				break;
980 			case 1024:
981 				x = 1280;
982 				break;
983 			}
984 		}
985 		else
986 			x = (x+1)*8;
987 		if(mode->x < x){
988 			x = (mode->x*4096)/x;
989 			mp->lcd[LCD_HorzStretch] |= 0xC0000000|x;
990 		}
991 	}
992 
993 	if(ctlr->flag&Uenhanced)
994 		setdsp(vga, ctlr);
995 
996 	ctlr->flag |= Finit;
997 }
998 
999 static void
load(Vga * vga,Ctlr * ctlr)1000 load(Vga* vga, Ctlr* ctlr)
1001 {
1002 	Mach64xx *mp;
1003 	int i;
1004 
1005 	mp = vga->private;
1006 
1007 	/*
1008 	 * Unlock the CRTC and LCD registers.
1009 	 */
1010 	mp->iow32(mp, CrtcGenCntl, mp->ior32(mp, CrtcGenCntl)&~0x00400000);
1011 	if(mp->lcdon)
1012 		lcdw32(mp, LCD_GenCtrl, mp->lcd[LCD_GenCtrl]|0x80000000);
1013 
1014 	/*
1015 	 * Always use an aperture on a 16Mb boundary.
1016 	 */
1017 	if(ctlr->flag & Ulinear)
1018 		mp->reg[ConfigCntl] = ((vga->vmb/(4*1024*1024))<<4)|0x02;
1019 
1020 	mp->iow32(mp, ConfigCntl, mp->reg[ConfigCntl]);
1021 
1022 	mp->iow32(mp, GenTestCntl, 0);
1023 	mp->iow32(mp, GenTestCntl, 0x100);
1024 
1025 	if((ctlr->flag&Uenhanced) == 0)
1026 	  mp->iow32(mp, MemCntl, mp->reg[MemCntl] & ~0x70000);
1027 	mp->iow32(mp, BusCntl, mp->reg[BusCntl]);
1028 	mp->iow32(mp, HTotalDisp, mp->reg[HTotalDisp]);
1029 	mp->iow32(mp, HSyncStrtWid, mp->reg[HSyncStrtWid]);
1030 	mp->iow32(mp, VTotalDisp, mp->reg[VTotalDisp]);
1031 	mp->iow32(mp, VSyncStrtWid, mp->reg[VSyncStrtWid]);
1032 	mp->iow32(mp, IntCntl, mp->reg[IntCntl]);
1033 	mp->iow32(mp, OffPitch, mp->reg[OffPitch]);
1034 	if(mp->lcdon){
1035 		for(i=0; i<Nlcd; i++)
1036 			lcdw32(mp, i, mp->lcd[i]);
1037 	}
1038 
1039 	mp->iow32(mp, GenTestCntl, mp->reg[GenTestCntl]);
1040 	mp->iow32(mp, ConfigCntl, mp->reg[ConfigCntl]);
1041 	mp->iow32(mp, CrtcGenCntl, mp->reg[CrtcGenCntl]);
1042 	mp->iow32(mp, OvrClr, mp->reg[OvrClr]);
1043 	mp->iow32(mp, OvrWidLR, mp->reg[OvrWidLR]);
1044 	mp->iow32(mp, OvrWidTB, mp->reg[OvrWidTB]);
1045 	if(ctlr->flag&Uenhanced){
1046 	  mp->iow32(mp, DacRegs, mp->reg[DacRegs]);
1047 	  mp->iow32(mp, DacCntl, mp->reg[DacCntl]);
1048 	  mp->iow32(mp, CrtcGenCntl, mp->reg[CrtcGenCntl]&~0x02000000);
1049 	  mp->iow32(mp, DspOnOff, mp->reg[DspOnOff]);
1050 	  mp->iow32(mp, DspConfig, mp->reg[DspConfig]);
1051 	  mp->iow32(mp, CrtcGenCntl, mp->reg[CrtcGenCntl]);
1052 	  pllw(mp, PLLx, mp->pll[PLLx]);
1053 	}
1054 	pllw(mp, PLLn2, mp->pll[PLLn2]);
1055 	pllw(mp, PLLp, mp->pll[PLLp]);
1056 	pllw(mp, PLLn3, mp->pll[PLLn3]);
1057 
1058 	mp->iow32(mp, ClockCntl, mp->reg[ClockCntl]);
1059 	mp->iow32(mp, ClockCntl, 0x40|mp->reg[ClockCntl]);
1060 
1061 	mp->iow32(mp, DpPixWidth, mp->reg[DpPixWidth]);
1062 
1063 	if(vga->mode->z > 8){
1064 		int sh, i;
1065 		/*
1066 		 * We need to initialize the palette, since the DACs use it
1067 		 * in true color modes.  First see if the card supports an
1068 		 * 8-bit DAC.
1069 		 */
1070 		mp->iow32(mp, DacCntl, mp->reg[DacCntl] | 0x100);
1071 		if(mp->ior32(mp, DacCntl)&0x100){
1072 			/* card appears to support it */
1073 			vgactlw("palettedepth", "8");
1074 			mp->reg[DacCntl] |= 0x100;
1075 		}
1076 
1077 		if(mp->reg[DacCntl] & 0x100)
1078 			sh = 0;	/* 8-bit DAC */
1079 		else
1080 			sh = 2;	/* 6-bit DAC */
1081 
1082 		for(i=0; i<256; i++)
1083 			setpalette(i, i>>sh, i>>sh, i>>sh);
1084 	}
1085 
1086 	ctlr->flag |= Fload;
1087 }
1088 
1089 static void
pixelclock(Vga * vga,Ctlr * ctlr)1090 pixelclock(Vga* vga, Ctlr* ctlr)
1091 {
1092 	Mach64xx *mp;
1093 	ushort table, s;
1094 	int memclk, ref_freq, ref_divider, min_freq, max_freq;
1095 	int feedback, nmult, pd, post, value;
1096 	int clock;
1097 
1098 	/*
1099 	 * Find the pixel clock from the BIOS and current
1100 	 * settings. Lifted from the ATI-supplied example code.
1101 	 * The clocks stored in the BIOS table are in kHz/10.
1102 	 *
1103 	 * This is the clock LCDs use in vgadb to set the DSP
1104 	 * values.
1105 	 */
1106 	mp = vga->private;
1107 
1108 	/*
1109 	 * GetPLLInfo()
1110 	 */
1111 	table = *(ushort*)readbios(sizeof table, 0xc0048);
1112 	trace("rom table offset %uX\n", table);
1113 	table = *(ushort*)readbios(sizeof table, 0xc0000+table+16);
1114 	trace("freq table offset %uX\n", table);
1115 	s = *(ushort*)readbios(sizeof s, 0xc0000+table+18);
1116 	memclk = s*10000;
1117 	trace("memclk %ud\n", memclk);
1118 	s = *(ushort*)readbios(sizeof s, 0xc0000+table+8);
1119 	ref_freq = s*10000;
1120 	trace("ref_freq %ud\n", ref_freq);
1121 	s = *(ushort*)readbios(sizeof s, 0xc0000+table+10);
1122 	ref_divider = s;
1123 	trace("ref_divider %ud\n", ref_divider);
1124 	s = *(ushort*)readbios(sizeof s, 0xc0000+table+2);
1125 	min_freq = s*10000;
1126 	trace("min_freq %ud\n", min_freq);
1127 	s = *(ushort*)readbios(sizeof s, 0xc0000+table+4);
1128 	max_freq = s*10000;
1129 	trace("max_freq %ud\n", max_freq);
1130 
1131 	/*
1132 	 * GetDivider()
1133 	 */
1134 	pd = mp->pll[PLLp] & 0x03;
1135 	value = (mp->pll[PLLx] & 0x10)>>2;
1136 	trace("pd %uX value %uX (|%d)\n", pd, value, value|pd);
1137 	value |= pd;
1138 	post = 0;
1139 	switch(value){
1140 	case 0:
1141 		post = 1;
1142 		break;
1143 	case 1:
1144 		post = 2;
1145 		break;
1146 	case 2:
1147 		post = 4;
1148 		break;
1149 	case 3:
1150 		post = 8;
1151 		break;
1152 	case 4:
1153 		post = 3;
1154 		break;
1155 	case 5:
1156 		post = 0;
1157 		break;
1158 	case 6:
1159 		post = 6;
1160 		break;
1161 	case 7:
1162 		post = 12;
1163 		break;
1164 	}
1165 	trace("post = %d\n", post);
1166 
1167 	feedback = mp->pll[PLLn0];
1168 	if(mp->pll[PLLx] & 0x08)
1169 		nmult = 4;
1170 	else
1171 		nmult = 2;
1172 
1173 	clock = (ref_freq/10000)*nmult*feedback;
1174 	clock /= ref_divider*post;
1175 	clock *= 10000;
1176 
1177 	Bprint(&stdout, "%s pixel clock = %ud\n", ctlr->name, clock);
1178 }
1179 
1180 static void dumpmach64bios(Mach64xx*);
1181 
1182 static void
dump(Vga * vga,Ctlr * ctlr)1183 dump(Vga* vga, Ctlr* ctlr)
1184 {
1185 	Mach64xx *mp;
1186 	int i, m, n, p;
1187 	double f;
1188 	static int first = 1;
1189 
1190 	if((mp = vga->private) == 0)
1191 		return;
1192 
1193 	Bprint(&stdout, "%s pci %p io %lux %s\n", ctlr->name,
1194 		mp->pci, mp->io, mp->ior32 == pciior32 ? "pciregs" : "ioregs");
1195 	if(mp->pci)
1196 		Bprint(&stdout, "%s ccru %ux\n", ctlr->name, mp->pci->ccru);
1197 	for(i = 0; i < Nreg; i++)
1198 		Bprint(&stdout, "%s %-*s%.8luX\n",
1199 			ctlr->name, 20, iorname[i], mp->reg[i]);
1200 
1201 	printitem(ctlr->name, "PLL");
1202 	for(i = 0; i < Npll; i++)
1203 		printreg(mp->pll[i]);
1204 	Bprint(&stdout, "\n");
1205 
1206 	switch(mp->reg[ConfigChipId] & 0xFFFF){
1207 	default:
1208 		break;
1209 	case ('L'<<8)|'B':		/* 4C42: Rage LTPro AGP */
1210 	case ('L'<<8)|'I':		/* 4C49: Rage 3D LTPro */
1211 	case ('L'<<8)|'M':		/* 4C4D: Rage Mobility */
1212 	case ('L'<<8)|'P':		/* 4C50: Rage 3D LTPro */
1213 		for(i = 0; i < Nlcd; i++)
1214 			Bprint(&stdout, "%s %-*s%.8luX\n",
1215 				ctlr->name, 20, lcdname[i], mp->lcd[i]);
1216 		break;
1217 	}
1218 
1219 	/*
1220 	 *     (2*r*n)
1221 	 * f = -------
1222 	 *	(m*p)
1223 	 */
1224 	m = mp->pll[2];
1225 	for(i = 0; i < 4; i++){
1226 		n = mp->pll[7+i];
1227 		p = (mp->pll[6]>>(i*2)) & 0x03;
1228 		p |= (mp->pll[11]>>(2+i)) & 0x04;
1229 		switch(p){
1230 		case 0:
1231 		case 1:
1232 		case 2:
1233 		case 3:
1234 			p = 1<<p;
1235 			break;
1236 		case 4+0:
1237 			p = 3;
1238 			break;
1239 		case 4+2:
1240 			p = 6;
1241 			break;
1242 		case 4+3:
1243 			p = 12;
1244 			break;
1245 
1246 		default:
1247 		case 4+1:
1248 			p = -1;
1249 			break;
1250 		}
1251 		if(m*p == 0)
1252 			Bprint(&stdout, "unknown VCLK%d\n", i);
1253 		else {
1254 			f = (2.0*RefFreq*n)/(m*p) + 0.5;
1255 			Bprint(&stdout, "%s VCLK%d\t%ud\n", ctlr->name, i, (int)f);
1256 		}
1257 	}
1258 
1259 	pixelclock(vga, ctlr);
1260 
1261 	if(first) {
1262 		first = 0;
1263 		dumpmach64bios(mp);
1264 	}
1265 }
1266 
1267 enum {
1268 	ClockFixed=0,
1269 	ClockIcs2595,
1270 	ClockStg1703,
1271 	ClockCh8398,
1272 	ClockInternal,
1273 	ClockAtt20c408,
1274 	ClockIbmrgb514
1275 };
1276 
1277 /*
1278  * mostly derived from the xfree86 probe routines.
1279  */
1280 static void
dumpmach64bios(Mach64xx * mp)1281 dumpmach64bios(Mach64xx *mp)
1282 {
1283 	int i, romtable, clocktable, freqtable, lcdtable, lcdpanel;
1284 	uchar bios[0x10000];
1285 
1286 	memmove(bios, readbios(sizeof bios, 0xC0000), sizeof bios);
1287 
1288 	/* find magic string */
1289 	for(i=0; i<1024; i++)
1290 		if(strncmp((char*)bios+i, " 761295520", 10) == 0)
1291 			break;
1292 
1293 	if(i==1024) {
1294 		Bprint(&stdout, "no ATI bios found\n");
1295 		return;
1296 	}
1297 
1298 	/* this is horribly endian dependent.  sorry. */
1299 	romtable = *(ushort*)(bios+0x48);
1300 	if(romtable+0x12 > sizeof(bios)) {
1301 		Bprint(&stdout, "couldn't find ATI rom table\n");
1302 		return;
1303 	}
1304 
1305 	clocktable = *(ushort*)(bios+romtable+0x10);
1306 	if(clocktable+0x0C > sizeof(bios)) {
1307 		Bprint(&stdout, "couldn't find ATI clock table\n");
1308 		return;
1309 	}
1310 
1311 	freqtable = *(ushort*)(bios+clocktable-2);
1312 	if(freqtable+0x20 > sizeof(bios)) {
1313 		Bprint(&stdout, "couldn't find ATI frequency table\n");
1314 		return;
1315 	}
1316 
1317 	Bprint(&stdout, "ATI BIOS rom 0x%x freq 0x%x clock 0x%x\n", romtable, freqtable, clocktable);
1318 	Bprint(&stdout, "clocks:");
1319 	for(i=0; i<16; i++)
1320 		Bprint(&stdout, " %d", *(ushort*)(bios+freqtable+2*i));
1321 	Bprint(&stdout, "\n");
1322 
1323 	Bprint(&stdout, "programmable clock: %d\n", bios[clocktable]);
1324 	Bprint(&stdout, "clock to program: %d\n", bios[clocktable+6]);
1325 
1326 	if(*(ushort*)(bios+clocktable+8) != 1430) {
1327 		Bprint(&stdout, "reference numerator: %d\n", *(ushort*)(bios+clocktable+8)*10);
1328 		Bprint(&stdout, "reference denominator: 1\n");
1329 	} else {
1330 		Bprint(&stdout, "default reference numerator: 157500\n");
1331 		Bprint(&stdout, "default reference denominator: 11\n");
1332 	}
1333 
1334 	switch(bios[clocktable]) {
1335 	case ClockIcs2595:
1336 		Bprint(&stdout, "ics2595\n");
1337 		Bprint(&stdout, "reference divider: %d\n", *(ushort*)(bios+clocktable+0x0A));
1338 		break;
1339 	case ClockStg1703:
1340 		Bprint(&stdout, "stg1703\n");
1341 		break;
1342 	case ClockCh8398:
1343 		Bprint(&stdout, "ch8398\n");
1344 		break;
1345 	case ClockInternal:
1346 		Bprint(&stdout, "internal clock\n");
1347 		Bprint(&stdout, "reference divider in plls\n");
1348 		break;
1349 	case ClockAtt20c408:
1350 		Bprint(&stdout, "att 20c408\n");
1351 		break;
1352 	case ClockIbmrgb514:
1353 		Bprint(&stdout, "ibm rgb514\n");
1354 		Bprint(&stdout, "clock to program = 7\n");
1355 		break;
1356 	default:
1357 		Bprint(&stdout, "unknown clock\n");
1358 		break;
1359 	}
1360 
1361 	USED(mp);
1362 	if(1 || mp->lcdpanelid) {
1363 		lcdtable = *(ushort*)(bios+0x78);
1364 		if(lcdtable+5 > sizeof bios || lcdtable+bios[lcdtable+5] > sizeof bios) {
1365 			Bprint(&stdout, "can't find lcd bios table\n");
1366 			goto NoLcd;
1367 		}
1368 
1369 		lcdpanel = *(ushort*)(bios+lcdtable+0x0A);
1370 		if(lcdpanel+0x1D > sizeof bios /*|| bios[lcdpanel] != mp->lcdpanelid*/) {
1371 			Bprint(&stdout, "can't find lcd bios table0\n");
1372 			goto NoLcd;
1373 		}
1374 
1375 		Bprint(&stdout, "panelid %d x %d y %d\n", bios[lcdpanel], *(ushort*)(bios+lcdpanel+0x19), *(ushort*)(bios+lcdpanel+0x1B));
1376 	}
1377 NoLcd:;
1378 }
1379 
1380 Ctlr mach64xx = {
1381 	"mach64xx",			/* name */
1382 	snarf,				/* snarf */
1383 	0,				/* options */
1384 	init,				/* init */
1385 	load,				/* load */
1386 	dump,				/* dump */
1387 };
1388 
1389 Ctlr mach64xxhwgc = {
1390 	"mach64xxhwgc",			/* name */
1391 	0,				/* snarf */
1392 	0,				/* options */
1393 	0,				/* init */
1394 	0,				/* load */
1395 	0,				/* dump */
1396 };
1397 
1398 
1399