17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier
57dd7cddfSDavid du Colombier #include "pci.h"
69a747e4fSDavid du Colombier #include "vga.h"
77dd7cddfSDavid du Colombier
87dd7cddfSDavid du Colombier /*
97dd7cddfSDavid du Colombier * Matrox Millenium and Matrox Millenium II.
107dd7cddfSDavid du Colombier * Matrox MGA-2064W, MGA-2164W 3D graphics accelerators
117dd7cddfSDavid du Colombier * Texas Instruments Tvp3026 RAMDAC.
127dd7cddfSDavid du Colombier */
137dd7cddfSDavid du Colombier enum {
147dd7cddfSDavid du Colombier Meg = 1024*1024,
157dd7cddfSDavid du Colombier /* pci chip manufacturer */
167dd7cddfSDavid du Colombier MATROX = 0x102B,
177dd7cddfSDavid du Colombier
187dd7cddfSDavid du Colombier /* pci chip device ids */
197dd7cddfSDavid du Colombier MGA2064 = 0x0519,
207dd7cddfSDavid du Colombier MGA2164 = 0x051B,
217dd7cddfSDavid du Colombier MGA2164AGP = 0x051F,
227dd7cddfSDavid du Colombier
237dd7cddfSDavid du Colombier /* i/o ports */
247dd7cddfSDavid du Colombier Crtcext = 0x03DE, /* CRTC Extensions */
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier /* config space offsets */
277dd7cddfSDavid du Colombier Devctrl = 0x04, /* Device Control */
287dd7cddfSDavid du Colombier Option = 0x40, /* Option */
297dd7cddfSDavid du Colombier
307dd7cddfSDavid du Colombier /* control aperture offsets */
317dd7cddfSDavid du Colombier RAMDAC = 0x3C00, /* RAMDAC registers */
327dd7cddfSDavid du Colombier CACHEFLUSH = 0x1FFF,
337dd7cddfSDavid du Colombier };
347dd7cddfSDavid du Colombier
357dd7cddfSDavid du Colombier typedef struct {
367dd7cddfSDavid du Colombier Pcidev* pci;
377dd7cddfSDavid du Colombier int devid;
38*74f16c81SDavid du Colombier uchar* membase1;
39*74f16c81SDavid du Colombier uchar* membase2;
407dd7cddfSDavid du Colombier ulong devctrl;
417dd7cddfSDavid du Colombier ulong option;
427dd7cddfSDavid du Colombier uchar crtcext[6];
437dd7cddfSDavid du Colombier uchar tvp[64];
447dd7cddfSDavid du Colombier uchar pclk[3];
457dd7cddfSDavid du Colombier uchar mclk[3];
467dd7cddfSDavid du Colombier uchar lclk[3];
477dd7cddfSDavid du Colombier } Mga;
487dd7cddfSDavid du Colombier
497dd7cddfSDavid du Colombier static uchar
_tvp3026i(Vga * vga,Ctlr * ctlr,uchar reg)507dd7cddfSDavid du Colombier _tvp3026i(Vga* vga, Ctlr* ctlr, uchar reg)
517dd7cddfSDavid du Colombier {
527dd7cddfSDavid du Colombier Mga *mga;
537dd7cddfSDavid du Colombier
547dd7cddfSDavid du Colombier if(reg >= 0x10)
557dd7cddfSDavid du Colombier error("%s: tvp3026io: direct reg 0x%uX out of range\n", ctlr->name, reg);
567dd7cddfSDavid du Colombier
577dd7cddfSDavid du Colombier if(vga->private == nil)
587dd7cddfSDavid du Colombier error("%s: tvp3026io: no *mga\n", ctlr->name);
597dd7cddfSDavid du Colombier mga = vga->private;
607dd7cddfSDavid du Colombier
61*74f16c81SDavid du Colombier return *(mga->membase1+RAMDAC+reg);
627dd7cddfSDavid du Colombier }
637dd7cddfSDavid du Colombier
647dd7cddfSDavid du Colombier static void
_tvp3026o(Vga * vga,Ctlr * ctlr,uchar reg,uchar data)657dd7cddfSDavid du Colombier _tvp3026o(Vga* vga, Ctlr* ctlr, uchar reg, uchar data)
667dd7cddfSDavid du Colombier {
677dd7cddfSDavid du Colombier Mga *mga;
687dd7cddfSDavid du Colombier
697dd7cddfSDavid du Colombier if(reg >= 0x10)
707dd7cddfSDavid du Colombier error("%s: tvp3026io: direct reg 0x%uX out of range\n", ctlr->name, reg);
717dd7cddfSDavid du Colombier
727dd7cddfSDavid du Colombier if(vga->private == nil)
737dd7cddfSDavid du Colombier error("%s: tvp3026io: no *mga\n", ctlr->name);
747dd7cddfSDavid du Colombier mga = vga->private;
757dd7cddfSDavid du Colombier
76*74f16c81SDavid du Colombier *(mga->membase1+RAMDAC+reg) = data;
777dd7cddfSDavid du Colombier }
787dd7cddfSDavid du Colombier
797dd7cddfSDavid du Colombier static uchar
_tvp3026xi(Vga * vga,Ctlr * ctlr,uchar index)807dd7cddfSDavid du Colombier _tvp3026xi(Vga* vga, Ctlr* ctlr, uchar index)
817dd7cddfSDavid du Colombier {
827dd7cddfSDavid du Colombier if(index >= 0x40)
837dd7cddfSDavid du Colombier error("%s: tvp3026xi: reg 0x%uX out of range\n", ctlr->name, index);
847dd7cddfSDavid du Colombier
857dd7cddfSDavid du Colombier _tvp3026o(vga, ctlr, 0x00, index);
867dd7cddfSDavid du Colombier
877dd7cddfSDavid du Colombier return _tvp3026i(vga, ctlr, 0x0A);
887dd7cddfSDavid du Colombier }
897dd7cddfSDavid du Colombier
907dd7cddfSDavid du Colombier void
_tvp3026xo(Vga * vga,Ctlr * ctlr,uchar index,uchar data)917dd7cddfSDavid du Colombier _tvp3026xo(Vga* vga, Ctlr* ctlr, uchar index, uchar data)
927dd7cddfSDavid du Colombier {
937dd7cddfSDavid du Colombier if(index >= 0x40)
947dd7cddfSDavid du Colombier error("%s: tvp3026xo: reg 0x%uX out of range\n", ctlr->name, index);
957dd7cddfSDavid du Colombier
967dd7cddfSDavid du Colombier _tvp3026o(vga, ctlr, 0x00, index);
977dd7cddfSDavid du Colombier _tvp3026o(vga, ctlr, 0x0A, data);
987dd7cddfSDavid du Colombier }
997dd7cddfSDavid du Colombier
1007dd7cddfSDavid du Colombier static uchar
crtcexti(uchar index)1017dd7cddfSDavid du Colombier crtcexti(uchar index)
1027dd7cddfSDavid du Colombier {
1037dd7cddfSDavid du Colombier uchar data;
1047dd7cddfSDavid du Colombier
1057dd7cddfSDavid du Colombier outportb(Crtcext, index);
1067dd7cddfSDavid du Colombier data = inportb(Crtcext+1);
1077dd7cddfSDavid du Colombier
1087dd7cddfSDavid du Colombier return data;
1097dd7cddfSDavid du Colombier }
1107dd7cddfSDavid du Colombier
1117dd7cddfSDavid du Colombier static void
crtcexto(uchar index,uchar data)1127dd7cddfSDavid du Colombier crtcexto(uchar index, uchar data)
1137dd7cddfSDavid du Colombier {
1147dd7cddfSDavid du Colombier outportb(Crtcext, index);
1157dd7cddfSDavid du Colombier outportb(Crtcext+1, data);
1167dd7cddfSDavid du Colombier }
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier static void
mapmga(Vga * vga,Ctlr * ctlr)1197dd7cddfSDavid du Colombier mapmga(Vga* vga, Ctlr* ctlr)
1207dd7cddfSDavid du Colombier {
1217dd7cddfSDavid du Colombier int f;
122*74f16c81SDavid du Colombier uchar *m;
1237dd7cddfSDavid du Colombier Mga *mga;
1247dd7cddfSDavid du Colombier
1257dd7cddfSDavid du Colombier if(vga->private == nil)
1267dd7cddfSDavid du Colombier error("%s: tvp3026io: no *mga\n", ctlr->name);
1277dd7cddfSDavid du Colombier mga = vga->private;
1287dd7cddfSDavid du Colombier
1297dd7cddfSDavid du Colombier f = open("#v/vgactl", OWRITE);
1307dd7cddfSDavid du Colombier if(f < 0)
1317dd7cddfSDavid du Colombier error("%s: can't open vgactl\n", ctlr->name);
1327dd7cddfSDavid du Colombier if(write(f, "type mga2164w", 13) != 13)
1337dd7cddfSDavid du Colombier error("%s: can't set mga type\n", ctlr->name);
1347dd7cddfSDavid du Colombier
1357dd7cddfSDavid du Colombier m = segattach(0, "mga2164wmmio", 0, 16*1024);
136*74f16c81SDavid du Colombier if(m == (void*)-1)
1377dd7cddfSDavid du Colombier error("%s: can't attach mga2164wmmio segment\n", ctlr->name);
1387dd7cddfSDavid du Colombier mga->membase1 = m;
1397dd7cddfSDavid du Colombier
1407dd7cddfSDavid du Colombier m = segattach(0, "mga2164wscreen", 0, (mga->devid==MGA2064? 8 : 16)*Meg);
141*74f16c81SDavid du Colombier if(m ==(void*)-1)
1427dd7cddfSDavid du Colombier error("%s: can't attach mga2164wscreen segment\n", ctlr->name);
1437dd7cddfSDavid du Colombier
1447dd7cddfSDavid du Colombier mga->membase2 = m;
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier
1477dd7cddfSDavid du Colombier static void
clockcalc(Vga * vga,Ctlr * ctlr,int bpp)1487dd7cddfSDavid du Colombier clockcalc(Vga* vga, Ctlr* ctlr, int bpp)
1497dd7cddfSDavid du Colombier {
1507dd7cddfSDavid du Colombier ulong m, n, p, q;
1517dd7cddfSDavid du Colombier double z, fdiff, fmindiff, fvco, fgoal;
1527dd7cddfSDavid du Colombier Mga *mga;
1537dd7cddfSDavid du Colombier
1547dd7cddfSDavid du Colombier USED(ctlr);
1557dd7cddfSDavid du Colombier
1567dd7cddfSDavid du Colombier mga = vga->private;
1577dd7cddfSDavid du Colombier
1587dd7cddfSDavid du Colombier /*
1597dd7cddfSDavid du Colombier * Look for values of n, d and p that give
1607dd7cddfSDavid du Colombier * the least error for
1617dd7cddfSDavid du Colombier * Fvco = 8*RefFreq*(65-m)/(65-n)
1627dd7cddfSDavid du Colombier * Fpll = Fvco/2**p
1637dd7cddfSDavid du Colombier * N and m are 6 bits, p is 2 bits. Constraints:
1647dd7cddfSDavid du Colombier * 110MHz <= Fvco <= 250MHz
1657dd7cddfSDavid du Colombier * 40 <= n <= 62
1667dd7cddfSDavid du Colombier * 1 <= m <= 62
1677dd7cddfSDavid du Colombier * 0 <= p <= 3
1687dd7cddfSDavid du Colombier */
1697dd7cddfSDavid du Colombier fgoal = (double)vga->f[0];
1707dd7cddfSDavid du Colombier fmindiff = fgoal;
1717dd7cddfSDavid du Colombier vga->m[0] = 0x15;
1727dd7cddfSDavid du Colombier vga->n[0] = 0x18;
1737dd7cddfSDavid du Colombier vga->p[0] = 3;
1747dd7cddfSDavid du Colombier for(m = 62; m > 0; m--){
1757dd7cddfSDavid du Colombier for(n = 62; n >= 40; n--){
1767dd7cddfSDavid du Colombier fvco = 8.*((double)RefFreq)*(65.-m)/(65.-n);
1777dd7cddfSDavid du Colombier if(fvco < 110e6 || fvco > 250e6)
1787dd7cddfSDavid du Colombier continue;
1797dd7cddfSDavid du Colombier for(p = 0; p < 4; p++){
1807dd7cddfSDavid du Colombier fdiff = fgoal - fvco/(1<<p);
1817dd7cddfSDavid du Colombier if(fdiff < 0)
1827dd7cddfSDavid du Colombier fdiff = -fdiff;
1837dd7cddfSDavid du Colombier if(fdiff < fmindiff){
1847dd7cddfSDavid du Colombier fmindiff = fdiff;
1857dd7cddfSDavid du Colombier vga->m[0] = m;
1867dd7cddfSDavid du Colombier vga->n[0] = n;
1877dd7cddfSDavid du Colombier vga->p[0] = p;
1887dd7cddfSDavid du Colombier }
1897dd7cddfSDavid du Colombier }
1907dd7cddfSDavid du Colombier }
1917dd7cddfSDavid du Colombier }
1927dd7cddfSDavid du Colombier mga->pclk[0] = 0xC0 | (vga->n[0] & 0x3f);
1937dd7cddfSDavid du Colombier mga->pclk[1] = (vga->m[0] & 0x3f);
1947dd7cddfSDavid du Colombier mga->pclk[2] = 0xB0 | (vga->p[0] & 0x03);
1957dd7cddfSDavid du Colombier
1967dd7cddfSDavid du Colombier /*
1977dd7cddfSDavid du Colombier * Now the loop clock:
1987dd7cddfSDavid du Colombier * m is fixed;
1997dd7cddfSDavid du Colombier * calculate n;
2007dd7cddfSDavid du Colombier * set z to the lower bound (110MHz) and calculate p and q.
2017dd7cddfSDavid du Colombier */
2027dd7cddfSDavid du Colombier vga->m[1] = 61;
2037dd7cddfSDavid du Colombier n = 65 - 4*(64/(vga->vmz==2*Meg? bpp*2 : bpp));
2047dd7cddfSDavid du Colombier fvco = (8*RefFreq*(65-vga->m[0]))/(65-vga->n[0]);
2057dd7cddfSDavid du Colombier vga->f[1] = fvco/(1<<vga->p[0]);
2067dd7cddfSDavid du Colombier z = 110e6*(65.-n)/(4.*vga->f[1]);
2077dd7cddfSDavid du Colombier if(z <= 16){
2087dd7cddfSDavid du Colombier for(p = 0; p < 4; p++){
2097dd7cddfSDavid du Colombier if(1<<(p+1) > z)
2107dd7cddfSDavid du Colombier break;
2117dd7cddfSDavid du Colombier }
2127dd7cddfSDavid du Colombier q = 0;
2137dd7cddfSDavid du Colombier }
2147dd7cddfSDavid du Colombier else{
2157dd7cddfSDavid du Colombier p = 3;
2167dd7cddfSDavid du Colombier q = (z - 16)/16 + 1;
2177dd7cddfSDavid du Colombier }
2187dd7cddfSDavid du Colombier vga->n[1] = n;
2197dd7cddfSDavid du Colombier vga->p[1] = p;
2207dd7cddfSDavid du Colombier vga->q[1] = q;
2217dd7cddfSDavid du Colombier mga->lclk[0] = 0xC0 | (vga->n[1] & 0x3f);
2227dd7cddfSDavid du Colombier mga->lclk[1] = (vga->m[1] & 0x3f);
2237dd7cddfSDavid du Colombier mga->lclk[2] = 0xF0 | (vga->p[1] & 0x03);
2247dd7cddfSDavid du Colombier mga->tvp[0x39] = 0x38 | q;
2257dd7cddfSDavid du Colombier }
2267dd7cddfSDavid du Colombier
2277dd7cddfSDavid du Colombier static void
snarf(Vga * vga,Ctlr * ctlr)2287dd7cddfSDavid du Colombier snarf(Vga* vga, Ctlr* ctlr)
2297dd7cddfSDavid du Colombier {
2307dd7cddfSDavid du Colombier int i, k, n;
2317dd7cddfSDavid du Colombier uchar *p, x[8];
2327dd7cddfSDavid du Colombier Pcidev *pci;
2337dd7cddfSDavid du Colombier Mga *mga;
2347dd7cddfSDavid du Colombier
2357dd7cddfSDavid du Colombier if(vga->private == nil) {
2367dd7cddfSDavid du Colombier pci = pcimatch(nil, MATROX, MGA2164AGP);
2377dd7cddfSDavid du Colombier if(pci == nil)
2387dd7cddfSDavid du Colombier pci = pcimatch(nil, MATROX, MGA2164);
2397dd7cddfSDavid du Colombier if(pci == nil)
2407dd7cddfSDavid du Colombier pci = pcimatch(nil, MATROX, MGA2064);
2417dd7cddfSDavid du Colombier if(pci == nil)
2427dd7cddfSDavid du Colombier error("%s: no Pcidev with Vid=0x102B, Did=0x051[9BF] or 0x521\n", ctlr->name);
2437dd7cddfSDavid du Colombier
2447dd7cddfSDavid du Colombier vga->private = alloc(sizeof(Mga));
2457dd7cddfSDavid du Colombier mga = (Mga*)vga->private;
2467dd7cddfSDavid du Colombier mga->devid = pci->did;
2477dd7cddfSDavid du Colombier mga->pci = pci;
2487dd7cddfSDavid du Colombier mapmga(vga, ctlr);
2497dd7cddfSDavid du Colombier }
2507dd7cddfSDavid du Colombier else {
2517dd7cddfSDavid du Colombier mga = (Mga*)vga->private;
2527dd7cddfSDavid du Colombier pci = mga->pci;
2537dd7cddfSDavid du Colombier }
2547dd7cddfSDavid du Colombier
2557dd7cddfSDavid du Colombier for(i = 0; i < 0x06; i++)
2567dd7cddfSDavid du Colombier mga->crtcext[i] = crtcexti(i);
2577dd7cddfSDavid du Colombier
2587dd7cddfSDavid du Colombier mga->devctrl = pcicfgr32(pci, Devctrl);
2597dd7cddfSDavid du Colombier mga->option = pcicfgr32(pci, Option);
2607dd7cddfSDavid du Colombier
2617dd7cddfSDavid du Colombier for(i = 0; i < 64; i++)
2627dd7cddfSDavid du Colombier mga->tvp[i] = _tvp3026xi(vga, ctlr, i);
2637dd7cddfSDavid du Colombier
2647dd7cddfSDavid du Colombier for(i = 0; i < 3; i++){
2657dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2C, (i<<4)|(i<<2)|i);
2667dd7cddfSDavid du Colombier mga->pclk[i] = _tvp3026xi(vga, ctlr, 0x2D);
2677dd7cddfSDavid du Colombier }
2687dd7cddfSDavid du Colombier
2697dd7cddfSDavid du Colombier for(i = 0; i < 3; i++){
2707dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2C, (i<<4)|(i<<2)|i);
2717dd7cddfSDavid du Colombier mga->mclk[i] = _tvp3026xi(vga, ctlr, 0x2E);
2727dd7cddfSDavid du Colombier }
2737dd7cddfSDavid du Colombier
2747dd7cddfSDavid du Colombier for(i = 0; i < 3; i++){
2757dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2C, (i<<4)|(i<<2)|i);
2767dd7cddfSDavid du Colombier mga->lclk[i] = _tvp3026xi(vga, ctlr, 0x2F);
2777dd7cddfSDavid du Colombier }
2787dd7cddfSDavid du Colombier
2797dd7cddfSDavid du Colombier /* find out how much memory is here, some multiple of 2Meg */
2807dd7cddfSDavid du Colombier crtcexto(3, mga->crtcext[3] | 0x80); /* mga mode */
281*74f16c81SDavid du Colombier p = mga->membase2;
2827dd7cddfSDavid du Colombier n = (mga->devid==MGA2064? 4 : 8);
2837dd7cddfSDavid du Colombier for(i = 0; i < n; i++) {
2847dd7cddfSDavid du Colombier k = (2*i+1)*Meg;
2857dd7cddfSDavid du Colombier p[k] = 0;
2867dd7cddfSDavid du Colombier p[k] = i+1;
287*74f16c81SDavid du Colombier *(mga->membase1+CACHEFLUSH) = 0;
2887dd7cddfSDavid du Colombier x[i] = p[k];
2897dd7cddfSDavid du Colombier trace("x[%d]=%d\n", i, x[i]);
2907dd7cddfSDavid du Colombier }
2917dd7cddfSDavid du Colombier for(i = 1; i < n; i++)
2927dd7cddfSDavid du Colombier if(x[i] != i+1)
2937dd7cddfSDavid du Colombier break;
2947dd7cddfSDavid du Colombier vga->vmz = 2*i*Meg;
2957dd7cddfSDavid du Colombier trace("probe found %d megabytes\n", 2*i);
2967dd7cddfSDavid du Colombier crtcexto(3, mga->crtcext[3]); /* restore mga mode */
2977dd7cddfSDavid du Colombier
2987dd7cddfSDavid du Colombier
2997dd7cddfSDavid du Colombier ctlr->flag |= Fsnarf;
3007dd7cddfSDavid du Colombier }
3017dd7cddfSDavid du Colombier
3027dd7cddfSDavid du Colombier static void
options(Vga * vga,Ctlr * ctlr)3037dd7cddfSDavid du Colombier options(Vga* vga, Ctlr* ctlr)
3047dd7cddfSDavid du Colombier {
3059a747e4fSDavid du Colombier if(vga->virtx & 127)
3069a747e4fSDavid du Colombier vga->virtx = (vga->virtx+127)&~127;
3077dd7cddfSDavid du Colombier ctlr->flag |= Foptions;
3087dd7cddfSDavid du Colombier }
3097dd7cddfSDavid du Colombier
3107dd7cddfSDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)3117dd7cddfSDavid du Colombier init(Vga* vga, Ctlr* ctlr)
3127dd7cddfSDavid du Colombier {
3137dd7cddfSDavid du Colombier Mode *mode;
3147dd7cddfSDavid du Colombier Ctlr *c;
3157dd7cddfSDavid du Colombier Mga *mga;
3167dd7cddfSDavid du Colombier int scale, offset, pixbuswidth;
3177dd7cddfSDavid du Colombier
3187dd7cddfSDavid du Colombier mga = vga->private;
3197dd7cddfSDavid du Colombier mode = vga->mode;
3207dd7cddfSDavid du Colombier
3217dd7cddfSDavid du Colombier ctlr->flag |= Ulinear;
3227dd7cddfSDavid du Colombier
3237dd7cddfSDavid du Colombier pixbuswidth = (vga->vmz == 2*Meg) ? 32 : 64;
3247dd7cddfSDavid du Colombier trace("pixbuswidth=%d\n", pixbuswidth);
3257dd7cddfSDavid du Colombier
3267dd7cddfSDavid du Colombier if(vga->mode->z > 8)
3277dd7cddfSDavid du Colombier error("depth %d not supported\n", vga->mode->z);
3287dd7cddfSDavid du Colombier
3297dd7cddfSDavid du Colombier if(vga->f[0] == 0)
3307dd7cddfSDavid du Colombier vga->f[0] = vga->mode->frequency;
3317dd7cddfSDavid du Colombier
3327dd7cddfSDavid du Colombier /* supposed to let tvp reg 1D control sync polarity */
3337dd7cddfSDavid du Colombier vga->misc |= 0xC8;
3347dd7cddfSDavid du Colombier
3357dd7cddfSDavid du Colombier /*
3367dd7cddfSDavid du Colombier * In power graphics mode, supposed to use
3377dd7cddfSDavid du Colombier * hblkend = htotal+4
3387dd7cddfSDavid du Colombier * hblkstr = hdispend
3397dd7cddfSDavid du Colombier */
3407dd7cddfSDavid du Colombier if((vga->crt[0x00] & 0x0F) == 0x0F) {
3417dd7cddfSDavid du Colombier vga->crt[0x00]++;
3427dd7cddfSDavid du Colombier mode->ht += 8;
3437dd7cddfSDavid du Colombier }
3447dd7cddfSDavid du Colombier vga->crt[0x02] = vga->crt[0x01];
3457dd7cddfSDavid du Colombier vga->crt[0x03] = (((mode->ht>>3)-1) & 0x1F) | 0x80;
3467dd7cddfSDavid du Colombier vga->crt[0x05] = ((((mode->ht>>3)-1) & 0x20) << 2)
3477dd7cddfSDavid du Colombier | ((mode->ehs>>3) & 0x1F);
3487dd7cddfSDavid du Colombier
3499a747e4fSDavid du Colombier offset = (vga->virtx*mode->z) >> ((pixbuswidth==32)? 6 : 7);
3507dd7cddfSDavid du Colombier vga->crt[0x13] = offset;
3517dd7cddfSDavid du Colombier vga->crt[0x14] = 0;
3527dd7cddfSDavid du Colombier vga->crt[0x17] = 0xE3;
3537dd7cddfSDavid du Colombier
3547dd7cddfSDavid du Colombier mga->crtcext[0] = (offset & 0x300) >> 4;
3557dd7cddfSDavid du Colombier mga->crtcext[1] = ((((mode->ht>>3)-5) & 0x100) >> 8)
3567dd7cddfSDavid du Colombier | ((((mode->x>>3)-1) & 0x100) >> 7)
3577dd7cddfSDavid du Colombier | (((mode->shs>>3) & 0x100) >> 6) /* why not (shs>>3)-1 ? */
3587dd7cddfSDavid du Colombier | (((mode->ht>>3)-1) & 0x40);
3597dd7cddfSDavid du Colombier mga->crtcext[2] = (((mode->vt-2) & 0xC00) >> 10)
3607dd7cddfSDavid du Colombier | (((mode->y-1) & 0x400) >> 8)
3617dd7cddfSDavid du Colombier | ((mode->vrs & 0xC00) >> 7)
3627dd7cddfSDavid du Colombier | ((mode->vrs & 0xC00) >> 5);
3637dd7cddfSDavid du Colombier scale = mode->z == 8 ? 1 : (mode->z == 16? 2 : 4);
3647dd7cddfSDavid du Colombier if(pixbuswidth == 32)
3657dd7cddfSDavid du Colombier scale *= 2;
3667dd7cddfSDavid du Colombier scale--;
3677dd7cddfSDavid du Colombier mga->crtcext[3] = scale | 0x80;
3687dd7cddfSDavid du Colombier if(vga->vmz >= 8*Meg)
3697dd7cddfSDavid du Colombier mga->crtcext[3] |= 0x10;
3707dd7cddfSDavid du Colombier else if(vga->vmz == 2*Meg)
3717dd7cddfSDavid du Colombier mga->crtcext[3] |= 0x08;
3727dd7cddfSDavid du Colombier mga->crtcext[4] = 0;
3737dd7cddfSDavid du Colombier mga->crtcext[5] = 0;
3747dd7cddfSDavid du Colombier
3757dd7cddfSDavid du Colombier mga->tvp[0x0F] = (mode->z == 8) ? 0x06 : 0x07;
3767dd7cddfSDavid du Colombier mga->tvp[0x18] = (mode->z == 8) ? 0x80 :
3777dd7cddfSDavid du Colombier (mode->z == 16) ? 0x05 : 0x06;
3787dd7cddfSDavid du Colombier mga->tvp[0x19] = (mode->z == 8) ? 0x4C :
3797dd7cddfSDavid du Colombier (mode->z == 16) ? 0x54 : 0x5C;
3807dd7cddfSDavid du Colombier if(pixbuswidth == 32)
3817dd7cddfSDavid du Colombier mga->tvp[0x19]--;
3827dd7cddfSDavid du Colombier mga->tvp[0x1A] = (mode->z == 8) ? 0x25 :
3837dd7cddfSDavid du Colombier (mode->z == 16) ? 0x15 : 0x05;
3847dd7cddfSDavid du Colombier mga->tvp[0x1C] = 0;
3857dd7cddfSDavid du Colombier mga->tvp[0x1D] = (mode->y < 768) ? 0x00 : 0x03;
3867dd7cddfSDavid du Colombier mga->tvp[0x1E] = (mode->z == 8) ? 0x04 : 0x24; /* six bit mode */
3877dd7cddfSDavid du Colombier mga->tvp[0x2A] = 0;
3887dd7cddfSDavid du Colombier mga->tvp[0x2B] = 0x1E;
3897dd7cddfSDavid du Colombier mga->tvp[0x30] = 0xFF;
3907dd7cddfSDavid du Colombier mga->tvp[0x31] = 0xFF;
3917dd7cddfSDavid du Colombier mga->tvp[0x32] = 0xFF;
3927dd7cddfSDavid du Colombier mga->tvp[0x33] = 0xFF;
3937dd7cddfSDavid du Colombier mga->tvp[0x34] = 0xFF;
3947dd7cddfSDavid du Colombier mga->tvp[0x35] = 0xFF;
3957dd7cddfSDavid du Colombier mga->tvp[0x36] = 0xFF;
3967dd7cddfSDavid du Colombier mga->tvp[0x37] = 0xFF;
3977dd7cddfSDavid du Colombier mga->tvp[0x38] = 0;
3987dd7cddfSDavid du Colombier mga->tvp[0x39] = 0;
3997dd7cddfSDavid du Colombier mga->tvp[0x3A] = 0;
4007dd7cddfSDavid du Colombier mga->tvp[0x06] = 0;
4017dd7cddfSDavid du Colombier
40259cc4ca5SDavid du Colombier // From: "Bruce G. Stewart" <bruce.g.stewart@worldnet.att.net>
40359cc4ca5SDavid du Colombier // 05-Jul-00 - Fix vertical blanking setup
40459cc4ca5SDavid du Colombier // This should probably be corrected in vga.c too.
40559cc4ca5SDavid du Colombier {
40659cc4ca5SDavid du Colombier // Start vertical blanking after the last displayed line
40759cc4ca5SDavid du Colombier // End vertical blanking after the total line count
40859cc4ca5SDavid du Colombier int svb = mode->y;
40959cc4ca5SDavid du Colombier int evb = mode->vt;
41059cc4ca5SDavid du Colombier
41159cc4ca5SDavid du Colombier // A field is 1/2 of the lines in interlaced mode
41259cc4ca5SDavid du Colombier if(mode->interlace == 'v'){
41359cc4ca5SDavid du Colombier svb /= 2;
41459cc4ca5SDavid du Colombier evb /= 2;
41559cc4ca5SDavid du Colombier }
41659cc4ca5SDavid du Colombier --svb;
41759cc4ca5SDavid du Colombier --evb; // line counter counts from 0
41859cc4ca5SDavid du Colombier
41959cc4ca5SDavid du Colombier vga->crt[0x15] = svb;
42059cc4ca5SDavid du Colombier vga->crt[0x07] = (vga->crt[0x07] & ~0x08) | ((svb & 0x100)>>5);
42159cc4ca5SDavid du Colombier vga->crt[0x09] = (vga->crt[0x09] & ~0x20) | ((svb & 0x200)>>4);
42259cc4ca5SDavid du Colombier // MGA specific: bits 10 and 11
42359cc4ca5SDavid du Colombier mga->crtcext[0x02] &= ~0x18;
42459cc4ca5SDavid du Colombier mga->crtcext[0x02] |= ((svb & 0xC00)>>7);
42559cc4ca5SDavid du Colombier
42659cc4ca5SDavid du Colombier vga->crt[0x16] = evb;
42759cc4ca5SDavid du Colombier }
42859cc4ca5SDavid du Colombier
4297dd7cddfSDavid du Colombier clockcalc(vga, ctlr, mode->z);
4307dd7cddfSDavid du Colombier
4317dd7cddfSDavid du Colombier
4327dd7cddfSDavid du Colombier mga->option = mga->option & ~0x3000;
4337dd7cddfSDavid du Colombier if(vga->vmz > 2*Meg)
4347dd7cddfSDavid du Colombier mga->option |= 0x1000;
4357dd7cddfSDavid du Colombier
4367dd7cddfSDavid du Colombier /* disable vga load (want to do fields in different order) */
4377dd7cddfSDavid du Colombier for(c = vga->link; c; c = c->link)
4387dd7cddfSDavid du Colombier if(c->name == "vga")
4397dd7cddfSDavid du Colombier c->load = nil;
4407dd7cddfSDavid du Colombier
4417dd7cddfSDavid du Colombier ctlr->flag |= Finit;
4427dd7cddfSDavid du Colombier }
4437dd7cddfSDavid du Colombier
4447dd7cddfSDavid du Colombier static void
load(Vga * vga,Ctlr * ctlr)4457dd7cddfSDavid du Colombier load(Vga* vga, Ctlr* ctlr)
4467dd7cddfSDavid du Colombier {
4477dd7cddfSDavid du Colombier int i;
4487dd7cddfSDavid du Colombier Mga *mga;
4497dd7cddfSDavid du Colombier Pcidev* pci;
4507dd7cddfSDavid du Colombier
4517dd7cddfSDavid du Colombier mga = vga->private;
4527dd7cddfSDavid du Colombier pci = mga->pci;
4537dd7cddfSDavid du Colombier
4547dd7cddfSDavid du Colombier trace("loading crtcext0-5\n");
4557dd7cddfSDavid du Colombier /* turn on mga mode, set other crt high bits */
4567dd7cddfSDavid du Colombier for(i = 0; i < 6; i++)
4577dd7cddfSDavid du Colombier crtcexto(i, mga->crtcext[i]);
4587dd7cddfSDavid du Colombier
4597dd7cddfSDavid du Colombier trace("setting memory mode\n");
4607dd7cddfSDavid du Colombier /* set memory mode */
4617dd7cddfSDavid du Colombier pcicfgw32(pci, Option, mga->option);
4627dd7cddfSDavid du Colombier
4637dd7cddfSDavid du Colombier /* clocksource: pixel clock PLL */
4647dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x1A, mga->tvp[0x1A]);
4657dd7cddfSDavid du Colombier
4667dd7cddfSDavid du Colombier /* disable pclk and lclk */
4677dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2C, 0x2A);
4687dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2F, 0);
4697dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2D, 0);
4707dd7cddfSDavid du Colombier
4717dd7cddfSDavid du Colombier trace("loading vga registers\n");
4727dd7cddfSDavid du Colombier /* vga misc, seq, and registers */
4737dd7cddfSDavid du Colombier vgao(MiscW, vga->misc);
4747dd7cddfSDavid du Colombier
4757dd7cddfSDavid du Colombier for(i = 2; i < 0x05; i++)
4767dd7cddfSDavid du Colombier vgaxo(Seqx, i, vga->sequencer[i]);
4777dd7cddfSDavid du Colombier
4787dd7cddfSDavid du Colombier vgaxo(Crtx, 0x11, vga->crt[0x11] & ~0x80);
4797dd7cddfSDavid du Colombier for(i = 0; i < 0x19; i++)
4807dd7cddfSDavid du Colombier vgaxo(Crtx, i, vga->crt[i]);
4817dd7cddfSDavid du Colombier
4827dd7cddfSDavid du Colombier /* apparently AGP needs this to restore start address */
4837dd7cddfSDavid du Colombier crtcexto(0, mga->crtcext[0]);
4847dd7cddfSDavid du Colombier
4857dd7cddfSDavid du Colombier trace("programming pclk\n");
4867dd7cddfSDavid du Colombier /* set up pclk */
4877dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2C, 0);
4887dd7cddfSDavid du Colombier for(i = 0; i < 3; i++)
4897dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2D, mga->pclk[i]);
4907dd7cddfSDavid du Colombier while(!(_tvp3026xi(vga, ctlr, 0x2D) & 0x40))
4917dd7cddfSDavid du Colombier ;
4927dd7cddfSDavid du Colombier
4937dd7cddfSDavid du Colombier trace("programming lclk\n");
4947dd7cddfSDavid du Colombier /* set up lclk */
4957dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x39, mga->tvp[0x39]);
4967dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2C, 0);
4977dd7cddfSDavid du Colombier for(i = 0; i < 3; i++)
4987dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2F, mga->lclk[i]);
4997dd7cddfSDavid du Colombier while(!(_tvp3026xi(vga, ctlr, 0x2F) & 0x40))
5007dd7cddfSDavid du Colombier ;
5017dd7cddfSDavid du Colombier
5027dd7cddfSDavid du Colombier trace("loading tvp registers\n");
5037dd7cddfSDavid du Colombier /* tvp registers, order matters */
5047dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x0F, mga->tvp[0x0F]);
5057dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x18, mga->tvp[0x18]);
5067dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x19, mga->tvp[0x19]);
5077dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x1A, mga->tvp[0x1A]);
5087dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x1C, mga->tvp[0x1C]);
5097dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x1D, mga->tvp[0x1D]);
5107dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x1E, mga->tvp[0x1E]);
5117dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2A, mga->tvp[0x2A]);
5127dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x2B, mga->tvp[0x2B]);
5137dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x30, mga->tvp[0x30]);
5147dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x31, mga->tvp[0x31]);
5157dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x32, mga->tvp[0x32]);
5167dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x33, mga->tvp[0x33]);
5177dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x34, mga->tvp[0x34]);
5187dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x35, mga->tvp[0x35]);
5197dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x36, mga->tvp[0x36]);
5207dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x37, mga->tvp[0x37]);
5217dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x38, mga->tvp[0x38]);
5227dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x39, mga->tvp[0x39]);
5237dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x3A, mga->tvp[0x3A]);
5247dd7cddfSDavid du Colombier _tvp3026xo(vga, ctlr, 0x06, mga->tvp[0x06]);
5257dd7cddfSDavid du Colombier
5267dd7cddfSDavid du Colombier trace("done mga load\n");
5277dd7cddfSDavid du Colombier ctlr->flag |= Fload;
5287dd7cddfSDavid du Colombier }
5297dd7cddfSDavid du Colombier
5307dd7cddfSDavid du Colombier static void
dump(Vga * vga,Ctlr * ctlr)5317dd7cddfSDavid du Colombier dump(Vga* vga, Ctlr* ctlr)
5327dd7cddfSDavid du Colombier {
5337dd7cddfSDavid du Colombier int i;
5347dd7cddfSDavid du Colombier char *name;
5357dd7cddfSDavid du Colombier Mga *mga;
5367dd7cddfSDavid du Colombier
5377dd7cddfSDavid du Colombier name = ctlr->name;
5387dd7cddfSDavid du Colombier mga = vga->private;
5397dd7cddfSDavid du Colombier
5407dd7cddfSDavid du Colombier printitem(name, "Devctrl");
5417dd7cddfSDavid du Colombier printreg(mga->devctrl);
5427dd7cddfSDavid du Colombier
5437dd7cddfSDavid du Colombier printitem(name, "Option");
5447dd7cddfSDavid du Colombier printreg(mga->option);
5457dd7cddfSDavid du Colombier
5467dd7cddfSDavid du Colombier printitem(name, "Crtcext");
5477dd7cddfSDavid du Colombier for(i = 0; i < 0x06; i++)
5487dd7cddfSDavid du Colombier printreg(mga->crtcext[i]);
5497dd7cddfSDavid du Colombier
5507dd7cddfSDavid du Colombier printitem(name, "TVP");
5517dd7cddfSDavid du Colombier for(i = 0; i < 64; i++)
5527dd7cddfSDavid du Colombier printreg(mga->tvp[i]);
5537dd7cddfSDavid du Colombier
5547dd7cddfSDavid du Colombier printitem(name, "PCLK");
5557dd7cddfSDavid du Colombier for(i = 0; i < 3; i++)
5567dd7cddfSDavid du Colombier printreg(mga->pclk[i]);
5577dd7cddfSDavid du Colombier
5587dd7cddfSDavid du Colombier printitem(name, "MCLK");
5597dd7cddfSDavid du Colombier for(i = 0; i < 3; i++)
5607dd7cddfSDavid du Colombier printreg(mga->mclk[i]);
5617dd7cddfSDavid du Colombier
5627dd7cddfSDavid du Colombier printitem(name, "LCLK");
5637dd7cddfSDavid du Colombier for(i = 0; i < 3; i++)
5647dd7cddfSDavid du Colombier printreg(mga->lclk[i]);
5657dd7cddfSDavid du Colombier }
5667dd7cddfSDavid du Colombier
5677dd7cddfSDavid du Colombier Ctlr mga2164w = {
5687dd7cddfSDavid du Colombier "mga2164w", /* name */
5697dd7cddfSDavid du Colombier snarf, /* snarf */
5707dd7cddfSDavid du Colombier options, /* options */
5717dd7cddfSDavid du Colombier init, /* init */
5727dd7cddfSDavid du Colombier load, /* load */
5737dd7cddfSDavid du Colombier dump, /* dump */
5747dd7cddfSDavid du Colombier };
5757dd7cddfSDavid du Colombier
5767dd7cddfSDavid du Colombier Ctlr mga2164whwgc = {
5777dd7cddfSDavid du Colombier "mga2164whwgc", /* name */
5787dd7cddfSDavid du Colombier 0, /* snarf */
5797dd7cddfSDavid du Colombier 0, /* options */
5807dd7cddfSDavid du Colombier 0, /* init */
5817dd7cddfSDavid du Colombier 0, /* load */
5827dd7cddfSDavid du Colombier dump, /* dump */
5837dd7cddfSDavid du Colombier };
584