xref: /plan9/sys/src/9/pc/vgamach64xx.c (revision 8498559bac70ac8118e6f36ad9d674181f43f45d)
17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "io.h"
77dd7cddfSDavid du Colombier #include "../port/error.h"
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier #define	Image	IMAGE
107dd7cddfSDavid du Colombier #include <draw.h>
117dd7cddfSDavid du Colombier #include <memdraw.h>
127dd7cddfSDavid du Colombier #include <cursor.h>
137dd7cddfSDavid du Colombier #include "screen.h"
147dd7cddfSDavid du Colombier 
159a747e4fSDavid du Colombier char Eunsupportedformat[] = "unsupported video format";
169a747e4fSDavid du Colombier char Enotconfigured[] = "device not configured";
179a747e4fSDavid du Colombier 
189a747e4fSDavid du Colombier #define SCALE_ZERO_EXTEND           	0x0
199a747e4fSDavid du Colombier #define SCALE_DYNAMIC               		0x1
209a747e4fSDavid du Colombier #define SCALE_RED_TEMP_6500K        	0x0
219a747e4fSDavid du Colombier #define SCALE_RED_TEMP_9800K        	0x2
229a747e4fSDavid du Colombier #define SCALE_HORZ_BLEND            	0x0
239a747e4fSDavid du Colombier #define SCALE_HORZ_REP              		0x4
249a747e4fSDavid du Colombier #define SCALE_VERT_BLEND            		0x0
259a747e4fSDavid du Colombier #define SCALE_VERT_REP              		0x8
269a747e4fSDavid du Colombier #define SCALE_BANDWIDTH_NORMAL     0x0
279a747e4fSDavid du Colombier #define SCALE_BANDWIDTH_EXCEEDED  0x4000000
289a747e4fSDavid du Colombier #define SCALE_BANDWIDTH_RESET       	0x4000000
299a747e4fSDavid du Colombier #define SCALE_CLK_ACTIVITY          	0x0
309a747e4fSDavid du Colombier #define SCALE_CLK_CONTINUOUS        	0x20000000
319a747e4fSDavid du Colombier #define OVERLAY_DISABLE             		0x0
329a747e4fSDavid du Colombier #define OVERLAY_ENABLE              		0x40000000
339a747e4fSDavid du Colombier #define SCALE_DISABLE               		0x0
349a747e4fSDavid du Colombier #define SCALE_ENABLE                		0x80000000
359a747e4fSDavid du Colombier 
369a747e4fSDavid du Colombier #define SCALER_FRAME_READ_MODE_FULL 	0x0
379a747e4fSDavid du Colombier #define SCALER_BUF_MODE_SINGLE      		0x0
389a747e4fSDavid du Colombier #define SCALER_BUF_MODE_DOUBLE      		0x40000
399a747e4fSDavid du Colombier #define SCALER_BUF_NEXT_0           		0x0
409a747e4fSDavid du Colombier #define SCALER_BUF_NEXT_1           		0x80000
419a747e4fSDavid du Colombier #define SCALER_BUF_STATUS_0         		0x0
429a747e4fSDavid du Colombier #define SCALER_BUF_STATUS_1         		0x100000
439a747e4fSDavid du Colombier 
449a747e4fSDavid du Colombier #define OVERLAY_MIX_G_CMP           		0x0
459a747e4fSDavid du Colombier #define OVERLAY_MIX_ALWAYS_G        		0x100
469a747e4fSDavid du Colombier #define OVERLAY_MIX_ALWAYS_V        		0x200
479a747e4fSDavid du Colombier #define OVERLAY_MIX_NOT_G           		0x300
489a747e4fSDavid du Colombier #define OVERLAY_MIX_NOT_V           		0x400
499a747e4fSDavid du Colombier #define OVERLAY_MIX_G_XOR_V         		0x500
509a747e4fSDavid du Colombier #define OVERLAY_MIX_NOT_G_XOR_V     	0x600
519a747e4fSDavid du Colombier #define OVERLAY_MIX_V_CMP           		0x700
529a747e4fSDavid du Colombier #define OVERLAY_MIX_NOT_G_OR_NOT_V	0x800
539a747e4fSDavid du Colombier #define OVERLAY_MIX_G_OR_NOT_V      	0x900
549a747e4fSDavid du Colombier #define OVERLAY_MIX_NOT_G_OR_V      	0xA00
559a747e4fSDavid du Colombier #define OVERLAY_MIX_G_OR_V          		0xB00
569a747e4fSDavid du Colombier #define OVERLAY_MIX_G_AND_V         		0xC00
579a747e4fSDavid du Colombier #define OVERLAY_MIX_NOT_G_AND_V     	0xD00
589a747e4fSDavid du Colombier #define OVERLAY_MIX_G_AND_NOT_V     	0xE00
599a747e4fSDavid du Colombier #define OVERLAY_MIX_NOT_G_AND_NOT_V 	0xF00
609a747e4fSDavid du Colombier #define OVERLAY_EXCLUSIVE_NORMAL    	0x0
619a747e4fSDavid du Colombier #define OVERLAY_EXCLUSIVE_V_ONLY    	0x80000000
629a747e4fSDavid du Colombier 
639a747e4fSDavid du Colombier #define VIDEO_IN_8BPP               			0x2
649a747e4fSDavid du Colombier #define VIDEO_IN_16BPP              			0x4
659a747e4fSDavid du Colombier #define VIDEO_IN_32BPP              			0x6
669a747e4fSDavid du Colombier #define VIDEO_IN_VYUY422            			0xB         		/*16 bpp */
679a747e4fSDavid du Colombier #define VIDEO_IN_YVYU422            			0xC         		/* 16 bpp */
689a747e4fSDavid du Colombier #define SCALE_IN_15BPP              			0x30000     	/* aRGB 1555 */
699a747e4fSDavid du Colombier #define SCALE_IN_16BPP              			0x40000     	/* RGB 565 */
709a747e4fSDavid du Colombier #define SCALE_IN_32BPP              			0x60000     	/* aRGB 8888 */
719a747e4fSDavid du Colombier #define SCALE_IN_YUV9               			0x90000     	/* planar */
729a747e4fSDavid du Colombier #define SCALE_IN_YUV12              			0xA0000     	/* planar */
739a747e4fSDavid du Colombier #define SCALE_IN_VYUY422            			0xB0000     	/* 16 bpp */
749a747e4fSDavid du Colombier #define SCALE_IN_YVYU422            			0xC0000     	/* 16 bpp */
759a747e4fSDavid du Colombier #define HOST_YUV_APERTURE_UPPER     		0x0
769a747e4fSDavid du Colombier #define HOST_YUV_APERTURE_LOWER     	0x20000000
779a747e4fSDavid du Colombier #define HOST_MEM_MODE_Y             		0x40000000
789a747e4fSDavid du Colombier #define HOST_MEM_MODE_U             		0x80000000
799a747e4fSDavid du Colombier #define HOST_MEM_MODE_V             		0xC0000000
809a747e4fSDavid du Colombier #define HOST_MEM_MODE_NORMAL     		HOST_YUV_APERTURE_UPPER
819a747e4fSDavid du Colombier 
829a747e4fSDavid du Colombier static Chan *ovl_chan;		/* Channel of controlling process */
839a747e4fSDavid du Colombier static int ovl_width;		/* Width of input overlay buffer */
849a747e4fSDavid du Colombier static int ovl_height;		/* Height of input overlay buffer */
859a747e4fSDavid du Colombier static int ovl_format;		/* Overlay format */
869a747e4fSDavid du Colombier static ulong ovl_fib;		/* Frame in bytes */
879a747e4fSDavid du Colombier 
889a747e4fSDavid du Colombier enum {
8941dd6b47SDavid du Colombier 	 VTGTB1S1	= 0x01, /* Asic description for VTB1S1 and GTB1S1. */
9041dd6b47SDavid du Colombier 	 VT4GTIIC	= 0x3A,		/* asic descr for VT4 and RAGE IIC */
9141dd6b47SDavid du Colombier 	 GTB1U1		= 0x19,		/* Asic description for GTB1U1. */
9241dd6b47SDavid du Colombier 	 GTB1S2		= 0x41,		/* Asic description for GTB1S2. */
939a747e4fSDavid du Colombier 	 GTB2U1		= 0x1A,
949a747e4fSDavid du Colombier 	 GTB2U2		= 0x5A,
959a747e4fSDavid du Colombier 	 GTB2U3		= 0x9A,
9641dd6b47SDavid du Colombier 	 GTIIIC1U1	= 0x1B,		/* 3D RAGE PRO asic descrp. */
9741dd6b47SDavid du Colombier 	 GTIIIC1U2	= 0x5B,		/* 3D RAGE PRO asic descrp. */
9841dd6b47SDavid du Colombier 	 GTIIIC2U1	= 0x1C,		/* 3D RAGE PRO asic descrp. */
9941dd6b47SDavid du Colombier 	 GTIIIC2U2	= 0x5C,		/* 3D RAGE PRO asic descrp. */
10041dd6b47SDavid du Colombier 	 GTIIIC2U3	= 0x7C,		/* 3D RAGE PRO asic descrp. */
10141dd6b47SDavid du Colombier 	 GTBC		= 0x3A,		/* 3D RAGE IIC asic descrp. */
10241dd6b47SDavid du Colombier 	 LTPRO		= 0x9C,		/* 3D RAGE LT PRO */
1039a747e4fSDavid du Colombier };
1049a747e4fSDavid du Colombier 
1057dd7cddfSDavid du Colombier /*
10659cc4ca5SDavid du Colombier  * ATI Mach64(CT|ET|G*|V*|L*).
1077dd7cddfSDavid du Colombier  */
10859c21d95SDavid du Colombier typedef struct Mach64types Mach64types;
10959c21d95SDavid du Colombier struct Mach64types {
1109a747e4fSDavid du Colombier 	ushort 	m64_id;			/* Chip ID */
1119a747e4fSDavid du Colombier 	int 	m64_vtgt;		/* Is this a VT or GT chipset? */
1129a747e4fSDavid du Colombier 	ulong	m64_ovlclock;		/* Max. overlay clock frequency */
1139a747e4fSDavid du Colombier 	int	m64_pro;		/* Is this a PRO? */
11459c21d95SDavid du Colombier };
1159a747e4fSDavid du Colombier 
1169a747e4fSDavid du Colombier static ulong mach64refclock;
11759c21d95SDavid du Colombier static Mach64types *mach64type;
1189a747e4fSDavid du Colombier static int mach64revb;			/* Revision B or greater? */
1199a747e4fSDavid du Colombier static ulong mach64overlay;		/* Overlay buffer */
1209a747e4fSDavid du Colombier 
12159c21d95SDavid du Colombier static Mach64types mach64s[] = {
1223ff48bf5SDavid du Colombier 	('C'<<8)|'T',	0,	1350000, /*?*/	0,	/* 4354: CT */
1233ff48bf5SDavid du Colombier 	('E'<<8)|'T',	0,	1350000, /*?*/	0,	/* 4554: ET */
1249a747e4fSDavid du Colombier 	('G'<<8)|'B',	1,	1250000,	1, 	/* 4742: 264GT PRO */
1259a747e4fSDavid du Colombier 	('G'<<8)|'D',	1,	1250000,	1, 	/* 4744: 264GT PRO */
1269a747e4fSDavid du Colombier 	('G'<<8)|'I',	1,	1250000,	1, 	/* 4749: 264GT PRO */
1279a747e4fSDavid du Colombier 	('G'<<8)|'M',	0,	1350000,	0,	/* 474D: Rage XL */
1289a747e4fSDavid du Colombier 	('G'<<8)|'P',	1,	1250000,	1, 	/* 4750: 264GT PRO */
1299a747e4fSDavid du Colombier 	('G'<<8)|'Q',	1,	1250000,	1,	/* 4751: 264GT PRO */
1309a747e4fSDavid du Colombier 	('G'<<8)|'R',	1,	1250000,	1,	/* 4752: */
1319a747e4fSDavid du Colombier 	('G'<<8)|'T',	1,	800000,		0,	/* 4754: 264GT[B] */
1329a747e4fSDavid du Colombier 	('G'<<8)|'U',	1,	1000000,	0,	/* 4755: 264GT DVD */
1339a747e4fSDavid du Colombier 	('G'<<8)|'V',	1,	1000000,	0,	/* 4756: Rage2C */
1349a747e4fSDavid du Colombier 	('G'<<8)|'Z',	1,	1000000,	0,	/* 475A: Rage2C */
1359a747e4fSDavid du Colombier 	('V'<<8)|'T',	1,	800000,		0,	/* 5654: 264VT/GT/VTB */
1369a747e4fSDavid du Colombier 	('V'<<8)|'U',	1,	800000,		0,	/* 5655: 264VT3 */
1379a747e4fSDavid du Colombier 	('V'<<8)|'V',	1,	1000000,	0,	/* 5656: 264VT4 */
1389a747e4fSDavid du Colombier 	('L'<<8)|'B',	0,	1350000,	1,	/* 4C42: Rage LTPro AGP */
1399a747e4fSDavid du Colombier 	('L'<<8)|'I',	0,	1350000,	0,	/* 4C49: Rage LTPro AGP */
1409a747e4fSDavid du Colombier 	('L'<<8)|'M',	0,	1350000,	0,	/* 4C4D: Rage Mobility */
1419a747e4fSDavid du Colombier 	('L'<<8)|'P',	0,	1350000,	1,	/* 4C50: 264LT PRO */
1427dd7cddfSDavid du Colombier };
1437dd7cddfSDavid du Colombier 
1449a747e4fSDavid du Colombier 
1457dd7cddfSDavid du Colombier static int hwfill(VGAscr*, Rectangle, ulong);
1467dd7cddfSDavid du Colombier static int hwscroll(VGAscr*, Rectangle, Rectangle);
1477dd7cddfSDavid du Colombier static void initengine(VGAscr*);
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier static Pcidev*
mach64xxpci(void)1507dd7cddfSDavid du Colombier mach64xxpci(void)
1517dd7cddfSDavid du Colombier {
1527dd7cddfSDavid du Colombier 	Pcidev *p;
1539a747e4fSDavid du Colombier 	int i;
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier 	if((p = pcimatch(nil, 0x1002, 0)) == nil)
1567dd7cddfSDavid du Colombier 		return nil;
1579a747e4fSDavid du Colombier 
1589a747e4fSDavid du Colombier 	for (i = 0; i != nelem(mach64s); i++)
1599a747e4fSDavid du Colombier 		if (mach64s[i].m64_id == p->did) {
1609a747e4fSDavid du Colombier 			mach64type = &mach64s[i];
1617dd7cddfSDavid du Colombier 			return p;
1627dd7cddfSDavid du Colombier 		}
1637dd7cddfSDavid du Colombier 	return nil;
1647dd7cddfSDavid du Colombier }
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier static void
mach64xxenable(VGAscr * scr)1677dd7cddfSDavid du Colombier mach64xxenable(VGAscr* scr)
1687dd7cddfSDavid du Colombier {
1697dd7cddfSDavid du Colombier 	Pcidev *p;
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	if(scr->io)
1727dd7cddfSDavid du Colombier 		return;
1737dd7cddfSDavid du Colombier 	if(p = mach64xxpci()){
1747dd7cddfSDavid du Colombier 		scr->id = p->did;
1754de34a7eSDavid du Colombier 		scr->pci = p;
1767dd7cddfSDavid du Colombier 
1777dd7cddfSDavid du Colombier 		/*
1787dd7cddfSDavid du Colombier 		 * The CT doesn't always have the I/O base address
1797dd7cddfSDavid du Colombier 		 * in the PCI base registers. There is a way to find
1807dd7cddfSDavid du Colombier 		 * it via the vendor-specific PCI config space but
1817dd7cddfSDavid du Colombier 		 * this will do for now.
1827dd7cddfSDavid du Colombier 		 */
1837dd7cddfSDavid du Colombier 		scr->io = p->mem[1].bar & ~0x03;
1847dd7cddfSDavid du Colombier 
18559cc4ca5SDavid du Colombier 		if(scr->io == 0)
1867dd7cddfSDavid du Colombier 			scr->io = 0x2EC;
1877dd7cddfSDavid du Colombier 	}
1887dd7cddfSDavid du Colombier }
1897dd7cddfSDavid du Colombier 
1904de34a7eSDavid du Colombier static void
mach64xxlinear(VGAscr * scr,int size,int)1914de34a7eSDavid du Colombier mach64xxlinear(VGAscr* scr, int size, int)
1927dd7cddfSDavid du Colombier {
193*8498559bSDavid du Colombier 	ulong mmiophys;
194*8498559bSDavid du Colombier 
1954de34a7eSDavid du Colombier 	vgalinearpci(scr);
1964de34a7eSDavid du Colombier 	if(scr->paddr == 0)
1974de34a7eSDavid du Colombier 		return;
198*8498559bSDavid du Colombier 	/*
199*8498559bSDavid du Colombier 	 * vgalinearpci sets framebuffer into write combining mode.
200*8498559bSDavid du Colombier 	 * Because mmio register page is inside framebuffer space,
201*8498559bSDavid du Colombier 	 * set it back to uncached.
202*8498559bSDavid du Colombier 	 */
203*8498559bSDavid du Colombier 	mmiophys = scr->paddr + size - BY2PG;
204*8498559bSDavid du Colombier 	if(!waserror()){
205*8498559bSDavid du Colombier 		mtrr(mmiophys, BY2PG, "uc");
206*8498559bSDavid du Colombier 		poperror();
207*8498559bSDavid du Colombier 	}
2084de34a7eSDavid du Colombier 	scr->mmio = (ulong*)((uchar*)scr->vaddr+size-1024);
209*8498559bSDavid du Colombier 	addvgaseg("mach64mmio", mmiophys, BY2PG);
2104de34a7eSDavid du Colombier 	addvgaseg("mach64screen", scr->paddr, scr->apsize);
2117dd7cddfSDavid du Colombier }
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier enum {
2147dd7cddfSDavid du Colombier 	CrtcOffPitch	= 0x05,
2157dd7cddfSDavid du Colombier 	CrtcGenCtl	= 0x07,
2167dd7cddfSDavid du Colombier 	CurClr0		= 0x0B,		/* I/O Select */
2177dd7cddfSDavid du Colombier 	CurClr1		= 0x0C,
2187dd7cddfSDavid du Colombier 	CurOffset	= 0x0D,
2197dd7cddfSDavid du Colombier 	CurHVposn	= 0x0E,
2207dd7cddfSDavid du Colombier 	CurHVoff	= 0x0F,
2217dd7cddfSDavid du Colombier 	BusCntl	= 0x13,
2227dd7cddfSDavid du Colombier 	GenTestCntl	= 0x19,
2237dd7cddfSDavid du Colombier 
2247dd7cddfSDavid du Colombier 	CrtcHsyncDis	= 0x04,
2257dd7cddfSDavid du Colombier 	CrtcVsyncDis	= 0x08,
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier 	ContextMask	= 0x100,	/* not accessible via I/O */
2287dd7cddfSDavid du Colombier 	FifoStat,
2297dd7cddfSDavid du Colombier 	GuiStat,
2307dd7cddfSDavid du Colombier 	DpFrgdClr,
2317dd7cddfSDavid du Colombier 	DpBkgdClr,
2327dd7cddfSDavid du Colombier 	DpWriteMask,
2337dd7cddfSDavid du Colombier 	DpMix,
2347dd7cddfSDavid du Colombier 	DpPixWidth,
2357dd7cddfSDavid du Colombier 	DpSrc,
2367dd7cddfSDavid du Colombier 	ClrCmpCntl,
2377dd7cddfSDavid du Colombier 	GuiTrajCntl,
2387dd7cddfSDavid du Colombier 	ScLeftRight,
2397dd7cddfSDavid du Colombier 	ScTopBottom,
2407dd7cddfSDavid du Colombier 	DstOffPitch,
2417dd7cddfSDavid du Colombier 	DstYX,
2427dd7cddfSDavid du Colombier 	DstHeightWidth,
2437dd7cddfSDavid du Colombier 	DstCntl,
2447dd7cddfSDavid du Colombier 	DstHeight,
2457dd7cddfSDavid du Colombier 	DstBresErr,
2467dd7cddfSDavid du Colombier 	DstBresInc,
2477dd7cddfSDavid du Colombier 	DstBresDec,
2487dd7cddfSDavid du Colombier 	SrcCntl,
2497dd7cddfSDavid du Colombier 	SrcHeight1Width1,
2507dd7cddfSDavid du Colombier 	SrcHeight2Width2,
2517dd7cddfSDavid du Colombier 	SrcYX,
2527dd7cddfSDavid du Colombier 	SrcWidth1,
2537dd7cddfSDavid du Colombier 	SrcYXstart,
2547dd7cddfSDavid du Colombier 	HostCntl,
2557dd7cddfSDavid du Colombier 	PatReg0,
2567dd7cddfSDavid du Colombier 	PatReg1,
2577dd7cddfSDavid du Colombier 	PatCntl,
2587dd7cddfSDavid du Colombier 	ScBottom,
2597dd7cddfSDavid du Colombier 	ScLeft,
2607dd7cddfSDavid du Colombier 	ScRight,
2617dd7cddfSDavid du Colombier 	ScTop,
2627dd7cddfSDavid du Colombier 	ClrCmpClr,
2637dd7cddfSDavid du Colombier 	ClrCmpMask,
2647dd7cddfSDavid du Colombier 	DpChainMask,
2657dd7cddfSDavid du Colombier 	SrcOffPitch,
2667dd7cddfSDavid du Colombier 	LcdIndex,
2677dd7cddfSDavid du Colombier 	LcdData,
2689a747e4fSDavid du Colombier 	ClockCntl,
2699a747e4fSDavid du Colombier 	OverlayScaleCntl,
2709a747e4fSDavid du Colombier 	ConfigChipId,
2719a747e4fSDavid du Colombier 	Buf0Pitch,
2729a747e4fSDavid du Colombier 	ScalerBuf0Pitch,
2739a747e4fSDavid du Colombier 	CaptureConfig,
2749a747e4fSDavid du Colombier 	OverlayKeyCntl,
2759a747e4fSDavid du Colombier 	ScalerColourCntl,
2769a747e4fSDavid du Colombier 	ScalerHCoef0,
2779a747e4fSDavid du Colombier 	ScalerHCoef1,
2789a747e4fSDavid du Colombier 	ScalerHCoef2,
2799a747e4fSDavid du Colombier 	ScalerHCoef3,
2809a747e4fSDavid du Colombier 	ScalerHCoef4,
2819a747e4fSDavid du Colombier 	VideoFormat,
2829a747e4fSDavid du Colombier 	Buf0Offset,
2839a747e4fSDavid du Colombier 	ScalerBuf0Offset,
2849a747e4fSDavid du Colombier 	CrtcGenCntl,
2859a747e4fSDavid du Colombier 	OverlayScaleInc,
2869a747e4fSDavid du Colombier 	OverlayYX,
2879a747e4fSDavid du Colombier 	OverlayYXEnd,
2889a747e4fSDavid du Colombier 	ScalerHeightWidth,
2899a747e4fSDavid du Colombier 	HTotalDisp,
2909a747e4fSDavid du Colombier 	VTotalDisp,
2917dd7cddfSDavid du Colombier };
2927dd7cddfSDavid du Colombier 
2937dd7cddfSDavid du Colombier enum {
2947dd7cddfSDavid du Colombier 	LCD_ConfigPanel = 0,
2957dd7cddfSDavid du Colombier 	LCD_GenCtrl,
2967dd7cddfSDavid du Colombier 	LCD_DstnCntl,
2977dd7cddfSDavid du Colombier 	LCD_HfbPitchAddr,
2987dd7cddfSDavid du Colombier 	LCD_HorzStretch,
2997dd7cddfSDavid du Colombier 	LCD_VertStretch,
3007dd7cddfSDavid du Colombier 	LCD_ExtVertStretch,
3017dd7cddfSDavid du Colombier 	LCD_LtGio,
3027dd7cddfSDavid du Colombier 	LCD_PowerMngmnt,
3037dd7cddfSDavid du Colombier 	LCD_ZvgPio,
3047dd7cddfSDavid du Colombier 	Nlcd,
3057dd7cddfSDavid du Colombier };
3067dd7cddfSDavid du Colombier 
3079a747e4fSDavid du Colombier #define Bank1			(-0x100)		/* 1KB */
3089a747e4fSDavid du Colombier 
3099a747e4fSDavid du Colombier static int mmoffset[] = {
3109a747e4fSDavid du Colombier 	[HTotalDisp]		0x00,
3119a747e4fSDavid du Colombier 	[VTotalDisp]		0x02,
3127dd7cddfSDavid du Colombier 	[CrtcOffPitch]		0x05,
3139a747e4fSDavid du Colombier 	[CrtcGenCntl]		0x07,
3147dd7cddfSDavid du Colombier 	[CurClr0]			0x18,
3157dd7cddfSDavid du Colombier 	[CurClr1]			0x19,
3167dd7cddfSDavid du Colombier 	[CurOffset]		0x1A,
3177dd7cddfSDavid du Colombier 	[CurHVposn]		0x1B,
3187dd7cddfSDavid du Colombier 	[CurHVoff]		0x1C,
3199a747e4fSDavid du Colombier 	[ClockCntl]		0x24,
3207dd7cddfSDavid du Colombier 	[BusCntl]			0x28,
3217dd7cddfSDavid du Colombier 	[LcdIndex]		0x29,
3227dd7cddfSDavid du Colombier 	[LcdData]			0x2A,
3237dd7cddfSDavid du Colombier 	[GenTestCntl]		0x34,
3249a747e4fSDavid du Colombier 	[ConfigChipId]		0x38,
3257dd7cddfSDavid du Colombier 	[DstOffPitch]		0x40,
3267dd7cddfSDavid du Colombier 	[DstYX]			0x43,
3277dd7cddfSDavid du Colombier 	[DstHeight]		0x45,
3287dd7cddfSDavid du Colombier 	[DstHeightWidth]	0x46,
3297dd7cddfSDavid du Colombier 	[DstBresErr]		0x49,
3307dd7cddfSDavid du Colombier 	[DstBresInc]		0x4A,
3317dd7cddfSDavid du Colombier 	[DstBresDec]		0x4B,
3327dd7cddfSDavid du Colombier 	[DstCntl]			0x4C,
3337dd7cddfSDavid du Colombier 	[SrcOffPitch]		0x60,
3347dd7cddfSDavid du Colombier 	[SrcYX]			0x63,
3357dd7cddfSDavid du Colombier 	[SrcWidth1]		0x64,
3367dd7cddfSDavid du Colombier 	[SrcYXstart]		0x69,
3377dd7cddfSDavid du Colombier 	[SrcHeight1Width1]	0x66,
3387dd7cddfSDavid du Colombier 	[SrcHeight2Width2]	0x6C,
3397dd7cddfSDavid du Colombier 	[SrcCntl]			0x6D,
3407dd7cddfSDavid du Colombier 	[HostCntl]			0x90,
3417dd7cddfSDavid du Colombier 	[PatReg0]			0xA0,
3427dd7cddfSDavid du Colombier 	[PatReg1]			0xA1,
3437dd7cddfSDavid du Colombier 	[PatCntl]			0xA2,
3447dd7cddfSDavid du Colombier 	[ScLeft]			0xA8,
3457dd7cddfSDavid du Colombier 	[ScRight]			0xA9,
3467dd7cddfSDavid du Colombier 	[ScLeftRight]		0xAA,
3477dd7cddfSDavid du Colombier 	[ScTop]			0xAB,
3487dd7cddfSDavid du Colombier 	[ScBottom] 		0xAC,
3497dd7cddfSDavid du Colombier 	[ScTopBottom]		0xAD,
3507dd7cddfSDavid du Colombier 	[DpBkgdClr]		0xB0,
3517dd7cddfSDavid du Colombier 	[DpFrgdClr]		0xB1,
3527dd7cddfSDavid du Colombier 	[DpWriteMask]		0xB2,
3537dd7cddfSDavid du Colombier 	[DpChainMask]		0xB3,
3547dd7cddfSDavid du Colombier 	[DpPixWidth]		0xB4,
3557dd7cddfSDavid du Colombier 	[DpMix]			0xB5,
3567dd7cddfSDavid du Colombier 	[DpSrc]			0xB6,
3577dd7cddfSDavid du Colombier 	[ClrCmpClr]		0xC0,
3587dd7cddfSDavid du Colombier 	[ClrCmpMask]		0xC1,
3597dd7cddfSDavid du Colombier 	[ClrCmpCntl]		0xC2,
3607dd7cddfSDavid du Colombier 	[FifoStat]			0xC4,
3617dd7cddfSDavid du Colombier 	[ContextMask]		0xC8,
3627dd7cddfSDavid du Colombier 	[GuiTrajCntl]		0xCC,
3637dd7cddfSDavid du Colombier 	[GuiStat]			0xCE,
3649a747e4fSDavid du Colombier 
3659a747e4fSDavid du Colombier 	/* Bank1 */
3669a747e4fSDavid du Colombier 	[OverlayYX]		Bank1 + 0x00,
3679a747e4fSDavid du Colombier 	[OverlayYXEnd]		Bank1 + 0x01,
3689a747e4fSDavid du Colombier 	[OverlayKeyCntl]	Bank1 + 0x06,
3699a747e4fSDavid du Colombier 	[OverlayScaleInc]	Bank1 + 0x08,
3709a747e4fSDavid du Colombier 	[OverlayScaleCntl]	Bank1 + 0x09,
3719a747e4fSDavid du Colombier 	[ScalerHeightWidth]	Bank1 + 0x0A,
3729a747e4fSDavid du Colombier 	[ScalerBuf0Offset]	Bank1 + 0x0D,
3739a747e4fSDavid du Colombier 	[ScalerBuf0Pitch]	Bank1 + 0x0F,
3749a747e4fSDavid du Colombier 	[VideoFormat]		Bank1 + 0x12,
3759a747e4fSDavid du Colombier 	[CaptureConfig]	Bank1 + 0x14,
3769a747e4fSDavid du Colombier 	[Buf0Offset]		Bank1 + 0x20,
3779a747e4fSDavid du Colombier 	[Buf0Pitch]		Bank1 + 0x23,
3789a747e4fSDavid du Colombier 	[ScalerColourCntl]	Bank1 + 0x54,
3799a747e4fSDavid du Colombier 	[ScalerHCoef0]		Bank1 + 0x55,
3809a747e4fSDavid du Colombier 	[ScalerHCoef1]		Bank1 + 0x56,
3819a747e4fSDavid du Colombier 	[ScalerHCoef2]		Bank1 + 0x57,
3829a747e4fSDavid du Colombier 	[ScalerHCoef3]		Bank1 + 0x58,
3839a747e4fSDavid du Colombier 	[ScalerHCoef4]		Bank1 + 0x59,
3847dd7cddfSDavid du Colombier };
3857dd7cddfSDavid du Colombier 
3867dd7cddfSDavid du Colombier static ulong
ior32(VGAscr * scr,int r)3877dd7cddfSDavid du Colombier ior32(VGAscr* scr, int r)
3887dd7cddfSDavid du Colombier {
3897dd7cddfSDavid du Colombier 	if(scr->io == 0x2EC || scr->io == 0x1C8)
3907dd7cddfSDavid du Colombier 		return inl((r<<10)+scr->io);
3917dd7cddfSDavid du Colombier 	if(r >= 0x100 && scr->mmio != nil)
3927dd7cddfSDavid du Colombier 		return scr->mmio[mmoffset[r]];
3937dd7cddfSDavid du Colombier 	return inl((mmoffset[r]<<2)+scr->io);
3947dd7cddfSDavid du Colombier }
3957dd7cddfSDavid du Colombier 
3967dd7cddfSDavid du Colombier static void
iow32(VGAscr * scr,int r,ulong l)3977dd7cddfSDavid du Colombier iow32(VGAscr* scr, int r, ulong l)
3987dd7cddfSDavid du Colombier {
3997dd7cddfSDavid du Colombier 	if(scr->io == 0x2EC || scr->io == 0x1C8)
4007dd7cddfSDavid du Colombier 		outl(((r)<<10)+scr->io, l);
4017dd7cddfSDavid du Colombier 	else if(r >= 0x100 && scr->mmio != nil)
4027dd7cddfSDavid du Colombier 		scr->mmio[mmoffset[r]] = l;
4037dd7cddfSDavid du Colombier 	else
4047dd7cddfSDavid du Colombier 		outl((mmoffset[r]<<2)+scr->io, l);
4057dd7cddfSDavid du Colombier }
4067dd7cddfSDavid du Colombier 
4077dd7cddfSDavid du Colombier static ulong
lcdr32(VGAscr * scr,ulong r)4087dd7cddfSDavid du Colombier lcdr32(VGAscr *scr, ulong r)
4097dd7cddfSDavid du Colombier {
4107dd7cddfSDavid du Colombier 	ulong or;
4117dd7cddfSDavid du Colombier 
4127dd7cddfSDavid du Colombier 	or = ior32(scr, LcdIndex);
4137dd7cddfSDavid du Colombier 	iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
4147dd7cddfSDavid du Colombier 	return ior32(scr, LcdData);
4157dd7cddfSDavid du Colombier }
4167dd7cddfSDavid du Colombier 
4177dd7cddfSDavid du Colombier static void
lcdw32(VGAscr * scr,ulong r,ulong v)4187dd7cddfSDavid du Colombier lcdw32(VGAscr *scr, ulong r, ulong v)
4197dd7cddfSDavid du Colombier {
4207dd7cddfSDavid du Colombier 	ulong or;
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier 	or = ior32(scr, LcdIndex);
4237dd7cddfSDavid du Colombier 	iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
4247dd7cddfSDavid du Colombier 	iow32(scr, LcdData, v);
4257dd7cddfSDavid du Colombier }
4267dd7cddfSDavid du Colombier 
4277dd7cddfSDavid du Colombier static void
mach64xxcurdisable(VGAscr * scr)4287dd7cddfSDavid du Colombier mach64xxcurdisable(VGAscr* scr)
4297dd7cddfSDavid du Colombier {
4307dd7cddfSDavid du Colombier 	ulong r;
4317dd7cddfSDavid du Colombier 
4327dd7cddfSDavid du Colombier 	r = ior32(scr, GenTestCntl);
4337dd7cddfSDavid du Colombier 	iow32(scr, GenTestCntl, r & ~0x80);
4347dd7cddfSDavid du Colombier }
4357dd7cddfSDavid du Colombier 
4367dd7cddfSDavid du Colombier static void
mach64xxcurload(VGAscr * scr,Cursor * curs)4377dd7cddfSDavid du Colombier mach64xxcurload(VGAscr* scr, Cursor* curs)
4387dd7cddfSDavid du Colombier {
4397dd7cddfSDavid du Colombier 	uchar *p;
4407dd7cddfSDavid du Colombier 	int i, y;
4417dd7cddfSDavid du Colombier 	ulong c, s, m, r;
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier 	/*
4447dd7cddfSDavid du Colombier 	 * Disable the cursor.
4457dd7cddfSDavid du Colombier 	 */
4467dd7cddfSDavid du Colombier 	r = ior32(scr, GenTestCntl);
4477dd7cddfSDavid du Colombier 	iow32(scr, GenTestCntl, r & ~0x80);
4487dd7cddfSDavid du Colombier 
4494de34a7eSDavid du Colombier 	p = scr->vaddr;
4507dd7cddfSDavid du Colombier 	p += scr->storage;
4517dd7cddfSDavid du Colombier 
4527dd7cddfSDavid du Colombier 	/*
4537dd7cddfSDavid du Colombier 	 * Initialise the 64x64 cursor RAM array.
4547dd7cddfSDavid du Colombier 	 * The cursor mode gives the following truth table:
4557dd7cddfSDavid du Colombier 	 *	p1 p0	colour
4567dd7cddfSDavid du Colombier 	 *	 0  0	Cursor Colour 0
4577dd7cddfSDavid du Colombier 	 *	 0  1	Cursor Colour 1
4587dd7cddfSDavid du Colombier 	 *	 1  0	Transparent
4597dd7cddfSDavid du Colombier 	 *	 1  1	Complement
4607dd7cddfSDavid du Colombier 	 * Put the cursor into the top-right of the 64x64 array.
4617dd7cddfSDavid du Colombier 	 */
4627dd7cddfSDavid du Colombier 	for(y = 0; y < 16; y++){
4637dd7cddfSDavid du Colombier 		for(i = 0; i < (64-16)/8; i++){
4647dd7cddfSDavid du Colombier 			*p++ = 0xAA;
4657dd7cddfSDavid du Colombier 			*p++ = 0xAA;
4667dd7cddfSDavid du Colombier 		}
4677dd7cddfSDavid du Colombier 
4687dd7cddfSDavid du Colombier 		c = (curs->clr[2*y]<<8)|curs->clr[y*2 + 1];
4697dd7cddfSDavid du Colombier 		s = (curs->set[2*y]<<8)|curs->set[y*2 + 1];
4707dd7cddfSDavid du Colombier 
4717dd7cddfSDavid du Colombier 		m = 0x00000000;
4727dd7cddfSDavid du Colombier 		for(i = 0; i < 16; i++){
4737dd7cddfSDavid du Colombier 			if(s & (1<<(15-i)))
4747dd7cddfSDavid du Colombier 				m |= 0x01<<(2*i);
4759a747e4fSDavid du Colombier 			else if(c & (1<<(15-i))){
4769a747e4fSDavid du Colombier 				/* nothing to do */
4779a747e4fSDavid du Colombier 			}
4787dd7cddfSDavid du Colombier 			else
4797dd7cddfSDavid du Colombier 				m |= 0x02<<(2*i);
4807dd7cddfSDavid du Colombier 		}
4817dd7cddfSDavid du Colombier 		*p++ = m;
4827dd7cddfSDavid du Colombier 		*p++ = m>>8;
4837dd7cddfSDavid du Colombier 		*p++ = m>>16;
4847dd7cddfSDavid du Colombier 		*p++ = m>>24;
4857dd7cddfSDavid du Colombier 	}
4867dd7cddfSDavid du Colombier 	memset(p, 0xAA, (64-16)*16);
4877dd7cddfSDavid du Colombier 
4887dd7cddfSDavid du Colombier 	/*
4897dd7cddfSDavid du Colombier 	 * Set the cursor hotpoint and enable the cursor.
4907dd7cddfSDavid du Colombier 	 */
4917dd7cddfSDavid du Colombier 	scr->offset = curs->offset;
4927dd7cddfSDavid du Colombier 	iow32(scr, GenTestCntl, 0x80|r);
4937dd7cddfSDavid du Colombier }
4947dd7cddfSDavid du Colombier 
4957dd7cddfSDavid du Colombier static int
ptalmostinrect(Point p,Rectangle r)4967dd7cddfSDavid du Colombier ptalmostinrect(Point p, Rectangle r)
4977dd7cddfSDavid du Colombier {
4987dd7cddfSDavid du Colombier 	return p.x>=r.min.x && p.x<=r.max.x &&
4997dd7cddfSDavid du Colombier 	       p.y>=r.min.y && p.y<=r.max.y;
5007dd7cddfSDavid du Colombier }
5017dd7cddfSDavid du Colombier 
5027dd7cddfSDavid du Colombier /*
5037dd7cddfSDavid du Colombier  * If necessary, translate the rectangle physr
5047dd7cddfSDavid du Colombier  * some multiple of [dx dy] so that it includes p.
5057dd7cddfSDavid du Colombier  * Return 1 if the rectangle changed.
5067dd7cddfSDavid du Colombier  */
5077dd7cddfSDavid du Colombier static int
screenpan(Point p,Rectangle * physr,int dx,int dy)5087dd7cddfSDavid du Colombier screenpan(Point p, Rectangle *physr, int dx, int dy)
5097dd7cddfSDavid du Colombier {
5107dd7cddfSDavid du Colombier 	int d;
5117dd7cddfSDavid du Colombier 
5127dd7cddfSDavid du Colombier 	if(ptalmostinrect(p, *physr))
5137dd7cddfSDavid du Colombier 		return 0;
5147dd7cddfSDavid du Colombier 
5157dd7cddfSDavid du Colombier 	if(p.y < physr->min.y){
5167dd7cddfSDavid du Colombier 		d = physr->min.y - (p.y&~(dy-1));
5177dd7cddfSDavid du Colombier 		physr->min.y -= d;
5187dd7cddfSDavid du Colombier 		physr->max.y -= d;
5197dd7cddfSDavid du Colombier 	}
5207dd7cddfSDavid du Colombier 	if(p.y > physr->max.y){
5217dd7cddfSDavid du Colombier 		d = ((p.y+dy-1)&~(dy-1)) - physr->max.y;
5227dd7cddfSDavid du Colombier 		physr->min.y += d;
5237dd7cddfSDavid du Colombier 		physr->max.y += d;
5247dd7cddfSDavid du Colombier 	}
5257dd7cddfSDavid du Colombier 
5267dd7cddfSDavid du Colombier 	if(p.x < physr->min.x){
5277dd7cddfSDavid du Colombier 		d = physr->min.x - (p.x&~(dx-1));
5287dd7cddfSDavid du Colombier 		physr->min.x -= d;
5297dd7cddfSDavid du Colombier 		physr->max.x -= d;
5307dd7cddfSDavid du Colombier 	}
5317dd7cddfSDavid du Colombier 	if(p.x > physr->max.x){
5327dd7cddfSDavid du Colombier 		d = ((p.x+dx-1)&~(dx-1)) - physr->max.x;
5337dd7cddfSDavid du Colombier 		physr->min.x += d;
5347dd7cddfSDavid du Colombier 		physr->max.x += d;
5357dd7cddfSDavid du Colombier 	}
5367dd7cddfSDavid du Colombier 	return 1;
5377dd7cddfSDavid du Colombier }
5387dd7cddfSDavid du Colombier 
5397dd7cddfSDavid du Colombier static int
mach64xxcurmove(VGAscr * scr,Point p)5407dd7cddfSDavid du Colombier mach64xxcurmove(VGAscr* scr, Point p)
5417dd7cddfSDavid du Colombier {
5427dd7cddfSDavid du Colombier 	int x, xo, y, yo;
5437dd7cddfSDavid du Colombier 	int dx;
5447dd7cddfSDavid du Colombier 	ulong off, pitch;
5457dd7cddfSDavid du Colombier 
5467dd7cddfSDavid du Colombier 	/*
5477dd7cddfSDavid du Colombier 	 * If the point we want to display is outside the current
5487dd7cddfSDavid du Colombier 	 * screen rectangle, pan the screen to display it.
5497dd7cddfSDavid du Colombier 	 *
5507dd7cddfSDavid du Colombier 	 * We have to move in 64-bit chunks.
5517dd7cddfSDavid du Colombier 	 */
5527dd7cddfSDavid du Colombier 	if(scr->gscreen->depth == 24)
5537dd7cddfSDavid du Colombier 		dx = (64*3)/24;
5547dd7cddfSDavid du Colombier 	else
5557dd7cddfSDavid du Colombier 		dx = 64 / scr->gscreen->depth;
5567dd7cddfSDavid du Colombier 
5579a747e4fSDavid du Colombier 	if(panning && screenpan(p, &physgscreenr, dx, 1)){
5587dd7cddfSDavid du Colombier 		off = (physgscreenr.min.y*Dx(scr->gscreen->r)+physgscreenr.min.x)/dx;
5597dd7cddfSDavid du Colombier 		pitch = Dx(scr->gscreen->r)/8;
5607dd7cddfSDavid du Colombier 		iow32(scr, CrtcOffPitch, (pitch<<22)|off);
5617dd7cddfSDavid du Colombier 	}
5627dd7cddfSDavid du Colombier 
5637dd7cddfSDavid du Colombier 	p.x -= physgscreenr.min.x;
5647dd7cddfSDavid du Colombier 	p.y -= physgscreenr.min.y;
5657dd7cddfSDavid du Colombier 
5667dd7cddfSDavid du Colombier 	/*
5677dd7cddfSDavid du Colombier 	 * Mustn't position the cursor offscreen even partially,
5687dd7cddfSDavid du Colombier 	 * or it disappears. Therefore, if x or y is -ve, adjust the
5697dd7cddfSDavid du Colombier 	 * cursor presets instead. If y is negative also have to
5707dd7cddfSDavid du Colombier 	 * adjust the starting offset.
5717dd7cddfSDavid du Colombier 	 */
5727dd7cddfSDavid du Colombier 	if((x = p.x+scr->offset.x) < 0){
5737dd7cddfSDavid du Colombier 		xo = x;
5747dd7cddfSDavid du Colombier 		x = 0;
5757dd7cddfSDavid du Colombier 	}
5767dd7cddfSDavid du Colombier 	else
5777dd7cddfSDavid du Colombier 		xo = 0;
5787dd7cddfSDavid du Colombier 	if((y = p.y+scr->offset.y) < 0){
5797dd7cddfSDavid du Colombier 		yo = y;
5807dd7cddfSDavid du Colombier 		y = 0;
5817dd7cddfSDavid du Colombier 	}
5827dd7cddfSDavid du Colombier 	else
5837dd7cddfSDavid du Colombier 		yo = 0;
5847dd7cddfSDavid du Colombier 
5857dd7cddfSDavid du Colombier 	iow32(scr, CurHVoff, ((64-16-yo)<<16)|(64-16-xo));
5867dd7cddfSDavid du Colombier 	iow32(scr, CurOffset, scr->storage/8 + (-yo*2));
5877dd7cddfSDavid du Colombier 	iow32(scr, CurHVposn, (y<<16)|x);
5887dd7cddfSDavid du Colombier 
5897dd7cddfSDavid du Colombier 	return 0;
5907dd7cddfSDavid du Colombier }
5917dd7cddfSDavid du Colombier 
5927dd7cddfSDavid du Colombier static void
mach64xxcurenable(VGAscr * scr)5937dd7cddfSDavid du Colombier mach64xxcurenable(VGAscr* scr)
5947dd7cddfSDavid du Colombier {
5957dd7cddfSDavid du Colombier 	ulong r, storage;
5967dd7cddfSDavid du Colombier 
5977dd7cddfSDavid du Colombier 	mach64xxenable(scr);
5987dd7cddfSDavid du Colombier 	if(scr->io == 0)
5997dd7cddfSDavid du Colombier 		return;
6007dd7cddfSDavid du Colombier 
6017dd7cddfSDavid du Colombier 	r = ior32(scr, GenTestCntl);
6027dd7cddfSDavid du Colombier 	iow32(scr, GenTestCntl, r & ~0x80);
6037dd7cddfSDavid du Colombier 
6047dd7cddfSDavid du Colombier 	iow32(scr, CurClr0, (Pwhite<<24)|(Pwhite<<16)|(Pwhite<<8)|Pwhite);
6057dd7cddfSDavid du Colombier 	iow32(scr, CurClr1, (Pblack<<24)|(Pblack<<16)|(Pblack<<8)|Pblack);
6067dd7cddfSDavid du Colombier 
6077dd7cddfSDavid du Colombier 	/*
6087dd7cddfSDavid du Colombier 	 * Find a place for the cursor data in display memory.
6097dd7cddfSDavid du Colombier 	 * Must be 64-bit aligned.
6107dd7cddfSDavid du Colombier 	 */
6117dd7cddfSDavid du Colombier 	storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+7)/8;
6127dd7cddfSDavid du Colombier 	iow32(scr, CurOffset, storage);
6137dd7cddfSDavid du Colombier 	scr->storage = storage*8;
6147dd7cddfSDavid du Colombier 
6157dd7cddfSDavid du Colombier 	/*
6167dd7cddfSDavid du Colombier 	 * Cursor goes in the top right corner of the 64x64 array
6177dd7cddfSDavid du Colombier 	 * so the horizontal and vertical presets are 64-16.
6187dd7cddfSDavid du Colombier 	 */
6197dd7cddfSDavid du Colombier 	iow32(scr, CurHVposn, (0<<16)|0);
6207dd7cddfSDavid du Colombier 	iow32(scr, CurHVoff, ((64-16)<<16)|(64-16));
6217dd7cddfSDavid du Colombier 
6227dd7cddfSDavid du Colombier 	/*
6237dd7cddfSDavid du Colombier 	 * Load, locate and enable the 64x64 cursor.
6247dd7cddfSDavid du Colombier 	 */
6257dd7cddfSDavid du Colombier 	mach64xxcurload(scr, &arrow);
6267dd7cddfSDavid du Colombier 	mach64xxcurmove(scr, ZP);
6277dd7cddfSDavid du Colombier 	iow32(scr, GenTestCntl, 0x80|r);
6287dd7cddfSDavid du Colombier }
6297dd7cddfSDavid du Colombier 
6307dd7cddfSDavid du Colombier static void
waitforfifo(VGAscr * scr,int entries)6317dd7cddfSDavid du Colombier waitforfifo(VGAscr *scr, int entries)
6327dd7cddfSDavid du Colombier {
6337dd7cddfSDavid du Colombier 	int x;
63459c21d95SDavid du Colombier 
6357dd7cddfSDavid du Colombier 	x = 0;
6367dd7cddfSDavid du Colombier 	while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000)
6377dd7cddfSDavid du Colombier 		;
6387dd7cddfSDavid du Colombier 	if(x >= 1000000)
639567483c8SDavid du Colombier 		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));
6407dd7cddfSDavid du Colombier }
6417dd7cddfSDavid du Colombier 
6427dd7cddfSDavid du Colombier static void
waitforidle(VGAscr * scr)6437dd7cddfSDavid du Colombier waitforidle(VGAscr *scr)
6447dd7cddfSDavid du Colombier {
6457dd7cddfSDavid du Colombier 	int x;
64659c21d95SDavid du Colombier 
6477dd7cddfSDavid du Colombier 	waitforfifo(scr, 16);
6487dd7cddfSDavid du Colombier 	x = 0;
6497dd7cddfSDavid du Colombier 	while((ior32(scr, GuiStat)&1) && x++ < 1000000)
6507dd7cddfSDavid du Colombier 		;
6517dd7cddfSDavid du Colombier 	if(x >= 1000000)
652567483c8SDavid du Colombier 		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));
6537dd7cddfSDavid du Colombier }
6547dd7cddfSDavid du Colombier 
6557dd7cddfSDavid du Colombier static void
resetengine(VGAscr * scr)6567dd7cddfSDavid du Colombier resetengine(VGAscr *scr)
6577dd7cddfSDavid du Colombier {
6587dd7cddfSDavid du Colombier 	ulong x;
6597dd7cddfSDavid du Colombier 	x = ior32(scr, GenTestCntl);
6607dd7cddfSDavid du Colombier 	iow32(scr, GenTestCntl, x&~0x100);
6617dd7cddfSDavid du Colombier 	iow32(scr, GenTestCntl, x|0x100);
6627dd7cddfSDavid du Colombier 	iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000);
6637dd7cddfSDavid du Colombier }
6647dd7cddfSDavid du Colombier 
6657dd7cddfSDavid du Colombier static void
init_overlayclock(VGAscr * scr)6669a747e4fSDavid du Colombier init_overlayclock(VGAscr *scr)
6679a747e4fSDavid du Colombier {
6689a747e4fSDavid du Colombier 	uchar *cc, save, pll_ref_div, pll_vclk_cntl, vclk_post_div,
6699a747e4fSDavid du Colombier 			vclk_fb_div, ecp_div;
6709a747e4fSDavid du Colombier 	int i;
6719a747e4fSDavid du Colombier 	ulong dotclock;
6729a747e4fSDavid du Colombier 
6739a747e4fSDavid du Colombier 	/* Taken from GLX */
6749a747e4fSDavid du Colombier 	/* Get monitor dotclock, check for Overlay Scaler clock limit */
6759a747e4fSDavid du Colombier  	cc = (uchar *)&scr->mmio[mmoffset[ClockCntl]];
6769a747e4fSDavid du Colombier   	save = cc[1]; i = cc[0] & 3;
6779a747e4fSDavid du Colombier   	cc[1] = 2<<2; pll_ref_div = cc[2];
6789a747e4fSDavid du Colombier   	cc[1] = 5<<2; pll_vclk_cntl = cc[2];
6799a747e4fSDavid du Colombier   	cc[1] = 6<<2; vclk_post_div = (cc[2]>>(i+i)) & 3;
6809a747e4fSDavid du Colombier   	cc[1] = (7+i)<<2; vclk_fb_div = cc[2];
6819a747e4fSDavid du Colombier 
6829a747e4fSDavid du Colombier 	dotclock = 2 * mach64refclock * vclk_fb_div /
6839a747e4fSDavid du Colombier 			(pll_ref_div * (1 << vclk_post_div));
6849a747e4fSDavid du Colombier 	/* ecp_div: 0=dotclock, 1=dotclock/2, 2=dotclock/4 */
6859a747e4fSDavid du Colombier   	ecp_div = dotclock / mach64type->m64_ovlclock;
6869a747e4fSDavid du Colombier   	if (ecp_div>2) ecp_div = 2;
6879a747e4fSDavid du Colombier 
6889a747e4fSDavid du Colombier   	/* Force a scaler clock factor of 1 if refclock *
6899a747e4fSDavid du Colombier    	  * is unknown (VCLK_SRC not PLLVCLK)  */
6909a747e4fSDavid du Colombier   	if ((pll_vclk_cntl & 0x03) != 0x03)
6919a747e4fSDavid du Colombier 		ecp_div = 0;
6929a747e4fSDavid du Colombier   	if ((pll_vclk_cntl & 0x30) != ecp_div<<4) {
6939a747e4fSDavid du Colombier     		cc[1] = (5<<2)|2;
6949a747e4fSDavid du Colombier     		cc[2] = (pll_vclk_cntl&0xCF) | (ecp_div<<4);
6959a747e4fSDavid du Colombier 	}
6969a747e4fSDavid du Colombier 
6979a747e4fSDavid du Colombier   	/* Restore PLL Register Index */
6989a747e4fSDavid du Colombier   	cc[1] = save;
6999a747e4fSDavid du Colombier }
7009a747e4fSDavid du Colombier 
7019a747e4fSDavid du Colombier static void
initengine(VGAscr * scr)7027dd7cddfSDavid du Colombier initengine(VGAscr *scr)
7037dd7cddfSDavid du Colombier {
7047dd7cddfSDavid du Colombier 	ulong pitch;
7059a747e4fSDavid du Colombier 	uchar *bios;
7069a747e4fSDavid du Colombier 	ushort table;
7077dd7cddfSDavid du Colombier 
7087dd7cddfSDavid du Colombier 	pitch = Dx(scr->gscreen->r)/8;
7097dd7cddfSDavid du Colombier 	if(scr->gscreen->depth == 24)
7107dd7cddfSDavid du Colombier 		pitch *= 3;
7117dd7cddfSDavid du Colombier 
7127dd7cddfSDavid du Colombier 	resetengine(scr);
7137dd7cddfSDavid du Colombier 	waitforfifo(scr, 14);
7147dd7cddfSDavid du Colombier 	iow32(scr, ContextMask, ~0);
7157dd7cddfSDavid du Colombier 	iow32(scr, DstOffPitch, pitch<<22);
7167dd7cddfSDavid du Colombier 	iow32(scr, DstYX, 0);
7177dd7cddfSDavid du Colombier 	iow32(scr, DstHeight, 0);
7187dd7cddfSDavid du Colombier 	iow32(scr, DstBresErr, 0);
7197dd7cddfSDavid du Colombier 	iow32(scr, DstBresInc, 0);
7207dd7cddfSDavid du Colombier 	iow32(scr, DstBresDec, 0);
7217dd7cddfSDavid du Colombier 	iow32(scr, DstCntl, 0x23);
7227dd7cddfSDavid du Colombier 	iow32(scr, SrcOffPitch, pitch<<22);
7237dd7cddfSDavid du Colombier 	iow32(scr, SrcYX, 0);
7247dd7cddfSDavid du Colombier 	iow32(scr, SrcHeight1Width1, 1);
7257dd7cddfSDavid du Colombier 	iow32(scr, SrcYXstart, 0);
7267dd7cddfSDavid du Colombier 	iow32(scr, SrcHeight2Width2, 1);
7277dd7cddfSDavid du Colombier 	iow32(scr, SrcCntl, 0x01);
7287dd7cddfSDavid du Colombier 
7297dd7cddfSDavid du Colombier 	waitforfifo(scr, 13);
7307dd7cddfSDavid du Colombier 	iow32(scr, HostCntl, 0);
7317dd7cddfSDavid du Colombier 	iow32(scr, PatReg0, 0);
7327dd7cddfSDavid du Colombier 	iow32(scr, PatReg1, 0);
7337dd7cddfSDavid du Colombier 	iow32(scr, PatCntl, 0);
7347dd7cddfSDavid du Colombier 	iow32(scr, ScLeft, 0);
7357dd7cddfSDavid du Colombier 	iow32(scr, ScTop, 0);
7367dd7cddfSDavid du Colombier 	iow32(scr, ScBottom, 0xFFFF);
7377dd7cddfSDavid du Colombier 	iow32(scr, ScRight, 0xFFFF);
7387dd7cddfSDavid du Colombier 	iow32(scr, DpBkgdClr, 0);
7397dd7cddfSDavid du Colombier 	iow32(scr, DpFrgdClr, ~0);
7407dd7cddfSDavid du Colombier 	iow32(scr, DpWriteMask, ~0);
7417dd7cddfSDavid du Colombier 	iow32(scr, DpMix, 0x70003);
7427dd7cddfSDavid du Colombier 	iow32(scr, DpSrc, 0x00010100);
7437dd7cddfSDavid du Colombier 
7447dd7cddfSDavid du Colombier 	waitforfifo(scr, 3);
7457dd7cddfSDavid du Colombier 	iow32(scr, ClrCmpClr, 0);
7467dd7cddfSDavid du Colombier 	iow32(scr, ClrCmpMask, ~0);
7477dd7cddfSDavid du Colombier 	iow32(scr, ClrCmpCntl, 0);
7487dd7cddfSDavid du Colombier 
7497dd7cddfSDavid du Colombier 	waitforfifo(scr, 2);
7507dd7cddfSDavid du Colombier 	switch(scr->gscreen->depth){
7517dd7cddfSDavid du Colombier 	case 8:
7527dd7cddfSDavid du Colombier 	case 24:	/* [sic] */
7537dd7cddfSDavid du Colombier 		iow32(scr, DpPixWidth, 0x00020202);
7547dd7cddfSDavid du Colombier 		iow32(scr, DpChainMask, 0x8080);
7557dd7cddfSDavid du Colombier 		break;
7567dd7cddfSDavid du Colombier 	case 16:
7577dd7cddfSDavid du Colombier 		iow32(scr, DpPixWidth, 0x00040404);
7587dd7cddfSDavid du Colombier 		iow32(scr, DpChainMask, 0x8410);
7597dd7cddfSDavid du Colombier 		break;
7607dd7cddfSDavid du Colombier 	case 32:
7617dd7cddfSDavid du Colombier 		iow32(scr, DpPixWidth, 0x00060606);
7627dd7cddfSDavid du Colombier 		iow32(scr, DpChainMask, 0x8080);
7637dd7cddfSDavid du Colombier 		break;
7647dd7cddfSDavid du Colombier 	}
7657dd7cddfSDavid du Colombier 
7669a747e4fSDavid du Colombier 	/* Get the base freq from the BIOS */
7674de34a7eSDavid du Colombier 	bios  = kaddr(0xC000);
7689a747e4fSDavid du Colombier 	table = *(ushort *)(bios + 0x48);
7699a747e4fSDavid du Colombier 	table = *(ushort *)(bios + table + 0x10);
7709a747e4fSDavid du Colombier 	switch (*(ushort *)(bios + table + 0x08)) {
7719a747e4fSDavid du Colombier       	case 2700:
7729a747e4fSDavid du Colombier 		mach64refclock = 270000;
7739a747e4fSDavid du Colombier 		break;
7749a747e4fSDavid du Colombier       	case 2863:
7759a747e4fSDavid du Colombier       	case 2864:
7769a747e4fSDavid du Colombier 		mach64refclock = 286363;
7779a747e4fSDavid du Colombier 		break;
7789a747e4fSDavid du Colombier       	case 2950:
7799a747e4fSDavid du Colombier 		mach64refclock = 294989;
7809a747e4fSDavid du Colombier 		break;
7819a747e4fSDavid du Colombier     	case 1432:
7829a747e4fSDavid du Colombier 	default:
7839a747e4fSDavid du Colombier 		mach64refclock = 143181;
7849a747e4fSDavid du Colombier 		break ;
7859a747e4fSDavid du Colombier 	}
7869a747e4fSDavid du Colombier 
7879a747e4fSDavid du Colombier 	/* Figure out which revision this chip is */
7889a747e4fSDavid du Colombier 	switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) {
7899a747e4fSDavid du Colombier 	case VTGTB1S1:
7909a747e4fSDavid du Colombier 	case GTB1U1:
7919a747e4fSDavid du Colombier 	case GTB1S2:
7929a747e4fSDavid du Colombier 	case GTB2U1:
7939a747e4fSDavid du Colombier 	case GTB2U2:
7949a747e4fSDavid du Colombier 	case GTB2U3:
7959a747e4fSDavid du Colombier 	case GTBC:
7969a747e4fSDavid du Colombier 	case GTIIIC1U1:
7979a747e4fSDavid du Colombier 	case GTIIIC1U2:
7989a747e4fSDavid du Colombier 	case GTIIIC2U1:
7999a747e4fSDavid du Colombier 	case GTIIIC2U2:
8009a747e4fSDavid du Colombier 	case GTIIIC2U3:
8019a747e4fSDavid du Colombier 	case LTPRO:
8029a747e4fSDavid du Colombier 			mach64revb = 1;
8039a747e4fSDavid du Colombier 			break;
8049a747e4fSDavid du Colombier 	default:
8059a747e4fSDavid du Colombier 			mach64revb = 0;
8069a747e4fSDavid du Colombier 			break;
8079a747e4fSDavid du Colombier 	}
8089a747e4fSDavid du Colombier 
8097dd7cddfSDavid du Colombier 	waitforidle(scr);
8107dd7cddfSDavid du Colombier }
8117dd7cddfSDavid du Colombier 
8127dd7cddfSDavid du Colombier static int
mach64hwfill(VGAscr * scr,Rectangle r,ulong sval)8137dd7cddfSDavid du Colombier mach64hwfill(VGAscr *scr, Rectangle r, ulong sval)
8147dd7cddfSDavid du Colombier {
8157dd7cddfSDavid du Colombier 	ulong pitch;
8167dd7cddfSDavid du Colombier 	ulong ctl;
8177dd7cddfSDavid du Colombier 
8187dd7cddfSDavid du Colombier if(drawdebug)
8197dd7cddfSDavid du Colombier 	iprint("hwfill %R val %lux...\n", r, sval);
8207dd7cddfSDavid du Colombier 
8217dd7cddfSDavid du Colombier 	/* shouldn't happen */
8227dd7cddfSDavid du Colombier 	if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0)
8237dd7cddfSDavid du Colombier 		return 0;
8247dd7cddfSDavid du Colombier 
8257dd7cddfSDavid du Colombier 	pitch = Dx(scr->gscreen->r)/8;
8267dd7cddfSDavid du Colombier 	ctl = 1|2;	/* left-to-right, top-to-bottom */
8277dd7cddfSDavid du Colombier 	if(scr->gscreen->depth == 24){
8287dd7cddfSDavid du Colombier 		r.min.x *= 3;
8297dd7cddfSDavid du Colombier 		r.max.x *= 3;
8307dd7cddfSDavid du Colombier 		pitch *= 3;
8317dd7cddfSDavid du Colombier 		ctl |= (1<<7)|(((r.min.x/4)%6)<<8);
8327dd7cddfSDavid du Colombier 	}
8337dd7cddfSDavid du Colombier 
8347dd7cddfSDavid du Colombier 	waitforfifo(scr, 11);
8357dd7cddfSDavid du Colombier 	iow32(scr, DpFrgdClr, sval);
8367dd7cddfSDavid du Colombier 	iow32(scr, DpWriteMask, 0xFFFFFFFF);
8377dd7cddfSDavid du Colombier 	iow32(scr, DpMix, 0x00070003);
8387dd7cddfSDavid du Colombier 	iow32(scr, DpSrc, 0x00000111);
8397dd7cddfSDavid du Colombier 	iow32(scr, ClrCmpCntl, 0x00000000);
8407dd7cddfSDavid du Colombier 	iow32(scr, ScLeftRight, 0x1FFF0000);
8417dd7cddfSDavid du Colombier 	iow32(scr, ScTopBottom, 0x1FFF0000);
8427dd7cddfSDavid du Colombier 	iow32(scr, DstOffPitch, pitch<<22);
8437dd7cddfSDavid du Colombier 	iow32(scr, DstCntl, ctl);
8447dd7cddfSDavid du Colombier 	iow32(scr, DstYX, (r.min.x<<16)|r.min.y);
8457dd7cddfSDavid du Colombier 	iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r));
8467dd7cddfSDavid du Colombier 
8477dd7cddfSDavid du Colombier 	waitforidle(scr);
8487dd7cddfSDavid du Colombier 	return 1;
8497dd7cddfSDavid du Colombier }
8507dd7cddfSDavid du Colombier 
8517dd7cddfSDavid du Colombier static int
mach64hwscroll(VGAscr * scr,Rectangle r,Rectangle sr)8527dd7cddfSDavid du Colombier mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
8537dd7cddfSDavid du Colombier {
8547dd7cddfSDavid du Colombier 	ulong pitch;
8557dd7cddfSDavid du Colombier 	Point dp, sp;
8567dd7cddfSDavid du Colombier 	ulong ctl;
8577dd7cddfSDavid du Colombier 	int dx, dy;
8587dd7cddfSDavid du Colombier 
8597dd7cddfSDavid du Colombier 	dx = Dx(r);
8607dd7cddfSDavid du Colombier 	dy = Dy(r);
8617dd7cddfSDavid du Colombier 	pitch = Dx(scr->gscreen->r)/8;
8627dd7cddfSDavid du Colombier 	if(scr->gscreen->depth == 24){
8637dd7cddfSDavid du Colombier 		dx *= 3;
8647dd7cddfSDavid du Colombier 		pitch *= 3;
8657dd7cddfSDavid du Colombier 		r.min.x *= 3;
8667dd7cddfSDavid du Colombier 		sr.min.x *= 3;
8677dd7cddfSDavid du Colombier 	}
8687dd7cddfSDavid du Colombier 
8697dd7cddfSDavid du Colombier 	ctl = 0;
8707dd7cddfSDavid du Colombier 	if(r.min.x <= sr.min.x){
8717dd7cddfSDavid du Colombier 		ctl |= 1;
8727dd7cddfSDavid du Colombier 		dp.x = r.min.x;
8737dd7cddfSDavid du Colombier 		sp.x = sr.min.x;
8747dd7cddfSDavid du Colombier 	}else{
8757dd7cddfSDavid du Colombier 		dp.x = r.min.x+dx-1;
8767dd7cddfSDavid du Colombier 		sp.x = sr.min.x+dx-1;
8777dd7cddfSDavid du Colombier 	}
8787dd7cddfSDavid du Colombier 
8797dd7cddfSDavid du Colombier 	if(r.min.y <= sr.min.y){
8807dd7cddfSDavid du Colombier 		ctl |= 2;
8817dd7cddfSDavid du Colombier 		dp.y = r.min.y;
8827dd7cddfSDavid du Colombier 		sp.y = sr.min.y;
8837dd7cddfSDavid du Colombier 	}else{
8847dd7cddfSDavid du Colombier 		dp.y = r.min.y+dy-1;
8857dd7cddfSDavid du Colombier 		sp.y = sr.min.y+dy-1;
8867dd7cddfSDavid du Colombier 	}
8877dd7cddfSDavid du Colombier 
8887dd7cddfSDavid du Colombier 	if(scr->gscreen->depth == 24)
8897dd7cddfSDavid du Colombier 		ctl |= (1<<7)|(((dp.x/4)%6)<<8);
8907dd7cddfSDavid du Colombier 
8917dd7cddfSDavid du Colombier 	waitforfifo(scr, 6);
8927dd7cddfSDavid du Colombier 	iow32(scr, ScLeftRight, 0x1FFF0000);
8937dd7cddfSDavid du Colombier 	iow32(scr, ScTopBottom, 0x1FFF0000);
8947dd7cddfSDavid du Colombier 	iow32(scr, DpWriteMask, 0xFFFFFFFF);
8957dd7cddfSDavid du Colombier 	iow32(scr, DpMix, 0x00070003);
8967dd7cddfSDavid du Colombier 	iow32(scr, DpSrc, 0x00000300);
8977dd7cddfSDavid du Colombier 	iow32(scr, ClrCmpCntl, 0x00000000);
8987dd7cddfSDavid du Colombier 
8997dd7cddfSDavid du Colombier 	waitforfifo(scr, 8);
9007dd7cddfSDavid du Colombier 	iow32(scr, SrcOffPitch, pitch<<22);
9017dd7cddfSDavid du Colombier 	iow32(scr, SrcCntl, 0x00000000);
9027dd7cddfSDavid du Colombier 	iow32(scr, SrcYX, (sp.x<<16)|sp.y);
9037dd7cddfSDavid du Colombier 	iow32(scr, SrcWidth1, dx);
9047dd7cddfSDavid du Colombier 	iow32(scr, DstOffPitch, pitch<<22);
9057dd7cddfSDavid du Colombier 	iow32(scr, DstCntl, ctl);
9067dd7cddfSDavid du Colombier 
9077dd7cddfSDavid du Colombier 	iow32(scr, DstYX, (dp.x<<16)|dp.y);
9087dd7cddfSDavid du Colombier 	iow32(scr, DstHeightWidth, (dx<<16)|dy);
9097dd7cddfSDavid du Colombier 
9107dd7cddfSDavid du Colombier 	waitforidle(scr);
9117dd7cddfSDavid du Colombier 
9127dd7cddfSDavid du Colombier 	return 1;
9137dd7cddfSDavid du Colombier }
9147dd7cddfSDavid du Colombier 
9157dd7cddfSDavid du Colombier /*
9167dd7cddfSDavid du Colombier  * This should work, but doesn't.
9177dd7cddfSDavid du Colombier  * It messes up the screen timings for some reason.
9187dd7cddfSDavid du Colombier  */
9197dd7cddfSDavid du Colombier static void
mach64blank(VGAscr * scr,int blank)9207dd7cddfSDavid du Colombier mach64blank(VGAscr *scr, int blank)
9217dd7cddfSDavid du Colombier {
9227dd7cddfSDavid du Colombier 	ulong ctl;
9237dd7cddfSDavid du Colombier 
9247dd7cddfSDavid du Colombier 	ctl = ior32(scr, CrtcGenCtl) & ~(CrtcHsyncDis|CrtcVsyncDis);
9257dd7cddfSDavid du Colombier 	if(blank)
9267dd7cddfSDavid du Colombier 		ctl |= CrtcHsyncDis|CrtcVsyncDis;
9277dd7cddfSDavid du Colombier 	iow32(scr, CrtcGenCtl, ctl);
9287dd7cddfSDavid du Colombier }
9297dd7cddfSDavid du Colombier 
9307dd7cddfSDavid du Colombier /*
9317dd7cddfSDavid du Colombier  * We squirrel away whether the LCD and/or CRT were
9327dd7cddfSDavid du Colombier  * on when we were called to blank the screen, and
9337dd7cddfSDavid du Colombier  * restore the old state.  If we are called to blank the
9347dd7cddfSDavid du Colombier  * screen when it is already blank, we don't update the state.
9357dd7cddfSDavid du Colombier  * Such a call sequence should not happen, though.
9367dd7cddfSDavid du Colombier  *
9377dd7cddfSDavid du Colombier  * We could try forcing the chip into power management
9387dd7cddfSDavid du Colombier  * mode instead, but I'm not sure how that would interact
9397dd7cddfSDavid du Colombier  * with screen updates going on while the screen is blanked.
9407dd7cddfSDavid du Colombier  */
9417dd7cddfSDavid du Colombier static void
mach64lcdblank(VGAscr * scr,int blank)9427dd7cddfSDavid du Colombier mach64lcdblank(VGAscr *scr, int blank)
9437dd7cddfSDavid du Colombier {
9447dd7cddfSDavid du Colombier 	static int crtlcd;
9457dd7cddfSDavid du Colombier 	ulong x;
9467dd7cddfSDavid du Colombier 
9477dd7cddfSDavid du Colombier 	if(blank) {
9487dd7cddfSDavid du Colombier 		x = lcdr32(scr, LCD_GenCtrl);
9497dd7cddfSDavid du Colombier 		if(x & 3) {
9507dd7cddfSDavid du Colombier 			crtlcd = x & 3;
9517dd7cddfSDavid du Colombier 			lcdw32(scr, LCD_GenCtrl,  x&~3);
9527dd7cddfSDavid du Colombier 		}
9537dd7cddfSDavid du Colombier 	} else {
9547dd7cddfSDavid du Colombier 		if(crtlcd == 0)
9557dd7cddfSDavid du Colombier 			crtlcd = 2;	/* lcd only */
9567dd7cddfSDavid du Colombier 		x = lcdr32(scr, LCD_GenCtrl);
9577dd7cddfSDavid du Colombier 		lcdw32(scr, LCD_GenCtrl, x | crtlcd);
9587dd7cddfSDavid du Colombier 	}
9597dd7cddfSDavid du Colombier }
9607dd7cddfSDavid du Colombier 
9617dd7cddfSDavid du Colombier static void
mach64xxdrawinit(VGAscr * scr)9627dd7cddfSDavid du Colombier mach64xxdrawinit(VGAscr *scr)
9637dd7cddfSDavid du Colombier {
9647dd7cddfSDavid du Colombier 	if(scr->io > 0x2FF){
9657dd7cddfSDavid du Colombier 		initengine(scr);
9667dd7cddfSDavid du Colombier 		scr->fill = mach64hwfill;
9677dd7cddfSDavid du Colombier 		scr->scroll = mach64hwscroll;
9687dd7cddfSDavid du Colombier 	}
9697dd7cddfSDavid du Colombier /*	scr->blank = mach64blank; */
970223a736eSDavid du Colombier 	switch(scr->id){
971223a736eSDavid du Colombier 	default:
972223a736eSDavid du Colombier 		break;
973223a736eSDavid du Colombier 	case ('L'<<8)|'B':		/* 4C42: Rage 3D LTPro */
974223a736eSDavid du Colombier 	case ('L'<<8)|'I':		/* 4C49: Rage 3D LTPro */
975223a736eSDavid du Colombier 	case ('L'<<8)|'M':		/* 4C4D: Rage Mobility */
976223a736eSDavid du Colombier 	case ('L'<<8)|'P':		/* 4C50: Rage 3D LTPro */
9777dd7cddfSDavid du Colombier 		scr->blank = mach64lcdblank;
9789a747e4fSDavid du Colombier 		hwblank = 1;
979223a736eSDavid du Colombier 		break;
980223a736eSDavid du Colombier 	}
9817dd7cddfSDavid du Colombier }
9827dd7cddfSDavid du Colombier 
9839a747e4fSDavid du Colombier static void
ovl_configure(VGAscr * scr,Chan * c,char ** field)9849a747e4fSDavid du Colombier ovl_configure(VGAscr *scr, Chan *c, char **field)
9859a747e4fSDavid du Colombier {
9869a747e4fSDavid du Colombier 	int w, h;
9879a747e4fSDavid du Colombier 	char *format;
9889a747e4fSDavid du Colombier 
9899a747e4fSDavid du Colombier 	w = (int)strtol(field[1], nil, 0);
9909a747e4fSDavid du Colombier 	h = (int)strtol(field[2], nil, 0);
9919a747e4fSDavid du Colombier 	format = field[3];
9929a747e4fSDavid du Colombier 
9939a747e4fSDavid du Colombier 	if (c != ovl_chan)
9949a747e4fSDavid du Colombier 		error(Einuse);
9959a747e4fSDavid du Colombier 	if (strcmp(format, "YUYV"))
9969a747e4fSDavid du Colombier 		error(Eunsupportedformat);
9979a747e4fSDavid du Colombier 
9989a747e4fSDavid du Colombier 	ovl_width  = w;
9999a747e4fSDavid du Colombier 	ovl_height = h;
10009a747e4fSDavid du Colombier 	ovl_fib       = w * h * sizeof(ushort);
10019a747e4fSDavid du Colombier 
10029a747e4fSDavid du Colombier 	waitforidle(scr);
10039a747e4fSDavid du Colombier 	scr->mmio[mmoffset[BusCntl]] |= 0x08000000;	/* Enable regblock 1 */
10049a747e4fSDavid du Colombier 	scr->mmio[mmoffset[OverlayScaleCntl]] =
10059a747e4fSDavid du Colombier 		SCALE_ZERO_EXTEND|SCALE_RED_TEMP_6500K|
10069a747e4fSDavid du Colombier 		SCALE_HORZ_BLEND|SCALE_VERT_BLEND;
10079a747e4fSDavid du Colombier 	scr->mmio[mmoffset[!mach64revb? Buf0Pitch: ScalerBuf0Pitch]] = w;
10089a747e4fSDavid du Colombier 	scr->mmio[mmoffset[CaptureConfig]] =
10099a747e4fSDavid du Colombier 		SCALER_FRAME_READ_MODE_FULL|
10109a747e4fSDavid du Colombier 		SCALER_BUF_MODE_SINGLE|
10119a747e4fSDavid du Colombier 		SCALER_BUF_NEXT_0;
10129a747e4fSDavid du Colombier 	scr->mmio[mmoffset[OverlayKeyCntl]] = !mach64revb?
10139a747e4fSDavid du Colombier 		OVERLAY_MIX_ALWAYS_V|(OVERLAY_EXCLUSIVE_NORMAL << 28):
10149a747e4fSDavid du Colombier 		0x011;
10159a747e4fSDavid du Colombier 
10169a747e4fSDavid du Colombier 	if (mach64type->m64_pro) {
10179a747e4fSDavid du Colombier 		waitforfifo(scr, 6);
10189a747e4fSDavid du Colombier 
10199a747e4fSDavid du Colombier 		/* set the scaler co-efficient registers */
10209a747e4fSDavid du Colombier 		scr->mmio[mmoffset[ScalerColourCntl]] =
10219a747e4fSDavid du Colombier 			(0x00) | (0x10 << 8) | (0x10 << 16);
10229a747e4fSDavid du Colombier 		scr->mmio[mmoffset[ScalerHCoef0]] =
10239a747e4fSDavid du Colombier 			(0x00) | (0x20 << 8);
10249a747e4fSDavid du Colombier 		scr->mmio[mmoffset[ScalerHCoef1]] =
10259a747e4fSDavid du Colombier 			(0x0D) | (0x20 << 8) | (0x06 << 16) | (0x0D << 24);
10269a747e4fSDavid du Colombier 		scr->mmio[mmoffset[ScalerHCoef2]] =
10279a747e4fSDavid du Colombier 			(0x0D) | (0x1C << 8) | (0x0A << 16) | (0x0D << 24);
10289a747e4fSDavid du Colombier 		scr->mmio[mmoffset[ScalerHCoef3]] =
10299a747e4fSDavid du Colombier 			(0x0C) | (0x1A << 8) | (0x0E << 16) | (0x0C << 24);
10309a747e4fSDavid du Colombier 		scr->mmio[mmoffset[ScalerHCoef4]] =
10319a747e4fSDavid du Colombier 			(0x0C) | (0x14 << 8) | (0x14 << 16) | (0x0C << 24);
10329a747e4fSDavid du Colombier 	}
10339a747e4fSDavid du Colombier 
10349a747e4fSDavid du Colombier 	waitforfifo(scr, 3);
10359a747e4fSDavid du Colombier 	scr->mmio[mmoffset[VideoFormat]] = SCALE_IN_YVYU422 |
10369a747e4fSDavid du Colombier 		(!mach64revb? 0xC: 0);
10379a747e4fSDavid du Colombier 
10389a747e4fSDavid du Colombier 	if (mach64overlay == 0)
10399a747e4fSDavid du Colombier 		mach64overlay = scr->storage + 64 * 64 * sizeof(uchar);
10409a747e4fSDavid du Colombier 	scr->mmio[mmoffset[!mach64revb? Buf0Offset: ScalerBuf0Offset]] =
10419a747e4fSDavid du Colombier 		mach64overlay;
10429a747e4fSDavid du Colombier }
10439a747e4fSDavid du Colombier 
10449a747e4fSDavid du Colombier static void
ovl_enable(VGAscr * scr,Chan * c,char ** field)10459a747e4fSDavid du Colombier ovl_enable(VGAscr *scr, Chan *c, char **field)
10469a747e4fSDavid du Colombier {
10479a747e4fSDavid du Colombier 	int x, y, w, h;
10489a747e4fSDavid du Colombier 	long h_inc, v_inc;
10499a747e4fSDavid du Colombier 
10509a747e4fSDavid du Colombier 	x = (int)strtol(field[1], nil, 0);
10519a747e4fSDavid du Colombier 	y = (int)strtol(field[2], nil, 0);
10529a747e4fSDavid du Colombier 	w = (int)strtol(field[3], nil, 0);
10539a747e4fSDavid du Colombier 	h = (int)strtol(field[4], nil, 0);
10549a747e4fSDavid du Colombier 
10559a747e4fSDavid du Colombier 	if (x < 0 || x + w > physgscreenr.max.x ||
10569a747e4fSDavid du Colombier 	     y < 0 || y + h > physgscreenr.max.y)
10579a747e4fSDavid du Colombier 		error(Ebadarg);
10589a747e4fSDavid du Colombier 
10599a747e4fSDavid du Colombier 	if (c != ovl_chan)
10609a747e4fSDavid du Colombier 		error(Einuse);
10619a747e4fSDavid du Colombier 	if (scr->mmio[mmoffset[CrtcGenCntl]] & 1) {	/* double scan enable */
10629a747e4fSDavid du Colombier 		y *= 2;
10639a747e4fSDavid du Colombier 		h *= 2;
10649a747e4fSDavid du Colombier 	}
10659a747e4fSDavid du Colombier 
10669a747e4fSDavid du Colombier 	waitforfifo(scr, 2);
10679a747e4fSDavid du Colombier 	scr->mmio[mmoffset[OverlayYX]] =
10689a747e4fSDavid du Colombier 			((x & 0xFFFF) << 16) | (y & 0xFFFF);
10699a747e4fSDavid du Colombier 	scr->mmio[mmoffset[OverlayYXEnd]] =
10709a747e4fSDavid du Colombier 			(((x + w) & 0xFFFF) << 16) | ((y + h) & 0xFFFF);
10719a747e4fSDavid du Colombier 
10729a747e4fSDavid du Colombier 	h_inc = (ovl_width << 12) / (w >> 1);  /* ??? */
10739a747e4fSDavid du Colombier 	v_inc = (ovl_height << 12) / h;
10749a747e4fSDavid du Colombier 	waitforfifo(scr, 2);
10759a747e4fSDavid du Colombier 	scr->mmio[mmoffset[OverlayScaleInc]] =
10769a747e4fSDavid du Colombier 			((h_inc & 0xFFFF) << 16) | (v_inc & 0xFFFF);
10779a747e4fSDavid du Colombier 	scr->mmio[mmoffset[ScalerHeightWidth]] =
10789a747e4fSDavid du Colombier 			((ovl_width & 0xFFFF) << 16) | (ovl_height & 0xFFFF);
10799a747e4fSDavid du Colombier 	waitforidle(scr);
10809a747e4fSDavid du Colombier 	scr->mmio[mmoffset[OverlayScaleCntl]] |=
10819a747e4fSDavid du Colombier 			(SCALE_ENABLE|OVERLAY_ENABLE);
10829a747e4fSDavid du Colombier }
10839a747e4fSDavid du Colombier 
10849a747e4fSDavid du Colombier static void
ovl_status(VGAscr * scr,Chan *,char ** field)10859a747e4fSDavid du Colombier ovl_status(VGAscr *scr, Chan *, char **field)
10869a747e4fSDavid du Colombier {
1087e464ed1aSDavid du Colombier 	pprint("%s: %s %.4uX, VT/GT %s, PRO %s, ovlclock %lud, rev B %s, refclock %ld\n",
10889a747e4fSDavid du Colombier 		   scr->dev->name, field[0], mach64type->m64_id,
10899a747e4fSDavid du Colombier 		   mach64type->m64_vtgt? "yes": "no",
10909a747e4fSDavid du Colombier 		   mach64type->m64_pro? "yes": "no",
10919a747e4fSDavid du Colombier 		   mach64type->m64_ovlclock,
10929a747e4fSDavid du Colombier 		   mach64revb? "yes": "no",
10939a747e4fSDavid du Colombier 		   mach64refclock);
10949a747e4fSDavid du Colombier 	pprint("%s: storage @%.8luX, aperture @%8.ulX, ovl buf @%.8ulX\n",
10954de34a7eSDavid du Colombier 		   scr->dev->name, scr->storage, scr->paddr,
10969a747e4fSDavid du Colombier 		   mach64overlay);
10979a747e4fSDavid du Colombier }
10989a747e4fSDavid du Colombier 
10999a747e4fSDavid du Colombier static void
ovl_openctl(VGAscr *,Chan * c,char **)11009a747e4fSDavid du Colombier ovl_openctl(VGAscr *, Chan *c, char **)
11019a747e4fSDavid du Colombier {
11029a747e4fSDavid du Colombier 	if (ovl_chan)
11039a747e4fSDavid du Colombier 		error(Einuse);
11049a747e4fSDavid du Colombier 	ovl_chan = c;
11059a747e4fSDavid du Colombier }
11069a747e4fSDavid du Colombier 
11079a747e4fSDavid du Colombier static void
ovl_closectl(VGAscr * scr,Chan * c,char **)11089a747e4fSDavid du Colombier ovl_closectl(VGAscr *scr, Chan *c, char **)
11099a747e4fSDavid du Colombier {
11109a747e4fSDavid du Colombier 	if (c != ovl_chan) return;
11119a747e4fSDavid du Colombier 
11129a747e4fSDavid du Colombier 	waitforidle(scr);
11139a747e4fSDavid du Colombier 	scr->mmio[mmoffset[OverlayScaleCntl]] &=
11149a747e4fSDavid du Colombier 			~(SCALE_ENABLE|OVERLAY_ENABLE);
11159a747e4fSDavid du Colombier 	ovl_chan = nil;
11169a747e4fSDavid du Colombier 	ovl_width = ovl_height = ovl_fib = 0;
11179a747e4fSDavid du Colombier }
11189a747e4fSDavid du Colombier 
11199a747e4fSDavid du Colombier enum
11209a747e4fSDavid du Colombier {
11219a747e4fSDavid du Colombier 	CMclosectl,
11229a747e4fSDavid du Colombier 	CMconfigure,
11239a747e4fSDavid du Colombier 	CMenable,
11249a747e4fSDavid du Colombier 	CMopenctl,
11259a747e4fSDavid du Colombier 	CMstatus,
11269a747e4fSDavid du Colombier };
11279a747e4fSDavid du Colombier 
11289a747e4fSDavid du Colombier static void (*ovl_cmds[])(VGAscr *, Chan *, char **) =
11299a747e4fSDavid du Colombier {
11309a747e4fSDavid du Colombier 	[CMclosectl]	ovl_closectl,
11319a747e4fSDavid du Colombier 	[CMconfigure]	ovl_configure,
11329a747e4fSDavid du Colombier 	[CMenable]	ovl_enable,
11339a747e4fSDavid du Colombier 	[CMopenctl]	ovl_openctl,
11349a747e4fSDavid du Colombier 	[CMstatus]	ovl_status,
11359a747e4fSDavid du Colombier };
11369a747e4fSDavid du Colombier 
11379a747e4fSDavid du Colombier static Cmdtab mach64xxcmd[] =
11389a747e4fSDavid du Colombier {
11399a747e4fSDavid du Colombier 	CMclosectl,	"closectl",	1,
11409a747e4fSDavid du Colombier 	CMconfigure,	"configure",	4,
11419a747e4fSDavid du Colombier 	CMenable,	"enable",	5,
11429a747e4fSDavid du Colombier 	CMopenctl,	"openctl",	1,
11439a747e4fSDavid du Colombier 	CMstatus,	"status",	1,
11449a747e4fSDavid du Colombier };
11459a747e4fSDavid du Colombier 
11469a747e4fSDavid du Colombier static void
mach64xxovlctl(VGAscr * scr,Chan * c,void * a,int n)11479a747e4fSDavid du Colombier mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int n)
11489a747e4fSDavid du Colombier {
11499a747e4fSDavid du Colombier 	Cmdbuf *cb;
11509a747e4fSDavid du Colombier 	Cmdtab *ct;
11519a747e4fSDavid du Colombier 
11529a747e4fSDavid du Colombier 	if(!mach64type->m64_vtgt)
11539a747e4fSDavid du Colombier 		error(Enodev);
11549a747e4fSDavid du Colombier 
1155fb7f0c93SDavid du Colombier 	if(!scr->overlayinit){
1156fb7f0c93SDavid du Colombier 		scr->overlayinit = 1;
1157fb7f0c93SDavid du Colombier 		init_overlayclock(scr);
1158fb7f0c93SDavid du Colombier 	}
11599a747e4fSDavid du Colombier 	cb = parsecmd(a, n);
11609a747e4fSDavid du Colombier 	if(waserror()){
11619a747e4fSDavid du Colombier 		free(cb);
11629a747e4fSDavid du Colombier 		nexterror();
11639a747e4fSDavid du Colombier 	}
11649a747e4fSDavid du Colombier 
11659a747e4fSDavid du Colombier 	ct = lookupcmd(cb, mach64xxcmd, nelem(mach64xxcmd));
11669a747e4fSDavid du Colombier 
11679a747e4fSDavid du Colombier 	ovl_cmds[ct->index](scr, c, cb->f);
11689a747e4fSDavid du Colombier 
11699a747e4fSDavid du Colombier 	poperror();
11709a747e4fSDavid du Colombier 	free(cb);
11719a747e4fSDavid du Colombier }
11729a747e4fSDavid du Colombier 
11739a747e4fSDavid du Colombier static int
mach64xxovlwrite(VGAscr * scr,void * a,int len,vlong offs)11749a747e4fSDavid du Colombier mach64xxovlwrite(VGAscr *scr, void *a, int len, vlong offs)
11759a747e4fSDavid du Colombier {
11769a747e4fSDavid du Colombier 	uchar *src;
11779a747e4fSDavid du Colombier 	int _len;
11789a747e4fSDavid du Colombier 
11799a747e4fSDavid du Colombier 	if (ovl_chan == nil) return len;	/* Acts as a /dev/null */
11809a747e4fSDavid du Colombier 
11819a747e4fSDavid du Colombier 	/* Calculate the destination address */
11829a747e4fSDavid du Colombier 	_len = len;
11839a747e4fSDavid du Colombier 	src   = (uchar *)a;
11849a747e4fSDavid du Colombier 	while (len > 0) {
11859a747e4fSDavid du Colombier 		ulong _offs;
11869a747e4fSDavid du Colombier 		int nb;
11879a747e4fSDavid du Colombier 
11889a747e4fSDavid du Colombier 		_offs = (ulong)(offs % ovl_fib);
11899a747e4fSDavid du Colombier 		nb     = (_offs + len > ovl_fib)? ovl_fib - _offs: len;
11904de34a7eSDavid du Colombier 		memmove((uchar *)scr->vaddr + mach64overlay + _offs,
11919a747e4fSDavid du Colombier 				  src, nb);
11929a747e4fSDavid du Colombier 		offs += nb;
11939a747e4fSDavid du Colombier 		src  += nb;
11949a747e4fSDavid du Colombier 		len  -= nb;
11959a747e4fSDavid du Colombier 	}
11969a747e4fSDavid du Colombier 	return _len;
11979a747e4fSDavid du Colombier }
11989a747e4fSDavid du Colombier 
11997dd7cddfSDavid du Colombier VGAdev vgamach64xxdev = {
12007dd7cddfSDavid du Colombier 	"mach64xx",
12017dd7cddfSDavid du Colombier 
12027dd7cddfSDavid du Colombier 	mach64xxenable,			/* enable */
12037dd7cddfSDavid du Colombier 	0,				/* disable */
12047dd7cddfSDavid du Colombier 	0,				/* page */
12057dd7cddfSDavid du Colombier 	mach64xxlinear,			/* linear */
12067dd7cddfSDavid du Colombier 	mach64xxdrawinit,	/* drawinit */
12079a747e4fSDavid du Colombier 	0,
12089a747e4fSDavid du Colombier 	mach64xxovlctl,	/* overlay control */
12099a747e4fSDavid du Colombier 	mach64xxovlwrite,	/* write the overlay */
12107dd7cddfSDavid du Colombier };
12117dd7cddfSDavid du Colombier 
12127dd7cddfSDavid du Colombier VGAcur vgamach64xxcur = {
12137dd7cddfSDavid du Colombier 	"mach64xxhwgc",
12147dd7cddfSDavid du Colombier 
12157dd7cddfSDavid du Colombier 	mach64xxcurenable,		/* enable */
12167dd7cddfSDavid du Colombier 	mach64xxcurdisable,		/* disable */
12177dd7cddfSDavid du Colombier 	mach64xxcurload,		/* load */
12187dd7cddfSDavid du Colombier 	mach64xxcurmove,		/* move */
12197dd7cddfSDavid du Colombier 
12207dd7cddfSDavid du Colombier 	1					/* doespanning */
12217dd7cddfSDavid du Colombier };
122259cc4ca5SDavid du Colombier 
1223