📄 mach64xx.c
字号:
* * For some reason, x gets stretched out if LCD stretching * is turned on. */ x = ((double)memclk*640000.0) / ((double)vga->mode->frequency * (double)vga->mode->z); if(mp->lcd[LCD_HorzStretch] & (1<<31)) x *= 4096.0 / (double)(mp->lcd[LCD_HorzStretch] & 0xFFFF); trace("memclk %d... x %f...", memclk, x); /* * We have 14 bits to specify x in. Decide where to * put the decimal (err, binary) point by counting how * many significant bits are in the integer portion of x. */ t = x; for(i=31; i>=0; i--) if(t & (1<<i)) break; xprec = i+1; trace("t %lud... xprec %d...", t, xprec); /* * The maximum FIFO size is the number of XCLKs per QWORD * multiplied by 32, for some reason. We have 11 bits to * specify fifosz. */ fifosz = x * 32.0; trace("fifosz %f...", fifosz); t = fifosz; for(i=31; i>=0; i--) if(t & (1<<i)) break; fprec = i+1; trace("fprec %d...", fprec); /* * Precision is specified as 3 less than the number of bits * in the integer part of x, and 5 less than the number of bits * in the integer part of fifosz. * * It is bounded by zero and seven. */ prec = (xprec-3 > fprec-5) ? xprec-3 : fprec-5; if(prec < 0) prec = 0; if(prec > 7) prec = 7; xprec = prec+3; fprec = prec+5; trace("prec %d...", prec); /* * Actual fifo size */ afifosz = (1<<fprec) / x; if(afifosz > 32) afifosz = 32; fifooff = ceil(x*(afifosz-1)); /* * I am suspicious of this table, lifted from ATI docs, * because it doesn't agree with the Windows drivers. * We always get 0x0A for lat+2 while Windows uses 0x08. */ lat = looplatencytab[memtyp > 1][vga->vmz > 1*1024*1024]; trace("afifosz %d...fifooff %f...", afifosz, fifooff); /* * Page fault clock */ t = mp->reg[MemCntl]; mem->trp = (t>>8)&3; /* RAS precharge time */ mem->trcd = (t>>10)&3; /* RAS to CAS delay */ mem->tcrd = (t>>12)&1; /* CAS to RAS delay */ mem->tras = (t>>16)&7; /* RAS low minimum pulse width */ pfc = mem->trp + 1 + mem->trcd + 1 + mem->tcrd; trace("pfc %d...", pfc); /* * Maximum random access cycle clock. */ ncycle = cyclesperqwordtab[memtyp > 1][vga->vmz > 1*1024*1024]; rcc = mem->trp + 1 + mem->tras + 1; if(rcc < pfc+ncycle) rcc = pfc+ncycle; trace("rcc %d...", rcc); fifoon = (rcc > floor(x)) ? rcc : floor(x); fifoon += (3.0 * rcc) - 1 + pfc + ncycle; trace("fifoon %f...\n", fifoon); /* * Now finally put the bits together. * x is stored in a 14 bit field with xprec bits of integer. */ pw = x * (1<<(14-xprec)); mp->reg[DspConfig] = (ulong)pw | (((lat+2)&0xF)<<16) | ((prec&7)<<20); /* * These are stored in an 11 bit field with fprec bits of integer. */ dspon = (ushort)fifoon << (11-fprec); dspoff = (ushort)fifooff << (11-fprec); mp->reg[DspOnOff] = ((dspon&0x7ff) << 16) | (dspoff&0x7ff);}static voidinit(Vga* vga, Ctlr* ctlr){ Mode *mode; Mach64xx *mp; int p, x, y; mode = vga->mode; if((mode->x > 640 || mode->y > 480) && mode->z == 1) error("%s: no support for 1-bit mode other than 640x480x1\n", ctlr->name); mp = vga->private; if(mode->z > 8 && mp->pci == nil) error("%s: no support for >8-bit color without PCI\n", ctlr->name); /* * Check for Rage chip */ switch (mp->reg[ConfigChipId]&0xffff) { case ('G'<<8)|'B': /* 4742: 264GT PRO */ case ('G'<<8)|'D': /* 4744: 264GT PRO */ case ('G'<<8)|'I': /* 4749: 264GT PRO */ case ('G'<<8)|'M': /* 474D: Rage XL */ case ('G'<<8)|'P': /* 4750: 264GT PRO */ case ('G'<<8)|'Q': /* 4751: 264GT PRO */ case ('G'<<8)|'R': /* 4752: */ case ('G'<<8)|'U': /* 4755: 264GT DVD */ case ('G'<<8)|'V': /* 4756: Rage2C */ case ('G'<<8)|'Z': /* 475A: Rage2C */ case ('V'<<8)|'U': /* 5655: 264VT3 */ case ('V'<<8)|'V': /* 5656: 264VT4 */ case ('G'<<8)|'T': /* 4754: 264GT[B] */ case ('V'<<8)|'T': /* 5654: 264VT/GT/VTB */ case ('L'<<8)|'B': /* 4C42: Rage LTPro AGP */ case ('L'<<8)|'I': /* 4C49: 264LT PRO */ case ('L'<<8)|'M': /* 4C4D: Rage Mobility */ case ('L'<<8)|'P': /* 4C50: 264LT PRO */ ctlr->flag |= Uenhanced; break; } /* * Always use VCLK2. */ clock(vga, ctlr); mp->pll[PLLn2] = vga->n[0]; mp->pll[PLLp] &= ~(0x03<<(2*2)); switch(vga->p[0]){ case 1: case 3: p = 0; break; case 2: p = 1; break; case 4: case 6: p = 2; break; case 8: case 12: p = 3; break; default: p = 3; break; } mp->pll[PLLp] |= p<<(2*2); if ((1<<p) != vga->p[0]) mp->pll[PLLx] |= 1<<(4+2); else mp->pll[PLLx] &= ~(1<<(4+2)); mp->reg[ClockCntl] = 2; mp->reg[ConfigCntl] = 0; mp->reg[CrtcGenCntl] = 0x02000000|(mp->reg[CrtcGenCntl] & ~0x01400700); switch(mode->z){ default: case 1: mp->reg[CrtcGenCntl] |= 0x00000100; mp->reg[DpPixWidth] = 0x00000000; break; case 8: mp->reg[CrtcGenCntl] |= 0x01000200; mp->reg[DpPixWidth] = 0x00020202; break; case 15: mp->reg[CrtcGenCntl] |= 0x01000300; mp->reg[DpPixWidth] = 0x00030303; break; case 16: mp->reg[CrtcGenCntl] |= 0x01000400; mp->reg[DpPixWidth] = 0x00040404; break; case 24: mp->reg[CrtcGenCntl] |= 0x01000500; mp->reg[DpPixWidth] = 0x00050505; break; case 32: mp->reg[CrtcGenCntl] |= 0x01000600; mp->reg[DpPixWidth] = 0x00060606; break; } mp->reg[HTotalDisp] = (((mode->x>>3)-1)<<16)|((mode->ht>>3)-1); mp->reg[HSyncStrtWid] = (((mode->ehs - mode->shs)>>3)<<16) |((mode->shs>>3)-1); if(mode->hsync == '-') mp->reg[HSyncStrtWid] |= 0x00200000; mp->reg[VTotalDisp] = ((mode->y-1)<<16)|(mode->vt-1); mp->reg[VSyncStrtWid] = ((mode->vre - mode->vrs)<<16)|(mode->vrs-1); if(mode->vsync == '-') mp->reg[VSyncStrtWid] |= 0x00200000; mp->reg[IntCntl] = 0; /* * This used to set it to (mode->x/(8*2))<<22 for depths < 8, * but from the manual that seems wrong to me. -rsc */ mp->reg[OffPitch] = (vga->virtx/8)<<22; mp->reg[OvrClr] = Pblack; if(vga->linear && mode->z != 1) ctlr->flag |= Ulinear; /* * Heuristic fiddling on LT PRO. * Do this before setdsp so the stretching is right. */ if(mp->lcdon){ /* use non-shadowed registers */ mp->lcd[LCD_GenCtrl] &= ~0x00000404; mp->lcd[LCD_ConfigPanel] |= 0x00004000; mp->lcd[LCD_VertStretch] = 0; y = ((mp->lcd[LCD_ExtVertStretch]>>11) & 0x7FF)+1; if(mode->y < y){ x = (mode->y*1024)/y; mp->lcd[LCD_VertStretch] = 0xC0000000|x; } mp->lcd[LCD_ExtVertStretch] &= ~0x00400400; /* * The x value doesn't seem to be available on all * chips so intuit it from the y value which seems to * be reliable. */ mp->lcd[LCD_HorzStretch] &= ~0xC00000FF; x = (mp->lcd[LCD_HorzStretch]>>20) & 0xFF; if(x == 0){ switch(y){ default: break; case 480: x = 640; break; case 600: x = 800; break; case 768: x = 1024; break; case 1024: x = 1280; break; } } else x = (x+1)*8; if(mode->x < x){ x = (mode->x*4096)/x; mp->lcd[LCD_HorzStretch] |= 0xC0000000|x; } } if(ctlr->flag&Uenhanced) setdsp(vga, ctlr); ctlr->flag |= Finit;}static voidload(Vga* vga, Ctlr* ctlr){ Mach64xx *mp; int i; mp = vga->private; /* * Unlock the CRTC and LCD registers. */ mp->iow32(mp, CrtcGenCntl, mp->ior32(mp, CrtcGenCntl)&~0x00400000); if(mp->lcdon) lcdw32(mp, LCD_GenCtrl, mp->lcd[LCD_GenCtrl]|0x80000000); /* * Always use an aperture on a 16Mb boundary. */ if(ctlr->flag & Ulinear) mp->reg[ConfigCntl] = ((vga->vmb/(4*1024*1024))<<4)|0x02; mp->iow32(mp, ConfigCntl, mp->reg[ConfigCntl]); mp->iow32(mp, GenTestCntl, 0); mp->iow32(mp, GenTestCntl, 0x100); if((ctlr->flag&Uenhanced) == 0) mp->iow32(mp, MemCntl, mp->reg[MemCntl] & ~0x70000); mp->iow32(mp, BusCntl, mp->reg[BusCntl]); mp->iow32(mp, HTotalDisp, mp->reg[HTotalDisp]); mp->iow32(mp, HSyncStrtWid, mp->reg[HSyncStrtWid]); mp->iow32(mp, VTotalDisp, mp->reg[VTotalDisp]); mp->iow32(mp, VSyncStrtWid, mp->reg[VSyncStrtWid]); mp->iow32(mp, IntCntl, mp->reg[IntCntl]); mp->iow32(mp, OffPitch, mp->reg[OffPitch]); if(mp->lcdon){ for(i=0; i<Nlcd; i++) lcdw32(mp, i, mp->lcd[i]); } mp->iow32(mp, GenTestCntl, mp->reg[GenTestCntl]); mp->iow32(mp, ConfigCntl, mp->reg[ConfigCntl]); mp->iow32(mp, CrtcGenCntl, mp->reg[CrtcGenCntl]); mp->iow32(mp, OvrClr, mp->reg[OvrClr]); mp->iow32(mp, OvrWidLR, mp->reg[OvrWidLR]); mp->iow32(mp, OvrWidTB, mp->reg[OvrWidTB]); if(ctlr->flag&Uenhanced){ mp->iow32(mp, DacRegs, mp->reg[DacRegs]); mp->iow32(mp, DacCntl, mp->reg[DacCntl]); mp->iow32(mp, CrtcGenCntl, mp->reg[CrtcGenCntl]&~0x02000000); mp->iow32(mp, DspOnOff, mp->reg[DspOnOff]); mp->iow32(mp, DspConfig, mp->reg[DspConfig]); mp->iow32(mp, CrtcGenCntl, mp->reg[CrtcGenCntl]); pllw(mp, PLLx, mp->pll[PLLx]); } pllw(mp, PLLn2, mp->pll[PLLn2]); pllw(mp, PLLp, mp->pll[PLLp]); pllw(mp, PLLn3, mp->pll[PLLn3]); mp->iow32(mp, ClockCntl, mp->reg[ClockCntl]); mp->iow32(mp, ClockCntl, 0x40|mp->reg[ClockCntl]); mp->iow32(mp, DpPixWidth, mp->reg[DpPixWidth]); if(vga->mode->z > 8){ int sh, i; /* * We need to initialize the palette, since the DACs use it * in true color modes. First see if the card supports an * 8-bit DAC. */ mp->iow32(mp, DacCntl, mp->reg[DacCntl] | 0x100); if(mp->ior32(mp, DacCntl)&0x100){ /* card appears to support it */ vgactlw("palettedepth", "8"); mp->reg[DacCntl] |= 0x100; } if(mp->reg[DacCntl] & 0x100) sh = 0; /* 8-bit DAC */ else sh = 2; /* 6-bit DAC */ for(i=0; i<256; i++) setpalette(i, i>>sh, i>>sh, i>>sh); } ctlr->flag |= Fload;}static voidpixelclock(Vga* vga, Ctlr* ctlr){ Mach64xx *mp; ushort table, s; int memclk, ref_freq, ref_divider, min_freq, max_freq; int feedback, nmult, pd, post, value; int clock; /* * Find the pixel clock from the BIOS and current * settings. Lifted from the ATI-supplied example code. * The clocks stored in the BIOS table are in kHz/10. * * This is the clock LCDs use in vgadb to set the DSP * values. */ mp = vga->private; /* * GetPLLInfo() */ table = *(ushort*)readbios(sizeof table, 0xc0048); trace("rom table offset %uX\n", table); table = *(ushort*)readbios(sizeof table, 0xc0000+table+16); trace("freq table offset %uX\n", table); s = *(ushort*)readbios(sizeof s, 0xc0000+table+18); memclk = s*10000; trace("memclk %ud\n", memclk); s = *(ushort*)readbios(sizeof s, 0xc0000+table+8); ref_freq = s*10000; trace("ref_freq %ud\n", ref_freq); s = *(ushort*)readbios(sizeof s, 0xc0000+table+10); ref_divider = s; trace("ref_divider %ud\n", ref_divider); s = *(ushort*)readbios(sizeof s, 0xc0000+table+2); min_freq = s*10000; trace("min_freq %ud\n", min_freq); s = *(ushort*)readbios(sizeof s, 0xc0000+table+4); max_freq = s*10000; trace("max_freq %ud\n", max_freq); /* * GetDivider() */ pd = mp->pll[PLLp] & 0x03; value = (mp->pll[PLLx] & 0x10)>>2; trace("pd %uX value %uX (|%d)\n", pd, value, value|pd); value |= pd; post = 0; switch(value){ case 0: post = 1; break; case 1: post = 2; break; case 2: post = 4; break; case 3: post = 8; break; case 4: post = 3; break; case 5: post = 0; break; case 6: post = 6; break; case 7: post = 12; break; } trace("post = %d\n", post); feedback = mp->pll[PLLn0]; if(mp->pll[PLLx] & 0x08) nmult = 4; else nmult = 2; clock = (ref_freq/10000)*nmult*feedback; clock /= ref_divider*post; clock *= 10000; Bprint(&stdout, "%s pixel clock = %ud\n", ctlr->name, clock);}static void dumpmach64bios(Mach64xx*);static voiddump(Vga* vga, Ctlr* ctlr){ Mach64xx *mp; int i, m, n, p; double f; static int first = 1; if((mp = vga->private) == 0) return; Bprint(&stdout, "%s pci %p io %lux %s\n", ctlr->name, mp->pci, mp->io, mp->ior32 == pciior32 ? "pciregs" : "ioregs"); if(mp->pci) Bprint(&stdout, "%s ccru %ux\n", ctlr->name, mp->pci->ccru); for(i = 0; i < Nreg; i++) Bprint(&stdout, "%s %-*s%.8luX\n", ctlr->name, 20, iorname[i], mp->reg[i]); printitem(ctlr->name, "PLL"); for(i = 0; i < Npll; i++) printreg(mp->pll[i]); Bprint(&stdout, "\n"); switch(mp->reg[ConfigChipId] & 0xFFFF){ default: break; case ('L'<<8)|'B': /* 4C42: Rage LTPro AGP */ case ('L'<<8)|'I': /* 4C49: Rage 3D LTPro */ case ('L'<<8)|'M': /* 4C4D: Rage Mobility */ case ('L'<<8)|'P': /* 4C50: Rage 3D LTPro */ for(i = 0; i < Nlcd; i++) Bprint(&stdout, "%s %-*s%.8luX\n", ctlr->name, 20, lcdname[i], mp->lcd[i]); break; } /* * (2*r*n) * f = ------- * (m*p) */ m = mp->pll[2]; for(i = 0; i < 4; i++){ n = mp->pll[7+i]; p = (mp->pll[6]>>(i*2)) & 0x03; p |= (mp->pll[11]>>(2+i)) & 0x04; switch(p){ case 0: case 1: case 2: case 3: p = 1<<p; break; case 4+0: p = 3; break; case 4+2: p = 6; break; case 4+3: p = 12; break; default: case 4+1: p = -1; break; } if(m*p == 0) Bprint(&stdout, "unknown VCLK%d\n", i); else { f = (2.0*RefFreq*n)/(m*p) + 0.5; Bprint(&stdout, "%s VCLK%d\t%ud\n", ctlr->name, i, (int)f); } } pixelclock(vga, ctlr); if(first) { first = 0; dumpmach64bios(mp); }}enum { ClockFixed=0, ClockIcs2595, ClockStg1703, ClockCh8398, ClockInternal, ClockAtt20c408, ClockIbmrgb514};/* * mostly derived from the xfree86 probe routines. */static void dumpmach64bios(Mach64xx *mp){ int i, romtable, clocktable, freqtable, lcdtable, lcdpanel; uchar bios[0x10000]; memmove(bios, readbios(sizeof bios, 0xC0000), sizeof bios); /* find magic string */ for(i=0; i<1024; i++) if(strncmp((char*)bios+i, " 761295520", 10) == 0) break; if(i==1024) { Bprint(&stdout, "no ATI bios found\n"); return; } /* this is horribly endian dependent. sorry. */ romtable = *(ushort*)(bios+0x48); if(romtable+0x12 > sizeof(bios)) { Bprint(&stdout, "couldn't find ATI rom table\n"); return; } clocktable = *(ushort*)(bios+romtable+0x10); if(clocktable+0x0C > sizeof(bios)) { Bprint(&stdout, "couldn't find ATI clock table\n"); return; } freqtable = *(ushort*)(bios+clocktable-2); if(freqtable+0x20 > sizeof(bios)) { Bprint(&stdout, "couldn't find ATI frequency table\n"); return; } Bprint(&stdout, "ATI BIOS rom 0x%x freq 0x%x clock 0x%x\n", romtable, freqtable, clocktable); Bprint(&stdout, "clocks:"); for(i=0; i<16; i++) Bprint(&stdout, " %d", *(ushort*)(bios+freqtable+2*i)); Bprint(&stdout, "\n"); Bprint(&stdout, "programmable clock: %d\n", bios[clocktable]); Bprint(&stdout, "clock to program: %d\n", bios[clocktable+6]); if(*(ushort*)(bios+clocktable+8) != 1430) { Bprint(&stdout, "reference numerator: %d\n", *(ushort*)(bios+clocktable+8)*10); Bprint(&stdout, "reference denominator: 1\n"); } else { Bprint(&stdout, "default reference numerator: 157500\n"); Bprint(&stdout, "default reference denominator: 11\n"); } switch(bios[clocktable]) { case ClockIcs2595: Bprint(&stdout, "ics2595\n"); Bprint(&stdout, "reference divider: %d\n", *(ushort*)(bios+clocktable+0x0A)); break; case ClockStg1703: Bprint(&stdout, "stg1703\n"); break; case ClockCh8398: Bprint(&stdout, "ch8398\n"); break; case ClockInternal: Bprint(&stdout, "internal clock\n"); Bprint(&stdout, "reference divider in plls\n"); break; case ClockAtt20c408: Bprint(&stdout, "att 20c408\n"); break; case ClockIbmrgb514: Bprint(&stdout, "ibm rgb514\n"); Bprint(&stdout, "clock to program = 7\n"); break; default: Bprint(&stdout, "unknown clock\n"); break; } USED(mp); if(1 || mp->lcdpanelid) { lcdtable = *(ushort*)(bios+0x78); if(lcdtable+5 > sizeof bios || lcdtable+bios[lcdtable+5] > sizeof bios) { Bprint(&stdout, "can't find lcd bios table\n"); goto NoLcd; } lcdpanel = *(ushort*)(bios+lcdtable+0x0A); if(lcdpanel+0x1D > sizeof bios /*|| bios[lcdpanel] != mp->lcdpanelid*/) { Bprint(&stdout, "can't find lcd bios table0\n"); goto NoLcd; } Bprint(&stdout, "panelid %d x %d y %d\n", bios[lcdpanel], *(ushort*)(bios+lcdpanel+0x19), *(ushort*)(bios+lcdpanel+0x1B)); }NoLcd:;}Ctlr mach64xx = { "mach64xx", /* name */ snarf, /* snarf */ 0, /* options */ init, /* init */ load, /* load */ dump, /* dump */};Ctlr mach64xxhwgc = { "mach64xxhwgc", /* name */ 0, /* snarf */ 0, /* options */ 0, /* init */ 0, /* load */ 0, /* dump */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -