diff options
Diffstat (limited to 'os/pc/vgamga4xx.c')
| -rw-r--r-- | os/pc/vgamga4xx.c | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/os/pc/vgamga4xx.c b/os/pc/vgamga4xx.c new file mode 100644 index 00000000..7ddeebf1 --- /dev/null +++ b/os/pc/vgamga4xx.c @@ -0,0 +1,603 @@ + +/* + * Matrox G200, G400 and G450. + * see /sys/src/cmd/aux/vga/mga4xx.c + */ + +#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 { + MATROX = 0x102B, + MGA4xx = 0x0525, + MGA200 = 0x0521, + + Kilo = 1024, + Meg = 1024*1024, + + 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_REPLACE2 = (DWG_REPLACE | 0x40), + DWG_XOR = 0x00060010, + DWG_BFCOL = 0x04000000, + DWG_BMONOWF = 0x08000000, + DWG_TRANSC = 0x40000000, + SRCORG = 0x2cb4, + PITCH = 0x1c8c, + DSTORG = 0x2cb8, + 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_SCANLEFT = 1, + SGN_SCANRIGHT = 0, + SGN_SDY_POSITIVE = 0, + SGN_SDY_NEGATIVE = 4, + + GO = 0x0100, + FIFOSTATUS = 0x1E10, + CACHEFLUSH = 0x1FFF, + + CRTCEXTIDX = 0x1FDE, /* CRTC Extension Index */ + CRTCEXTDATA = 0x1FDF, /* CRTC Extension Data */ + + FILL_OPERAND = 0x800c7804, +}; + +static Pcidev* +mgapcimatch(void) +{ + Pcidev* p; + + p = pcimatch(nil, MATROX, MGA4xx); + if (p == nil) + p = pcimatch(nil, MATROX, MGA200); + return p; +} + +static ulong +mga4xxlinear(VGAscr* scr, int* size, int* align) +{ + ulong aperture, oaperture; + int oapsize, wasupamem; + Pcidev * p; + + oaperture = scr->aperture; + oapsize = scr->apsize; + wasupamem = scr->isupamem; + + if(p = mgapcimatch()){ + aperture = p->mem[0].bar & ~0x0F; + if(p->did == MGA4xx) + *size = 32*Meg; + else + *size = 8*Meg; + } + else + aperture = 0; + + 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 +mgawrite8(VGAscr* scr, int index, uchar val) +{ + ((uchar*)scr->io)[index] = val; +} + +static uchar +mgaread8(VGAscr* scr, int index) +{ + return ((uchar*)scr->io)[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, align; + ulong aperture; + int i, n, k; + uchar * p; + uchar x[16]; + uchar crtcext3; + + /* + * Only once, can't be disabled for now. + * scr->io holds the virtual address of + * the MMIO registers. + */ + if(scr->io) + return; + + pci = mgapcimatch(); + if(pci == nil) + return; + + scr->io = upamalloc(pci->mem[1].bar & ~0x0F, 16*1024, 0); + if(scr->io == 0) + return; + + addvgaseg("mga4xxmmio", scr->io, pci->mem[1].size); + + scr->io = (ulong)KADDR(scr->io); + + /* need to map frame buffer here too, so vga can find memory size */ + size = 8*Meg; + align = 0; + aperture = mga4xxlinear(scr, &size, &align); + if(aperture) { + scr->aperture = aperture; + addvgaseg("mga4xxscreen", aperture, size); + + /* Find out how much memory is here, some multiple of 2 Meg */ + + /* First Set MGA Mode ... */ + crtcext3 = crtcextset(scr, 3, 0x80, 0x00); + + p = (uchar*)aperture; + n = (size / Meg) / 2; + for (i = 0; i < n; i++) { + k = (2*i+1)*Meg; + p[k] = 0; + p[k] = i+1; + *((uchar*)(scr->io + CACHEFLUSH)) = 0; + x[i] = p[k]; + } + for(i = 1; i < n; i++) + if(x[i] != i+1) + break; + scr->apsize = 2*i*Meg; + + 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->io == 0) + return; + + dac4xx = KADDR(scr->io+0x3C00); + + *(dac4xx+Index) = Icctl; + *(dac4xx+Data) = 0x00; +} + +static void +dac4xxload(VGAscr* scr, Cursor* curs) +{ + int y; + uchar * p; + uchar * dac4xx; + + if(scr->io == 0) + return; + + dac4xx = KADDR(scr->io+0x3C00); + + dac4xxdisable(scr); + + p = KADDR(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]|curs->clr[1+2*y]; + *p++ = curs->set[y*2]|curs->clr[2*y]; + } 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]; + *p++ = curs->set[y*2]; + } 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->io == 0) + return 1; + + dac4xx = KADDR(scr->io + 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->io == 0) + return; + dac4xx = KADDR(scr->io+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) KADDR((ulong)scr->aperture + (ulong)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, &arrow); + 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->io == 0) + return; + mga = KADDR(scr->io); + + 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 * l; + + l = (ulong *)(&mga[reg]); + l[0] = val; +} + +static ulong +mgaread32(uchar * mga, ulong reg) +{ + return *((ulong *)(&mga[reg])); +} + +static int +mga4xxfill(VGAscr* scr, Rectangle r, ulong color) +{ + uchar * mga; + + /* Constant Shaded Trapezoids / Rectangle Fills */ + if(scr->io == 0) + return 0; + mga = KADDR(scr->io); + + mgawrite32(mga, DWGCTL, 0); + mgawrite32(mga, FCOL, color); + mgawrite32(mga, FXRIGHT, r.max.x); + mgawrite32(mga, FXLEFT, r.min.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; +} + +#define mga_fifo(n) do {} while ((mgaread32(mga, FIFOSTATUS) & 0xFF) < (n)) + +static int +mga4xxscroll(VGAscr* scr, Rectangle r_dst, Rectangle r_src) +{ + uchar * mga; + ulong pitch, y; + ulong width, height, start, end, scandir; + int ydir; + + /* Two-operand Bitblts */ + if(scr->io == 0) + return 0; + + mga = KADDR(scr->io); + + pitch = Dx(scr->gscreen->r); + + mgawrite32(mga, DWGCTL, 0); + + scandir = 0; + + height = abs(Dy(r_src)); + width = abs(Dx(r_src)); + + assert(height == abs(Dy(r_dst))); + assert(width == abs(Dx(r_dst))); + + if ((r_src.min.y == r_dst.min.y) && (r_src.min.x == r_dst.min.x)) + { + if (0) + print("move x,y to x,y !\n"); + return 1; + } + + ydir = 1; + if (r_dst.min.y > r_src.min.y) + { + if (0) + print("ydir = -1\n"); + ydir = -1; + scandir |= 4; // Blit UP + } + + if (r_dst.min.x > r_src.min.x) + { + if (0) + print("xdir = -1\n"); + scandir |= 1; // Blit Left + } + + mga_fifo(4); + if (scandir) + { + mgawrite32(mga, DWGCTL, DWG_BITBLT | DWG_SHIFTZERO | + DWG_SGNZERO | DWG_BFCOL | DWG_REPLACE); + mgawrite32(mga, SGN, scandir); + } else + { + mgawrite32(mga, DWGCTL, DWG_BITBLT | DWG_SHIFTZERO | + DWG_BFCOL | DWG_REPLACE); + } + mgawrite32(mga, AR5, ydir * pitch); + + width--; + start = end = r_src.min.x + (r_src.min.y * pitch); + if ((scandir & 1) == 1) + { + start += width; + } else + { + end += width; + } + + y = r_dst.min.y; + if ((scandir & 4) == 4) + { + start += (height - 1) * pitch; + end += (height - 1) * pitch; + y += (height - 1); + } + + mga_fifo(4); + mgawrite32(mga, AR0, end); + mgawrite32(mga, AR3, start); + mgawrite32(mga, FXBNDRY, ((r_dst.min.x+width)<<16) | r_dst.min.x); + mgawrite32(mga, YDSTLEN + GO, (y << 16) | height); + + if (1) + { + while (mgaread32(mga, STATUS) & 0x00010000) + ; + } + + return 1; +} + +static void +mga4xxdrawinit(VGAscr* scr) +{ + uchar * mga; + Pcidev* p; + + p = pcimatch(nil, MATROX, MGA4xx); + if (p == nil) + return ; + + if(scr->io == 0) + return; + mga = KADDR(scr->io); + + mgawrite32(mga, SRCORG, 0); + mgawrite32(mga, DSTORG, 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 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 */ + mga4xxlinear, /* linear */ + mga4xxdrawinit, +}; + +VGAcur vgamga4xxcur = { + "mga4xxhwgc", + dac4xxenable, + dac4xxdisable, + dac4xxload, + dac4xxmove, +}; |
