Home | History | Annotate | Line # | Download | only in dev
grf_cv.c revision 1.6
      1 /*	$NetBSD: grf_cv.c,v 1.6 1996/02/24 20:13:01 chopps Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1995 Michael Teske
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *      This product includes software developed by Ezra Story, by Kari
     18  *      Mettinen and by Bernd Ernesti.
     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 "grfcv.h"
     34 #if NGRFCV > 0
     35 
     36 #undef CV64CONSOLE /* DO NOT REMOVE THIS till ite5 is ready */
     37 
     38 /*
     39  * Graphics routines for the CyberVision 64 board, using the S3 Trio64.
     40  *
     41  * Modified for CV64 from
     42  * Kari Mettinen's Cirrus driver by Michael Teske 10/95
     43  * For questions mail me at teske (at) dice2.desy.de
     44  *
     45  * Thanks to Tekelec Airtronic for providing me with a S3 Trio64 documentation.
     46  * Thanks to Bernd 'the fabulous bug-finder' Ernesti for bringing my messy
     47  * source to NetBSD style :)
     48  *
     49  * TODO:
     50  *    Hardware Cursor support
     51  *    Blitter support
     52  *
     53  * BUGS:
     54  *    Xamiag24 and grf_cv can crash when you use fvwm with xterm's, you can
     55  *    avoid this by starting the xterm with '-ah', see the manpage of xterm
     56  *    for more informations about this switch.
     57  *    There is a bug in the Trio64 which produce a small (1 or 2 pixel) white
     58  *    vertical bar on the right side of an 8bit-Screen (only when you use more
     59  *    then 80MHz pixelclock). This has to be fixed in the Xserver.
     60  *
     61  */
     62 
     63 #include <sys/param.h>
     64 #include <sys/errno.h>
     65 #include <sys/ioctl.h>
     66 #include <sys/device.h>
     67 #include <sys/malloc.h>
     68 #include <sys/systm.h>
     69 #include <machine/cpu.h>
     70 #include <dev/cons.h>
     71 #include <amiga/amiga/device.h>
     72 #include <amiga/dev/grfioctl.h>
     73 #include <amiga/dev/grfvar.h>
     74 #include <amiga/dev/grf_cvreg.h>
     75 #include <amiga/dev/zbusvar.h>
     76 
     77 int	grfcvmatch  __P((struct device *, struct cfdata *, void *));
     78 void	grfcvattach __P((struct device *, struct device *, void *));
     79 int	grfcvprint  __P((void *, char *));
     80 
     81 static int cv_has_4mb __P((volatile char *));
     82 static unsigned short compute_clock __P((unsigned long));
     83 void	cv_boardinit __P((struct grf_softc *));
     84 int	cv_getvmode __P((struct grf_softc *, struct grfvideo_mode *));
     85 int	cv_setvmode __P((struct grf_softc *, unsigned int));
     86 int	cv_blank __P((struct grf_softc *, int *));
     87 int	cv_mode __P((register struct grf_softc *, int, void *, int, int));
     88 int	cv_ioctl __P((register struct grf_softc *gp, int cmd, void *data));
     89 int	cv_setmonitor __P((struct grf_softc *, struct grfvideo_mode *));
     90 int	cv_getcmap __P((struct grf_softc *, struct grf_colormap *));
     91 int	cv_putcmap __P((struct grf_softc *, struct grf_colormap *));
     92 int	cv_toggle __P((struct grf_softc *));
     93 int	cv_mondefok __P((struct grfvideo_mode *));
     94 int	cv_load_mon __P((struct grf_softc *, struct grfcvtext_mode *));
     95 void	cv_inittextmode __P((struct grf_softc *));
     96 void	cv_memset __P((unsigned char *, unsigned char, int));
     97 
     98 #ifdef CV64CONSOLE
     99 extern void grfcv_iteinit __P((struct grf_softc *));
    100 #endif
    101 
    102 /* Graphics display definitions.
    103  * These are filled by 'grfconfig' using GRFIOCSETMON.
    104  */
    105 #define monitor_def_max 8
    106 static struct grfvideo_mode monitor_def[8] = {
    107 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}
    108 };
    109 static struct grfvideo_mode *monitor_current = &monitor_def[0];
    110 #define MAXPIXELCLOCK 135000000 /* safety */
    111 
    112 /* generated by gen_cvtab.c */
    113 static int cv_convtab[31] = {
    114 	163,	148,	135,	124,	114,
    115 	106,	98,	91,	85,	79,
    116 	74,	69,	65,	61,	57,
    117 	53,	50,	47,	44,	42,
    118 	39,	37,	35,	33,	31,
    119 	29,	27,	26,	24,	22,
    120 	21,
    121 };
    122 
    123 /* Console display definition.
    124  *   Default hardcoded text mode.  This grf_cv is set up to
    125  *   use one text mode only, and this is it.  You may use
    126  *   grfconfig to change the mode after boot.
    127  */
    128 
    129 /* Console font */
    130 #define S3FONT kernel_font_8x8
    131 #define S3FONTX 8
    132 #define S3FONTY 8
    133 extern unsigned char S3FONT[];
    134 
    135 struct grfcvtext_mode cvconsole_mode = {
    136 	{255, "", 25000000, 640, 400, 4, 640, 656, 672, 720, 760, 406,
    137 	441, 412, 426, 447},
    138 	S3FONTX, S3FONTY, 80, 506/S3FONTY, S3FONT, 32, 255
    139 };
    140 
    141 /* Console colors */
    142 unsigned char cvconscolors[3][3] = {	/* background, foreground, hilite */
    143 	{0,0x40,0x50}, {152,152,152}, {255,255,255}
    144 };
    145 
    146 
    147 /* Board Address of CV64 */
    148 
    149 static volatile caddr_t cv_boardaddr;
    150 static int cv_fbsize;
    151 
    152 int
    153 grfcv_cnprobe()
    154 {
    155 	int rv;
    156 	rv = CN_DEAD;
    157 	return (rv);
    158 }
    159 
    160 /* standard driver stuff */
    161 struct cfdriver grfcvcd = {
    162 	NULL, "grfcv", (cfmatch_t)grfcvmatch, grfcvattach,
    163 	DV_DULL, sizeof(struct grf_softc), NULL, 0
    164 };
    165 static struct cfdata *cfdata;
    166 
    167 
    168 /* Reads from the fb must be done at addr + 0x02000000 */
    169 #define READ_OFFSET 0x02000000
    170 
    171 /*
    172  * Get frambuffer memory size.
    173  * phase5 didn't provide the bit in CR36,
    174  * so we have to do it this way.
    175  * Return 0 for 2MB, 1 for 4MB
    176  */
    177 
    178 static int
    179 cv_has_4mb (volatile char *fb)
    180 {
    181 	volatile unsigned long *testfbw, *testfbr;
    182 
    183 	/* write patterns in memory and test if they can be read */
    184 	testfbw = (volatile unsigned long *) fb;
    185 	*testfbw = 0x87654321;
    186 	testfbr = (volatile unsigned long *)(fb + READ_OFFSET);
    187 	if (*testfbr != 0x87654321)
    188 		return (0);
    189 	/* upper memory region */
    190 	testfbw = (volatile unsigned long *)(fb + 0x00200000);
    191 	testfbr = (volatile unsigned long *)(fb + 0x00200000 + READ_OFFSET);
    192 	*testfbw = 0x87654321;
    193 	if (*testfbr != 0x87654321)
    194 		return (0);
    195 	*testfbw = 0xAAAAAAAA;
    196 	if (*testfbr != 0xAAAAAAAA)
    197 		return (0);
    198 	*testfbw = 0x55555555;
    199 	if (*testfbr != 0x55555555)
    200 		return (0);
    201 	return (1);
    202 }
    203 
    204 int
    205 grfcvmatch(pdp, cfp, auxp)
    206 	struct device *pdp;
    207 	struct cfdata *cfp;
    208 	void *auxp;
    209 {
    210 	struct zbus_args *zap;
    211 
    212 	zap = auxp;
    213 
    214 #ifndef CV64CONSOLE
    215 	if (amiga_realconfig == 0)
    216 		 return (0);
    217 #endif
    218 
    219         /* Lets be Paranoid: Test man and prod id */
    220 	if (zap->manid != 8512 || zap->prodid != 34)
    221 		return (0);
    222 
    223 	cv_boardaddr = zap->va;
    224 
    225 #ifdef CV64CONSOLE
    226 	if (amiga_realconfig == 0) {
    227 		cfdata = cfp;
    228 	}
    229 #endif
    230 
    231 	return (1);
    232 }
    233 
    234 void
    235 grfcvattach(pdp, dp, auxp)
    236 	struct device *pdp, *dp;
    237 	void *auxp;
    238 {
    239 	struct zbus_args *zap;
    240 	struct grf_softc *gp;
    241 
    242 	zap = auxp;
    243 
    244 	printf("\n");
    245 
    246 	gp = (struct grf_softc *)dp;
    247 
    248 	gp->g_regkva = (volatile caddr_t)cv_boardaddr + READ_OFFSET;
    249 	gp->g_fbkva = (volatile caddr_t)cv_boardaddr + 0x01400000;
    250 
    251 	gp->g_unit = GRF_CV64_UNIT;
    252 	gp->g_mode = cv_mode;
    253 	gp->g_conpri = grfcv_cnprobe();
    254 	gp->g_flags = GF_ALIVE;
    255 
    256 	/* wakeup the board */
    257 	cv_boardinit(gp);
    258 
    259 #ifdef CV64CONSOLE
    260 	grfcv_iteinit(gp);
    261 	(void)cv_load_mon(gp, &cvconsole_mode);
    262 #endif
    263 
    264 	/*
    265 	 * attach grf
    266 	 */
    267 	if (amiga_config_found(cfdata, &gp->g_device, gp, grfcvprint))
    268 		printf("grfcv: CyberVision64 with %dMB being used\n", cv_fbsize/0x100000);
    269 }
    270 
    271 int
    272 grfcvprint(auxp, pnp)
    273 	void *auxp;
    274 	char *pnp;
    275 {
    276 	if (pnp)
    277 		printf("ite at %s: ", pnp);
    278 	return (UNCONF);
    279 }
    280 
    281 
    282 /*
    283  * Computes M, N, and R values from
    284  * given input frequency. It uses a table of
    285  * precomputed values, to keep CPU time low.
    286  *
    287  * The return value consist of:
    288  * lower byte:  Bits 4-0: N Divider Value
    289  *	        Bits 5-6: R Value          for e.g. SR10 or SR12
    290  * higher byte: Bits 0-6: M divider value  for e.g. SR11 or SR13
    291  */
    292 
    293 static unsigned short
    294 compute_clock(freq)
    295 	unsigned long freq;
    296 {
    297 
    298 	static unsigned char *mnr, *save;	/* M, N + R vals */
    299 	unsigned long work_freq, r;
    300 	unsigned short erg;
    301 	long diff, d2;
    302 
    303 	/* 0xBEBC20 = 12.5M */
    304 	/* 0x080BEFC0 = 135M */
    305 	if (freq < 0x00BEBC20 || freq > 0x080BEFC0) {
    306 		printf("grfcv: Wrong clock frequency: %dMHz", freq/1000000);
    307 		printf("grfcv: Using default frequency: 25MHz");
    308 		freq = 0x017D7840;
    309 	}
    310 
    311 	mnr = clocks;	/* there the vals are stored */
    312 	d2 = 0x7fffffff;
    313 
    314 	while (*mnr) {	/* mnr vals are 0-terminated */
    315 		work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
    316 
    317 		r = (mnr[1] >> 5) & 0x03;
    318     		if (r != 0)
    319 			work_freq=work_freq >> r;	/* r is the freq divider */
    320 
    321 		work_freq *= 0x3E8;	/* 2nd part of OSC */
    322 
    323 		diff = abs(freq - work_freq);
    324 
    325 		if (d2 >= diff) {
    326 			d2 = diff;
    327 			/* In save are the vals for minimal diff */
    328 			save = mnr;
    329 		}
    330 		mnr += 2;
    331 	}
    332 	erg = *((unsigned short *)save);
    333 
    334 	return (erg);
    335 }
    336 
    337 
    338 void
    339 cv_boardinit(gp)
    340 	struct grf_softc *gp;
    341 {
    342 	volatile caddr_t ba = gp->g_regkva;
    343 	unsigned char test;
    344 	unsigned int clockpar;
    345 	int i;
    346 	struct grfinfo *gi;
    347 
    348 	/* Reset board */
    349 	for (i = 0; i < 6; i++)
    350 		cv_write_port (0xff, ba - READ_OFFSET);	/* Clear all bits */
    351 
    352 	/* Return to operational Mode */
    353 	cv_write_port(0x8004, ba - READ_OFFSET);
    354 
    355 	/* Wakeup Chip */
    356 	vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x10);
    357 	vgaw(ba, SREG_OPTION_SELECT, 0x1);
    358 	vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x8);
    359 
    360 	vgaw(ba, GREG_MISC_OUTPUT_W, 0x23);
    361 
    362 	WCrt(ba, CRT_ID_REGISTER_LOCK_1, 0x48);	/* unlock S3 VGA regs */
    363 	WCrt(ba, CRT_ID_REGISTER_LOCK_2, 0xA5);	/* unlock syscontrol */
    364 
    365 	test = RCrt(ba, CRT_ID_SYSTEM_CONFIG);
    366 	test = test | 0x01;	/* enable enhaced register access */
    367 	test = test & 0xEF;	/* clear bit 4, 0 wait state */
    368 	WCrt(ba, CRT_ID_SYSTEM_CONFIG, test);
    369 
    370 	/*
    371 	 * bit 1=1: enable enhanced mode functions
    372 	 * bit 4=1: enable linear adressing
    373  	 */
    374 	vgaw(ba, ECR_ADV_FUNC_CNTL, 0x11);
    375 
    376 	/* enable cpu acess, color mode, high 64k page */
    377 	vgaw(ba, GREG_MISC_OUTPUT_W, 0x23);
    378 
    379 	/* Cpu base addr */
    380 	WCrt(ba, CRT_ID_EXT_SYS_CNTL_4, 0x0);
    381 
    382 	/* Reset. This does nothing, but everyone does it:) */
    383 	WSeq(ba, SEQ_ID_RESET, 0x3);
    384 
    385 	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x1);	/* 8 Dot Clock */
    386 	WSeq(ba, SEQ_ID_MAP_MASK, 0xF);		/* Enable write planes */
    387 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x0);	/* Character Font */
    388 
    389 	WSeq(ba, SEQ_ID_MEMORY_MODE, 0x2);	/* Complete mem access */
    390 
    391 	WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x6);	/* Unlock extensions */
    392 	test = RSeq(ba, SEQ_ID_BUS_REQ_CNTL);	/* Bus Request */
    393 
    394 	/* enable 4MB fast Page Mode */
    395 	test = test | 1 << 6;
    396 	WSeq(ba, SEQ_ID_BUS_REQ_CNTL, test);
    397 	/* faster LUT write */
    398 	WSeq(ba, SEQ_ID_RAMDAC_CNTL, 0x40);
    399 
    400 	test = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);	/* Clksyn2 read */
    401 
    402 	/* immediately Clkload bit clear */
    403 	test = test & 0xDF;
    404 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, test);
    405 
    406 	clockpar = compute_clock(0x3473BC0);
    407 	test = (clockpar & 0xFF00) >> 8;
    408 
    409 	if (RCrt(ba, CRT_ID_REVISION) == 0x10) {
    410 		WSeq(ba, SEQ_ID_MCLK_HI, test); /* PLL N-Divider Value */
    411 
    412 		test = clockpar & 0xFF;
    413 		WSeq(ba, SEQ_ID_MCLK_LO, test); /* PLL M-Divider Value */
    414 
    415 		test = (clockpar & 0xFF00) >> 8;
    416 		WSeq(ba, SEQ_ID_MORE_MAGIC, test);
    417 	} else {
    418                WSeq(ba, SEQ_ID_MCLK_HI, test); /* PLL N-Divider Value */
    419 
    420                test = clockpar & 0xFF;
    421                WSeq(ba, SEQ_ID_MCLK_LO, test); /* PLL M-Divider Value */
    422 	}
    423 
    424 	/* We now load an 25 MHz, 31 kHz, 640x480 standard VGA Mode. */
    425 	/* DCLK */
    426 	WSeq(ba, SEQ_ID_DCLK_HI, 0x13);
    427 	WSeq(ba, SEQ_ID_DCLK_LO, 0x41);
    428 
    429 	test = RSeq (ba, SEQ_ID_CLKSYN_CNTL_2);
    430 	test = test | 0x22;
    431 
    432 	/* DCLK + MCLK Clock immediate load! */
    433 	WSeq(ba,SEQ_ID_CLKSYN_CNTL_2, test);
    434 
    435 	/* DCLK load */
    436 	test = vgar(ba, 0x3cc);
    437 	test = test | 0x0c;
    438 	vgaw(ba, 0x3c2, test);
    439 
    440 	/* Clear bit 5 again, prevent further loading. */
    441 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, 0x2);
    442 
    443 	WCrt(ba, CRT_ID_HOR_TOTAL, 0x5F);
    444 	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, 0x4F);
    445 	WCrt(ba, CRT_ID_START_HOR_BLANK, 0x50);
    446 	WCrt(ba, CRT_ID_END_HOR_BLANK, 0x82);
    447 	WCrt(ba, CRT_ID_START_HOR_RETR, 0x54);
    448 	WCrt(ba, CRT_ID_END_HOR_RETR, 0x80);
    449 	WCrt(ba, CRT_ID_VER_TOTAL, 0xBF);
    450 
    451 	WCrt(ba, CRT_ID_OVERFLOW, 0x1F);	/* overflow reg */
    452 
    453 	WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x0);	/* no panning */
    454 
    455 	WCrt(ba, CRT_ID_MAX_SCAN_LINE, 0x40);	/* vscan */
    456 
    457 	WCrt(ba, CRT_ID_CURSOR_START, 0x00);
    458 	WCrt(ba, CRT_ID_CURSOR_END, 0x00);
    459 
    460 	/* Display start adress */
    461 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
    462 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
    463 
    464 	/* Cursor location */
    465 	WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
    466 	WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
    467 
    468 	/* Vertical retrace */
    469 	WCrt(ba, CRT_ID_START_VER_RETR, 0x9C);
    470 	WCrt(ba, CRT_ID_END_VER_RETR, 0x0E);
    471 
    472 	WCrt(ba, CRT_ID_VER_DISP_ENA_END, 0x8F);
    473 	WCrt(ba, CRT_ID_SCREEN_OFFSET, 0x50);
    474 
    475 	WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x00);
    476 
    477 	WCrt(ba, CRT_ID_START_VER_BLANK, 0x96);
    478 	WCrt(ba, CRT_ID_END_VER_BLANK, 0xB9);
    479 
    480 	WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3);
    481 
    482 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xFF);
    483 
    484 	WCrt(ba, CRT_ID_BACKWAD_COMP_3, 0x10);	/* FIFO enabled */
    485 
    486 	/* Refresh count 1, High speed text font, enhanced color mode */
    487 	WCrt(ba, CRT_ID_MISC_1, 0x35);
    488 
    489 	/* start fifo position */
    490 	WCrt(ba, CRT_ID_DISPLAY_FIFO, 0x5a);
    491 
    492 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, 0x70);
    493 
    494 	/* address window position */
    495 	WCrt(ba, CRT_ID_LAW_POS_LO, 0x40);
    496 
    497 	/* N Parameter for Display FIFO */
    498 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
    499 
    500 	WGfx(ba, GCT_ID_SET_RESET, 0x0);
    501 	WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x0);
    502 	WGfx(ba, GCT_ID_COLOR_COMPARE, 0x0);
    503 	WGfx(ba, GCT_ID_DATA_ROTATE, 0x0);
    504 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x0);
    505 	WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40);
    506 	WGfx(ba, GCT_ID_MISC, 0x01);
    507 	WGfx(ba, GCT_ID_COLOR_XCARE, 0x0F);
    508 	WGfx(ba, GCT_ID_BITMASK, 0xFF);
    509 
    510 	/* colors for text mode */
    511 	for (i = 0; i <= 0xf; i++)
    512 		WAttr (ba, i, i);
    513 
    514 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x41);
    515 	WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x01);
    516 	WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0F);
    517 	WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x0);
    518 	WAttr(ba, ACT_ID_COLOR_SELECT, 0x0);
    519 
    520 	vgaw(ba, VDAC_MASK, 0xFF);	/* DAC Mask */
    521 
    522 	*((unsigned long *)(ba + ECR_FRGD_COLOR)) = 0xFF;
    523 	*((unsigned long *)(ba + ECR_BKGD_COLOR)) = 0;
    524 
    525 	/* colors initially set to greyscale */
    526 
    527 	vgaw(ba, VDAC_ADDRESS_W, 0);
    528 	for (i = 255; i >= 0 ; i--) {
    529 		vgaw(ba, VDAC_DATA, i);
    530 		vgaw(ba, VDAC_DATA, i);
    531 		vgaw(ba, VDAC_DATA, i);
    532 	}
    533 
    534 	/* GFx hardware cursor off */
    535 	WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
    536 
    537 	/* Set first to 4 MB, so test will work */
    538 	WCrt(ba, CRT_ID_LAW_CNTL, 0x13);
    539 
    540 	/* find *correct* fbsize of z3 board */
    541 	if (cv_has_4mb((volatile char *)cv_boardaddr + 0x01400000)) {
    542 		cv_fbsize = 1024 * 1024 * 4;
    543 		WCrt(ba, CRT_ID_LAW_CNTL, 0x13); /* 4 MB */
    544 	} else {
    545 		cv_fbsize = 1024 * 1024 * 2;
    546 		WCrt(ba, CRT_ID_LAW_CNTL, 0x12); /* 2 MB */
    547 	}
    548 
    549 	/* If I knew what this really does... but it _is_ necessary
    550 	to get any gfx on the screen!! Undocumented register? */
    551 	WAttr(ba, 0x33, 0);
    552 
    553 	gi = &gp->g_display;
    554 	gi->gd_regaddr	= (caddr_t) kvtop (ba);
    555 	gi->gd_regsize	= 64 * 1024;
    556 	gi->gd_fbaddr	= (caddr_t) kvtop (gp->g_fbkva);
    557 	gi->gd_fbsize	= cv_fbsize;
    558 }
    559 
    560 
    561 int
    562 cv_getvmode(gp, vm)
    563 	struct grf_softc *gp;
    564 	struct grfvideo_mode *vm;
    565 {
    566 	struct grfvideo_mode *gv;
    567 
    568 #ifdef CV64CONSOLE
    569 	/* Handle grabbing console mode */
    570 	if (vm->mode_num == 255) {
    571 		bcopy(&cvconsole_mode, vm, sizeof(struct grfvideo_mode));
    572 		/* XXX so grfconfig can tell us the correct text dimensions. */
    573 		vm->depth = cvconsole_mode.fy;
    574 	} else
    575 #endif
    576 	{
    577 		if (vm->mode_num == 0)
    578 			vm->mode_num = (monitor_current - monitor_def) + 1;
    579 		if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
    580 			return (EINVAL);
    581 		gv = monitor_def + (vm->mode_num - 1);
    582 		if (gv->mode_num == 0)
    583 			return (EINVAL);
    584 
    585 		bcopy(gv, vm, sizeof(struct grfvideo_mode));
    586 	}
    587 
    588 	/* adjust internal values to pixel values */
    589 
    590 	vm->hblank_start *= 8;
    591 	vm->hblank_stop *= 8;
    592 	vm->hsync_start *= 8;
    593 	vm->hsync_stop *= 8;
    594 	vm->htotal *= 8;
    595 
    596 	return (0);
    597 }
    598 
    599 
    600 int
    601 cv_setvmode(gp, mode)
    602 	struct grf_softc *gp;
    603 	unsigned mode;
    604 {
    605 	if (!mode || (mode > monitor_def_max) ||
    606 	    monitor_def[mode - 1].mode_num == 0)
    607 		return (EINVAL);
    608 
    609 	monitor_current = monitor_def + (mode - 1);
    610 
    611 	return (0);
    612 }
    613 
    614 
    615 int
    616 cv_blank(gp, on)
    617 	struct grf_softc *gp;
    618 	int *on;
    619 {
    620 	volatile caddr_t ba = gp->g_regkva;
    621 
    622 	gfx_on_off(*on ? 1 : 0, ba);
    623 	return (0);
    624 }
    625 
    626 
    627 /*
    628  * Change the mode of the display.
    629  * Return a UNIX error number or 0 for success.
    630  */
    631 int
    632 cv_mode(gp, cmd, arg, a2, a3)
    633 	register struct grf_softc *gp;
    634 	int cmd;
    635 	void *arg;
    636 	int a2, a3;
    637 {
    638 	int error;
    639 
    640 	switch (cmd) {
    641 	case GM_GRFON:
    642 		error = cv_load_mon (gp,
    643 		    (struct grfcvtext_mode *) monitor_current) ? 0 : EINVAL;
    644 		return (error);
    645 
    646 	case GM_GRFOFF:
    647 #ifndef CV64CONSOLE
    648 		(void)cv_toggle(gp);
    649 #else
    650 		cv_load_mon(gp, &cvconsole_mode);
    651 #endif
    652 		return (0);
    653 
    654 	case GM_GRFCONFIG:
    655 		return (0);
    656 
    657 	case GM_GRFGETVMODE:
    658 		return (cv_getvmode (gp, (struct grfvideo_mode *) arg));
    659 
    660 	case GM_GRFSETVMODE:
    661 		error = cv_setvmode (gp, *(unsigned *) arg);
    662 		if (!error && (gp->g_flags & GF_GRFON))
    663 			cv_load_mon(gp,
    664 			    (struct grfcvtext_mode *) monitor_current);
    665 		return (error);
    666 
    667 	case GM_GRFGETNUMVM:
    668 		*(int *)arg = monitor_def_max;
    669 		return (0);
    670 
    671 	case GM_GRFIOCTL:
    672 		return (cv_ioctl (gp, (int) arg, (caddr_t) a2));
    673 
    674 	default:
    675 		break;
    676 	}
    677 
    678 	return (EINVAL);
    679 }
    680 
    681 int
    682 cv_ioctl (gp, cmd, data)
    683 	register struct grf_softc *gp;
    684 	int cmd;
    685 	void *data;
    686 {
    687 	switch (cmd) {
    688 	case GRFIOCGSPRITEPOS:
    689 	case GRFIOCSSPRITEPOS:
    690 	case GRFIOCSSPRITEINF:
    691 	case GRFIOCGSPRITEINF:
    692 	case GRFIOCGSPRITEMAX:
    693 		break;
    694 
    695 	case GRFIOCGETCMAP:
    696 		return (cv_getcmap (gp, (struct grf_colormap *) data));
    697 
    698 	case GRFIOCPUTCMAP:
    699 		return (cv_putcmap (gp, (struct grf_colormap *) data));
    700 
    701 	case GRFIOCBITBLT:
    702 		break;
    703 
    704 	case GRFTOGGLE:
    705 		return (cv_toggle (gp));
    706 
    707 	case GRFIOCSETMON:
    708 		return (cv_setmonitor (gp, (struct grfvideo_mode *)data));
    709 
    710 	case GRFIOCBLANK:
    711 		return (cv_blank (gp, (int *)data));
    712 	}
    713 	return (EINVAL);
    714 }
    715 
    716 int
    717 cv_setmonitor(gp, gv)
    718 	struct grf_softc *gp;
    719 	struct grfvideo_mode *gv;
    720 {
    721 	struct grfvideo_mode *md;
    722 
    723 	if (!cv_mondefok(gv))
    724 		return (EINVAL);
    725 
    726 #ifdef CV64CONSOLE
    727 	/* handle interactive setting of console mode */
    728 	if (gv->mode_num == 255) {
    729 		bcopy(gv, &cvconsole_mode.gv, sizeof(struct grfvideo_mode));
    730 		cvconsole_mode.gv.hblank_start /= 8;
    731 		cvconsole_mode.gv.hblank_stop /= 8;
    732 		cvconsole_mode.gv.hsync_start /= 8;
    733 		cvconsole_mode.gv.hsync_stop /= 8;
    734 		cvconsole_mode.gv.htotal /= 8;
    735 		cvconsole_mode.rows = gv->disp_height / cvconsole_mode.fy;
    736 		cvconsole_mode.cols = gv->disp_width / cvconsole_mode.fx;
    737 		if (!(gp->g_flags & GF_GRFON))
    738 			cv_load_mon(gp, &cvconsole_mode);
    739 		ite_reinit(gp->g_itedev);
    740 		return (0);
    741 	}
    742 #endif
    743 
    744 	md = monitor_def + (gv->mode_num - 1);
    745 	bcopy(gv, md, sizeof(struct grfvideo_mode));
    746 
    747 	/* adjust pixel oriented values to internal rep. */
    748 
    749 	md->hblank_start /= 8;
    750 	md->hblank_stop /= 8;
    751 	md->hsync_start /= 8;
    752 	md->hsync_stop /= 8;
    753 	md->htotal /= 8;
    754 
    755 	return (0);
    756 }
    757 
    758 int
    759 cv_getcmap(gfp, cmap)
    760 	struct grf_softc *gfp;
    761 	struct grf_colormap *cmap;
    762 {
    763 	volatile caddr_t ba;
    764 	u_char red[256], green[256], blue[256], *rp, *gp, *bp;
    765 	short x;
    766 	int error;
    767 
    768 	if (cmap->count == 0 || cmap->index >= 256)
    769 		return (0);
    770 
    771 	if (cmap->index + cmap->count > 256)
    772 		cmap->count = 256 - cmap->index;
    773 
    774 	ba = gfp->g_regkva;
    775 	/* first read colors out of the chip, then copyout to userspace */
    776 	vgaw (ba, VDAC_ADDRESS_W, cmap->index);
    777 	x = cmap->count - 1;
    778 
    779 	rp = red + cmap->index;
    780 	gp = green + cmap->index;
    781 	bp = blue + cmap->index;
    782 
    783 	do {
    784 		*rp++ = vgar (ba, VDAC_DATA) << 2;
    785 		*gp++ = vgar (ba, VDAC_DATA) << 2;
    786 		*bp++ = vgar (ba, VDAC_DATA) << 2;
    787 	} while (x-- > 0);
    788 
    789 	if (!(error = copyout (red + cmap->index, cmap->red, cmap->count))
    790 	    && !(error = copyout (green + cmap->index, cmap->green, cmap->count))
    791 	    && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count)))
    792 		return (0);
    793 
    794 	return (error);
    795 }
    796 
    797 int
    798 cv_putcmap(gfp, cmap)
    799 	struct grf_softc *gfp;
    800 	struct grf_colormap *cmap;
    801 {
    802 	volatile caddr_t ba;
    803 	u_char red[256], green[256], blue[256], *rp, *gp, *bp;
    804 	short x;
    805 	int error;
    806 
    807 	if (cmap->count == 0 || cmap->index >= 256)
    808 		return (0);
    809 
    810 	if (cmap->index + cmap->count > 256)
    811 		cmap->count = 256 - cmap->index;
    812 
    813 	/* first copy the colors into kernelspace */
    814 	if (!(error = copyin (cmap->red, red + cmap->index, cmap->count))
    815 	    && !(error = copyin (cmap->green, green + cmap->index, cmap->count))
    816 	    && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count))) {
    817 		ba = gfp->g_regkva;
    818 		vgaw (ba, VDAC_ADDRESS_W, cmap->index);
    819 		x = cmap->count - 1;
    820 
    821 		rp = red + cmap->index;
    822 		gp = green + cmap->index;
    823 		bp = blue + cmap->index;
    824 
    825 		do {
    826 			vgaw (ba, VDAC_DATA, *rp++ >> 2);
    827 			vgaw (ba, VDAC_DATA, *gp++ >> 2);
    828 			vgaw (ba, VDAC_DATA, *bp++ >> 2);
    829 		} while (x-- > 0);
    830 		return (0);
    831 	} else
    832 		return (error);
    833 }
    834 
    835 
    836 int
    837 cv_toggle(gp)
    838 	struct grf_softc *gp;
    839 {
    840 	volatile caddr_t ba;
    841 
    842 	ba = gp->g_regkva;
    843 	cvscreen(1, ba - READ_OFFSET);
    844 
    845 	return (0);
    846 }
    847 
    848 
    849 int
    850 cv_mondefok(gv)
    851 	struct grfvideo_mode *gv;
    852 {
    853 	unsigned long maxpix;
    854 
    855 	if (gv->mode_num < 1 || gv->mode_num > monitor_def_max)
    856 		if (gv->mode_num != 255 || gv->depth != 4)
    857 			return (0);
    858 
    859 	switch(gv->depth) {
    860 	   case 1:
    861 	   case 4:
    862 		/* Remove this comment when ite5 is ready */
    863 		/* if (gv->mode_num != 255) */
    864 			return (0);
    865 	   case 8:
    866 		maxpix = MAXPIXELCLOCK;
    867 		break;
    868 	   case 15:
    869 	   case 16:
    870 		maxpix = MAXPIXELCLOCK - 55000000;
    871 		break;
    872 	   case 24:
    873 		maxpix = MAXPIXELCLOCK - 85000000;
    874 		break;
    875 	   default:
    876 		return (0);
    877 	}
    878 
    879 	if (gv->pixel_clock > maxpix)
    880 		return (0);
    881 	return (1);
    882 }
    883 
    884 int
    885 cv_load_mon(gp, md)
    886 	struct grf_softc *gp;
    887 	struct grfcvtext_mode *md;
    888 {
    889 	struct grfvideo_mode *gv;
    890 	struct grfinfo *gi;
    891 	volatile caddr_t ba, fb;
    892 	unsigned short mnr;
    893 	unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
    894 		VSE, VT;
    895 	char LACE, DBLSCAN, TEXT;
    896 	int uplim, lowlim;
    897 	int cr33, sr15, sr18, clock_mode, test;
    898 	int m, n, clock, i;	/* For calc'ing display FIFO */
    899 
    900 	/* identity */
    901 	gv = &md->gv;
    902 	TEXT = (gv->depth == 4);
    903 
    904 	if (!cv_mondefok(gv)) {
    905 		printf("mondef not ok\n");
    906 		return (0);
    907 	}
    908 	ba = gp->g_regkva;
    909 	fb = gp->g_fbkva;
    910 
    911 	/* turn gfx off, don't mess up the display */
    912 	gfx_on_off(1, ba);
    913 
    914 	/* provide all needed information in grf device-independant locations */
    915 	gp->g_data		= (caddr_t) gv;
    916 	gi = &gp->g_display;
    917 	gi->gd_colors		= 1 << gv->depth;
    918 	gi->gd_planes		= gv->depth;
    919 	gi->gd_fbwidth		= gv->disp_width;
    920 	gi->gd_fbheight		= gv->disp_height;
    921 	gi->gd_fbx		= 0;
    922 	gi->gd_fby		= 0;
    923 	if (TEXT) {
    924 		gi->gd_dwidth	= md->fx * md->cols;
    925 		gi->gd_dheight	= md->fy * md->rows;
    926 	} else {
    927 		gi->gd_dwidth	= gv->disp_width;
    928 		gi->gd_dheight	= gv->disp_height;
    929 	}
    930 	gi->gd_dx		= 0;
    931 	gi->gd_dy		= 0;
    932 
    933 	/* get display mode parameters */
    934 
    935 	HBS = gv->hblank_start;
    936 	HBE = gv->hblank_stop;
    937 	HSS = gv->hsync_start;
    938 	HSE = gv->hsync_stop;
    939 	HT  = gv->htotal - 5;
    940 	VBS = gv->vblank_start - 1;
    941 	VSS = gv->vsync_start;
    942 	VSE = gv->vsync_stop;
    943 	VBE = gv->vblank_stop;
    944 	VT  = gv->vtotal - 2;
    945 
    946 	if (TEXT)
    947 		HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
    948 	else
    949 		HDE = (gv->disp_width + 3) / 8 - 1; /*HBS;*/
    950 	VDE = gv->disp_height - 1;
    951 
    952 	/* figure out whether lace or dblscan is needed */
    953 
    954 	uplim = gv->disp_height + (gv->disp_height / 4);
    955 	lowlim = gv->disp_height - (gv->disp_height / 4);
    956 	LACE = (((VT * 2) > lowlim) && ((VT * 2) < uplim)) ? 1 : 0;
    957 	DBLSCAN = (((VT / 2) > lowlim) && ((VT / 2) < uplim)) ? 1 : 0;
    958 
    959 	/* adjustments */
    960 
    961 	if (LACE)
    962 		VDE /= 2;
    963 
    964 	WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
    965 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
    966 	WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
    967 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
    968 
    969 	/* Set clock */
    970 
    971 	switch (gv->depth) {
    972 	   case 15:
    973 	   case 16:
    974 		mnr = compute_clock(gv->pixel_clock * 2);
    975 		break;
    976 	   case 24:
    977 		mnr = compute_clock(gv->pixel_clock * 3);
    978 		break;
    979 	   default:
    980 		mnr = compute_clock(gv->pixel_clock);
    981 		break;
    982 	}
    983 
    984 	WSeq(ba, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8) );
    985 	WSeq(ba, SEQ_ID_DCLK_LO, (mnr & 0xFF));
    986 
    987 	/* load display parameters into board */
    988 
    989 	WCrt(ba, CRT_ID_EXT_HOR_OVF,
    990 	   ((HT & 0x100) ? 0x01 : 0x00) |
    991 	   ((HDE & 0x100) ? 0x02 : 0x00) |
    992 	   ((HBS & 0x100) ? 0x04 : 0x00) |
    993 	/* ((HBE & 0x40) ? 0x08 : 0x00) | */  /* Later... */
    994 	   ((HSS & 0x100) ? 0x10 : 0x00) |
    995 	/* ((HSE & 0x20) ? 0x20 : 0x00) | */
    996 	   (((HT-5) & 0x100) ? 0x40 : 0x00) );
    997 
    998 	WCrt(ba, CRT_ID_EXT_VER_OVF,
    999 	    0x40 |	/* Line compare */
   1000 	    ((VT  & 0x400) ? 0x01 : 0x00) |
   1001 	    ((VDE & 0x400) ? 0x02 : 0x00) |
   1002 	    ((VBS & 0x400) ? 0x04 : 0x00) |
   1003 	    ((VSS & 0x400) ? 0x10 : 0x00) );
   1004 
   1005 	WCrt(ba, CRT_ID_HOR_TOTAL, HT);
   1006 	WCrt(ba, CRT_ID_DISPLAY_FIFO, HT - 5);
   1007 
   1008 	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
   1009 	WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
   1010 	WCrt(ba, CRT_ID_END_HOR_BLANK, ((HBE & 0x1f) | 0x80));
   1011 	WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
   1012 	WCrt(ba, CRT_ID_END_HOR_RETR,
   1013 	    (HSE & 0x1f) |
   1014 	    ((HBE & 0x20) ? 0x80 : 0x00) );
   1015 	WCrt(ba, CRT_ID_VER_TOTAL, VT);
   1016 	WCrt(ba, CRT_ID_OVERFLOW,
   1017 	    0x10 |
   1018 	    ((VT  & 0x100) ? 0x01 : 0x00) |
   1019 	    ((VDE & 0x100) ? 0x02 : 0x00) |
   1020 	    ((VSS & 0x100) ? 0x04 : 0x00) |
   1021 	    ((VBS & 0x100) ? 0x08 : 0x00) |
   1022 	    ((VT  & 0x200) ? 0x20 : 0x00) |
   1023 	    ((VDE & 0x200) ? 0x40 : 0x00) |
   1024 	    ((VSS & 0x200) ? 0x80 : 0x00) );
   1025 
   1026 	WCrt(ba, CRT_ID_MAX_SCAN_LINE,
   1027 	    0x40 |  /* TEXT ? 0x00 ??? */
   1028 	    (DBLSCAN ? 0x80 : 0x00) |
   1029 	    ((VBS & 0x200) ? 0x20 : 0x00) |
   1030 	    (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
   1031 
   1032 	WCrt(ba, CRT_ID_MODE_CONTROL,
   1033 	    ((TEXT || (gv->depth == 1)) ? 0xc3 : 0xe3));
   1034 
   1035 	/* text cursor */
   1036 
   1037 	if (TEXT) {
   1038 #if 1
   1039 		WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
   1040 		WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
   1041 #else
   1042 		WCrt(ba, CRT_ID_CURSOR_START, 0x00);
   1043 		WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
   1044 #endif
   1045 		WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f);
   1046 
   1047 		WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
   1048 		WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
   1049 	}
   1050 
   1051 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
   1052 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
   1053 
   1054 	WCrt(ba, CRT_ID_START_VER_RETR, VSS);
   1055 	WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f));
   1056 	WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
   1057 	WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
   1058 	WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
   1059 
   1060 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
   1061 	WCrt(ba, CRT_ID_LACE_RETR_START, HT / 2);
   1062 	WCrt(ba, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
   1063 
   1064 	WGfx(ba, GCT_ID_GRAPHICS_MODE,
   1065 	    ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
   1066 	WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
   1067 
   1068 	WSeq (ba, SEQ_ID_MEMORY_MODE,
   1069 	    ((TEXT || (gv->depth == 1)) ? 0x6 : 0x02));
   1070 
   1071 	vgaw(ba, VDAC_MASK, 0xff);
   1072 
   1073 	sr15 = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);
   1074 	sr15 &= 0xef;
   1075 	sr18 = RSeq(ba, SEQ_ID_RAMDAC_CNTL);
   1076 	sr18 &= 0x7f;
   1077 	cr33 = RCrt(ba, CRT_ID_BACKWAD_COMP_2);
   1078 	cr33 &= 0xdf;
   1079 	clock_mode = 0x00;
   1080 
   1081 	test = RCrt(ba, CRT_ID_EXT_MISC_CNTL_2);
   1082 	test &= 0xd;
   1083 
   1084 	switch (gv->depth) {
   1085 	   case 1:
   1086 	   case 4: /* text */
   1087 		HDE = gv->disp_width / 16;
   1088 		break;
   1089 	   case 8:
   1090 		if (gv->pixel_clock > 80000000) {
   1091 			clock_mode = 0x10 | 0x02;
   1092 			sr15 |= 0x10;
   1093 			sr18 |= 0x80;
   1094 			cr33 |= 0x20;
   1095 		}
   1096 		HDE = gv->disp_width / 8;
   1097 		break;
   1098 	   case 15:
   1099 		clock_mode = 0x30;
   1100 		HDE = gv->disp_width / 4;
   1101 		break;
   1102 	   case 16:
   1103 		clock_mode = 0x50;
   1104 		HDE = gv->disp_width / 4;
   1105 		break;
   1106 	   case 24:
   1107 		clock_mode = 0xd0;
   1108 		HDE = (gv->disp_width / 8) * 3;
   1109 		break;
   1110 	}
   1111 
   1112 	WCrt(ba, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
   1113 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, sr15);
   1114 	WSeq(ba, SEQ_ID_RAMDAC_CNTL, sr18);
   1115 	WCrt(ba, CRT_ID_BACKWAD_COMP_2, cr33);
   1116 	WCrt(ba, CRT_ID_SCREEN_OFFSET, HDE);
   1117 
   1118 	test = RCrt(ba, CRT_ID_EXT_SYS_CNTL_2);
   1119 	/* HDE Overflow in bits 4-5 */
   1120 	test |= (HDE >> 4) & 0x30;
   1121 	WCrt(ba, CRT_ID_EXT_SYS_CNTL_2, test);
   1122 
   1123 	delay(100000);
   1124 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x0a : 0x41));
   1125 	delay(100000);
   1126 	WAttr(ba, ACT_ID_COLOR_PLANE_ENA,
   1127 	    (gv->depth == 1) ? 0x01 : 0x0f);
   1128 	delay(100000);
   1129 
   1130 	/*
   1131 	 * Calc. display fifo m and n parameters
   1132 	 * Dont't ask me what the hell these values mean.
   1133 	 */
   1134 
   1135 	n = 0xff;
   1136 	if (gv->depth < 9)
   1137 		clock = gv->pixel_clock / 500000;
   1138 	else if (gv->depth == 15)
   1139 		clock = gv->pixel_clock / 250000;
   1140 	else
   1141 		clock = (gv->pixel_clock * (gv->depth / 8)) / 500000;
   1142 #if 0
   1143 	/*
   1144 	 * Note: if you change this you should change it in
   1145 	 * gen_cvtab.c and regenerate the conversion table
   1146 	 * rerun gen_cvtab
   1147 	 */
   1148 	m = (int)((55 * .72 + 16.867) * 89.736 / (clock + 39) - 21.1543)
   1149 	m = (m / 2) - 1;
   1150 	if (m > 31)
   1151 		m = 31;
   1152 	else if (m <= 0) {
   1153 		m = 0;
   1154 		n = 16;
   1155 	}
   1156 #endif
   1157 	for (m = 0; m < 31; ++m)
   1158 		if (clock >= cv_convtab[m])
   1159 			break;
   1160 	if (m == 0)
   1161 		n = 16;
   1162 
   1163 	m = m << 3;
   1164 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, m);
   1165 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, n);
   1166 	delay(10000);
   1167 
   1168 	/* text initialization */
   1169 
   1170 	if (TEXT) {
   1171 		cv_inittextmode(gp);
   1172 	}
   1173 
   1174 	/* Some kind of Magic */
   1175 	WAttr(ba, 0x33, 0);
   1176 
   1177 	/* turn gfx on again */
   1178 	gfx_on_off(0, ba);
   1179 
   1180 	/* Pass-through */
   1181 	cvscreen(0, ba - READ_OFFSET);
   1182 
   1183 	return (1);
   1184 }
   1185 
   1186 void
   1187 cv_inittextmode(gp)
   1188 	struct grf_softc *gp;
   1189 {
   1190 	struct grfcvtext_mode *tm = (struct grfcvtext_mode *)gp->g_data;
   1191 	volatile caddr_t ba = gp->g_regkva;
   1192 	volatile caddr_t fb = gp->g_fbkva;
   1193 	unsigned char *c, *f, y;
   1194 	unsigned short z;
   1195 
   1196 
   1197 	/* load text font into beginning of display memory.
   1198 	 * Each character cell is 32 bytes long (enough for 4 planes)
   1199 	 */
   1200 
   1201 	SetTextPlane(ba, 0x02);
   1202 	cv_memset(fb, 0, 256 * 32);
   1203 	c = (unsigned char *) (fb) + (32 * tm->fdstart);
   1204 	f = tm->fdata;
   1205 	for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy))
   1206 		for (y = 0; y < tm->fy; y++)
   1207 			*c++ = *f++;
   1208 
   1209 	/* clear out text/attr planes (three screens worth) */
   1210 
   1211 	SetTextPlane(ba, 0x01);
   1212 	cv_memset(fb, 0x07, tm->cols * tm->rows * 3);
   1213 	SetTextPlane(ba, 0x00);
   1214 	cv_memset(fb, 0x20, tm->cols * tm->rows * 3);
   1215 
   1216 	/* print out a little init msg */
   1217 
   1218 	c = (unsigned char *)(fb) + (tm->cols-16);
   1219 	strcpy(c, "CV64");
   1220 	c[6] = 0x20;
   1221 
   1222 	/* set colors (B&W) */
   1223 
   1224 	vgaw(ba, VDAC_ADDRESS_W, 0);
   1225 	for (z=0; z<256; z++) {
   1226 		unsigned char r, g, b;
   1227 
   1228 		y = (z & 1) ? ((z > 7) ? 2 : 1) : 0;
   1229 
   1230 		r = cvconscolors[y][0];
   1231 		g = cvconscolors[y][1];
   1232 		b = cvconscolors[y][2];
   1233 		vgaw(ba, VDAC_DATA, r >> 2);
   1234 		vgaw(ba, VDAC_DATA, g >> 2);
   1235 		vgaw(ba, VDAC_DATA, b >> 2);
   1236 	}
   1237 }
   1238 
   1239 void
   1240 cv_memset(d, c, l)
   1241 	unsigned char *d;
   1242 	unsigned char c;
   1243 	int l;
   1244 {
   1245 	for(; l > 0; l--)
   1246 		*d++ = c;
   1247 }
   1248 
   1249 #endif  /* NGRFCV */
   1250