#include #include #include #include "pci.h" #include "vga.h" /* * IBM RGB524. * 170/220MHz High Performance Palette DAC. * * Assumes hooked up to an S3 Vision96[48]. */ enum { IndexLo = 0x00, IndexHi = 0x01, Data = 0x02, IndexCtl = 0x03, }; enum { /* index registers */ MiscClock = 0x02, PixelFormat = 0x0A, PLLControl1 = 0x10, PLLControl2 = 0x11, PLLReference = 0x14, Frequency0 = 0x20, MiscControl1 = 0x70, MiscControl2 = 0x71, }; static uchar setrs2(void) { uchar rs2; rs2 = vgaxi(Crtx, 0x55); vgaxo(Crtx, 0x55, (rs2 & 0xFC)|0x01); return rs2; } static uchar rgb524xi(int index) { outportb(dacxreg[IndexLo], index & 0xFF); outportb(dacxreg[IndexHi], (index>>8) & 0xFF); return inportb(dacxreg[Data]); } static void rgb524xo(int index, uchar data) { outportb(dacxreg[IndexLo], index & 0xFF); outportb(dacxreg[IndexHi], (index>>8) & 0xFF); outportb(dacxreg[Data], data); } static void restorers2(uchar rs2) { vgaxo(Crtx, 0x55, rs2); } static void clock(Vga* vga, Ctlr* ctlr) { if(vga->f[0] >= 16250000 && vga->f[0] <= 32000000){ vga->f[0] = (vga->f[0]/250000)*250000; vga->d[0] = (4*vga->f[0])/1000000 - 65; } else if(vga->f[0] >= 32500000 && vga->f[0] <= 64000000){ vga->f[0] = (vga->f[0]/500000)*500000; vga->d[0] = 0x40|((2*vga->f[0])/1000000 - 65); } else if(vga->f[0] >= 65000000 && vga->f[0] <= 128000000){ vga->f[0] = (vga->f[0]/1000000)*1000000; vga->d[0] = 0x80|(vga->f[0]/1000000 - 65); } else if(vga->f[0] >= 130000000 && vga->f[0] <= 220000000){ vga->f[0] = (vga->f[0]/2000000)*2000000; vga->d[0] = 0xC0|((vga->f[0]/2)/1000000 - 65); } else error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]); } static void init(Vga* vga, Ctlr* ctlr) { ulong pclk; char *p; /* * Part comes in -170 and -220MHz speed-grades. */ pclk = 170000000; if(p = strrchr(ctlr->name, '-')) pclk = strtoul(p+1, 0, 0) * 1000000; /* * If we don't already have a desired pclk, * take it from the mode. * Check it's within range. */ if(vga->f[0] == 0) vga->f[0] = vga->mode->frequency; if(vga->f[0] > pclk) error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]); /* * Determine whether to use clock-doubler or not. */ if((ctlr->flag & Uclk2) == 0 && vga->mode->z == 8) resyncinit(vga, ctlr, Uclk2, 0); /* * Clock bits. If the desired video clock is * one of the two standard VGA clocks it can just be * set using bits <3:2> of vga->misc, otherwise we * need to programme the PLL. */ vga->misc &= ~0x0C; if(vga->mode->z == 8 || (vga->f[0] != VgaFreq0 && vga->f[0] != VgaFreq1)){ /* * Initialise the PLL parameters. * Use internal FS3 fixed-reference divider. */ clock(vga, ctlr); vga->i[0] = 0x03; } else if(vga->f[0] == VgaFreq0) vga->i[0] = 0; else if(vga->f[0] == VgaFreq1){ vga->misc |= 0x04; vga->i[0] = 1; } ctlr->flag |= Finit; } static void load(Vga* vga, Ctlr* ctlr) { uchar mc2, rs2, x; char *val; int f; rs2 = setrs2(); /* * Set VgaFreq[01]. */ rgb524xo(PLLControl1, 0x00); rgb524xo(Frequency0, 0x24); rgb524xo(Frequency0+1, 0x30); if(val = dbattr(vga->attr, "rgb524refclk")){ f = strtol(val, 0, 0); if(f > 1000000) f /= 1000000; rgb524xo(PLLReference, f/2); } /* * Enable pixel programming and clock divide * factor. */ x = rgb524xi(MiscClock) & ~0x0E; x |= 0x01; if(ctlr->flag & Uclk2) x |= 0x02; rgb524xo(MiscClock, x); if(vga->mode->z == 1) rgb524xo(PixelFormat, 0x02); else if(vga->mode->z == 8) rgb524xo(PixelFormat, 0x03); x = rgb524xi(MiscControl1) & ~0x41; x |= 0x01; rgb524xo(MiscControl1, x); mc2 = rgb524xi(MiscControl2) & ~0x41; vga->crt[0x22] &= ~0x08; if(vga->i[0] == 3){ rgb524xo(Frequency0+3, vga->d[0]); rgb524xo(PLLControl1, 0x02); rgb524xo(PLLControl2, vga->i[0]); mc2 |= 0x41; vga->crt[0x22] |= 0x08; } rgb524xo(MiscControl2, mc2); vgaxo(Crtx, 0x22, vga->crt[0x22]); restorers2(rs2); ctlr->flag |= Fload; } static void dump(Vga*, Ctlr* ctlr) { uchar rs2, r, x[256]; char buf[32]; int df, i, maxf, vcodc, vf; rs2 = setrs2(); printitem(ctlr->name, "index00"); for(i = 0x00; i < 0x0F; i++){ x[i] = rgb524xi(i); printreg(x[i]); } printitem(ctlr->name, "index10"); for(i = 0x10; i < 0x17; i++){ x[i] = rgb524xi(i); printreg(x[i]); } printitem(ctlr->name, "index20"); for(i = 0x20; i < 0x30; i++){ x[i] = rgb524xi(i); printreg(x[i]); } printitem(ctlr->name, "index30"); for(i = 0x30; i < 0x37; i++){ x[i] = rgb524xi(i); printreg(x[i]); } printitem(ctlr->name, "index40"); for(i = 0x40; i < 0x49; i++){ x[i] = rgb524xi(i); printreg(x[i]); } printitem(ctlr->name, "index60"); for(i = 0x60; i < 0x63; i++){ x[i] = rgb524xi(i); printreg(x[i]); } printitem(ctlr->name, "index70"); for(i = 0x70; i < 0x73; i++){ x[i] = rgb524xi(i); printreg(x[i]); } printitem(ctlr->name, "index8E"); for(i = 0x8E; i < 0x92; i++){ x[i] = rgb524xi(i); printreg(x[i]); } restorers2(rs2); /* * x[0x10] pixel clock frequency selection * 0, 2 for direct programming * x[0x20-0x2F] pixel frequency 0-15 */ printitem(ctlr->name, "refclk"); Bprint(&stdout, "%12ud\n", x[PLLReference]*2*1000000); if((i = (x[0x10] & 0x07)) == 0x00 || i == 0x02){ /* * Direct programming, external frequency select. * F[0-4] are probably tied directly to the 2 clock-select * bits in the VGA Misc register. */ if(i == 0) maxf = 4; else maxf = 16; for(i = 0; i < maxf; i++){ if((r = x[0x20+i]) == 0) continue; sprint(buf, "direct F%X", i); printitem(ctlr->name, buf); df = (r>>6) & 0x03; vcodc = r & 0x3F; vf = 0; switch(df){ case 0: vf = (vcodc+65)/4; break; case 1: vf = (vcodc+65)/2; break; case 2: vf = (vcodc+65); break; case 3: vf = (vcodc+65)*2; break; } Bprint(&stdout, "%12ud\n", vf); } } } Ctlr rgb524 = { "rgb524", /* name */ 0, /* snarf */ 0, /* options */ init, /* init */ load, /* load */ dump, /* dump */ };