Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
282
pciior32(Mach64xx* mp, int r)
283
{
284
	return inportl((pciregs[r]<<2)+mp->io);
285
}
286
 
287
static void
288
pciiow32(Mach64xx* mp, int r, ulong l)
289
{
290
	outportl((pciregs[r]<<2)+mp->io, l);
291
}
292
 
293
static uchar
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
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
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
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
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
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
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
477
options(Vga*, Ctlr* ctlr)
478
{
479
	ctlr->flag |= Hlinear|Foptions;
480
}
481
 
482
static void
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
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
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
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
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
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 
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