summaryrefslogtreecommitdiff
path: root/os/pc/vganvidia.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/pc/vganvidia.c')
-rw-r--r--os/pc/vganvidia.c373
1 files changed, 373 insertions, 0 deletions
diff --git a/os/pc/vganvidia.c b/os/pc/vganvidia.c
new file mode 100644
index 00000000..e057ef1f
--- /dev/null
+++ b/os/pc/vganvidia.c
@@ -0,0 +1,373 @@
+#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 <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+
+enum {
+ Pramin = 0x00710000,
+ Pramdac = 0x00680000,
+ Fifo = 0x00800000,
+ Pgraph = 0x00400000
+};
+
+enum {
+ hwCurPos = Pramdac + 0x0300,
+ hwCurImage = Pramin + (0x00010000 - 0x0800),
+};
+
+/* Nvidia is good about backwards compatibility -- any did >= 0x20 is fine */
+static Pcidev*
+nvidiapci(void)
+{
+ Pcidev *p;
+
+ p = nil;
+ while((p = pcimatch(p, 0x10DE, 0)) != nil){
+ if(p->did >= 0x20 && p->ccrb == 3) /* video card */
+ 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;
+
+ 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->id = p->did;
+
+ 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++) {
+ switch(scr->id){
+ default:
+ c = (curs->clr[2 * i] << 8) | curs->clr[2 * i+1];
+ s = (curs->set[2 * i] << 8) | curs->set[2 * i+1];
+ break;
+ case 0x171: /* for Geforece4 MX bug, K.Okamoto */
+ case 0x181:
+ c = (curs->clr[2 * i+1] << 8) | curs->clr[2 * i];
+ s = (curs->set[2 * i+1] << 8) | curs->set[2 * i];
+ break;
+ }
+ 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 + hwCurPos);
+ *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,
+};