17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier
5*9a747e4fSDavid du Colombier #include "pci.h"
67dd7cddfSDavid du Colombier #include "vga.h"
77dd7cddfSDavid du Colombier
87dd7cddfSDavid du Colombier enum
97dd7cddfSDavid du Colombier {
107dd7cddfSDavid du Colombier X= 0x3D6, /* index reg */
117dd7cddfSDavid du Colombier D= 0x3D7, /* data reg */
127dd7cddfSDavid du Colombier };
137dd7cddfSDavid du Colombier
147dd7cddfSDavid du Colombier static int misc[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xE, 0x28, 0x29,
157dd7cddfSDavid du Colombier 0x70, 0x72, 0x73, 0x7D, 0x7F, -1};
167dd7cddfSDavid du Colombier static int map[] = { 0x7, 0x8, 0xB, 0xC, 0x10, 0x11, -1};
177dd7cddfSDavid du Colombier static int flags[] = { 0xF, 0x2B, 0x44, 0x45, -1};
187dd7cddfSDavid du Colombier static int compat[] = { 0x14, 0x15, 0x1F, 0x7E, -1};
197dd7cddfSDavid du Colombier static int clock[] = { 0x30, 0x31, 0x32, 0x33, -1};
207dd7cddfSDavid du Colombier static int mm[] = { 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, -1};
217dd7cddfSDavid du Colombier static int alt[] = { 0x0D, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E,
227dd7cddfSDavid du Colombier 0x24, 0x25, 0x26, 0x64, 0x65, 0x66, 0x67, -1};
237dd7cddfSDavid du Colombier static int flat[] = { 0x2C, 0x2D, 0x2E, 0x2F, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
247dd7cddfSDavid du Colombier 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E,
257dd7cddfSDavid du Colombier 0x5F, 0x60, 0x61, 0x62, 0x63, 0x68, 0x6C, 0x6E, 0x6F, -1};
267dd7cddfSDavid du Colombier
277dd7cddfSDavid du Colombier typedef struct Group Group;
287dd7cddfSDavid du Colombier struct Group {
297dd7cddfSDavid du Colombier char *name;
307dd7cddfSDavid du Colombier int *x;
317dd7cddfSDavid du Colombier };
327dd7cddfSDavid du Colombier static Group group[] =
337dd7cddfSDavid du Colombier {
347dd7cddfSDavid du Colombier { "misc", misc, },
357dd7cddfSDavid du Colombier { "map", map, },
367dd7cddfSDavid du Colombier { "compatability", compat, },
377dd7cddfSDavid du Colombier { "clock", clock, },
387dd7cddfSDavid du Colombier { "multimedia", mm, },
397dd7cddfSDavid du Colombier { "alternate", alt, },
407dd7cddfSDavid du Colombier { "flat-panel", flat, },
417dd7cddfSDavid du Colombier { 0 },
427dd7cddfSDavid du Colombier };
437dd7cddfSDavid du Colombier
447dd7cddfSDavid du Colombier static uchar greg[256];
457dd7cddfSDavid du Colombier
467dd7cddfSDavid du Colombier static uchar
ctxi(uchar index)477dd7cddfSDavid du Colombier ctxi(uchar index)
487dd7cddfSDavid du Colombier {
497dd7cddfSDavid du Colombier outportb(X, index);
507dd7cddfSDavid du Colombier return inportb(D);
517dd7cddfSDavid du Colombier }
527dd7cddfSDavid du Colombier
537dd7cddfSDavid du Colombier static void
ctxo(uchar index,uchar data)547dd7cddfSDavid du Colombier ctxo(uchar index, uchar data)
557dd7cddfSDavid du Colombier {
567dd7cddfSDavid du Colombier outportb(X, index);
577dd7cddfSDavid du Colombier outportb(D, data);
587dd7cddfSDavid du Colombier }
597dd7cddfSDavid du Colombier
607dd7cddfSDavid du Colombier /*
617dd7cddfSDavid du Colombier * ct65540.
627dd7cddfSDavid du Colombier */
637dd7cddfSDavid du Colombier static void
snarf(Vga *,Ctlr * ctlr)647dd7cddfSDavid du Colombier snarf(Vga*, Ctlr* ctlr)
657dd7cddfSDavid du Colombier {
667dd7cddfSDavid du Colombier Group *g;
677dd7cddfSDavid du Colombier int *xp;
687dd7cddfSDavid du Colombier
697dd7cddfSDavid du Colombier ctlr->flag |= Fsnarf;
707dd7cddfSDavid du Colombier
717dd7cddfSDavid du Colombier for(g = group; g->name; g++)
727dd7cddfSDavid du Colombier for(xp = g->x; *xp >= 0; xp++)
737dd7cddfSDavid du Colombier greg[*xp] = ctxi(*xp);
747dd7cddfSDavid du Colombier }
757dd7cddfSDavid du Colombier
767dd7cddfSDavid du Colombier static void
options(Vga *,Ctlr * ctlr)777dd7cddfSDavid du Colombier options(Vga*, Ctlr* ctlr)
787dd7cddfSDavid du Colombier {
797dd7cddfSDavid du Colombier ctlr->flag |= Hlinear|Foptions;
807dd7cddfSDavid du Colombier }
817dd7cddfSDavid du Colombier
827dd7cddfSDavid du Colombier /*
837dd7cddfSDavid du Colombier * brute force and ignorance
847dd7cddfSDavid du Colombier */
857dd7cddfSDavid du Colombier static int
setclock(Vga * vga)867dd7cddfSDavid du Colombier setclock(Vga* vga)
877dd7cddfSDavid du Colombier {
887dd7cddfSDavid du Colombier ulong fvco, t;
897dd7cddfSDavid du Colombier ulong m, n;
907dd7cddfSDavid du Colombier ulong bestm, bestn, diff, bestdiff, lastdiff;
917dd7cddfSDavid du Colombier ulong p;
927dd7cddfSDavid du Colombier
937dd7cddfSDavid du Colombier if(vga->mode->frequency > 220000000)
947dd7cddfSDavid du Colombier return -1;
957dd7cddfSDavid du Colombier
967dd7cddfSDavid du Colombier vga->misc &= ~(3<<2);
977dd7cddfSDavid du Colombier vga->feature &= ~3;
987dd7cddfSDavid du Colombier greg[0x33] &= ~0x20; /* set VCLK not MCLK */
997dd7cddfSDavid du Colombier greg[0x33] &= ~0x80; /* clk0 & clk1 are 25.175 & 28.322 MHz */
1007dd7cddfSDavid du Colombier
1017dd7cddfSDavid du Colombier vga->misc |= (2<<2);
1027dd7cddfSDavid du Colombier vga->feature |= 2;
1037dd7cddfSDavid du Colombier
1047dd7cddfSDavid du Colombier fvco = vga->mode->frequency;
1057dd7cddfSDavid du Colombier if(fvco == 0)
1067dd7cddfSDavid du Colombier return -1;
1077dd7cddfSDavid du Colombier p = 0;
1087dd7cddfSDavid du Colombier while(fvco < 100000000){
1097dd7cddfSDavid du Colombier fvco *= 2;
1107dd7cddfSDavid du Colombier p++;
1117dd7cddfSDavid du Colombier }
1127dd7cddfSDavid du Colombier
1137dd7cddfSDavid du Colombier m = (1<<31)/(4*RefFreq);
1147dd7cddfSDavid du Colombier if(m > 127)
1157dd7cddfSDavid du Colombier m = 127;
1167dd7cddfSDavid du Colombier bestdiff = 1<<31;
1177dd7cddfSDavid du Colombier bestm = 3;
1187dd7cddfSDavid du Colombier bestn = 3;
1197dd7cddfSDavid du Colombier for(; m > 2; m--){
1207dd7cddfSDavid du Colombier lastdiff = 1<<31;
1217dd7cddfSDavid du Colombier for(n = 3; n < 128; n++){
1227dd7cddfSDavid du Colombier t = (RefFreq*4*m)/n;
1237dd7cddfSDavid du Colombier diff = abs(fvco-t);
1247dd7cddfSDavid du Colombier if(diff < bestdiff){
1257dd7cddfSDavid du Colombier bestdiff = diff;
1267dd7cddfSDavid du Colombier bestm = m;
1277dd7cddfSDavid du Colombier bestn = n;
1287dd7cddfSDavid du Colombier } else {
1297dd7cddfSDavid du Colombier if(diff > lastdiff)
1307dd7cddfSDavid du Colombier break;
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier lastdiff = diff;
1337dd7cddfSDavid du Colombier }
1347dd7cddfSDavid du Colombier }
1357dd7cddfSDavid du Colombier
1367dd7cddfSDavid du Colombier greg[0x31] = bestm - 2;
1377dd7cddfSDavid du Colombier greg[0x32] = bestn - 2;
1387dd7cddfSDavid du Colombier greg[0x30] = (p<<1) | 1;
1397dd7cddfSDavid du Colombier return 0;
1407dd7cddfSDavid du Colombier }
1417dd7cddfSDavid du Colombier
1427dd7cddfSDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)1437dd7cddfSDavid du Colombier init(Vga* vga, Ctlr* ctlr)
1447dd7cddfSDavid du Colombier {
1457dd7cddfSDavid du Colombier int x;
1467dd7cddfSDavid du Colombier
1477dd7cddfSDavid du Colombier greg[0x15] = 0; /* allow writes to all registers */
1487dd7cddfSDavid du Colombier
1497dd7cddfSDavid du Colombier if(vga->mode->z > 8)
1507dd7cddfSDavid du Colombier error("depth %d not supported\n", vga->mode->z);
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier if(vga->mode->z == 8){
1537dd7cddfSDavid du Colombier if(vga->linear && (ctlr->flag & Hlinear))
1547dd7cddfSDavid du Colombier ctlr->flag |= Ulinear;
1557dd7cddfSDavid du Colombier vga->vmz = 1024*1024;
1567dd7cddfSDavid du Colombier vga->vmb = 1024*1024;
1577dd7cddfSDavid du Colombier
1587dd7cddfSDavid du Colombier /* linear mapping - extension regs*/
1597dd7cddfSDavid du Colombier greg[0x04] = (1<<2); /* enable CRTC bits 16 & 17, 32 bit mode */
1607dd7cddfSDavid du Colombier greg[0x0b] = 0x15; /* linear addressing, > 256k, sequential addr */
1617dd7cddfSDavid du Colombier greg[0x28] = 0x90; /* non-interlaced, 256 colors */
1627dd7cddfSDavid du Colombier
1637dd7cddfSDavid du Colombier /* normal regs */
1647dd7cddfSDavid du Colombier vga->sequencer[0x04] = 0x0A; /* sequential memory access */
1657dd7cddfSDavid du Colombier vga->graphics[0x05] = 0x00; /* sequential access, shift out 8 bits at */
1667dd7cddfSDavid du Colombier /* a time */
1677dd7cddfSDavid du Colombier vga->attribute[0x10] &= ~(1<<6); /* 1 dot clock per pixel */
1687dd7cddfSDavid du Colombier vga->crt[0x14] = 0x00;
1697dd7cddfSDavid du Colombier vga->crt[0x17] = 0xe3; /* always byte mode */
1707dd7cddfSDavid du Colombier } else {
1717dd7cddfSDavid du Colombier /* mapped to 0xa0000 - extension regs*/
1727dd7cddfSDavid du Colombier greg[0x04] = (1<<2); /* enable CRTC bits 16 & 17, 32 bit mode */
1737dd7cddfSDavid du Colombier greg[0x0b] = 0x01; /* 0xA0000 - 0xAFFFF, planar addressing */
1747dd7cddfSDavid du Colombier greg[0x28] = 0x80; /* non-interlaced, 16 colors */
1757dd7cddfSDavid du Colombier }
1767dd7cddfSDavid du Colombier
1777dd7cddfSDavid du Colombier /* the extension registers have even more overflow bits */
1787dd7cddfSDavid du Colombier x = 0;
1797dd7cddfSDavid du Colombier if(vga->mode->vt & (1<<10))
1807dd7cddfSDavid du Colombier x |= (1<<0);
1817dd7cddfSDavid du Colombier if(vga->mode->vrs & (1<<10))
1827dd7cddfSDavid du Colombier x |= (1<<2);
1837dd7cddfSDavid du Colombier greg[0x16] = x;
1847dd7cddfSDavid du Colombier x = 0;
1857dd7cddfSDavid du Colombier if(vga->mode->ht & (1<<(8+3)))
1867dd7cddfSDavid du Colombier x |= (1<<0);
1877dd7cddfSDavid du Colombier if(vga->mode->shb & (1<<(8+3)))
1887dd7cddfSDavid du Colombier x |= (1<<4);
1897dd7cddfSDavid du Colombier if(vga->mode->ehb & (1<<(6+3)))
1907dd7cddfSDavid du Colombier x |= (1<<5);
1917dd7cddfSDavid du Colombier greg[0x17] = x;
1927dd7cddfSDavid du Colombier
1937dd7cddfSDavid du Colombier if(vga->mode->y > 480)
1947dd7cddfSDavid du Colombier vga->misc &= 0x3F;
1957dd7cddfSDavid du Colombier
1967dd7cddfSDavid du Colombier setclock(vga);
1977dd7cddfSDavid du Colombier
1987dd7cddfSDavid du Colombier ctlr->flag |= Finit;
1997dd7cddfSDavid du Colombier }
2007dd7cddfSDavid du Colombier
2017dd7cddfSDavid du Colombier static void
load(Vga * vga,Ctlr * ctlr)2027dd7cddfSDavid du Colombier load(Vga* vga, Ctlr* ctlr)
2037dd7cddfSDavid du Colombier {
2047dd7cddfSDavid du Colombier Group *g;
2057dd7cddfSDavid du Colombier int *xp;
2067dd7cddfSDavid du Colombier
2077dd7cddfSDavid du Colombier /* must be first */
2087dd7cddfSDavid du Colombier ctxo(0x15, greg[0x15]); /* write protect */
2097dd7cddfSDavid du Colombier ctxo(0x33, greg[0x33]); /* select clock */
2107dd7cddfSDavid du Colombier
2117dd7cddfSDavid du Colombier if(ctlr->flag & Ulinear){
2127dd7cddfSDavid du Colombier greg[0x8] = vga->vmb>>20;
2137dd7cddfSDavid du Colombier ctxo(0x08, greg[0x08]);
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier
2167dd7cddfSDavid du Colombier /* only write what changed */
2177dd7cddfSDavid du Colombier for(g = group; g->name; g++)
2187dd7cddfSDavid du Colombier for(xp = g->x; *xp >= 0; xp++)
2197dd7cddfSDavid du Colombier ctxo(*xp, greg[*xp]);
2207dd7cddfSDavid du Colombier
2217dd7cddfSDavid du Colombier ctlr->flag |= Fload;
2227dd7cddfSDavid du Colombier }
2237dd7cddfSDavid du Colombier
2247dd7cddfSDavid du Colombier static void
dump(Vga *,Ctlr * ctlr)2257dd7cddfSDavid du Colombier dump(Vga*, Ctlr* ctlr)
2267dd7cddfSDavid du Colombier {
2277dd7cddfSDavid du Colombier Group *g;
2287dd7cddfSDavid du Colombier int *xp;
2297dd7cddfSDavid du Colombier char *name;
2307dd7cddfSDavid du Colombier int lastx;
2317dd7cddfSDavid du Colombier char item[32];
2327dd7cddfSDavid du Colombier
2337dd7cddfSDavid du Colombier name = ctlr->name;
2347dd7cddfSDavid du Colombier
2357dd7cddfSDavid du Colombier for(g = group; g->name; g++){
2367dd7cddfSDavid du Colombier lastx = -2;
2377dd7cddfSDavid du Colombier for(xp = g->x; *xp >= 0; xp++){
2387dd7cddfSDavid du Colombier if(*xp != lastx+1){
2397dd7cddfSDavid du Colombier sprint(item, "%s %2.2ux:", g->name, *xp);
2407dd7cddfSDavid du Colombier printitem(name, item);
2417dd7cddfSDavid du Colombier }
2427dd7cddfSDavid du Colombier lastx = *xp;
2437dd7cddfSDavid du Colombier printreg(greg[*xp]);
2447dd7cddfSDavid du Colombier }
2457dd7cddfSDavid du Colombier }
2467dd7cddfSDavid du Colombier }
2477dd7cddfSDavid du Colombier
2487dd7cddfSDavid du Colombier Ctlr ct65540 = {
2497dd7cddfSDavid du Colombier "ct65540", /* name */
2507dd7cddfSDavid du Colombier snarf, /* snarf */
2517dd7cddfSDavid du Colombier options, /* options */
2527dd7cddfSDavid du Colombier init, /* init */
2537dd7cddfSDavid du Colombier load, /* load */
2547dd7cddfSDavid du Colombier dump, /* dump */
2557dd7cddfSDavid du Colombier };
2567dd7cddfSDavid du Colombier
2577dd7cddfSDavid du Colombier Ctlr ct65545 = {
2587dd7cddfSDavid du Colombier "ct65545", /* name */
2597dd7cddfSDavid du Colombier snarf, /* snarf */
2607dd7cddfSDavid du Colombier options, /* options */
2617dd7cddfSDavid du Colombier init, /* init */
2627dd7cddfSDavid du Colombier load, /* load */
2637dd7cddfSDavid du Colombier dump, /* dump */
2647dd7cddfSDavid du Colombier };
2657dd7cddfSDavid du Colombier
2667dd7cddfSDavid du Colombier Ctlr ct65545hwgc = {
2677dd7cddfSDavid du Colombier "ct65545hwgc", /* name */
2687dd7cddfSDavid du Colombier 0, /* snarf */
2697dd7cddfSDavid du Colombier 0, /* options */
2707dd7cddfSDavid du Colombier 0, /* init */
2717dd7cddfSDavid du Colombier 0, /* load */
2727dd7cddfSDavid du Colombier 0, /* dump */
2737dd7cddfSDavid du Colombier };
274