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