summaryrefslogtreecommitdiff
path: root/sys/src/9/pc/vganvidia.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/pc/vganvidia.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/pc/vganvidia.c')
-rwxr-xr-xsys/src/9/pc/vganvidia.c540
1 files changed, 540 insertions, 0 deletions
diff --git a/sys/src/9/pc/vganvidia.c b/sys/src/9/pc/vganvidia.c
new file mode 100755
index 000000000..5ef910451
--- /dev/null
+++ b/sys/src/9/pc/vganvidia.c
@@ -0,0 +1,540 @@
+
+/* Portions of this file derived from work with the following copyright */
+
+ /***************************************************************************\
+|* *|
+|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *|
+|* *|
+|* NOTICE TO USER: The source code is copyrighted under U.S. and *|
+|* international laws. Users and possessors of this source code are *|
+|* hereby granted a nonexclusive, royalty-free copyright license to *|
+|* use this code in individual and commercial software. *|
+|* *|
+|* Any use of this source code must include, in the user documenta- *|
+|* tion and internal comments to the code, notices to the end user *|
+|* as follows: *|
+|* *|
+|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *|
+|* *|
+|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *|
+|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *|
+|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *|
+|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *|
+|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *|
+|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *|
+|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *|
+|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *|
+|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *|
+|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *|
+|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *|
+|* *|
+|* U.S. Government End Users. This source code is a "commercial *|
+|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *|
+|* consisting of "commercial computer software" and "commercial *|
+|* computer software documentation," as such terms are used in *|
+|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *|
+|* ment only as a commercial end item. Consistent with 48 C.F.R. *|
+|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *|
+|* all U.S. Government End Users acquire the source code with only *|
+|* those rights set forth herein. *|
+|* *|
+ \***************************************************************************/
+
+#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"
+#include "nv_dma.h"
+
+enum {
+ Pramin = 0x00710000,
+ Pramdac = 0x00680000,
+ Fifo = 0x00800000,
+ Pgraph = 0x00400000,
+ Pfb = 0x00100000
+};
+
+enum {
+ hwCurPos = Pramdac + 0x0300,
+};
+
+#define SKIPS 8
+
+struct {
+ ulong *dmabase;
+ int dmacurrent;
+ int dmaput;
+ int dmafree;
+ int dmamax;
+} nv;
+
+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 void
+nvidialinear(VGAscr*, int, int)
+{
+}
+
+static void
+nvidiaenable(VGAscr* scr)
+{
+ Pcidev *p;
+ ulong *q;
+ int tmp;
+
+ if(scr->mmio)
+ return;
+ p = nvidiapci();
+ if(p == nil)
+ return;
+ scr->id = p->did;
+ scr->pci = p;
+
+ scr->mmio = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);
+ if(scr->mmio == nil)
+ return;
+ addvgaseg("nvidiammio", p->mem[0].bar&~0x0F, p->mem[0].size);
+
+ vgalinearpci(scr);
+ if(scr->apsize)
+ addvgaseg("nvidiascreen", scr->paddr, scr->apsize);
+
+ /* find video memory size */
+ switch (scr->id & 0x0ff0) {
+ case 0x0020:
+ case 0x00A0:
+ q = (void*)((uchar*)scr->mmio + Pfb);
+ tmp = *q;
+ if (tmp & 0x0100) {
+ scr->storage = ((tmp >> 12) & 0x0F) * 1024 + 1024 * 2;
+ } else {
+ tmp &= 0x03;
+ if (tmp)
+ scr->storage = (1024*1024*2) << tmp;
+ else
+ scr->storage = 1024*1024*32;
+ }
+ break;
+ case 0x01A0:
+ p = pcimatchtbdf(MKBUS(BusPCI, 0, 0, 1));
+ tmp = pcicfgr32(p, 0x7C);
+ scr->storage = (((tmp >> 6) & 31) + 1) * 1024 * 1024;
+ break;
+ case 0x01F0:
+ p = pcimatchtbdf(MKBUS(BusPCI, 0, 0, 1));
+ tmp = pcicfgr32(p, 0x84);
+ scr->storage = (((tmp >> 4) & 127) + 1) * 1024 * 1024;
+ break;
+ default:
+ q = (void*)((uchar*)scr->mmio + Pfb + 0x020C);
+ tmp = (*q >> 20) & 0xFFF;
+ if (tmp == 0)
+ tmp = 16;
+ scr->storage = tmp*1024*1024;
+ break;
+ }
+}
+
+static void
+nvidiacurdisable(VGAscr* scr)
+{
+ if(scr->mmio == 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->mmio == 0)
+ return;
+
+ vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) & ~0x01);
+
+ switch (scr->id & 0x0ff0) {
+ case 0x0020:
+ case 0x00A0:
+ p = (void*)((uchar*)scr->mmio + Pramin + 0x1E00 * 4);
+ break;
+ default:
+ /*
+ * Reset the cursor location, since the kernel may
+ * have allocated less storage than aux/vga
+ * expected.
+ */
+ tmp = scr->apsize - 96*1024;
+ p = (void*)((uchar*)scr->vaddr + tmp);
+ vgaxo(Crtx, 0x30, 0x80|(tmp>>17));
+ vgaxo(Crtx, 0x31, (tmp>>11)<<2);
+ vgaxo(Crtx, 0x2F, tmp>>24);
+ break;
+ }
+
+ 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->mmio == 0)
+ return 1;
+
+ cursorpos = (void*)((uchar*)scr->mmio + 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->mmio == 0)
+ return;
+
+ vgaxo(Crtx, 0x1F, 0x57);
+
+ nvidiacurload(scr, &arrow);
+ nvidiacurmove(scr, ZP);
+
+ vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) | 0x01);
+}
+
+void
+writeput(VGAscr *scr, int data)
+{
+ uchar *p, scratch;
+ ulong *fifo;
+
+ outb(0x3D0,0);
+ p = scr->vaddr;
+ scratch = *p;
+ fifo = (void*)((uchar*)scr->mmio + Fifo);
+ fifo[0x10] = (data << 2);
+ USED(scratch);
+}
+
+ulong
+readget(VGAscr *scr)
+{
+ ulong *fifo;
+
+ fifo = (void*)((uchar*)scr->mmio + Fifo);
+ return (fifo[0x0011] >> 2);
+}
+
+void
+nvdmakickoff(VGAscr *scr)
+{
+ if(nv.dmacurrent != nv.dmaput) {
+ nv.dmaput = nv.dmacurrent;
+ writeput(scr, nv.dmaput);
+ }
+}
+
+static void
+nvdmanext(ulong data)
+{
+ nv.dmabase[nv.dmacurrent++] = data;
+}
+
+void
+nvdmawait(VGAscr *scr, int size)
+{
+ int dmaget;
+
+ size++;
+
+ while(nv.dmafree < size) {
+ dmaget = readget(scr);
+
+ if(nv.dmaput >= dmaget) {
+ nv.dmafree = nv.dmamax - nv.dmacurrent;
+ if(nv.dmafree < size) {
+ nvdmanext(0x20000000);
+ if(dmaget <= SKIPS) {
+ if (nv.dmaput <= SKIPS) /* corner case - will be idle */
+ writeput(scr, SKIPS + 1);
+ do { dmaget = readget(scr); }
+ while(dmaget <= SKIPS);
+ }
+ writeput(scr, SKIPS);
+ nv.dmacurrent = nv.dmaput = SKIPS;
+ nv.dmafree = dmaget - (SKIPS + 1);
+ }
+ } else
+ nv.dmafree = dmaget - nv.dmacurrent - 1;
+ }
+}
+
+
+static void
+nvdmastart(VGAscr *scr, ulong tag, int size)
+{
+ if (nv.dmafree <= size)
+ nvdmawait(scr, size);
+ nvdmanext((size << 18) | tag);
+ nv.dmafree -= (size + 1);
+}
+
+static void
+waitforidle(VGAscr *scr)
+{
+ ulong* pgraph;
+ int x;
+
+ pgraph = (void*)((uchar*)scr->mmio + Pgraph);
+
+ x = 0;
+ while((readget(scr) != nv.dmaput) && x++ < 1000000)
+ ;
+ if(x >= 1000000)
+ iprint("idle stat %lud put %d scr %#p pc %#p\n", readget(scr), nv.dmaput, scr, getcallerpc(&scr));
+
+ x = 0;
+ while(pgraph[0x00000700/4] & 0x01 && x++ < 1000000)
+ ;
+
+ if(x >= 1000000)
+ iprint("idle stat %lud scrio %#p scr %#p pc %#p\n", *pgraph, scr->mmio, scr, getcallerpc(&scr));
+}
+
+static void
+nvresetgraphics(VGAscr *scr)
+{
+ ulong surfaceFormat, patternFormat, rectFormat, lineFormat;
+ int pitch, i;
+
+ pitch = scr->gscreen->width*BY2WD;
+
+ /*
+ * DMA is at the end of the virtual window,
+ * but we might have cut it short when mapping it.
+ */
+ if(nv.dmabase == nil){
+ if(scr->storage <= scr->apsize)
+ nv.dmabase = (ulong*)((uchar*)scr->vaddr + scr->storage - 128*1024);
+ else{
+ nv.dmabase = (void*)vmap(scr->paddr + scr->storage - 128*1024, 128*1024);
+ if(nv.dmabase == 0){
+ hwaccel = 0;
+ hwblank = 0;
+ print("vmap nvidia dma failed\n");
+ return;
+ }
+ }
+ }
+
+ for(i=0; i<SKIPS; i++)
+ nv.dmabase[i] = 0x00000000;
+
+ nv.dmabase[0x0 + SKIPS] = 0x00040000;
+ nv.dmabase[0x1 + SKIPS] = 0x80000010;
+ nv.dmabase[0x2 + SKIPS] = 0x00042000;
+ nv.dmabase[0x3 + SKIPS] = 0x80000011;
+ nv.dmabase[0x4 + SKIPS] = 0x00044000;
+ nv.dmabase[0x5 + SKIPS] = 0x80000012;
+ nv.dmabase[0x6 + SKIPS] = 0x00046000;
+ nv.dmabase[0x7 + SKIPS] = 0x80000013;
+ nv.dmabase[0x8 + SKIPS] = 0x00048000;
+ nv.dmabase[0x9 + SKIPS] = 0x80000014;
+ nv.dmabase[0xA + SKIPS] = 0x0004A000;
+ nv.dmabase[0xB + SKIPS] = 0x80000015;
+ nv.dmabase[0xC + SKIPS] = 0x0004C000;
+ nv.dmabase[0xD + SKIPS] = 0x80000016;
+ nv.dmabase[0xE + SKIPS] = 0x0004E000;
+ nv.dmabase[0xF + SKIPS] = 0x80000017;
+
+ nv.dmaput = 0;
+ nv.dmacurrent = 16 + SKIPS;
+ nv.dmamax = 8191;
+ nv.dmafree = nv.dmamax - nv.dmacurrent;
+
+ switch(scr->gscreen->depth) {
+ case 32:
+ case 24:
+ surfaceFormat = SURFACE_FORMAT_DEPTH24;
+ patternFormat = PATTERN_FORMAT_DEPTH24;
+ rectFormat = RECT_FORMAT_DEPTH24;
+ lineFormat = LINE_FORMAT_DEPTH24;
+ break;
+ case 16:
+ case 15:
+ surfaceFormat = SURFACE_FORMAT_DEPTH16;
+ patternFormat = PATTERN_FORMAT_DEPTH16;
+ rectFormat = RECT_FORMAT_DEPTH16;
+ lineFormat = LINE_FORMAT_DEPTH16;
+ break;
+ default:
+ surfaceFormat = SURFACE_FORMAT_DEPTH8;
+ patternFormat = PATTERN_FORMAT_DEPTH8;
+ rectFormat = RECT_FORMAT_DEPTH8;
+ lineFormat = LINE_FORMAT_DEPTH8;
+ break;
+ }
+
+ nvdmastart(scr, SURFACE_FORMAT, 4);
+ nvdmanext(surfaceFormat);
+ nvdmanext(pitch | (pitch << 16));
+ nvdmanext(0);
+ nvdmanext(0);
+
+ nvdmastart(scr, PATTERN_FORMAT, 1);
+ nvdmanext(patternFormat);
+
+ nvdmastart(scr, RECT_FORMAT, 1);
+ nvdmanext(rectFormat);
+
+ nvdmastart(scr, LINE_FORMAT, 1);
+ nvdmanext(lineFormat);
+
+ nvdmastart(scr, PATTERN_COLOR_0, 4);
+ nvdmanext(~0);
+ nvdmanext(~0);
+ nvdmanext(~0);
+ nvdmanext(~0);
+
+ nvdmastart(scr, ROP_SET, 1);
+ nvdmanext(0xCC);
+
+ nvdmakickoff(scr);
+ waitforidle(scr);
+}
+
+
+static int
+nvidiahwfill(VGAscr *scr, Rectangle r, ulong sval)
+{
+ nvdmastart(scr, RECT_SOLID_COLOR, 1);
+ nvdmanext(sval);
+
+ nvdmastart(scr, RECT_SOLID_RECTS(0), 2);
+ nvdmanext((r.min.x << 16) | r.min.y);
+ nvdmanext((Dx(r) << 16) | Dy(r));
+
+ //if ( (Dy(r) * Dx(r)) >= 512)
+ nvdmakickoff(scr);
+
+ waitforidle(scr);
+
+ return 1;
+}
+
+static int
+nvidiahwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
+{
+ nvdmastart(scr, BLIT_POINT_SRC, 3);
+ nvdmanext((sr.min.y << 16) | sr.min.x);
+ nvdmanext((r.min.y << 16) | r.min.x);
+ nvdmanext((Dy(r) << 16) | Dx(r));
+
+ //if ( (Dy(r) * Dx(r)) >= 512)
+ nvdmakickoff(scr);
+
+ 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)
+{
+ nvresetgraphics(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,
+};