xref: /netbsd-src/sys/arch/amiga/dev/grf_rt.c (revision 0b9f50897e9a9c6709320fafb4c3787fddcc0a45)
1 #include "grf.h"
2 #if NGRF > 0
3 
4 /* Graphics routines for the Retina board,
5    using the NCR 77C22E+ VGA controller. */
6 
7 #include "sys/param.h"
8 #include "sys/errno.h"
9 #include "grfioctl.h"
10 #include "grfvar.h"
11 #include "grf_rtreg.h"
12 #include "../include/cpu.h"
13 #include "device.h"
14 
15 extern caddr_t ZORRO2ADDR;
16 
17 /* NOTE: this driver for the MacroSystem Retina board was only possible,
18          because MacroSystem provided information about the pecularities
19          of the board. THANKS! Competition in Europe among gfx board
20          manufacturers is rather tough, so Lutz Vieweg, who wrote the
21          initial driver, has made an agreement with MS not to document
22          the driver source (see also his Copyright disclaimer below).
23          -> ALL comments after
24 	 -> "/* -------------- START OF CODE -------------- * /"
25 	 -> have been added by myself (mw) from studying the publically
26 	 -> available "NCR 77C22E+" Data Manual
27 
28 	 Lutz' original driver source (without any of my comments) is
29 	 available on request. */
30 
31 
32 /* This code offers low-level routines to access the Retina graphics-board
33    manufactured by MS MacroSystem GmbH from within NetBSD for the Amiga.
34    No warranties for any kind of function at all - this code may crash
35    your hardware and scratch your harddisk.
36    Use at your own risk.
37    Freely distributable.
38 
39    Written by Lutz Vieweg 07/93
40 
41    Thanks to MacroSystem for providing me with the neccessary information
42    to create theese routines. The sparse documentation of this code
43    results from the agreements between MS and me.
44 */
45 
46 extern unsigned char kernel_font_width, kernel_font_height;
47 extern unsigned char kernel_font_lo, kernel_font_hi;
48 extern unsigned char kernel_font[];
49 
50 
51 #define MDF_DBL 1
52 #define MDF_LACE 2
53 #define MDF_CLKDIV2 4
54 
55 
56 /* standard-palette definition */
57 
58 unsigned char NCRStdPalette[16*3] = {
59 /*   R   G   B  */
60 	  0,  0,  0,
61 	192,192,192,
62 	128,  0,  0,
63 	  0,128,  0,
64 	  0,  0,128,
65 	128,128,  0,
66 	  0,128,128,
67 	128,  0,128,
68 	 64, 64, 64, /* the higher 8 colors have more intensity for  */
69 	255,255,255, /* compatibility with standard attributes       */
70 	255,  0,  0,
71 	  0,255,  0,
72 	  0,  0,255,
73 	255,255,  0,
74 	  0,255,255,
75 	255,  0,255
76 };
77 
78 
79 /* The following structures are examples for monitor-definitions. To make one
80    of your own, first use "DefineMonitor" and create the 8-bit monitor-mode of
81    your dreams. Then save it, and make a structure from the values provided in
82    the file DefineMonitor stored - the labels in the comment above the
83    structure definition show where to put what value.
84 
85    Then you'll need to adapt your monitor-definition to the font you want to
86    use. Be FX the width of the font, then the following modifications have to
87    be applied to your values:
88 
89    HBS = (HBS * 4) / FX
90    HSS = (HSS * 4) / FX
91    HSE = (HSE * 4) / FX
92    HBE = (HBE * 4) / FX
93    HT  = (HT  * 4) / FX
94 
95    Make sure your maximum width (MW) and height (MH) are even multiples of
96    the fonts' width and height.
97 */
98 
99 #if 0
100 /* horizontal 31.5 kHz */
101 
102 /*                                      FQ     FLG    MW   MH   HBS HSS HSE HBE  HT  VBS  VSS  VSE  VBE   VT  */
103    struct MonDef MON_640_512_60  = { 50000000,  28,  640, 512,   81, 86, 93, 98, 95, 513, 513, 521, 535, 535,
104    /* Depth,           PAL, TX,  TY,    XY,FontX, FontY,    FontData,  FLo,  Fhi */
105           4, NCRStdPalette, 80,  64,  5120,    8,     8, kernel_font,   32,  255};
106 
107 /* horizontal 38kHz */
108 
109    struct MonDef MON_768_600_60  = { 75000000,  28,  768, 600,   97, 99,107,120,117, 601, 615, 625, 638, 638,
110           4, NCRStdPalette, 96,  75,  7200,    8,     8, kernel_font,   32,  255};
111 
112 /* horizontal 64kHz */
113 
114    struct MonDef MON_768_600_80  = { 50000000, 24,  768, 600,   97,104,112,122,119, 601, 606, 616, 628, 628,
115           4, NCRStdPalette, 96,  75,  7200,    8,     8, kernel_font,   32,  255};
116 
117    struct MonDef MON_1024_768_80 = { 90000000, 24, 1024, 768,  129,130,141,172,169, 769, 770, 783, 804, 804,
118           4, NCRStdPalette,128,  96, 12288,    8,     8, kernel_font,   32,  255};
119 
120    struct MonDef MON_1024_1024_59= { 90000000, 24, 1024,1024,  129,130,141,173,170,1025,1059,1076,1087,1087,
121           4, NCRStdPalette,128, 128, 16384,    8,     8, kernel_font,   32,  255};
122 
123 /* WARNING: THE FOLLOWING MONITOR MODES EXCEED THE 90-MHz LIMIT THE PROCESSOR
124             HAS BEEN SPECIFIED FOR. USE AT YOUR OWN RISK (AND THINK ABOUT
125             MOUNTING SOME COOLING DEVICE AT THE PROCESSOR AND RAMDAC)!     */
126 
127    struct MonDef MON_1280_1024_60= {110000000,  24, 1280,1024,  161,162,176,211,208,1025,1026,1043,1073,1073,
128           4, NCRStdPalette,160, 128, 20480,    8,     8, kernel_font,   32,  255};
129 
130 /* horizontal 75kHz */
131 
132    struct MonDef MON_1280_1024_69= {120000000,  24, 1280,1024,  161,162,175,200,197,1025,1026,1043,1073,1073,
133           4, NCRStdPalette,160, 128, 20480,    8,     8, kernel_font,   32,  255};
134 
135 #else
136 
137 struct MonDef monitor_defs[] = {
138 /* horizontal 31.5 kHz */
139 
140    { 50000000,  28,  640, 512,   81, 86, 93, 98, 95, 513, 513, 521, 535, 535,
141           4, NCRStdPalette, 80,  64,  5120,    8,     8, kernel_font,   32,  255},
142 
143 /* horizontal 38kHz */
144 
145    { 75000000,  28,  768, 600,   97, 99,107,120,117, 601, 615, 625, 638, 638,
146           4, NCRStdPalette, 96,  75,  7200,    8,     8, kernel_font,   32,  255},
147 
148 /* horizontal 64kHz */
149 
150    { 50000000, 24,  768, 600,   97,104,112,122,119, 601, 606, 616, 628, 628,
151           4, NCRStdPalette, 96,  75,  7200,    8,     8, kernel_font,   32,  255},
152 
153    { 90000000, 24, 1024, 768,  129,130,141,172,169, 769, 770, 783, 804, 804,
154           4, NCRStdPalette,128,  96, 12288,    8,     8, kernel_font,   32,  255},
155 
156    { 90000000, 24, 1024,1024,  129,130,141,173,170,1025,1059,1076,1087,1087,
157           4, NCRStdPalette,128, 128, 16384,    8,     8, kernel_font,   32,  255},
158 
159 /* WARNING: THE FOLLOWING MONITOR MODES EXCEED THE 90-MHz LIMIT THE PROCESSOR
160             HAS BEEN SPECIFIED FOR. USE AT YOUR OWN RISK (AND THINK ABOUT
161             MOUNTING SOME COOLING DEVICE AT THE PROCESSOR AND RAMDAC)!     */
162 
163    {110000000,  24, 1280,1024,  161,162,176,211,208,1025,1026,1043,1073,1073,
164           4, NCRStdPalette,160, 128, 20480,    8,     8, kernel_font,   32,  255},
165 
166 /* horizontal 75kHz */
167 
168    {120000000,  24, 1280,1024,  161,162,175,200,197,1025,1026,1043,1073,1073,
169           4, NCRStdPalette,160, 128, 20480,    8,     8, kernel_font,   32,  255},
170 
171 };
172 
173 static const char *monitor_descr[] = {
174   "80x64 (640x512) 31.5kHz",
175   "96x75 (768x600) 38kHz",
176   "96x75 (768x600) 64kHz",
177   "128x96 (1024x768) 64kHz",
178   "128x128 (1024x1024) 64kHz",
179   "160x128 (1280x1024) 64kHz ***EXCEEDS CHIP LIMIT!!!***",
180   "160x128 (1280x1024) 75kHz ***EXCEEDS CHIP LIMIT!!!***",
181 };
182 
183 int retina_mon_max = sizeof (monitor_defs)/sizeof (monitor_defs[0]);
184 
185 /* patchable */
186 int retina_default_mon = 2;
187 
188 #endif
189 
190 
191 static struct MonDef *current_mon;
192 
193 /* -------------- START OF CODE -------------- */
194 
195 
196 static const long FQTab[16] =
197 { 25175000,  28322000,  36000000,  65000000,
198   44900000,  50000000,  80000000,  75000000,
199   56644000,  63000000,  72000000, 130000000,
200   90000000, 100000000, 110000000, 120000000 };
201 
202 
203 /*--------------------------------------------------*/
204 /*--------------------------------------------------*/
205 
206 #if 0
207 static struct MonDef *default_monitor = &DEFAULT_MONDEF;
208 #endif
209 
210 
211 static int rt_load_mon (struct grf_softc *gp, struct MonDef *md)
212 {
213 	struct grfinfo *gi = &gp->g_display;
214 	volatile unsigned char *ba;
215 	volatile unsigned char *fb;
216 	short FW, clksel, HDE, VDE;
217 
218 	for (clksel = 15; clksel; clksel--) {
219 		if (FQTab[clksel] == md->FQ) break;
220 	}
221 	if (clksel < 0) return 0;
222 
223 	ba = gp->g_regkva;;
224 	fb = gp->g_fbkva;
225 
226 	switch (md->FX) {
227 	case 4:
228 		FW = 0;
229 		break;
230 	case 7:
231 		FW = 1;
232 		break;
233 	case 8:
234 		FW = 2;
235 		break;
236 	case 9:
237 		FW = 3;
238 		break;
239 	case 10:
240 		FW = 4;
241 		break;
242 	case 11:
243 		FW = 5;
244 		break;
245 	case 12:
246 		FW = 6;
247 		break;
248 	case 13:
249 		FW = 7;
250 		break;
251 	case 14:
252 		FW = 8;
253 		break;
254 	case 15:
255 		FW = 9;
256 		break;
257 	case 16:
258 		FW = 11;
259 		break;
260 	default:
261 		return 0;
262 		break;
263 	};
264 
265 	HDE = (md->MW+md->FX-1)/md->FX;
266 	VDE = md->MH-1;
267 
268 	/* hmm... */
269 	fb[0x8000] = 0;
270 
271 	/* program the clock oscillator */
272 	vgaw (ba, GREG_MISC_OUTPUT_W, 0xe3 | ((clksel & 3) * 0x04));
273 	vgaw (ba, GREG_FEATURE_CONTROL_W, 0x00);
274 
275 	/* XXXX according to the NCR specs, this register should be set to 1
276 	   XXXX before doing the MISC_OUTPUT setting and CLOCKING_MODE
277 	   XXXX setting. */
278 	WSeq (ba, SEQ_ID_RESET, 		0x03);
279 
280 	WSeq (ba, SEQ_ID_CLOCKING_MODE, 	0x01 | ((md->FLG & MDF_CLKDIV2)/ MDF_CLKDIV2 * 8));
281 	WSeq (ba, SEQ_ID_MAP_MASK, 		0x0f);
282 	WSeq (ba, SEQ_ID_CHAR_MAP_SELECT, 	0x00);
283 		/* odd/even write select + extended memory */
284 	WSeq (ba, SEQ_ID_MEMORY_MODE, 	0x06);
285 	/* XXXX I think this order of setting RESET is wrong... */
286 	WSeq (ba, SEQ_ID_RESET, 		0x01);
287 	WSeq (ba, SEQ_ID_RESET, 		0x03);
288 
289 		/* enable extension registers *
290 	WSeq (ba, SEQ_ID_EXTENDED_ENABLE,	0x05);
291 		/* monochrome cursor */
292 	WSeq (ba, SEQ_ID_CURSOR_CONTROL,	0x00);
293 		/* bank0 */
294 	WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI,	0x00);
295 	WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO,	0x00);
296 	WSeq (ba, 0x1a , 0x00);  /* these are reserved, really set them to 0 ??? */
297 	WSeq (ba, 0x1b , 0x00);  /* these are reserved, really set them to 0 ??? */
298 		/* bank0 */
299 	WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI,	0x00);
300 	WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO,	0x00);
301 		/* 1M-chips + ena SEC + ena EMem + rw PrimA0/rw Sec/B0 */
302 	WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA,	0x3 | 0x4 | 0x10 | 0x40);
303 		/* set font width + rest of clocks */
304 	WSeq (ba, SEQ_ID_EXT_CLOCK_MODE,	0x30 | (FW & 0x0f) | ((clksel & 4) / 4 * 0x40) );
305 		/* no ext-chain4 + no host-addr-bit-16 */
306 	WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR,	0x00);
307 		/* no packed/nibble + no 256bit gfx format */
308 	WSeq (ba, SEQ_ID_EXT_PIXEL_CNTL,	0x00);
309 		/* AT-interface */
310 	WSeq (ba, SEQ_ID_BUS_WIDTH_FEEDB,	0x06);
311 		/* see fg/bg color expansion */
312 	WSeq (ba, SEQ_ID_COLOR_EXP_WFG,		0x01);
313 	WSeq (ba, SEQ_ID_COLOR_EXP_WBG,		0x00);
314 	WSeq (ba, SEQ_ID_EXT_RW_CONTROL,	0x00);
315 		/* another clock bit, plus hw stuff */
316 	WSeq (ba, SEQ_ID_MISC_FEATURE_SEL,	0xf4 | (clksel & 8) );
317 		/* don't tristate PCLK and PIX */
318 	WSeq (ba, SEQ_ID_COLOR_KEY_CNTL,	0x40 );
319 		/* reset CRC circuit */
320 	WSeq (ba, SEQ_ID_CRC_CONTROL,		0x00 );
321 		/* set RAS/CAS swap */
322 	WSeq (ba, SEQ_ID_PERF_SELECT,		0x20);
323 
324 	WCrt (ba, CRT_ID_END_VER_RETR,		(md->VSE & 0xf ) | 0x20);
325 	WCrt (ba, CRT_ID_HOR_TOTAL,		md->HT   & 0xff);
326 	WCrt (ba, CRT_ID_HOR_DISP_ENA_END,	(HDE-1)  & 0xff);
327 	WCrt (ba, CRT_ID_START_HOR_BLANK,	md->HBS  & 0xff);
328 	WCrt (ba, CRT_ID_END_HOR_BLANK,		(md->HBE & 0x1f) | 0x80);
329 
330 	WCrt (ba, CRT_ID_START_HOR_RETR,	md->HSS  & 0xff);
331 	WCrt (ba, CRT_ID_END_HOR_RETR,		(md->HSE & 0x1f) | ((md->HBE & 0x20)/ 0x20 * 0x80));
332 	WCrt (ba, CRT_ID_VER_TOTAL,		(md->VT  & 0xff));
333 	WCrt (ba, CRT_ID_OVERFLOW,		(( (md->VSS  & 0x200) / 0x200 * 0x80)
334 						 | ((VDE     & 0x200) / 0x200 * 0x40)
335 						 | ((md->VT  & 0x200) / 0x200 * 0x20)
336 						 | 				0x10
337 						 | ((md->VBS & 0x100) / 0x100 * 8   )
338 						 | ((md->VSS & 0x100) / 0x100 * 4   )
339 						 | ((VDE     & 0x100) / 0x100 * 2   )
340 						 | ((md->VT  & 0x100) / 0x100       )));
341 	WCrt (ba, CRT_ID_PRESET_ROW_SCAN,	0x00);
342 
343 	WCrt (ba, CRT_ID_MAX_SCAN_LINE, 	((  (md->FLG & MDF_DBL)/ MDF_DBL * 0x80)
344 						 | 				   0x40
345 						 | ((md->VBS & 0x200)/0x200	 * 0x20)
346 						 | ((md->FY-1) 			 & 0x1f)));
347 
348 	WCrt (ba, CRT_ID_CURSOR_START,		(md->FY & 0x1f) - 2);
349 	WCrt (ba, CRT_ID_CURSOR_END,		(md->FY & 0x1f) - 1);
350 
351 	WCrt (ba, CRT_ID_START_ADDR_HIGH,	0x00);
352 	WCrt (ba, CRT_ID_START_ADDR_LOW,	0x00);
353 
354 	WCrt (ba, CRT_ID_CURSOR_LOC_HIGH,	0x00);
355 	WCrt (ba, CRT_ID_CURSOR_LOC_LOW,	0x00);
356 
357 	WCrt (ba, CRT_ID_START_VER_RETR,	md->VSS    & 0xff);
358 	WCrt (ba, CRT_ID_END_VER_RETR,		(md->VSE   & 0x0f) | 0x80 | 0x20);
359 	WCrt (ba, CRT_ID_VER_DISP_ENA_END,	VDE        & 0xff);
360 	WCrt (ba, CRT_ID_OFFSET,		(HDE / 2)  & 0xff);
361 	WCrt (ba, CRT_ID_UNDERLINE_LOC,		(md->FY-1) & 0x1f);
362 	WCrt (ba, CRT_ID_START_VER_BLANK,	md->VBS    & 0xff);
363 	WCrt (ba, CRT_ID_END_VER_BLANK,		md->VBE    & 0xff);
364 		/* byte mode + wrap + select row scan counter + cms */
365 	WCrt (ba, CRT_ID_MODE_CONTROL,		0xe3);
366 	WCrt (ba, CRT_ID_LINE_COMPARE,		0xff);
367 
368 		/* enable extended end bits + those bits */
369 	WCrt (ba, CRT_ID_EXT_HOR_TIMING1,	(           				 0x20
370 						 | ((md->FLG & MDF_LACE)  / MDF_LACE   * 0x10)
371 						 | ((md->HT  & 0x100) / 0x100          * 0x01)
372 						 | (((HDE-1) & 0x100) / 0x100 	       * 0x02)
373 						 | ((md->HBS & 0x100) / 0x100 	       * 0x04)
374 						 | ((md->HSS & 0x100) / 0x100 	       * 0x08)));
375 
376 	WCrt (ba, CRT_ID_EXT_START_ADDR,	(((HDE / 2) & 0x100)/0x100 * 16));
377 
378 	WCrt (ba, CRT_ID_EXT_HOR_TIMING2, 	(  ((md->HT  & 0x200)/ 0x200  	       * 0x01)
379 						 | (((HDE-1) & 0x200)/ 0x200 	       * 0x02)
380 						 | ((md->HBS & 0x200)/ 0x200 	       * 0x04)
381 						 | ((md->HSS & 0x200)/ 0x200 	       * 0x08)
382 						 | ((md->HBE & 0xc0) / 0x40  	       * 0x10)
383 						 | ((md->HSE & 0x60) / 0x20  	       * 0x40)));
384 
385 	WCrt (ba, CRT_ID_EXT_VER_TIMING,	(  ((md->VSE & 0x10) / 0x10  	       * 0x80)
386 						 | ((md->VBE & 0x300)/ 0x100 	       * 0x20)
387 						 |				         0x10
388 						 | ((md->VSS & 0x400)/ 0x400 	       * 0x08)
389 						 | ((md->VBS & 0x400)/ 0x400 	       * 0x04)
390 						 | ((VDE     & 0x400)/ 0x400 	       * 0x02)
391 						 | ((md->VT  & 0x400)/ 0x400           * 0x01)));
392 
393 	WGfx (ba, GCT_ID_SET_RESET,		0x00);
394 	WGfx (ba, GCT_ID_ENABLE_SET_RESET,	0x00);
395 	WGfx (ba, GCT_ID_COLOR_COMPARE,		0x00);
396 	WGfx (ba, GCT_ID_DATA_ROTATE,		0x00);
397 	WGfx (ba, GCT_ID_READ_MAP_SELECT,	0x00);
398 	WGfx (ba, GCT_ID_GRAPHICS_MODE,		0x00);
399 	WGfx (ba, GCT_ID_MISC,			0x04);
400 	WGfx (ba, GCT_ID_COLOR_XCARE,		0xff);
401 	WGfx (ba, GCT_ID_BITMASK,		0xff);
402 
403 	/* reset the Attribute Controller flipflop */
404 	vgar (ba, GREG_STATUS1_R);
405 	WAttr (ba, ACT_ID_PALETTE0,		0x00);
406 	WAttr (ba, ACT_ID_PALETTE1,		0x01);
407 	WAttr (ba, ACT_ID_PALETTE2,		0x02);
408 	WAttr (ba, ACT_ID_PALETTE3,		0x03);
409 	WAttr (ba, ACT_ID_PALETTE4,		0x04);
410 	WAttr (ba, ACT_ID_PALETTE5,		0x05);
411 	WAttr (ba, ACT_ID_PALETTE6,		0x06);
412 	WAttr (ba, ACT_ID_PALETTE7,		0x07);
413 	WAttr (ba, ACT_ID_PALETTE8,		0x08);
414 	WAttr (ba, ACT_ID_PALETTE9,		0x09);
415 	WAttr (ba, ACT_ID_PALETTE10,		0x0a);
416 	WAttr (ba, ACT_ID_PALETTE11,		0x0b);
417 	WAttr (ba, ACT_ID_PALETTE12,		0x0c);
418 	WAttr (ba, ACT_ID_PALETTE13,		0x0d);
419 	WAttr (ba, ACT_ID_PALETTE14,		0x0e);
420 	WAttr (ba, ACT_ID_PALETTE15,		0x0f);
421 
422 	vgar (ba, GREG_STATUS1_R);
423 	WAttr (ba, ACT_ID_ATTR_MODE_CNTL,	0x08);
424 
425 	WAttr (ba, ACT_ID_OVERSCAN_COLOR,	0x00);
426 	WAttr (ba, ACT_ID_COLOR_PLANE_ENA,	0x0f);
427 	WAttr (ba, ACT_ID_HOR_PEL_PANNING,	0x00);
428 	WAttr (ba, ACT_ID_COLOR_SELECT,	0x00);
429 
430 	vgar (ba, GREG_STATUS1_R);
431 		/* I have *NO* idea what strobing reg-0x20 might do... */
432 	vgaw (ba, ACT_ADDRESS_W, 0x20);
433 
434 	WCrt (ba, CRT_ID_MAX_SCAN_LINE,		( ((md->FLG & MDF_DBL)/ MDF_DBL * 0x80)
435 						|	                          0x40
436 						| ((md->VBS & 0x200)/0x200	* 0x20)
437 						| ((md->FY-1) 			& 0x1f)));
438 
439 
440 	/* not it's time for guessing... */
441 
442 	vgaw (ba, VDAC_REG_D, 	   0x02);
443 
444 		/* if this does what I think it does, it selects DAC
445 		   register 0, and writes the palette in subsequent
446 		   registers, thus it works similar to the WD33C93
447 		   select/data mechanism */
448 	vgaw (ba, VDAC_REG_SELECT, 0x00);
449 
450 	{
451 
452 		short x = 15;
453 		const unsigned char * col = md->PAL;
454 		do {
455 
456 			vgaw (ba, VDAC_REG_DATA, *col++);
457 			vgaw (ba, VDAC_REG_DATA, *col++);
458 			vgaw (ba, VDAC_REG_DATA, *col++);
459 
460 
461 		} while (x--);
462 
463 	}
464 
465 
466 	/* now load the font into maps 2 (and 3 for fonts wider than 8 pixels) */
467 	{
468 
469 		/* first set the whole font memory to a test-pattern, so we
470 		   can see if something that shouldn't be drawn IS drawn.. */
471 		{
472 			unsigned char * c = fb;
473 			long x;
474 			Map(2);
475 
476 			for (x = 0; x < 65536; x++) {
477 				*c++ = (x & 1)? 0xaa : 0x55;
478 			}
479 		}
480 
481 		{
482 			unsigned char * c = fb;
483 			long x;
484 			Map(3);
485 
486 			for (x = 0; x < 65536; x++) {
487 				*c++ = (x & 1)? 0xaa : 0x55;
488 			}
489 		}
490 
491 		{
492 		  /* ok, now position at first defined character, and
493 		     copy over the images */
494 		  unsigned char * c = fb + md->FLo * 32;
495 		  const unsigned char * f = md->FData;
496 		  unsigned short z;
497 
498 		  Map(2);
499 		  for (z = md->FLo; z <= md->FHi; z++) {
500 
501 			short y = md->FY-1;
502 			if (md->FX > 8){
503 				do {
504 					*c++ = *f;
505 					f += 2;
506 				} while (y--);
507 			}
508 			else {
509 				do {
510 					*c++ = *f++;
511 				} while (y--);
512 			}
513 
514 			c += 32-md->FY;
515 
516 		  }
517 
518 		  if (md->FX > 8) {
519 			unsigned short z;
520 
521 			Map(3);
522 			c = fb + md->FLo*32;
523 			f = md->FData+1;
524 			for (z = md->FLo; z <= md->FHi; z++) {
525 
526 				short y = md->FY-1;
527 				do {
528 					*c++ = *f;
529 					f += 2;
530 				} while (y--);
531 
532 				c += 32-md->FY;
533 
534 			}
535 		  }
536 		}
537 
538 	}
539 
540 		/* select map 0 */
541 	WGfx (ba, GCT_ID_READ_MAP_SELECT,	0);
542 		/* allow writes into maps 0 and 1 */
543 	WSeq (ba, SEQ_ID_MAP_MASK,		3);
544 		/* select extended chain4 addressing:
545 		    !A0/!A1	map 0	character to be displayed
546 		    !A1/ A1	map 1	attribute of that character
547 		     A0/!A1	map 2	not used (masked out, ignored)
548 		     A0/ A1 	map 3	not used (masked out, ignored) */
549 	WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR,	RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02);
550 
551 	{
552 		/* position in display memory */
553 		unsigned short * c = (unsigned short *) fb;
554 
555 		/* fill with blank, white on black */
556 		const unsigned short fill_val = 0x2010;
557 		short x = md->XY;
558 		do {
559 			*c = fill_val;
560 			c += 2;
561 		} while (x--);
562 
563 		/* I won't comment this :-)) */
564 		c = (unsigned short *) fb;
565 		c += (md->TX-6)*2;
566 		{
567 		  unsigned short init_msg[6] = {0x520a, 0x450b, 0x540c, 0x490d, 0x4e0e, 0x410f};
568 		  unsigned short * f = init_msg;
569 		  x = 5;
570 		  do {
571 			*c = *f++;
572 			c += 2;
573 	 	  } while (x--);
574 	 	}
575 
576 
577 	}
578 
579 
580 	gi->gd_regaddr  = (caddr_t) md; /* XXX */
581 	gi->gd_regsize  = 0;
582 
583 	gi->gd_fbaddr   = (long)fb - (long)ZORRO2ADDR + (long)ZORRO2BASE;
584 	gi->gd_fbsize   = 64*1024;	/* larger, but that's whats mappable */
585 
586 	gi->gd_colors   = 1 << md->DEP;
587 	gi->gd_planes   = md->DEP;
588 
589 	gi->gd_fbwidth  = md->MW;
590 	gi->gd_fbheight = md->MH;
591 	gi->gd_fbx	= 0;
592 	gi->gd_fby	= 0;
593 	gi->gd_dwidth   = md->TX * md->FX;
594 	gi->gd_dheight  = md->TY * md->FY;
595 	gi->gd_dx	= 0;
596 	gi->gd_dy	= 0;
597 
598 	/* initialized, works, return 1 */
599 	return 1;
600 }
601 
602 int rt_init (struct grf_softc *gp, struct amiga_device *ad, struct amiga_hw *ahw)
603 {
604   /* if already initialized, fail */
605   if (gp->g_regkva)
606     return 0;
607 
608   gp->g_regkva = ahw->hw_kva;
609   gp->g_fbkva  = ahw->hw_kva + 64*1024;
610 
611   /* don't let them patch it out of bounds */
612   if ((unsigned)retina_default_mon >= retina_mon_max)
613     retina_default_mon = 0;
614 
615   current_mon = monitor_defs + retina_default_mon;
616 
617   return rt_load_mon (gp, current_mon);
618 }
619 
620 static int
621 rt_getvmode (gp, vm)
622      struct grf_softc *gp;
623      struct grfvideo_mode *vm;
624 {
625   struct MonDef *md;
626 
627   if (vm->mode_num && vm->mode_num > retina_mon_max)
628     return EINVAL;
629 
630   if (! vm->mode_num)
631     vm->mode_num = (current_mon - monitor_defs) + 1;
632 
633   md = monitor_defs + (vm->mode_num - 1);
634   strncpy (vm->mode_descr, monitor_descr + (vm->mode_num - 1),
635 	   sizeof (vm->mode_descr));
636   vm->pixel_clock  = md->FQ;
637   vm->disp_width   = md->MW;
638   vm->disp_height  = md->MH;
639   vm->depth        = md->DEP;
640   vm->hblank_start = md->HBS;
641   vm->hblank_stop  = md->HBE;
642   vm->hsync_start  = md->HSS;
643   vm->hsync_stop   = md->HSE;
644   vm->htotal       = md->HT;
645   vm->vblank_start = md->VBS;
646   vm->vblank_stop  = md->VBE;
647   vm->vsync_start  = md->VSS;
648   vm->vsync_stop   = md->VSE;
649   vm->vtotal       = md->VT;
650 
651   return 0;
652 }
653 
654 
655 static int
656 rt_setvmode (gp, mode)
657      struct grf_softc *gp;
658      unsigned mode;
659 {
660   struct MonDef *md;
661 
662   if (!mode || mode > retina_mon_max)
663     return EINVAL;
664 
665   current_mon = monitor_defs + (mode - 1);
666   return rt_load_mon (gp, current_mon) ? 0 : EINVAL;
667 }
668 
669 
670 /*
671  * Change the mode of the display.
672  * Right now all we can do is grfon/grfoff.
673  * Return a UNIX error number or 0 for success.
674  */
675 rt_mode(gp, cmd, arg)
676 	register struct grf_softc *gp;
677 	int cmd;
678 	void *arg;
679 {
680   /* implement these later... */
681 
682   switch (cmd)
683     {
684     case GM_GRFON:
685       return 0;
686 
687     case GM_GRFOFF:
688       return 0;
689 
690     case GM_GRFCONFIG:
691       return 0;
692 
693     case GM_GRFGETVMODE:
694       return rt_getvmode (gp, (struct grfvideo_mode *) arg);
695 
696     case GM_GRFSETVMODE:
697       return rt_setvmode (gp, *(unsigned *) arg);
698 
699     case GM_GRFGETNUMVM:
700       *(int *)arg = retina_mon_max;
701       return 0;
702 
703     default:
704       break;
705     }
706 
707   return EINVAL;
708 }
709 
710 #endif	/* NGRF */
711