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