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