#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #define Image IMAGE #include #include #include #include "screen.h" enum { Pramin = 0x00710000, Pramdac0 = 0x00680000, Pramdac1 = 0x00680000 + 0x2000, Fifo = 0x00800000, Pgraph = 0x00400000 }; enum { hwCurPos0 = Pramdac0 + 0x0300, hwCurPos1 = Pramdac1 + 0x0300, hwCurImage = Pramin + (0x00010000 - 0x0800), }; static ushort nvidiadid[] = { 0x0020, /* Riva TNT */ 0x0028, /* Riva TNT2 */ 0x0029, /* Riva TNT2 (Ultra)*/ 0x002C, /* Riva TNT2 (Vanta) */ 0x002D, /* Riva TNT2 M64 */ 0x00A0, /* Riva TNT2 (Integrated) */ 0x0100, /* GeForce 256 */ 0x0101, /* GeForce DDR */ 0x0103, /* Quadro */ 0x0110, /* GeForce2 MX */ 0x0111, /* GeForce2 MX DDR */ 0x0112, /* GeForce 2 Go */ 0x0113, /* Quadro 2 MXR */ 0x0150, /* GeForce2 GTS */ 0x0151, /* GeForce2 GTS (rev 1) */ 0x0152, /* GeForce2 Ultra */ 0x0153, /* Quadro 2 Pro */ 0x0170, /* GeForce4 MX 460 */ 0x0171, /* GeForce4 MX 440 */ 0x0172, /* GeForce4 MX 420 */ 0x0174, /* GeForce4 440 GO */ 0x0175, /* GeForce4 420 GO */ 0x0176, /* GeForce4 440 GO M32 */ 0x0178, /* Quadro4 500XGL */ 0x0179, /* GeForce4 440 GO M64 */ 0x017A, /* Guadro4 200 */ 0x017B, /* Quadro4 550XGL */ 0x017C, /* Quadro4 500 GOGL */ 0x01A0, /* IGeForce2 */ 0x0200, /* GeForce3 */ 0x0201, /* GeForce3 TI 200 */ 0x0202, /* GeForce3 TI 500 */ 0x0203, /* Quadro DDC */ 0x0250, /* GeForce4 TI 4600 */ 0x0251, /* GeForce4 TI 4400 */ 0x0253, /* GeForce4 TI 4200 */ 0x0258, /* Quadro4 900XGL */ 0x0259, /* Quadro4 750XGL */ 0x025B, /* Quadro4 700XGL */ 0, }; static int twoheads; static Pcidev* nvidiapci(void) { Pcidev *p; ushort *did; if((p = pcimatch(nil, 0x10DE, 0)) == nil) return nil; for(did = nvidiadid; *did; did++){ if(*did == p->did) return p; } return nil; } static ulong nvidialinear(VGAscr* scr, int* size, int* align) { Pcidev *p; int oapsize, wasupamem; ulong aperture, oaperture; oaperture = scr->aperture; oapsize = scr->apsize; wasupamem = scr->isupamem; aperture = 0; if(p = nvidiapci()){ aperture = p->mem[1].bar & ~0x0F; *size = p->mem[1].size; } if(wasupamem) { if(oaperture == aperture) return oaperture; upafree(oaperture, oapsize); } scr->isupamem = 0; aperture = upamalloc(aperture, *size, *align); if(aperture == 0){ if(wasupamem && upamalloc(oaperture, oapsize, 0)){ aperture = oaperture; scr->isupamem = 1; } else scr->isupamem = 0; } else scr->isupamem = 1; switch(p->did & 0x0ff0) { case 0x0110: case 0x0170: case 0x0250: twoheads = 1; break; default: twoheads = 0; break; } return aperture; } static void nvidiaenable(VGAscr* scr) { Pcidev *p; ulong aperture; int align, size; /* * Only once, can't be disabled for now. * scr->io holds the physical address of * the MMIO registers. */ if(scr->io) return; p = nvidiapci(); if(p == nil) return; scr->io = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0); if (scr->io == 0) return; addvgaseg("nvidiammio", scr->io, p->mem[0].size); size = p->mem[1].size; align = 0; aperture = nvidialinear(scr, &size, &align); if(aperture) { scr->aperture = aperture; scr->apsize = size; addvgaseg("nvidiascreen", aperture, size); } } static void nvidiacurdisable(VGAscr* scr) { if(scr->io == 0) return; vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) & ~0x01); } static void nvidiacurload(VGAscr* scr, Cursor* curs) { ulong* p; int i,j; ushort c,s; ulong tmp; if(scr->io == 0) return; vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) & ~0x01); p = KADDR(scr->io + hwCurImage); for (i=0; i<16; i++) { c = (curs->clr[2 * i] << 8) | curs->clr[2 * i+1]; s = (curs->set[2 * i] << 8) | curs->set[2 * i+1]; tmp = 0; for (j=0; j<16; j++) { if(s&0x8000) tmp |= 0x80000000; else if(c&0x8000) tmp |= 0xFFFF0000; if (j&0x1) { *p++ = tmp; tmp = 0; } else { tmp>>=16; } c<<=1; s<<=1; } for (j=0; j<8; j++) *p++ = 0; } for (i=0; i<256; i++) *p++ = 0; scr->offset = curs->offset; vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) | 0x01); return; } static int nvidiacurmove(VGAscr* scr, Point p) { ulong* cursorpos; if(scr->io == 0) return 1; cursorpos = KADDR(scr->io + hwCurPos0); *cursorpos = ((p.y+scr->offset.y)<<16)|((p.x+scr->offset.x) & 0xFFFF); if (twoheads) { cursorpos = KADDR(scr->io + hwCurPos1); *cursorpos = ((p.y+scr->offset.y)<<16)|((p.x+scr->offset.x) & 0xFFFF); } return 0; } static void nvidiacurenable(VGAscr* scr) { nvidiaenable(scr); if(scr->io == 0) return; vgaxo(Crtx, 0x1F, 0x57); nvidiacurload(scr, &arrow); nvidiacurmove(scr, ZP); vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) | 0x01); } enum { RopFifo = 0x00000000, ClipFifo = 0x00002000, PattFifo = 0x00004000, BltFifo = 0x00008000, BitmapFifo = 0x0000A000, }; enum { RopRop3 = RopFifo + 0x300, ClipTopLeft = ClipFifo + 0x300, ClipWidthHeight = ClipFifo + 0x304, PattShape = PattFifo + 0x0308, PattColor0 = PattFifo + 0x0310, PattColor1 = PattFifo + 0x0314, PattMonochrome0 = PattFifo + 0x0318, PattMonochrome1 = PattFifo + 0x031C, BltTopLeftSrc = BltFifo + 0x0300, BltTopLeftDst = BltFifo + 0x0304, BltWidthHeight = BltFifo + 0x0308, BitmapColor1A = BitmapFifo + 0x03FC, BitmapURect0TopLeft = BitmapFifo + 0x0400, BitmapURect0WidthHeight = BitmapFifo + 0x0404, }; static void waitforidle(VGAscr *scr) { ulong* pgraph; int x; pgraph = KADDR(scr->io + Pgraph); x = 0; while (pgraph[0x00000700/4] & 0x01 && x++ < 1000000) ; if(x >= 1000000) iprint("idle stat %lud scrio %.8lux scr %p pc %luX\n", *pgraph, scr->io, scr, getcallerpc(&scr)); } static void waitforfifo(VGAscr *scr, int fifo, int entries) { ushort* fifofree; int x; x = 0; fifofree = KADDR(scr->io + Fifo + fifo + 0x10); while (((*fifofree >> 2) < entries) && x++ < 1000000) ; if(x >= 1000000) iprint("fifo stat %d scrio %.8lux scr %p pc %luX\n", *fifofree, scr->io, scr, getcallerpc(&scr)); } static int nvidiahwfill(VGAscr *scr, Rectangle r, ulong sval) { ulong* fifo; fifo = KADDR(scr->io + Fifo); waitforfifo(scr, BitmapFifo, 1); fifo[BitmapColor1A/4] = sval; waitforfifo(scr, BitmapFifo, 2); fifo[BitmapURect0TopLeft/4] = (r.min.x << 16) | r.min.y; fifo[BitmapURect0WidthHeight/4] = (Dx(r) << 16) | Dy(r); waitforidle(scr); return 1; } static int nvidiahwscroll(VGAscr *scr, Rectangle r, Rectangle sr) { ulong* fifo; fifo = KADDR(scr->io + Fifo); waitforfifo(scr, BltFifo, 3); fifo[BltTopLeftSrc/4] = (sr.min.y << 16) | sr.min.x; fifo[BltTopLeftDst/4] = (r.min.y << 16) | r.min.x; fifo[BltWidthHeight/4] = (Dy(r) << 16) | Dx(r); waitforidle(scr); return 1; } void nvidiablank(VGAscr*, int blank) { uchar seq1, crtc1A; seq1 = vgaxi(Seqx, 1) & ~0x20; crtc1A = vgaxi(Crtx, 0x1A) & ~0xC0; if(blank) { seq1 |= 0x20; // crtc1A |= 0xC0; crtc1A |= 0x80; } vgaxo(Seqx, 1, seq1); vgaxo(Crtx, 0x1A, crtc1A); } static void nvidiadrawinit(VGAscr *scr) { ulong* fifo; fifo = KADDR(scr->io + Fifo); waitforfifo(scr, ClipFifo, 2); fifo[ClipTopLeft/4] = 0x0; fifo[ClipWidthHeight/4] = 0x80008000; waitforfifo(scr, PattFifo, 5); fifo[PattShape/4] = 0; fifo[PattColor0/4] = 0xffffffff; fifo[PattColor1/4] = 0xffffffff; fifo[PattMonochrome0/4] = 0xffffffff; fifo[PattMonochrome1/4] = 0xffffffff; waitforfifo(scr, RopFifo, 1); fifo[RopRop3/4] = 0xCC; waitforidle(scr); scr->blank = nvidiablank; hwblank = 1; scr->fill = nvidiahwfill; scr->scroll = nvidiahwscroll; } VGAdev vganvidiadev = { "nvidia", nvidiaenable, nil, nil, nvidialinear, nvidiadrawinit, }; VGAcur vganvidiacur = { "nvidiahwgc", nvidiacurenable, nvidiacurdisable, nvidiacurload, nvidiacurmove, };