xref: /netbsd-src/sys/arch/amiga/dev/grf_rt.c (revision 1f2744e6e4915c9da2a3f980279398c4cf7d5e6d)
1 /*	$NetBSD: grf_rt.c,v 1.22 1995/02/23 19:14:46 chopps Exp $	*/
2 
3 /*
4  * Copyright (c) 1993 Markus Wild
5  * Copyright (c) 1993 Lutz Vieweg
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by Lutz Vieweg.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 #include "grfrt.h"
34 #if NGRFRT > 0
35 
36 /* Graphics routines for the Retina board,
37    using the NCR 77C22E+ VGA controller. */
38 
39 #include <sys/param.h>
40 #include <sys/errno.h>
41 #include <sys/ioctl.h>
42 #include <sys/device.h>
43 #include <machine/cpu.h>
44 #include <amiga/amiga/device.h>
45 #include <amiga/dev/zbusvar.h>
46 #include <amiga/dev/grfioctl.h>
47 #include <amiga/dev/grfvar.h>
48 #include <amiga/dev/grf_rtreg.h>
49 
50 int rt_ioctl __P((struct grf_softc *gp, u_long, void *));
51 
52 /*
53  * marked true early so that retina_cnprobe() can tell if we are alive.
54  */
55 int retina_inited;
56 
57 
58 /*
59  * This driver for the MacroSystem Retina board was only possible,
60  * because MacroSystem provided information about the pecularities
61  * of the board. THANKS! Competition in Europe among gfx board
62  * manufacturers is rather tough, so Lutz Vieweg, who wrote the
63  * initial driver, has made an agreement with MS not to document
64  * the driver source (see also his comment below).
65  * -> ALL comments after
66  * -> "/* -------------- START OF CODE -------------- * /"
67  * -> have been added by myself (mw) from studying the publically
68  * -> available "NCR 77C22E+" Data Manual
69  */
70 /*
71  * This code offers low-level routines to access the Retina graphics-board
72  * manufactured by MS MacroSystem GmbH from within NetBSD for the Amiga.
73  *
74  * Thanks to MacroSystem for providing me with the neccessary information
75  * to create theese routines. The sparse documentation of this code
76  * results from the agreements between MS and me.
77  */
78 
79 extern unsigned char kernel_font_8x8_width, kernel_font_8x8_height;
80 extern unsigned char kernel_font_8x8_lo, kernel_font_8x8_hi;
81 extern unsigned char kernel_font_8x8[];
82 
83 
84 #define MDF_DBL 1
85 #define MDF_LACE 2
86 #define MDF_CLKDIV2 4
87 
88 
89 /* standard-palette definition */
90 
91 unsigned char NCRStdPalette[16*3] = {
92 /*   R   G   B  */
93 	  0,  0,  0,
94 	192,192,192,
95 	128,  0,  0,
96 	  0,128,  0,
97 	  0,  0,128,
98 	128,128,  0,
99 	  0,128,128,
100 	128,  0,128,
101 	 64, 64, 64, /* the higher 8 colors have more intensity for  */
102 	255,255,255, /* compatibility with standard attributes       */
103 	255,  0,  0,
104 	  0,255,  0,
105 	  0,  0,255,
106 	255,255,  0,
107 	  0,255,255,
108 	255,  0,255
109 };
110 
111 
112 /* The following structures are examples for monitor-definitions. To make one
113    of your own, first use "DefineMonitor" and create the 8-bit monitor-mode of
114    your dreams. Then save it, and make a structure from the values provided in
115    the file DefineMonitor stored - the labels in the comment above the
116    structure definition show where to put what value.
117 
118    Then you'll need to adapt your monitor-definition to the font you want to
119    use. Be FX the width of the font, then the following modifications have to
120    be applied to your values:
121 
122    HBS = (HBS * 4) / FX
123    HSS = (HSS * 4) / FX
124    HSE = (HSE * 4) / FX
125    HBE = (HBE * 4) / FX
126    HT  = (HT  * 4) / FX
127 
128    Make sure your maximum width (MW) and height (MH) are even multiples of
129    the fonts' width and height.
130 */
131 
132 #if 0
133 /* horizontal 31.5 kHz */
134 
135 /*                                      FQ     FLG    MW   MH   HBS HSS HSE HBE  HT  VBS  VSS  VSE  VBE   VT  */
136    struct MonDef MON_640_512_60  = { 50000000,  28,  640, 512,   81, 86, 93, 98, 95, 513, 513, 521, 535, 535,
137    /* Depth,           PAL, TX,  TY,    XY,FontX, FontY,    FontData,  FLo,  Fhi */
138           4, NCRStdPalette, 80,  64,  5120,    8,     8, kernel_font_8x8,   32,  255};
139 
140  struct MonDef MON_640_480_62_G  = { 50000000,   4,  640, 480,  161,171,184,196,195, 481, 484, 492, 502, 502,
141           8, NCRStdPalette,640,480,  5120,    8,     8, kernel_font_8x8,   32,  255};
142 /* Enter higher values here ^   ^ for panning! */
143 
144 /* horizontal 38kHz */
145 
146    struct MonDef MON_768_600_60  = { 75000000,  28,  768, 600,   97, 99,107,120,117, 601, 615, 625, 638, 638,
147           4, NCRStdPalette, 96,  75,  7200,    8,     8, kernel_font_8x8,   32,  255};
148 
149 /* horizontal 64kHz */
150 
151    struct MonDef MON_768_600_80  = { 50000000, 24,  768, 600,   97,104,112,122,119, 601, 606, 616, 628, 628,
152           4, NCRStdPalette, 96,  75,  7200,    8,     8, kernel_font_8x8,   32,  255};
153 
154    struct MonDef MON_1024_768_80 = { 90000000, 24, 1024, 768,  129,130,141,172,169, 769, 770, 783, 804, 804,
155           4, NCRStdPalette,128,  96, 12288,    8,     8, kernel_font_8x8,   32,  255};
156 
157 /*                                     FQ     FLG    MW   MH   HBS HSS HSE HBE  HT  VBS  VSS  VSE  VBE   VT  */
158  struct MonDef MON_1024_768_80_G = { 90000000, 0,  1024, 768,  257,258,280,344,343, 769, 770, 783, 804, 804,
159           8, NCRStdPalette, 1024, 768, 12288,    8,     8, kernel_font_8x8,   32,  255};
160 
161    struct MonDef MON_1024_1024_59= { 90000000, 24, 1024,1024,  129,130,141,173,170,1025,1059,1076,1087,1087,
162           4, NCRStdPalette,128, 128, 16384,    8,     8, kernel_font_8x8,   32,  255};
163 
164 /* WARNING: THE FOLLOWING MONITOR MODES EXCEED THE 90-MHz LIMIT THE PROCESSOR
165             HAS BEEN SPECIFIED FOR. USE AT YOUR OWN RISK (AND THINK ABOUT
166             MOUNTING SOME COOLING DEVICE AT THE PROCESSOR AND RAMDAC)!     */
167 
168    struct MonDef MON_1280_1024_60= {110000000,  24, 1280,1024,  161,162,176,211,208,1025,1026,1043,1073,1073,
169           4, NCRStdPalette,160, 128, 20480,    8,     8, kernel_font_8x8,   32,  255};
170 
171  struct MonDef MON_1280_1024_60_G= {110000000,   0, 1280,1024,  321,322,349,422,421,1025,1026,1043,1073,1073,
172           8, NCRStdPalette,1280,1024, 20480,    8,     8, kernel_font_8x8,   32,  255};
173 
174 /* horizontal 75kHz */
175 
176    struct MonDef MON_1280_1024_69= {120000000,  24, 1280,1024,  161,162,175,200,197,1025,1026,1043,1073,1073,
177           4, NCRStdPalette,160, 128, 20480,    8,     8, kernel_font_8x8,   32,  255};
178 
179 #else
180 
181 struct MonDef monitor_defs[] = {
182 /* horizontal 31.5 kHz */
183 
184    { 50000000,  28,  640, 512,   81, 86, 93, 98, 95, 513, 513, 521, 535, 535,
185           4, NCRStdPalette, 80,  64,  5120,    8,     8, kernel_font_8x8,   32,  255},
186 
187 /* horizontal 38kHz */
188 
189    { 75000000,  28,  768, 600,   97, 99,107,120,117, 601, 615, 625, 638, 638,
190           4, NCRStdPalette, 96,  75,  7200,    8,     8, kernel_font_8x8,   32,  255},
191 
192 /* horizontal 64kHz */
193 
194    { 50000000, 24,  768, 600,   97,104,112,122,119, 601, 606, 616, 628, 628,
195           4, NCRStdPalette, 96,  75,  7200,    8,     8, kernel_font_8x8,   32,  255},
196 
197    { 90000000, 24, 1024, 768,  129,130,141,172,169, 769, 770, 783, 804, 804,
198           4, NCRStdPalette,128,  96, 12288,    8,     8, kernel_font_8x8,   32,  255},
199 
200    /* GFX modes */
201 
202 /* horizontal 31.5 kHz */
203 
204    { 50000000,   4,  640, 480,  161,171,184,196,195, 481, 484, 492, 502, 502,
205           8, NCRStdPalette,640, 480,  5120,    8,     8, kernel_font_8x8,   32,  255},
206 
207 /* horizontal 64kHz */
208 
209    { 90000000, 0,  1024, 768,  257,258,280,344,343, 769, 770, 783, 804, 804,
210           8, NCRStdPalette, 1024, 768, 12288,    8,     8, kernel_font_8x8,   32,  255},
211 
212 /* WARNING: THE FOLLOWING MONITOR MODES EXCEED THE 90-MHz LIMIT THE PROCESSOR
213             HAS BEEN SPECIFIED FOR. USE AT YOUR OWN RISK (AND THINK ABOUT
214             MOUNTING SOME COOLING DEVICE AT THE PROCESSOR AND RAMDAC)!     */
215 
216    {110000000,   0, 1280,1024,  321,322,349,422,421,1025,1026,1043,1073,1073,
217           8, NCRStdPalette,1280,1024, 20480,    8,     8, kernel_font_8x8,   32,  255},
218 };
219 
220 static const char *monitor_descr[] = {
221   "80x64 (640x512) 31.5kHz",
222   "96x75 (768x600) 38kHz",
223   "96x75 (768x600) 64kHz",
224   "128x96 (1024x768) 64kHz",
225 
226   "GFX (640x480) 31.5kHz",
227   "GFX (1024x768) 64kHz",
228   "GFX (1280x1024) 64kHz ***EXCEEDS CHIP LIMIT!!!***",
229 };
230 
231 int retina_mon_max = sizeof (monitor_defs)/sizeof (monitor_defs[0]);
232 
233 /* patchable */
234 int retina_default_mon = 0;
235 int retina_default_gfx = 4;
236 
237 #endif
238 
239 
240 static struct MonDef *current_mon;
241 
242 /* -------------- START OF CODE -------------- */
243 
244 
245 static const long FQTab[16] =
246 { 25175000,  28322000,  36000000,  65000000,
247   44900000,  50000000,  80000000,  75000000,
248   56644000,  63000000,  72000000, 130000000,
249   90000000, 100000000, 110000000, 120000000 };
250 
251 
252 /*--------------------------------------------------*/
253 /*--------------------------------------------------*/
254 
255 #if 0
256 static struct MonDef *default_monitor = &DEFAULT_MONDEF;
257 #endif
258 
259 /*
260  * used to query the retina to see if its alive (?)
261  */
262 int
263 retina_alive(mdp)
264 	struct MonDef *mdp;
265 {
266 	short clksel;
267 
268 	for (clksel = 15; clksel; clksel--) {
269 		if (FQTab[clksel] == mdp->FQ)
270 			break;
271 	}
272 	if (clksel < 0)
273 		return(0);
274 	if (mdp->DEP != 4)
275 		return(1);
276 	if (mdp->FX == 4 || (mdp->FX >= 7 && mdp->FX <= 16))
277 		return(1);
278 	return(0);
279 }
280 
281 static int
282 rt_load_mon(gp, md)
283 	struct grf_softc *gp;
284 	struct MonDef *md;
285 {
286 	struct grfinfo *gi = &gp->g_display;
287 	volatile unsigned char *ba;
288 	volatile unsigned char *fb;
289 	short FW, clksel, HDE, VDE;
290 
291 	for (clksel = 15; clksel; clksel--) {
292 		if (FQTab[clksel] == md->FQ) break;
293 	}
294 	if (clksel < 0)
295 		return(0);
296 
297 	ba = gp->g_regkva;;
298 	fb = gp->g_fbkva;
299 
300 	FW = 0;
301 	if (md->DEP == 4) {
302 		switch (md->FX) {
303 		case 4:
304 			FW = 0;
305 			break;
306 		case 7:
307 			FW = 1;
308 			break;
309 		case 8:
310 			FW = 2;
311 			break;
312 		case 9:
313 			FW = 3;
314 			break;
315 		case 10:
316 			FW = 4;
317 			break;
318 		case 11:
319 			FW = 5;
320 			break;
321 		case 12:
322 			FW = 6;
323 			break;
324 		case 13:
325 			FW = 7;
326 			break;
327 		case 14:
328 			FW = 8;
329 			break;
330 		case 15:
331 			FW = 9;
332 			break;
333 		case 16:
334 			FW = 11;
335 			break;
336 		default:
337 			return(0);
338 			break;
339 		};
340 	}
341 
342         if (md->DEP == 4) HDE = (md->MW+md->FX-1)/md->FX;
343         else              HDE = (md->MW+3)/4;
344 	VDE = md->MH-1;
345 
346 	/* hmm... */
347 	fb[0x8000] = 0;
348 
349 		/* enable extension registers */
350 	WSeq (ba, SEQ_ID_EXTENDED_ENABLE,	0x05);
351 
352 #if 0
353 	/* program the clock oscillator */
354 	vgaw (ba, GREG_MISC_OUTPUT_W, 0xe3 | ((clksel & 3) * 0x04));
355 	vgaw (ba, GREG_FEATURE_CONTROL_W, 0x00);
356 
357 	/* XXXX according to the NCR specs, this register should be set to 1
358 	   XXXX before doing the MISC_OUTPUT setting and CLOCKING_MODE
359 	   XXXX setting. */
360 	WSeq (ba, SEQ_ID_RESET, 		0x03);
361 
362 	WSeq (ba, SEQ_ID_CLOCKING_MODE, 	0x01 | ((md->FLG & MDF_CLKDIV2)/ MDF_CLKDIV2 * 8));
363 	WSeq (ba, SEQ_ID_MAP_MASK, 		0x0f);
364 	WSeq (ba, SEQ_ID_CHAR_MAP_SELECT, 	0x00);
365 		/* odd/even write select + extended memory */
366 	WSeq (ba, SEQ_ID_MEMORY_MODE, 	0x06);
367 	/* XXXX I think this order of setting RESET is wrong... */
368 	WSeq (ba, SEQ_ID_RESET, 		0x01);
369 	WSeq (ba, SEQ_ID_RESET, 		0x03);
370 #else
371 	WSeq (ba, SEQ_ID_RESET, 		0x01);
372 
373 		/* set font width + rest of clocks */
374 	WSeq (ba, SEQ_ID_EXT_CLOCK_MODE,	0x30 | (FW & 0x0f) | ((clksel & 4) / 4 * 0x40) );
375 		/* another clock bit, plus hw stuff */
376 	WSeq (ba, SEQ_ID_MISC_FEATURE_SEL,	0xf4 | (clksel & 8) );
377 
378 	/* program the clock oscillator */
379 	vgaw (ba, GREG_MISC_OUTPUT_W, 		0xe3 | ((clksel & 3) * 0x04));
380 	vgaw (ba, GREG_FEATURE_CONTROL_W, 	0x00);
381 
382 	WSeq (ba, SEQ_ID_CLOCKING_MODE, 	0x01 | ((md->FLG & MDF_CLKDIV2)/ MDF_CLKDIV2 * 8));
383 	WSeq (ba, SEQ_ID_MAP_MASK, 		0x0f);
384 	WSeq (ba, SEQ_ID_CHAR_MAP_SELECT, 	0x00);
385 		/* odd/even write select + extended memory */
386 	WSeq (ba, SEQ_ID_MEMORY_MODE, 		0x06);
387 	WSeq (ba, SEQ_ID_RESET, 		0x03);
388 #endif
389 
390 		/* monochrome cursor */
391 	WSeq (ba, SEQ_ID_CURSOR_CONTROL,	0x00);
392 		/* bank0 */
393 	WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI,	0x00);
394 	WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO,	0x00);
395 	WSeq (ba, SEQ_ID_DISP_OFF_HI , 		0x00);
396 	WSeq (ba, SEQ_ID_DISP_OFF_LO , 		0x00);
397 		/* bank0 */
398 	WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI,	0x00);
399 	WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO,	0x00);
400 		/* 1M-chips + ena SEC + ena EMem + rw PrimA0/rw Sec/B0 */
401 	WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA,	0x3 | 0x4 | 0x10 | 0x40);
402 #if 0
403 		/* set font width + rest of clocks */
404 	WSeq (ba, SEQ_ID_EXT_CLOCK_MODE,	0x30 | (FW & 0x0f) | ((clksel & 4) / 4 * 0x40) );
405 #endif
406 	if (md->DEP == 4) {
407 			/* no ext-chain4 + no host-addr-bit-16 */
408 		WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR,	0x00);
409 			/* no packed/nibble + no 256bit gfx format */
410 		WSeq (ba, SEQ_ID_EXT_PIXEL_CNTL,	0x00);
411 	}
412 	else {
413 		WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR,	0x02);
414 			/* 256bit gfx format */
415 		WSeq (ba, SEQ_ID_EXT_PIXEL_CNTL,	0x01);
416 	}
417 		/* AT-interface */
418 	WSeq (ba, SEQ_ID_BUS_WIDTH_FEEDB,	0x06);
419 		/* see fg/bg color expansion */
420 	WSeq (ba, SEQ_ID_COLOR_EXP_WFG,		0x01);
421 	WSeq (ba, SEQ_ID_COLOR_EXP_WBG,		0x00);
422 	WSeq (ba, SEQ_ID_EXT_RW_CONTROL,	0x00);
423 #if 0
424 		/* another clock bit, plus hw stuff */
425 	WSeq (ba, SEQ_ID_MISC_FEATURE_SEL,	0xf4 | (clksel & 8) );
426 #endif
427 		/* don't tristate PCLK and PIX */
428 	WSeq (ba, SEQ_ID_COLOR_KEY_CNTL,	0x40 );
429 		/* reset CRC circuit */
430 	WSeq (ba, SEQ_ID_CRC_CONTROL,		0x00 );
431 		/* set RAS/CAS swap */
432 	WSeq (ba, SEQ_ID_PERF_SELECT,		0x20);
433 
434 	WCrt (ba, CRT_ID_END_VER_RETR,		(md->VSE & 0xf ) | 0x20);
435 	WCrt (ba, CRT_ID_HOR_TOTAL,		md->HT   & 0xff);
436 	WCrt (ba, CRT_ID_HOR_DISP_ENA_END,	(HDE-1)  & 0xff);
437 	WCrt (ba, CRT_ID_START_HOR_BLANK,	md->HBS  & 0xff);
438 	WCrt (ba, CRT_ID_END_HOR_BLANK,		(md->HBE & 0x1f) | 0x80);
439 
440 	WCrt (ba, CRT_ID_START_HOR_RETR,	md->HSS  & 0xff);
441 	WCrt (ba, CRT_ID_END_HOR_RETR,		(md->HSE & 0x1f) | ((md->HBE & 0x20)/ 0x20 * 0x80));
442 	WCrt (ba, CRT_ID_VER_TOTAL,		(md->VT  & 0xff));
443 	WCrt (ba, CRT_ID_OVERFLOW,		(( (md->VSS  & 0x200) / 0x200 * 0x80)
444 						 | ((VDE     & 0x200) / 0x200 * 0x40)
445 						 | ((md->VT  & 0x200) / 0x200 * 0x20)
446 						 | 				0x10
447 						 | ((md->VBS & 0x100) / 0x100 * 8   )
448 						 | ((md->VSS & 0x100) / 0x100 * 4   )
449 						 | ((VDE     & 0x100) / 0x100 * 2   )
450 						 | ((md->VT  & 0x100) / 0x100       )));
451 	WCrt (ba, CRT_ID_PRESET_ROW_SCAN,	0x00);
452 
453 	if (md->DEP == 4) {
454 		WCrt (ba, CRT_ID_MAX_SCAN_LINE, 	((  (md->FLG & MDF_DBL)/ MDF_DBL * 0x80)
455 							 | 				   0x40
456 							 | ((md->VBS & 0x200)/0x200	 * 0x20)
457 							 | ((md->FY-1) 			 & 0x1f)));
458 	}
459 	else {
460 		WCrt (ba, CRT_ID_MAX_SCAN_LINE, 	((  (md->FLG & MDF_DBL)/ MDF_DBL * 0x80)
461 							 | 				   0x40
462 							 | ((md->VBS & 0x200)/0x200	 * 0x20)
463 							 | (0	 			 & 0x1f)));
464 	}
465 
466 	WCrt (ba, CRT_ID_CURSOR_START,		(md->FY & 0x1f) - 2);
467 	WCrt (ba, CRT_ID_CURSOR_END,		(md->FY & 0x1f) - 1);
468 
469 	WCrt (ba, CRT_ID_START_ADDR_HIGH,	0x00);
470 	WCrt (ba, CRT_ID_START_ADDR_LOW,	0x00);
471 
472 	WCrt (ba, CRT_ID_CURSOR_LOC_HIGH,	0x00);
473 	WCrt (ba, CRT_ID_CURSOR_LOC_LOW,	0x00);
474 
475 	WCrt (ba, CRT_ID_START_VER_RETR,	md->VSS    & 0xff);
476 	WCrt (ba, CRT_ID_END_VER_RETR,		(md->VSE   & 0x0f) | 0x80 | 0x20);
477 	WCrt (ba, CRT_ID_VER_DISP_ENA_END,	VDE        & 0xff);
478 	if (md->DEP == 4)
479 		WCrt (ba, CRT_ID_OFFSET,	(HDE / 2)  & 0xff);
480 	else
481 		WCrt (ba, CRT_ID_OFFSET,	(md->TX / 8)  & 0xff);
482 
483 	WCrt (ba, CRT_ID_UNDERLINE_LOC,		(md->FY-1) & 0x1f);
484 	WCrt (ba, CRT_ID_START_VER_BLANK,	md->VBS    & 0xff);
485 	WCrt (ba, CRT_ID_END_VER_BLANK,		md->VBE    & 0xff);
486 		/* byte mode + wrap + select row scan counter + cms */
487 	WCrt (ba, CRT_ID_MODE_CONTROL,		0xe3);
488 	WCrt (ba, CRT_ID_LINE_COMPARE,		0xff);
489 
490 		/* enable extended end bits + those bits */
491 	WCrt (ba, CRT_ID_EXT_HOR_TIMING1,	(           				 0x20
492 						 | ((md->FLG & MDF_LACE)  / MDF_LACE   * 0x10)
493 						 | ((md->HT  & 0x100) / 0x100          * 0x01)
494 						 | (((HDE-1) & 0x100) / 0x100 	       * 0x02)
495 						 | ((md->HBS & 0x100) / 0x100 	       * 0x04)
496 						 | ((md->HSS & 0x100) / 0x100 	       * 0x08)));
497 
498 	if (md->DEP == 4)
499 		WCrt (ba, CRT_ID_EXT_START_ADDR,	(((HDE / 2) & 0x100)/0x100 * 16));
500 	else
501 		WCrt (ba, CRT_ID_EXT_START_ADDR,	(((md->TX / 8) & 0x100)/0x100 * 16));
502 
503 	WCrt (ba, CRT_ID_EXT_HOR_TIMING2, 	(  ((md->HT  & 0x200)/ 0x200  	       * 0x01)
504 						 | (((HDE-1) & 0x200)/ 0x200 	       * 0x02)
505 						 | ((md->HBS & 0x200)/ 0x200 	       * 0x04)
506 						 | ((md->HSS & 0x200)/ 0x200 	       * 0x08)
507 						 | ((md->HBE & 0xc0) / 0x40  	       * 0x10)
508 						 | ((md->HSE & 0x60) / 0x20  	       * 0x40)));
509 
510 	WCrt (ba, CRT_ID_EXT_VER_TIMING,	(  ((md->VSE & 0x10) / 0x10  	       * 0x80)
511 						 | ((md->VBE & 0x300)/ 0x100 	       * 0x20)
512 						 |				         0x10
513 						 | ((md->VSS & 0x400)/ 0x400 	       * 0x08)
514 						 | ((md->VBS & 0x400)/ 0x400 	       * 0x04)
515 						 | ((VDE     & 0x400)/ 0x400 	       * 0x02)
516 						 | ((md->VT  & 0x400)/ 0x400           * 0x01)));
517 
518 	WGfx (ba, GCT_ID_SET_RESET,		0x00);
519 	WGfx (ba, GCT_ID_ENABLE_SET_RESET,	0x00);
520 	WGfx (ba, GCT_ID_COLOR_COMPARE,		0x00);
521 	WGfx (ba, GCT_ID_DATA_ROTATE,		0x00);
522 	WGfx (ba, GCT_ID_READ_MAP_SELECT,	0x00);
523 	WGfx (ba, GCT_ID_GRAPHICS_MODE,		0x00);
524 	if (md->DEP == 4)
525 		WGfx (ba, GCT_ID_MISC,			0x04);
526 	else
527 		WGfx (ba, GCT_ID_MISC,			0x05);
528 	WGfx (ba, GCT_ID_COLOR_XCARE,		0xff);
529 	WGfx (ba, GCT_ID_BITMASK,		0xff);
530 
531 	/* reset the Attribute Controller flipflop */
532 	vgar (ba, GREG_STATUS1_R);
533 	WAttr (ba, ACT_ID_PALETTE0,		0x00);
534 	WAttr (ba, ACT_ID_PALETTE1,		0x01);
535 	WAttr (ba, ACT_ID_PALETTE2,		0x02);
536 	WAttr (ba, ACT_ID_PALETTE3,		0x03);
537 	WAttr (ba, ACT_ID_PALETTE4,		0x04);
538 	WAttr (ba, ACT_ID_PALETTE5,		0x05);
539 	WAttr (ba, ACT_ID_PALETTE6,		0x06);
540 	WAttr (ba, ACT_ID_PALETTE7,		0x07);
541 	WAttr (ba, ACT_ID_PALETTE8,		0x08);
542 	WAttr (ba, ACT_ID_PALETTE9,		0x09);
543 	WAttr (ba, ACT_ID_PALETTE10,		0x0a);
544 	WAttr (ba, ACT_ID_PALETTE11,		0x0b);
545 	WAttr (ba, ACT_ID_PALETTE12,		0x0c);
546 	WAttr (ba, ACT_ID_PALETTE13,		0x0d);
547 	WAttr (ba, ACT_ID_PALETTE14,		0x0e);
548 	WAttr (ba, ACT_ID_PALETTE15,		0x0f);
549 
550 	vgar (ba, GREG_STATUS1_R);
551 	if (md->DEP == 4)
552 		WAttr (ba, ACT_ID_ATTR_MODE_CNTL,	0x08);
553 	else
554 		WAttr (ba, ACT_ID_ATTR_MODE_CNTL,	0x09);
555 
556 	WAttr (ba, ACT_ID_OVERSCAN_COLOR,	0x00);
557 	WAttr (ba, ACT_ID_COLOR_PLANE_ENA,	0x0f);
558 	WAttr (ba, ACT_ID_HOR_PEL_PANNING,	0x00);
559 	WAttr (ba, ACT_ID_COLOR_SELECT,	0x00);
560 
561 	vgar (ba, GREG_STATUS1_R);
562 		/* I have *NO* idea what strobing reg-0x20 might do... */
563 	vgaw (ba, ACT_ADDRESS_W, 0x20);
564 
565 	if (md->DEP == 4)
566 		WCrt (ba, CRT_ID_MAX_SCAN_LINE,	( ((md->FLG & MDF_DBL)/ MDF_DBL * 0x80)
567 						|	                          0x40
568 						| ((md->VBS & 0x200)/0x200	* 0x20)
569 						| ((md->FY-1) 			& 0x1f)));
570 	else
571 		WCrt (ba, CRT_ID_MAX_SCAN_LINE,	( ((md->FLG & MDF_DBL)/ MDF_DBL * 0x80)
572 						|	                          0x40
573 						| ((md->VBS & 0x200)/0x200	* 0x20)
574 						| (0	 			& 0x1f)));
575 
576 
577 	/* not it's time for guessing... */
578 
579 	vgaw (ba, VDAC_REG_D, 	   0x02);
580 
581 		/* if this does what I think it does, it selects DAC
582 		   register 0, and writes the palette in subsequent
583 		   registers, thus it works similar to the WD33C93
584 		   select/data mechanism */
585 	vgaw (ba, VDAC_REG_SELECT, 0x00);
586 
587 	{
588 
589 		short x = 15;
590 		const unsigned char * col = md->PAL;
591 		do {
592 
593 			vgaw (ba, VDAC_REG_DATA, *col++);
594 			vgaw (ba, VDAC_REG_DATA, *col++);
595 			vgaw (ba, VDAC_REG_DATA, *col++);
596 
597 
598 		} while (x--);
599 
600 		if (md->DEP != 4) {
601 			short x = 256-17;
602 			unsigned char col = 16;
603 			do {
604 
605 				vgaw(ba, VDAC_REG_DATA, col);
606 				vgaw(ba, VDAC_REG_DATA, col);
607 				vgaw(ba, VDAC_REG_DATA, col);
608 				col++;
609 
610 			} while (x--);
611 		}
612 	}
613 
614 
615 	/* now load the font into maps 2 (and 3 for fonts wider than 8 pixels) */
616 	if (md->DEP == 4) {
617 
618 		/* first set the whole font memory to a test-pattern, so we
619 		   can see if something that shouldn't be drawn IS drawn.. */
620 		{
621 			volatile unsigned char * c = fb;
622 			long x;
623 			Map(2);
624 
625 			for (x = 0; x < 65536; x++) {
626 				*c++ = (x & 1)? 0xaa : 0x55;
627 			}
628 		}
629 
630 		{
631 			volatile unsigned char * c = fb;
632 			long x;
633 			Map(3);
634 
635 			for (x = 0; x < 65536; x++) {
636 				*c++ = (x & 1)? 0xaa : 0x55;
637 			}
638 		}
639 
640 		{
641 		  /* ok, now position at first defined character, and
642 		     copy over the images */
643 		  volatile unsigned char * c = fb + md->FLo * 32;
644 		  const unsigned char * f = md->FData;
645 		  unsigned short z;
646 
647 		  Map(2);
648 		  for (z = md->FLo; z <= md->FHi; z++) {
649 
650 			short y = md->FY-1;
651 			if (md->FX > 8){
652 				do {
653 					*c++ = *f;
654 					f += 2;
655 				} while (y--);
656 			}
657 			else {
658 				do {
659 					*c++ = *f++;
660 				} while (y--);
661 			}
662 
663 			c += 32-md->FY;
664 
665 		  }
666 
667 		  if (md->FX > 8) {
668 			unsigned short z;
669 
670 			Map(3);
671 			c = fb + md->FLo*32;
672 			f = md->FData+1;
673 			for (z = md->FLo; z <= md->FHi; z++) {
674 
675 				short y = md->FY-1;
676 				do {
677 					*c++ = *f;
678 					f += 2;
679 				} while (y--);
680 
681 				c += 32-md->FY;
682 
683 			}
684 		  }
685 		}
686 
687 	}
688 
689 		/* select map 0 */
690 	WGfx (ba, GCT_ID_READ_MAP_SELECT,	0);
691 	if (md->DEP == 4)
692 			/* allow writes into maps 0 and 1 */
693 		WSeq (ba, SEQ_ID_MAP_MASK,		3);
694 	else
695 			/* allow writes into all maps */
696 		WSeq (ba, SEQ_ID_MAP_MASK,		0x0f);
697 
698 		/* select extended chain4 addressing:
699 		    !A0/!A1	map 0	character to be displayed
700 		    !A1/ A1	map 1	attribute of that character
701 		     A0/!A1	map 2	not used (masked out, ignored)
702 		     A0/ A1 	map 3	not used (masked out, ignored) */
703 	WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR,	RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02);
704 
705 	if (md->DEP == 4) {
706 		/* position in display memory */
707 		unsigned short * c = (unsigned short *) fb;
708 
709 		/* fill with blank, white on black */
710 		const unsigned short fill_val = 0x2010;
711 		short x = md->XY;
712 		do {
713 			*c = fill_val;
714 			c += 2; } while (x--);
715 
716 		/* I won't comment this :-)) */
717 		c = (unsigned short *) fb;
718 		c += (md->TX-6)*2;
719 		{
720 		  unsigned short init_msg[6] = {0x520a, 0x450b, 0x540c, 0x490d, 0x4e0e, 0x410f};
721 		  unsigned short * f = init_msg;
722 		  x = 5;
723 		  do {
724 			*c = *f++;
725 			c += 2;
726 	 	  } while (x--);
727 	 	}
728 	}
729 	else if (md->DEP == 8) {
730 		/* could clear the gfx screen here, but that's what the X server does anyway */
731 	        ;
732 	}
733 
734 	gp->g_data	= (caddr_t)md;
735 	gi->gd_regaddr  = (caddr_t)ztwopa(ba);
736 	gi->gd_regsize  = 64*1024;
737 
738 	gi->gd_fbaddr   = (caddr_t)ztwopa(fb);
739 #ifdef BANKEDDEVPAGER
740 	gi->gd_fbsize	= 4*1024*1024;  /* XXX */
741 	gi->gd_bank_size = 64*1024;
742 #else
743 	gi->gd_fbsize   = 64*1024;	/* larger, but that's whats mappable */
744 #endif
745 
746 	gi->gd_colors   = 1 << md->DEP;
747 	gi->gd_planes   = md->DEP;
748 
749 	gi->gd_fbwidth  = md->MW;
750 	gi->gd_fbheight = md->MH;
751 	gi->gd_fbx	= 0;
752 	gi->gd_fby	= 0;
753 	gi->gd_dwidth   = md->TX * md->FX;
754 	gi->gd_dheight  = md->TY * md->FY;
755 	gi->gd_dx	= 0;
756 	gi->gd_dy	= 0;
757 
758 	/* initialized, works, return 1 */
759 	return(1);
760 }
761 
762 int rt_mode __P((struct grf_softc *, int, void *, int , int));
763 
764 void grfrtattach __P((struct device *, struct device *, void *));
765 int grfrtprint __P((void *, char *));
766 int grfrtmatch __P((struct device *, struct cfdata *, void *));
767 
768 struct cfdriver grfrtcd = {
769 	NULL, "grfrt", (cfmatch_t)grfrtmatch, grfrtattach,
770 	DV_DULL, sizeof(struct grf_softc), NULL, 0 };
771 
772 /*
773  * only used in console init
774  */
775 static struct cfdata *cfdata;
776 
777 /*
778  * we make sure to only init things once.  this is somewhat
779  * tricky regarding the console.
780  */
781 int
782 grfrtmatch(pdp, cfp, auxp)
783 	struct device *pdp;
784 	struct cfdata *cfp;
785 	void *auxp;
786 {
787 #ifdef RETINACONSOLE
788 	static int rtconunit = -1;
789 #endif
790 	struct zbus_args *zap;
791 
792 	zap = auxp;
793 
794 	/*
795 	 * allow only one retina console
796 	 */
797 	if (amiga_realconfig == 0)
798 #ifdef RETINACONSOLE
799 		if (rtconunit != -1)
800 #endif
801 			return(0);
802 	/*
803 	 * check that this is a retina board.
804 	 */
805 	if (zap->manid != 18260 || zap->prodid != 6)
806 		return(0);
807 
808 #ifdef RETINACONSOLE
809 	if (amiga_realconfig == 0 || rtconunit != cfp->cf_unit) {
810 #endif
811 		if ((unsigned)retina_default_mon >= retina_mon_max ||
812 		    monitor_defs[retina_default_mon].DEP == 8)
813 			retina_default_mon = 0;
814 
815 		current_mon = monitor_defs + retina_default_mon;
816 		if (retina_alive(current_mon) == 0)
817 			return(0);
818 #ifdef RETINACONSOLE
819 		if (amiga_realconfig == 0) {
820 			rtconunit = cfp->cf_unit;
821 			cfdata = cfp;
822 		}
823 	}
824 #endif
825 	return(1);
826 }
827 
828 /*
829  * attach to the grfbus (zbus)
830  */
831 void
832 grfrtattach(pdp, dp, auxp)
833 	struct device *pdp, *dp;
834 	void *auxp;
835 {
836 	static struct grf_softc congrf;
837 	static int coninited;
838 	struct zbus_args *zap;
839 	struct grf_softc *gp;
840 
841 	zap = auxp;
842 
843 	if (dp == NULL)
844 		gp = &congrf;
845 	else
846 		gp = (struct grf_softc *)dp;
847 
848 	if (dp != NULL && congrf.g_regkva != 0) {
849 		/*
850 		 * we inited earlier just copy the info
851 		 * take care not to copy the device struct though.
852 		 */
853 		bcopy(&congrf.g_display, &gp->g_display,
854 		    (char *)&gp[1] - (char *)&gp->g_display);
855 	} else {
856 		gp->g_regkva = (volatile caddr_t)zap->va;
857 		gp->g_fbkva = (volatile caddr_t)zap->va + 64 * 1024;
858 		gp->g_unit = GRF_RETINAII_UNIT;
859 		gp->g_flags = GF_ALIVE;
860 		gp->g_mode = rt_mode;
861 		gp->g_conpri = grfrt_cnprobe();
862 		grfrt_iteinit(gp);
863 		(void)rt_load_mon(gp, current_mon);
864 	}
865 	if (dp != NULL)
866 		printf("\n");
867 	/*
868 	 * attach grf
869 	 */
870 	amiga_config_found(cfdata, &gp->g_device, gp, grfrtprint);
871 }
872 
873 int
874 grfrtprint(auxp, pnp)
875 	void *auxp;
876 	char *pnp;
877 {
878 	if (pnp)
879 		printf("grf%d at %s", ((struct grf_softc *)auxp)->g_unit,
880 			pnp);
881 	return(UNCONF);
882 }
883 
884 static int
885 rt_getvmode (gp, vm)
886      struct grf_softc *gp;
887      struct grfvideo_mode *vm;
888 {
889   struct MonDef *md;
890 
891   if (vm->mode_num && vm->mode_num > retina_mon_max)
892     return EINVAL;
893 
894   if (! vm->mode_num)
895     vm->mode_num = (current_mon - monitor_defs) + 1;
896 
897   md = monitor_defs + (vm->mode_num - 1);
898   strncpy (vm->mode_descr, monitor_descr + (vm->mode_num - 1),
899 	   sizeof (vm->mode_descr));
900   vm->pixel_clock  = md->FQ;
901   vm->disp_width   = md->MW;
902   vm->disp_height  = md->MH;
903   vm->depth        = md->DEP;
904   vm->hblank_start = md->HBS;
905   vm->hblank_stop  = md->HBE;
906   vm->hsync_start  = md->HSS;
907   vm->hsync_stop   = md->HSE;
908   vm->htotal       = md->HT;
909   vm->vblank_start = md->VBS;
910   vm->vblank_stop  = md->VBE;
911   vm->vsync_start  = md->VSS;
912   vm->vsync_stop   = md->VSE;
913   vm->vtotal       = md->VT;
914 
915   return 0;
916 }
917 
918 
919 static int
920 rt_setvmode (gp, mode, txtonly)
921      struct grf_softc *gp;
922      unsigned mode;
923      int txtonly;
924 {
925   struct MonDef *md;
926   int error;
927 
928   if (!mode || mode > retina_mon_max)
929     return EINVAL;
930 
931   if (txtonly && monitor_defs[mode-1].DEP == 8)
932     return EINVAL;
933 
934   current_mon = monitor_defs + (mode - 1);
935 
936   error = rt_load_mon (gp, current_mon) ? 0 : EINVAL;
937 
938   return error;
939 }
940 
941 
942 /*
943  * Change the mode of the display.
944  * Return a UNIX error number or 0 for success.
945  */
946 int
947 rt_mode(gp, cmd, arg, a2, a3)
948 	struct grf_softc *gp;
949 	int cmd;
950 	void *arg;
951 	int a2, a3;
952 {
953   /* implement these later... */
954 
955   switch (cmd)
956     {
957     case GM_GRFON:
958       rt_setvmode (gp, retina_default_gfx + 1, 0);
959       return 0;
960 
961     case GM_GRFOFF:
962       rt_setvmode (gp, retina_default_mon + 1, 0);
963       return 0;
964 
965     case GM_GRFCONFIG:
966       return 0;
967 
968     case GM_GRFGETVMODE:
969       return rt_getvmode (gp, (struct grfvideo_mode *) arg);
970 
971     case GM_GRFSETVMODE:
972       return rt_setvmode (gp, *(unsigned *) arg, 1);
973 
974     case GM_GRFGETNUMVM:
975       *(int *)arg = retina_mon_max;
976       return 0;
977 
978 #ifdef BANKEDDEVPAGER
979     case GM_GRFGETBANK:
980       *(int *)arg = rt_getbank (gp, a2, a3);
981       return 0;
982 
983     case GM_GRFGETCURBANK:
984       *(int *)arg = rt_getcurbank (gp);
985       return 0;
986 
987     case GM_GRFSETBANK:
988       return rt_setbank (gp, arg);
989 #endif
990     case GM_GRFIOCTL:
991       return rt_ioctl (gp, (u_long)arg, (void *)a2);
992 
993     default:
994       break;
995     }
996 
997   return EINVAL;
998 }
999 
1000 int
1001 rt_ioctl (gp, cmd, data)
1002 	register struct grf_softc *gp;
1003 	u_long cmd;
1004 	void *data;
1005 {
1006   switch (cmd)
1007     {
1008     case GRFIOCGSPRITEPOS:
1009       return rt_getspritepos (gp, (struct grf_position *) data);
1010 
1011     case GRFIOCSSPRITEPOS:
1012       return rt_setspritepos (gp, (struct grf_position *) data);
1013 
1014     case GRFIOCSSPRITEINF:
1015       return rt_setspriteinfo (gp, (struct grf_spriteinfo *) data);
1016 
1017     case GRFIOCGSPRITEINF:
1018       return rt_getspriteinfo (gp, (struct grf_spriteinfo *) data);
1019 
1020     case GRFIOCGSPRITEMAX:
1021       return rt_getspritemax (gp, (struct grf_position *) data);
1022 
1023     case GRFIOCGETCMAP:
1024       return rt_getcmap (gp, (struct grf_colormap *) data);
1025 
1026     case GRFIOCPUTCMAP:
1027       return rt_putcmap (gp, (struct grf_colormap *) data);
1028 
1029     case GRFIOCBITBLT:
1030       return rt_bitblt (gp, (struct grf_bitblt *) data);
1031     }
1032 
1033   return EINVAL;
1034 }
1035 
1036 #ifdef BANKEDDEVPAGER
1037 
1038 /* Retina banks can overlap. Don't use this information (yet?), and
1039    only switch 64k sized banks. */
1040 
1041 int
1042 rt_getbank (gp, offs, prot)
1043      struct grf_softc *gp;
1044      off_t offs;
1045      int prot;
1046 {
1047   /* XXX */
1048   if (offs <  0 || offs >= 4*1024*1024)
1049     return -1;
1050   else
1051     return offs >> 16;
1052 }
1053 
1054 int
1055 rt_getcurbank (gp)
1056      struct grf_softc *gp;
1057 {
1058   struct grfinfo *gi = &gp->g_display;
1059   volatile unsigned char *ba;
1060   int bank;
1061 
1062   ba = gp->g_regkva;
1063   bank = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO) | (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI) << 8);
1064 
1065   /* bank register is multiple of 64 byte, make this multiple of 64k */
1066   bank >>= 10;
1067   return bank;
1068 }
1069 
1070 int
1071 rt_setbank (gp, bank)
1072      struct grf_softc *gp;
1073      int bank;
1074 {
1075   volatile unsigned char *ba;
1076 
1077   ba = gp->g_regkva;
1078   /* bank register is multiple of 64 byte, make this multiple of 64k */
1079   bank <<= 10;
1080   WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, (unsigned char) bank);
1081   bank >>= 8;
1082   WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, (unsigned char) bank);
1083 
1084   return 0;
1085 }
1086 
1087 #endif
1088 
1089 int
1090 rt_getcmap (gfp, cmap)
1091      struct grf_softc *gfp;
1092      struct grf_colormap *cmap;
1093 {
1094   volatile unsigned char *ba;
1095   u_char red[256], green[256], blue[256], *rp, *gp, *bp;
1096   short x;
1097   int error;
1098 
1099   if (cmap->count == 0 || cmap->index >= 256)
1100     return 0;
1101 
1102   if (cmap->index + cmap->count > 256)
1103     cmap->count = 256 - cmap->index;
1104 
1105   ba = gfp->g_regkva;
1106   /* first read colors out of the chip, then copyout to userspace */
1107   vgaw (ba, VDAC_REG_SELECT, cmap->index);
1108   x = cmap->count - 1;
1109   rp = red + cmap->index;
1110   gp = green + cmap->index;
1111   bp = blue + cmap->index;
1112   do
1113     {
1114       *rp++ = vgar (ba, VDAC_REG_DATA);
1115       *gp++ = vgar (ba, VDAC_REG_DATA);
1116       *bp++ = vgar (ba, VDAC_REG_DATA);
1117     }
1118   while (x--);
1119 
1120   if (!(error = copyout (red + cmap->index, cmap->red, cmap->count))
1121       && !(error = copyout (green + cmap->index, cmap->green, cmap->count))
1122       && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count)))
1123     return 0;
1124 
1125   return error;
1126 }
1127 
1128 int
1129 rt_putcmap (gfp, cmap)
1130      struct grf_softc *gfp;
1131      struct grf_colormap *cmap;
1132 {
1133   volatile unsigned char *ba;
1134   u_char red[256], green[256], blue[256], *rp, *gp, *bp;
1135   short x;
1136   int error;
1137 
1138   if (cmap->count == 0 || cmap->index >= 256)
1139     return 0;
1140 
1141   if (cmap->index + cmap->count > 256)
1142     cmap->count = 256 - cmap->index;
1143 
1144   /* first copy the colors into kernelspace */
1145   if (!(error = copyin (cmap->red, red + cmap->index, cmap->count))
1146       && !(error = copyin (cmap->green, green + cmap->index, cmap->count))
1147       && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count)))
1148     {
1149       ba = gfp->g_regkva;
1150       vgaw (ba, VDAC_REG_SELECT, cmap->index);
1151       x = cmap->count - 1;
1152       rp = red + cmap->index;
1153       gp = green + cmap->index;
1154       bp = blue + cmap->index;
1155       do
1156 	{
1157 	  vgaw (ba, VDAC_REG_DATA, *rp++);
1158 	  vgaw (ba, VDAC_REG_DATA, *gp++);
1159 	  vgaw (ba, VDAC_REG_DATA, *bp++);
1160 	}
1161       while (x--);
1162       return 0;
1163     }
1164   else
1165     return error;
1166 }
1167 
1168 int
1169 rt_getspritepos (gp, pos)
1170      struct grf_softc *gp;
1171      struct grf_position *pos;
1172 {
1173   volatile unsigned char *ba;
1174 
1175   ba = gp->g_regkva;
1176   pos->x = vgar (ba, SEQ_ID_CURSOR_X_LOC_LO) | (vgar (ba, SEQ_ID_CURSOR_X_LOC_HI) << 8);
1177   pos->y = vgar (ba, SEQ_ID_CURSOR_Y_LOC_LO) | (vgar (ba, SEQ_ID_CURSOR_Y_LOC_HI) << 8);
1178   return 0;
1179 }
1180 
1181 int
1182 rt_setspritepos (gp, pos)
1183      struct grf_softc *gp;
1184      struct grf_position *pos;
1185 {
1186   volatile unsigned char *ba;
1187 
1188   ba = gp->g_regkva;
1189   vgaw (ba, SEQ_ID_CURSOR_X_LOC_LO, pos->x & 0xff);
1190   vgaw (ba, SEQ_ID_CURSOR_X_LOC_HI, (pos->x >> 8) & 0x07);
1191   vgaw (ba, SEQ_ID_CURSOR_Y_LOC_LO, pos->y & 0xff);
1192   vgaw (ba, SEQ_ID_CURSOR_Y_LOC_HI, (pos->y >> 8) & 0x07);
1193   return 0;
1194 }
1195 
1196 /* assume an at least 2M retina (XXX), sprite is last in memory.
1197    According to the bogus docs, the cursor can be at most 128 lines
1198    in height, and the x-hostspot can be placed at most at pos 31,
1199    this gives width of a long */
1200 #define SPRITE_ADDR (2*1024*1024 - 128*4)
1201 
1202 int
1203 rt_getspriteinfo (gp, info)
1204      struct grf_softc *gp;
1205      struct grf_spriteinfo *info;
1206 {
1207   volatile unsigned char *ba, *fb;
1208 
1209   ba = gp->g_regkva;
1210   fb = gp->g_fbkva;
1211   if (info->set & GRFSPRSET_ENABLE)
1212     info->enable = vgar (ba, SEQ_ID_CURSOR_CONTROL) & 0x01;
1213   if (info->set & GRFSPRSET_POS)
1214     rt_getspritepos (gp, &info->pos);
1215   if (info->set & GRFSPRSET_HOT)
1216     {
1217       info->hot.x = vgar (ba, SEQ_ID_CURSOR_X_INDEX) & 0x1f;
1218       info->hot.y = vgar (ba, SEQ_ID_CURSOR_Y_INDEX) & 0x7f;
1219     }
1220   if (info->set & GRFSPRSET_CMAP)
1221     {
1222       struct grf_colormap cmap;
1223       int index;
1224       cmap.index = 0;
1225       cmap.count = 256;
1226       rt_getcmap (gp, &cmap);
1227       index = vgar (ba, SEQ_ID_CURSOR_COLOR0);
1228       info->cmap.red[0] = cmap.red[index];
1229       info->cmap.green[0] = cmap.green[index];
1230       info->cmap.blue[0] = cmap.blue[index];
1231       index = vgar (ba, SEQ_ID_CURSOR_COLOR1);
1232       info->cmap.red[1] = cmap.red[index];
1233       info->cmap.green[1] = cmap.green[index];
1234       info->cmap.blue[1] = cmap.blue[index];
1235     }
1236   if (info->set & GRFSPRSET_SHAPE)
1237     {
1238       int saved_bank_lo = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO);
1239       int saved_bank_hi = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI);
1240       int last_bank = SPRITE_ADDR >> 6;
1241       int last_bank_lo = last_bank & 0xff;
1242       int last_bank_hi = last_bank >> 8;
1243       u_char mask;
1244       WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, last_bank_lo);
1245       WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, last_bank_hi);
1246       copyout (fb, info->image, 128*4);
1247       mask = RSeq (ba, SEQ_ID_CURSOR_PIXELMASK);
1248       WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, saved_bank_lo);
1249       WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, saved_bank_hi);
1250       copyout (&mask, info->mask, 1);
1251       info->size.x = 32; /* ??? */
1252       info->size.y = (RSeq (ba, SEQ_ID_CURSOR_CONTROL) & 6) << 4;
1253     }
1254 
1255 }
1256 
1257 int
1258 rt_setspriteinfo (gp, info)
1259      struct grf_softc *gp;
1260      struct grf_spriteinfo *info;
1261 {
1262   volatile unsigned char *ba, *fb;
1263   u_char control;
1264 
1265   ba = gp->g_regkva;
1266   fb = gp->g_fbkva;
1267   control = vgar (ba, SEQ_ID_CURSOR_CONTROL);
1268   if (info->set & GRFSPRSET_ENABLE)
1269     {
1270       if (info->enable)
1271 	control |= 1;
1272       else
1273 	control &= ~1;
1274       vgaw (ba, SEQ_ID_CURSOR_CONTROL, control);
1275     }
1276   if (info->set & GRFSPRSET_POS)
1277     rt_setspritepos (gp, &info->pos);
1278   if (info->set & GRFSPRSET_HOT)
1279     {
1280       vgaw (ba, SEQ_ID_CURSOR_X_INDEX, info->hot.x & 0x1f);
1281       vgaw (ba, SEQ_ID_CURSOR_Y_INDEX, info->hot.y & 0x7f);
1282     }
1283   if (info->set & GRFSPRSET_CMAP)
1284     {
1285       /* hey cheat a bit here.. XXX */
1286       vgaw (ba, SEQ_ID_CURSOR_COLOR0, 0);
1287       vgaw (ba, SEQ_ID_CURSOR_COLOR1, 1);
1288     }
1289   if (info->set & GRFSPRSET_SHAPE)
1290     {
1291       int saved_bank_lo = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO);
1292       int saved_bank_hi = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI);
1293       int last_bank = SPRITE_ADDR >> 6;
1294       int last_bank_lo = last_bank & 0xff;
1295       int last_bank_hi = last_bank >> 8;
1296       u_char mask;
1297       WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, last_bank_lo);
1298       WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, last_bank_hi);
1299       copyin (info->image, fb, 128*4);
1300       WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, saved_bank_lo);
1301       WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, saved_bank_hi);
1302       copyin (info->mask, &mask, 1);
1303       WSeq (ba, SEQ_ID_CURSOR_PIXELMASK, mask);
1304       /* info->size.x = 32; *//* ??? */
1305 
1306       info->size.y = (RSeq (ba, SEQ_ID_CURSOR_CONTROL) & 6) << 4;
1307       control = (control & ~6) | ((info->size.y >> 4) & 6);
1308       vgaw (ba, SEQ_ID_CURSOR_CONTROL, control);
1309 
1310       /* sick intel bull-addressing.. */
1311       WSeq (ba, SEQ_ID_CURSOR_STORE_LO, SPRITE_ADDR & 0x0f);
1312       WSeq (ba, SEQ_ID_CURSOR_STORE_HI, 0);
1313       WSeq (ba, SEQ_ID_CURSOR_ST_OFF_LO, (SPRITE_ADDR >> 4) & 0xff);
1314       WSeq (ba, SEQ_ID_CURSOR_ST_OFF_HI, ((SPRITE_ADDR >> 4) >> 8) & 0xff);
1315     }
1316 
1317   return 0;
1318 }
1319 
1320 int
1321 rt_getspritemax (gp, pos)
1322      struct grf_softc *gp;
1323      struct grf_position *pos;
1324 {
1325   pos->x = 32;
1326   pos->y = 128;
1327 
1328   return 0;
1329 }
1330 
1331 
1332 /*
1333  * !!! THIS AREA UNDER CONSTRUCTION !!!
1334  */
1335 
1336 int
1337 rt_bitblt (gp, bb)
1338      struct grf_softc *gp;
1339      struct grf_bitblt *bb;
1340 {
1341   return EINVAL;
1342 
1343 
1344 #if 0
1345   volatile unsigned char *ba, *fb;
1346   u_char control;
1347   u_char saved_bank_lo;
1348   u_char saved_bank_hi;
1349   u_char src_bank_lo, src_bank_hi;
1350   u_char dst_bank_lo, dst_bank_hi;
1351   u_long src_offset, dst_offset;
1352   u_short src_bank, dst_bank;
1353   u_char *srcp, *dstp;
1354   short x, y;
1355   u_long tot;
1356 
1357   ba = gp->g_regkva;
1358   fb = gp->g_fbkva;
1359 
1360   saved_bank_lo = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO);
1361   saved_bank_hi = RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI);
1362 
1363   /* for now, only GRFBBcopy is supported, and only for depth 8. No
1364      clipping is performed, either... */
1365 
1366   if (bb->op != GRFBBcopy && gp->g_display.gd_planes != 8)
1367     return EINVAL;
1368 
1369   src_offset = op->src_x + op->src_y * gp->g_display.gd_fbwidth;
1370   dst_offset = op->dst_x + op->dst_y * gp->g_display.gd_fbwidth;
1371   tot = op->w * op->h;
1372 
1373   /* set write mode 1, "[...] data in the read latches is written
1374      to memory during CPU memory write cycles. [...]" */
1375   WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1);
1376   /* write to primary, read from secondary */
1377   WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0 );
1378 
1379   if (src_offset < dst_offset)
1380     {
1381       /* start at end */
1382       src_offset += tot;
1383       dst_offset += tot;
1384     }
1385 
1386   src_bank_lo = (src_offset >> 6) & 0xff;
1387   src_bank_hi = (src_offset >> 14) & 0xff;
1388   dst_bank_lo = (dst_offset >> 6) & 0xff;
1389   dst_bank_hi = (dst_offset >> 14) & 0xff;
1390 
1391   while (tot)
1392     {
1393       WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, src_bank_lo);
1394       WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, src_bank_hi);
1395       WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, dst_bank_lo);
1396       WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, dst_bank_hi);
1397 
1398       if (src_offset < dst_offset)
1399 	{
1400 
1401 
1402 	}
1403       else
1404 	{
1405 
1406 	}
1407     }
1408 
1409 
1410 #endif
1411 }
1412 
1413 
1414 #endif	/* NGRF */
1415