Home | History | Annotate | Line # | Download | only in dev
grf_cv.c revision 1.11
      1 /*	$NetBSD: grf_cv.c,v 1.11 1996/03/17 05:58:36 mhitch 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 /*
     37  * Graphics routines for the CyberVision 64 board, using the S3 Trio64.
     38  *
     39  * Modified for CV64 from
     40  * Kari Mettinen's Cirrus driver by Michael Teske 10/95
     41  * For questions mail me at teske (at) dice2.desy.de
     42  *
     43  * Thanks to Tekelec Airtronic for providing me with a S3 Trio64 documentation.
     44  * Thanks to Bernd 'the fabulous bug-finder' Ernesti for bringing my messy
     45  * source to NetBSD style :)
     46  *
     47  * TODO:
     48  *    Hardware Cursor support
     49  */
     50 
     51 #include <sys/param.h>
     52 #include <sys/errno.h>
     53 #include <sys/ioctl.h>
     54 #include <sys/device.h>
     55 #include <sys/malloc.h>
     56 #include <sys/systm.h>
     57 #include <machine/cpu.h>
     58 #include <dev/cons.h>
     59 #include <amiga/dev/itevar.h>
     60 #include <amiga/amiga/device.h>
     61 #include <amiga/dev/grfioctl.h>
     62 #include <amiga/dev/grfvar.h>
     63 #include <amiga/dev/grf_cvreg.h>
     64 #include <amiga/dev/zbusvar.h>
     65 
     66 int	grfcvmatch  __P((struct device *, void *, void *));
     67 void	grfcvattach __P((struct device *, struct device *, void *));
     68 int	grfcvprint  __P((void *, char *));
     69 
     70 static int cv_has_4mb __P((volatile caddr_t));
     71 static unsigned short compute_clock __P((unsigned long));
     72 void	cv_boardinit __P((struct grf_softc *));
     73 int	cv_getvmode __P((struct grf_softc *, struct grfvideo_mode *));
     74 int	cv_setvmode __P((struct grf_softc *, unsigned int));
     75 int	cv_blank __P((struct grf_softc *, int *));
     76 int	cv_mode __P((register struct grf_softc *, int, void *, int, int));
     77 int	cv_ioctl __P((register struct grf_softc *gp, int cmd, void *data));
     78 int	cv_setmonitor __P((struct grf_softc *, struct grfvideo_mode *));
     79 int	cv_getcmap __P((struct grf_softc *, struct grf_colormap *));
     80 int	cv_putcmap __P((struct grf_softc *, struct grf_colormap *));
     81 int	cv_toggle __P((struct grf_softc *));
     82 int	cv_mondefok __P((struct grfvideo_mode *));
     83 int	cv_load_mon __P((struct grf_softc *, struct grfcvtext_mode *));
     84 void	cv_inittextmode __P((struct grf_softc *));
     85 void	cv_memset __P((unsigned char *, unsigned char, int));
     86 static	inline void cv_write_port __P((unsigned short, volatile caddr_t));
     87 static	inline void cvscreen __P((int, volatile caddr_t));
     88 static	inline void gfx_on_off __P((int, volatile caddr_t));
     89 
     90 /* Graphics display definitions.
     91  * These are filled by 'grfconfig' using GRFIOCSETMON.
     92  */
     93 #define monitor_def_max 24
     94 static struct grfvideo_mode monitor_def[24] = {
     95 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
     96 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
     97 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}
     98 };
     99 static struct grfvideo_mode *monitor_current = &monitor_def[0];
    100 #define MAXPIXELCLOCK 135000000 /* safety */
    101 
    102 
    103 /* Console display definition.
    104  *   Default hardcoded text mode.  This grf_cv is set up to
    105  *   use one text mode only, and this is it.  You may use
    106  *   grfconfig to change the mode after boot.
    107  */
    108 
    109 /* Console font */
    110 #ifdef KFONT_8X11
    111 #define S3FONT kernel_font_8x11
    112 #define S3FONTY 11
    113 #else
    114 #define S3FONT kernel_font_8x8
    115 #define S3FONTY 8
    116 #endif
    117 extern unsigned char S3FONT[];
    118 
    119 /*
    120  * Define default console mode
    121  * (Internally, we still have to use hvalues/8!)
    122  */
    123 struct grfcvtext_mode cvconsole_mode = {
    124 	{255, "", 25000000, 640, 480, 4, 640/8, 784/8, 680/8, 768/8, 800/8,
    125 	 481, 521, 491, 493, 525},
    126 	8, S3FONTY, 80, 480 / S3FONTY, S3FONT, 32, 255
    127 };
    128 
    129 /* Console colors */
    130 unsigned char cvconscolors[4][3] = {	/* background, foreground, hilite */
    131 	{0x30, 0x30, 0x30}, {0, 0, 0}, {0x18, 0x20, 0x34}, {0x2a, 0x2a, 0x2a}
    132 };
    133 
    134 static unsigned char clocks[]={
    135 0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69,
    136 0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c,
    137 0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a,
    138 0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69,
    139 0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65,
    140 0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63,
    141 0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d,
    142 0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49,
    143 0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42,
    144 0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43,
    145 0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49,
    146 0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a,
    147 0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49,
    148 0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41,
    149 0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43,
    150 0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45,
    151 0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45,
    152 0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45,
    153 0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44,
    154 0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46,
    155 0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f,
    156 0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22,
    157 0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46,
    158 0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b,
    159 0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44,
    160 0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26,
    161 0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b,
    162 0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25,
    163 0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25,
    164 0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21,
    165 0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29,
    166 0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29,
    167 0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29,
    168 0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28,
    169 0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26,
    170 0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21,
    171 0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28,
    172 0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27,
    173 0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22,
    174 0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27,
    175 0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27,
    176 0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21,
    177 0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26,
    178 0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27,
    179 0x13, 0x1,  0x13, 0x1,  0x7d, 0x27, 0x4c, 0x9,
    180 0x37, 0x22, 0x5b, 0xb,  0x71, 0x26, 0x5c, 0xb,
    181 0x6b, 0xd,  0x47, 0x23, 0x14, 0x1,  0x4f, 0x9,
    182 0x23, 0x3,  0x75, 0x26, 0x7d, 0xf,  0x1c, 0x2,
    183 0x51, 0x9,  0x59, 0x24, 0x61, 0xb,  0x69, 0x25,
    184 0x79, 0x26, 0x34, 0x5,  0x1d, 0x2,  0x6b, 0x25,
    185 0x54, 0x9,  0x35, 0x5,  0x45, 0x7,  0x6d, 0x25,
    186 0x7d, 0x26, 0x16, 0x1,  0x7f, 0x26, 0x77, 0xd,
    187 0x4f, 0x23, 0x78, 0xd,  0x2f, 0x21, 0x27, 0x3,
    188 0x1f, 0x2,  0x59, 0x9,  0x6a, 0xb,  0x73, 0x25,
    189 0x6b, 0xb,  0x63, 0x24, 0x5b, 0x9,  0x20, 0x2,
    190 0x7e, 0xd,  0x4b, 0x7,  0x65, 0x24, 0x43, 0x22,
    191 0x18, 0x1,  0x6f, 0xb,  0x5e, 0x9,  0x70, 0xb,
    192 0x2a, 0x3,  0x33, 0x4,  0x45, 0x6,  0x60, 0x9,
    193 0x7b, 0xc,  0x19, 0x1,  0x19, 0x1,  0x7d, 0xc,
    194 0x74, 0xb,  0x50, 0x7,  0x75, 0xb,  0x63, 0x9,
    195 0x51, 0x7,  0x23, 0x2,  0x3f, 0x5,  0x1a, 0x1,
    196 0x65, 0x9,  0x2d, 0x3,  0x40, 0x5,  0x0,  0x0,
    197 };
    198 
    199 
    200 /* Board Address of CV64 */
    201 static volatile caddr_t cv_boardaddr;
    202 static int cv_fbsize;
    203 
    204 /*
    205  * Memory clock (binpatchable).
    206  * Let's be defensive: 45 MHz runs on all boards I know of.
    207  * 55 MHz runs on most boards. But you should know what you're doing
    208  * if you set this flag. Again: This flag may destroy your CV Board.
    209  * Use it at your own risk!!!
    210  * Anyway, this doesn't imply that I'm responsible if your board breaks
    211  * without setting this flag :-).
    212  */
    213 #ifdef CV_AGGRESSIVE_TIMING
    214 long cv_memclk = 55000000;
    215 #else
    216 long cv_memclk = 45000000;
    217 #endif
    218 
    219 /* standard driver stuff */
    220 struct cfattach grfcv_ca = {
    221 	sizeof(struct grf_softc), grfcvmatch, grfcvattach
    222 };
    223 
    224 struct cfdriver grfcv_cd = {
    225 	NULL, "grfcv", DV_DULL, NULL, 0
    226 };
    227 static struct cfdata *cfdata;
    228 
    229 
    230 /*
    231  * Get frambuffer memory size.
    232  * phase5 didn't provide the bit in CR36,
    233  * so we have to do it this way.
    234  * Return 0 for 2MB, 1 for 4MB
    235  */
    236 static int
    237 cv_has_4mb(fb)
    238 	volatile caddr_t fb;
    239 {
    240 	volatile unsigned long *testfbw, *testfbr;
    241 
    242 	/* write patterns in memory and test if they can be read */
    243 	testfbw = (volatile unsigned long *)fb;
    244 	testfbr = (volatile unsigned long *)(fb + 0x02000000);
    245 	*testfbw = 0x87654321;
    246 	if (*testfbr != 0x87654321)
    247 		return (0);
    248 
    249 	/* upper memory region */
    250 	testfbw = (volatile unsigned long *)(fb + 0x00200000);
    251 	testfbr = (volatile unsigned long *)(fb + 0x02200000);
    252 	*testfbw = 0x87654321;
    253 	if (*testfbr != 0x87654321)
    254 		return (0);
    255 	*testfbw = 0xAAAAAAAA;
    256 	if (*testfbr != 0xAAAAAAAA)
    257 		return (0);
    258 	*testfbw = 0x55555555;
    259 	if (*testfbr != 0x55555555)
    260 		return (0);
    261 	return (1);
    262 }
    263 
    264 int
    265 grfcvmatch(pdp, match, auxp)
    266 	struct device *pdp;
    267 	void *match, *auxp;
    268 {
    269 	struct cfdata *cfp = match;
    270 	struct zbus_args *zap;
    271 	static int cvcons_unit = -1;
    272 
    273 	zap = auxp;
    274 
    275 	if (amiga_realconfig == 0)
    276 #ifdef CV64CONSOLE
    277 		if (cvcons_unit != -1)
    278 #endif
    279 			 return (0);
    280 
    281 	/* Lets be Paranoid: Test man and prod id */
    282 	if (zap->manid != 8512 || zap->prodid != 34)
    283 		return (0);
    284 
    285 	cv_boardaddr = zap->va;
    286 
    287 #ifdef CV64CONSOLE
    288 	if (amiga_realconfig == 0) {
    289 		cvcons_unit = cfp->cf_unit;
    290 		cfdata = cfp;
    291 	}
    292 #endif
    293 
    294 	return (1);
    295 }
    296 
    297 void
    298 grfcvattach(pdp, dp, auxp)
    299 	struct device *pdp, *dp;
    300 	void *auxp;
    301 {
    302 	static struct grf_softc congrf;
    303 	struct zbus_args *zap;
    304 	struct grf_softc *gp;
    305 	static char attachflag = 0;
    306 
    307 	zap = auxp;
    308 
    309 	/*
    310 	 * This function is called twice, once on console init (dp == NULL)
    311 	 * and once on "normal" grf5 init.
    312 	 */
    313 
    314 	if (dp == NULL) /* console init */
    315 		gp = &congrf;
    316 	else
    317 		gp = (struct grf_softc *)dp;
    318 
    319 	if (dp != NULL && congrf.g_regkva != 0) {
    320 		/*
    321 		 * inited earlier, just copy (not device struct)
    322 		 */
    323 
    324 		printf("\n");
    325 #ifdef CV64CONSOLE
    326 		bcopy(&congrf.g_display, &gp->g_display,
    327 			(char *) &gp[1] - (char *) &gp->g_display);
    328 #else
    329 		gp->g_regkva = (volatile caddr_t)cv_boardaddr + 0x02000000;
    330 		gp->g_fbkva = (volatile caddr_t)cv_boardaddr + 0x01400000;
    331 
    332 		gp->g_unit = GRF_CV64_UNIT;
    333 		gp->g_mode = cv_mode;
    334 		gp->g_conpri = grfcv_cnprobe();
    335 		gp->g_flags = GF_ALIVE;
    336 #endif
    337 	} else {
    338 		gp->g_regkva = (volatile caddr_t)cv_boardaddr + 0x02000000;
    339 		gp->g_fbkva = (volatile caddr_t)cv_boardaddr + 0x01400000;
    340 
    341 		gp->g_unit = GRF_CV64_UNIT;
    342 		gp->g_mode = cv_mode;
    343 		gp->g_conpri = grfcv_cnprobe();
    344 		gp->g_flags = GF_ALIVE;
    345 
    346 		/* wakeup the board */
    347 		cv_boardinit(gp);
    348 
    349 #ifdef CV64CONSOLE
    350 		grfcv_iteinit(gp);
    351 		(void)cv_load_mon(gp, &cvconsole_mode);
    352 #endif
    353 	}
    354 
    355 	/*
    356 	 * attach grf
    357 	 */
    358 	if (amiga_config_found(cfdata, &gp->g_device, gp, grfcvprint)) {
    359 		if (dp != NULL)
    360 			printf("grfcv: CyberVision64 with %dMB being used\n", cv_fbsize/0x100000);
    361 		attachflag = 1;
    362 	} else {
    363 		if (!attachflag)
    364 			/*printf("grfcv unattached!!\n")*/;
    365 	}
    366 }
    367 
    368 int
    369 grfcvprint(auxp, pnp)
    370 	void *auxp;
    371 	char *pnp;
    372 {
    373 	if (pnp)
    374 		printf("ite at %s: ", pnp);
    375 	return (UNCONF);
    376 }
    377 
    378 
    379 /*
    380  * Computes M, N, and R values from
    381  * given input frequency. It uses a table of
    382  * precomputed values, to keep CPU time low.
    383  *
    384  * The return value consist of:
    385  * lower byte:  Bits 4-0: N Divider Value
    386  *	        Bits 5-6: R Value          for e.g. SR10 or SR12
    387  * higher byte: Bits 0-6: M divider value  for e.g. SR11 or SR13
    388  */
    389 
    390 static unsigned short
    391 compute_clock(freq)
    392 	unsigned long freq;
    393 {
    394 	static unsigned char *mnr, *save;	/* M, N + R vals */
    395 	unsigned long work_freq, r;
    396 	unsigned short erg;
    397 	long diff, d2;
    398 
    399 	if (freq < 12500000 || freq > MAXPIXELCLOCK) {
    400 		printf("grfcv: Illegal clock frequency: %ldMHz\n", freq/1000000);
    401 		printf("grfcv: Using default frequency: 25MHz\n");
    402 		printf("grfcv: See the manpage of grfconfig for more informations.\n");
    403 		freq = 25000000;
    404 	}
    405 
    406 	mnr = clocks;	/* there the vals are stored */
    407 	d2 = 0x7fffffff;
    408 
    409 	while (*mnr) {	/* mnr vals are 0-terminated */
    410 		work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
    411 
    412 		r = (mnr[1] >> 5) & 0x03;
    413 		if (r != 0)
    414 			work_freq=work_freq >> r;	/* r is the freq divider */
    415 
    416 		work_freq *= 0x3E8;	/* 2nd part of OSC */
    417 
    418 		diff = abs(freq - work_freq);
    419 
    420 		if (d2 >= diff) {
    421 			d2 = diff;
    422 			/* In save are the vals for minimal diff */
    423 			save = mnr;
    424 		}
    425 		mnr += 2;
    426 	}
    427 	erg = *((unsigned short *)save);
    428 
    429 	return (erg);
    430 }
    431 
    432 
    433 void
    434 cv_boardinit(gp)
    435 	struct grf_softc *gp;
    436 {
    437 	volatile caddr_t ba;
    438 	unsigned char test;
    439 	unsigned int clockpar;
    440 	int i;
    441 	struct grfinfo *gi;
    442 
    443 	ba = gp->g_regkva;
    444 	/* Reset board */
    445 	for (i = 0; i < 6; i++)
    446 		cv_write_port (0xff, ba - 0x02000000);	/* Clear all bits */
    447 
    448 	/* Return to operational Mode */
    449 	cv_write_port(0x8004, ba - 0x02000000);
    450 
    451 	/* Wakeup Chip */
    452 	vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x10);
    453 	vgaw(ba, SREG_OPTION_SELECT, 0x1);
    454 	vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x8);
    455 
    456 	vgaw(ba, GREG_MISC_OUTPUT_W, 0x23);
    457 
    458 	WCrt(ba, CRT_ID_REGISTER_LOCK_1, 0x48);	/* unlock S3 VGA regs */
    459 	WCrt(ba, CRT_ID_REGISTER_LOCK_2, 0xA5);	/* unlock syscontrol */
    460 
    461 	test = RCrt(ba, CRT_ID_SYSTEM_CONFIG);
    462 	test = test | 0x01;	/* enable enhaced register access */
    463 	test = test & 0xEF;	/* clear bit 4, 0 wait state */
    464 	WCrt(ba, CRT_ID_SYSTEM_CONFIG, test);
    465 
    466 	/*
    467 	 * bit 1=1: enable enhanced mode functions
    468 	 * bit 4=1: enable linear adressing
    469 	 * bit 5=1: enable MMIO
    470  	 */
    471 	vgaw(ba, ECR_ADV_FUNC_CNTL, 0x31);
    472 
    473 	/* enable cpu acess, color mode, high 64k page */
    474 	vgaw(ba, GREG_MISC_OUTPUT_W, 0x23);
    475 
    476 	/* Cpu base addr */
    477 	WCrt(ba, CRT_ID_EXT_SYS_CNTL_4, 0x0);
    478 
    479 	/* Reset. This does nothing, but everyone does it:) */
    480 	WSeq(ba, SEQ_ID_RESET, 0x3);
    481 
    482 	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x1);	/* 8 Dot Clock */
    483 	WSeq(ba, SEQ_ID_MAP_MASK, 0xF);		/* Enable write planes */
    484 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x0);	/* Character Font */
    485 
    486 	WSeq(ba, SEQ_ID_MEMORY_MODE, 0x2);	/* Complete mem access */
    487 
    488 	WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x6);	/* Unlock extensions */
    489 	test = RSeq(ba, SEQ_ID_BUS_REQ_CNTL);	/* Bus Request */
    490 
    491 	/* enable 4MB fast Page Mode */
    492 	test = test | 1 << 6;
    493 	WSeq(ba, SEQ_ID_BUS_REQ_CNTL, test);
    494 	/* faster LUT write */
    495 	WSeq(ba, SEQ_ID_RAMDAC_CNTL, 0xC0);
    496 
    497 	test = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);	/* Clksyn2 read */
    498 
    499 	/* immediately Clkload bit clear */
    500 	test = test & 0xDF;
    501 
    502 	/* 2 MCLK Memory Write.... */
    503 	if (cv_memclk >= 55000000)
    504 		test |= 0x80;
    505 
    506 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, test);
    507 
    508 	/* Memory CLK */
    509 	clockpar = compute_clock(cv_memclk);
    510 	test = (clockpar & 0xFF00) >> 8;
    511 	WSeq(ba, SEQ_ID_MCLK_HI, test);		/* PLL N-Divider Value */
    512 	if (RCrt(ba, CRT_ID_REVISION) == 0x10)	/* bugfix for new S3 chips */
    513 		WSeq(ba, SEQ_ID_MORE_MAGIC, test);
    514 
    515 	test = clockpar & 0xFF;
    516 	WSeq(ba, SEQ_ID_MCLK_LO, test);		/* PLL M-Divider Value */
    517 
    518 	/* We now load an 25 MHz, 31 kHz, 640x480 standard VGA Mode. */
    519 	/* DCLK */
    520 	WSeq(ba, SEQ_ID_DCLK_HI, 0x13);
    521 	WSeq(ba, SEQ_ID_DCLK_LO, 0x41);
    522 
    523 	test = RSeq (ba, SEQ_ID_CLKSYN_CNTL_2);
    524 	test = test | 0x22;
    525 
    526 	/* DCLK + MCLK Clock immediate load! */
    527 	WSeq(ba,SEQ_ID_CLKSYN_CNTL_2, test);
    528 
    529 	/* DCLK load */
    530 	test = vgar(ba, 0x3cc);
    531 	test = test | 0x0c;
    532 	vgaw(ba, 0x3c2, test);
    533 
    534 	/* Clear bit 5 again, prevent further loading. */
    535 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, 0x2);
    536 
    537 	WCrt(ba, CRT_ID_HOR_TOTAL, 0x5F);
    538 	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, 0x4F);
    539 	WCrt(ba, CRT_ID_START_HOR_BLANK, 0x50);
    540 	WCrt(ba, CRT_ID_END_HOR_BLANK, 0x82);
    541 	WCrt(ba, CRT_ID_START_HOR_RETR, 0x54);
    542 	WCrt(ba, CRT_ID_END_HOR_RETR, 0x80);
    543 	WCrt(ba, CRT_ID_VER_TOTAL, 0xBF);
    544 
    545 	WCrt(ba, CRT_ID_OVERFLOW, 0x1F);	/* overflow reg */
    546 
    547 	WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x0);	/* no panning */
    548 
    549 	WCrt(ba, CRT_ID_MAX_SCAN_LINE, 0x40);	/* vscan */
    550 
    551 	WCrt(ba, CRT_ID_CURSOR_START, 0x00);
    552 	WCrt(ba, CRT_ID_CURSOR_END, 0x00);
    553 
    554 	/* Display start adress */
    555 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
    556 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
    557 
    558 	/* Cursor location */
    559 	WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
    560 	WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
    561 
    562 	/* Vertical retrace */
    563 	WCrt(ba, CRT_ID_START_VER_RETR, 0x9C);
    564 	WCrt(ba, CRT_ID_END_VER_RETR, 0x0E);
    565 
    566 	WCrt(ba, CRT_ID_VER_DISP_ENA_END, 0x8F);
    567 	WCrt(ba, CRT_ID_SCREEN_OFFSET, 0x50);
    568 
    569 	WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x00);
    570 
    571 	WCrt(ba, CRT_ID_START_VER_BLANK, 0x96);
    572 	WCrt(ba, CRT_ID_END_VER_BLANK, 0xB9);
    573 
    574 	WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3);
    575 
    576 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xFF);
    577 
    578 	WCrt(ba, CRT_ID_BACKWAD_COMP_3, 0x10);	/* FIFO enabled */
    579 
    580 	/* Refresh count 1, High speed text font, enhanced color mode */
    581 	WCrt(ba, CRT_ID_MISC_1, 0x35);
    582 
    583 	/* start fifo position */
    584 	WCrt(ba, CRT_ID_DISPLAY_FIFO, 0x5a);
    585 
    586 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, 0x70);
    587 
    588 	/* address window position */
    589 	WCrt(ba, CRT_ID_LAW_POS_LO, 0x40);
    590 
    591 	/* N Parameter for Display FIFO */
    592 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
    593 
    594 	WGfx(ba, GCT_ID_SET_RESET, 0x0);
    595 	WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x0);
    596 	WGfx(ba, GCT_ID_COLOR_COMPARE, 0x0);
    597 	WGfx(ba, GCT_ID_DATA_ROTATE, 0x0);
    598 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x0);
    599 	WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40);
    600 	WGfx(ba, GCT_ID_MISC, 0x01);
    601 	WGfx(ba, GCT_ID_COLOR_XCARE, 0x0F);
    602 	WGfx(ba, GCT_ID_BITMASK, 0xFF);
    603 
    604 	/* colors for text mode */
    605 	for (i = 0; i <= 0xf; i++)
    606 		WAttr (ba, i, i);
    607 
    608 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x41);
    609 	WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x01);
    610 	WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0F);
    611 	WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x0);
    612 	WAttr(ba, ACT_ID_COLOR_SELECT, 0x0);
    613 
    614 	vgaw(ba, VDAC_MASK, 0xFF);	/* DAC Mask */
    615 
    616 	*((unsigned long *)(ba + ECR_FRGD_COLOR)) = 0xFF;
    617 	*((unsigned long *)(ba + ECR_BKGD_COLOR)) = 0;
    618 
    619 	/* colors initially set to greyscale */
    620 
    621 	vgaw(ba, VDAC_ADDRESS_W, 0);
    622 	for (i = 255; i >= 0 ; i--) {
    623 		vgaw(ba, VDAC_DATA, i);
    624 		vgaw(ba, VDAC_DATA, i);
    625 		vgaw(ba, VDAC_DATA, i);
    626 	}
    627 
    628 	/* GFx hardware cursor off */
    629 	WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
    630 
    631 	/* Set first to 4 MB, so test will work */
    632 	WCrt(ba, CRT_ID_LAW_CNTL, 0x13);
    633 
    634 	/* find *correct* fbsize of z3 board */
    635 	if (cv_has_4mb((volatile caddr_t)cv_boardaddr + 0x01400000)) {
    636 		cv_fbsize = 1024 * 1024 * 4;
    637 		WCrt(ba, CRT_ID_LAW_CNTL, 0x13); /* 4 MB */
    638 	} else {
    639 		cv_fbsize = 1024 * 1024 * 2;
    640 		WCrt(ba, CRT_ID_LAW_CNTL, 0x12); /* 2 MB */
    641 	}
    642 
    643 	/* Enable Video Display (Set Bit 5) */
    644 	WAttr(ba, 0x33, 0);
    645 
    646 	gi = &gp->g_display;
    647 	gi->gd_regaddr	= (caddr_t) kvtop (ba);
    648 	gi->gd_regsize	= 64 * 1024;
    649 	gi->gd_fbaddr	= (caddr_t) kvtop (gp->g_fbkva);
    650 	gi->gd_fbsize	= cv_fbsize;
    651 }
    652 
    653 
    654 int
    655 cv_getvmode(gp, vm)
    656 	struct grf_softc *gp;
    657 	struct grfvideo_mode *vm;
    658 {
    659 	struct grfvideo_mode *gv;
    660 
    661 #ifdef CV64CONSOLE
    662 	/* Handle grabbing console mode */
    663 	if (vm->mode_num == 255) {
    664 		bcopy(&cvconsole_mode, vm, sizeof(struct grfvideo_mode));
    665 		/* XXX so grfconfig can tell us the correct text dimensions. */
    666 		vm->depth = cvconsole_mode.fy;
    667 	} else
    668 #endif
    669 	{
    670 		if (vm->mode_num == 0)
    671 			vm->mode_num = (monitor_current - monitor_def) + 1;
    672 		if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
    673 			return (EINVAL);
    674 		gv = monitor_def + (vm->mode_num - 1);
    675 		if (gv->mode_num == 0)
    676 			return (EINVAL);
    677 
    678 		bcopy(gv, vm, sizeof(struct grfvideo_mode));
    679 	}
    680 
    681 	/* adjust internal values to pixel values */
    682 
    683 	vm->hblank_start *= 8;
    684 	vm->hblank_stop *= 8;
    685 	vm->hsync_start *= 8;
    686 	vm->hsync_stop *= 8;
    687 	vm->htotal *= 8;
    688 
    689 	return (0);
    690 }
    691 
    692 
    693 int
    694 cv_setvmode(gp, mode)
    695 	struct grf_softc *gp;
    696 	unsigned mode;
    697 {
    698 
    699 	if (!mode || (mode > monitor_def_max) ||
    700 	    monitor_def[mode - 1].mode_num == 0)
    701 		return (EINVAL);
    702 
    703 	monitor_current = monitor_def + (mode - 1);
    704 
    705 	return (0);
    706 }
    707 
    708 
    709 int
    710 cv_blank(gp, on)
    711 	struct grf_softc *gp;
    712 	int *on;
    713 {
    714 	volatile caddr_t ba;
    715 
    716 	ba = gp->g_regkva;
    717 	gfx_on_off(*on ? 0 : 1, ba);
    718 	return (0);
    719 }
    720 
    721 
    722 /*
    723  * Change the mode of the display.
    724  * Return a UNIX error number or 0 for success.
    725  */
    726 int
    727 cv_mode(gp, cmd, arg, a2, a3)
    728 	register struct grf_softc *gp;
    729 	int cmd;
    730 	void *arg;
    731 	int a2, a3;
    732 {
    733 	int error;
    734 
    735 	switch (cmd) {
    736 	case GM_GRFON:
    737 		error = cv_load_mon (gp,
    738 		    (struct grfcvtext_mode *) monitor_current) ? 0 : EINVAL;
    739 		return (error);
    740 
    741 	case GM_GRFOFF:
    742 #ifndef CV64CONSOLE
    743 		(void)cv_toggle(gp);
    744 #else
    745 		cv_load_mon(gp, &cvconsole_mode);
    746 		ite_reinit(gp->g_itedev);
    747 #endif
    748 		return (0);
    749 
    750 	case GM_GRFCONFIG:
    751 		return (0);
    752 
    753 	case GM_GRFGETVMODE:
    754 		return (cv_getvmode (gp, (struct grfvideo_mode *) arg));
    755 
    756 	case GM_GRFSETVMODE:
    757 		error = cv_setvmode (gp, *(unsigned *) arg);
    758 		if (!error && (gp->g_flags & GF_GRFON))
    759 			cv_load_mon(gp,
    760 			    (struct grfcvtext_mode *) monitor_current);
    761 		return (error);
    762 
    763 	case GM_GRFGETNUMVM:
    764 		*(int *)arg = monitor_def_max;
    765 		return (0);
    766 
    767 	case GM_GRFIOCTL:
    768 		return (cv_ioctl (gp, (int) arg, (caddr_t) a2));
    769 
    770 	default:
    771 		break;
    772 	}
    773 
    774 	return (EINVAL);
    775 }
    776 
    777 int
    778 cv_ioctl (gp, cmd, data)
    779 	register struct grf_softc *gp;
    780 	int cmd;
    781 	void *data;
    782 {
    783 	switch (cmd) {
    784 	case GRFIOCGSPRITEPOS:
    785 	case GRFIOCSSPRITEPOS:
    786 	case GRFIOCSSPRITEINF:
    787 	case GRFIOCGSPRITEINF:
    788 	case GRFIOCGSPRITEMAX:
    789 		break;
    790 
    791 	case GRFIOCGETCMAP:
    792 		return (cv_getcmap (gp, (struct grf_colormap *) data));
    793 
    794 	case GRFIOCPUTCMAP:
    795 		return (cv_putcmap (gp, (struct grf_colormap *) data));
    796 
    797 	case GRFIOCBITBLT:
    798 		break;
    799 
    800 	case GRFTOGGLE:
    801 		return (cv_toggle (gp));
    802 
    803 	case GRFIOCSETMON:
    804 		return (cv_setmonitor (gp, (struct grfvideo_mode *)data));
    805 
    806 	case GRFIOCBLANK:
    807 		return (cv_blank (gp, (int *)data));
    808 	}
    809 	return (EINVAL);
    810 }
    811 
    812 int
    813 cv_setmonitor(gp, gv)
    814 	struct grf_softc *gp;
    815 	struct grfvideo_mode *gv;
    816 {
    817 	struct grfvideo_mode *md;
    818 
    819 	if (!cv_mondefok(gv))
    820 		return (EINVAL);
    821 
    822 #ifdef CV64CONSOLE
    823 	/* handle interactive setting of console mode */
    824 	if (gv->mode_num == 255) {
    825 		bcopy(gv, &cvconsole_mode.gv, sizeof(struct grfvideo_mode));
    826 		cvconsole_mode.gv.hblank_start /= 8;
    827 		cvconsole_mode.gv.hblank_stop /= 8;
    828 		cvconsole_mode.gv.hsync_start /= 8;
    829 		cvconsole_mode.gv.hsync_stop /= 8;
    830 		cvconsole_mode.gv.htotal /= 8;
    831 		cvconsole_mode.rows = gv->disp_height / cvconsole_mode.fy;
    832 		cvconsole_mode.cols = gv->disp_width / cvconsole_mode.fx;
    833 		if (!(gp->g_flags & GF_GRFON))
    834 			cv_load_mon(gp, &cvconsole_mode);
    835 		ite_reinit(gp->g_itedev);
    836 		return (0);
    837 	}
    838 #endif
    839 
    840 	md = monitor_def + (gv->mode_num - 1);
    841 	bcopy(gv, md, sizeof(struct grfvideo_mode));
    842 
    843 	/* adjust pixel oriented values to internal rep. */
    844 
    845 	md->hblank_start /= 8;
    846 	md->hblank_stop /= 8;
    847 	md->hsync_start /= 8;
    848 	md->hsync_stop /= 8;
    849 	md->htotal /= 8;
    850 
    851 	return (0);
    852 }
    853 
    854 int
    855 cv_getcmap(gfp, cmap)
    856 	struct grf_softc *gfp;
    857 	struct grf_colormap *cmap;
    858 {
    859 	volatile caddr_t ba;
    860 	u_char red[256], green[256], blue[256], *rp, *gp, *bp;
    861 	short x;
    862 	int error;
    863 
    864 	ba = gfp->g_regkva;
    865 	if (cmap->count == 0 || cmap->index >= 256)
    866 		return (0);
    867 
    868 	if (cmap->index + cmap->count > 256)
    869 		cmap->count = 256 - cmap->index;
    870 
    871 	/* first read colors out of the chip, then copyout to userspace */
    872 	vgaw (ba, VDAC_ADDRESS_W, cmap->index);
    873 	x = cmap->count - 1;
    874 
    875 	rp = red + cmap->index;
    876 	gp = green + cmap->index;
    877 	bp = blue + cmap->index;
    878 
    879 	do {
    880 		*rp++ = vgar (ba, VDAC_DATA) << 2;
    881 		*gp++ = vgar (ba, VDAC_DATA) << 2;
    882 		*bp++ = vgar (ba, VDAC_DATA) << 2;
    883 	} while (x-- > 0);
    884 
    885 	if (!(error = copyout (red + cmap->index, cmap->red, cmap->count))
    886 	    && !(error = copyout (green + cmap->index, cmap->green, cmap->count))
    887 	    && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count)))
    888 		return (0);
    889 
    890 	return (error);
    891 }
    892 
    893 int
    894 cv_putcmap(gfp, cmap)
    895 	struct grf_softc *gfp;
    896 	struct grf_colormap *cmap;
    897 {
    898 	volatile caddr_t ba;
    899 	u_char red[256], green[256], blue[256], *rp, *gp, *bp;
    900 	short x;
    901 	int error;
    902 
    903 	ba = gfp->g_regkva;
    904 	if (cmap->count == 0 || cmap->index >= 256)
    905 		return (0);
    906 
    907 	if (cmap->index + cmap->count > 256)
    908 		cmap->count = 256 - cmap->index;
    909 
    910 	/* first copy the colors into kernelspace */
    911 	if (!(error = copyin (cmap->red, red + cmap->index, cmap->count))
    912 	    && !(error = copyin (cmap->green, green + cmap->index, cmap->count))
    913 	    && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count))) {
    914 		vgaw (ba, VDAC_ADDRESS_W, cmap->index);
    915 		x = cmap->count - 1;
    916 
    917 		rp = red + cmap->index;
    918 		gp = green + cmap->index;
    919 		bp = blue + cmap->index;
    920 
    921 		do {
    922 			vgaw (ba, VDAC_DATA, *rp++ >> 2);
    923 			vgaw (ba, VDAC_DATA, *gp++ >> 2);
    924 			vgaw (ba, VDAC_DATA, *bp++ >> 2);
    925 		} while (x-- > 0);
    926 		return (0);
    927 	} else
    928 		return (error);
    929 }
    930 
    931 
    932 int
    933 cv_toggle(gp)
    934 	struct grf_softc *gp;
    935 {
    936 	volatile caddr_t ba;
    937 
    938 	ba = gp->g_regkva;
    939 	cvscreen(1, ba - 0x02000000);
    940 
    941 	return (0);
    942 }
    943 
    944 
    945 int
    946 cv_mondefok(gv)
    947 	struct grfvideo_mode *gv;
    948 {
    949 	unsigned long maxpix;
    950 	int widthok = 0;
    951 
    952 	if (gv->mode_num < 1 || gv->mode_num > monitor_def_max) {
    953 		if (gv->mode_num != 255 || (gv->depth != 4 && gv->depth != 8))
    954 			return (0);
    955 		else
    956 			/*
    957 			 * We have 8 bit console modes. This _is_
    958 			 * a hack but necessary to be compatible.
    959 			 */
    960 			gv->depth = 8;
    961 	}
    962 
    963 	switch(gv->depth) {
    964 	   case 1:
    965 	   case 4:
    966 		return (0);
    967 	   case 8:
    968 		maxpix = MAXPIXELCLOCK;
    969 		break;
    970 	   case 15:
    971 	   case 16:
    972 #ifdef CV_AGGRESSIVE_TIMING
    973 		maxpix = MAXPIXELCLOCK - 35000000;
    974 #else
    975 		maxpix = MAXPIXELCLOCK - 55000000;
    976 #endif
    977 		break;
    978 	   case 24:
    979 	   case 32:
    980 #ifdef CV_AGGRESSIVE_TIMING
    981 		maxpix = MAXPIXELCLOCK - 75000000;
    982 #else
    983 		maxpix = MAXPIXELCLOCK - 85000000;
    984 #endif
    985 		break;
    986 	   default:
    987 		return (0);
    988 	}
    989 
    990 	if (gv->pixel_clock > maxpix)
    991 		return (0);
    992 
    993 	/*
    994 	 * These are the supported witdh values for the
    995 	 * graphics engine. To Support other widths, one
    996 	 * has to use one of these widths for memory alignment, i.e.
    997 	 * one has to set CRT_ID_SCREEN_OFFSET to one of these values and
    998 	 * CRT_ID_HOR_DISP_ENA_END to the desired width.
    999 	 * Since a working graphics engine is essential
   1000 	 * for the console, console modes of other width are not supported.
   1001 	 * We could do that, though, but then you have to tell the Xserver
   1002 	 * about this strange configuration and I don't know how at the moment :-)
   1003 	 */
   1004 
   1005 	switch (gv->disp_width) {
   1006 	    case 1024:
   1007 	    case 640:
   1008 	    case 800:
   1009 	    case 1280:
   1010 	    case 1152:
   1011 	    case 1600:
   1012 		widthok = 1;
   1013 		break;
   1014 	    default: /* XXX*/
   1015 		widthok = 0;
   1016 		break;
   1017 	}
   1018 
   1019 	if (widthok) return (1);
   1020 	else {
   1021 		if (gv->mode_num == 255) { /* console mode */
   1022 			printf ("This display width is not supported by the CV64 console.\n");
   1023 			printf ("Use one of 640 800 1024 1152 1280 1600!\n");
   1024 			return (0);
   1025 		} else {
   1026 			printf ("Warning for mode %d:\n", (int) gv->mode_num);
   1027 			printf ("Don't use a blitter-suporting Xserver with this display width\n");
   1028 			printf ("Use one of 640 800 1024 1152 1280 1600!\n");
   1029 			return (1);
   1030 		}
   1031 	}
   1032 	return (1);
   1033 }
   1034 
   1035 int
   1036 cv_load_mon(gp, md)
   1037 	struct grf_softc *gp;
   1038 	struct grfcvtext_mode *md;
   1039 {
   1040 	struct grfvideo_mode *gv;
   1041 	struct grfinfo *gi;
   1042 	volatile caddr_t ba, fb;
   1043 	unsigned short mnr;
   1044 	unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
   1045 		VSE, VT;
   1046 	char LACE, DBLSCAN, TEXT, CONSOLE;
   1047 	int uplim, lowlim;
   1048 	int cr50, cr33, sr15, sr18, clock_mode, test;
   1049 	int m, n;	/* For calc'ing display FIFO */
   1050 	int tfillm, temptym;	/* FIFO fill and empty mclk's */
   1051 	int hmul;	/* Multiplier for hor. Values */
   1052 	/* identity */
   1053 	gv = &md->gv;
   1054 
   1055 	/*
   1056 	 * No way to get text modes to work.
   1057 	 * Blame phase5, not me!
   1058 	 */
   1059 	TEXT = 0; /* (gv->depth == 4); */
   1060 	CONSOLE = (gv->mode_num == 255);
   1061 
   1062 	if (!cv_mondefok(gv)) {
   1063 		printf("grfcv: The monitor definition is not okay.\n");
   1064 		printf("grfcv: See the manpage of grfconfig for more informations\n");
   1065 		return (0);
   1066 	}
   1067 	ba = gp->g_regkva;
   1068 	fb = gp->g_fbkva;
   1069 
   1070 	/* turn gfx off, don't mess up the display */
   1071 	gfx_on_off(1, ba);
   1072 
   1073 	/* provide all needed information in grf device-independant locations */
   1074 	gp->g_data		= (caddr_t) gv;
   1075 	gi = &gp->g_display;
   1076 	gi->gd_colors		= 1 << gv->depth;
   1077 	gi->gd_planes		= gv->depth;
   1078 	gi->gd_fbwidth		= gv->disp_width;
   1079 	gi->gd_fbheight		= gv->disp_height;
   1080 	gi->gd_fbx		= 0;
   1081 	gi->gd_fby		= 0;
   1082 	if (CONSOLE) {
   1083 		gi->gd_dwidth	= md->fx * md->cols;
   1084 		gi->gd_dheight	= md->fy * md->rows;
   1085 	} else {
   1086 		gi->gd_dwidth	= gv->disp_width;
   1087 		gi->gd_dheight	= gv->disp_height;
   1088 	}
   1089 	gi->gd_dx		= 0;
   1090 	gi->gd_dy		= 0;
   1091 
   1092 	/* get display mode parameters */
   1093 	switch (gv->depth) {
   1094 		case 15:
   1095 		case 16:
   1096 			hmul = 2;
   1097 			break;
   1098 		default:
   1099 			hmul = 1;
   1100         		break;
   1101 	}
   1102 
   1103 	HBS = gv->hblank_start * hmul;
   1104 	HBE = gv->hblank_stop * hmul;
   1105 	HSS = gv->hsync_start * hmul;
   1106 	HSE = gv->hsync_stop * hmul;
   1107 	HT  = gv->htotal*hmul - 5;
   1108 	VBS = gv->vblank_start - 1;
   1109 	VSS = gv->vsync_start;
   1110 	VSE = gv->vsync_stop;
   1111 	VBE = gv->vblank_stop;
   1112 	VT  = gv->vtotal - 2;
   1113 
   1114 	if (TEXT)
   1115 		HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
   1116 	else
   1117 		HDE = (gv->disp_width + 3) * hmul / 8 - 1; /*HBS;*/
   1118 	VDE = gv->disp_height - 1;
   1119 
   1120 	/* figure out whether lace or dblscan is needed */
   1121 
   1122 	uplim = gv->disp_height + (gv->disp_height / 4);
   1123 	lowlim = gv->disp_height - (gv->disp_height / 4);
   1124 	LACE = (((VT * 2) > lowlim) && ((VT * 2) < uplim)) ? 1 : 0;
   1125 	DBLSCAN = (((VT / 2) > lowlim) && ((VT / 2) < uplim)) ? 1 : 0;
   1126 
   1127 	/* adjustments */
   1128 
   1129 	if (LACE)
   1130 		VDE /= 2;
   1131 
   1132 	WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
   1133 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
   1134 	WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
   1135 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
   1136 
   1137 	/* Set clock */
   1138 
   1139 	mnr = compute_clock(gv->pixel_clock);
   1140 	WSeq(ba, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8) );
   1141 	WSeq(ba, SEQ_ID_DCLK_LO, (mnr & 0xFF));
   1142 
   1143 	/* load display parameters into board */
   1144 
   1145 	WCrt(ba, CRT_ID_EXT_HOR_OVF,
   1146 	   ((HT & 0x100) ? 0x01 : 0x00) |
   1147 	   ((HDE & 0x100) ? 0x02 : 0x00) |
   1148 	   ((HBS & 0x100) ? 0x04 : 0x00) |
   1149 	/* ((HBE & 0x40) ? 0x08 : 0x00) | */  /* Later... */
   1150 	   ((HSS & 0x100) ? 0x10 : 0x00) |
   1151 	/* ((HSE & 0x20) ? 0x20 : 0x00) | */
   1152 	   (((HT-5) & 0x100) ? 0x40 : 0x00) );
   1153 
   1154 	WCrt(ba, CRT_ID_EXT_VER_OVF,
   1155 	    0x40 |	/* Line compare */
   1156 	    ((VT  & 0x400) ? 0x01 : 0x00) |
   1157 	    ((VDE & 0x400) ? 0x02 : 0x00) |
   1158 	    ((VBS & 0x400) ? 0x04 : 0x00) |
   1159 	    ((VSS & 0x400) ? 0x10 : 0x00) );
   1160 
   1161 	WCrt(ba, CRT_ID_HOR_TOTAL, HT);
   1162 	WCrt(ba, CRT_ID_DISPLAY_FIFO, HT - 5);
   1163 
   1164 	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
   1165 	WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
   1166 	WCrt(ba, CRT_ID_END_HOR_BLANK, ((HBE & 0x1f) | 0x80));
   1167 	WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
   1168 	WCrt(ba, CRT_ID_END_HOR_RETR,
   1169 	    (HSE & 0x1f) |
   1170 	    ((HBE & 0x20) ? 0x80 : 0x00) );
   1171 	WCrt(ba, CRT_ID_VER_TOTAL, VT);
   1172 	WCrt(ba, CRT_ID_OVERFLOW,
   1173 	    0x10 |
   1174 	    ((VT  & 0x100) ? 0x01 : 0x00) |
   1175 	    ((VDE & 0x100) ? 0x02 : 0x00) |
   1176 	    ((VSS & 0x100) ? 0x04 : 0x00) |
   1177 	    ((VBS & 0x100) ? 0x08 : 0x00) |
   1178 	    ((VT  & 0x200) ? 0x20 : 0x00) |
   1179 	    ((VDE & 0x200) ? 0x40 : 0x00) |
   1180 	    ((VSS & 0x200) ? 0x80 : 0x00) );
   1181 
   1182 	WCrt(ba, CRT_ID_MAX_SCAN_LINE,
   1183 	    0x40 |  /* TEXT ? 0x00 ??? */
   1184 	    (DBLSCAN ? 0x80 : 0x00) |
   1185 	    ((VBS & 0x200) ? 0x20 : 0x00) |
   1186 	    (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
   1187 
   1188 	WCrt(ba, CRT_ID_MODE_CONTROL,
   1189 	    ((TEXT || (gv->depth == 1)) ? 0xc3 : 0xe3));
   1190 
   1191 	/* text cursor */
   1192 
   1193 	if (TEXT) {
   1194 #if 1
   1195 		WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
   1196 		WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
   1197 #else
   1198 		WCrt(ba, CRT_ID_CURSOR_START, 0x00);
   1199 		WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
   1200 #endif
   1201 		WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f);
   1202 
   1203 		WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
   1204 		WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
   1205 	}
   1206 
   1207 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
   1208 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
   1209 
   1210 	WCrt(ba, CRT_ID_START_VER_RETR, VSS);
   1211 	WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f));
   1212 	WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
   1213 	WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
   1214 	WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
   1215 
   1216 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
   1217 	WCrt(ba, CRT_ID_LACE_RETR_START, HT / 2);
   1218 	WCrt(ba, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
   1219 
   1220 	WGfx(ba, GCT_ID_GRAPHICS_MODE,
   1221 	    ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
   1222 	WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
   1223 
   1224 	WSeq (ba, SEQ_ID_MEMORY_MODE,
   1225 	    ((TEXT || (gv->depth == 1)) ? 0x06 : 0x02));
   1226 
   1227 	vgaw(ba, VDAC_MASK, 0xff);
   1228 
   1229 	sr15 = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);
   1230 	sr15 &= 0xef;
   1231 	sr18 = RSeq(ba, SEQ_ID_RAMDAC_CNTL);
   1232 	sr18 &= 0x7f;
   1233 	cr33 = RCrt(ba, CRT_ID_BACKWAD_COMP_2);
   1234 	cr33 &= 0xdf;
   1235 	clock_mode = 0x00;
   1236 	cr50 = 0x00;
   1237 
   1238 	test = RCrt(ba, CRT_ID_EXT_MISC_CNTL_2);
   1239 	test &= 0xd;
   1240 
   1241 	/* clear roxxler  byte-swapping... */
   1242 	cv_write_port(0x0040, cv_boardaddr);
   1243 	cv_write_port(0x0020, cv_boardaddr);
   1244 
   1245 	switch (gv->depth) {
   1246 	   case 1:
   1247 	   case 4: /* text */
   1248 		HDE = gv->disp_width / 16;
   1249 		break;
   1250 	   case 8:
   1251 		if (gv->pixel_clock > 80000000) {
   1252 			clock_mode = 0x10 | 0x02;
   1253 			sr15 |= 0x10;
   1254 			sr18 |= 0x80;
   1255 			cr33 |= 0x20;
   1256 		}
   1257 		HDE = gv->disp_width / 8;
   1258 		cr50 |= 0x00;
   1259 		break;
   1260 	   case 15:
   1261 		cv_write_port (0x8020, cv_boardaddr);
   1262 		clock_mode = 0x30;
   1263 		HDE = gv->disp_width / 4;
   1264 		cr50 |= 0x10;
   1265 		break;
   1266 	   case 16:
   1267 		cv_write_port (0x8020, cv_boardaddr);
   1268 		clock_mode = 0x50;
   1269 		HDE = gv->disp_width / 4;
   1270 		cr50 |= 0x10;
   1271 		break;
   1272 	   case 24: /* this is really 32 Bit on CV64 */
   1273 	   case 32:
   1274 		cv_write_port(0x8040, cv_boardaddr);
   1275 		clock_mode = 0xd0;
   1276 		HDE = (gv->disp_width / 2);
   1277 		cr50 |= 0x30;
   1278 		break;
   1279 	}
   1280 
   1281 	WCrt(ba, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
   1282 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, sr15);
   1283 	WSeq(ba, SEQ_ID_RAMDAC_CNTL, sr18);
   1284 	WCrt(ba, CRT_ID_BACKWAD_COMP_2, cr33);
   1285 	WCrt(ba, CRT_ID_SCREEN_OFFSET, HDE);
   1286 
   1287 	test = RCrt(ba, CRT_ID_EXT_SYS_CNTL_2);
   1288 	test &= ~0x30;
   1289 	/* HDE Overflow in bits 4-5 */
   1290 	test |= (HDE >> 4) & 0x30;
   1291 	WCrt(ba, CRT_ID_EXT_SYS_CNTL_2, test);
   1292 
   1293 	/* Set up graphics engine */
   1294 	switch (gv->disp_width) {
   1295 	   case 1024:
   1296 		cr50 |= 0x00;
   1297 		break;
   1298 	   case 640:
   1299 		cr50 |= 0x40;
   1300 		break;
   1301 	   case 800:
   1302 		cr50 |= 0x80;
   1303 		break;
   1304 	   case 1280:
   1305 		cr50 |= 0xc0;
   1306 		break;
   1307 	   case 1152:
   1308 		cr50 |= 0x01;
   1309 		break;
   1310 	   case 1600:
   1311 		cr50 |= 0x81;
   1312 		break;
   1313 	   default: /* XXX*/
   1314 		break;
   1315 	}
   1316 
   1317 	WCrt(ba, CRT_ID_EXT_SYS_CNTL_1, cr50);
   1318 
   1319 	delay(100000);
   1320 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x0a : 0x41));
   1321 	delay(100000);
   1322 	WAttr(ba, ACT_ID_COLOR_PLANE_ENA,
   1323 	    (gv->depth == 1) ? 0x01 : 0x0f);
   1324 	delay(100000);
   1325 
   1326 	/*
   1327 	 * M-Parameter of Display FIFO
   1328 	 * This is dependant on the pixel clock and the memory clock.
   1329 	 * The FIFO filling bandwidth is 240 MHz  and the FIFO is 96 Byte wide.
   1330 	 * Then the time to fill the FIFO is tfill = (96/240000000) sec, the time
   1331 	 * to empty the FIFO is tempty = (96/pixelclock) sec.
   1332 	 * Then the M parameter maximum is ((tempty-tfill)*cv_memclk-9)/2.
   1333 	 * This seems to be logical, ain't it?
   1334 	 * Remember: We have to use integer arithmetics :(
   1335 	 * Divide by 1000 to prevent overflows.
   1336 	 */
   1337 
   1338 	tfillm = (96 * (cv_memclk/1000))/240000;
   1339 
   1340 	switch(gv->depth) {
   1341 	   case 32:
   1342 	   case 24:
   1343 		temptym = (24 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
   1344 		break;
   1345 	   case 15:
   1346 	   case 16:
   1347 		temptym = (48 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
   1348 		break;
   1349 	   default:
   1350 		temptym = (96 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
   1351 		break;
   1352 	}
   1353 
   1354 	m = (temptym - tfillm - 9) / 2;
   1355 	m = (m & 0x1f) << 3;
   1356 	if (m < 0x18)
   1357 		m = 0x18;
   1358 	n = 0xff;
   1359 
   1360 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, m);
   1361 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, n);
   1362 	delay(10000);
   1363 
   1364 	/* text initialization */
   1365 
   1366 	if (TEXT) {
   1367 		cv_inittextmode(gp);
   1368 	}
   1369 
   1370 	if (CONSOLE) {
   1371 		int i;
   1372 		vgaw(ba, VDAC_ADDRESS_W, 0);
   1373 		for (i = 0; i < 4; i++) {
   1374 			vgaw(ba, VDAC_DATA, cvconscolors[i][0]);
   1375 			vgaw(ba, VDAC_DATA, cvconscolors[i][1]);
   1376 			vgaw(ba, VDAC_DATA, cvconscolors[i][2]);
   1377 		}
   1378 	}
   1379 
   1380 	/* Some kind of Magic */
   1381 	WAttr(ba, 0x33, 0);
   1382 
   1383 	/* turn gfx on again */
   1384 	gfx_on_off(0, ba);
   1385 
   1386 	/* Pass-through */
   1387 	cvscreen(0, ba - 0x02000000);
   1388 
   1389 	return (1);
   1390 }
   1391 
   1392 void
   1393 cv_inittextmode(gp)
   1394 	struct grf_softc *gp;
   1395 {
   1396 	struct grfcvtext_mode *tm = (struct grfcvtext_mode *)gp->g_data;
   1397 	volatile caddr_t ba, fb;
   1398 	unsigned char *c, *f, y;
   1399 	unsigned short z;
   1400 
   1401 	ba = gp->g_regkva;
   1402 	fb = gp->g_fbkva;
   1403 
   1404 	/* load text font into beginning of display memory.
   1405 	 * Each character cell is 32 bytes long (enough for 4 planes)
   1406 	 */
   1407 
   1408 	SetTextPlane(ba, 0x02);
   1409 	cv_memset(fb, 0, 256 * 32);
   1410 	c = (unsigned char *) (fb) + (32 * tm->fdstart);
   1411 	f = tm->fdata;
   1412 	for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy))
   1413 		for (y = 0; y < tm->fy; y++)
   1414 			*c++ = *f++;
   1415 
   1416 	/* clear out text/attr planes (three screens worth) */
   1417 
   1418 	SetTextPlane(ba, 0x01);
   1419 	cv_memset(fb, 0x07, tm->cols * tm->rows * 3);
   1420 	SetTextPlane(ba, 0x00);
   1421 	cv_memset(fb, 0x20, tm->cols * tm->rows * 3);
   1422 
   1423 	/* print out a little init msg */
   1424 
   1425 	c = (unsigned char *)(fb) + (tm->cols-16);
   1426 	strcpy(c, "CV64");
   1427 	c[6] = 0x20;
   1428 
   1429 	/* set colors (B&W) */
   1430 
   1431 	vgaw(ba, VDAC_ADDRESS_W, 0);
   1432 	for (z=0; z<256; z++) {
   1433 		unsigned char r, g, b;
   1434 
   1435 		y = (z & 1) ? ((z > 7) ? 2 : 1) : 0;
   1436 
   1437 		r = cvconscolors[y][0];
   1438 		g = cvconscolors[y][1];
   1439 		b = cvconscolors[y][2];
   1440 		vgaw(ba, VDAC_DATA, r >> 2);
   1441 		vgaw(ba, VDAC_DATA, g >> 2);
   1442 		vgaw(ba, VDAC_DATA, b >> 2);
   1443 	}
   1444 }
   1445 
   1446 void
   1447 cv_memset(d, c, l)
   1448 	unsigned char *d;
   1449 	unsigned char c;
   1450 	int l;
   1451 {
   1452 	for(; l > 0; l--)
   1453 		*d++ = c;
   1454 }
   1455 
   1456 
   1457 static inline void
   1458 cv_write_port(bits, BoardAddr)
   1459 	unsigned short bits;
   1460 	volatile caddr_t BoardAddr;
   1461 {
   1462 	volatile caddr_t addr;
   1463 	static unsigned char CVPortBits = 0;	/* mirror port bits here */
   1464 
   1465 	addr = BoardAddr + 0x40001;
   1466 	if (bits & 0x8000)
   1467 		CVPortBits |= bits & 0xFF;	/* Set bits */
   1468 	else {
   1469 		bits = bits & 0xFF;
   1470 		bits = (~bits) & 0xFF ;
   1471 		CVPortBits &= bits;	/* Clear bits */
   1472 	}
   1473 
   1474 	*addr = CVPortBits;
   1475 }
   1476 
   1477 
   1478 /*
   1479  *  Monitor Switch
   1480  *  0 = CyberVision Signal
   1481  *  1 = Amiga Signal,
   1482  * ba = boardaddr
   1483  */
   1484 static inline void
   1485 cvscreen(toggle, ba)
   1486 	int toggle;
   1487 	volatile caddr_t ba;
   1488 {
   1489 
   1490 	if (toggle == 1)
   1491 		cv_write_port (0x10, ba);
   1492 	else
   1493 		cv_write_port (0x8010, ba);
   1494 }
   1495 
   1496 /* 0 = on, 1= off */
   1497 /* ba= registerbase */
   1498 static inline void
   1499 gfx_on_off(toggle, ba)
   1500 	int toggle;
   1501 	volatile caddr_t ba;
   1502 {
   1503 	int r;
   1504 
   1505 	toggle &= 0x1;
   1506 	toggle = toggle << 5;
   1507 
   1508 	r = RSeq(ba, SEQ_ID_CLOCKING_MODE);
   1509 	r &= 0xdf;	/* set Bit 5 to 0 */
   1510 
   1511 	WSeq(ba, SEQ_ID_CLOCKING_MODE, r | toggle);
   1512 }
   1513 
   1514 #endif  /* NGRFCV */
   1515