ref: 61cc0694649a4d4b109d168032f431751f57f083
dir: /sys/src/9/pc/vgamga4xx.c/
/* * Matrox G200, G400 and G450. * Written by Philippe Anel <xigh@free.fr> * * 2006-08-07 : Minor fix to allow the G200 cards to work fine. YDSTORG is now initialized. * : Also support for 16 and 24 bit modes is added. * : by Leonardo Valencia <leoval@anixcorp.com> */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/pci.h" #include "../port/error.h" #define Image IMAGE #include <draw.h> #include <memdraw.h> #include <cursor.h> #include "screen.h" enum { MATROX = 0x102B, MGA550 = 0x2527, MGA4xx = 0x0525, MGA200 = 0x0521, FCOL = 0x1c24, FXRIGHT = 0x1cac, FXLEFT = 0x1ca8, YDST = 0x1c90, YLEN = 0x1c5c, DWGCTL = 0x1c00, DWG_TRAP = 0x04, DWG_BITBLT = 0x08, DWG_ILOAD = 0x09, DWG_LINEAR = 0x0080, DWG_SOLID = 0x0800, DWG_ARZERO = 0x1000, DWG_SGNZERO = 0x2000, DWG_SHIFTZERO = 0x4000, DWG_REPLACE = 0x000C0000, DWG_BFCOL = 0x04000000, SRCORG = 0x2cb4, PITCH = 0x1c8c, DSTORG = 0x2cb8, YDSTORG = 0x1c94, PLNWRT = 0x1c1c, ZORG = 0x1c0c, MACCESS = 0x1c04, STATUS = 0x1e14, FXBNDRY = 0x1C84, CXBNDRY = 0x1C80, YTOP = 0x1C98, YBOT = 0x1C9C, YDSTLEN = 0x1C88, AR0 = 0x1C60, AR1 = 0x1C64, AR2 = 0x1C68, AR3 = 0x1C6C, AR4 = 0x1C70, AR5 = 0x1C74, SGN = 0x1C58, SGN_LEFT = 1, SGN_UP = 4, GO = 0x0100, FIFOSTATUS = 0x1E10, CACHEFLUSH = 0x1FFF, CRTCEXTIDX = 0x1FDE, /* CRTC Extension Index */ CRTCEXTDATA = 0x1FDF, /* CRTC Extension Data */ FILL_OPERAND = 0x800c7804, }; static void mgawrite8(VGAscr *scr, int index, uchar val) { ((uchar*)scr->mmio)[index] = val; } static uchar mgaread8(VGAscr *scr, int index) { return ((uchar*)scr->mmio)[index]; } static uchar crtcextset(VGAscr *scr, int index, uchar set, uchar clr) { uchar tmp; mgawrite8(scr, CRTCEXTIDX, index); tmp = mgaread8(scr, CRTCEXTDATA); mgawrite8(scr, CRTCEXTIDX, index); mgawrite8(scr, CRTCEXTDATA, (tmp & ~clr) | set); return tmp; } static void mga4xxenable(VGAscr* scr) { Pcidev *pci; int size; int i, n, k; uchar *p; uchar x[16]; uchar crtcext3; if(scr->mmio) return; pci = scr->pci; if(pci == nil) return; /* need to map frame buffer here too, so vga can find memory size */ if(pci->did == MGA4xx || pci->did == MGA550) size = 32*MB; else size = 8*MB; if((pci->mem[0].bar & 1) != 0 || pci->mem[0].size < size || (pci->mem[1].bar & 1) != 0 || pci->mem[1].size < 16*1024) return; scr->mmio = vmap(pci->mem[1].bar&~0x0F, 16*1024); if(scr->mmio == nil) return; addvgaseg("mga4xxmmio", pci->mem[1].bar&~0x0F, pci->mem[1].size); vgalinearaddr(scr, pci->mem[0].bar&~0x0F, size); if(scr->paddr){ /* Find out how much memory is here, some multiple of 2 MB */ /* First Set MGA Mode ... */ crtcext3 = crtcextset(scr, 3, 0x80, 0x00); p = scr->vaddr; n = (size / MB) / 2; for(i = 0; i < n; i++){ k = (2*i+1)*MB; p[k] = 0; p[k] = i+1; *((uchar*)scr->mmio + CACHEFLUSH) = 0; x[i] = p[k]; } for(i = 1; i < n; i++) if(x[i] != i+1) break; scr->apsize = 2*i*MB; /* sketchy */ addvgaseg("mga4xxscreen", scr->paddr, scr->apsize); crtcextset(scr, 3, crtcext3, 0xff); } } enum{ Index = 0x00, /* Index */ Data = 0x0A, /* Data */ Cxlsb = 0x0C, /* Cursor X LSB */ Cxmsb = 0x0D, /* Cursor X MSB */ Cylsb = 0x0E, /* Cursor Y LSB */ Cymsb = 0x0F, /* Cursor Y MSB */ Icuradrl = 0x04, /* Cursor Base Address Low */ Icuradrh = 0x05, /* Cursor Base Address High */ Icctl = 0x06, /* Indirect Cursor Control */ }; static void dac4xxdisable(VGAscr *scr) { uchar *dac4xx; if(scr->mmio == 0) return; dac4xx = (uchar*)scr->mmio+0x3C00; *(dac4xx+Index) = Icctl; *(dac4xx+Data) = 0x00; } static void dac4xxload(VGAscr *scr, Cursor *curs) { int y; uchar *p; uchar *dac4xx; if(scr->mmio == 0) return; dac4xx = (uchar*)scr->mmio+0x3C00; dac4xxdisable(scr); p = (uchar*)scr->storage; for(y = 0; y < 64; y++){ *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0; if(y < 16){ *p++ = curs->set[1+y*2]; *p++ = curs->set[y*2]; } else{ *p++ = 0; *p++ = 0; } *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0; if(y < 16){ *p++ = curs->set[1+y*2]|curs->clr[1+2*y]; *p++ = curs->set[y*2]|curs->clr[2*y]; } else{ *p++ = 0; *p++ = 0; } } scr->offset.x = 64 + curs->offset.x; scr->offset.y = 64 + curs->offset.y; *(dac4xx+Index) = Icctl; *(dac4xx+Data) = 0x03; } static int dac4xxmove(VGAscr *scr, Point p) { int x, y; uchar *dac4xx; if(scr->mmio == 0) return 1; dac4xx = (uchar*)scr->mmio + 0x3C00; x = p.x + scr->offset.x; y = p.y + scr->offset.y; *(dac4xx+Cxlsb) = x & 0xFF; *(dac4xx+Cxmsb) = (x>>8) & 0x0F; *(dac4xx+Cylsb) = y & 0xFF; *(dac4xx+Cymsb) = (y>>8) & 0x0F; return 0; } static void dac4xxenable(VGAscr *scr) { uchar *dac4xx; ulong storage; if(scr->mmio == 0) return; dac4xx = (uchar*)scr->mmio+0x3C00; dac4xxdisable(scr); storage = (scr->apsize-4096)&~0x3ff; *(dac4xx+Index) = Icuradrl; *(dac4xx+Data) = 0xff & (storage >> 10); *(dac4xx+Index) = Icuradrh; *(dac4xx+Data) = 0xff & (storage >> 18); scr->storage = (ulong)scr->vaddr + storage; /* Show X11-Like Cursor */ *(dac4xx+Index) = Icctl; *(dac4xx+Data) = 0x03; /* Cursor Color 0 : White */ *(dac4xx+Index) = 0x08; *(dac4xx+Data) = 0xff; *(dac4xx+Index) = 0x09; *(dac4xx+Data) = 0xff; *(dac4xx+Index) = 0x0a; *(dac4xx+Data) = 0xff; /* Cursor Color 1 : Black */ *(dac4xx+Index) = 0x0c; *(dac4xx+Data) = 0x00; *(dac4xx+Index) = 0x0d; *(dac4xx+Data) = 0x00; *(dac4xx+Index) = 0x0e; *(dac4xx+Data) = 0x00; /* Cursor Color 2 : Red */ *(dac4xx+Index) = 0x10; *(dac4xx+Data) = 0xff; *(dac4xx+Index) = 0x11; *(dac4xx+Data) = 0x00; *(dac4xx+Index) = 0x12; *(dac4xx+Data) = 0x00; /* * Load, locate and enable the * 64x64 cursor in X11 mode. */ dac4xxload(scr, &cursor); dac4xxmove(scr, ZP); } static void mga4xxblank(VGAscr *scr, int blank) { char *cp; uchar *mga; uchar seq1, crtcext1; /* blank = 0 -> turn screen on */ /* blank = 1 -> turn screen off */ if(scr->mmio == 0) return; mga = (uchar*)scr->mmio; if(blank == 0){ seq1 = 0x00; crtcext1 = 0x00; } else { seq1 = 0x20; crtcext1 = 0x10; /* Default value ... : standby */ cp = getconf("*dpms"); if(cp){ if(cistrcmp(cp, "standby") == 0) crtcext1 = 0x10; else if(cistrcmp(cp, "suspend") == 0) crtcext1 = 0x20; else if(cistrcmp(cp, "off") == 0) crtcext1 = 0x30; } } *(mga + 0x1fc4) = 1; seq1 |= *(mga + 0x1fc5) & ~0x20; *(mga + 0x1fc5) = seq1; *(mga + 0x1fde) = 1; crtcext1 |= *(mga + 0x1fdf) & ~0x30; *(mga + 0x1fdf) = crtcext1; } static void mgawrite32(uchar *mga, ulong reg, ulong val) { *((ulong*)(&mga[reg])) = val; } static ulong mgaread32(uchar *mga, ulong reg) { return *((ulong*)(&mga[reg])); } static void mga_fifo(uchar *mga, uchar n) { ulong t; #define Timeout 100 for (t = 0; t < Timeout; t++) if ((mgaread32(mga, FIFOSTATUS) & 0xff) >= n) break; if (t >= Timeout) print("mga4xx: fifo timeout"); } static int mga4xxfill(VGAscr *scr, Rectangle r, ulong color) { uchar *mga; if(scr->mmio == 0) return 0; mga = (uchar*)scr->mmio; mga_fifo(mga, 7); mgawrite32(mga, DWGCTL, 0); mgawrite32(mga, FCOL, color); mgawrite32(mga, FXLEFT, r.min.x); mgawrite32(mga, FXRIGHT, r.max.x); mgawrite32(mga, YDST, r.min.y); mgawrite32(mga, YLEN, Dy(r)); mgawrite32(mga, DWGCTL + GO, FILL_OPERAND); while(mgaread32(mga, STATUS) & 0x00010000) ; return 1; } static int mga4xxscroll(VGAscr *scr, Rectangle dr, Rectangle sr) { uchar * mga; int width, height; ulong start, end, sgn; Point sp, dp; if(scr->mmio == 0) return 0; mga = (uchar*)scr->mmio; assert(Dx(sr) == Dx(dr) && Dy(sr) == Dy(dr)); sp = sr.min; dp = dr.min; if(eqpt(sp, dp)) return 1; width = Dx(sr); height = Dy(sr); sgn = 0; if(dp.y > sp.y && dp.y < sp.y + height){ sp.y += height - 1; dp.y += height - 1; sgn |= SGN_UP; } width--; start = end = sp.x + (sp.y * scr->width); if(dp.x > sp.x && dp.x < sp.x + width){ start += width; sgn |= SGN_LEFT; } else end += width; mga_fifo(mga, 8); mgawrite32(mga, DWGCTL, 0); mgawrite32(mga, SGN, sgn); mgawrite32(mga, AR5, sgn & SGN_UP ? -scr->width : scr->width); mgawrite32(mga, AR0, end); mgawrite32(mga, AR3, start); mgawrite32(mga, FXBNDRY, ((dp.x + width) << 16) | dp.x); mgawrite32(mga, YDSTLEN, (dp.y << 16) | height); mgawrite32(mga, DWGCTL + GO, DWG_BITBLT | DWG_SHIFTZERO | DWG_BFCOL | DWG_REPLACE); while(mgaread32(mga, STATUS) & 0x00010000) ; return 1; } static void mga4xxdrawinit(VGAscr *scr) { uchar *mga; if(scr->mmio == 0) return; mga = (uchar*)scr->mmio; mgawrite32(mga, SRCORG, 0); mgawrite32(mga, DSTORG, 0); mgawrite32(mga, YDSTORG, 0); mgawrite32(mga, ZORG, 0); mgawrite32(mga, PLNWRT, ~0); mgawrite32(mga, FCOL, 0xffff0000); mgawrite32(mga, CXBNDRY, 0xFFFF0000); mgawrite32(mga, YTOP, 0); mgawrite32(mga, YBOT, 0x01FFFFFF); mgawrite32(mga, PITCH, Dx(scr->gscreen->r) & ((1 << 13) - 1)); switch(scr->gscreen->depth){ case 8: mgawrite32(mga, MACCESS, 0); break; case 16: mgawrite32(mga, MACCESS, 1); break; case 24: mgawrite32(mga, MACCESS, 3); break; case 32: mgawrite32(mga, MACCESS, 2); break; default: return; /* depth not supported ! */ } scr->fill = mga4xxfill; scr->scroll = mga4xxscroll; scr->blank = mga4xxblank; } VGAdev vgamga4xxdev = { "mga4xx", mga4xxenable, /* enable */ 0, /* disable */ 0, /* page */ 0, /* linear */ mga4xxdrawinit, }; VGAcur vgamga4xxcur = { "mga4xxhwgc", dac4xxenable, dac4xxdisable, dac4xxload, dac4xxmove, };