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