123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- #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 {
- PCIS3 = 0x5333, /* PCI VID */
- SAVAGE3D = 0x8A20, /* PCI DID */
- SAVAGE3DMV = 0x8A21,
- SAVAGE4 = 0x8A22,
- PROSAVAGEP = 0x8A25,
- PROSAVAGEK = 0x8A26,
- PROSAVAGE8 = 0x8D04,
- SAVAGEMXMV = 0x8C10,
- SAVAGEMX = 0x8C11,
- SAVAGEIXMV = 0x8C12,
- SAVAGEIX = 0x8C13,
- SUPERSAVAGEIXC16 = 0x8C2E,
- SAVAGE2000 = 0x9102,
- VIRGE = 0x5631,
- VIRGEGX2 = 0x8A10,
- VIRGEDXGX = 0x8A01,
- VIRGEVX = 0x883D,
- VIRGEMX = 0x8C01,
- VIRGEMXP = 0x8C03,
- VIRTUALPC2004 = 0x8810,
- AURORA64VPLUS = 0x8812,
- };
- static int
- s3pageset(VGAscr* scr, int page)
- {
- uchar crt35, crt51;
- int opage;
- crt35 = vgaxi(Crtx, 0x35);
- if(scr->gscreen->depth >= 8){
- /*
- * The S3 registers need to be unlocked for this.
- * Let's hope they are already:
- * vgaxo(Crtx, 0x38, 0x48);
- * vgaxo(Crtx, 0x39, 0xA0);
- *
- * The page is 6 bits, the lower 4 bits in Crt35<3:0>,
- * the upper 2 in Crt51<3:2>.
- */
- vgaxo(Crtx, 0x35, page & 0x0F);
- crt51 = vgaxi(Crtx, 0x51);
- vgaxo(Crtx, 0x51, (crt51 & ~0x0C)|((page & 0x30)>>2));
- opage = ((crt51 & 0x0C)<<2)|(crt35 & 0x0F);
- }
- else{
- vgaxo(Crtx, 0x35, (page<<2) & 0x0C);
- opage = (crt35>>2) & 0x03;
- }
- return opage;
- }
- static void
- s3page(VGAscr* scr, int page)
- {
- int id;
- id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
- switch(id){
- case VIRGEGX2:
- break;
- default:
- lock(&scr->devlock);
- s3pageset(scr, page);
- unlock(&scr->devlock);
- break;
- }
- }
- static void
- s3linear(VGAscr* scr, int, int)
- {
- int id, j;
- ulong mmiobase, mmiosize;
- Pcidev *p;
-
- vgalinearpciid(scr, PCIS3, 0);
- p = scr->pci;
- if(scr->paddr == 0 || p == nil)
- return;
-
- addvgaseg("s3screen", scr->paddr, scr->apsize);
-
- id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
- switch(id){ /* find mmio */
- case SAVAGE4:
- case PROSAVAGEP:
- case PROSAVAGEK:
- case PROSAVAGE8:
- case SUPERSAVAGEIXC16:
- /*
- * We could assume that the MMIO registers
- * will be in the screen segment and just use
- * that, but PCI software is allowed to move them
- * if it feels like it, so we look for an aperture of
- * the right size; only the first 512k actually means
- * anything. The S3 engineers overestimated how
- * much space they would need in the first design.
- */
- for(j=0; j<nelem(p->mem); j++){
- if((p->mem[j].bar&~0x0F) != scr->paddr)
- if(p->mem[j].size==512*1024 || p->mem[j].size==16*1024*1024){
- mmiobase = p->mem[j].bar & ~0x0F;
- mmiosize = 512*1024;
- scr->mmio = vmap(mmiobase, mmiosize);
- if(scr->mmio == nil)
- return;
- addvgaseg("savagemmio", mmiobase, mmiosize);
- break;
- }
- }
- }
- }
- static void
- s3vsyncactive(void)
- {
- /*
- * Hardware cursor information is fetched from display memory
- * during the horizontal blank active time. The 80x chips may hang
- * if the cursor is turned on or off during this period.
- */
- while((vgai(Status1) & 0x08) == 0)
- ;
- }
- static void
- s3disable(VGAscr*)
- {
- uchar crt45;
- /*
- * Turn cursor off.
- */
- crt45 = vgaxi(Crtx, 0x45) & 0xFE;
- s3vsyncactive();
- vgaxo(Crtx, 0x45, crt45);
- }
- static void
- s3load(VGAscr* scr, Cursor* curs)
- {
- uchar *p;
- int id, dolock, opage, x, y;
- /*
- * Disable the cursor and
- * set the pointer to the two planes.
- */
- s3disable(scr);
- opage = 0;
- p = scr->vaddr;
- id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
- switch(id){
- case VIRTUALPC2004:
- case VIRGE:
- case VIRGEDXGX:
- case VIRGEGX2:
- case VIRGEVX:
- case SAVAGEMXMV:
- case SAVAGEIXMV:
- case SAVAGE4:
- case PROSAVAGEP:
- case PROSAVAGEK:
- case PROSAVAGE8:
- case SUPERSAVAGEIXC16:
- dolock = 0;
- p += scr->storage;
- break;
- default:
- dolock = 1;
- lock(&scr->devlock);
- opage = s3pageset(scr, scr->storage>>16);
- p += (scr->storage & 0xFFFF);
- break;
- }
- /*
- * The cursor is set in Microsoft Windows format (the ViRGE/GX2 doesn't
- * support the X11 format) which gives the following truth table:
- * and xor colour
- * 0 0 background colour
- * 0 1 foreground colour
- * 1 0 current screen pixel
- * 1 1 NOT current screen pixel
- * Put the cursor into the top-left of the 64x64 array.
- *
- * The cursor pattern in memory is interleaved words of
- * AND and XOR patterns.
- */
- for(y = 0; y < 64; y++){
- for(x = 0; x < 64/8; x += 2){
- if(x < 16/8 && y < 16){
- *p++ = ~(curs->clr[2*y + x]|curs->set[2*y + x]);
- *p++ = ~(curs->clr[2*y + x+1]|curs->set[2*y + x+1]);
- *p++ = curs->set[2*y + x];
- *p++ = curs->set[2*y + x+1];
- }
- else {
- *p++ = 0xFF;
- *p++ = 0xFF;
- *p++ = 0x00;
- *p++ = 0x00;
- }
- }
- }
- if(dolock){
- s3pageset(scr, opage);
- unlock(&scr->devlock);
- }
- /*
- * Save the cursor hotpoint and enable the cursor.
- */
- scr->offset = curs->offset;
- s3vsyncactive();
- vgaxo(Crtx, 0x45, 0x01);
- }
- static int
- s3move(VGAscr* scr, Point p)
- {
- int x, xo, y, yo;
- /*
- * Mustn't position the cursor offscreen even partially,
- * or it disappears. Therefore, if x or y is -ve, adjust the
- * cursor offset instead.
- * There seems to be a bug in that if the offset is 1, the
- * cursor doesn't disappear off the left edge properly, so
- * round it up to be even.
- */
- if((x = p.x+scr->offset.x) < 0){
- xo = -x;
- xo = ((xo+1)/2)*2;
- x = 0;
- }
- else
- xo = 0;
- if((y = p.y+scr->offset.y) < 0){
- yo = -y;
- y = 0;
- }
- else
- yo = 0;
- vgaxo(Crtx, 0x46, (x>>8) & 0x07);
- vgaxo(Crtx, 0x47, x & 0xFF);
- vgaxo(Crtx, 0x49, y & 0xFF);
- vgaxo(Crtx, 0x4E, xo);
- vgaxo(Crtx, 0x4F, yo);
- vgaxo(Crtx, 0x48, (y>>8) & 0x07);
- return 0;
- }
- static void
- s3enable(VGAscr* scr)
- {
- int i;
- ulong storage;
- s3disable(scr);
- /*
- * Cursor colours. Set both the CR0[EF] and the colour
- * stack in case we are using a 16-bit RAMDAC.
- */
- vgaxo(Crtx, 0x0E, Pwhite);
- vgaxo(Crtx, 0x0F, Pblack);
- vgaxi(Crtx, 0x45);
- for(i = 0; i < 3; i++)
- vgaxo(Crtx, 0x4A, Pblack);
- vgaxi(Crtx, 0x45);
- for(i = 0; i < 3; i++)
- vgaxo(Crtx, 0x4B, Pwhite);
- /*
- * Find a place for the cursor data in display memory.
- * Must be on a 1024-byte boundary.
- */
- storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+1023)/1024;
- vgaxo(Crtx, 0x4C, storage>>8);
- vgaxo(Crtx, 0x4D, storage & 0xFF);
- storage *= 1024;
- scr->storage = storage;
- /*
- * Load, locate and enable the cursor
- * in Microsoft Windows format.
- */
- s3load(scr, &arrow);
- s3move(scr, ZP);
- vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55) & ~0x10);
- s3vsyncactive();
- vgaxo(Crtx, 0x45, 0x01);
- }
- /*
- * The manual gives byte offsets, but we want ulong offsets, hence /4.
- */
- enum {
- SrcBase = 0xA4D4/4,
- DstBase = 0xA4D8/4,
- Stride = 0xA4E4/4,
- FgrdData = 0xA4F4/4,
- WidthHeight = 0xA504/4,
- SrcXY = 0xA508/4,
- DestXY = 0xA50C/4,
- Command = 0xA500/4,
- SubStat = 0x8504/4,
- FifoStat = 0x850C/4,
- };
- /*
- * Wait for writes to VGA memory via linear aperture to flush.
- */
- enum {Maxloop = 1<<24};
- struct {
- ulong linear;
- ulong fifo;
- ulong idle;
- ulong lineartimeout;
- ulong fifotimeout;
- ulong idletimeout;
- } waitcount;
- static void
- waitforlinearfifo(VGAscr *scr)
- {
- ulong *mmio;
- long x;
- static ulong nwaitforlinearfifo;
- ulong mask, val;
- switch(scr->id){
- default:
- panic("unknown scr->id in s3 waitforlinearfifo");
- case 0x8A01: /* ViRGE/[DG]X. XFree86 says no waiting necessary */
- return;
- case 0x5631: /* ViRGE */
- case 0x883D: /* ViRGE/VX */
- mask = 0x0F<<6;
- val = 0x08<<6;
- break;
- case 0x8A10: /* ViRGE/GX2 */
- mask = 0x1F<<6;
- val = 0x10<<6;
- break;
- }
- mmio = scr->mmio;
- x = 0;
- while((mmio[FifoStat]&mask) != val && x++ < Maxloop)
- waitcount.linear++;
- if(x >= Maxloop)
- waitcount.lineartimeout++;
- }
- static void
- waitforfifo(VGAscr *scr, int entries)
- {
- ulong *mmio;
- long x;
- static ulong nwaitforfifo;
- mmio = scr->mmio;
- x = 0;
- while((mmio[SubStat]&0x1F00) < ((entries+2)<<8) && x++ < Maxloop)
- waitcount.fifo++;
- if(x >= Maxloop)
- waitcount.fifotimeout++;
- }
- static void
- waitforidle(VGAscr *scr)
- {
- ulong *mmio;
- long x;
- mmio = scr->mmio;
- x = 0;
- while((mmio[SubStat]&0x3F00) != 0x3000 && x++ < Maxloop)
- waitcount.idle++;
- if(x >= Maxloop)
- waitcount.idletimeout++;
- }
- static int
- hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
- {
- enum { Bitbltop = 0xCC }; /* copy source */
- ulong *mmio;
- ulong cmd, stride;
- Point dp, sp;
- int did, d;
- d = scr->gscreen->depth;
- did = (d-8)/8;
- cmd = 0x00000020|(Bitbltop<<17)|(did<<2);
- stride = Dx(scr->gscreen->r)*d/8;
- if(r.min.x <= sr.min.x){
- cmd |= 1<<25;
- dp.x = r.min.x;
- sp.x = sr.min.x;
- }else{
- dp.x = r.max.x-1;
- sp.x = sr.max.x-1;
- }
- if(r.min.y <= sr.min.y){
- cmd |= 1<<26;
- dp.y = r.min.y;
- sp.y = sr.min.y;
- }else{
- dp.y = r.max.y-1;
- sp.y = sr.max.y-1;
- }
- mmio = scr->mmio;
- waitforlinearfifo(scr);
- waitforfifo(scr, 7);
- mmio[SrcBase] = scr->paddr;
- mmio[DstBase] = scr->paddr;
- mmio[Stride] = (stride<<16)|stride;
- mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
- mmio[SrcXY] = (sp.x<<16)|sp.y;
- mmio[DestXY] = (dp.x<<16)|dp.y;
- mmio[Command] = cmd;
- waitforidle(scr);
- return 1;
- }
- static int
- hwfill(VGAscr *scr, Rectangle r, ulong sval)
- {
- enum { Bitbltop = 0xCC }; /* copy source */
- ulong *mmio;
- ulong cmd, stride;
- int did, d;
- d = scr->gscreen->depth;
- did = (d-8)/8;
- cmd = 0x16000120|(Bitbltop<<17)|(did<<2);
- stride = Dx(scr->gscreen->r)*d/8;
- mmio = scr->mmio;
- waitforlinearfifo(scr);
- waitforfifo(scr, 8);
- mmio[SrcBase] = scr->paddr;
- mmio[DstBase] = scr->paddr;
- mmio[DstBase] = scr->paddr;
- mmio[Stride] = (stride<<16)|stride;
- mmio[FgrdData] = sval;
- mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
- mmio[DestXY] = (r.min.x<<16)|r.min.y;
- mmio[Command] = cmd;
- waitforidle(scr);
- return 1;
- }
- enum {
- CursorSyncCtl = 0x0D, /* in Seqx */
- VsyncHi = 0x80,
- VsyncLo = 0x40,
- HsyncHi = 0x20,
- HsyncLo = 0x10,
- };
- static void
- s3blank(VGAscr*, int blank)
- {
- uchar x;
- x = vgaxi(Seqx, CursorSyncCtl);
- x &= ~0xF0;
- if(blank)
- x |= VsyncLo | HsyncLo;
- vgaxo(Seqx, CursorSyncCtl, x);
- }
- static void
- s3drawinit(VGAscr *scr)
- {
- extern void savageinit(VGAscr*); /* vgasavage.c */
- ulong id;
- id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
- scr->id = id;
- /*
- * It's highly likely that other ViRGEs will work without
- * change to the driver, with the exception of the size of
- * the linear aperture memory write FIFO. Since we don't
- * know that size, I'm not turning them on. See waitforlinearfifo
- * above.
- */
- scr->blank = s3blank;
- /* hwblank = 1; not known to work well */
- switch(id){
- case VIRGE:
- case VIRGEVX:
- case VIRGEGX2:
- scr->mmio = (ulong*)((char*)scr->vaddr+0x1000000);
- scr->fill = hwfill;
- scr->scroll = hwscroll;
- break;
- case SAVAGEMXMV:
- case SAVAGEIXMV:
- scr->mmio = (ulong*)((char*)scr->vaddr+0x1000000);
- savageinit(scr);
- break;
- case SUPERSAVAGEIXC16:
- case SAVAGE4:
- case PROSAVAGEP:
- case PROSAVAGE8:
- case PROSAVAGEK:
- /* scr->mmio is set by s3linear */
- savageinit(scr);
- break;
- }
- }
- VGAdev vgas3dev = {
- "s3",
- 0,
- 0,
- s3page,
- s3linear,
- s3drawinit,
- };
- VGAcur vgas3cur = {
- "s3hwgc",
- s3enable,
- s3disable,
- s3load,
- s3move,
- };
|