diff options
Diffstat (limited to 'os/pc/vganeomagic.c')
| -rw-r--r-- | os/pc/vganeomagic.c | 541 |
1 files changed, 541 insertions, 0 deletions
diff --git a/os/pc/vganeomagic.c b/os/pc/vganeomagic.c new file mode 100644 index 00000000..ba25a581 --- /dev/null +++ b/os/pc/vganeomagic.c @@ -0,0 +1,541 @@ +#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" + +typedef struct CursorNM CursorNM; +struct CursorNM { + int enable; + int x; + int y; + int colour1; + int colour2; + int addr; +}; + +static ulong +neomagiclinear(VGAscr* scr, int* size, int* align) +{ + ulong aperture, oaperture; + int oapsize, wasupamem; + Pcidev *p; + + oaperture = scr->aperture; + oapsize = scr->apsize; + wasupamem = scr->isupamem; + + aperture = 0; + if(p = pcimatch(nil, 0x10C8, 0)){ + switch(p->did){ + case 0x0004: /* MagicGraph 128XD */ + case 0x0005: /* MagicMedia 256AV */ + case 0x0006: /* MagicMedia 256ZX */ + aperture = p->mem[0].bar & ~0x0F; + *size = p->mem[0].size; + break; + default: + break; + } + } + + 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 +neomagicenable(VGAscr* scr) +{ + Pcidev *p; + int align, curoff, size, vmsize; + ulong aperture; + + /* + * Only once, can't be disabled for now. + * scr->io holds the physical address of the cursor registers + * in the MMIO space. This may need to change for older chips + * which have the MMIO space offset in the framebuffer region. + */ + if(scr->io) + return; + if(p = pcimatch(nil, 0x10C8, 0)){ + switch(p->did){ + case 0x0004: /* MagicGraph 128XD */ + curoff = 0x100; + vmsize = 2048*1024; + break; + case 0x0005: /* MagicMedia 256AV */ + curoff = 0x1000; + vmsize = 2560*1024; + break; + case 0x0006: /* MagicMedia 256ZX */ + curoff = 0x1000; + vmsize = 4096*1024; + break; + default: + return; + } + } + else + return; + scr->io = upamalloc(p->mem[1].bar & ~0x0F, p->mem[1].size, 0); + if(scr->io == 0) + return; + addvgaseg("neomagicmmio", scr->io, p->mem[1].size); + scr->mmio = KADDR(scr->io); + + /* + * Find a place for the cursor data in display memory. + * 2 cursor images might be needed, 1KB each so use the + * last 2KB of the framebuffer. + */ + scr->storage = vmsize-2*1024; + scr->io += curoff; + + size = p->mem[0].size; + align = 0; + aperture = neomagiclinear(scr, &size, &align); + if(aperture) { + scr->aperture = aperture; + scr->apsize = size; + addvgaseg("neomagicscreen", aperture, size); + } +} + +static void +neomagiccurdisable(VGAscr* scr) +{ + CursorNM *cursornm; + + if(scr->io == 0) + return; + cursornm = KADDR(scr->io); + cursornm->enable = 0; +} + +static void +neomagicinitcursor(VGAscr* scr, int xo, int yo, int index) +{ + uchar *p; + uint p0, p1; + int x, y; + + p = KADDR(scr->aperture); + p += scr->storage + index*1024; + + for(y = yo; y < 16; y++){ + p0 = scr->set[2*y]; + p1 = scr->set[2*y+1]; + if(xo){ + p0 = (p0<<xo)|(p1>>(8-xo)); + p1 <<= xo; + } + *p++ = p0; + *p++ = p1; + + for(x = 16; x < 64; x += 8) + *p++ = 0x00; + + p0 = scr->clr[2*y]|scr->set[2*y]; + p1 = scr->clr[2*y+1]|scr->set[2*y+1]; + if(xo){ + p0 = (p0<<xo)|(p1>>(8-xo)); + p1 <<= xo; + } + *p++ = p0; + *p++ = p1; + + for(x = 16; x < 64; x += 8) + *p++ = 0x00; + } + while(y < 64+yo){ + for(x = 0; x < 64; x += 8){ + *p++ = 0x00; + *p++ = 0x00; + } + y++; + } +} + +static void +neomagiccurload(VGAscr* scr, Cursor* curs) +{ + CursorNM *cursornm; + + if(scr->io == 0) + return; + cursornm = KADDR(scr->io); + + cursornm->enable = 0; + memmove(&scr->Cursor, curs, sizeof(Cursor)); + neomagicinitcursor(scr, 0, 0, 0); + cursornm->enable = 1; +} + +static int +neomagiccurmove(VGAscr* scr, Point p) +{ + CursorNM *cursornm; + int addr, index, x, xo, y, yo; + + if(scr->io == 0) + return 1; + cursornm = KADDR(scr->io); + + index = 0; + if((x = p.x+scr->offset.x) < 0){ + xo = -x; + x = 0; + } + else + xo = 0; + if((y = p.y+scr->offset.y) < 0){ + yo = -y; + y = 0; + } + else + yo = 0; + + if(xo || yo){ + index = 1; + neomagicinitcursor(scr, xo, yo, index); + } + addr = ((scr->storage+(1024*index))>>10) & 0xFFF; + addr = ((addr & 0x00F)<<8)|((addr>>4) & 0xFF); + if(cursornm->addr != addr) + cursornm->addr = addr; + + cursornm->x = x; + cursornm->y = y; + + return 0; +} + +static void +neomagiccurenable(VGAscr* scr) +{ + CursorNM *cursornm; + + neomagicenable(scr); + if(scr->io == 0) + return; + cursornm = KADDR(scr->io); + cursornm->enable = 0; + + /* + * Cursor colours. + */ + cursornm->colour1 = (Pblack<<16)|(Pblack<<8)|Pblack; + cursornm->colour2 = (Pwhite<<16)|(Pwhite<<8)|Pwhite; + + /* + * Load, locate and enable the 64x64 cursor. + */ + neomagiccurload(scr, &arrow); + neomagiccurmove(scr, ZP); + cursornm->enable = 1; +} + +static int neomagicbltflags; + +/* registers */ +enum { + BltStat = 0, + BltCntl = 1, + XPColor = 2, + FGColor = 3, + BGColor = 4, + Pitch = 5, + ClipLT = 6, + ClipRB = 7, + SrcBitOff = 8, + SrcStartOff = 9, + + DstStartOff = 11, + XYExt = 12, + + PageCntl = 20, + PageBase, + PostBase, + PostPtr, + DataPtr, +}; + +/* flags */ +enum { + NEO_BS0_BLT_BUSY = 0x00000001, + NEO_BS0_FIFO_AVAIL = 0x00000002, + NEO_BS0_FIFO_PEND = 0x00000004, + + NEO_BC0_DST_Y_DEC = 0x00000001, + NEO_BC0_X_DEC = 0x00000002, + NEO_BC0_SRC_TRANS = 0x00000004, + NEO_BC0_SRC_IS_FG = 0x00000008, + NEO_BC0_SRC_Y_DEC = 0x00000010, + NEO_BC0_FILL_PAT = 0x00000020, + NEO_BC0_SRC_MONO = 0x00000040, + NEO_BC0_SYS_TO_VID = 0x00000080, + + NEO_BC1_DEPTH8 = 0x00000100, + NEO_BC1_DEPTH16 = 0x00000200, + NEO_BC1_DEPTH24 = 0x00000300, + NEO_BC1_X_320 = 0x00000400, + NEO_BC1_X_640 = 0x00000800, + NEO_BC1_X_800 = 0x00000c00, + NEO_BC1_X_1024 = 0x00001000, + NEO_BC1_X_1152 = 0x00001400, + NEO_BC1_X_1280 = 0x00001800, + NEO_BC1_X_1600 = 0x00001c00, + NEO_BC1_DST_TRANS = 0x00002000, + NEO_BC1_MSTR_BLT = 0x00004000, + NEO_BC1_FILTER_Z = 0x00008000, + + NEO_BC2_WR_TR_DST = 0x00800000, + + NEO_BC3_SRC_XY_ADDR = 0x01000000, + NEO_BC3_DST_XY_ADDR = 0x02000000, + NEO_BC3_CLIP_ON = 0x04000000, + NEO_BC3_FIFO_EN = 0x08000000, + NEO_BC3_BLT_ON_ADDR = 0x10000000, + NEO_BC3_SKIP_MAPPING = 0x80000000, + + NEO_MODE1_DEPTH8 = 0x0100, + NEO_MODE1_DEPTH16 = 0x0200, + NEO_MODE1_DEPTH24 = 0x0300, + NEO_MODE1_X_320 = 0x0400, + NEO_MODE1_X_640 = 0x0800, + NEO_MODE1_X_800 = 0x0c00, + NEO_MODE1_X_1024 = 0x1000, + NEO_MODE1_X_1152 = 0x1400, + NEO_MODE1_X_1280 = 0x1800, + NEO_MODE1_X_1600 = 0x1c00, + NEO_MODE1_BLT_ON_ADDR = 0x2000, +}; + +/* Raster Operations */ +enum { + GXclear = 0x000000, /* 0x0000 */ + GXand = 0x080000, /* 0x1000 */ + GXandReverse = 0x040000, /* 0x0100 */ + GXcopy = 0x0c0000, /* 0x1100 */ + GXandInvert = 0x020000, /* 0x0010 */ + GXnoop = 0x0a0000, /* 0x1010 */ + GXxor = 0x060000, /* 0x0110 */ + GXor = 0x0e0000, /* 0x1110 */ + GXnor = 0x010000, /* 0x0001 */ + GXequiv = 0x090000, /* 0x1001 */ + GXinvert = 0x050000, /* 0x0101 */ + GXorReverse = 0x0d0000, /* 0x1101 */ + GXcopyInvert = 0x030000, /* 0x0011 */ + GXorInverted = 0x0b0000, /* 0x1011 */ + GXnand = 0x070000, /* 0x0111 */ + GXset = 0x0f0000, /* 0x1111 */ +}; + +static void +waitforidle(VGAscr *scr) +{ + ulong *mmio; + long x; + + mmio = scr->mmio; + x = 0; + while((mmio[BltStat] & NEO_BS0_BLT_BUSY) && x++ < 1000000) + ; + //if(x >= 1000000) + // iprint("idle stat %lud scrmmio %.8lux scr %p pc %luX\n", mmio[BltStat], scr->mmio, scr, getcallerpc(&scr)); +} + +static void +waitforfifo(VGAscr *scr, int entries) +{ + ulong *mmio; + long x; + + mmio = scr->mmio; + x = 0; + while(((mmio[BltStat]>>8) < entries) && x++ < 1000000) + ; + //if(x >= 1000000) + // iprint("fifo stat %d scrmmio %.8lux scr %p pc %luX\n", mmio[BltStat]>>8, scr->mmio, scr, getcallerpc(&scr)); + /* DirectFB says the above doesn't work. if so... */ + /* waitforidle(scr); */ +} + +static int +neomagichwfill(VGAscr *scr, Rectangle r, ulong sval) +{ + ulong *mmio; + + mmio = scr->mmio; + + waitforfifo(scr, 1); + mmio[FGColor] = sval; + waitforfifo(scr, 3); + mmio[BltCntl] = neomagicbltflags + | NEO_BC3_FIFO_EN + | NEO_BC0_SRC_IS_FG + | NEO_BC3_SKIP_MAPPING + | GXcopy; + mmio[DstStartOff] = scr->aperture + + r.min.y*scr->gscreen->width*BY2WD + + r.min.x*scr->gscreen->depth/BI2BY; + mmio[XYExt] = (Dy(r) << 16) | (Dx(r) & 0xffff); + waitforidle(scr); + return 1; +} + +static int +neomagichwscroll(VGAscr *scr, Rectangle r, Rectangle sr) +{ + ulong *mmio; + int pitch, pixel; + + mmio = scr->mmio; + + pitch = scr->gscreen->width*BY2WD; + pixel = scr->gscreen->depth/BI2BY; + + waitforfifo(scr, 4); + if (r.min.y < sr.min.y || (r.min.y == sr.min.y && r.min.x < sr.min.x)) { + /* start from upper-left */ + mmio[BltCntl] = neomagicbltflags + | NEO_BC3_FIFO_EN + | NEO_BC3_SKIP_MAPPING + | GXcopy; + mmio[SrcStartOff] = scr->aperture + + sr.min.y*pitch + sr.min.x*pixel; + mmio[DstStartOff] = scr->aperture + + r.min.y*pitch + r.min.x*pixel; + } else { + /* start from lower-right */ + mmio[BltCntl] = neomagicbltflags + | NEO_BC0_X_DEC + | NEO_BC0_DST_Y_DEC + | NEO_BC0_SRC_Y_DEC + | NEO_BC3_FIFO_EN + | NEO_BC3_SKIP_MAPPING + | GXcopy; + mmio[SrcStartOff] = scr->aperture + + (sr.max.y-1)*pitch + (sr.max.x-1)*pixel; + mmio[DstStartOff] = scr->aperture + + (r.max.y-1)*pitch + (r.max.x-1)*pixel; + } + mmio[XYExt] = (Dy(r) << 16) | (Dx(r) & 0xffff); + waitforidle(scr); + return 1; +} + +static void +neomagicdrawinit(VGAscr *scr) +{ + ulong *mmio; + uint bltmode, pitch; + + mmio = scr->mmio; + + pitch = scr->gscreen->width*BY2WD; + + neomagicbltflags = bltmode = 0; + + switch(scr->gscreen->depth) { + case 8: + bltmode |= NEO_MODE1_DEPTH8; + neomagicbltflags |= NEO_BC1_DEPTH8; + break; + case 16: + bltmode |= NEO_MODE1_DEPTH16; + neomagicbltflags |= NEO_BC1_DEPTH16; + break; + case 24: /* I can't get it to work, and XFree86 doesn't either. */ + default: /* give up */ + return; + } + + switch(Dx(scr->gscreen->r)) { + case 320: + bltmode |= NEO_MODE1_X_320; + neomagicbltflags |= NEO_BC1_X_320; + break; + case 640: + bltmode |= NEO_MODE1_X_640; + neomagicbltflags |= NEO_BC1_X_640; + break; + case 800: + bltmode |= NEO_MODE1_X_800; + neomagicbltflags |= NEO_BC1_X_800; + break; + case 1024: + bltmode |= NEO_MODE1_X_1024; + neomagicbltflags |= NEO_BC1_X_1024; + break; + case 1152: + bltmode |= NEO_MODE1_X_1152; + neomagicbltflags |= NEO_BC1_X_1152; + break; + case 1280: + bltmode |= NEO_MODE1_X_1280; + neomagicbltflags |= NEO_BC1_X_1280; + break; + case 1600: + bltmode |= NEO_MODE1_X_1600; + neomagicbltflags |= NEO_BC1_X_1600; + break; + default: + /* don't worry about it */ + break; + } + + waitforidle(scr); + mmio[BltStat] = bltmode << 16; + mmio[Pitch] = (pitch << 16) | (pitch & 0xffff); + + scr->fill = neomagichwfill; + scr->scroll = neomagichwscroll; +} + +VGAdev vganeomagicdev = { + "neomagic", + + neomagicenable, + nil, + nil, + neomagiclinear, + neomagicdrawinit, +}; + +VGAcur vganeomagiccur = { + "neomagichwgc", + + neomagiccurenable, + neomagiccurdisable, + neomagiccurload, + neomagiccurmove, +}; + |
