#include #include #include #include "vga.h" #include "pci.h" typedef struct Nvidia Nvidia; struct Nvidia { ulong mmio; Pcidev* pci; int arch; int crystalfreq; ulong* pfb; ulong* pramdac; ulong* pextdev; ulong cursor2; ulong vpll; ulong pllsel; ulong general; ulong config; }; static int extcrts[] = { 0x19, 0x1A, 0x25, 0x28, 0x2D, 0x30, 0x31, -1 }; static void snarf(Vga* vga, Ctlr* ctlr) { Nvidia *nv; Pcidev *p; ulong m, tmp; int i; if(vga->private == nil){ vga->private = alloc(sizeof(Nvidia)); nv = vga->private; if((p = pcimatch(0, 0x10DE, 0)) == nil) error("%s: not found\n", ctlr->name); switch(p->did){ case 0x0020: /* Riva TNT */ case 0x0028: /* Riva TNT2 */ case 0x0029: /* Riva TNT2 (Ultra)*/ case 0x002C: /* Riva TNT2 (Vanta) */ case 0x002D: /* Riva TNT2 M64 */ case 0x00A0: /* Riva TNT2 (Integrated) */ nv->arch = 4; break; case 0x0100: /* GeForce 256 */ case 0x0101: /* GeForce DDR */ case 0x0103: /* Quadro */ case 0x0110: /* GeForce2 MX */ case 0x0111: /* GeForce2 MX DDR */ case 0x0112: /* GeForce 2 Go */ case 0x0113: /* Quadro 2 MXR */ case 0x0150: /* GeForce2 GTS */ case 0x0151: /* GeForce2 GTS (rev 1) */ case 0x0152: /* GeForce2 Ultra */ case 0x0153: /* Quadro 2 Pro */ nv->arch = 10; break; default: error("%s: DID %4.4uX unsupported\n", ctlr->name, p->did); } vgactlw("type", ctlr->name); if((m = segattach(0, "nvidiammio", 0, p->mem[0].size)) == -1) error("%s: can't attach mmio segment\n", ctlr->name); nv->pci = p; nv->mmio = m; nv->pfb = (ulong*) (nv->mmio + 0x00100000); nv->pramdac = (ulong*) (nv->mmio + 0x00680000); nv->pextdev = (ulong*) (nv->mmio + 0x00101000); } nv = vga->private; vga->p[1] = 4; vga->n[1] = 255; vga->f[1] = 350000000; /* * Unlock */ vgaxo(Crtx, 0x1F, 0x57); if (nv->pextdev[0x00000000] & 0x00000040){ nv->crystalfreq = RefFreq; vga->m[1] = 14; } else { nv->crystalfreq = 13500000; vga->m[1] = 13; } if (nv->arch == 4) { tmp = nv->pfb[0x00000000]; if (tmp & 0x0100) { vga->vmz = ((tmp >> 12) & 0x0F) * 1024 + 1024 * 2; } else { tmp &= 0x03; if (tmp) vga->vmz = (1024*1024*2) << tmp; else vga->vmz = 1024*1024*32; } } if (nv->arch == 10) { tmp = (nv->pfb[0x0000020C/4] >> 20) & 0xFF; if (tmp == 0) tmp = 16; vga->vmz = 1024*1024*tmp; } for(i = 0; extcrts[i] >= 0; i++) vga->crt[extcrts[i]] = vgaxi(Crtx, extcrts[i]); nv->cursor2 = nv->pramdac[0x00000300/4]; nv->vpll = nv->pramdac[0x00000508/4]; nv->pllsel = nv->pramdac[0x0000050C/4]; nv->general = nv->pramdac[0x00000600/4]; nv->config = nv->pfb[0x00000200/4]; ctlr->flag |= Fsnarf; } static void options(Vga*, Ctlr* ctlr) { ctlr->flag |= Hlinear|Foptions; } static void clock(Vga* vga, Ctlr* ctlr) { int m, n, p, f, d; Nvidia *nv; double trouble; nv = vga->private; if(vga->f[0] == 0) vga->f[0] = vga->mode->frequency; vga->d[0] = vga->f[0]+1; for (p=0; p <= vga->p[1]; p++){ f = vga->f[0] << p; if ((f >= 128000000) && (f <= vga->f[1])) { for (m=7; m <= vga->m[1]; m++){ trouble = (double) nv->crystalfreq / (double) (m << p); n = (vga->f[0] / trouble)+0.5; f = n*trouble + 0.5; d = vga->f[0] - f; if (d < 0) d = -d; if (n & ~0xFF) d = vga->d[0] + 1; if (d <= vga->d[0]){ vga->n[0] = n; vga->m[0] = m; vga->p[0] = p; vga->d[0] = d; } } } } if (vga->d[0] > vga->f[0]) error("%s: vclk %lud out of range\n", ctlr->name, vga->f[0]); } static void init(Vga* vga, Ctlr* ctlr) { Mode *mode; Nvidia *nv; int tmp; mode = vga->mode; /* seems to work at higher depth if(mode->z != 8) error("%s: only supports 8-bit colour\n", ctlr->name); */ nv = vga->private; if(vga->linear && (ctlr->flag & Hlinear)) ctlr->flag |= Ulinear; clock(vga, ctlr); vga->crt[0x30] = 0x00; vga->crt[0x31] = 0xFC; nv->cursor2 = 0; nv->vpll = (vga->p[0] << 16) | (vga->n[0] << 8) | vga->m[0]; nv->pllsel = 0x10000700; if (mode->z == 16) nv->general = 0x00001100; else nv->general = 0x00000100; nv->config = 0x00001114; vga->attribute[0x11] = Pblack; vga->crt[0x14] = 0x00; tmp = vga->crt[0x12]; vga->crt[0x15] = tmp; if(tmp & 0x100) vga->crt[0x07] |= 0x08; else vga->crt[0x07] &= ~0x08; if(tmp & 0x200) vga->crt[0x09] |= 0x20; else vga->crt[0x09] &= ~0x20; vga->crt[0x16] = vga->crt[0x06] + 1; vga->crt[0x02] = vga->crt[0x01]; tmp = vga->crt[0x00] + 4; vga->crt[0x03] = 0x80 | (tmp & 0x1F); if (tmp & 0x20) vga->crt[0x05] |= 0x80; else vga->crt[0x05] &= ~0x80; /* overflow bits */ vga->crt[0x1A] = 0x02; if (mode->x < 1280) vga->crt[0x1A] |= 0x04; tmp = (mode->z / 8); if (tmp > 3) tmp=3; vga->crt[0x28] = tmp; vga->crt[0x19] = (vga->crt[0x13] & 0x0700) >> 3; vga->crt[0x25] = 0x00; if (vga->crt[0x06] & 0x400) vga->crt[0x25] |= 0x01; if (vga->crt[0x12] & 0x400) vga->crt[0x25] |= 0x02; if (vga->crt[0x10] & 0x400) vga->crt[0x25] |= 0x04; if (vga->crt[0x15] & 0x400) vga->crt[0x25] |= 0x08; if ((mode->ehb >> 3) & 0x40) vga->crt[0x25] |= 0x10; vga->crt[0x2D] = 0x00; if (vga->crt[0x00] & 0x100) vga->crt[0x2D] |= 0x01; if(vga->crt[0x01] & 0x100) vga->crt[0x2D] |= 0x02; if(vga->crt[0x02] & 0x100) vga->crt[0x2D] |= 0x04; if(vga->crt[0x04] & 0x100) vga->crt[0x2D] |= 0x08; ctlr->flag |= Finit; } static void load(Vga* vga, Ctlr* ctlr) { Nvidia *nv; int i; nv = vga->private; /* * Unlock */ vgaxo(Crtx, 0x1F, 0x57); if (nv->arch == 4) nv->pfb[0x00000200/4] = nv->config; for(i = 0; extcrts[i] >= 0; i++) vgaxo(Crtx, extcrts[i], vga->crt[extcrts[i]]); nv->pramdac[0x00000300/4] = nv->cursor2; nv->pramdac[0x00000508/4] = nv->vpll; nv->pramdac[0x0000050C/4] = nv->pllsel; nv->pramdac[0x00000600/4] = nv->general; ctlr->flag |= Fload; } static void dump(Vga* vga, Ctlr* ctlr) { Nvidia *nv; int i, m, n, p, f; char buf[100]; double trouble; if((nv = vga->private) == 0) return; for(i = 0; extcrts[i] >= 0; i++){ sprint(buf, "Crt%2.2uX", extcrts[i]); printitem(ctlr->name, buf); printreg(vga->crt[extcrts[i]]); } p = (nv->vpll >> 16); n = (nv->vpll >> 8) & 0xFF; m = nv->vpll & 0xFF; trouble = nv->crystalfreq; trouble = trouble * n / (m<name, "dclk m n p"); Bprint(&stdout, " %d %d - %d %d\n", f, m, n, p); printitem(ctlr->name, "CrystalFreq"); Bprint(&stdout, " %d Hz\n", nv->crystalfreq); printitem(ctlr->name, "cursor2"); Bprint(&stdout, " %lux\n", nv->cursor2); printitem(ctlr->name, "vpll"); Bprint(&stdout, " %lux\n", nv->vpll); printitem(ctlr->name, "pllsel"); Bprint(&stdout, " %lux\n", nv->pllsel); printitem(ctlr->name, "general"); Bprint(&stdout, " %lux\n", nv->general); printitem(ctlr->name, "config"); Bprint(&stdout, " %lux\n", nv->config); } Ctlr nvidia = { "nvidia", /* name */ snarf, /* snarf */ options, /* options */ init, /* init */ load, /* load */ dump, /* dump */ }; Ctlr nvidiahwgc = { "nvidiahwgc", /* name */ 0, /* snarf */ 0, /* options */ 0, /* init */ 0, /* load */ 0, /* dump */ };