Home | History | Annotate | Line # | Download | only in dev
grf_rt.c revision 1.1
      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