ref: 48555e785ac03a29aad4c027674d9487d148227c
dir: /sys/src/9/pc/vgamach64xx.c/
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/pci.h" #include "../port/error.h" #define Image IMAGE #include <draw.h> #include <memdraw.h> #include <cursor.h> #include "screen.h" char Eunsupportedformat[] = "unsupported video format"; char Enotconfigured[] = "device not configured"; #define SCALE_ZERO_EXTEND 0x0 #define SCALE_DYNAMIC 0x1 #define SCALE_RED_TEMP_6500K 0x0 #define SCALE_RED_TEMP_9800K 0x2 #define SCALE_HORZ_BLEND 0x0 #define SCALE_HORZ_REP 0x4 #define SCALE_VERT_BLEND 0x0 #define SCALE_VERT_REP 0x8 #define SCALE_BANDWIDTH_NORMAL 0x0 #define SCALE_BANDWIDTH_EXCEEDED 0x4000000 #define SCALE_BANDWIDTH_RESET 0x4000000 #define SCALE_CLK_ACTIVITY 0x0 #define SCALE_CLK_CONTINUOUS 0x20000000 #define OVERLAY_DISABLE 0x0 #define OVERLAY_ENABLE 0x40000000 #define SCALE_DISABLE 0x0 #define SCALE_ENABLE 0x80000000 #define SCALER_FRAME_READ_MODE_FULL 0x0 #define SCALER_BUF_MODE_SINGLE 0x0 #define SCALER_BUF_MODE_DOUBLE 0x40000 #define SCALER_BUF_NEXT_0 0x0 #define SCALER_BUF_NEXT_1 0x80000 #define SCALER_BUF_STATUS_0 0x0 #define SCALER_BUF_STATUS_1 0x100000 #define OVERLAY_MIX_G_CMP 0x0 #define OVERLAY_MIX_ALWAYS_G 0x100 #define OVERLAY_MIX_ALWAYS_V 0x200 #define OVERLAY_MIX_NOT_G 0x300 #define OVERLAY_MIX_NOT_V 0x400 #define OVERLAY_MIX_G_XOR_V 0x500 #define OVERLAY_MIX_NOT_G_XOR_V 0x600 #define OVERLAY_MIX_V_CMP 0x700 #define OVERLAY_MIX_NOT_G_OR_NOT_V 0x800 #define OVERLAY_MIX_G_OR_NOT_V 0x900 #define OVERLAY_MIX_NOT_G_OR_V 0xA00 #define OVERLAY_MIX_G_OR_V 0xB00 #define OVERLAY_MIX_G_AND_V 0xC00 #define OVERLAY_MIX_NOT_G_AND_V 0xD00 #define OVERLAY_MIX_G_AND_NOT_V 0xE00 #define OVERLAY_MIX_NOT_G_AND_NOT_V 0xF00 #define OVERLAY_EXCLUSIVE_NORMAL 0x0 #define OVERLAY_EXCLUSIVE_V_ONLY 0x80000000 #define VIDEO_IN_8BPP 0x2 #define VIDEO_IN_16BPP 0x4 #define VIDEO_IN_32BPP 0x6 #define VIDEO_IN_VYUY422 0xB /*16 bpp */ #define VIDEO_IN_YVYU422 0xC /* 16 bpp */ #define SCALE_IN_15BPP 0x30000 /* aRGB 1555 */ #define SCALE_IN_16BPP 0x40000 /* RGB 565 */ #define SCALE_IN_32BPP 0x60000 /* aRGB 8888 */ #define SCALE_IN_YUV9 0x90000 /* planar */ #define SCALE_IN_YUV12 0xA0000 /* planar */ #define SCALE_IN_VYUY422 0xB0000 /* 16 bpp */ #define SCALE_IN_YVYU422 0xC0000 /* 16 bpp */ #define HOST_YUV_APERTURE_UPPER 0x0 #define HOST_YUV_APERTURE_LOWER 0x20000000 #define HOST_MEM_MODE_Y 0x40000000 #define HOST_MEM_MODE_U 0x80000000 #define HOST_MEM_MODE_V 0xC0000000 #define HOST_MEM_MODE_NORMAL HOST_YUV_APERTURE_UPPER enum { VTGTB1S1 = 0x01, /* Asic description for VTB1S1 and GTB1S1. */ VT4GTIIC = 0x3A, /* asic descr for VT4 and RAGE IIC */ GTB1U1 = 0x19, /* Asic description for GTB1U1. */ GTB1S2 = 0x41, /* Asic description for GTB1S2. */ GTB2U1 = 0x1A, GTB2U2 = 0x5A, GTB2U3 = 0x9A, GTIIIC1U1 = 0x1B, /* 3D RAGE PRO asic descrp. */ GTIIIC1U2 = 0x5B, /* 3D RAGE PRO asic descrp. */ GTIIIC2U1 = 0x1C, /* 3D RAGE PRO asic descrp. */ GTIIIC2U2 = 0x5C, /* 3D RAGE PRO asic descrp. */ GTIIIC2U3 = 0x7C, /* 3D RAGE PRO asic descrp. */ GTBC = 0x3A, /* 3D RAGE IIC asic descrp. */ LTPRO = 0x9C, /* 3D RAGE LT PRO */ }; /* * ATI Mach64(CT|ET|G*|V*|L*). */ typedef struct Mach64types Mach64types; struct Mach64types { ushort m64_id; /* Chip ID */ int m64_vtgt; /* Is this a VT or GT chipset? */ ulong m64_ovlclock; /* Max. overlay clock frequency */ int m64_pro; /* Is this a PRO? */ }; static ulong mach64refclock; static Mach64types *mach64type; static int mach64revb; /* Revision B or greater? */ static Mach64types mach64s[] = { ('C'<<8)|'T', 0, 1350000, /*?*/ 0, /* 4354: CT */ ('E'<<8)|'T', 0, 1350000, /*?*/ 0, /* 4554: ET */ ('G'<<8)|'B', 1, 1250000, 1, /* 4742: 264GT PRO */ ('G'<<8)|'D', 1, 1250000, 1, /* 4744: 264GT PRO */ ('G'<<8)|'I', 1, 1250000, 1, /* 4749: 264GT PRO */ ('G'<<8)|'M', 0, 1350000, 0, /* 474D: Rage XL */ ('G'<<8)|'P', 1, 1250000, 1, /* 4750: 264GT PRO */ ('G'<<8)|'Q', 1, 1250000, 1, /* 4751: 264GT PRO */ ('G'<<8)|'R', 1, 1250000, 1, /* 4752: */ ('G'<<8)|'T', 1, 800000, 0, /* 4754: 264GT[B] */ ('G'<<8)|'U', 1, 1000000, 0, /* 4755: 264GT DVD */ ('G'<<8)|'V', 1, 1000000, 0, /* 4756: Rage2C */ ('G'<<8)|'Z', 1, 1000000, 0, /* 475A: Rage2C */ ('V'<<8)|'T', 1, 800000, 0, /* 5654: 264VT/GT/VTB */ ('V'<<8)|'U', 1, 800000, 0, /* 5655: 264VT3 */ ('V'<<8)|'V', 1, 1000000, 0, /* 5656: 264VT4 */ ('L'<<8)|'B', 0, 1350000, 1, /* 4C42: Rage LTPro AGP */ ('L'<<8)|'I', 0, 1350000, 0, /* 4C49: Rage LTPro AGP */ ('L'<<8)|'M', 0, 1350000, 0, /* 4C4D: Rage Mobility */ ('L'<<8)|'P', 0, 1350000, 1, /* 4C50: 264LT PRO */ }; static int hwfill(VGAscr*, Rectangle, ulong); static int hwscroll(VGAscr*, Rectangle, Rectangle); static void initengine(VGAscr*); static void mach64xxenable(VGAscr* scr) { Pcidev *p; int i; if(scr->io) return; p = scr->pci; if(p == nil || p->vid != 0x1002) return; mach64type = nil; for (i = 0; i != nelem(mach64s); i++) if (mach64s[i].m64_id == p->did) { scr->id = p->did; mach64type = &mach64s[i]; break; } if(mach64type != nil){ /* * The CT doesn't always have the I/O base address * in the PCI base registers. There is a way to find * it via the vendor-specific PCI config space but * this will do for now. */ scr->io = p->mem[1].bar & ~0x03; if(scr->io == 0) scr->io = 0x2EC; } } static void mach64xxlinear(VGAscr* scr, int size, int) { vgalinearpci(scr); if(scr->paddr == 0) return; scr->mmio = (ulong*)((uchar*)scr->vaddr+size-1024); addvgaseg("mach64mmio", scr->paddr+size-BY2PG, BY2PG); addvgaseg("mach64screen", scr->paddr, scr->apsize); } enum { CrtcOffPitch = 0x05, CrtcGenCtl = 0x07, CurClr0 = 0x0B, /* I/O Select */ CurClr1 = 0x0C, CurOffset = 0x0D, CurHVposn = 0x0E, CurHVoff = 0x0F, BusCntl = 0x13, GenTestCntl = 0x19, CrtcHsyncDis = 0x04, CrtcVsyncDis = 0x08, ContextMask = 0x100, /* not accessible via I/O */ FifoStat, GuiStat, DpFrgdClr, DpBkgdClr, DpWriteMask, DpMix, DpPixWidth, DpSrc, ClrCmpCntl, GuiTrajCntl, ScLeftRight, ScTopBottom, DstOffPitch, DstYX, DstHeightWidth, DstCntl, DstHeight, DstBresErr, DstBresInc, DstBresDec, SrcCntl, SrcHeight1Width1, SrcHeight2Width2, SrcYX, SrcWidth1, SrcYXstart, HostCntl, PatReg0, PatReg1, PatCntl, ScBottom, ScLeft, ScRight, ScTop, ClrCmpClr, ClrCmpMask, DpChainMask, SrcOffPitch, LcdIndex, LcdData, ClockCntl, OverlayScaleCntl, ConfigChipId, Buf0Pitch, ScalerBuf0Pitch, CaptureConfig, OverlayKeyCntl, ScalerColourCntl, ScalerHCoef0, ScalerHCoef1, ScalerHCoef2, ScalerHCoef3, ScalerHCoef4, VideoFormat, Buf0Offset, ScalerBuf0Offset, CrtcGenCntl, OverlayScaleInc, OverlayYX, OverlayYXEnd, ScalerHeightWidth, HTotalDisp, VTotalDisp, }; enum { LCD_ConfigPanel = 0, LCD_GenCtrl, LCD_DstnCntl, LCD_HfbPitchAddr, LCD_HorzStretch, LCD_VertStretch, LCD_ExtVertStretch, LCD_LtGio, LCD_PowerMngmnt, LCD_ZvgPio, Nlcd, }; #define Bank1 (-0x100) /* 1KB */ static int mmoffset[] = { [HTotalDisp] 0x00, [VTotalDisp] 0x02, [CrtcOffPitch] 0x05, [CrtcGenCntl] 0x07, [CurClr0] 0x18, [CurClr1] 0x19, [CurOffset] 0x1A, [CurHVposn] 0x1B, [CurHVoff] 0x1C, [ClockCntl] 0x24, [BusCntl] 0x28, [LcdIndex] 0x29, [LcdData] 0x2A, [GenTestCntl] 0x34, [ConfigChipId] 0x38, [DstOffPitch] 0x40, [DstYX] 0x43, [DstHeight] 0x45, [DstHeightWidth] 0x46, [DstBresErr] 0x49, [DstBresInc] 0x4A, [DstBresDec] 0x4B, [DstCntl] 0x4C, [SrcOffPitch] 0x60, [SrcYX] 0x63, [SrcWidth1] 0x64, [SrcYXstart] 0x69, [SrcHeight1Width1] 0x66, [SrcHeight2Width2] 0x6C, [SrcCntl] 0x6D, [HostCntl] 0x90, [PatReg0] 0xA0, [PatReg1] 0xA1, [PatCntl] 0xA2, [ScLeft] 0xA8, [ScRight] 0xA9, [ScLeftRight] 0xAA, [ScTop] 0xAB, [ScBottom] 0xAC, [ScTopBottom] 0xAD, [DpBkgdClr] 0xB0, [DpFrgdClr] 0xB1, [DpWriteMask] 0xB2, [DpChainMask] 0xB3, [DpPixWidth] 0xB4, [DpMix] 0xB5, [DpSrc] 0xB6, [ClrCmpClr] 0xC0, [ClrCmpMask] 0xC1, [ClrCmpCntl] 0xC2, [FifoStat] 0xC4, [ContextMask] 0xC8, [GuiTrajCntl] 0xCC, [GuiStat] 0xCE, /* Bank1 */ [OverlayYX] Bank1 + 0x00, [OverlayYXEnd] Bank1 + 0x01, [OverlayKeyCntl] Bank1 + 0x06, [OverlayScaleInc] Bank1 + 0x08, [OverlayScaleCntl] Bank1 + 0x09, [ScalerHeightWidth] Bank1 + 0x0A, [ScalerBuf0Offset] Bank1 + 0x0D, [ScalerBuf0Pitch] Bank1 + 0x0F, [VideoFormat] Bank1 + 0x12, [CaptureConfig] Bank1 + 0x14, [Buf0Offset] Bank1 + 0x20, [Buf0Pitch] Bank1 + 0x23, [ScalerColourCntl] Bank1 + 0x54, [ScalerHCoef0] Bank1 + 0x55, [ScalerHCoef1] Bank1 + 0x56, [ScalerHCoef2] Bank1 + 0x57, [ScalerHCoef3] Bank1 + 0x58, [ScalerHCoef4] Bank1 + 0x59, }; static ulong ior32(VGAscr* scr, int r) { if(scr->io == 0x2EC || scr->io == 0x1C8) return inl((r<<10)+scr->io); if(r >= 0x100 && scr->mmio != nil) return scr->mmio[mmoffset[r]]; return inl((mmoffset[r]<<2)+scr->io); } static void iow32(VGAscr* scr, int r, ulong l) { if(scr->io == 0x2EC || scr->io == 0x1C8) outl(((r)<<10)+scr->io, l); else if(r >= 0x100 && scr->mmio != nil) scr->mmio[mmoffset[r]] = l; else outl((mmoffset[r]<<2)+scr->io, l); } static ulong lcdr32(VGAscr *scr, ulong r) { ulong or; or = ior32(scr, LcdIndex); iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F)); return ior32(scr, LcdData); } static void lcdw32(VGAscr *scr, ulong r, ulong v) { ulong or; or = ior32(scr, LcdIndex); iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F)); iow32(scr, LcdData, v); } static void mach64xxcurdisable(VGAscr* scr) { ulong r; r = ior32(scr, GenTestCntl); iow32(scr, GenTestCntl, r & ~0x80); } static void mach64xxcurload(VGAscr* scr, Cursor* curs) { uchar *p; int i, y; ulong c, s, m, r; /* * Disable the cursor. */ r = ior32(scr, GenTestCntl); iow32(scr, GenTestCntl, r & ~0x80); p = scr->vaddr; p += scr->storage; /* * Initialise the 64x64 cursor RAM array. * The cursor mode gives the following truth table: * p1 p0 colour * 0 0 Cursor Colour 0 * 0 1 Cursor Colour 1 * 1 0 Transparent * 1 1 Complement * Put the cursor into the top-right of the 64x64 array. */ for(y = 0; y < 16; y++){ for(i = 0; i < (64-16)/8; i++){ *p++ = 0xAA; *p++ = 0xAA; } c = (curs->clr[2*y]<<8)|curs->clr[y*2 + 1]; s = (curs->set[2*y]<<8)|curs->set[y*2 + 1]; m = 0x00000000; for(i = 0; i < 16; i++){ if(s & (1<<(15-i))) m |= 0x01<<(2*i); else if(c & (1<<(15-i))){ /* nothing to do */ } else m |= 0x02<<(2*i); } *p++ = m; *p++ = m>>8; *p++ = m>>16; *p++ = m>>24; } memset(p, 0xAA, (64-16)*16); /* * Set the cursor hotpoint and enable the cursor. */ scr->offset = curs->offset; iow32(scr, GenTestCntl, 0x80|r); } static int ptalmostinrect(Point p, Rectangle r) { return p.x>=r.min.x && p.x<=r.max.x && p.y>=r.min.y && p.y<=r.max.y; } static int mach64xxcurmove(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 presets instead. If y is negative also have to * adjust the starting offset. */ 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; iow32(scr, CurHVoff, ((64-16-yo)<<16)|(64-16-xo)); iow32(scr, CurOffset, scr->storage/8 + (-yo*2)); iow32(scr, CurHVposn, (y<<16)|x); return 0; } static void mach64xxcurenable(VGAscr* scr) { ulong r, storage; mach64xxenable(scr); if(scr->io == 0) return; r = ior32(scr, GenTestCntl); iow32(scr, GenTestCntl, r & ~0x80); iow32(scr, CurClr0, (Pwhite<<24)|(Pwhite<<16)|(Pwhite<<8)|Pwhite); iow32(scr, CurClr1, (Pblack<<24)|(Pblack<<16)|(Pblack<<8)|Pblack); /* * Find a place for the cursor data in display memory. * Must be 64-bit aligned. */ storage = (scr->pitch*scr->height+7)/8; iow32(scr, CurOffset, storage); scr->storage = storage*8; /* * Cursor goes in the top right corner of the 64x64 array * so the horizontal and vertical presets are 64-16. */ iow32(scr, CurHVposn, (0<<16)|0); iow32(scr, CurHVoff, ((64-16)<<16)|(64-16)); /* * Load, locate and enable the 64x64 cursor. */ mach64xxcurload(scr, &cursor); mach64xxcurmove(scr, ZP); iow32(scr, GenTestCntl, 0x80|r); } static void waitforfifo(VGAscr *scr, int entries) { int x; x = 0; while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000) ; if(x >= 1000000) iprint("fifo %d stat %#.8lux %#.8lux scrio %#.8lux mmio %#p scr %#p pc %#p\n", entries, ior32(scr, FifoStat), scr->mmio[mmoffset[FifoStat]], scr->io, scr->mmio, scr, getcallerpc(&scr)); } static void waitforidle(VGAscr *scr) { int x; waitforfifo(scr, 16); x = 0; while((ior32(scr, GuiStat)&1) && x++ < 1000000) ; if(x >= 1000000) iprint("idle stat %#.8lux %#.8lux scrio %#.8lux mmio %#p scr %#p pc %#p\n", ior32(scr, GuiStat), scr->mmio[mmoffset[GuiStat]], scr->io, scr->mmio, scr, getcallerpc(&scr)); } static void resetengine(VGAscr *scr) { ulong x; x = ior32(scr, GenTestCntl); iow32(scr, GenTestCntl, x&~0x100); iow32(scr, GenTestCntl, x|0x100); iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000); } static void initengine(VGAscr *scr) { uchar *bios; ushort table; resetengine(scr); waitforfifo(scr, 14); iow32(scr, ContextMask, ~0); iow32(scr, DstOffPitch, scr->pitch<<22); iow32(scr, DstYX, 0); iow32(scr, DstHeight, 0); iow32(scr, DstBresErr, 0); iow32(scr, DstBresInc, 0); iow32(scr, DstBresDec, 0); iow32(scr, DstCntl, 0x23); iow32(scr, SrcOffPitch, scr->pitch<<22); iow32(scr, SrcYX, 0); iow32(scr, SrcHeight1Width1, 1); iow32(scr, SrcYXstart, 0); iow32(scr, SrcHeight2Width2, 1); iow32(scr, SrcCntl, 0x01); waitforfifo(scr, 13); iow32(scr, HostCntl, 0); iow32(scr, PatReg0, 0); iow32(scr, PatReg1, 0); iow32(scr, PatCntl, 0); iow32(scr, ScLeft, 0); iow32(scr, ScTop, 0); iow32(scr, ScBottom, 0xFFFF); iow32(scr, ScRight, 0xFFFF); iow32(scr, DpBkgdClr, 0); iow32(scr, DpFrgdClr, ~0); iow32(scr, DpWriteMask, ~0); iow32(scr, DpMix, 0x70003); iow32(scr, DpSrc, 0x00010100); waitforfifo(scr, 3); iow32(scr, ClrCmpClr, 0); iow32(scr, ClrCmpMask, ~0); iow32(scr, ClrCmpCntl, 0); waitforfifo(scr, 2); switch(scr->gscreen->depth){ case 8: case 24: /* [sic] */ iow32(scr, DpPixWidth, 0x00020202); iow32(scr, DpChainMask, 0x8080); break; case 16: iow32(scr, DpPixWidth, 0x00040404); iow32(scr, DpChainMask, 0x8410); break; case 32: iow32(scr, DpPixWidth, 0x00060606); iow32(scr, DpChainMask, 0x8080); break; } /* Get the base freq from the BIOS */ bios = kaddr(0xC000); table = *(ushort *)(bios + 0x48); table = *(ushort *)(bios + table + 0x10); switch (*(ushort *)(bios + table + 0x08)) { case 2700: mach64refclock = 270000; break; case 2863: case 2864: mach64refclock = 286363; break; case 2950: mach64refclock = 294989; break; case 1432: default: mach64refclock = 143181; break ; } /* Figure out which revision this chip is */ switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) { case VTGTB1S1: case GTB1U1: case GTB1S2: case GTB2U1: case GTB2U2: case GTB2U3: case GTBC: case GTIIIC1U1: case GTIIIC1U2: case GTIIIC2U1: case GTIIIC2U2: case GTIIIC2U3: case LTPRO: mach64revb = 1; break; default: mach64revb = 0; break; } waitforidle(scr); } static int mach64hwfill(VGAscr *scr, Rectangle r, ulong sval) { ulong ctl; /* shouldn't happen */ if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0) return 0; ctl = 1|2; /* left-to-right, top-to-bottom */ if(scr->gscreen->depth == 24){ r.min.x *= 3; r.max.x *= 3; ctl |= (1<<7)|(((r.min.x/4)%6)<<8); } waitforfifo(scr, 11); iow32(scr, DpFrgdClr, sval); iow32(scr, DpWriteMask, 0xFFFFFFFF); iow32(scr, DpMix, 0x00070003); iow32(scr, DpSrc, 0x00000111); iow32(scr, ClrCmpCntl, 0x00000000); iow32(scr, ScLeftRight, 0x1FFF0000); iow32(scr, ScTopBottom, 0x1FFF0000); iow32(scr, DstOffPitch, scr->pitch<<22); iow32(scr, DstCntl, ctl); iow32(scr, DstYX, (r.min.x<<16)|r.min.y); iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r)); waitforidle(scr); return 1; } static int mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr) { Point dp, sp; ulong ctl; int dx, dy; dx = Dx(r); dy = Dy(r); if(scr->gscreen->depth == 24){ dx *= 3; r.min.x *= 3; sr.min.x *= 3; } ctl = 0; if(r.min.x <= sr.min.x){ ctl |= 1; dp.x = r.min.x; sp.x = sr.min.x; }else{ dp.x = r.min.x+dx-1; sp.x = sr.min.x+dx-1; } if(r.min.y <= sr.min.y){ ctl |= 2; dp.y = r.min.y; sp.y = sr.min.y; }else{ dp.y = r.min.y+dy-1; sp.y = sr.min.y+dy-1; } if(scr->gscreen->depth == 24) ctl |= (1<<7)|(((dp.x/4)%6)<<8); waitforfifo(scr, 6); iow32(scr, ScLeftRight, 0x1FFF0000); iow32(scr, ScTopBottom, 0x1FFF0000); iow32(scr, DpWriteMask, 0xFFFFFFFF); iow32(scr, DpMix, 0x00070003); iow32(scr, DpSrc, 0x00000300); iow32(scr, ClrCmpCntl, 0x00000000); waitforfifo(scr, 8); iow32(scr, SrcOffPitch, scr->pitch<<22); iow32(scr, SrcCntl, 0x00000000); iow32(scr, SrcYX, (sp.x<<16)|sp.y); iow32(scr, SrcWidth1, dx); iow32(scr, DstOffPitch, scr->pitch<<22); iow32(scr, DstCntl, ctl); iow32(scr, DstYX, (dp.x<<16)|dp.y); iow32(scr, DstHeightWidth, (dx<<16)|dy); waitforidle(scr); return 1; } /* * This should work, but doesn't. * It messes up the screen timings for some reason. */ static void mach64blank(VGAscr *scr, int blank) { ulong ctl; ctl = ior32(scr, CrtcGenCtl) & ~(CrtcHsyncDis|CrtcVsyncDis); if(blank) ctl |= CrtcHsyncDis|CrtcVsyncDis; iow32(scr, CrtcGenCtl, ctl); } /* * We squirrel away whether the LCD and/or CRT were * on when we were called to blank the screen, and * restore the old state. If we are called to blank the * screen when it is already blank, we don't update the state. * Such a call sequence should not happen, though. * * We could try forcing the chip into power management * mode instead, but I'm not sure how that would interact * with screen updates going on while the screen is blanked. */ static void mach64lcdblank(VGAscr *scr, int blank) { static int crtlcd; ulong x; if(blank) { x = lcdr32(scr, LCD_GenCtrl); if(x & 3) { crtlcd = x & 3; lcdw32(scr, LCD_GenCtrl, x&~3); } } else { if(crtlcd == 0) crtlcd = 2; /* lcd only */ x = lcdr32(scr, LCD_GenCtrl); lcdw32(scr, LCD_GenCtrl, x | crtlcd); } } static void mach64xxdrawinit(VGAscr *scr) { if(scr->io > 0x2FF){ initengine(scr); scr->fill = mach64hwfill; scr->scroll = mach64hwscroll; } /* scr->blank = mach64blank; */ switch(scr->id){ default: break; case ('L'<<8)|'B': /* 4C42: Rage 3D LTPro */ case ('L'<<8)|'I': /* 4C49: Rage 3D LTPro */ case ('L'<<8)|'M': /* 4C4D: Rage Mobility */ case ('L'<<8)|'P': /* 4C50: Rage 3D LTPro */ scr->blank = mach64lcdblank; break; } } VGAdev vgamach64xxdev = { "mach64xx", mach64xxenable, /* enable */ 0, /* disable */ 0, /* page */ mach64xxlinear, /* linear */ mach64xxdrawinit, /* drawinit */ }; VGAcur vgamach64xxcur = { "mach64xxhwgc", mach64xxcurenable, /* enable */ mach64xxcurdisable, /* disable */ mach64xxcurload, /* load */ mach64xxcurmove, /* move */ };