123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 |
- #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,
- AURORA64VPLUS = 0x8812,
- };
- /*
- * Savage4 et al. acceleration.
- *
- * This is based only on the Savage4 documentation.
- * It is expected to work on other Savage cards as well,
- * but has not been tried.
- *
- * There are five ways to access the 2D graphics engine registers:
- * - Old MMIO non-packed format
- * - Old MMIO packed format
- * - New MMIO non-packed format
- * - New MMIO packed format
- * - Burst Command Interface (BCI)
- *
- * Of these, the manual hints that the first three are deprecated,
- * and it does not document any of those three well enough to use.
- *
- * I have tried for many hours with no success to understand the BCI
- * interface well enough to use it. It is not well documented, and the
- * XFree86 driver seems to completely contradict what little documentation
- * there is.
- *
- * This leaves the packed new MMIO.
- * The manual contradicts itself here, claming that the registers
- * start at 0x2008100 as well as at 0x0008100 from the base of the
- * mmio segment. Since the segment is only 512k, we assume that
- * the latter is the correct offset.
- *
- * According to the manual, only 16-bit reads of the 2D registers
- * are supported: 32-bit reads will return garbage in the upper word.
- * 32-bit writes must be enabled explicitly.
- *
- * 32-bit reads of the status registers seem just fine.
- */
- /* 2D graphics engine registers for Savage4; others appear to be mostly the same */
- enum {
- SubsystemStatus = 0x8504, /* Subsystem Status: read only */
- /* read only: whether we get interrupts on various events */
- VsyncInt = 1<<0, /* vertical sync */
- GeBusyInt = 1<<1, /* 2D graphics engine busy */
- BfifoFullInt = 1<<2, /* BIU FIFO full */
- BfifoEmptyInt = 1<<3, /* BIU FIFO empty */
- CfifoFullInt = 1<<4, /* command FIFO full */
- CfifoEmptyInt = 1<<5, /* command FIFO empty */
- BciInt = 1<<6, /* BCI */
- LpbInt = 1<<7, /* LPB */
- CbHiInt = 1<<16, /* COB upper threshold */
- CbLoInt = 1<<17, /* COB lower threshold */
- SubsystemCtl = 0x8504, /* Subsystem Control: write only */
- /* clear interrupts for various events */
- VsyncClr = 1<<0,
- GeBusyClr = 1<<1,
- BfifoFullClr = 1<<2,
- BfifoEmptyClr = 1<<3,
- CfifoFullClr = 1<<4,
- CfifoEmptyClr = 1<<5,
- BciClr = 1<<6,
- LpbClr = 1<<7,
- CbHiClr = 1<<16,
- CbLoClr = 1<<17,
- /* enable interrupts for various events */
- VsyncEna = 1<<8,
- Busy2DEna = 1<<9,
- BfifoFullEna = 1<<10,
- BfifoEmptyEna = 1<<11,
- CfifoFullEna = 1<<12,
- CfifoEmptyEna = 1<<13,
- SubsysBciEna = 1<<14,
- CbHiEna = 1<<24,
- CbLoEna = 1<<25,
- /* 2D graphics engine software reset */
- GeSoftReset = 1<<15,
- FifoStatus = 0x8508, /* FIFO status: read only */
- CwbEmpty = 1<<0, /* command write buffer empty */
- CrbEmpty = 1<<1, /* command read buffer empty */
- CobEmpty = 1<<2, /* command overflow buffer empty */
- CfifoEmpty = 1<<3, /* command FIFO empty */
- CwbFull = 1<<8, /* command write buffer full */
- CrbFull = 1<<9, /* command read buffer full */
- CobFull = 1<<10, /* command overflow buffer full */
- CfifoFull = 1<<11, /* command FIFO full */
- AdvFunCtl = 0x850C, /* Advanced Function Control: read/write */
- GeEna = 1<<0, /* enable 2D/3D engine */
- /*
- * according to the manual, BigPixel should be
- * set when bpp >= 8 (bpp != 4), and then CR50_5-4 are
- * used to figure out bpp example. however, it does bad things
- * to the screen in 8bpp mode.
- */
- BigPixel = 1<<2, /* 8 or more bpp enhanced mode */
- LaEna = 1<<3, /* linear addressing ena: or'ed with CR58_4 */
- Mclk_2 = 0<<8, /* 2D engine clock divide: MCLK/2 */
- Mclk_4 = 1<<8, /* " MCLK/4 */
- Mclk = 2<<8, /* " MCLK */
- /* Mclk = 3<<8, /* " MCLK */
- Ic33mhz = 1<<16, /* Internal clock 33 MHz (instead of 66) */
- WakeupReg = 0x8510, /* Wakeup: read/write */
- WakeupBit = 1<<0, /* wake up: or'ed with 3C3_0 */
- SourceY = 0x8100, /* UL corner of bitblt source */
- SourceX = 0x8102, /* " */
- RectY = 0x8100, /* UL corner of rectangle fill */
- RectX = 0x8102, /* " */
- DestY = 0x8108, /* UL corner of bitblt dest */
- DestX = 0x810A, /* " */
- Height = 0x8148, /* bitblt, image xfer rectangle height */
- Width = 0x814A, /* bitblt, image xfer rectangle width */
- StartY = 0x8100, /* Line draw: first point*/
- StartX = 0x8102, /* " */
- /*
- * For line draws, the following must be programmed:
- * axial step constant = 2*min(|dx|,|dy|)
- * diagonal step constant = 2*[min(|dx|,|dy|) - max(|dx|,|dy|)]
- * error term = 2*min(|dx|,|dy|) - max(|dx|,|dy| - 1
- * [sic] when start X < end X
- * error term = 2*min(|dx|,|dy|) - max(|dx|,|dy|
- * [sic] when start X >= end X
- */
- AxialStep = 0x8108,
- DiagonalStep = 0x810A,
- LineError = 0x8110,
- MinorLength = 0x8148, /* pixel count along minor axis */
- MajorLength = 0x814A, /* pixel count along major axis */
- DrawCmd = 0x8118, /* Drawing Command: write only */
- CmdMagic = 0<<1,
- AcrossPlane = 1<<1, /* across the plane mode */
- LastPixelOff = 1<<2, /* last pixel of line or vector draw not drawn */
- Radial = 1<<3, /* enable radial direction (else axial) */
- DoDraw = 1<<4, /* draw pixels (else only move current pos) */
- DrawRight = 1<<5, /* axial drawing direction: left to right */
- /* DrawLeft = 0<<5, */
- MajorY = 1<<6,
- /* MajorX = 0<<6, */
- DrawDown = 1<<7,
- /* DrawUp = 0<<7, */
- Degree0 = 0<<5, /* drawing direction when Radial */
- Degree45 = 1<<5,
- /* ... */
- Degree315 = 7<<5,
- UseCPUData = 1<<8,
- /* image write bus transfer width */
- Bus8 = 0<<9,
- Bus16 = 1<<9,
- /*
- * in Bus32 mode, doubleword bits beyond the image rect width are
- * discarded. each line starts on a new doubleword.
- * Bus32AP is intended for across-the-plane mode and
- * rounds to byte boundaries instead.
- */
- Bus32 = 2<<9,
- Bus32AP = 3<<9,
- CmdNop = 0<<13, /* nop */
- CmdLine = 1<<13, /* draw line */
- CmdFill = 2<<13, /* fill rectangle */
- CmdBitblt = 6<<13, /* bitblt */
- CmdPatblt = 7<<13, /* 8x8 pattern blt */
- SrcGBD = 0<<16,
- SrcPBD = 1<<16,
- SrcSBD = 2<<16,
- DstGBD = 0<<18,
- DstPBD = 1<<18,
- DstSBD = 2<<18,
- /* color sources, controls */
- BgColor = 0x8120, /* Background Color: read/write */
- FgColor = 0x8124, /* Foreground Color: read/write */
- BitplaneWmask = 0x8128, /* Bitplane Write Mask: read/write */
- BitplaneRmask = 0x812C, /* Bitplane Read Mask: read/write */
- CmpColor = 0x8130, /* Color Compare: read/write */
- BgMix = 0x8134,
- FgMix = 0x8136,
- MixNew = 7,
- SrcBg = 0<<5,
- SrcFg = 1<<5,
- SrcCPU = 2<<5,
- SrcDisp = 3<<5,
- /* clipping rectangle */
- TopScissors = 0x8138, /* Top Scissors: write only */
- LeftScissors = 0x813A, /* Left Scissors: write only */
- BottomScissors = 0x813C, /* Bottom Scissors: write only */
- RightScissors = 0x813E, /* Right Scissors: write only */
- /*
- * Registers with Magic were indirectly accessed in older modes.
- * It is not clear whether the Magic is necessary.
- * In the older modes, writes to these registers were pipelined,
- * so that you had to issue an engine command and wait for engine
- * idle before reading a write back. It is not clear if this is
- * still the case either.
- */
- PixCtl = 0x8140, /* Pixel Control: write only */
- PixMagic = 0xA<<12,
- PixMixFg = 0<<6, /* foreground mix register always */
- PixMixCPU = 2<<6, /* CPU data determines mix register */
- PixMixDisp = 3<<6, /* display data determines mix register */
- MfMisc2Ctl = 0x8142, /* Multifunction Control Misc. 2: write only */
- MfMisc2Magic = 0xD<<12,
- DstShift = 0, /* 3 bits: destination base address in MB */
- SrcShift = 4, /* 3 bits: source base address in MB */
- WaitFifoEmpty = 2<<8, /* wait for write FIFO empty between draws */
- MfMiscCtl = 0x8144, /* Multifunction Control Misc: write only */
- MfMiscMagic = 0xE<<12,
- UseHighBits = 1<<4, /* select upper 16 bits for 32-bit reg access */
- ClipInvert = 1<<5, /* only touch pixels outside clip rectangle */
- SkipSame = 0<<6, /* ignore pixels with color CmpColor */
- SkipDifferent = 1<<7, /* ignore pixels not color CmpColor */
- CmpEna = 1<<8, /* enable color compare */
- W32Ena = 1<<9, /* enable 32-bit register write */
- ClipDis = 1<<11, /* disable clipping */
- /*
- * The bitmap descriptor 1 registers contain the starting
- * address of the bitmap (in bytes).
- * The bitmap descriptor 2 registesr contain stride (in pixels)
- * in the lower 16 bits, depth (in bits) in the next 8 bits,
- * and whether block write is disabled.
- */
- GBD1 = 0x8168, /* Global Bitmap Descriptor 1: read/write */
- GBD2 = 0x816C, /* Global Bitmap Descriptor 2: read/write */
- /* GBD2-only bits */
- BDS64 = 1<<0, /* bitmap descriptor size 64 bits */
- GBDBciEna = 1<<3, /* BCI enable */
- /* generic BD2 bits */
- BlockWriteDis = 1<<28,
- StrideShift = 0,
- DepthShift = 16,
- PBD1 = 0x8170, /* Primary Bitmap Descriptor: read/write */
- PBD2 = 0x8174,
- SBD1 = 0x8178, /* Secondary Bitmap Descriptor: read/write */
- SBD2 = 0x817C,
- };
- /* mastered data transfer registers */
- /* configuration/status registers */
- enum {
- XStatus0 = 0x48C00, /* Status Word 0: read only */
- /* rev. A silicon differs from rev. B; use AltStatus0 */
- CBEMaskA = 0x1FFFF, /* filled command buffer entries */
- CBEShiftA = 0,
- BciIdleA = 1<<17, /* BCI idle */
- Ge3IdleA = 1<<18, /* 3D engine idle */
- Ge2IdleA = 1<<19, /* 2D engine idle */
- McpIdleA = 1<<20, /* motion compensation processor idle */
- MeIdleA = 1<<22, /* master engine idle */
- PfPendA = 1<<23, /* page flip pending */
- CBEMaskB = 0x1FFFFF,
- CBEShiftB = 0,
- BciIdleB = 1<<25,
- Ge3IdleB = 1<<26,
- Ge2IdleB = 1<<27,
- McpIdleB = 1<<28,
- MeIdleB = 1<<30,
- PfPendB = 1<<31,
- AltStatus0 = 0x48C60, /* Alternate Status Word 0: read only */
- CBEMask = 0x1FFFF,
- CBEShift = 0,
- /* the Savage4 manual says bits 17..23 for these, like Status0 */
- /* empirically, they are bits 21..26 */
- BciIdle = 1<<21,
- Ge3Idle = 1<<22,
- Ge2Idle = 1<<23,
- McpIdle = 1<<24,
- MeIdle = 1<<25,
- PfPend = 1<<26,
- XStatus1 = 0x48C04, /* Status Word 1: read only */
- /* contains event tag 1, event tag 0, both 16 bits */
- XStatus2 = 0x48C08, /* Status Word 2: read only */
- ScanMask = 0x3FF, /* current scan line */
- ScanShift = 0,
- VRTMask = 0x7F100, /* vert retrace count */
- VRTShift = 11,
- CbThresh = 0x48C10, /* Command Buffer Thresholds: read/write */
- CobOff = 0x48C14, /* Command Overflow Buffer: read/write */
- CobPtr = 0x48C18, /* Command Overflow Buffer Pointers: read/write */
- CobEna = 1<<2, /* command overflow buffer enable */
- CobBciEna = 1<<3, /* BCI function enable */
- CbeMask = 0xFFFF8000, /* no. of entries in command buffer */
- CbeShift = 15,
- AltStatus1 = 0x48C64, /* Alternate Status Word 1: read onnly */
- /* contains current texture surface tag, vertex buffer tag */
- };
- struct {
- ulong idletimeout;
- ulong tostatw[16];
- } savagestats;
- enum {
- Maxloop = 1<<20
- };
- static void
- savagewaitidle(VGAscr *scr)
- {
- long x;
- ulong *statw, mask, goal;
- switch(scr->id){
- case SAVAGE4:
- case PROSAVAGEP:
- case PROSAVAGEK:
- case PROSAVAGE8:
- /* wait for engine idle and FIFO empty */
- statw = (ulong*)((uchar*)scr->mmio+AltStatus0);
- mask = CBEMask | Ge2Idle;
- goal = Ge2Idle;
- break;
- /* case SAVAGEMXMV: ? */
- /* case SAVAGEMX: ? */
- /* case SAVAGEIX: ? */
- case SUPERSAVAGEIXC16:
- case SAVAGEIXMV:
- case SAVAGEMXMV:
- /* wait for engine idle and FIFO empty */
- statw = (ulong*)((uchar*)scr->mmio+XStatus0);
- mask = CBEMaskA | Ge2IdleA;
- goal = Ge2IdleA;
- break;
- default:
- /*
- * best we can do: can't print or we'll call ourselves.
- * savageinit is supposed to not let this happen.
- */
- return;
- }
- for(x=0; x<Maxloop; x++)
- if((*statw & mask) == goal)
- return;
- savagestats.tostatw[savagestats.idletimeout++&15] = *statw;
- savagestats.tostatw[savagestats.idletimeout++&15] = (ulong)statw;
- }
- static int
- savagefill(VGAscr *scr, Rectangle r, ulong sval)
- {
- uchar *mmio;
- mmio = (uchar*)scr->mmio;
- *(ulong*)(mmio+FgColor) = sval;
- *(ulong*)(mmio+BgColor) = sval;
- *(ulong*)(mmio+BgMix) = SrcFg|MixNew;
- *(ulong*)(mmio+FgMix) = SrcFg|MixNew;
- *(ushort*)(mmio+RectY) = r.min.y;
- *(ushort*)(mmio+RectX) = r.min.x;
- *(ushort*)(mmio+Width) = Dx(r)-1;
- *(ushort*)(mmio+Height) = Dy(r)-1;
- *(ulong*)(mmio+DrawCmd) = CmdMagic | DoDraw | CmdFill | DrawRight | DrawDown;
- savagewaitidle(scr);
- return 1;
- }
- static int
- savagescroll(VGAscr *scr, Rectangle r, Rectangle sr)
- {
- uchar *mmio;
- ulong cmd;
- Point dp, sp;
- cmd = CmdMagic | DoDraw | CmdBitblt | SrcPBD | DstGBD;
- if(r.min.x <= sr.min.x){
- cmd |= DrawRight;
- 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 |= DrawDown;
- dp.y = r.min.y;
- sp.y = sr.min.y;
- }else{
- dp.y = r.max.y-1;
- sp.y = sr.max.y-1;
- }
- mmio = (uchar*)scr->mmio;
- *(ushort*)(mmio+SourceX) = sp.x;
- *(ushort*)(mmio+SourceY) = sp.y;
- *(ushort*)(mmio+DestX) = dp.x;
- *(ushort*)(mmio+DestY) = dp.y;
- *(ushort*)(mmio+Width) = Dx(r)-1;
- *(ushort*)(mmio+Height) = Dy(r)-1;
- *(ulong*)(mmio+BgMix) = SrcDisp|MixNew;
- *(ulong*)(mmio+FgMix) = SrcDisp|MixNew;
- *(ulong*)(mmio+DrawCmd) = cmd;
- savagewaitidle(scr);
- return 1;
- }
- static void
- savageblank(VGAscr*, int blank)
- {
- uchar seqD;
- /*
- * Will handle DPMS to monitor
- */
- vgaxo(Seqx, 8, vgaxi(Seqx,8)|0x06);
- seqD = vgaxi(Seqx, 0xD);
- seqD &= 0x03;
- if(blank)
- seqD |= 0x50;
- vgaxo(Seqx, 0xD, seqD);
- /*
- * Will handle LCD
- */
- if(blank)
- vgaxo(Seqx, 0x31, vgaxi(Seqx, 0x31) & ~0x10);
- else
- vgaxo(Seqx, 0x31, vgaxi(Seqx, 0x31) | 0x10);
- }
- void
- savageinit(VGAscr *scr)
- {
- uchar *mmio;
- ulong bd;
- /* if you add chip IDs here be sure to update savagewaitidle */
- switch(scr->id){
- case SAVAGE4:
- case PROSAVAGEP:
- case PROSAVAGEK:
- case PROSAVAGE8:
- case SAVAGEIXMV:
- case SUPERSAVAGEIXC16:
- case SAVAGEMXMV:
- break;
- default:
- print("unknown savage %.4lux\n", scr->id);
- return;
- }
- mmio = (uchar*)scr->mmio;
- if(mmio == nil) {
- print("savageinit: no mmio\n");
- return;
- }
- /* 2D graphics engine software reset */
- *(ushort*)(mmio+SubsystemCtl) = GeSoftReset;
- delay(2);
- *(ushort*)(mmio+SubsystemCtl) = 0;
- savagewaitidle(scr);
- /* disable BCI as much as possible */
- *(ushort*)(mmio+CobPtr) &= ~CobBciEna;
- *(ushort*)(mmio+GBD2) &= ~GBDBciEna;
- savagewaitidle(scr);
- /* enable 32-bit writes, disable clipping */
- *(ushort*)(mmio+MfMiscCtl) = MfMiscMagic|W32Ena|ClipDis;
- savagewaitidle(scr);
- /* enable all read, write planes */
- *(ulong*)(mmio+BitplaneRmask) = ~0;
- *(ulong*)(mmio+BitplaneWmask) = ~0;
- savagewaitidle(scr);
- /* turn on linear access, 2D engine */
- *(ulong*)(mmio+AdvFunCtl) |= GeEna|LaEna;
- savagewaitidle(scr);
- /* set bitmap descriptors */
- bd = (scr->gscreen->depth<<DepthShift) |
- (Dx(scr->gscreen->r)<<StrideShift) | BlockWriteDis
- | BDS64;
- *(ulong*)(mmio+GBD1) = 0;
- *(ulong*)(mmio+GBD2) = bd;
- *(ulong*)(mmio+PBD1) = 0;
- *(ulong*)(mmio+PBD2) = bd;
- *(ulong*)(mmio+SBD1) = 0;
- *(ulong*)(mmio+SBD2) = bd;
- /*
- * For some reason, the GBD needs to get programmed twice,
- * once before the PBD, SBD, and once after.
- * This empirically makes it get set right.
- * I would like to better understand the ugliness
- * going on here.
- */
- *(ulong*)(mmio+GBD1) = 0;
- *(ulong*)(mmio+GBD2) = bd;
- *(ushort*)(mmio+GBD2+2) = bd>>16;
- savagewaitidle(scr);
- scr->fill = savagefill;
- scr->scroll = savagescroll;
- scr->blank = savageblank;
- hwblank = 0;
- }
|