Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "io.h"
7
#include "../port/error.h"
8
 
9
#define	Image	IMAGE
10
#include <draw.h>
11
#include <memdraw.h>
12
#include <cursor.h>
13
#include "screen.h"
14
 
15
char Eunsupportedformat[] = "unsupported video format";
16
char Enotconfigured[] = "device not configured";
17
 
18
#define SCALE_ZERO_EXTEND           	0x0
19
#define SCALE_DYNAMIC               		0x1
20
#define SCALE_RED_TEMP_6500K        	0x0
21
#define SCALE_RED_TEMP_9800K        	0x2
22
#define SCALE_HORZ_BLEND            	0x0
23
#define SCALE_HORZ_REP              		0x4
24
#define SCALE_VERT_BLEND            		0x0
25
#define SCALE_VERT_REP              		0x8
26
#define SCALE_BANDWIDTH_NORMAL     0x0
27
#define SCALE_BANDWIDTH_EXCEEDED  0x4000000
28
#define SCALE_BANDWIDTH_RESET       	0x4000000
29
#define SCALE_CLK_ACTIVITY          	0x0
30
#define SCALE_CLK_CONTINUOUS        	0x20000000
31
#define OVERLAY_DISABLE             		0x0
32
#define OVERLAY_ENABLE              		0x40000000
33
#define SCALE_DISABLE               		0x0
34
#define SCALE_ENABLE                		0x80000000
35
 
36
#define SCALER_FRAME_READ_MODE_FULL 	0x0
37
#define SCALER_BUF_MODE_SINGLE      		0x0
38
#define SCALER_BUF_MODE_DOUBLE      		0x40000
39
#define SCALER_BUF_NEXT_0           		0x0
40
#define SCALER_BUF_NEXT_1           		0x80000
41
#define SCALER_BUF_STATUS_0         		0x0
42
#define SCALER_BUF_STATUS_1         		0x100000
43
 
44
#define OVERLAY_MIX_G_CMP           		0x0
45
#define OVERLAY_MIX_ALWAYS_G        		0x100
46
#define OVERLAY_MIX_ALWAYS_V        		0x200
47
#define OVERLAY_MIX_NOT_G           		0x300
48
#define OVERLAY_MIX_NOT_V           		0x400
49
#define OVERLAY_MIX_G_XOR_V         		0x500
50
#define OVERLAY_MIX_NOT_G_XOR_V     	0x600
51
#define OVERLAY_MIX_V_CMP           		0x700
52
#define OVERLAY_MIX_NOT_G_OR_NOT_V	0x800
53
#define OVERLAY_MIX_G_OR_NOT_V      	0x900
54
#define OVERLAY_MIX_NOT_G_OR_V      	0xA00
55
#define OVERLAY_MIX_G_OR_V          		0xB00
56
#define OVERLAY_MIX_G_AND_V         		0xC00
57
#define OVERLAY_MIX_NOT_G_AND_V     	0xD00
58
#define OVERLAY_MIX_G_AND_NOT_V     	0xE00
59
#define OVERLAY_MIX_NOT_G_AND_NOT_V 	0xF00
60
#define OVERLAY_EXCLUSIVE_NORMAL    	0x0
61
#define OVERLAY_EXCLUSIVE_V_ONLY    	0x80000000
62
 
63
#define VIDEO_IN_8BPP               			0x2
64
#define VIDEO_IN_16BPP              			0x4
65
#define VIDEO_IN_32BPP              			0x6
66
#define VIDEO_IN_VYUY422            			0xB         		/*16 bpp */
67
#define VIDEO_IN_YVYU422            			0xC         		/* 16 bpp */
68
#define SCALE_IN_15BPP              			0x30000     	/* aRGB 1555 */
69
#define SCALE_IN_16BPP              			0x40000     	/* RGB 565 */
70
#define SCALE_IN_32BPP              			0x60000     	/* aRGB 8888 */
71
#define SCALE_IN_YUV9               			0x90000     	/* planar */
72
#define SCALE_IN_YUV12              			0xA0000     	/* planar */
73
#define SCALE_IN_VYUY422            			0xB0000     	/* 16 bpp */
74
#define SCALE_IN_YVYU422            			0xC0000     	/* 16 bpp */
75
#define HOST_YUV_APERTURE_UPPER     		0x0
76
#define HOST_YUV_APERTURE_LOWER     	0x20000000
77
#define HOST_MEM_MODE_Y             		0x40000000
78
#define HOST_MEM_MODE_U             		0x80000000
79
#define HOST_MEM_MODE_V             		0xC0000000
80
#define HOST_MEM_MODE_NORMAL     		HOST_YUV_APERTURE_UPPER 
81
 
82
static Chan *ovl_chan;		/* Channel of controlling process */
83
static int ovl_width;		/* Width of input overlay buffer */
84
static int ovl_height;		/* Height of input overlay buffer */
85
static int ovl_format;		/* Overlay format */
86
static ulong ovl_fib;		/* Frame in bytes */
87
 
88
enum {
89
	 VTGTB1S1	= 0x01, /* Asic description for VTB1S1 and GTB1S1. */
90
	 VT4GTIIC	= 0x3A,		/* asic descr for VT4 and RAGE IIC */
91
	 GTB1U1		= 0x19,		/* Asic description for GTB1U1. */
92
	 GTB1S2		= 0x41,		/* Asic description for GTB1S2. */
93
	 GTB2U1		= 0x1A,
94
	 GTB2U2		= 0x5A,
95
	 GTB2U3		= 0x9A,
96
	 GTIIIC1U1	= 0x1B,		/* 3D RAGE PRO asic descrp. */
97
	 GTIIIC1U2	= 0x5B,		/* 3D RAGE PRO asic descrp. */
98
	 GTIIIC2U1	= 0x1C,		/* 3D RAGE PRO asic descrp. */
99
	 GTIIIC2U2	= 0x5C,		/* 3D RAGE PRO asic descrp. */
100
	 GTIIIC2U3	= 0x7C,		/* 3D RAGE PRO asic descrp. */
101
	 GTBC		= 0x3A,		/* 3D RAGE IIC asic descrp. */
102
	 LTPRO		= 0x9C,		/* 3D RAGE LT PRO */
103
};
104
 
105
/*
106
 * ATI Mach64(CT|ET|G*|V*|L*).
107
 */
108
typedef struct Mach64types Mach64types;
109
struct Mach64types {
110
	ushort 	m64_id;			/* Chip ID */
111
	int 	m64_vtgt;		/* Is this a VT or GT chipset? */
112
	ulong	m64_ovlclock;		/* Max. overlay clock frequency */
113
	int	m64_pro;		/* Is this a PRO? */
114
};
115
 
116
static ulong mach64refclock;
117
static Mach64types *mach64type;
118
static int mach64revb;			/* Revision B or greater? */
119
static ulong mach64overlay;		/* Overlay buffer */
120
 
121
static Mach64types mach64s[] = {
122
	('C'<<8)|'T',	0,	1350000, /*?*/	0,	/* 4354: CT */
123
	('E'<<8)|'T',	0,	1350000, /*?*/	0,	/* 4554: ET */
124
	('G'<<8)|'B',	1,	1250000,	1, 	/* 4742: 264GT PRO */
125
	('G'<<8)|'D',	1,	1250000,	1, 	/* 4744: 264GT PRO */
126
	('G'<<8)|'I',	1,	1250000,	1, 	/* 4749: 264GT PRO */
127
	('G'<<8)|'M',	0,	1350000,	0,	/* 474D: Rage XL */
128
	('G'<<8)|'P',	1,	1250000,	1, 	/* 4750: 264GT PRO */
129
	('G'<<8)|'Q',	1,	1250000,	1,	/* 4751: 264GT PRO */
130
	('G'<<8)|'R',	1,	1250000,	1,	/* 4752: */
131
	('G'<<8)|'T',	1,	800000,		0,	/* 4754: 264GT[B] */
132
	('G'<<8)|'U',	1,	1000000,	0,	/* 4755: 264GT DVD */
133
	('G'<<8)|'V',	1,	1000000,	0,	/* 4756: Rage2C */
134
	('G'<<8)|'Z',	1,	1000000,	0,	/* 475A: Rage2C */
135
	('V'<<8)|'T',	1,	800000,		0,	/* 5654: 264VT/GT/VTB */
136
	('V'<<8)|'U',	1,	800000,		0,	/* 5655: 264VT3 */
137
	('V'<<8)|'V',	1,	1000000,	0,	/* 5656: 264VT4 */
138
	('L'<<8)|'B',	0,	1350000,	1,	/* 4C42: Rage LTPro AGP */
139
	('L'<<8)|'I',	0,	1350000,	0,	/* 4C49: Rage LTPro AGP */
140
	('L'<<8)|'M',	0,	1350000,	0,	/* 4C4D: Rage Mobility */
141
	('L'<<8)|'P',	0,	1350000,	1,	/* 4C50: 264LT PRO */
142
};
143
 
144
 
145
static int hwfill(VGAscr*, Rectangle, ulong);
146
static int hwscroll(VGAscr*, Rectangle, Rectangle);
147
static void initengine(VGAscr*);
148
 
149
static Pcidev*
150
mach64xxpci(void)
151
{
152
	Pcidev *p;
153
	int i;
154
 
155
	if((p = pcimatch(nil, 0x1002, 0)) == nil)
156
		return nil;
157
 
158
	for (i = 0; i != nelem(mach64s); i++)
159
		if (mach64s[i].m64_id == p->did) {
160
			mach64type = &mach64s[i];
161
			return p;
162
		}
163
	return nil;
164
}
165
 
166
static void
167
mach64xxenable(VGAscr* scr)
168
{
169
	Pcidev *p;
170
 
171
	if(scr->io)
172
		return;
173
	if(p = mach64xxpci()){
174
		scr->id = p->did;
175
		scr->pci = p;
176
 
177
		/*
178
		 * The CT doesn't always have the I/O base address
179
		 * in the PCI base registers. There is a way to find
180
		 * it via the vendor-specific PCI config space but
181
		 * this will do for now.
182
		 */
183
		scr->io = p->mem[1].bar & ~0x03;
184
 
185
		if(scr->io == 0)
186
			scr->io = 0x2EC;
187
	}
188
}
189
 
190
static void
191
mach64xxlinear(VGAscr* scr, int size, int)
192
{
193
	ulong mmiophys;
194
 
195
	vgalinearpci(scr);
196
	if(scr->paddr == 0)
197
		return;
198
	/*
199
	 * vgalinearpci sets framebuffer into write combining mode.
200
	 * Because mmio register page is inside framebuffer space,
201
	 * set it back to uncached.
202
	 */
203
	mmiophys = scr->paddr + size - BY2PG;
204
	if(!waserror()){
205
		mtrr(mmiophys, BY2PG, "uc");
206
		poperror();
207
	}
208
	scr->mmio = (ulong*)((uchar*)scr->vaddr+size-1024);
209
	addvgaseg("mach64mmio", mmiophys, BY2PG);
210
	addvgaseg("mach64screen", scr->paddr, scr->apsize);
211
}
212
 
213
enum {
214
	CrtcOffPitch	= 0x05,
215
	CrtcGenCtl	= 0x07,
216
	CurClr0		= 0x0B,		/* I/O Select */
217
	CurClr1		= 0x0C,
218
	CurOffset	= 0x0D,
219
	CurHVposn	= 0x0E,
220
	CurHVoff	= 0x0F,
221
	BusCntl	= 0x13,
222
	GenTestCntl	= 0x19,
223
 
224
	CrtcHsyncDis	= 0x04,
225
	CrtcVsyncDis	= 0x08,
226
 
227
	ContextMask	= 0x100,	/* not accessible via I/O */
228
	FifoStat,
229
	GuiStat,
230
	DpFrgdClr,
231
	DpBkgdClr,
232
	DpWriteMask,
233
	DpMix,
234
	DpPixWidth,
235
	DpSrc,
236
	ClrCmpCntl,
237
	GuiTrajCntl,
238
	ScLeftRight,
239
	ScTopBottom,
240
	DstOffPitch,
241
	DstYX,
242
	DstHeightWidth,
243
	DstCntl,
244
	DstHeight,
245
	DstBresErr,
246
	DstBresInc,
247
	DstBresDec,
248
	SrcCntl,
249
	SrcHeight1Width1,
250
	SrcHeight2Width2,
251
	SrcYX,
252
	SrcWidth1,
253
	SrcYXstart,
254
	HostCntl,
255
	PatReg0,
256
	PatReg1,
257
	PatCntl,
258
	ScBottom,
259
	ScLeft,
260
	ScRight,
261
	ScTop,
262
	ClrCmpClr,
263
	ClrCmpMask,
264
	DpChainMask,
265
	SrcOffPitch,	
266
	LcdIndex,
267
	LcdData,
268
	ClockCntl,
269
	OverlayScaleCntl,
270
	ConfigChipId,
271
	Buf0Pitch,
272
	ScalerBuf0Pitch,
273
	CaptureConfig,
274
	OverlayKeyCntl,
275
	ScalerColourCntl,
276
	ScalerHCoef0,
277
	ScalerHCoef1,
278
	ScalerHCoef2,
279
	ScalerHCoef3,
280
	ScalerHCoef4,
281
	VideoFormat,
282
	Buf0Offset,
283
	ScalerBuf0Offset,
284
	CrtcGenCntl,
285
	OverlayScaleInc,
286
	OverlayYX,
287
	OverlayYXEnd,
288
	ScalerHeightWidth,
289
	HTotalDisp,
290
	VTotalDisp,
291
};
292
 
293
enum {
294
	LCD_ConfigPanel = 0,
295
	LCD_GenCtrl,
296
	LCD_DstnCntl,
297
	LCD_HfbPitchAddr,
298
	LCD_HorzStretch,
299
	LCD_VertStretch,
300
	LCD_ExtVertStretch,
301
	LCD_LtGio,
302
	LCD_PowerMngmnt,
303
	LCD_ZvgPio,
304
	Nlcd,
305
};
306
 
307
#define Bank1			(-0x100)		/* 1KB */
308
 
309
static int mmoffset[] = {
310
	[HTotalDisp]		0x00,
311
	[VTotalDisp]		0x02,
312
	[CrtcOffPitch]		0x05,
313
	[CrtcGenCntl]		0x07,
314
	[CurClr0]			0x18,
315
	[CurClr1]			0x19,
316
	[CurOffset]		0x1A,
317
	[CurHVposn]		0x1B,
318
	[CurHVoff]		0x1C,
319
	[ClockCntl]		0x24,
320
	[BusCntl]			0x28,
321
	[LcdIndex]		0x29,
322
	[LcdData]			0x2A,
323
	[GenTestCntl]		0x34,
324
	[ConfigChipId]		0x38,
325
	[DstOffPitch]		0x40,
326
	[DstYX]			0x43,
327
	[DstHeight]		0x45,
328
	[DstHeightWidth]	0x46,
329
	[DstBresErr]		0x49,
330
	[DstBresInc]		0x4A,
331
	[DstBresDec]		0x4B,
332
	[DstCntl]			0x4C,
333
	[SrcOffPitch]		0x60,
334
	[SrcYX]			0x63,
335
	[SrcWidth1]		0x64,
336
	[SrcYXstart]		0x69,
337
	[SrcHeight1Width1]	0x66,
338
	[SrcHeight2Width2]	0x6C,
339
	[SrcCntl]			0x6D,
340
	[HostCntl]			0x90,
341
	[PatReg0]			0xA0,
342
	[PatReg1]			0xA1,
343
	[PatCntl]			0xA2,
344
	[ScLeft]			0xA8,
345
	[ScRight]			0xA9,
346
	[ScLeftRight]		0xAA,
347
	[ScTop]			0xAB,
348
	[ScBottom] 		0xAC,
349
	[ScTopBottom]		0xAD,
350
	[DpBkgdClr]		0xB0,
351
	[DpFrgdClr]		0xB1,
352
	[DpWriteMask]		0xB2,
353
	[DpChainMask]		0xB3,
354
	[DpPixWidth]		0xB4,
355
	[DpMix]			0xB5,
356
	[DpSrc]			0xB6,
357
	[ClrCmpClr]		0xC0,
358
	[ClrCmpMask]		0xC1,
359
	[ClrCmpCntl]		0xC2,
360
	[FifoStat]			0xC4,
361
	[ContextMask]		0xC8,
362
	[GuiTrajCntl]		0xCC,
363
	[GuiStat]			0xCE,
364
 
365
	/* Bank1 */
366
	[OverlayYX]		Bank1 + 0x00,
367
	[OverlayYXEnd]		Bank1 + 0x01,
368
	[OverlayKeyCntl]	Bank1 + 0x06,
369
	[OverlayScaleInc]	Bank1 + 0x08,
370
	[OverlayScaleCntl]	Bank1 + 0x09,
371
	[ScalerHeightWidth]	Bank1 + 0x0A,
372
	[ScalerBuf0Offset]	Bank1 + 0x0D,
373
	[ScalerBuf0Pitch]	Bank1 + 0x0F,
374
	[VideoFormat]		Bank1 + 0x12,
375
	[CaptureConfig]	Bank1 + 0x14,
376
	[Buf0Offset]		Bank1 + 0x20,
377
	[Buf0Pitch]		Bank1 + 0x23,
378
	[ScalerColourCntl]	Bank1 + 0x54,
379
	[ScalerHCoef0]		Bank1 + 0x55,
380
	[ScalerHCoef1]		Bank1 + 0x56,
381
	[ScalerHCoef2]		Bank1 + 0x57,
382
	[ScalerHCoef3]		Bank1 + 0x58,
383
	[ScalerHCoef4]		Bank1 + 0x59,
384
};
385
 
386
static ulong
387
ior32(VGAscr* scr, int r)
388
{
389
	if(scr->io == 0x2EC || scr->io == 0x1C8)
390
		return inl((r<<10)+scr->io);
391
	if(r >= 0x100 && scr->mmio != nil)
392
		return scr->mmio[mmoffset[r]];
393
	return inl((mmoffset[r]<<2)+scr->io);
394
}
395
 
396
static void
397
iow32(VGAscr* scr, int r, ulong l)
398
{
399
	if(scr->io == 0x2EC || scr->io == 0x1C8)
400
		outl(((r)<<10)+scr->io, l);
401
	else if(r >= 0x100 && scr->mmio != nil)
402
		scr->mmio[mmoffset[r]] = l;
403
	else
404
		outl((mmoffset[r]<<2)+scr->io, l);
405
}
406
 
407
static ulong
408
lcdr32(VGAscr *scr, ulong r)
409
{
410
	ulong or;
411
 
412
	or = ior32(scr, LcdIndex);
413
	iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
414
	return ior32(scr, LcdData);
415
}
416
 
417
static void
418
lcdw32(VGAscr *scr, ulong r, ulong v)
419
{
420
	ulong or;
421
 
422
	or = ior32(scr, LcdIndex);
423
	iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
424
	iow32(scr, LcdData, v);
425
}
426
 
427
static void
428
mach64xxcurdisable(VGAscr* scr)
429
{
430
	ulong r;
431
 
432
	r = ior32(scr, GenTestCntl);
433
	iow32(scr, GenTestCntl, r & ~0x80);
434
}
435
 
436
static void
437
mach64xxcurload(VGAscr* scr, Cursor* curs)
438
{
439
	uchar *p;
440
	int i, y;
441
	ulong c, s, m, r;
442
 
443
	/*
444
	 * Disable the cursor.
445
	 */
446
	r = ior32(scr, GenTestCntl);
447
	iow32(scr, GenTestCntl, r & ~0x80);
448
 
449
	p = scr->vaddr;
450
	p += scr->storage;
451
 
452
	/*
453
	 * Initialise the 64x64 cursor RAM array.
454
	 * The cursor mode gives the following truth table:
455
	 *	p1 p0	colour
456
	 *	 0  0	Cursor Colour 0
457
	 *	 0  1	Cursor Colour 1
458
	 *	 1  0	Transparent
459
	 *	 1  1	Complement
460
	 * Put the cursor into the top-right of the 64x64 array.
461
	 */
462
	for(y = 0; y < 16; y++){
463
		for(i = 0; i < (64-16)/8; i++){
464
			*p++ = 0xAA;
465
			*p++ = 0xAA;
466
		}
467
 
468
		c = (curs->clr[2*y]<<8)|curs->clr[y*2 + 1];
469
		s = (curs->set[2*y]<<8)|curs->set[y*2 + 1];
470
 
471
		m = 0x00000000;
472
		for(i = 0; i < 16; i++){
473
			if(s & (1<<(15-i)))
474
				m |= 0x01<<(2*i);
475
			else if(c & (1<<(15-i))){
476
				/* nothing to do */
477
			}
478
			else
479
				m |= 0x02<<(2*i);
480
		}
481
		*p++ = m;
482
		*p++ = m>>8;
483
		*p++ = m>>16;
484
		*p++ = m>>24;
485
	}
486
	memset(p, 0xAA, (64-16)*16);
487
 
488
	/*
489
	 * Set the cursor hotpoint and enable the cursor.
490
	 */
491
	scr->offset = curs->offset;
492
	iow32(scr, GenTestCntl, 0x80|r);
493
}
494
 
495
static int
496
ptalmostinrect(Point p, Rectangle r)
497
{
498
	return p.x>=r.min.x && p.x<=r.max.x &&
499
	       p.y>=r.min.y && p.y<=r.max.y;
500
}
501
 
502
/*
503
 * If necessary, translate the rectangle physr
504
 * some multiple of [dx dy] so that it includes p.
505
 * Return 1 if the rectangle changed.
506
 */
507
static int
508
screenpan(Point p, Rectangle *physr, int dx, int dy)
509
{
510
	int d;
511
 
512
	if(ptalmostinrect(p, *physr))
513
		return 0;
514
 
515
	if(p.y < physr->min.y){
516
		d = physr->min.y - (p.y&~(dy-1));
517
		physr->min.y -= d;
518
		physr->max.y -= d;
519
	}
520
	if(p.y > physr->max.y){
521
		d = ((p.y+dy-1)&~(dy-1)) - physr->max.y;
522
		physr->min.y += d;
523
		physr->max.y += d;
524
	}
525
 
526
	if(p.x < physr->min.x){
527
		d = physr->min.x - (p.x&~(dx-1));
528
		physr->min.x -= d;
529
		physr->max.x -= d;
530
	}
531
	if(p.x > physr->max.x){
532
		d = ((p.x+dx-1)&~(dx-1)) - physr->max.x;
533
		physr->min.x += d;
534
		physr->max.x += d;
535
	}
536
	return 1;
537
}
538
 
539
static int
540
mach64xxcurmove(VGAscr* scr, Point p)
541
{
542
	int x, xo, y, yo;
543
	int dx;
544
	ulong off, pitch;
545
 
546
	/*
547
	 * If the point we want to display is outside the current
548
	 * screen rectangle, pan the screen to display it.
549
	 *
550
	 * We have to move in 64-bit chunks.
551
	 */
552
	if(scr->gscreen->depth == 24)
553
		dx = (64*3)/24;
554
	else
555
		dx = 64 / scr->gscreen->depth;
556
 
557
	if(panning && screenpan(p, &physgscreenr, dx, 1)){
558
		off = (physgscreenr.min.y*Dx(scr->gscreen->r)+physgscreenr.min.x)/dx;
559
		pitch = Dx(scr->gscreen->r)/8;
560
		iow32(scr, CrtcOffPitch, (pitch<<22)|off);
561
	}
562
 
563
	p.x -= physgscreenr.min.x;
564
	p.y -= physgscreenr.min.y;
565
 
566
	/*
567
	 * Mustn't position the cursor offscreen even partially,
568
	 * or it disappears. Therefore, if x or y is -ve, adjust the
569
	 * cursor presets instead. If y is negative also have to
570
	 * adjust the starting offset.
571
	 */
572
	if((x = p.x+scr->offset.x) < 0){
573
		xo = x;
574
		x = 0;
575
	}
576
	else
577
		xo = 0;
578
	if((y = p.y+scr->offset.y) < 0){
579
		yo = y;
580
		y = 0;
581
	}
582
	else
583
		yo = 0;
584
 
585
	iow32(scr, CurHVoff, ((64-16-yo)<<16)|(64-16-xo));
586
	iow32(scr, CurOffset, scr->storage/8 + (-yo*2));
587
	iow32(scr, CurHVposn, (y<<16)|x);
588
 
589
	return 0;
590
}
591
 
592
static void
593
mach64xxcurenable(VGAscr* scr)
594
{
595
	ulong r, storage;
596
 
597
	mach64xxenable(scr);
598
	if(scr->io == 0)
599
		return;
600
 
601
	r = ior32(scr, GenTestCntl);
602
	iow32(scr, GenTestCntl, r & ~0x80);
603
 
604
	iow32(scr, CurClr0, (Pwhite<<24)|(Pwhite<<16)|(Pwhite<<8)|Pwhite);
605
	iow32(scr, CurClr1, (Pblack<<24)|(Pblack<<16)|(Pblack<<8)|Pblack);
606
 
607
	/*
608
	 * Find a place for the cursor data in display memory.
609
	 * Must be 64-bit aligned.
610
	 */
611
	storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+7)/8;
612
	iow32(scr, CurOffset, storage);
613
	scr->storage = storage*8;
614
 
615
	/*
616
	 * Cursor goes in the top right corner of the 64x64 array
617
	 * so the horizontal and vertical presets are 64-16.
618
	 */
619
	iow32(scr, CurHVposn, (0<<16)|0);
620
	iow32(scr, CurHVoff, ((64-16)<<16)|(64-16));
621
 
622
	/*
623
	 * Load, locate and enable the 64x64 cursor.
624
	 */
625
	mach64xxcurload(scr, &arrow);
626
	mach64xxcurmove(scr, ZP);
627
	iow32(scr, GenTestCntl, 0x80|r);
628
}
629
 
630
static void
631
waitforfifo(VGAscr *scr, int entries)
632
{
633
	int x;
634
 
635
	x = 0;
636
	while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000)
637
		;
638
	if(x >= 1000000)
639
		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));
640
}
641
 
642
static void
643
waitforidle(VGAscr *scr)
644
{
645
	int x;
646
 
647
	waitforfifo(scr, 16);
648
	x = 0;
649
	while((ior32(scr, GuiStat)&1) && x++ < 1000000)
650
		;
651
	if(x >= 1000000)
652
		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));
653
}
654
 
655
static void
656
resetengine(VGAscr *scr)
657
{
658
	ulong x;
659
	x = ior32(scr, GenTestCntl);
660
	iow32(scr, GenTestCntl, x&~0x100);
661
	iow32(scr, GenTestCntl, x|0x100);
662
	iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000);
663
}
664
 
665
static void
666
init_overlayclock(VGAscr *scr)
667
{
668
	uchar *cc, save, pll_ref_div, pll_vclk_cntl, vclk_post_div, 
669
			vclk_fb_div, ecp_div;
670
	int i;
671
	ulong dotclock;
672
 
673
	/* Taken from GLX */
674
	/* Get monitor dotclock, check for Overlay Scaler clock limit */
675
 	cc = (uchar *)&scr->mmio[mmoffset[ClockCntl]];
676
  	save = cc[1]; i = cc[0] & 3;
677
  	cc[1] = 2<<2; pll_ref_div = cc[2];
678
  	cc[1] = 5<<2; pll_vclk_cntl = cc[2];
679
  	cc[1] = 6<<2; vclk_post_div = (cc[2]>>(i+i)) & 3;
680
  	cc[1] = (7+i)<<2; vclk_fb_div = cc[2];
681
 
682
	dotclock = 2 * mach64refclock * vclk_fb_div / 
683
			(pll_ref_div * (1 << vclk_post_div));
684
	/* ecp_div: 0=dotclock, 1=dotclock/2, 2=dotclock/4 */
685
  	ecp_div = dotclock / mach64type->m64_ovlclock;
686
  	if (ecp_div>2) ecp_div = 2;
687
 
688
  	/* Force a scaler clock factor of 1 if refclock *
689
   	  * is unknown (VCLK_SRC not PLLVCLK)  */
690
  	if ((pll_vclk_cntl & 0x03) != 0x03) 
691
		ecp_div = 0;
692
  	if ((pll_vclk_cntl & 0x30) != ecp_div<<4) {
693
    		cc[1] = (5<<2)|2;
694
    		cc[2] = (pll_vclk_cntl&0xCF) | (ecp_div<<4);
695
	}
696
 
697
  	/* Restore PLL Register Index */
698
  	cc[1] = save;
699
}
700
 
701
static void
702
initengine(VGAscr *scr)
703
{
704
	ulong pitch;
705
	uchar *bios;
706
	ushort table;
707
 
708
	pitch = Dx(scr->gscreen->r)/8;
709
	if(scr->gscreen->depth == 24)
710
		pitch *= 3;
711
 
712
	resetengine(scr);
713
	waitforfifo(scr, 14);
714
	iow32(scr, ContextMask, ~0);
715
	iow32(scr, DstOffPitch, pitch<<22);
716
	iow32(scr, DstYX, 0);
717
	iow32(scr, DstHeight, 0);
718
	iow32(scr, DstBresErr, 0);
719
	iow32(scr, DstBresInc, 0);
720
	iow32(scr, DstBresDec, 0);
721
	iow32(scr, DstCntl, 0x23);
722
	iow32(scr, SrcOffPitch, pitch<<22);
723
	iow32(scr, SrcYX, 0);
724
	iow32(scr, SrcHeight1Width1, 1);
725
	iow32(scr, SrcYXstart, 0);
726
	iow32(scr, SrcHeight2Width2, 1);
727
	iow32(scr, SrcCntl, 0x01);
728
 
729
	waitforfifo(scr, 13);
730
	iow32(scr, HostCntl, 0);
731
	iow32(scr, PatReg0, 0);
732
	iow32(scr, PatReg1, 0);
733
	iow32(scr, PatCntl, 0);
734
	iow32(scr, ScLeft, 0);
735
	iow32(scr, ScTop, 0);
736
	iow32(scr, ScBottom, 0xFFFF);
737
	iow32(scr, ScRight, 0xFFFF);
738
	iow32(scr, DpBkgdClr, 0);
739
	iow32(scr, DpFrgdClr, ~0);
740
	iow32(scr, DpWriteMask, ~0);
741
	iow32(scr, DpMix, 0x70003);
742
	iow32(scr, DpSrc, 0x00010100);
743
 
744
	waitforfifo(scr, 3);
745
	iow32(scr, ClrCmpClr, 0);
746
	iow32(scr, ClrCmpMask, ~0);
747
	iow32(scr, ClrCmpCntl, 0);
748
 
749
	waitforfifo(scr, 2);
750
	switch(scr->gscreen->depth){
751
	case 8:
752
	case 24:	/* [sic] */
753
		iow32(scr, DpPixWidth, 0x00020202);
754
		iow32(scr, DpChainMask, 0x8080);
755
		break;
756
	case 16:
757
		iow32(scr, DpPixWidth, 0x00040404);
758
		iow32(scr, DpChainMask, 0x8410);
759
		break;
760
	case 32:
761
		iow32(scr, DpPixWidth, 0x00060606);
762
		iow32(scr, DpChainMask, 0x8080);
763
		break;
764
	}
765
 
766
	/* Get the base freq from the BIOS */
767
	bios  = kaddr(0xC000);
768
	table = *(ushort *)(bios + 0x48);
769
	table = *(ushort *)(bios + table + 0x10);
770
	switch (*(ushort *)(bios + table + 0x08)) {
771
      	case 2700: 
772
		mach64refclock = 270000; 
773
		break;
774
      	case 2863: 
775
      	case 2864: 
776
		mach64refclock = 286363; 
777
		break;
778
      	case 2950: 
779
		mach64refclock = 294989; 
780
		break;
781
    	case 1432: 
782
	default:
783
		mach64refclock = 143181; 
784
		break ;	
785
	}
786
 
787
	/* Figure out which revision this chip is */
788
	switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) {
789
	case VTGTB1S1:
790
	case GTB1U1:
791
	case GTB1S2:
792
	case GTB2U1:
793
	case GTB2U2:
794
	case GTB2U3:
795
	case GTBC:
796
	case GTIIIC1U1:
797
	case GTIIIC1U2:
798
	case GTIIIC2U1:
799
	case GTIIIC2U2: 
800
	case GTIIIC2U3: 
801
	case LTPRO:
802
			mach64revb = 1;
803
			break;
804
	default: 
805
			mach64revb = 0;
806
			break;
807
	}
808
 
809
	waitforidle(scr);
810
}
811
 
812
static int
813
mach64hwfill(VGAscr *scr, Rectangle r, ulong sval)
814
{
815
	ulong pitch;
816
	ulong ctl;
817
 
818
if(drawdebug)
819
	iprint("hwfill %R val %lux...\n", r, sval);
820
 
821
	/* shouldn't happen */
822
	if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0)
823
		return 0;
824
 
825
	pitch = Dx(scr->gscreen->r)/8;
826
	ctl = 1|2;	/* left-to-right, top-to-bottom */
827
	if(scr->gscreen->depth == 24){
828
		r.min.x *= 3;
829
		r.max.x *= 3;
830
		pitch *= 3;
831
		ctl |= (1<<7)|(((r.min.x/4)%6)<<8);
832
	}
833
 
834
	waitforfifo(scr, 11);
835
	iow32(scr, DpFrgdClr, sval);
836
	iow32(scr, DpWriteMask, 0xFFFFFFFF);
837
	iow32(scr, DpMix, 0x00070003);
838
	iow32(scr, DpSrc, 0x00000111);
839
	iow32(scr, ClrCmpCntl, 0x00000000);
840
	iow32(scr, ScLeftRight, 0x1FFF0000);
841
	iow32(scr, ScTopBottom, 0x1FFF0000);
842
	iow32(scr, DstOffPitch, pitch<<22);
843
	iow32(scr, DstCntl, ctl);
844
	iow32(scr, DstYX, (r.min.x<<16)|r.min.y);
845
	iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r));
846
 
847
	waitforidle(scr);
848
	return 1;
849
}
850
 
851
static int
852
mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
853
{
854
	ulong pitch;
855
	Point dp, sp;
856
	ulong ctl;
857
	int dx, dy;
858
 
859
	dx = Dx(r);
860
	dy = Dy(r);
861
	pitch = Dx(scr->gscreen->r)/8;
862
	if(scr->gscreen->depth == 24){
863
		dx *= 3;
864
		pitch *= 3;
865
		r.min.x *= 3;
866
		sr.min.x *= 3;
867
	}
868
 
869
	ctl = 0;
870
	if(r.min.x <= sr.min.x){
871
		ctl |= 1;
872
		dp.x = r.min.x;
873
		sp.x = sr.min.x;
874
	}else{
875
		dp.x = r.min.x+dx-1;
876
		sp.x = sr.min.x+dx-1;
877
	}
878
 
879
	if(r.min.y <= sr.min.y){
880
		ctl |= 2;
881
		dp.y = r.min.y;
882
		sp.y = sr.min.y;
883
	}else{
884
		dp.y = r.min.y+dy-1;
885
		sp.y = sr.min.y+dy-1;
886
	}
887
 
888
	if(scr->gscreen->depth == 24)
889
		ctl |= (1<<7)|(((dp.x/4)%6)<<8);
890
 
891
	waitforfifo(scr, 6);
892
	iow32(scr, ScLeftRight, 0x1FFF0000);
893
	iow32(scr, ScTopBottom, 0x1FFF0000);
894
	iow32(scr, DpWriteMask, 0xFFFFFFFF);
895
	iow32(scr, DpMix, 0x00070003);
896
	iow32(scr, DpSrc, 0x00000300);
897
	iow32(scr, ClrCmpCntl, 0x00000000);
898
 
899
	waitforfifo(scr, 8);
900
	iow32(scr, SrcOffPitch, pitch<<22);
901
	iow32(scr, SrcCntl, 0x00000000);
902
	iow32(scr, SrcYX, (sp.x<<16)|sp.y);
903
	iow32(scr, SrcWidth1, dx);
904
	iow32(scr, DstOffPitch, pitch<<22);
905
	iow32(scr, DstCntl, ctl);
906
 
907
	iow32(scr, DstYX, (dp.x<<16)|dp.y);
908
	iow32(scr, DstHeightWidth, (dx<<16)|dy);
909
 
910
	waitforidle(scr);
911
 
912
	return 1;
913
}
914
 
915
/*
916
 * This should work, but doesn't.
917
 * It messes up the screen timings for some reason.
918
 */
919
static void
920
mach64blank(VGAscr *scr, int blank)
921
{
922
	ulong ctl;
923
 
924
	ctl = ior32(scr, CrtcGenCtl) & ~(CrtcHsyncDis|CrtcVsyncDis);
925
	if(blank)
926
		ctl |= CrtcHsyncDis|CrtcVsyncDis;
927
	iow32(scr, CrtcGenCtl, ctl);
928
}
929
 
930
/*
931
 * We squirrel away whether the LCD and/or CRT were
932
 * on when we were called to blank the screen, and
933
 * restore the old state.  If we are called to blank the
934
 * screen when it is already blank, we don't update the state.
935
 * Such a call sequence should not happen, though.
936
 *
937
 * We could try forcing the chip into power management
938
 * mode instead, but I'm not sure how that would interact
939
 * with screen updates going on while the screen is blanked.
940
 */
941
static void
942
mach64lcdblank(VGAscr *scr, int blank)
943
{
944
	static int crtlcd;
945
	ulong x;
946
 
947
	if(blank) {
948
		x = lcdr32(scr, LCD_GenCtrl);
949
		if(x & 3) {
950
			crtlcd = x & 3;
951
			lcdw32(scr, LCD_GenCtrl,  x&~3);
952
		}
953
	} else {
954
		if(crtlcd == 0)
955
			crtlcd = 2;	/* lcd only */
956
		x = lcdr32(scr, LCD_GenCtrl);
957
		lcdw32(scr, LCD_GenCtrl, x | crtlcd);
958
	}
959
}
960
 
961
static void
962
mach64xxdrawinit(VGAscr *scr)
963
{
964
	if(scr->io > 0x2FF){
965
		initengine(scr);
966
		scr->fill = mach64hwfill;
967
		scr->scroll = mach64hwscroll;
968
	}
969
/*	scr->blank = mach64blank; */
970
	switch(scr->id){
971
	default:
972
		break;
973
	case ('L'<<8)|'B':		/* 4C42: Rage 3D LTPro */
974
	case ('L'<<8)|'I':		/* 4C49: Rage 3D LTPro */
975
	case ('L'<<8)|'M':		/* 4C4D: Rage Mobility */
976
	case ('L'<<8)|'P':		/* 4C50: Rage 3D LTPro */
977
		scr->blank = mach64lcdblank;
978
		hwblank = 1;
979
		break;
980
	}
981
}
982
 
983
static void
984
ovl_configure(VGAscr *scr, Chan *c, char **field)
985
{
986
	int w, h;
987
	char *format;
988
 
989
	w = (int)strtol(field[1], nil, 0);
990
	h = (int)strtol(field[2], nil, 0);
991
	format = field[3];
992
 
993
	if (c != ovl_chan) 
994
		error(Einuse);
995
	if (strcmp(format, "YUYV"))
996
		error(Eunsupportedformat);
997
 
998
	ovl_width  = w;
999
	ovl_height = h;
1000
	ovl_fib       = w * h * sizeof(ushort);
1001
 
1002
	waitforidle(scr);
1003
	scr->mmio[mmoffset[BusCntl]] |= 0x08000000;	/* Enable regblock 1 */
1004
	scr->mmio[mmoffset[OverlayScaleCntl]] = 
1005
		SCALE_ZERO_EXTEND|SCALE_RED_TEMP_6500K|
1006
		SCALE_HORZ_BLEND|SCALE_VERT_BLEND;
1007
	scr->mmio[mmoffset[!mach64revb? Buf0Pitch: ScalerBuf0Pitch]] = w;
1008
	scr->mmio[mmoffset[CaptureConfig]] = 
1009
		SCALER_FRAME_READ_MODE_FULL|
1010
		SCALER_BUF_MODE_SINGLE|
1011
		SCALER_BUF_NEXT_0;
1012
	scr->mmio[mmoffset[OverlayKeyCntl]] = !mach64revb?
1013
		OVERLAY_MIX_ALWAYS_V|(OVERLAY_EXCLUSIVE_NORMAL << 28): 
1014
		0x011;
1015
 
1016
	if (mach64type->m64_pro) {
1017
		waitforfifo(scr, 6);
1018
 
1019
		/* set the scaler co-efficient registers */
1020
		scr->mmio[mmoffset[ScalerColourCntl]] = 
1021
			(0x00) | (0x10 << 8) | (0x10 << 16);
1022
		scr->mmio[mmoffset[ScalerHCoef0]] = 
1023
			(0x00) | (0x20 << 8);
1024
		scr->mmio[mmoffset[ScalerHCoef1]] = 
1025
			(0x0D) | (0x20 << 8) | (0x06 << 16) | (0x0D << 24);
1026
		scr->mmio[mmoffset[ScalerHCoef2]] = 
1027
			(0x0D) | (0x1C << 8) | (0x0A << 16) | (0x0D << 24);
1028
		scr->mmio[mmoffset[ScalerHCoef3]] = 
1029
			(0x0C) | (0x1A << 8) | (0x0E << 16) | (0x0C << 24);
1030
		scr->mmio[mmoffset[ScalerHCoef4]] = 
1031
			(0x0C) | (0x14 << 8) | (0x14 << 16) | (0x0C << 24);
1032
	}
1033
 
1034
	waitforfifo(scr, 3);
1035
	scr->mmio[mmoffset[VideoFormat]] = SCALE_IN_YVYU422 |
1036
		(!mach64revb? 0xC: 0);
1037
 
1038
	if (mach64overlay == 0)
1039
		mach64overlay = scr->storage + 64 * 64 * sizeof(uchar);
1040
	scr->mmio[mmoffset[!mach64revb? Buf0Offset: ScalerBuf0Offset]] = 
1041
		mach64overlay;
1042
}
1043
 
1044
static void
1045
ovl_enable(VGAscr *scr, Chan *c, char **field)
1046
{
1047
	int x, y, w, h;
1048
	long h_inc, v_inc;
1049
 
1050
	x = (int)strtol(field[1], nil, 0);
1051
	y = (int)strtol(field[2], nil, 0);
1052
	w = (int)strtol(field[3], nil, 0);
1053
	h = (int)strtol(field[4], nil, 0);
1054
 
1055
	if (x < 0 || x + w > physgscreenr.max.x ||
1056
	     y < 0 || y + h > physgscreenr.max.y)
1057
		error(Ebadarg);
1058
 
1059
	if (c != ovl_chan) 
1060
		error(Einuse);
1061
	if (scr->mmio[mmoffset[CrtcGenCntl]] & 1) {	/* double scan enable */
1062
		y *= 2;
1063
		h *= 2;
1064
	}
1065
 
1066
	waitforfifo(scr, 2);
1067
	scr->mmio[mmoffset[OverlayYX]] = 
1068
			((x & 0xFFFF) << 16) | (y & 0xFFFF);
1069
	scr->mmio[mmoffset[OverlayYXEnd]] = 
1070
			(((x + w) & 0xFFFF) << 16) | ((y + h) & 0xFFFF);
1071
 
1072
	h_inc = (ovl_width << 12) / (w >> 1);  /* ??? */
1073
	v_inc = (ovl_height << 12) / h;
1074
	waitforfifo(scr, 2);
1075
	scr->mmio[mmoffset[OverlayScaleInc]] = 
1076
			((h_inc & 0xFFFF) << 16) | (v_inc & 0xFFFF);
1077
	scr->mmio[mmoffset[ScalerHeightWidth]] = 
1078
			((ovl_width & 0xFFFF) << 16) | (ovl_height & 0xFFFF);
1079
	waitforidle(scr);
1080
	scr->mmio[mmoffset[OverlayScaleCntl]] |= 
1081
			(SCALE_ENABLE|OVERLAY_ENABLE);
1082
}
1083
 
1084
static void
1085
ovl_status(VGAscr *scr, Chan *, char **field)
1086
{
1087
	pprint("%s: %s %.4uX, VT/GT %s, PRO %s, ovlclock %lud, rev B %s, refclock %ld\n",
1088
		   scr->dev->name, field[0], mach64type->m64_id,
1089
		   mach64type->m64_vtgt? "yes": "no",
1090
		   mach64type->m64_pro? "yes": "no",
1091
		   mach64type->m64_ovlclock,
1092
		   mach64revb? "yes": "no",
1093
		   mach64refclock);
1094
	pprint("%s: storage @%.8luX, aperture @%8.ulX, ovl buf @%.8ulX\n",
1095
		   scr->dev->name, scr->storage, scr->paddr,
1096
		   mach64overlay);
1097
}
1098
 
1099
static void
1100
ovl_openctl(VGAscr *, Chan *c, char **)
1101
{
1102
	if (ovl_chan) 
1103
		error(Einuse);
1104
	ovl_chan = c;
1105
}
1106
 
1107
static void
1108
ovl_closectl(VGAscr *scr, Chan *c, char **)
1109
{
1110
	if (c != ovl_chan) return;
1111
 
1112
	waitforidle(scr);
1113
	scr->mmio[mmoffset[OverlayScaleCntl]] &=
1114
			~(SCALE_ENABLE|OVERLAY_ENABLE);
1115
	ovl_chan = nil;
1116
	ovl_width = ovl_height = ovl_fib = 0;
1117
}
1118
 
1119
enum
1120
{
1121
	CMclosectl,
1122
	CMconfigure,
1123
	CMenable,
1124
	CMopenctl,
1125
	CMstatus,
1126
};
1127
 
1128
static void (*ovl_cmds[])(VGAscr *, Chan *, char **) =
1129
{
1130
	[CMclosectl]	ovl_closectl,
1131
	[CMconfigure]	ovl_configure,
1132
	[CMenable]	ovl_enable,
1133
	[CMopenctl]	ovl_openctl,
1134
	[CMstatus]	ovl_status,
1135
};
1136
 
1137
static Cmdtab mach64xxcmd[] =
1138
{
1139
	CMclosectl,	"closectl",	1,
1140
	CMconfigure,	"configure",	4,
1141
	CMenable,	"enable",	5,
1142
	CMopenctl,	"openctl",	1,
1143
	CMstatus,	"status",	1,
1144
};
1145
 
1146
static void
1147
mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int n)
1148
{
1149
	Cmdbuf *cb;
1150
	Cmdtab *ct;
1151
 
1152
	if(!mach64type->m64_vtgt) 
1153
		error(Enodev);
1154
 
1155
	if(!scr->overlayinit){
1156
		scr->overlayinit = 1;
1157
		init_overlayclock(scr);
1158
	}
1159
	cb = parsecmd(a, n);
1160
	if(waserror()){
1161
		free(cb);
1162
		nexterror();
1163
	}
1164
 
1165
	ct = lookupcmd(cb, mach64xxcmd, nelem(mach64xxcmd));
1166
 
1167
	ovl_cmds[ct->index](scr, c, cb->f);
1168
 
1169
	poperror();
1170
	free(cb);
1171
}
1172
 
1173
static int
1174
mach64xxovlwrite(VGAscr *scr, void *a, int len, vlong offs)
1175
{
1176
	uchar *src;
1177
	int _len;
1178
 
1179
	if (ovl_chan == nil) return len;	/* Acts as a /dev/null */
1180
 
1181
	/* Calculate the destination address */
1182
	_len = len;
1183
	src   = (uchar *)a;
1184
	while (len > 0) {
1185
		ulong _offs;
1186
		int nb;
1187
 
1188
		_offs = (ulong)(offs % ovl_fib);
1189
		nb     = (_offs + len > ovl_fib)? ovl_fib - _offs: len;
1190
		memmove((uchar *)scr->vaddr + mach64overlay + _offs, 
1191
				  src, nb);
1192
		offs += nb;
1193
		src  += nb;
1194
		len  -= nb;
1195
	}
1196
	return _len;
1197
}
1198
 
1199
VGAdev vgamach64xxdev = {
1200
	"mach64xx",
1201
 
1202
	mach64xxenable,			/* enable */
1203
	0,				/* disable */
1204
	0,				/* page */
1205
	mach64xxlinear,			/* linear */
1206
	mach64xxdrawinit,	/* drawinit */
1207
	0,
1208
	mach64xxovlctl,	/* overlay control */
1209
	mach64xxovlwrite,	/* write the overlay */
1210
};
1211
 
1212
VGAcur vgamach64xxcur = {
1213
	"mach64xxhwgc",
1214
 
1215
	mach64xxcurenable,		/* enable */
1216
	mach64xxcurdisable,		/* disable */
1217
	mach64xxcurload,		/* load */
1218
	mach64xxcurmove,		/* move */
1219
 
1220
	1					/* doespanning */
1221
};
1222