159cc4ca5SDavid du Colombier #include "u.h"
259cc4ca5SDavid du Colombier #include "../port/lib.h"
359cc4ca5SDavid du Colombier #include "mem.h"
459cc4ca5SDavid du Colombier #include "dat.h"
559cc4ca5SDavid du Colombier #include "fns.h"
659cc4ca5SDavid du Colombier #include "io.h"
759cc4ca5SDavid du Colombier #include "../port/error.h"
859cc4ca5SDavid du Colombier
959cc4ca5SDavid du Colombier #define Image IMAGE
1059cc4ca5SDavid du Colombier #include <draw.h>
1159cc4ca5SDavid du Colombier #include <memdraw.h>
1259cc4ca5SDavid du Colombier #include <cursor.h>
1359cc4ca5SDavid du Colombier #include "screen.h"
1459cc4ca5SDavid du Colombier
1559cc4ca5SDavid du Colombier enum {
1659cc4ca5SDavid du Colombier PCIS3 = 0x5333, /* PCI VID */
1759cc4ca5SDavid du Colombier
1859cc4ca5SDavid du Colombier SAVAGE3D = 0x8A20, /* PCI DID */
1959cc4ca5SDavid du Colombier SAVAGE3DMV = 0x8A21,
2059cc4ca5SDavid du Colombier SAVAGE4 = 0x8A22,
210b459c2cSDavid du Colombier PROSAVAGEP = 0x8A25,
220b459c2cSDavid du Colombier PROSAVAGEK = 0x8A26,
23*19dc9ffeSDavid du Colombier PROSAVAGE8 = 0x8D04,
2459cc4ca5SDavid du Colombier SAVAGEMXMV = 0x8C10,
2559cc4ca5SDavid du Colombier SAVAGEMX = 0x8C11,
2659cc4ca5SDavid du Colombier SAVAGEIXMV = 0x8C12,
2759cc4ca5SDavid du Colombier SAVAGEIX = 0x8C13,
289a747e4fSDavid du Colombier SUPERSAVAGEIXC16 = 0x8C2E,
2959cc4ca5SDavid du Colombier SAVAGE2000 = 0x9102,
3059cc4ca5SDavid du Colombier
3159cc4ca5SDavid du Colombier VIRGE = 0x5631,
3259cc4ca5SDavid du Colombier VIRGEGX2 = 0x8A10,
3359cc4ca5SDavid du Colombier VIRGEDXGX = 0x8A01,
3459cc4ca5SDavid du Colombier VIRGEVX = 0x883D,
3559cc4ca5SDavid du Colombier VIRGEMX = 0x8C01,
3659cc4ca5SDavid du Colombier VIRGEMXP = 0x8C03,
3759cc4ca5SDavid du Colombier
3859cc4ca5SDavid du Colombier AURORA64VPLUS = 0x8812,
3959cc4ca5SDavid du Colombier };
4059cc4ca5SDavid du Colombier
4159cc4ca5SDavid du Colombier /*
4259cc4ca5SDavid du Colombier * Savage4 et al. acceleration.
4359cc4ca5SDavid du Colombier *
4459cc4ca5SDavid du Colombier * This is based only on the Savage4 documentation.
4559cc4ca5SDavid du Colombier * It is expected to work on other Savage cards as well,
4659cc4ca5SDavid du Colombier * but has not been tried.
4759cc4ca5SDavid du Colombier *
4859cc4ca5SDavid du Colombier * There are five ways to access the 2D graphics engine registers:
4959cc4ca5SDavid du Colombier * - Old MMIO non-packed format
5059cc4ca5SDavid du Colombier * - Old MMIO packed format
5159cc4ca5SDavid du Colombier * - New MMIO non-packed format
5259cc4ca5SDavid du Colombier * - New MMIO packed format
5359cc4ca5SDavid du Colombier * - Burst Command Interface (BCI)
5459cc4ca5SDavid du Colombier *
5559cc4ca5SDavid du Colombier * Of these, the manual hints that the first three are deprecated,
5659cc4ca5SDavid du Colombier * and it does not document any of those three well enough to use.
5759cc4ca5SDavid du Colombier *
5859cc4ca5SDavid du Colombier * I have tried for many hours with no success to understand the BCI
5959cc4ca5SDavid du Colombier * interface well enough to use it. It is not well documented, and the
6059cc4ca5SDavid du Colombier * XFree86 driver seems to completely contradict what little documentation
6159cc4ca5SDavid du Colombier * there is.
6259cc4ca5SDavid du Colombier *
6359cc4ca5SDavid du Colombier * This leaves the packed new MMIO.
6459cc4ca5SDavid du Colombier * The manual contradicts itself here, claming that the registers
6559cc4ca5SDavid du Colombier * start at 0x2008100 as well as at 0x0008100 from the base of the
6659cc4ca5SDavid du Colombier * mmio segment. Since the segment is only 512k, we assume that
6759cc4ca5SDavid du Colombier * the latter is the correct offset.
6859cc4ca5SDavid du Colombier *
6959cc4ca5SDavid du Colombier * According to the manual, only 16-bit reads of the 2D registers
7059cc4ca5SDavid du Colombier * are supported: 32-bit reads will return garbage in the upper word.
7159cc4ca5SDavid du Colombier * 32-bit writes must be enabled explicitly.
7259cc4ca5SDavid du Colombier *
7359cc4ca5SDavid du Colombier * 32-bit reads of the status registers seem just fine.
7459cc4ca5SDavid du Colombier */
7559cc4ca5SDavid du Colombier
7659cc4ca5SDavid du Colombier /* 2D graphics engine registers for Savage4; others appear to be mostly the same */
7759cc4ca5SDavid du Colombier enum {
7859cc4ca5SDavid du Colombier SubsystemStatus = 0x8504, /* Subsystem Status: read only */
7959cc4ca5SDavid du Colombier /* read only: whether we get interrupts on various events */
8059cc4ca5SDavid du Colombier VsyncInt = 1<<0, /* vertical sync */
8159cc4ca5SDavid du Colombier GeBusyInt = 1<<1, /* 2D graphics engine busy */
8259cc4ca5SDavid du Colombier BfifoFullInt = 1<<2, /* BIU FIFO full */
8359cc4ca5SDavid du Colombier BfifoEmptyInt = 1<<3, /* BIU FIFO empty */
8459cc4ca5SDavid du Colombier CfifoFullInt = 1<<4, /* command FIFO full */
8559cc4ca5SDavid du Colombier CfifoEmptyInt = 1<<5, /* command FIFO empty */
8659cc4ca5SDavid du Colombier BciInt = 1<<6, /* BCI */
8759cc4ca5SDavid du Colombier LpbInt = 1<<7, /* LPB */
8859cc4ca5SDavid du Colombier CbHiInt = 1<<16, /* COB upper threshold */
8959cc4ca5SDavid du Colombier CbLoInt = 1<<17, /* COB lower threshold */
9059cc4ca5SDavid du Colombier
9159cc4ca5SDavid du Colombier SubsystemCtl = 0x8504, /* Subsystem Control: write only */
9259cc4ca5SDavid du Colombier /* clear interrupts for various events */
9359cc4ca5SDavid du Colombier VsyncClr = 1<<0,
9459cc4ca5SDavid du Colombier GeBusyClr = 1<<1,
9559cc4ca5SDavid du Colombier BfifoFullClr = 1<<2,
9659cc4ca5SDavid du Colombier BfifoEmptyClr = 1<<3,
9759cc4ca5SDavid du Colombier CfifoFullClr = 1<<4,
9859cc4ca5SDavid du Colombier CfifoEmptyClr = 1<<5,
9959cc4ca5SDavid du Colombier BciClr = 1<<6,
10059cc4ca5SDavid du Colombier LpbClr = 1<<7,
10159cc4ca5SDavid du Colombier CbHiClr = 1<<16,
10259cc4ca5SDavid du Colombier CbLoClr = 1<<17,
10359cc4ca5SDavid du Colombier
10459cc4ca5SDavid du Colombier /* enable interrupts for various events */
10559cc4ca5SDavid du Colombier VsyncEna = 1<<8,
10659cc4ca5SDavid du Colombier Busy2DEna = 1<<9,
10759cc4ca5SDavid du Colombier BfifoFullEna = 1<<10,
10859cc4ca5SDavid du Colombier BfifoEmptyEna = 1<<11,
10959cc4ca5SDavid du Colombier CfifoFullEna = 1<<12,
11059cc4ca5SDavid du Colombier CfifoEmptyEna = 1<<13,
11159cc4ca5SDavid du Colombier SubsysBciEna = 1<<14,
11259cc4ca5SDavid du Colombier CbHiEna = 1<<24,
11359cc4ca5SDavid du Colombier CbLoEna = 1<<25,
11459cc4ca5SDavid du Colombier
11559cc4ca5SDavid du Colombier /* 2D graphics engine software reset */
11659cc4ca5SDavid du Colombier GeSoftReset = 1<<15,
11759cc4ca5SDavid du Colombier
11859cc4ca5SDavid du Colombier FifoStatus = 0x8508, /* FIFO status: read only */
11959cc4ca5SDavid du Colombier CwbEmpty = 1<<0, /* command write buffer empty */
12059cc4ca5SDavid du Colombier CrbEmpty = 1<<1, /* command read buffer empty */
12159cc4ca5SDavid du Colombier CobEmpty = 1<<2, /* command overflow buffer empty */
12259cc4ca5SDavid du Colombier CfifoEmpty = 1<<3, /* command FIFO empty */
12359cc4ca5SDavid du Colombier CwbFull = 1<<8, /* command write buffer full */
12459cc4ca5SDavid du Colombier CrbFull = 1<<9, /* command read buffer full */
12559cc4ca5SDavid du Colombier CobFull = 1<<10, /* command overflow buffer full */
12659cc4ca5SDavid du Colombier CfifoFull = 1<<11, /* command FIFO full */
12759cc4ca5SDavid du Colombier
12859cc4ca5SDavid du Colombier AdvFunCtl = 0x850C, /* Advanced Function Control: read/write */
12959cc4ca5SDavid du Colombier GeEna = 1<<0, /* enable 2D/3D engine */
13059cc4ca5SDavid du Colombier /*
13159cc4ca5SDavid du Colombier * according to the manual, BigPixel should be
13259cc4ca5SDavid du Colombier * set when bpp >= 8 (bpp != 4), and then CR50_5-4 are
13359cc4ca5SDavid du Colombier * used to figure out bpp example. however, it does bad things
13459cc4ca5SDavid du Colombier * to the screen in 8bpp mode.
13559cc4ca5SDavid du Colombier */
13659cc4ca5SDavid du Colombier BigPixel = 1<<2, /* 8 or more bpp enhanced mode */
13759cc4ca5SDavid du Colombier LaEna = 1<<3, /* linear addressing ena: or'ed with CR58_4 */
13859cc4ca5SDavid du Colombier Mclk_2 = 0<<8, /* 2D engine clock divide: MCLK/2 */
13959cc4ca5SDavid du Colombier Mclk_4 = 1<<8, /* " MCLK/4 */
14059cc4ca5SDavid du Colombier Mclk = 2<<8, /* " MCLK */
14159cc4ca5SDavid du Colombier /* Mclk = 3<<8, /* " MCLK */
14259cc4ca5SDavid du Colombier Ic33mhz = 1<<16, /* Internal clock 33 MHz (instead of 66) */
14359cc4ca5SDavid du Colombier
14459cc4ca5SDavid du Colombier WakeupReg = 0x8510, /* Wakeup: read/write */
14559cc4ca5SDavid du Colombier WakeupBit = 1<<0, /* wake up: or'ed with 3C3_0 */
14659cc4ca5SDavid du Colombier
14759cc4ca5SDavid du Colombier SourceY = 0x8100, /* UL corner of bitblt source */
14859cc4ca5SDavid du Colombier SourceX = 0x8102, /* " */
14959cc4ca5SDavid du Colombier RectY = 0x8100, /* UL corner of rectangle fill */
15059cc4ca5SDavid du Colombier RectX = 0x8102, /* " */
15159cc4ca5SDavid du Colombier DestY = 0x8108, /* UL corner of bitblt dest */
15259cc4ca5SDavid du Colombier DestX = 0x810A, /* " */
15359cc4ca5SDavid du Colombier Height = 0x8148, /* bitblt, image xfer rectangle height */
15459cc4ca5SDavid du Colombier Width = 0x814A, /* bitblt, image xfer rectangle width */
15559cc4ca5SDavid du Colombier
15659cc4ca5SDavid du Colombier StartY = 0x8100, /* Line draw: first point*/
15759cc4ca5SDavid du Colombier StartX = 0x8102, /* " */
15859cc4ca5SDavid du Colombier /*
15959cc4ca5SDavid du Colombier * For line draws, the following must be programmed:
16059cc4ca5SDavid du Colombier * axial step constant = 2*min(|dx|,|dy|)
16159cc4ca5SDavid du Colombier * diagonal step constant = 2*[min(|dx|,|dy|) - max(|dx|,|dy|)]
16259cc4ca5SDavid du Colombier * error term = 2*min(|dx|,|dy|) - max(|dx|,|dy| - 1
16359cc4ca5SDavid du Colombier * [sic] when start X < end X
16459cc4ca5SDavid du Colombier * error term = 2*min(|dx|,|dy|) - max(|dx|,|dy|
16559cc4ca5SDavid du Colombier * [sic] when start X >= end X
16659cc4ca5SDavid du Colombier */
16759cc4ca5SDavid du Colombier AxialStep = 0x8108,
16859cc4ca5SDavid du Colombier DiagonalStep = 0x810A,
16959cc4ca5SDavid du Colombier LineError = 0x8110,
17059cc4ca5SDavid du Colombier MinorLength = 0x8148, /* pixel count along minor axis */
17159cc4ca5SDavid du Colombier MajorLength = 0x814A, /* pixel count along major axis */
17259cc4ca5SDavid du Colombier
17359cc4ca5SDavid du Colombier DrawCmd = 0x8118, /* Drawing Command: write only */
17459cc4ca5SDavid du Colombier CmdMagic = 0<<1,
17559cc4ca5SDavid du Colombier AcrossPlane = 1<<1, /* across the plane mode */
17659cc4ca5SDavid du Colombier LastPixelOff = 1<<2, /* last pixel of line or vector draw not drawn */
17759cc4ca5SDavid du Colombier Radial = 1<<3, /* enable radial direction (else axial) */
17859cc4ca5SDavid du Colombier DoDraw = 1<<4, /* draw pixels (else only move current pos) */
17959cc4ca5SDavid du Colombier
18059cc4ca5SDavid du Colombier DrawRight = 1<<5, /* axial drawing direction: left to right */
18159cc4ca5SDavid du Colombier /* DrawLeft = 0<<5, */
18259cc4ca5SDavid du Colombier MajorY = 1<<6,
18359cc4ca5SDavid du Colombier /* MajorX = 0<<6, */
18459cc4ca5SDavid du Colombier DrawDown = 1<<7,
18559cc4ca5SDavid du Colombier /* DrawUp = 0<<7, */
18659cc4ca5SDavid du Colombier Degree0 = 0<<5, /* drawing direction when Radial */
18759cc4ca5SDavid du Colombier Degree45 = 1<<5,
18859cc4ca5SDavid du Colombier /* ... */
18959cc4ca5SDavid du Colombier Degree315 = 7<<5,
19059cc4ca5SDavid du Colombier
19159cc4ca5SDavid du Colombier UseCPUData = 1<<8,
19259cc4ca5SDavid du Colombier
19359cc4ca5SDavid du Colombier /* image write bus transfer width */
19459cc4ca5SDavid du Colombier Bus8 = 0<<9,
19559cc4ca5SDavid du Colombier Bus16 = 1<<9,
19659cc4ca5SDavid du Colombier /*
19759cc4ca5SDavid du Colombier * in Bus32 mode, doubleword bits beyond the image rect width are
19859cc4ca5SDavid du Colombier * discarded. each line starts on a new doubleword.
19959cc4ca5SDavid du Colombier * Bus32AP is intended for across-the-plane mode and
20059cc4ca5SDavid du Colombier * rounds to byte boundaries instead.
20159cc4ca5SDavid du Colombier */
20259cc4ca5SDavid du Colombier Bus32 = 2<<9,
20359cc4ca5SDavid du Colombier Bus32AP = 3<<9,
20459cc4ca5SDavid du Colombier
20559cc4ca5SDavid du Colombier CmdNop = 0<<13, /* nop */
20659cc4ca5SDavid du Colombier CmdLine = 1<<13, /* draw line */
20759cc4ca5SDavid du Colombier CmdFill = 2<<13, /* fill rectangle */
20859cc4ca5SDavid du Colombier CmdBitblt = 6<<13, /* bitblt */
20959cc4ca5SDavid du Colombier CmdPatblt = 7<<13, /* 8x8 pattern blt */
21059cc4ca5SDavid du Colombier
21159cc4ca5SDavid du Colombier SrcGBD = 0<<16,
21259cc4ca5SDavid du Colombier SrcPBD = 1<<16,
21359cc4ca5SDavid du Colombier SrcSBD = 2<<16,
21459cc4ca5SDavid du Colombier
21559cc4ca5SDavid du Colombier DstGBD = 0<<18,
21659cc4ca5SDavid du Colombier DstPBD = 1<<18,
21759cc4ca5SDavid du Colombier DstSBD = 2<<18,
21859cc4ca5SDavid du Colombier
21959cc4ca5SDavid du Colombier /* color sources, controls */
22059cc4ca5SDavid du Colombier BgColor = 0x8120, /* Background Color: read/write */
22159cc4ca5SDavid du Colombier FgColor = 0x8124, /* Foreground Color: read/write */
22259cc4ca5SDavid du Colombier BitplaneWmask = 0x8128, /* Bitplane Write Mask: read/write */
22359cc4ca5SDavid du Colombier BitplaneRmask = 0x812C, /* Bitplane Read Mask: read/write */
22459cc4ca5SDavid du Colombier CmpColor = 0x8130, /* Color Compare: read/write */
22559cc4ca5SDavid du Colombier BgMix = 0x8134,
22659cc4ca5SDavid du Colombier FgMix = 0x8136,
22759cc4ca5SDavid du Colombier MixNew = 7,
22859cc4ca5SDavid du Colombier SrcBg = 0<<5,
22959cc4ca5SDavid du Colombier SrcFg = 1<<5,
23059cc4ca5SDavid du Colombier SrcCPU = 2<<5,
23159cc4ca5SDavid du Colombier SrcDisp = 3<<5,
23259cc4ca5SDavid du Colombier
23359cc4ca5SDavid du Colombier /* clipping rectangle */
23459cc4ca5SDavid du Colombier TopScissors = 0x8138, /* Top Scissors: write only */
23559cc4ca5SDavid du Colombier LeftScissors = 0x813A, /* Left Scissors: write only */
23659cc4ca5SDavid du Colombier BottomScissors = 0x813C, /* Bottom Scissors: write only */
23759cc4ca5SDavid du Colombier RightScissors = 0x813E, /* Right Scissors: write only */
23859cc4ca5SDavid du Colombier
23959cc4ca5SDavid du Colombier /*
24059cc4ca5SDavid du Colombier * Registers with Magic were indirectly accessed in older modes.
24159cc4ca5SDavid du Colombier * It is not clear whether the Magic is necessary.
24259cc4ca5SDavid du Colombier * In the older modes, writes to these registers were pipelined,
24359cc4ca5SDavid du Colombier * so that you had to issue an engine command and wait for engine
24459cc4ca5SDavid du Colombier * idle before reading a write back. It is not clear if this is
24559cc4ca5SDavid du Colombier * still the case either.
24659cc4ca5SDavid du Colombier */
24759cc4ca5SDavid du Colombier PixCtl = 0x8140, /* Pixel Control: write only */
24859cc4ca5SDavid du Colombier PixMagic = 0xA<<12,
24959cc4ca5SDavid du Colombier PixMixFg = 0<<6, /* foreground mix register always */
25059cc4ca5SDavid du Colombier PixMixCPU = 2<<6, /* CPU data determines mix register */
25159cc4ca5SDavid du Colombier PixMixDisp = 3<<6, /* display data determines mix register */
25259cc4ca5SDavid du Colombier
25359cc4ca5SDavid du Colombier MfMisc2Ctl = 0x8142, /* Multifunction Control Misc. 2: write only */
25459cc4ca5SDavid du Colombier MfMisc2Magic = 0xD<<12,
25559cc4ca5SDavid du Colombier DstShift = 0, /* 3 bits: destination base address in MB */
25659cc4ca5SDavid du Colombier SrcShift = 4, /* 3 bits: source base address in MB */
25759cc4ca5SDavid du Colombier WaitFifoEmpty = 2<<8, /* wait for write FIFO empty between draws */
25859cc4ca5SDavid du Colombier
25959cc4ca5SDavid du Colombier MfMiscCtl = 0x8144, /* Multifunction Control Misc: write only */
26059cc4ca5SDavid du Colombier MfMiscMagic = 0xE<<12,
26159cc4ca5SDavid du Colombier UseHighBits = 1<<4, /* select upper 16 bits for 32-bit reg access */
26259cc4ca5SDavid du Colombier ClipInvert = 1<<5, /* only touch pixels outside clip rectangle */
26359cc4ca5SDavid du Colombier SkipSame = 0<<6, /* ignore pixels with color CmpColor */
26459cc4ca5SDavid du Colombier SkipDifferent = 1<<7, /* ignore pixels not color CmpColor */
26559cc4ca5SDavid du Colombier CmpEna = 1<<8, /* enable color compare */
26659cc4ca5SDavid du Colombier W32Ena = 1<<9, /* enable 32-bit register write */
26759cc4ca5SDavid du Colombier ClipDis = 1<<11, /* disable clipping */
26859cc4ca5SDavid du Colombier
26959cc4ca5SDavid du Colombier /*
27059cc4ca5SDavid du Colombier * The bitmap descriptor 1 registers contain the starting
27159cc4ca5SDavid du Colombier * address of the bitmap (in bytes).
27259cc4ca5SDavid du Colombier * The bitmap descriptor 2 registesr contain stride (in pixels)
27359cc4ca5SDavid du Colombier * in the lower 16 bits, depth (in bits) in the next 8 bits,
27459cc4ca5SDavid du Colombier * and whether block write is disabled.
27559cc4ca5SDavid du Colombier */
27659cc4ca5SDavid du Colombier GBD1 = 0x8168, /* Global Bitmap Descriptor 1: read/write */
27759cc4ca5SDavid du Colombier GBD2 = 0x816C, /* Global Bitmap Descriptor 2: read/write */
27859cc4ca5SDavid du Colombier /* GBD2-only bits */
27959cc4ca5SDavid du Colombier BDS64 = 1<<0, /* bitmap descriptor size 64 bits */
28059cc4ca5SDavid du Colombier GBDBciEna = 1<<3, /* BCI enable */
28159cc4ca5SDavid du Colombier /* generic BD2 bits */
28259cc4ca5SDavid du Colombier BlockWriteDis = 1<<28,
28359cc4ca5SDavid du Colombier StrideShift = 0,
28459cc4ca5SDavid du Colombier DepthShift = 16,
28559cc4ca5SDavid du Colombier
28659cc4ca5SDavid du Colombier PBD1 = 0x8170, /* Primary Bitmap Descriptor: read/write */
28759cc4ca5SDavid du Colombier PBD2 = 0x8174,
28859cc4ca5SDavid du Colombier SBD1 = 0x8178, /* Secondary Bitmap Descriptor: read/write */
28959cc4ca5SDavid du Colombier SBD2 = 0x817C,
29059cc4ca5SDavid du Colombier };
29159cc4ca5SDavid du Colombier
29259cc4ca5SDavid du Colombier /* mastered data transfer registers */
29359cc4ca5SDavid du Colombier
29459cc4ca5SDavid du Colombier /* configuration/status registers */
29559cc4ca5SDavid du Colombier enum {
29659cc4ca5SDavid du Colombier XStatus0 = 0x48C00, /* Status Word 0: read only */
29759cc4ca5SDavid du Colombier /* rev. A silicon differs from rev. B; use AltStatus0 */
29859cc4ca5SDavid du Colombier CBEMaskA = 0x1FFFF, /* filled command buffer entries */
29959cc4ca5SDavid du Colombier CBEShiftA = 0,
30059cc4ca5SDavid du Colombier BciIdleA = 1<<17, /* BCI idle */
30159cc4ca5SDavid du Colombier Ge3IdleA = 1<<18, /* 3D engine idle */
30259cc4ca5SDavid du Colombier Ge2IdleA = 1<<19, /* 2D engine idle */
30359cc4ca5SDavid du Colombier McpIdleA = 1<<20, /* motion compensation processor idle */
30459cc4ca5SDavid du Colombier MeIdleA = 1<<22, /* master engine idle */
30559cc4ca5SDavid du Colombier PfPendA = 1<<23, /* page flip pending */
30659cc4ca5SDavid du Colombier
30759cc4ca5SDavid du Colombier CBEMaskB = 0x1FFFFF,
30859cc4ca5SDavid du Colombier CBEShiftB = 0,
30959cc4ca5SDavid du Colombier BciIdleB = 1<<25,
31059cc4ca5SDavid du Colombier Ge3IdleB = 1<<26,
31159cc4ca5SDavid du Colombier Ge2IdleB = 1<<27,
31259cc4ca5SDavid du Colombier McpIdleB = 1<<28,
31359cc4ca5SDavid du Colombier MeIdleB = 1<<30,
31459cc4ca5SDavid du Colombier PfPendB = 1<<31,
31559cc4ca5SDavid du Colombier
31659cc4ca5SDavid du Colombier AltStatus0 = 0x48C60, /* Alternate Status Word 0: read only */
31759cc4ca5SDavid du Colombier CBEMask = 0x1FFFF,
31859cc4ca5SDavid du Colombier CBEShift = 0,
31959cc4ca5SDavid du Colombier /* the Savage4 manual says bits 17..23 for these, like Status0 */
32059cc4ca5SDavid du Colombier /* empirically, they are bits 21..26 */
32159cc4ca5SDavid du Colombier BciIdle = 1<<21,
32259cc4ca5SDavid du Colombier Ge3Idle = 1<<22,
32359cc4ca5SDavid du Colombier Ge2Idle = 1<<23,
32459cc4ca5SDavid du Colombier McpIdle = 1<<24,
32559cc4ca5SDavid du Colombier MeIdle = 1<<25,
32659cc4ca5SDavid du Colombier PfPend = 1<<26,
32759cc4ca5SDavid du Colombier
32859cc4ca5SDavid du Colombier XStatus1 = 0x48C04, /* Status Word 1: read only */
32959cc4ca5SDavid du Colombier /* contains event tag 1, event tag 0, both 16 bits */
33059cc4ca5SDavid du Colombier
33159cc4ca5SDavid du Colombier XStatus2 = 0x48C08, /* Status Word 2: read only */
33259cc4ca5SDavid du Colombier ScanMask = 0x3FF, /* current scan line */
33359cc4ca5SDavid du Colombier ScanShift = 0,
33459cc4ca5SDavid du Colombier VRTMask = 0x7F100, /* vert retrace count */
33559cc4ca5SDavid du Colombier VRTShift = 11,
33659cc4ca5SDavid du Colombier
33759cc4ca5SDavid du Colombier CbThresh = 0x48C10, /* Command Buffer Thresholds: read/write */
33859cc4ca5SDavid du Colombier CobOff = 0x48C14, /* Command Overflow Buffer: read/write */
33959cc4ca5SDavid du Colombier
34059cc4ca5SDavid du Colombier CobPtr = 0x48C18, /* Command Overflow Buffer Pointers: read/write */
34159cc4ca5SDavid du Colombier CobEna = 1<<2, /* command overflow buffer enable */
34259cc4ca5SDavid du Colombier CobBciEna = 1<<3, /* BCI function enable */
34359cc4ca5SDavid du Colombier CbeMask = 0xFFFF8000, /* no. of entries in command buffer */
34459cc4ca5SDavid du Colombier CbeShift = 15,
34559cc4ca5SDavid du Colombier
34659cc4ca5SDavid du Colombier AltStatus1 = 0x48C64, /* Alternate Status Word 1: read onnly */
34759cc4ca5SDavid du Colombier /* contains current texture surface tag, vertex buffer tag */
34859cc4ca5SDavid du Colombier
34959cc4ca5SDavid du Colombier };
35059cc4ca5SDavid du Colombier
35159cc4ca5SDavid du Colombier struct {
35259cc4ca5SDavid du Colombier ulong idletimeout;
3539a747e4fSDavid du Colombier ulong tostatw[16];
35459cc4ca5SDavid du Colombier } savagestats;
35559cc4ca5SDavid du Colombier
35659cc4ca5SDavid du Colombier enum {
3579a747e4fSDavid du Colombier Maxloop = 1<<20
35859cc4ca5SDavid du Colombier };
35959cc4ca5SDavid du Colombier
36059cc4ca5SDavid du Colombier static void
savagewaitidle(VGAscr * scr)36159cc4ca5SDavid du Colombier savagewaitidle(VGAscr *scr)
36259cc4ca5SDavid du Colombier {
36359cc4ca5SDavid du Colombier long x;
36459cc4ca5SDavid du Colombier ulong *statw, mask, goal;
36559cc4ca5SDavid du Colombier
36659cc4ca5SDavid du Colombier switch(scr->id){
36759cc4ca5SDavid du Colombier case SAVAGE4:
3680b459c2cSDavid du Colombier case PROSAVAGEP:
3690b459c2cSDavid du Colombier case PROSAVAGEK:
370*19dc9ffeSDavid du Colombier case PROSAVAGE8:
37159cc4ca5SDavid du Colombier /* wait for engine idle and FIFO empty */
37259cc4ca5SDavid du Colombier statw = (ulong*)((uchar*)scr->mmio+AltStatus0);
3739a747e4fSDavid du Colombier mask = CBEMask | Ge2Idle;
3749a747e4fSDavid du Colombier goal = Ge2Idle;
37559cc4ca5SDavid du Colombier break;
37659cc4ca5SDavid du Colombier /* case SAVAGEMXMV: ? */
37759cc4ca5SDavid du Colombier /* case SAVAGEMX: ? */
37859cc4ca5SDavid du Colombier /* case SAVAGEIX: ? */
3799a747e4fSDavid du Colombier case SUPERSAVAGEIXC16:
38059cc4ca5SDavid du Colombier case SAVAGEIXMV:
3819a747e4fSDavid du Colombier case SAVAGEMXMV:
38259cc4ca5SDavid du Colombier /* wait for engine idle and FIFO empty */
38359cc4ca5SDavid du Colombier statw = (ulong*)((uchar*)scr->mmio+XStatus0);
3849a747e4fSDavid du Colombier mask = CBEMaskA | Ge2IdleA;
3859a747e4fSDavid du Colombier goal = Ge2IdleA;
38659cc4ca5SDavid du Colombier break;
38759cc4ca5SDavid du Colombier default:
38859cc4ca5SDavid du Colombier /*
38959cc4ca5SDavid du Colombier * best we can do: can't print or we'll call ourselves.
39059cc4ca5SDavid du Colombier * savageinit is supposed to not let this happen.
39159cc4ca5SDavid du Colombier */
39259cc4ca5SDavid du Colombier return;
39359cc4ca5SDavid du Colombier }
39459cc4ca5SDavid du Colombier
39559cc4ca5SDavid du Colombier for(x=0; x<Maxloop; x++)
39659cc4ca5SDavid du Colombier if((*statw & mask) == goal)
39759cc4ca5SDavid du Colombier return;
39859cc4ca5SDavid du Colombier
3999a747e4fSDavid du Colombier savagestats.tostatw[savagestats.idletimeout++&15] = *statw;
4009a747e4fSDavid du Colombier savagestats.tostatw[savagestats.idletimeout++&15] = (ulong)statw;
40159cc4ca5SDavid du Colombier }
40259cc4ca5SDavid du Colombier
40359cc4ca5SDavid du Colombier static int
savagefill(VGAscr * scr,Rectangle r,ulong sval)40459cc4ca5SDavid du Colombier savagefill(VGAscr *scr, Rectangle r, ulong sval)
40559cc4ca5SDavid du Colombier {
40659cc4ca5SDavid du Colombier uchar *mmio;
40759cc4ca5SDavid du Colombier
40859cc4ca5SDavid du Colombier mmio = (uchar*)scr->mmio;
40959cc4ca5SDavid du Colombier
41059cc4ca5SDavid du Colombier *(ulong*)(mmio+FgColor) = sval;
41159cc4ca5SDavid du Colombier *(ulong*)(mmio+BgColor) = sval;
41259cc4ca5SDavid du Colombier *(ulong*)(mmio+BgMix) = SrcFg|MixNew;
41359cc4ca5SDavid du Colombier *(ulong*)(mmio+FgMix) = SrcFg|MixNew;
41459cc4ca5SDavid du Colombier *(ushort*)(mmio+RectY) = r.min.y;
41559cc4ca5SDavid du Colombier *(ushort*)(mmio+RectX) = r.min.x;
41659cc4ca5SDavid du Colombier *(ushort*)(mmio+Width) = Dx(r)-1;
41759cc4ca5SDavid du Colombier *(ushort*)(mmio+Height) = Dy(r)-1;
41859cc4ca5SDavid du Colombier *(ulong*)(mmio+DrawCmd) = CmdMagic | DoDraw | CmdFill | DrawRight | DrawDown;
41959cc4ca5SDavid du Colombier savagewaitidle(scr);
42059cc4ca5SDavid du Colombier return 1;
42159cc4ca5SDavid du Colombier }
42259cc4ca5SDavid du Colombier
42359cc4ca5SDavid du Colombier static int
savagescroll(VGAscr * scr,Rectangle r,Rectangle sr)42459cc4ca5SDavid du Colombier savagescroll(VGAscr *scr, Rectangle r, Rectangle sr)
42559cc4ca5SDavid du Colombier {
42659cc4ca5SDavid du Colombier uchar *mmio;
42759cc4ca5SDavid du Colombier ulong cmd;
42859cc4ca5SDavid du Colombier Point dp, sp;
42959cc4ca5SDavid du Colombier
43059cc4ca5SDavid du Colombier cmd = CmdMagic | DoDraw | CmdBitblt | SrcPBD | DstGBD;
43159cc4ca5SDavid du Colombier
43259cc4ca5SDavid du Colombier if(r.min.x <= sr.min.x){
43359cc4ca5SDavid du Colombier cmd |= DrawRight;
43459cc4ca5SDavid du Colombier dp.x = r.min.x;
43559cc4ca5SDavid du Colombier sp.x = sr.min.x;
43659cc4ca5SDavid du Colombier }else{
43759cc4ca5SDavid du Colombier dp.x = r.max.x-1;
43859cc4ca5SDavid du Colombier sp.x = sr.max.x-1;
43959cc4ca5SDavid du Colombier }
44059cc4ca5SDavid du Colombier
44159cc4ca5SDavid du Colombier if(r.min.y <= sr.min.y){
44259cc4ca5SDavid du Colombier cmd |= DrawDown;
44359cc4ca5SDavid du Colombier dp.y = r.min.y;
44459cc4ca5SDavid du Colombier sp.y = sr.min.y;
44559cc4ca5SDavid du Colombier }else{
44659cc4ca5SDavid du Colombier dp.y = r.max.y-1;
44759cc4ca5SDavid du Colombier sp.y = sr.max.y-1;
44859cc4ca5SDavid du Colombier }
44959cc4ca5SDavid du Colombier
45059cc4ca5SDavid du Colombier mmio = (uchar*)scr->mmio;
45159cc4ca5SDavid du Colombier
45259cc4ca5SDavid du Colombier *(ushort*)(mmio+SourceX) = sp.x;
45359cc4ca5SDavid du Colombier *(ushort*)(mmio+SourceY) = sp.y;
45459cc4ca5SDavid du Colombier *(ushort*)(mmio+DestX) = dp.x;
45559cc4ca5SDavid du Colombier *(ushort*)(mmio+DestY) = dp.y;
45659cc4ca5SDavid du Colombier *(ushort*)(mmio+Width) = Dx(r)-1;
45759cc4ca5SDavid du Colombier *(ushort*)(mmio+Height) = Dy(r)-1;
45859cc4ca5SDavid du Colombier *(ulong*)(mmio+BgMix) = SrcDisp|MixNew;
45959cc4ca5SDavid du Colombier *(ulong*)(mmio+FgMix) = SrcDisp|MixNew;
46059cc4ca5SDavid du Colombier *(ulong*)(mmio+DrawCmd) = cmd;
46159cc4ca5SDavid du Colombier savagewaitidle(scr);
46259cc4ca5SDavid du Colombier return 1;
46359cc4ca5SDavid du Colombier }
46459cc4ca5SDavid du Colombier
4659a747e4fSDavid du Colombier static void
savageblank(VGAscr *,int blank)4669a747e4fSDavid du Colombier savageblank(VGAscr*, int blank)
4679a747e4fSDavid du Colombier {
4689a747e4fSDavid du Colombier uchar seqD;
4699a747e4fSDavid du Colombier
4709a747e4fSDavid du Colombier /*
4719a747e4fSDavid du Colombier * Will handle DPMS to monitor
4729a747e4fSDavid du Colombier */
4739a747e4fSDavid du Colombier vgaxo(Seqx, 8, vgaxi(Seqx,8)|0x06);
4749a747e4fSDavid du Colombier seqD = vgaxi(Seqx, 0xD);
4759a747e4fSDavid du Colombier seqD &= 0x03;
4769a747e4fSDavid du Colombier if(blank)
4779a747e4fSDavid du Colombier seqD |= 0x50;
4789a747e4fSDavid du Colombier vgaxo(Seqx, 0xD, seqD);
4799a747e4fSDavid du Colombier
4809a747e4fSDavid du Colombier /*
4819a747e4fSDavid du Colombier * Will handle LCD
4829a747e4fSDavid du Colombier */
4839a747e4fSDavid du Colombier if(blank)
4849a747e4fSDavid du Colombier vgaxo(Seqx, 0x31, vgaxi(Seqx, 0x31) & ~0x10);
4859a747e4fSDavid du Colombier else
4869a747e4fSDavid du Colombier vgaxo(Seqx, 0x31, vgaxi(Seqx, 0x31) | 0x10);
4879a747e4fSDavid du Colombier }
4889a747e4fSDavid du Colombier
4899a747e4fSDavid du Colombier
49059cc4ca5SDavid du Colombier void
savageinit(VGAscr * scr)49159cc4ca5SDavid du Colombier savageinit(VGAscr *scr)
49259cc4ca5SDavid du Colombier {
49359cc4ca5SDavid du Colombier uchar *mmio;
49459cc4ca5SDavid du Colombier ulong bd;
49559cc4ca5SDavid du Colombier
49659cc4ca5SDavid du Colombier /* if you add chip IDs here be sure to update savagewaitidle */
49759cc4ca5SDavid du Colombier switch(scr->id){
49859cc4ca5SDavid du Colombier case SAVAGE4:
4990b459c2cSDavid du Colombier case PROSAVAGEP:
5000b459c2cSDavid du Colombier case PROSAVAGEK:
501*19dc9ffeSDavid du Colombier case PROSAVAGE8:
50259cc4ca5SDavid du Colombier case SAVAGEIXMV:
5039a747e4fSDavid du Colombier case SUPERSAVAGEIXC16:
5049a747e4fSDavid du Colombier case SAVAGEMXMV:
50559cc4ca5SDavid du Colombier break;
50659cc4ca5SDavid du Colombier default:
50759cc4ca5SDavid du Colombier print("unknown savage %.4lux\n", scr->id);
50859cc4ca5SDavid du Colombier return;
50959cc4ca5SDavid du Colombier }
51059cc4ca5SDavid du Colombier
51159cc4ca5SDavid du Colombier mmio = (uchar*)scr->mmio;
51259cc4ca5SDavid du Colombier if(mmio == nil) {
51359cc4ca5SDavid du Colombier print("savageinit: no mmio\n");
51459cc4ca5SDavid du Colombier return;
51559cc4ca5SDavid du Colombier }
51659cc4ca5SDavid du Colombier
51759cc4ca5SDavid du Colombier /* 2D graphics engine software reset */
51859cc4ca5SDavid du Colombier *(ushort*)(mmio+SubsystemCtl) = GeSoftReset;
51959cc4ca5SDavid du Colombier delay(2);
52059cc4ca5SDavid du Colombier *(ushort*)(mmio+SubsystemCtl) = 0;
52159cc4ca5SDavid du Colombier savagewaitidle(scr);
52259cc4ca5SDavid du Colombier
52359cc4ca5SDavid du Colombier /* disable BCI as much as possible */
52459cc4ca5SDavid du Colombier *(ushort*)(mmio+CobPtr) &= ~CobBciEna;
52559cc4ca5SDavid du Colombier *(ushort*)(mmio+GBD2) &= ~GBDBciEna;
52659cc4ca5SDavid du Colombier savagewaitidle(scr);
52759cc4ca5SDavid du Colombier
52859cc4ca5SDavid du Colombier /* enable 32-bit writes, disable clipping */
52959cc4ca5SDavid du Colombier *(ushort*)(mmio+MfMiscCtl) = MfMiscMagic|W32Ena|ClipDis;
53059cc4ca5SDavid du Colombier savagewaitidle(scr);
53159cc4ca5SDavid du Colombier
53259cc4ca5SDavid du Colombier /* enable all read, write planes */
53359cc4ca5SDavid du Colombier *(ulong*)(mmio+BitplaneRmask) = ~0;
53459cc4ca5SDavid du Colombier *(ulong*)(mmio+BitplaneWmask) = ~0;
53559cc4ca5SDavid du Colombier savagewaitidle(scr);
53659cc4ca5SDavid du Colombier
53759cc4ca5SDavid du Colombier /* turn on linear access, 2D engine */
53859cc4ca5SDavid du Colombier *(ulong*)(mmio+AdvFunCtl) |= GeEna|LaEna;
53959cc4ca5SDavid du Colombier savagewaitidle(scr);
54059cc4ca5SDavid du Colombier
54159cc4ca5SDavid du Colombier /* set bitmap descriptors */
54259cc4ca5SDavid du Colombier bd = (scr->gscreen->depth<<DepthShift) |
5439a747e4fSDavid du Colombier (Dx(scr->gscreen->r)<<StrideShift) | BlockWriteDis
5449a747e4fSDavid du Colombier | BDS64;
54559cc4ca5SDavid du Colombier
54659cc4ca5SDavid du Colombier *(ulong*)(mmio+GBD1) = 0;
5479a747e4fSDavid du Colombier *(ulong*)(mmio+GBD2) = bd;
54859cc4ca5SDavid du Colombier
54959cc4ca5SDavid du Colombier *(ulong*)(mmio+PBD1) = 0;
55059cc4ca5SDavid du Colombier *(ulong*)(mmio+PBD2) = bd;
55159cc4ca5SDavid du Colombier
55259cc4ca5SDavid du Colombier *(ulong*)(mmio+SBD1) = 0;
55359cc4ca5SDavid du Colombier *(ulong*)(mmio+SBD2) = bd;
55459cc4ca5SDavid du Colombier
55559cc4ca5SDavid du Colombier /*
55659cc4ca5SDavid du Colombier * For some reason, the GBD needs to get programmed twice,
55759cc4ca5SDavid du Colombier * once before the PBD, SBD, and once after.
55859cc4ca5SDavid du Colombier * This empirically makes it get set right.
55959cc4ca5SDavid du Colombier * I would like to better understand the ugliness
56059cc4ca5SDavid du Colombier * going on here.
56159cc4ca5SDavid du Colombier */
56259cc4ca5SDavid du Colombier *(ulong*)(mmio+GBD1) = 0;
56359cc4ca5SDavid du Colombier *(ulong*)(mmio+GBD2) = bd;
56459cc4ca5SDavid du Colombier *(ushort*)(mmio+GBD2+2) = bd>>16;
56559cc4ca5SDavid du Colombier savagewaitidle(scr);
56659cc4ca5SDavid du Colombier
56759cc4ca5SDavid du Colombier scr->fill = savagefill;
56859cc4ca5SDavid du Colombier scr->scroll = savagescroll;
5699a747e4fSDavid du Colombier scr->blank = savageblank;
5709a747e4fSDavid du Colombier hwblank = 0;
57159cc4ca5SDavid du Colombier }
572