32 ScratchReg1, /* Scratch Register (BIOS info) */
42 ConfigCntl, /* Configuration control */
44 ConfigStat0, /* Configuration status 0 */
45 ConfigStat1, /* Configuration status 1 */
79 static char* iorname[Nreg] = {
130 static char* lcdname[Nlcd] = {
137 "LCD ExtVertStretch",
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.
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 */
187 static ushort pciregs[Nreg] = {
192 [VlineCrntVline] 0x04,
222 [ConfigStat1] 0x25, /* rsc: was 0x3A, but that's not what the LT manual says */
240 PLLx = 0x0B, /* external divisor (Rage) */
243 Ntv = 1, /* actually 256, but not used */
246 typedef struct Mach64xx Mach64xx;
259 ulong (*ior32)(Mach64xx*, int);
260 void (*iow32)(Mach64xx*, int, ulong);
264 portior32(Mach64xx* mp, int r)
266 if((ioregs[r] & IOREG) == 0)
269 return inportl(((ioregs[r] & ~IOREG)<<2)+mp->io);
273 portiow32(Mach64xx* mp, int r, ulong l)
275 if((ioregs[r] & IOREG) == 0)
278 outportl(((ioregs[r] & ~IOREG)<<2)+mp->io, l);
282 pciior32(Mach64xx* mp, int r)
284 return inportl((pciregs[r]<<2)+mp->io);
288 pciiow32(Mach64xx* mp, int r, ulong l)
290 outportl((pciregs[r]<<2)+mp->io, l);
294 pllr(Mach64xx* mp, int r)
298 if(mp->ior32 == portior32)
299 io = ((ioregs[ClockCntl]&~IOREG)<<2)+mp->io;
301 io = (pciregs[ClockCntl]<<2)+mp->io;
303 outportb(io+1, r<<2);
304 return inportb(io+2);
308 pllw(Mach64xx* mp, int r, uchar b)
312 if(mp->ior32 == portior32)
313 io = ((ioregs[ClockCntl]&~IOREG)<<2)+mp->io;
315 io = (pciregs[ClockCntl]<<2)+mp->io;
317 outportb(io+1, (r<<2)|0x02);
322 lcdr32(Mach64xx *mp, ulong r)
326 or = mp->ior32(mp, LcdIndex);
327 mp->iow32(mp, LcdIndex, (or&~0x0F) | (r&0x0F));
328 return mp->ior32(mp, LcdData);
332 lcdw32(Mach64xx *mp, ulong r, ulong v)
336 or = mp->ior32(mp, LcdIndex);
337 mp->iow32(mp, LcdIndex, (or&~0x0F) | (r&0x0F));
338 mp->iow32(mp, LcdData, v);
342 tvr32(Mach64xx *mp, ulong r)
344 outportb(mp->io+(TvIndex<<2), r&0x0F);
345 return inportl(mp->io+(TvData<<2));
349 tvw32(Mach64xx *mp, ulong r, ulong v)
351 outportb(mp->io+(TvIndex<<2), r&0x0F);
352 outportl(mp->io+(TvData<<2), v);
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,
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,
368 snarf(Vga* vga, Ctlr* ctlr)
374 if(vga->private == nil){
375 vga->private = alloc(sizeof(Mach64xx));
378 mp->ior32 = portior32;
379 mp->iow32 = portiow32;
380 mp->pci = pcimatch(0, 0x1002, 0);
382 if(v = mp->pci->mem[1].bar & ~0x3) {
384 mp->ior32 = pciior32;
385 mp->iow32 = pciiow32;
391 for(i = 0; i < Nreg; i++)
392 mp->reg[i] = mp->ior32(mp, i);
394 for(i = 0; i < Npll; i++)
395 mp->pll[i] = pllr(mp, i);
397 switch(mp->reg[ConfigChipId] & 0xFFFF){
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)
409 mp->lcdpanelid = ((mp->reg[ConfigStat2]>>14) & 0x1F);
414 * Check which memory size map we are using.
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 */
436 case ('G'<<8)|'T': /* 4754: 264GT[B] */
437 case ('V'<<8)|'T': /* 5654: 264VT/GT/VTB */
439 * Only the VTB and GTB use the new memory encoding,
440 * and they are identified by a nonzero ChipVersion,
443 if((mp->reg[ConfigChipId] >> 24) & 0x7)
449 * Memory size and aperture. It's recommended
450 * to use an 8Mb aperture on a 16Mb boundary.
453 vga->vmz = bigmem[mp->reg[MemCntl] & 0x0F];
455 vga->vmz = smallmem[mp->reg[MemCntl] & 0x07];
456 vga->vma = 16*1024*1024;
458 switch(mp->reg[ConfigCntl]&0x3){
460 vga->apz = 16*1024*1024; /* empirical -rsc */
463 vga->apz = 4*1024*1024;
466 vga->apz = 8*1024*1024;
469 vga->apz = 2*1024*1024; /* empirical: mach64GX -rsc */
473 ctlr->flag |= Fsnarf;
477 options(Vga*, Ctlr* ctlr)
479 ctlr->flag |= Hlinear|Foptions;
483 clock(Vga* vga, Ctlr* ctlr)
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.
501 clk = mp->reg[ClockCntl] & 0x03;
503 p = (mp->pll[6]>>(clk*2)) & 0x03;
504 p |= (mp->pll[11]>>(2+clk)) & 0x04;
528 f = (2.0*RefFreq*n)/(m*p) + 0.5;
538 vga->f[0] = vga->mode->frequency;
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
548 * Use the maximum reference divider left by the BIOS for now,
549 * otherwise MCLK might be a concern. It can be calculated as
551 * Upper Limit of PLL Lock Range
552 * Minimum PLLREFCLK = -----------------------------
556 * m = Floor[-----------------]
559 * For an upper limit of 135MHz and XTALIN of 14.318MHz m
566 * The post divider may be 1, 2, 4 or 8 and is determined by
571 * and using the result to look-up p.
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]);
592 if(q > 255 || q < 16)
593 error("%s: vclk %lud out of range\n", ctlr->name, vga->f[0]);
606 * The feedback divider should be kept in the range 0x80 to 0xFF
609 * rounded to the nearest whole number.
611 vga->n[0] = (q*p)+0.5;
614 typedef struct Meminfo Meminfo;
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 */
632 * The manuals and documentation are silent on which settings
633 * to use for Mwdram, or how to tell which to use.
635 static Meminfo meminfo[] = {
639 [Mwram] { 1, 3 }, /* non TYPE_A */
642 static ushort looplatencytab[2][2] = {
643 { 8, 6 }, /* DRAM: ≤1M, > 1M */
644 { 9, 8 }, /* SDRAM: ≤1M, > 1M */
647 static ushort cyclesperqwordtab[2][2] = {
648 { 3, 2 }, /* DRAM: ≤1M, > 1M */
649 { 2, 1 }, /* SDRAM: ≤1M, > 1M */
652 static int memtype[] = {
653 -1, /* disable memory access */
654 Mdram, /* basic DRAM */
656 Medo, /* hyper page DRAM or EDO */
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.
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.
673 setdsp(Vga* vga, Ctlr*)
677 ushort table, memclk, memtyp;
678 int i, prec, xprec, fprec;
680 double pw, x, fifosz, fifoon, fifooff;
681 ushort dspon, dspoff;
682 int afifosz, lat, ncycle, pfc, rcc;
687 * Get video ram configuration from BIOS and chip
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];
699 * First we need to calculate x, the number of
700 * XCLKs that one QWORD occupies in the display FIFO.
702 * For some reason, x gets stretched out if LCD stretching
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);
711 trace("memclk %d... x %f...", memclk, x);
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.
722 trace("t %lud... xprec %d...", t, xprec);
725 * The maximum FIFO size is the number of XCLKs per QWORD
726 * multiplied by 32, for some reason. We have 11 bits to
730 trace("fifosz %f...", fifosz);
736 trace("fprec %d...", fprec);
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.
743 * It is bounded by zero and seven.
745 prec = (xprec-3 > fprec-5) ? xprec-3 : fprec-5;
753 trace("prec %d...", prec);
758 afifosz = (1<<fprec) / x;
762 fifooff = ceil(x*(afifosz-1));
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.
769 lat = looplatencytab[memtyp > 1][vga->vmz > 1*1024*1024];
770 trace("afifosz %d...fifooff %f...", afifosz, fifooff);
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);
784 * Maximum random access cycle clock.
786 ncycle = cyclesperqwordtab[memtyp > 1][vga->vmz > 1*1024*1024];
787 rcc = mem->trp + 1 + mem->tras + 1;
790 trace("rcc %d...", rcc);
792 fifoon = (rcc > floor(x)) ? rcc : floor(x);
793 fifoon += (3.0 * rcc) - 1 + pfc + ncycle;
794 trace("fifoon %f...\n", fifoon);
796 * Now finally put the bits together.
797 * x is stored in a 14 bit field with xprec bits of integer.
799 pw = x * (1<<(14-xprec));
800 mp->reg[DspConfig] = (ulong)pw | (((lat+2)&0xF)<<16) | ((prec&7)<<20);
803 * These are stored in an 11 bit field with fprec bits of integer.
805 dspon = (ushort)fifoon << (11-fprec);
806 dspoff = (ushort)fifooff << (11-fprec);
807 mp->reg[DspOnOff] = ((dspon&0x7ff) << 16) | (dspoff&0x7ff);
811 init(Vga* vga, Ctlr* ctlr)
818 if((mode->x > 640 || mode->y > 480) && mode->z == 1)
819 error("%s: no support for 1-bit mode other than 640x480x1\n",
823 if(mode->z > 8 && mp->pci == nil)
824 error("%s: no support for >8-bit color without PCI\n",
828 * Check for Rage chip
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;
857 mp->pll[PLLn2] = vga->n[0];
858 mp->pll[PLLp] &= ~(0x03<<(2*2));
883 mp->pll[PLLp] |= p<<(2*2);
884 if ((1<<p) != vga->p[0])
885 mp->pll[PLLx] |= 1<<(4+2);
887 mp->pll[PLLx] &= ~(1<<(4+2));
888 mp->reg[ClockCntl] = 2;
890 mp->reg[ConfigCntl] = 0;
892 mp->reg[CrtcGenCntl] = 0x02000000|(mp->reg[CrtcGenCntl] & ~0x01400700);
896 mp->reg[CrtcGenCntl] |= 0x00000100;
897 mp->reg[DpPixWidth] = 0x00000000;
900 mp->reg[CrtcGenCntl] |= 0x01000200;
901 mp->reg[DpPixWidth] = 0x00020202;
904 mp->reg[CrtcGenCntl] |= 0x01000300;
905 mp->reg[DpPixWidth] = 0x00030303;
908 mp->reg[CrtcGenCntl] |= 0x01000400;
909 mp->reg[DpPixWidth] = 0x00040404;
912 mp->reg[CrtcGenCntl] |= 0x01000500;
913 mp->reg[DpPixWidth] = 0x00050505;
916 mp->reg[CrtcGenCntl] |= 0x01000600;
917 mp->reg[DpPixWidth] = 0x00060606;
921 mp->reg[HTotalDisp] = (((mode->x>>3)-1)<<16)|((mode->ht>>3)-1);
922 mp->reg[HSyncStrtWid] = (((mode->ehs - mode->shs)>>3)<<16)
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;
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
936 mp->reg[OffPitch] = (vga->virtx/8)<<22;
938 mp->reg[OvrClr] = Pblack;
940 if(vga->linear && mode->z != 1)
941 ctlr->flag |= Ulinear;
944 * Heuristic fiddling on LT PRO.
945 * Do this before setdsp so the stretching is right.
948 /* use non-shadowed registers */
949 mp->lcd[LCD_GenCtrl] &= ~0x00000404;
950 mp->lcd[LCD_ConfigPanel] |= 0x00004000;
952 mp->lcd[LCD_VertStretch] = 0;
953 y = ((mp->lcd[LCD_ExtVertStretch]>>11) & 0x7FF)+1;
955 x = (mode->y*1024)/y;
956 mp->lcd[LCD_VertStretch] = 0xC0000000|x;
958 mp->lcd[LCD_ExtVertStretch] &= ~0x00400400;
961 * The x value doesn't seem to be available on all
962 * chips so intuit it from the y value which seems to
965 mp->lcd[LCD_HorzStretch] &= ~0xC00000FF;
966 x = (mp->lcd[LCD_HorzStretch]>>20) & 0xFF;
988 x = (mode->x*4096)/x;
989 mp->lcd[LCD_HorzStretch] |= 0xC0000000|x;
993 if(ctlr->flag&Uenhanced)
1000 load(Vga* vga, Ctlr* ctlr)
1008 * Unlock the CRTC and LCD registers.
1010 mp->iow32(mp, CrtcGenCntl, mp->ior32(mp, CrtcGenCntl)&~0x00400000);
1012 lcdw32(mp, LCD_GenCtrl, mp->lcd[LCD_GenCtrl]|0x80000000);
1015 * Always use an aperture on a 16Mb boundary.
1017 if(ctlr->flag & Ulinear)
1018 mp->reg[ConfigCntl] = ((vga->vmb/(4*1024*1024))<<4)|0x02;
1020 mp->iow32(mp, ConfigCntl, mp->reg[ConfigCntl]);
1022 mp->iow32(mp, GenTestCntl, 0);
1023 mp->iow32(mp, GenTestCntl, 0x100);
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]);
1035 for(i=0; i<Nlcd; i++)
1036 lcdw32(mp, i, mp->lcd[i]);
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]);
1054 pllw(mp, PLLn2, mp->pll[PLLn2]);
1055 pllw(mp, PLLp, mp->pll[PLLp]);
1056 pllw(mp, PLLn3, mp->pll[PLLn3]);
1058 mp->iow32(mp, ClockCntl, mp->reg[ClockCntl]);
1059 mp->iow32(mp, ClockCntl, 0x40|mp->reg[ClockCntl]);
1061 mp->iow32(mp, DpPixWidth, mp->reg[DpPixWidth]);
1063 if(vga->mode->z > 8){
1066 * We need to initialize the palette, since the DACs use it
1067 * in true color modes. First see if the card supports an
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;
1077 if(mp->reg[DacCntl] & 0x100)
1078 sh = 0; /* 8-bit DAC */
1080 sh = 2; /* 6-bit DAC */
1082 for(i=0; i<256; i++)
1083 setpalette(i, i>>sh, i>>sh, i>>sh);
1086 ctlr->flag |= Fload;
1090 pixelclock(Vga* vga, Ctlr* ctlr)
1094 int memclk, ref_freq, ref_divider, min_freq, max_freq;
1095 int feedback, nmult, pd, post, value;
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.
1103 * This is the clock LCDs use in vgadb to set the DSP
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);
1117 trace("memclk %ud\n", memclk);
1118 s = *(ushort*)readbios(sizeof s, 0xc0000+table+8);
1120 trace("ref_freq %ud\n", ref_freq);
1121 s = *(ushort*)readbios(sizeof s, 0xc0000+table+10);
1123 trace("ref_divider %ud\n", ref_divider);
1124 s = *(ushort*)readbios(sizeof s, 0xc0000+table+2);
1126 trace("min_freq %ud\n", min_freq);
1127 s = *(ushort*)readbios(sizeof s, 0xc0000+table+4);
1129 trace("max_freq %ud\n", max_freq);
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);
1165 trace("post = %d\n", post);
1167 feedback = mp->pll[PLLn0];
1168 if(mp->pll[PLLx] & 0x08)
1173 clock = (ref_freq/10000)*nmult*feedback;
1174 clock /= ref_divider*post;
1177 Bprint(&stdout, "%s pixel clock = %ud\n", ctlr->name, clock);
1180 static void dumpmach64bios(Mach64xx*);
1183 dump(Vga* vga, Ctlr* ctlr)
1188 static int first = 1;
1190 if((mp = vga->private) == 0)
1193 Bprint(&stdout, "%s pci %p io %lux %s\n", ctlr->name,
1194 mp->pci, mp->io, mp->ior32 == pciior32 ? "pciregs" : "ioregs");
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]);
1201 printitem(ctlr->name, "PLL");
1202 for(i = 0; i < Npll; i++)
1203 printreg(mp->pll[i]);
1204 Bprint(&stdout, "\n");
1206 switch(mp->reg[ConfigChipId] & 0xFFFF){
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]);
1225 for(i = 0; i < 4; i++){
1227 p = (mp->pll[6]>>(i*2)) & 0x03;
1228 p |= (mp->pll[11]>>(2+i)) & 0x04;
1252 Bprint(&stdout, "unknown VCLK%d\n", i);
1254 f = (2.0*RefFreq*n)/(m*p) + 0.5;
1255 Bprint(&stdout, "%s VCLK%d\t%ud\n", ctlr->name, i, (int)f);
1259 pixelclock(vga, ctlr);
1278 * mostly derived from the xfree86 probe routines.
1281 dumpmach64bios(Mach64xx *mp)
1283 int i, romtable, clocktable, freqtable, lcdtable, lcdpanel;
1284 uchar bios[0x10000];
1286 memmove(bios, readbios(sizeof bios, 0xC0000), sizeof bios);
1288 /* find magic string */
1289 for(i=0; i<1024; i++)
1290 if(strncmp((char*)bios+i, " 761295520", 10) == 0)
1294 Bprint(&stdout, "no ATI bios found\n");
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");
1305 clocktable = *(ushort*)(bios+romtable+0x10);
1306 if(clocktable+0x0C > sizeof(bios)) {
1307 Bprint(&stdout, "couldn't find ATI clock table\n");
1311 freqtable = *(ushort*)(bios+clocktable-2);
1312 if(freqtable+0x20 > sizeof(bios)) {
1313 Bprint(&stdout, "couldn't find ATI frequency table\n");
1317 Bprint(&stdout, "ATI BIOS rom 0x%x freq 0x%x clock 0x%x\n", romtable, freqtable, clocktable);
1318 Bprint(&stdout, "clocks:");
1320 Bprint(&stdout, " %d", *(ushort*)(bios+freqtable+2*i));
1321 Bprint(&stdout, "\n");
1323 Bprint(&stdout, "programmable clock: %d\n", bios[clocktable]);
1324 Bprint(&stdout, "clock to program: %d\n", bios[clocktable+6]);
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");
1330 Bprint(&stdout, "default reference numerator: 157500\n");
1331 Bprint(&stdout, "default reference denominator: 11\n");
1334 switch(bios[clocktable]) {
1336 Bprint(&stdout, "ics2595\n");
1337 Bprint(&stdout, "reference divider: %d\n", *(ushort*)(bios+clocktable+0x0A));
1340 Bprint(&stdout, "stg1703\n");
1343 Bprint(&stdout, "ch8398\n");
1346 Bprint(&stdout, "internal clock\n");
1347 Bprint(&stdout, "reference divider in plls\n");
1349 case ClockAtt20c408:
1350 Bprint(&stdout, "att 20c408\n");
1352 case ClockIbmrgb514:
1353 Bprint(&stdout, "ibm rgb514\n");
1354 Bprint(&stdout, "clock to program = 7\n");
1357 Bprint(&stdout, "unknown clock\n");
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");
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");
1375 Bprint(&stdout, "panelid %d x %d y %d\n", bios[lcdpanel], *(ushort*)(bios+lcdpanel+0x19), *(ushort*)(bios+lcdpanel+0x1B));
1381 "mach64xx", /* name */
1389 Ctlr mach64xxhwgc = {
1390 "mach64xxhwgc", /* name */