Home | History | Annotate | Line # | Download | only in dev
grf_cv.c revision 1.39
      1 /*	$NetBSD: grf_cv.c,v 1.39 2005/12/11 12:16:28 christos 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, Michael Teske 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 "opt_amigacons.h"
     34 
     35 #include <sys/cdefs.h>
     36 __KERNEL_RCSID(0, "$NetBSD: grf_cv.c,v 1.39 2005/12/11 12:16:28 christos Exp $");
     37 
     38 #include "grfcv.h"
     39 #if NGRFCV > 0
     40 
     41 /*
     42  * Graphics routines for the CyberVision 64 board, using the S3 Trio64.
     43  *
     44  * Modified for CV64 from
     45  * Kari Mettinen's Cirrus driver by Michael Teske 10/95
     46  *
     47  * Thanks to Tekelec Airtronic for providing me with a S3 Trio64 documentation.
     48  * Thanks to Bernd 'the fabulous bug-finder' Ernesti for bringing my messy
     49  * source to NetBSD style :)
     50  * Thanks to Harald Koenig for providing information about undocumented
     51  * Trio64 Bugs.
     52  */
     53 
     54 #include <sys/param.h>
     55 #include <sys/errno.h>
     56 #include <sys/ioctl.h>
     57 #include <sys/device.h>
     58 #include <sys/malloc.h>
     59 #include <sys/systm.h>
     60 #include <sys/syslog.h>
     61 #include <machine/cpu.h>
     62 #include <dev/cons.h>
     63 #include <amiga/dev/itevar.h>
     64 #include <amiga/amiga/device.h>
     65 #include <amiga/amiga/isr.h>
     66 #include <amiga/dev/grfioctl.h>
     67 #include <amiga/dev/grfvar.h>
     68 #include <amiga/dev/grf_cvreg.h>
     69 #include <amiga/dev/zbusvar.h>
     70 
     71 int	grfcvmatch(struct device *, struct cfdata *, void *);
     72 void	grfcvattach(struct device *, struct device *, void *);
     73 int	grfcvprint(void *, const char *);
     74 
     75 int	cvintr(void *);
     76 static int cv_has_4mb(volatile caddr_t);
     77 static unsigned short cv_compute_clock(unsigned long);
     78 void	cv_boardinit(struct grf_softc *);
     79 int	cv_getvmode(struct grf_softc *, struct grfvideo_mode *);
     80 int	cv_setvmode(struct grf_softc *, unsigned int);
     81 int	cv_blank(struct grf_softc *, int *);
     82 int	cv_mode(register struct grf_softc *, u_long, void *, u_long, int);
     83 int	cv_ioctl(register struct grf_softc *gp, u_long cmd, void *data);
     84 int	cv_setmonitor(struct grf_softc *, struct grfvideo_mode *);
     85 int	cv_getcmap(struct grf_softc *, struct grf_colormap *);
     86 int	cv_putcmap(struct grf_softc *, struct grf_colormap *);
     87 int	cv_toggle(struct grf_softc *);
     88 int	cv_mondefok(struct grfvideo_mode *);
     89 int	cv_load_mon(struct grf_softc *, struct grfcvtext_mode *);
     90 void	cv_inittextmode(struct grf_softc *);
     91 static	__inline void cv_write_port(unsigned short, volatile caddr_t);
     92 static	__inline void cvscreen(int, volatile caddr_t);
     93 static	__inline void gfx_on_off(int, volatile caddr_t);
     94 
     95 #ifndef CV_NO_HARDWARE_CURSOR
     96 int	cv_getspritepos(struct grf_softc *, struct grf_position *);
     97 int	cv_setspritepos(struct grf_softc *, struct grf_position *);
     98 int	cv_getspriteinfo(struct grf_softc *,struct grf_spriteinfo *);
     99 void	cv_setup_hwc(struct grf_softc *);
    100 int	cv_setspriteinfo(struct grf_softc *,struct grf_spriteinfo *);
    101 int	cv_getspritemax(struct grf_softc *,struct grf_position *);
    102 #endif	/* !CV_NO_HARDWARE_CURSOR */
    103 
    104 /*
    105  * Extension to grf_softc for interrupt support
    106  */
    107 
    108 struct grf_cv_softc {
    109 	struct grf_softc	gcs_sc;
    110 	struct isr		gcs_isr;
    111 };
    112 
    113 /* Graphics display definitions.
    114  * These are filled by 'grfconfig' using GRFIOCSETMON.
    115  */
    116 #define monitor_def_max 24
    117 static struct grfvideo_mode monitor_def[24] = {
    118 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
    119 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
    120 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}
    121 };
    122 static struct grfvideo_mode *monitor_current = &monitor_def[0];
    123 #define MAXPIXELCLOCK 135000000 /* safety */
    124 
    125 unsigned char cv_pass_toggle;	/* passthru status tracker */
    126 
    127 /* Console display definition.
    128  *   Default hardcoded text mode.  This grf_cv is set up to
    129  *   use one text mode only, and this is it.  You may use
    130  *   grfconfig to change the mode after boot.
    131  */
    132 
    133 /* Console font */
    134 #ifdef KFONT_8X11
    135 #define S3FONT kernel_font_8x11
    136 #define S3FONTY 11
    137 #else
    138 #define S3FONT kernel_font_8x8
    139 #define S3FONTY 8
    140 #endif
    141 extern unsigned char S3FONT[];
    142 
    143 /*
    144  * Define default console mode
    145  * (Internally, we still have to use hvalues/8!)
    146  */
    147 struct grfcvtext_mode cvconsole_mode = {
    148 	{255, "", 25000000, 640, 480, 4, 640/8, 680/8, 768/8, 800/8,
    149 	 481, 491, 493, 525, 0},
    150 	8, S3FONTY, 80, 480 / S3FONTY, S3FONT, 32, 255
    151 };
    152 
    153 /* Console colors */
    154 unsigned char cvconscolors[16][3] = {	/* background, foreground, hilite */
    155 	/*  R     G     B  */
    156 	{0x30, 0x30, 0x30},
    157 	{0x00, 0x00, 0x00},
    158 	{0x80, 0x00, 0x00},
    159 	{0x00, 0x80, 0x00},
    160 	{0x00, 0x00, 0x80},
    161 	{0x80, 0x80, 0x00},
    162 	{0x00, 0x80, 0x80},
    163 	{0x80, 0x00, 0x80},
    164 	{0xff, 0xff, 0xff},
    165 	{0x40, 0x40, 0x40},
    166 	{0xff, 0x00, 0x00},
    167 	{0x00, 0xff, 0x00},
    168 	{0x00, 0x00, 0xff},
    169 	{0xff, 0xff, 0x00},
    170 	{0x00, 0xff, 0xff},
    171 	{0x00, 0x00, 0xff}
    172 };
    173 
    174 static unsigned char clocks[]={
    175 0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69,
    176 0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c,
    177 0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a,
    178 0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69,
    179 0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65,
    180 0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63,
    181 0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d,
    182 0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49,
    183 0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42,
    184 0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43,
    185 0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49,
    186 0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a,
    187 0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49,
    188 0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41,
    189 0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43,
    190 0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45,
    191 0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45,
    192 0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45,
    193 0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44,
    194 0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46,
    195 0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f,
    196 0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22,
    197 0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46,
    198 0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b,
    199 0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44,
    200 0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26,
    201 0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b,
    202 0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25,
    203 0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25,
    204 0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21,
    205 0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29,
    206 0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29,
    207 0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29,
    208 0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28,
    209 0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26,
    210 0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21,
    211 0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28,
    212 0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27,
    213 0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22,
    214 0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27,
    215 0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27,
    216 0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21,
    217 0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26,
    218 0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27,
    219 0x13, 0x1,  0x13, 0x1,  0x7d, 0x27, 0x4c, 0x9,
    220 0x37, 0x22, 0x5b, 0xb,  0x71, 0x26, 0x5c, 0xb,
    221 0x6b, 0xd,  0x47, 0x23, 0x14, 0x1,  0x4f, 0x9,
    222 0x23, 0x3,  0x75, 0x26, 0x7d, 0xf,  0x1c, 0x2,
    223 0x51, 0x9,  0x59, 0x24, 0x61, 0xb,  0x69, 0x25,
    224 0x79, 0x26, 0x34, 0x5,  0x1d, 0x2,  0x6b, 0x25,
    225 0x54, 0x9,  0x35, 0x5,  0x45, 0x7,  0x6d, 0x25,
    226 0x7d, 0x26, 0x16, 0x1,  0x7f, 0x26, 0x77, 0xd,
    227 0x4f, 0x23, 0x78, 0xd,  0x2f, 0x21, 0x27, 0x3,
    228 0x1f, 0x2,  0x59, 0x9,  0x6a, 0xb,  0x73, 0x25,
    229 0x6b, 0xb,  0x63, 0x24, 0x5b, 0x9,  0x20, 0x2,
    230 0x7e, 0xd,  0x4b, 0x7,  0x65, 0x24, 0x43, 0x22,
    231 0x18, 0x1,  0x6f, 0xb,  0x5e, 0x9,  0x70, 0xb,
    232 0x2a, 0x3,  0x33, 0x4,  0x45, 0x6,  0x60, 0x9,
    233 0x7b, 0xc,  0x19, 0x1,  0x19, 0x1,  0x7d, 0xc,
    234 0x74, 0xb,  0x50, 0x7,  0x75, 0xb,  0x63, 0x9,
    235 0x51, 0x7,  0x23, 0x2,  0x3f, 0x5,  0x1a, 0x1,
    236 0x65, 0x9,  0x2d, 0x3,  0x40, 0x5,  0x0,  0x0,
    237 };
    238 
    239 
    240 /* Board Address of CV64 */
    241 static volatile caddr_t cv_boardaddr;
    242 static int cv_fbsize;
    243 
    244 /*
    245  * Memory clock (binpatchable).
    246  * Let's be defensive: 50 MHz runs on all boards I know of.
    247  * 55 MHz runs on most boards. But you should know what you're doing
    248  * if you set this flag. Again: This flag may destroy your CV Board.
    249  * Use it at your own risk!!!
    250  * Anyway, this doesn't imply that I'm responsible if your board breaks
    251  * without setting this flag :-).
    252  */
    253 #ifdef CV_AGGRESSIVE_TIMING
    254 long cv_memclk = 55000000;
    255 #else
    256 long cv_memclk = 50000000;
    257 #endif
    258 
    259 /* standard driver stuff */
    260 CFATTACH_DECL(grfcv, sizeof(struct grf_cv_softc),
    261     grfcvmatch, grfcvattach, NULL, NULL);
    262 
    263 static struct cfdata *cfdata;
    264 
    265 #define CV_INT_NUM 6	/* CV interrupt Level: #2 or #6 */
    266 #define CV_ULCURSOR 1	/* Underlined Cursor in textmode */
    267 
    268 #ifndef CV_NO_HARDWARE_CURSOR
    269 
    270 #define HWC_OFF (cv_fbsize - 1024*2)
    271 #define HWC_SIZE 1024
    272 
    273 static unsigned short cv_cursor_storage[HWC_SIZE/2];
    274 static short curs_update_flag = 0;
    275 
    276 #endif	/* !CV_NO_HARDWARE_CURSOR */
    277 
    278 /*
    279  * Interrupt handler
    280  * This is used for updating the cursor shape (because it _must not_
    281  * be changed while cursor is displayed)
    282  * and maybe later to avoid busy waiting
    283  * for Vertical Blank and/or gfx engine busy
    284  */
    285 
    286 int
    287 cvintr(void *arg)
    288 {
    289 #ifndef CV_NO_HARDWARE_CURSOR
    290 	volatile unsigned long *csrc, *cdest;
    291 	int i;
    292 #endif
    293 	struct grf_softc *gp = arg;
    294 	volatile caddr_t ba = gp->g_regkva;
    295 	unsigned char test;
    296 	unsigned char cridx; /* Save the cr Register index */
    297 
    298 	if (gp == NULL)
    299 		return 0;
    300 
    301 	test = vgar(ba, GREG_INPUT_STATUS0_R);
    302 
    303 	if (test & 0x80) { /* VR int pending */
    304 		/* Save old CR index */
    305 		cridx = vgar (ba, CRT_ADDRESS);
    306 
    307 #if 0
    308 		test = RCrt(ba, CRT_ID_END_VER_RETR);
    309 		/* Clear int (bit 4) */
    310 		test &= ~0x10;
    311 		WCrt(ba, CRT_ID_END_VER_RETR, test);
    312 #else
    313 		vgaw(ba, CRT_ADDRESS, CRT_ID_END_VER_RETR);
    314 		__asm __volatile("bclr #4,%0@(0x3d5);nop" : : "a" (ba));
    315 #endif
    316 
    317 #ifndef CV_NO_HARDWARE_CURSOR
    318 		/* update the hardware cursor, if necessary */
    319 		if (curs_update_flag) {
    320 			csrc = (unsigned long *)cv_cursor_storage;
    321 			cdest = (volatile unsigned long *)(gp->g_fbkva +
    322 			    HWC_OFF);
    323 			for (i = 0; i < HWC_SIZE / sizeof(long); i++)
    324 				*cdest++ = *csrc++;
    325 			curs_update_flag = 0;
    326 		}
    327 		/* Reenable int */
    328 #if 0
    329 		test |= 0x10;
    330 		WCrt(ba, CRT_ID_END_VER_RETR, test);
    331 #else
    332 		/* I don't trust the optimizer here... */
    333 		__asm __volatile("bset #4,%0@(0x3d5);nop" : : "a" (ba));
    334 #endif
    335 		cv_setspritepos (gp, NULL);
    336 
    337 		/* Restore the old CR index */
    338 		vgaw(ba, CRT_ADDRESS, cridx);
    339 		__asm __volatile("nop");
    340 #endif  /* !CV_NO_HARDWARE_CURSOR */
    341 		return (1);
    342 	}
    343 	return (0);
    344 }
    345 
    346 /*
    347  * Get frambuffer memory size.
    348  * phase5 didn't provide the bit in CR36,
    349  * so we have to do it this way.
    350  * Return 0 for 2MB, 1 for 4MB
    351  */
    352 static int
    353 cv_has_4mb(volatile caddr_t fb)
    354 {
    355 	volatile unsigned long *testfbw, *testfbr;
    356 
    357 	/* write patterns in memory and test if they can be read */
    358 	testfbw = (volatile unsigned long *)fb;
    359 	testfbr = (volatile unsigned long *)(fb + 0x02000000);
    360 	*testfbw = 0x87654321;
    361 	__asm __volatile("nop");
    362 	if (*testfbr != 0x87654321)
    363 		return (0);
    364 
    365 	/* upper memory region */
    366 	testfbw = (volatile unsigned long *)(fb + 0x00200000);
    367 	testfbr = (volatile unsigned long *)(fb + 0x02200000);
    368 	*testfbw = 0x87654321;
    369 	__asm __volatile("nop");
    370 	if (*testfbr != 0x87654321)
    371 		return (0);
    372 	*testfbw = 0xAAAAAAAA;
    373 	__asm __volatile("nop");
    374 	if (*testfbr != 0xAAAAAAAA)
    375 		return (0);
    376 	*testfbw = 0x55555555;
    377 	__asm __volatile("nop");
    378 	if (*testfbr != 0x55555555)
    379 		return (0);
    380 	return (1);
    381 }
    382 
    383 int
    384 grfcvmatch(struct device *pdp, struct cfdata *cfp, void *auxp)
    385 {
    386 #ifdef CV64CONSOLE
    387 	static int cvcons_unit = -1;
    388 #endif
    389 	struct zbus_args *zap;
    390 
    391 	zap = auxp;
    392 
    393 	if (amiga_realconfig == 0)
    394 #ifdef CV64CONSOLE
    395 		if (cvcons_unit != -1)
    396 #endif
    397 			 return (0);
    398 
    399 	/* Lets be Paranoid: Test man and prod id */
    400 	if (zap->manid != 8512 || zap->prodid != 34)
    401 		return (0);
    402 
    403 	cv_boardaddr = zap->va;
    404 
    405 #ifdef CV64CONSOLE
    406 	if (amiga_realconfig == 0) {
    407 		cvcons_unit = cfp->cf_unit;
    408 		cfdata = cfp;
    409 	}
    410 #endif
    411 
    412 	return (1);
    413 }
    414 
    415 void
    416 grfcvattach(struct device *pdp, struct device *dp, void *auxp)
    417 {
    418 	static struct grf_cv_softc congrf;
    419 	struct zbus_args *zap;
    420 	struct grf_softc *gp;
    421 	struct grf_cv_softc *gcp;
    422 	static char attachflag = 0;
    423 
    424 	zap = auxp;
    425 
    426 	/*
    427 	 * This function is called twice, once on console init (dp == NULL)
    428 	 * and once on "normal" grf5 init.
    429 	 */
    430 
    431 	if (dp == NULL) /* console init */
    432 		gcp = &congrf;
    433 	else
    434 		gcp = (struct grf_cv_softc *)dp;
    435 
    436 	gp = &gcp->gcs_sc;
    437 
    438 	if (dp != NULL && congrf.gcs_sc.g_regkva != 0) {
    439 		/*
    440 		 * inited earlier, just copy (not device struct)
    441 		 */
    442 
    443 		printf("\n");
    444 		bcopy(&congrf.gcs_sc.g_display, &gp->g_display,
    445 			(char *) &gcp->gcs_isr - (char *) &gp->g_display);
    446 
    447 		/* ... and transfer the isr */
    448 		gcp->gcs_isr.isr_ipl = CV_INT_NUM;
    449 		gcp->gcs_isr.isr_intr = cvintr;
    450 		gcp->gcs_isr.isr_arg = (void *)gp;
    451 
    452 		/* First add new isr */
    453 		add_isr(&gcp->gcs_isr);
    454 		remove_isr(&congrf.gcs_isr);
    455 	} else {
    456 		gp->g_regkva = (volatile caddr_t)cv_boardaddr + 0x02000000;
    457 		gp->g_fbkva = (volatile caddr_t)cv_boardaddr + 0x01400000;
    458 
    459 		gp->g_unit = GRF_CV64_UNIT;
    460 		gp->g_mode = cv_mode;
    461 		gp->g_conpri = grfcv_cnprobe();
    462 		gp->g_flags = GF_ALIVE;
    463 
    464 		/* add Interrupt Handler */
    465 		gcp->gcs_isr.isr_ipl = CV_INT_NUM;
    466 		gcp->gcs_isr.isr_intr = cvintr;
    467 		gcp->gcs_isr.isr_arg = (void *)gp;
    468 		add_isr(&gcp->gcs_isr);
    469 
    470 		/* wakeup the board */
    471 		cv_boardinit(gp);
    472 
    473 #ifdef CV64CONSOLE
    474 		grfcv_iteinit(gp);
    475 		(void)cv_load_mon(gp, &cvconsole_mode);
    476 #endif
    477 	}
    478 
    479 	/*
    480 	 * attach grf
    481 	 */
    482 	if (amiga_config_found(cfdata, &gp->g_device, gp, grfcvprint)) {
    483 		if (dp != NULL)
    484 			printf("grfcv: CyberVision64 with %dMB being used\n",
    485 			    cv_fbsize/0x100000);
    486 		attachflag = 1;
    487 	} else {
    488 		if (!attachflag)
    489 			/*printf("grfcv unattached!!\n")*/;
    490 	}
    491 }
    492 
    493 int
    494 grfcvprint(void *auxp, const char *pnp)
    495 {
    496 	if (pnp)
    497 		aprint_normal("ite at %s: ", pnp);
    498 	return (UNCONF);
    499 }
    500 
    501 
    502 /*
    503  * Computes M, N, and R values from
    504  * given input frequency. It uses a table of
    505  * precomputed values, to keep CPU time low.
    506  *
    507  * The return value consist of:
    508  * lower byte:  Bits 4-0: N Divider Value
    509  *	        Bits 5-6: R Value          for e.g. SR10 or SR12
    510  * higher byte: Bits 0-6: M divider value  for e.g. SR11 or SR13
    511  */
    512 
    513 static unsigned short
    514 cv_compute_clock(unsigned long freq)
    515 {
    516 	static unsigned char *mnr, *save;	/* M, N + R vals */
    517 	unsigned long work_freq, r;
    518 	unsigned short erg;
    519 	long diff, d2;
    520 
    521 	if (freq < 12500000 || freq > MAXPIXELCLOCK) {
    522 		printf("grfcv: Illegal clock frequency: %ldMHz\n", freq/1000000);
    523 		printf("grfcv: Using default frequency: 25MHz\n");
    524 		printf("grfcv: See the manpage of grfconfig for more informations.\n");
    525 		freq = 25000000;
    526 	}
    527 
    528 	mnr = clocks;	/* there the vals are stored */
    529 	d2 = 0x7fffffff;
    530 
    531 	while (*mnr) {	/* mnr vals are 0-terminated */
    532 		work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
    533 
    534 		r = (mnr[1] >> 5) & 0x03;
    535 		if (r != 0)
    536 			work_freq=work_freq >> r;	/* r is the freq divider */
    537 
    538 		work_freq *= 0x3E8;	/* 2nd part of OSC */
    539 
    540 		diff = abs(freq - work_freq);
    541 
    542 		if (d2 >= diff) {
    543 			d2 = diff;
    544 			/* In save are the vals for minimal diff */
    545 			save = mnr;
    546 		}
    547 		mnr += 2;
    548 	}
    549 	erg = *((unsigned short *)save);
    550 
    551 	return (erg);
    552 }
    553 
    554 
    555 void
    556 cv_boardinit(struct grf_softc *gp)
    557 {
    558 	volatile caddr_t ba;
    559 	unsigned char test;
    560 	unsigned int clockpar;
    561 	int i;
    562 	struct grfinfo *gi;
    563 
    564 	ba = gp->g_regkva;
    565 	/* Reset board */
    566 	for (i = 0; i < 6; i++)
    567 		cv_write_port (0xff, ba - 0x02000000);	/* Clear all bits */
    568 
    569 	/* Return to operational Mode */
    570 	cv_write_port(0x8004, ba - 0x02000000);
    571 
    572 	/* Wakeup Chip */
    573 	vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x10);
    574 	vgaw(ba, SREG_OPTION_SELECT, 0x01);
    575 	vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x08);
    576 
    577 	vgaw(ba, GREG_MISC_OUTPUT_W, 0x03);
    578 
    579 	WCrt(ba, CRT_ID_REGISTER_LOCK_1, 0x48);	/* unlock S3 VGA regs */
    580 	WCrt(ba, CRT_ID_REGISTER_LOCK_2, 0xA5);	/* unlock syscontrol */
    581 
    582 	/*
    583 	 * The default board interrupt is #6.
    584 	 * Set the roxxler register to use interrupt #2, not #6.
    585 	 */
    586 #if CV_INT_NUM == 2
    587 	cv_write_port(0x8080, ba - 0x02000000);
    588 #endif
    589 
    590 	/* Enable board interrupts */
    591 	cv_write_port(0x8008, ba - 0x02000000);
    592 
    593 	test = RCrt(ba, CRT_ID_SYSTEM_CONFIG);
    594 	test = test | 0x01;	/* enable enhaced register access */
    595 	test = test & 0xEF;	/* clear bit 4, 0 wait state */
    596 	WCrt(ba, CRT_ID_SYSTEM_CONFIG, test);
    597 
    598 	/*
    599 	 * bit 1=1: enable enhanced mode functions
    600 	 * bit 4=1: enable linear addressing
    601 	 * bit 5=1: enable MMIO
    602 	 */
    603 	vgaw(ba, ECR_ADV_FUNC_CNTL, 0x31);
    604 
    605 	/* enable color mode (bit0), CPU access (bit1), high 64k page (bit5) */
    606 	vgaw(ba, GREG_MISC_OUTPUT_W, 0xe3);
    607 
    608 	/* CPU base addr */
    609 	WCrt(ba, CRT_ID_EXT_SYS_CNTL_4, 0x00);
    610 
    611 	/* Reset. This does nothing, but everyone does it:) */
    612 	WSeq(ba, SEQ_ID_RESET, 0x03);
    613 
    614 	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x01);	/* 8 Dot Clock */
    615 	WSeq(ba, SEQ_ID_MAP_MASK, 0x0f);	/* Enable write planes */
    616 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);	/* Character Font */
    617 
    618 	WSeq(ba, SEQ_ID_MEMORY_MODE, 0x02);	/* Complete mem access */
    619 
    620 	WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x06);	/* Unlock extensions */
    621 	test = RSeq(ba, SEQ_ID_BUS_REQ_CNTL);	/* Bus Request */
    622 
    623 	/* enable 4MB fast Page Mode */
    624 	test = test | 1 << 6;
    625 	WSeq(ba, SEQ_ID_BUS_REQ_CNTL, test);
    626 	/* faster LUT write */
    627 	WSeq(ba, SEQ_ID_RAMDAC_CNTL, 0xC0);
    628 
    629 	test = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);	/* Clksyn2 read */
    630 
    631 	/* immediately Clkload bit clear */
    632 	test = test & 0xDF;
    633 
    634 	/* 2 MCLK Memory Write.... */
    635 	if (cv_memclk >= 55000000)
    636 		test |= 0x80;
    637 
    638 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, test);
    639 
    640 	/* Memory CLK */
    641 	clockpar = cv_compute_clock(cv_memclk);
    642 	test = (clockpar & 0xFF00) >> 8;
    643 	WSeq(ba, SEQ_ID_MCLK_HI, test);		/* PLL N-Divider Value */
    644 
    645 	test = clockpar & 0xFF;
    646 	WSeq(ba, SEQ_ID_MCLK_LO, test);		/* PLL M-Divider Value */
    647 
    648 	if (RCrt(ba, CRT_ID_REVISION) == 0x10)	/* bugfix for new S3 chips */
    649 		WSeq(ba, SEQ_ID_MORE_MAGIC, test);
    650 
    651 	/* We now load an 25 MHz, 31 kHz, 640x480 standard VGA Mode. */
    652 	/* DCLK */
    653 	WSeq(ba, SEQ_ID_DCLK_HI, 0x13);
    654 	WSeq(ba, SEQ_ID_DCLK_LO, 0x41);
    655 
    656 	test = RSeq (ba, SEQ_ID_CLKSYN_CNTL_2);
    657 	test = test | 0x22;
    658 
    659 	/* DCLK + MCLK Clock immediate load! */
    660 	WSeq(ba,SEQ_ID_CLKSYN_CNTL_2, test);
    661 
    662 	/* DCLK load */
    663 	test = vgar(ba, 0x3cc);
    664 	test = test | 0x0c;
    665 	vgaw(ba, 0x3c2, test);
    666 
    667 	/* Clear bit 5 again, prevent further loading. */
    668 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, 0x02);
    669 
    670 	WCrt(ba, CRT_ID_HOR_TOTAL, 0x5F);
    671 	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, 0x4F);
    672 	WCrt(ba, CRT_ID_START_HOR_BLANK, 0x50);
    673 	WCrt(ba, CRT_ID_END_HOR_BLANK, 0x82);
    674 	WCrt(ba, CRT_ID_START_HOR_RETR, 0x54);
    675 	WCrt(ba, CRT_ID_END_HOR_RETR, 0x80);
    676 	WCrt(ba, CRT_ID_VER_TOTAL, 0xBF);
    677 
    678 	WCrt(ba, CRT_ID_OVERFLOW, 0x1F);	/* overflow reg */
    679 
    680 	WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00);	/* no panning */
    681 
    682 	WCrt(ba, CRT_ID_MAX_SCAN_LINE, 0x40);	/* vscan */
    683 
    684 	WCrt(ba, CRT_ID_CURSOR_START, 0x00);
    685 	WCrt(ba, CRT_ID_CURSOR_END, 0x00);
    686 
    687 	/* Display start address */
    688 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
    689 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
    690 
    691 	/* Cursor location */
    692 	WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
    693 	WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
    694 
    695 	/* Vertical retrace */
    696 	WCrt(ba, CRT_ID_START_VER_RETR, 0x9C);
    697 	WCrt(ba, CRT_ID_END_VER_RETR, 0x0E);
    698 
    699 	WCrt(ba, CRT_ID_VER_DISP_ENA_END, 0x8F);
    700 	WCrt(ba, CRT_ID_SCREEN_OFFSET, 0x50);
    701 
    702 	WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x00);
    703 
    704 	WCrt(ba, CRT_ID_START_VER_BLANK, 0x96);
    705 	WCrt(ba, CRT_ID_END_VER_BLANK, 0xB9);
    706 
    707 	WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3);
    708 
    709 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xFF);
    710 
    711 	WCrt(ba, CRT_ID_BACKWAD_COMP_3, 0x10);	/* FIFO enabled */
    712 
    713 	/* Refresh count 1, High speed text font, enhanced color mode */
    714 	WCrt(ba, CRT_ID_MISC_1, 0x35);
    715 
    716 	/* start fifo position */
    717 	WCrt(ba, CRT_ID_DISPLAY_FIFO, 0x5a);
    718 
    719 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, 0x70);
    720 
    721 	/* address window position */
    722 	WCrt(ba, CRT_ID_LAW_POS_LO, 0x40);
    723 
    724 	/* N Parameter for Display FIFO */
    725 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
    726 
    727 	WGfx(ba, GCT_ID_SET_RESET, 0x00);
    728 	WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x00);
    729 	WGfx(ba, GCT_ID_COLOR_COMPARE, 0x00);
    730 	WGfx(ba, GCT_ID_DATA_ROTATE, 0x00);
    731 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
    732 	WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40);
    733 	WGfx(ba, GCT_ID_MISC, 0x01);
    734 	WGfx(ba, GCT_ID_COLOR_XCARE, 0x0F);
    735 	WGfx(ba, GCT_ID_BITMASK, 0xFF);
    736 
    737 	/* colors for text mode */
    738 	for (i = 0; i <= 0xf; i++)
    739 		WAttr (ba, i, i);
    740 
    741 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x41);
    742 	WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x01);
    743 	WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0F);
    744 	WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x00);
    745 	WAttr(ba, ACT_ID_COLOR_SELECT, 0x00);
    746 
    747 	vgaw(ba, VDAC_MASK, 0xFF);	/* DAC Mask */
    748 
    749 	*((unsigned long *)(ba + ECR_FRGD_COLOR)) = 0xFF;
    750 	*((unsigned long *)(ba + ECR_BKGD_COLOR)) = 0;
    751 
    752 	/* colors initially set to greyscale */
    753 
    754 	vgaw(ba, VDAC_ADDRESS_W, 0);
    755 	for (i = 255; i >= 0 ; i--) {
    756 		vgaw(ba, VDAC_DATA, i);
    757 		vgaw(ba, VDAC_DATA, i);
    758 		vgaw(ba, VDAC_DATA, i);
    759 	}
    760 
    761 	/* GFx hardware cursor off */
    762 	WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
    763 
    764 	/* Set first to 4 MB, so test will work */
    765 	WCrt(ba, CRT_ID_LAW_CNTL, 0x13);
    766 
    767 	/* find *correct* fbsize of z3 board */
    768 	if (cv_has_4mb((volatile caddr_t)cv_boardaddr + 0x01400000)) {
    769 		cv_fbsize = 1024 * 1024 * 4;
    770 		WCrt(ba, CRT_ID_LAW_CNTL, 0x13); /* 4 MB */
    771 	} else {
    772 		cv_fbsize = 1024 * 1024 * 2;
    773 		WCrt(ba, CRT_ID_LAW_CNTL, 0x12); /* 2 MB */
    774 	}
    775 
    776 	/* Initialize graphics engine */
    777 	GfxBusyWait(ba);
    778 	vgaw16(ba, ECR_FRGD_MIX, 0x27);
    779 	vgaw16(ba, ECR_BKGD_MIX, 0x07);
    780 
    781 	vgaw16(ba, ECR_READ_REG_DATA, 0x1000);
    782 	delay(200000);
    783 	vgaw16(ba, ECR_READ_REG_DATA, 0x2000);
    784 	GfxBusyWait(ba);
    785 	vgaw16(ba, ECR_READ_REG_DATA, 0x3fff);
    786 	GfxBusyWait(ba);
    787 	delay(200000);
    788 	vgaw16(ba, ECR_READ_REG_DATA, 0x4fff);
    789 	GfxBusyWait(ba);
    790 
    791 	vgaw16(ba, ECR_BITPLANE_WRITE_MASK, ~0);
    792 
    793 	GfxBusyWait (ba);
    794 	vgaw16(ba, ECR_READ_REG_DATA, 0xe000);
    795 	vgaw16(ba, ECR_CURRENT_Y_POS2, 0x00);
    796 	vgaw16(ba, ECR_CURRENT_X_POS2, 0x00);
    797 	vgaw16(ba, ECR_READ_REG_DATA, 0xa000);
    798 	vgaw16(ba, ECR_DEST_Y__AX_STEP, 0x00);
    799 	vgaw16(ba, ECR_DEST_Y2__AX_STEP2, 0x00);
    800 	vgaw16(ba, ECR_DEST_X__DIA_STEP, 0x00);
    801 	vgaw16(ba, ECR_DEST_X2__DIA_STEP2, 0x00);
    802 	vgaw16(ba, ECR_SHORT_STROKE, 0x00);
    803 	vgaw16(ba, ECR_DRAW_CMD, 0x01);
    804 	GfxBusyWait (ba);
    805 
    806 	/* It ain't easy to write here, so let's do it again */
    807 	vgaw16(ba, ECR_READ_REG_DATA, 0x4fff);
    808 
    809 	vgaw16(ba, ECR_BKGD_COLOR, 0x01);
    810 	vgaw16(ba, ECR_FRGD_COLOR, 0x00);
    811 
    812 	/* Enable Video Display (Set Bit 5) */
    813 	WAttr(ba, 0x33, 0);
    814 
    815 	gi = &gp->g_display;
    816 	gi->gd_regaddr	= (caddr_t) kvtop (ba);
    817 	gi->gd_regsize	= 64 * 1024;
    818 	gi->gd_fbaddr	= (caddr_t) kvtop (gp->g_fbkva);
    819 	gi->gd_fbsize	= cv_fbsize;
    820 }
    821 
    822 
    823 int
    824 cv_getvmode(struct grf_softc *gp, struct grfvideo_mode *vm)
    825 {
    826 	struct grfvideo_mode *gv;
    827 
    828 #ifdef CV64CONSOLE
    829 	/* Handle grabbing console mode */
    830 	if (vm->mode_num == 255) {
    831 		bcopy(&cvconsole_mode, vm, sizeof(struct grfvideo_mode));
    832 		/* XXX so grfconfig can tell us the correct text dimensions. */
    833 		vm->depth = cvconsole_mode.fy;
    834 	} else
    835 #endif
    836 	{
    837 		if (vm->mode_num == 0)
    838 			vm->mode_num = (monitor_current - monitor_def) + 1;
    839 		if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
    840 			return (EINVAL);
    841 		gv = monitor_def + (vm->mode_num - 1);
    842 		if (gv->mode_num == 0)
    843 			return (EINVAL);
    844 
    845 		bcopy(gv, vm, sizeof(struct grfvideo_mode));
    846 	}
    847 
    848 	/* adjust internal values to pixel values */
    849 
    850 	vm->hblank_start *= 8;
    851 	vm->hsync_start *= 8;
    852 	vm->hsync_stop *= 8;
    853 	vm->htotal *= 8;
    854 
    855 	return (0);
    856 }
    857 
    858 
    859 int
    860 cv_setvmode(struct grf_softc *gp, unsigned mode)
    861 {
    862 
    863 	if (!mode || (mode > monitor_def_max) ||
    864 	    monitor_def[mode - 1].mode_num == 0)
    865 		return (EINVAL);
    866 
    867 	monitor_current = monitor_def + (mode - 1);
    868 
    869 	return (0);
    870 }
    871 
    872 
    873 int
    874 cv_blank(struct grf_softc *gp, int *on)
    875 {
    876 	volatile caddr_t ba;
    877 
    878 	ba = gp->g_regkva;
    879 	gfx_on_off(*on > 0 ? 0 : 1, ba);
    880 	return (0);
    881 }
    882 
    883 
    884 /*
    885  * Change the mode of the display.
    886  * Return a UNIX error number or 0 for success.
    887  */
    888 int
    889 cv_mode(register struct grf_softc *gp, u_long cmd, void *arg, u_long a2,
    890         int a3)
    891 {
    892 	int error;
    893 
    894 	switch (cmd) {
    895 	    case GM_GRFON:
    896 		error = cv_load_mon (gp,
    897 		    (struct grfcvtext_mode *) monitor_current) ? 0 : EINVAL;
    898 		return (error);
    899 
    900 	    case GM_GRFOFF:
    901 #ifndef CV64CONSOLE
    902 		cvscreen(1, gp->g_regkva - 0x02000000);
    903 #else
    904 		cv_load_mon(gp, &cvconsole_mode);
    905 		ite_reinit(gp->g_itedev);
    906 #endif
    907 		return (0);
    908 
    909 	    case GM_GRFCONFIG:
    910 		return (0);
    911 
    912 	    case GM_GRFGETVMODE:
    913 		return (cv_getvmode (gp, (struct grfvideo_mode *) arg));
    914 
    915 	    case GM_GRFSETVMODE:
    916 		error = cv_setvmode (gp, *(unsigned *) arg);
    917 		if (!error && (gp->g_flags & GF_GRFON))
    918 			cv_load_mon(gp,
    919 			    (struct grfcvtext_mode *) monitor_current);
    920 		return (error);
    921 
    922 	    case GM_GRFGETNUMVM:
    923 		*(int *)arg = monitor_def_max;
    924 		return (0);
    925 
    926 	    case GM_GRFIOCTL:
    927 		return (cv_ioctl (gp, a2, arg));
    928 
    929 	    default:
    930 		break;
    931 	}
    932 
    933 	return (EPASSTHROUGH);
    934 }
    935 
    936 
    937 int
    938 cv_ioctl(register struct grf_softc *gp, u_long cmd, void *data)
    939 {
    940 	switch (cmd) {
    941 #ifndef CV_NO_HARDWARE_CURSOR
    942 	    case GRFIOCGSPRITEPOS:
    943 		return(cv_getspritepos (gp, (struct grf_position *) data));
    944 
    945 	    case GRFIOCSSPRITEPOS:
    946 		return(cv_setspritepos (gp, (struct grf_position *) data));
    947 
    948 	    case GRFIOCSSPRITEINF:
    949 		return(cv_setspriteinfo (gp, (struct grf_spriteinfo *) data));
    950 
    951 	    case GRFIOCGSPRITEINF:
    952 		return(cv_getspriteinfo (gp, (struct grf_spriteinfo *) data));
    953 
    954 	    case GRFIOCGSPRITEMAX:
    955 		return(cv_getspritemax (gp, (struct grf_position *) data));
    956 #else	/* !CV_NO_HARDWARE_CURSOR */
    957 	    case GRFIOCGSPRITEPOS:
    958 	    case GRFIOCSSPRITEPOS:
    959 	    case GRFIOCSSPRITEINF:
    960 	    case GRFIOCGSPRITEINF:
    961 	    case GRFIOCGSPRITEMAX:
    962 		break;
    963 #endif	/* !CV_NO_HARDWARE_CURSOR */
    964 
    965 	    case GRFIOCGETCMAP:
    966 		return (cv_getcmap (gp, (struct grf_colormap *) data));
    967 
    968 	    case GRFIOCPUTCMAP:
    969 		return (cv_putcmap (gp, (struct grf_colormap *) data));
    970 
    971 	    case GRFIOCBITBLT:
    972 		break;
    973 
    974 	    case GRFTOGGLE:
    975 		return (cv_toggle (gp));
    976 
    977 	    case GRFIOCSETMON:
    978 		return (cv_setmonitor (gp, (struct grfvideo_mode *)data));
    979 
    980 	    case GRFIOCBLANK:
    981 		return (cv_blank (gp, (int *)data));
    982 	}
    983 	return (EPASSTHROUGH);
    984 }
    985 
    986 
    987 int
    988 cv_setmonitor(struct grf_softc *gp, struct grfvideo_mode *gv)
    989 {
    990 	struct grfvideo_mode *md;
    991 
    992 	if (!cv_mondefok(gv))
    993 		return (EINVAL);
    994 
    995 #ifdef CV64CONSOLE
    996 	/* handle interactive setting of console mode */
    997 	if (gv->mode_num == 255) {
    998 		bcopy(gv, &cvconsole_mode.gv, sizeof(struct grfvideo_mode));
    999 		cvconsole_mode.gv.hblank_start /= 8;
   1000 		cvconsole_mode.gv.hsync_start /= 8;
   1001 		cvconsole_mode.gv.hsync_stop /= 8;
   1002 		cvconsole_mode.gv.htotal /= 8;
   1003 		cvconsole_mode.rows = gv->disp_height / cvconsole_mode.fy;
   1004 		cvconsole_mode.cols = gv->disp_width / cvconsole_mode.fx;
   1005 		if (!(gp->g_flags & GF_GRFON))
   1006 			cv_load_mon(gp, &cvconsole_mode);
   1007 		ite_reinit(gp->g_itedev);
   1008 		return (0);
   1009 	}
   1010 #endif
   1011 
   1012 	md = monitor_def + (gv->mode_num - 1);
   1013 
   1014 	/*
   1015 	 * Prevent user from crashing the system by using
   1016 	 * grfconfig while in X
   1017 	 */
   1018 	if (gp->g_flags & GF_GRFON)
   1019 		if (md == monitor_current) {
   1020 			printf("grfcv: Changing the used mode not allowed!\n");
   1021 			return (EINVAL);
   1022 		}
   1023 
   1024 	bcopy(gv, md, sizeof(struct grfvideo_mode));
   1025 
   1026 	/* adjust pixel oriented values to internal rep. */
   1027 
   1028 	md->hblank_start /= 8;
   1029 	md->hsync_start /= 8;
   1030 	md->hsync_stop /= 8;
   1031 	md->htotal /= 8;
   1032 
   1033 	return (0);
   1034 }
   1035 
   1036 
   1037 int
   1038 cv_getcmap(struct grf_softc *gfp, struct grf_colormap *cmap)
   1039 {
   1040 	volatile caddr_t ba;
   1041 	u_char red[256], green[256], blue[256], *rp, *gp, *bp;
   1042 	short x;
   1043 	int error;
   1044 
   1045 	ba = gfp->g_regkva;
   1046 	if (cmap->count == 0 || cmap->index >= 256)
   1047 		return (0);
   1048 
   1049 	if (cmap->count > 256 - cmap->index)
   1050 		cmap->count = 256 - cmap->index;
   1051 
   1052 	/* first read colors out of the chip, then copyout to userspace */
   1053 	vgaw (ba, VDAC_ADDRESS_W, cmap->index);
   1054 	x = cmap->count - 1;
   1055 
   1056 	rp = red + cmap->index;
   1057 	gp = green + cmap->index;
   1058 	bp = blue + cmap->index;
   1059 
   1060 	do {
   1061 		*rp++ = vgar (ba, VDAC_DATA) << 2;
   1062 		*gp++ = vgar (ba, VDAC_DATA) << 2;
   1063 		*bp++ = vgar (ba, VDAC_DATA) << 2;
   1064 	} while (x-- > 0);
   1065 
   1066 	if (!(error = copyout (red + cmap->index, cmap->red, cmap->count))
   1067 	    && !(error = copyout (green + cmap->index, cmap->green, cmap->count))
   1068 	    && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count)))
   1069 		return (0);
   1070 
   1071 	return (error);
   1072 }
   1073 
   1074 
   1075 int
   1076 cv_putcmap(struct grf_softc *gfp, struct grf_colormap *cmap)
   1077 {
   1078 	volatile caddr_t ba;
   1079 	u_char red[256], green[256], blue[256], *rp, *gp, *bp;
   1080 	short x;
   1081 	int error;
   1082 
   1083 	ba = gfp->g_regkva;
   1084 	if (cmap->count == 0 || cmap->index >= 256)
   1085 		return (0);
   1086 
   1087 	if (cmap->count > 256 - cmap->index)
   1088 		cmap->count = 256 - cmap->index;
   1089 
   1090 	/* first copy the colors into kernelspace */
   1091 	if (!(error = copyin (cmap->red, red + cmap->index, cmap->count))
   1092 	    && !(error = copyin (cmap->green, green + cmap->index, cmap->count))
   1093 	    && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count))) {
   1094 		vgaw (ba, VDAC_ADDRESS_W, cmap->index);
   1095 		x = cmap->count - 1;
   1096 
   1097 		rp = red + cmap->index;
   1098 		gp = green + cmap->index;
   1099 		bp = blue + cmap->index;
   1100 
   1101 		do {
   1102 			vgaw (ba, VDAC_DATA, *rp++ >> 2);
   1103 			vgaw (ba, VDAC_DATA, *gp++ >> 2);
   1104 			vgaw (ba, VDAC_DATA, *bp++ >> 2);
   1105 		} while (x-- > 0);
   1106 		return (0);
   1107 	} else
   1108 		return (error);
   1109 }
   1110 
   1111 
   1112 int
   1113 cv_toggle(struct grf_softc *gp)
   1114 {
   1115 	volatile caddr_t ba;
   1116 
   1117 	ba = gp->g_regkva;
   1118 #ifndef CV64CONSOLE
   1119 	cv_pass_toggle = 1;
   1120 #endif /* !CV64CONSOLE */
   1121 
   1122 	if (cv_pass_toggle) {
   1123 		cvscreen(0, ba - 0x02000000);
   1124 		cv_pass_toggle = 0;
   1125 	} else {
   1126 		cvscreen(1, ba - 0x02000000);
   1127 		cv_pass_toggle = 1;
   1128 	}
   1129 
   1130 	return (0);
   1131 }
   1132 
   1133 
   1134 int
   1135 cv_mondefok(struct grfvideo_mode *gv)
   1136 {
   1137 	unsigned long maxpix;
   1138 
   1139 	if (gv->mode_num < 1 || gv->mode_num > monitor_def_max) {
   1140 		if (gv->mode_num != 255 || gv->depth != 4)
   1141 			return (0);
   1142 	}
   1143 
   1144 	switch(gv->depth) {
   1145 	   case 4:
   1146 		maxpix = MAXPIXELCLOCK - 55000000;
   1147 		break;
   1148 	   case 8:
   1149 		maxpix = MAXPIXELCLOCK;
   1150 		break;
   1151 	   case 15:
   1152 	   case 16:
   1153 #ifdef	CV_AGGRESSIVE_TIMING
   1154 		maxpix = MAXPIXELCLOCK - 35000000;
   1155 #else
   1156 		maxpix = MAXPIXELCLOCK - 55000000;
   1157 #endif
   1158 		break;
   1159 	   case 24:
   1160 	   case 32:
   1161 #ifdef	CV_AGGRESSIVE_TIMING
   1162 		maxpix = MAXPIXELCLOCK - 75000000;
   1163 #else
   1164 		maxpix = MAXPIXELCLOCK - 85000000;
   1165 #endif
   1166 		break;
   1167 	   default:
   1168 		printf("grfcv: Illegal depth in mode %d\n",
   1169 			(int) gv->mode_num);
   1170 		return (0);
   1171 	}
   1172 
   1173 	if (gv->pixel_clock > maxpix) {
   1174 		printf("grfcv: Pixelclock too high in mode %d\n",
   1175 			(int) gv->mode_num);
   1176 		return (0);
   1177 	}
   1178 
   1179 	if (gv->mode_num == 255) { /* console mode */
   1180 		if ((gv->disp_width / 8) > MAXCOLS) {
   1181 			printf ("grfcv: Too many columns for console\n");
   1182 			return (0);
   1183 		} else if ((gv->disp_height / S3FONTY) > MAXROWS) {
   1184 			printf ("grfcv: Too many rows for console\n");
   1185 			return (0);
   1186 		}
   1187 	}
   1188 
   1189 	if (gv->disp_flags & GRF_FLAGS_SYNC_ON_GREEN) {
   1190 		printf("grfcv: sync-on-green is not supported\n");
   1191 		return (0);
   1192 	}
   1193 
   1194 	return (1);
   1195 }
   1196 
   1197 
   1198 int
   1199 cv_load_mon(struct grf_softc *gp, struct grfcvtext_mode *md)
   1200 {
   1201 	struct grfvideo_mode *gv;
   1202 	struct grfinfo *gi;
   1203 	volatile caddr_t ba, fb;
   1204 	unsigned short mnr;
   1205 	unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
   1206 		VSE, VT;
   1207 	int cr50, sr15, sr18, clock_mode, test;
   1208 	int m, n;	/* For calc'ing display FIFO */
   1209 	int tfillm, temptym;	/* FIFO fill and empty mclk's */
   1210 	int hmul;	/* Multiplier for hor. Values */
   1211 	unsigned char hvsync_pulse;
   1212 	char TEXT, CONSOLE;
   1213 
   1214 	/* identity */
   1215 	gv = &md->gv;
   1216 
   1217 	TEXT = (gv->depth == 4);
   1218 	CONSOLE = (gv->mode_num == 255);
   1219 
   1220 	if (!cv_mondefok(gv)) {
   1221 		printf("grfcv: Monitor definition not ok\n");
   1222 		return (0);
   1223 	}
   1224 
   1225 	ba = gp->g_regkva;
   1226 	fb = gp->g_fbkva;
   1227 
   1228 	/* Disable Interrupts */
   1229 	test = RCrt(ba, CRT_ID_BACKWAD_COMP_1);
   1230 	test &= ~0x10;
   1231 	WCrt(ba, CRT_ID_BACKWAD_COMP_1, test);
   1232 
   1233 	/* turn gfx off, don't mess up the display */
   1234 	gfx_on_off(1, ba);
   1235 
   1236 	/* provide all needed information in grf device-independant locations */
   1237 	gp->g_data		= (caddr_t) gv;
   1238 	gi = &gp->g_display;
   1239 	gi->gd_colors		= 1 << gv->depth;
   1240 	gi->gd_planes		= gv->depth;
   1241 	gi->gd_fbwidth		= gv->disp_width;
   1242 	gi->gd_fbheight		= gv->disp_height;
   1243 	gi->gd_fbx		= 0;
   1244 	gi->gd_fby		= 0;
   1245 	if (CONSOLE) {
   1246 		gi->gd_dwidth	= md->fx * md->cols;
   1247 		gi->gd_dheight	= md->fy * md->rows;
   1248 	} else {
   1249 		gi->gd_dwidth	= gv->disp_width;
   1250 		gi->gd_dheight	= gv->disp_height;
   1251 	}
   1252 	gi->gd_dx		= 0;
   1253 	gi->gd_dy		= 0;
   1254 
   1255 	/* get display mode parameters */
   1256 	switch (gv->depth) {
   1257 	    case 15:
   1258 	    case 16:
   1259 		hmul = 2;
   1260 		break;
   1261 	    default:
   1262 		hmul = 1;
   1263 		break;
   1264 	}
   1265 
   1266 	HBS = gv->hblank_start * hmul;
   1267 	HSS = gv->hsync_start * hmul;
   1268 	HSE = gv->hsync_stop * hmul;
   1269 	HBE = gv->htotal * hmul - 6;
   1270 	HT  = gv->htotal * hmul - 5;
   1271 	VBS = gv->vblank_start - 1;
   1272 	VSS = gv->vsync_start;
   1273 	VSE = gv->vsync_stop;
   1274 	VBE = gv->vtotal - 3;
   1275 	VT  = gv->vtotal - 2;
   1276 
   1277 	/* Disable enhanced Mode for text display */
   1278 
   1279 	vgaw(ba, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
   1280 
   1281 	if (TEXT)
   1282 		HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
   1283 	else
   1284 		HDE = (gv->disp_width + 3) * hmul / 8 - 1; /*HBS;*/
   1285 	VDE = gv->disp_height - 1;
   1286 
   1287 	/* adjustments */
   1288 
   1289 	if (gv->disp_flags & GRF_FLAGS_LACE) {
   1290 		VDE = VDE / 2;
   1291 		VBS = VBS / 2;
   1292 		VSS = VSS / 2;
   1293 		VSE = VSE / 2;
   1294 		VBE = VBE / 2;
   1295 		VT  = VT / 2;
   1296 	}
   1297 
   1298 	/* Horizontal/Vertical Sync Pulse */
   1299 	/*
   1300 	 * GREG_MISC_OUTPUT_W Register:
   1301 	 * bit	description (0/1)
   1302 	 *  0	Monochrome/Color emulation
   1303 	 *  1	Disable/Enable access of the display memory from the CPU
   1304 	 *  5	Select the low/high 64K page of memory
   1305 	 *  6	Select a positive/negative horizontal retrace sync pulse
   1306 	 *  7	Select a positive/negative vertical retrace sync pulse
   1307 	 */
   1308 	hvsync_pulse = vgar(ba, GREG_MISC_OUTPUT_R);
   1309 	if (gv->disp_flags & GRF_FLAGS_PHSYNC)
   1310 		hvsync_pulse &= ~0x40;
   1311 	else
   1312 		hvsync_pulse |= 0x40;
   1313 	if (gv->disp_flags & GRF_FLAGS_PVSYNC)
   1314 		hvsync_pulse &= ~0x80;
   1315 	else
   1316 		hvsync_pulse |= 0x80;
   1317 	vgaw(ba, GREG_MISC_OUTPUT_W, hvsync_pulse);
   1318 
   1319 	/* GFX hardware cursor off */
   1320 	WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
   1321 	WCrt(ba, CRT_ID_EXT_DAC_CNTL, 0x00);
   1322 
   1323 	WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
   1324 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
   1325 	WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
   1326 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
   1327 
   1328 	/* Set clock */
   1329 
   1330 	mnr = cv_compute_clock(gv->pixel_clock);
   1331 	WSeq(ba, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
   1332 	WSeq(ba, SEQ_ID_DCLK_LO, (mnr & 0xFF));
   1333 
   1334 	/* load display parameters into board */
   1335 
   1336 	WCrt(ba, CRT_ID_EXT_HOR_OVF,
   1337 	   ((HT & 0x100) ? 0x01 : 0x00) |
   1338 	   ((HDE & 0x100) ? 0x02 : 0x00) |
   1339 	   ((HBS & 0x100) ? 0x04 : 0x00) |
   1340 	/* ((HBE & 0x40) ? 0x08 : 0x00) | */  /* Later... */
   1341 	   ((HSS & 0x100) ? 0x10 : 0x00) |
   1342 	/* ((HSE & 0x20) ? 0x20 : 0x00) | */
   1343 	   (((HT-5) & 0x100) ? 0x40 : 0x00) );
   1344 
   1345 	WCrt(ba, CRT_ID_EXT_VER_OVF,
   1346 	    0x40 |	/* Line compare */
   1347 	    ((VT  & 0x400) ? 0x01 : 0x00) |
   1348 	    ((VDE & 0x400) ? 0x02 : 0x00) |
   1349 	    ((VBS & 0x400) ? 0x04 : 0x00) |
   1350 	    ((VSS & 0x400) ? 0x10 : 0x00) );
   1351 
   1352 	WCrt(ba, CRT_ID_HOR_TOTAL, HT);
   1353 	WCrt(ba, CRT_ID_DISPLAY_FIFO, HT - 5);
   1354 
   1355 	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
   1356 	WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
   1357 	WCrt(ba, CRT_ID_END_HOR_BLANK, ((HBE & 0x1f) | 0x80));
   1358 	WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
   1359 	WCrt(ba, CRT_ID_END_HOR_RETR,
   1360 	    (HSE & 0x1f) |
   1361 	    ((HBE & 0x20) ? 0x80 : 0x00) );
   1362 	WCrt(ba, CRT_ID_VER_TOTAL, VT);
   1363 	WCrt(ba, CRT_ID_OVERFLOW,
   1364 	    0x10 |
   1365 	    ((VT  & 0x100) ? 0x01 : 0x00) |
   1366 	    ((VDE & 0x100) ? 0x02 : 0x00) |
   1367 	    ((VSS & 0x100) ? 0x04 : 0x00) |
   1368 	    ((VBS & 0x100) ? 0x08 : 0x00) |
   1369 	    ((VT  & 0x200) ? 0x20 : 0x00) |
   1370 	    ((VDE & 0x200) ? 0x40 : 0x00) |
   1371 	    ((VSS & 0x200) ? 0x80 : 0x00) );
   1372 
   1373 	WCrt(ba, CRT_ID_MAX_SCAN_LINE,
   1374 	    0x40 |  /* TEXT ? 0x00 ??? */
   1375 	    ((gv->disp_flags & GRF_FLAGS_DBLSCAN) ? 0x80 : 0x00) |
   1376 	    ((VBS & 0x200) ? 0x20 : 0x00) |
   1377 	    (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
   1378 
   1379 	WCrt(ba, CRT_ID_MODE_CONTROL, 0xe3);
   1380 
   1381 	/* text cursor */
   1382 
   1383 	if (TEXT) {
   1384 #if CV_ULCURSOR
   1385 		WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
   1386 		WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
   1387 #else
   1388 		WCrt(ba, CRT_ID_CURSOR_START, 0x00);
   1389 		WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
   1390 #endif
   1391 		WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f);
   1392 
   1393 		WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
   1394 		WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
   1395 	}
   1396 
   1397 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
   1398 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
   1399 
   1400 	WCrt(ba, CRT_ID_START_VER_RETR, VSS);
   1401 	WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f));
   1402 	WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
   1403 	WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
   1404 	WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
   1405 
   1406 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
   1407 	WCrt(ba, CRT_ID_LACE_RETR_START, HT / 2);
   1408 	WCrt(ba, CRT_ID_LACE_CONTROL,
   1409 	    ((gv->disp_flags & GRF_FLAGS_LACE) ? 0x20 : 0x00));
   1410 
   1411 	WGfx(ba, GCT_ID_GRAPHICS_MODE,
   1412 	    ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
   1413 	WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
   1414 
   1415 	WSeq (ba, SEQ_ID_MEMORY_MODE,
   1416 	    ((TEXT || (gv->depth == 1)) ? 0x06 : 0x02));
   1417 
   1418 	vgaw(ba, VDAC_MASK, 0xff);
   1419 
   1420 	/* Blank border */
   1421 	test = RCrt(ba, CRT_ID_BACKWAD_COMP_2);
   1422 	WCrt(ba, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
   1423 
   1424 	sr15 = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);
   1425 	sr15 &= ~0x10;
   1426 	sr18 = RSeq(ba, SEQ_ID_RAMDAC_CNTL);
   1427 	sr18 &= ~0x80;
   1428 	clock_mode = 0x00;
   1429 	cr50 = 0x00;
   1430 
   1431 	test = RCrt(ba, CRT_ID_EXT_MISC_CNTL_2);
   1432 	test &= 0xd;
   1433 
   1434 	/* clear roxxler  byte-swapping... */
   1435 	cv_write_port(0x0040, cv_boardaddr);
   1436 	cv_write_port(0x0020, cv_boardaddr);
   1437 
   1438 	switch (gv->depth) {
   1439 	   case 1:
   1440 	   case 4: /* text */
   1441 		HDE = gv->disp_width / 16;
   1442 		break;
   1443 	   case 8:
   1444 		if (gv->pixel_clock > 80000000) {
   1445 			clock_mode = 0x10 | 0x02;
   1446 			sr15 |= 0x10;
   1447 			sr18 |= 0x80;
   1448 		}
   1449 		HDE = gv->disp_width / 8;
   1450 		cr50 |= 0x00;
   1451 		break;
   1452 	   case 15:
   1453 		cv_write_port (0x8020, cv_boardaddr);
   1454 		clock_mode = 0x30;
   1455 		HDE = gv->disp_width / 4;
   1456 		cr50 |= 0x10;
   1457 		break;
   1458 	   case 16:
   1459 		cv_write_port (0x8020, cv_boardaddr);
   1460 		clock_mode = 0x50;
   1461 		HDE = gv->disp_width / 4;
   1462 		cr50 |= 0x10;
   1463 		break;
   1464 	   case 24: /* this is really 32 Bit on CV64 */
   1465 	   case 32:
   1466 		cv_write_port(0x8040, cv_boardaddr);
   1467 		clock_mode = 0xd0;
   1468 		HDE = (gv->disp_width / 2);
   1469 		cr50 |= 0x30;
   1470 		break;
   1471 	}
   1472 
   1473 	WCrt(ba, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
   1474 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, sr15);
   1475 	WSeq(ba, SEQ_ID_RAMDAC_CNTL, sr18);
   1476 	WCrt(ba, CRT_ID_SCREEN_OFFSET, HDE);
   1477 
   1478 	WCrt(ba, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
   1479 
   1480 	test = RCrt(ba, CRT_ID_EXT_SYS_CNTL_2);
   1481 	test &= ~0x30;
   1482 	/* HDE Overflow in bits 4-5 */
   1483 	test |= (HDE >> 4) & 0x30;
   1484 	WCrt(ba, CRT_ID_EXT_SYS_CNTL_2, test);
   1485 
   1486 	/* Set up graphics engine */
   1487 	switch (gv->disp_width) {
   1488 	   case 1024:
   1489 		cr50 |= 0x00;
   1490 		break;
   1491 	   case 640:
   1492 		cr50 |= 0x40;
   1493 		break;
   1494 	   case 800:
   1495 		cr50 |= 0x80;
   1496 		break;
   1497 	   case 1280:
   1498 		cr50 |= 0xc0;
   1499 		break;
   1500 	   case 1152:
   1501 		cr50 |= 0x01;
   1502 		break;
   1503 	   case 1600:
   1504 		cr50 |= 0x81;
   1505 		break;
   1506 	   default: /* XXX The Xserver has to handle this */
   1507 		break;
   1508 	}
   1509 
   1510 	WCrt(ba, CRT_ID_EXT_SYS_CNTL_1, cr50);
   1511 
   1512 	delay(100000);
   1513 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
   1514 	delay(100000);
   1515 	WAttr(ba, ACT_ID_COLOR_PLANE_ENA,
   1516 	    (gv->depth == 1) ? 0x01 : 0x0f);
   1517 	delay(100000);
   1518 
   1519 	/*
   1520 	 * M-Parameter of Display FIFO
   1521 	 * This is dependant on the pixel clock and the memory clock.
   1522 	 * The FIFO filling bandwidth is 240 MHz  and the FIFO is 96 Byte wide.
   1523 	 * Then the time to fill the FIFO is tfill = (96/240000000) sec, the time
   1524 	 * to empty the FIFO is tempty = (96/pixelclock) sec.
   1525 	 * Then the M parameter maximum is ((tempty-tfill)*cv_memclk-9)/2.
   1526 	 * This seems to be logical, ain't it?
   1527 	 * Remember: We have to use integer arithmetics :(
   1528 	 * Divide by 1000 to prevent overflows.
   1529 	 */
   1530 
   1531 	tfillm = (96 * (cv_memclk/1000))/240000;
   1532 
   1533 	switch(gv->depth) {
   1534 	    case 32:
   1535 	    case 24:
   1536 		temptym = (24 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
   1537 		break;
   1538 	    case 15:
   1539 	    case 16:
   1540 		temptym = (48 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
   1541 		break;
   1542 	    case 4:
   1543 		temptym = (192 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
   1544 		break;
   1545 	    default:
   1546 		temptym = (96 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
   1547 		break;
   1548 	}
   1549 
   1550 	m = (temptym - tfillm - 9) / 2;
   1551 	if (m < 0)
   1552 		m = 0;	/* prevent underflow */
   1553 	m = (m & 0x1f) << 3;
   1554 	if (m < 0x18)
   1555 		m = 0x18;
   1556 	n = 0xff;
   1557 
   1558 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, m);
   1559 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, n);
   1560 	delay(10000);
   1561 
   1562 	/* text initialization */
   1563 
   1564 	if (TEXT) {
   1565 		cv_inittextmode(gp);
   1566 	}
   1567 
   1568 	if (CONSOLE) {
   1569 		int i;
   1570 		vgaw(ba, VDAC_ADDRESS_W, 0);
   1571 		for (i = 0; i < 16; i++) {
   1572 			vgaw(ba, VDAC_DATA, cvconscolors[i][0]);
   1573 			vgaw(ba, VDAC_DATA, cvconscolors[i][1]);
   1574 			vgaw(ba, VDAC_DATA, cvconscolors[i][2]);
   1575 		}
   1576 	}
   1577 
   1578 	/* Set display enable flag */
   1579 	WAttr(ba, 0x33, 0);
   1580 
   1581 	/* turn gfx on again */
   1582 	gfx_on_off(0, ba);
   1583 
   1584 	/* enable interrupts */
   1585 	test = RCrt(ba, CRT_ID_BACKWAD_COMP_1);
   1586 	test |= 0x10;
   1587 	WCrt(ba, CRT_ID_BACKWAD_COMP_1, test);
   1588 
   1589 	test = RCrt(ba, CRT_ID_END_VER_RETR);
   1590 	test &= ~0x20;
   1591 	WCrt(ba, CRT_ID_END_VER_RETR, test);
   1592 	test &= ~0x10;
   1593 	WCrt(ba, CRT_ID_END_VER_RETR, test);
   1594 	test |= 0x10;
   1595 	WCrt(ba, CRT_ID_END_VER_RETR, test);
   1596 #ifndef CV_NO_HARDWARE_CURSOR
   1597 	cv_setup_hwc(gp);
   1598 #endif
   1599 
   1600 	/* Pass-through */
   1601 	cvscreen(0, ba - 0x02000000);
   1602 
   1603 	return (1);
   1604 }
   1605 
   1606 
   1607 void
   1608 cv_inittextmode(struct grf_softc *gp)
   1609 {
   1610 	struct grfcvtext_mode *tm = (struct grfcvtext_mode *)gp->g_data;
   1611 	volatile caddr_t ba, fb;
   1612 	unsigned char *c, *f, y;
   1613 	unsigned short z;
   1614 
   1615 	ba = gp->g_regkva;
   1616 	fb = gp->g_fbkva;
   1617 
   1618 	/* load text font into beginning of display memory.
   1619 	 * Each character cell is 32 bytes long (enough for 4 planes)
   1620 	 * In linear addressing text mode, the memory is organized
   1621 	 * so, that the Bytes of all 4 planes are interleaved.
   1622 	 * 1st byte plane 0, 1st byte plane 1, 1st byte plane 2,
   1623 	 * 1st byte plane 3, 2nd byte plane 0, 2nd byte plane 1,...
   1624 	 * The font is loaded in plane 2.
   1625 	 */
   1626 
   1627 	c = (unsigned char *) fb;
   1628 
   1629 	/* clear screen */
   1630 	for (z = 0; z < tm->cols * tm->rows * 3; z++) {
   1631 		*c++ = 0x20;
   1632 		*c++ = 0x07;
   1633 		*c++ = 0;
   1634 		*c++ = 0;
   1635 	}
   1636 
   1637 	c = (unsigned char *) (fb) + (32 * tm->fdstart * 4 + 2);
   1638 	f = tm->fdata;
   1639 	for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy) * 4)
   1640 		for (y = 0; y < tm->fy; y++) {
   1641 			*c = *f++;
   1642 			c += 4;
   1643 		}
   1644 
   1645 	/* print out a little init msg */
   1646 	c = (unsigned char *)(fb) + (tm->cols - 6) * 4;
   1647 	*c++ = 'C';
   1648 	*c++ = 0x0a;
   1649 	c +=2;
   1650 	*c++ = 'V';
   1651 	*c++ = 0x0b;
   1652 	c +=2;
   1653 	*c++ = '6';
   1654 	*c++ = 0x0c;
   1655 	c +=2;
   1656 	*c++ = '4';
   1657 	*c++ = 0x0d;
   1658 }
   1659 
   1660 
   1661 static __inline void
   1662 cv_write_port(unsigned short bits, volatile caddr_t BoardAddr)
   1663 {
   1664 	volatile caddr_t addr;
   1665 	static unsigned char CVPortBits = 0;	/* mirror port bits here */
   1666 
   1667 	addr = BoardAddr + 0x40001;
   1668 	if (bits & 0x8000)
   1669 		CVPortBits |= bits & 0xFF;	/* Set bits */
   1670 	else {
   1671 		bits = bits & 0xFF;
   1672 		bits = (~bits) & 0xFF ;
   1673 		CVPortBits &= bits;	/* Clear bits */
   1674 	}
   1675 
   1676 	*addr = CVPortBits;
   1677 }
   1678 
   1679 
   1680 /*
   1681  *  Monitor Switch
   1682  *  0 = CyberVision Signal
   1683  *  1 = Amiga Signal,
   1684  * ba = boardaddr
   1685  */
   1686 static __inline void
   1687 cvscreen(int toggle, volatile caddr_t ba)
   1688 {
   1689 
   1690 	if (toggle == 1)
   1691 		cv_write_port (0x10, ba);
   1692 	else
   1693 		cv_write_port (0x8010, ba);
   1694 }
   1695 
   1696 
   1697 /* 0 = on, 1= off */
   1698 /* ba= registerbase */
   1699 static __inline void
   1700 gfx_on_off(int toggle, volatile caddr_t ba)
   1701 {
   1702 	int r;
   1703 
   1704 	toggle &= 0x1;
   1705 	toggle = toggle << 5;
   1706 
   1707 	r = RSeq(ba, SEQ_ID_CLOCKING_MODE);
   1708 	r &= ~0x20;	/* set Bit 5 to 0 */
   1709 
   1710 	WSeq(ba, SEQ_ID_CLOCKING_MODE, r | toggle);
   1711 }
   1712 
   1713 
   1714 #ifndef CV_NO_HARDWARE_CURSOR
   1715 
   1716 static unsigned char cv_hotx = 0, cv_hoty = 0;
   1717 static char cv_cursor_on = 0;
   1718 
   1719 /* Hardware Cursor handling routines */
   1720 
   1721 int
   1722 cv_getspritepos(struct grf_softc *gp, struct grf_position *pos)
   1723 {
   1724 	int hi,lo;
   1725 	volatile caddr_t ba = gp->g_regkva;
   1726 
   1727 	hi = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_HI);
   1728 	lo = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_LO);
   1729 
   1730 	pos->y = (hi << 8) + lo;
   1731 	hi = RCrt(ba, CRT_ID_HWGC_ORIGIN_X_HI);
   1732 	lo = RCrt(ba, CRT_ID_HWGC_ORIGIN_X_LO);
   1733 	pos->x = (hi << 8) + lo;
   1734 	return (0);
   1735 }
   1736 
   1737 
   1738 int
   1739 cv_setspritepos(struct grf_softc *gp, struct grf_position *pos)
   1740 {
   1741 	volatile caddr_t ba = gp->g_regkva;
   1742 	short x, y;
   1743 	static short savex, savey;
   1744 	short xoff, yoff;
   1745 
   1746 	if (pos) {
   1747 		x = pos->x;
   1748 		y = pos->y;
   1749 		savex = x;
   1750 		savey= y;
   1751 	} else { /* restore cursor */
   1752 		x = savex;
   1753 		y = savey;
   1754 	}
   1755 	x -= cv_hotx;
   1756 	y -= cv_hoty;
   1757 	if (x < 0) {
   1758 		xoff = ((-x) & 0xFE);
   1759 		x = 0;
   1760 	} else {
   1761 		xoff = 0;
   1762 	}
   1763 
   1764 	if (y < 0) {
   1765 		yoff = ((-y) & 0xFE);
   1766 		y = 0;
   1767 	} else {
   1768 		yoff = 0;
   1769 	}
   1770 
   1771 	WCrt(ba, CRT_ID_HWGC_ORIGIN_X_HI, (x >> 8));
   1772 	WCrt(ba, CRT_ID_HWGC_ORIGIN_X_LO, (x & 0xff));
   1773 
   1774 	WCrt(ba, CRT_ID_HWGC_ORIGIN_Y_LO, (y & 0xff));
   1775 	WCrt(ba, CRT_ID_HWGC_DSTART_X, xoff);
   1776 	WCrt(ba, CRT_ID_HWGC_DSTART_Y, yoff);
   1777 	WCrt(ba, CRT_ID_HWGC_ORIGIN_Y_HI, (y >> 8));
   1778 
   1779 	return(0);
   1780 }
   1781 
   1782 static __inline short
   1783 M2I(short val)
   1784 {
   1785 	return ( ((val & 0xff00) >> 8) | ((val & 0xff) << 8));
   1786 }
   1787 
   1788 int
   1789 cv_getspriteinfo(struct grf_softc *gp, struct grf_spriteinfo *info)
   1790 {
   1791 	volatile caddr_t ba, fb;
   1792 
   1793 	ba = gp->g_regkva;
   1794 	fb = gp->g_fbkva;
   1795 
   1796 	if (info->set & GRFSPRSET_ENABLE)
   1797 		info->enable = RCrt(ba, CRT_ID_HWGC_MODE) & 0x01;
   1798 
   1799 	if (info->set & GRFSPRSET_POS)
   1800 		cv_getspritepos (gp, &info->pos);
   1801 
   1802 #if 0	/* XXX */
   1803 	if (info->set & GRFSPRSET_SHAPE) {
   1804 		u_char image[512], mask[512];
   1805 		volatile u_long *hwp;
   1806 		u_char *imp, *mp;
   1807 		short row;
   1808 		info->size.x = 64;
   1809 		info->size.y = 64;
   1810 		for (row = 0, hwp = (u_long *)(fb + HWC_OFF),
   1811 		    mp = mask, imp = image;
   1812 		    row < 64;
   1813 		    row++) {
   1814 			u_long bp10, bp20, bp11, bp21;
   1815 			bp10 = *hwp++;
   1816 			bp20 = *hwp++;
   1817 			bp11 = *hwp++;
   1818 			bp21 = *hwp++;
   1819 			M2I (bp10);
   1820 			M2I (bp20);
   1821 			M2I (bp11);
   1822 			M2I (bp21);
   1823 			*imp++ = (~bp10) & bp11;
   1824 			*imp++ = (~bp20) & bp21;
   1825 			*mp++  = (~bp10) | (bp10 & ~bp11);
   1826 			*mp++  = (~bp20) & (bp20 & ~bp21);
   1827 		}
   1828 		copyout (image, info->image, sizeof (image));
   1829 		copyout (mask, info->mask, sizeof (mask));
   1830 	}
   1831 #endif
   1832 	return(0);
   1833 }
   1834 
   1835 
   1836 void
   1837 cv_setup_hwc(struct grf_softc *gp)
   1838 {
   1839 	volatile caddr_t ba = gp->g_regkva;
   1840 	volatile caddr_t hwc;
   1841 	int test;
   1842 
   1843 	if (gp->g_display.gd_planes <= 4)
   1844 		cv_cursor_on = 0;	/* don't enable hwc in text modes */
   1845 	if (cv_cursor_on == 0)
   1846 		return;
   1847 
   1848 	/* reset colour stack */
   1849 #if 0
   1850 	test = RCrt(ba, CRT_ID_HWGC_MODE);
   1851 	__asm __volatile("nop");
   1852 #else
   1853 	/* do it in assembler, the above does't seem to work */
   1854 	__asm __volatile ("moveb #0x45, %1@(0x3d4); \
   1855 		moveb %1@(0x3d5),%0" : "=r" (test) : "a" (ba));
   1856 #endif
   1857 
   1858 	WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
   1859 
   1860 	hwc = ba + CRT_ADDRESS_W;
   1861 	*hwc = 0;
   1862 	*hwc = 0;
   1863 
   1864 #if 0
   1865 	test = RCrt(ba, CRT_ID_HWGC_MODE);
   1866 	__asm __volatile("nop");
   1867 #else
   1868 	/* do it in assembler, the above does't seem to work */
   1869 	__asm __volatile ("moveb #0x45, %1@(0x3d4); \
   1870 		moveb %1@(0x3d5),%0" : "=r" (test) : "a" (ba));
   1871 #endif
   1872 	switch (gp->g_display.gd_planes) {
   1873 	    case 8:
   1874 		WCrt (ba, CRT_ID_HWGC_BG_STACK, 0x1);
   1875 		*hwc = 1;
   1876 		break;
   1877 	    default:
   1878 		WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
   1879 		*hwc = 0xff;
   1880 		*hwc = 0xff;
   1881 	}
   1882 
   1883 	test = HWC_OFF / HWC_SIZE;
   1884 	WCrt (ba, CRT_ID_HWGC_START_AD_HI, (test >> 8));
   1885 	WCrt (ba, CRT_ID_HWGC_START_AD_LO, (test & 0xff));
   1886 
   1887 	WCrt (ba, CRT_ID_HWGC_DSTART_X , 0);
   1888 	WCrt (ba, CRT_ID_HWGC_DSTART_Y , 0);
   1889 
   1890 	WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x10);	/* Cursor X11 Mode */
   1891 	/*
   1892 	 * Put it into Windoze Mode or you'll see sometimes a white stripe
   1893 	 * on the right side (in double clocking modes with a screen bigger
   1894 	 * > 1023 pixels).
   1895 	 */
   1896 	WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x00);	/* Cursor Windoze Mode */
   1897 
   1898 	WCrt (ba, CRT_ID_HWGC_MODE, 0x01);
   1899 }
   1900 
   1901 
   1902 /*
   1903  * This was the reason why you shouldn't use the HWC in the Kernel:(
   1904  * Obsoleted now by use of interrupts :-)
   1905  */
   1906 
   1907 #define VerticalRetraceWait(ba) \
   1908 { \
   1909 	while (vgar(ba, GREG_INPUT_STATUS1_R) == 0x00) ; \
   1910 	while ((vgar(ba, GREG_INPUT_STATUS1_R) & 0x08) == 0x08) ; \
   1911 	while ((vgar(ba, GREG_INPUT_STATUS1_R) & 0x08) == 0x00) ; \
   1912 }
   1913 
   1914 
   1915 int
   1916 cv_setspriteinfo(struct grf_softc *gp, struct grf_spriteinfo *info)
   1917 {
   1918 	volatile caddr_t ba, fb;
   1919 	int depth = gp->g_display.gd_planes;
   1920 
   1921 	ba = gp->g_regkva;
   1922 	fb = gp->g_fbkva;
   1923 
   1924 	if (info->set & GRFSPRSET_SHAPE) {
   1925 		/*
   1926 		 * For an explanation of these weird actions here, see above
   1927 		 * when reading the shape.  We set the shape directly into
   1928 		 * the video memory, there's no reason to keep 1k on the
   1929 		 * kernel stack just as template
   1930 		 */
   1931 		u_char *image, *mask;
   1932 		volatile u_short *hwp;
   1933 		u_char *imp, *mp;
   1934 		unsigned short row;
   1935 
   1936 #ifdef CV_NO_INT
   1937 		/* Cursor off */
   1938 		WCrt (ba, CRT_ID_HWGC_MODE, 0x00);
   1939 
   1940 		/*
   1941 		 * The Trio64 crashes if the cursor data is written
   1942 		 * while the cursor is displayed.
   1943 		 * Sadly, turning the cursor off is not enough.
   1944 		 * What we have to do is:
   1945 		 * 1. Wait for vertical retrace, to make sure no-one
   1946 		 * has moved the cursor in this sync period (because
   1947 		 * another write then would have no effect, argh!).
   1948 		 * 2. Move the cursor off-screen
   1949 		 * 3. Another wait for v. retrace to make sure the cursor
   1950 		 * is really off.
   1951 		 * 4. Write the data, finally.
   1952 		 * (thanks to Harald Koenig for this tip!)
   1953 		 */
   1954 
   1955 		/*
   1956 		 * Remark 06/06/96: Update in interrupt obsoletes this,
   1957 		 * but the warning should stay there!
   1958 		 */
   1959 
   1960 		VerticalRetraceWait(ba);
   1961 
   1962 		WCrt (ba, CRT_ID_HWGC_ORIGIN_X_HI, 0x7);
   1963 		WCrt (ba, CRT_ID_HWGC_ORIGIN_X_LO,  0xff);
   1964 		WCrt (ba, CRT_ID_HWGC_ORIGIN_Y_LO, 0xff);
   1965 		WCrt (ba, CRT_ID_HWGC_DSTART_X, 0x3f);
   1966 		WCrt (ba, CRT_ID_HWGC_DSTART_Y, 0x3f);
   1967 		WCrt (ba, CRT_ID_HWGC_ORIGIN_Y_HI, 0x7);
   1968 #endif	/* CV_NO_INT */
   1969 
   1970 		if (info->size.y > 64)
   1971 			info->size.y = 64;
   1972 		if (info->size.x > 64)
   1973 			info->size.x = 64;
   1974 		if (info->size.x < 32)
   1975 			info->size.x = 32;
   1976 
   1977 		image = malloc(HWC_SIZE, M_TEMP, M_WAITOK);
   1978 		mask  = image + HWC_SIZE/2;
   1979 
   1980 		copyin(info->image, image, info->size.y * info->size.x / 8);
   1981 		copyin(info->mask, mask, info->size.y * info->size.x / 8);
   1982 
   1983 #ifdef CV_NO_INT
   1984 		hwp = (u_short *)(fb  +HWC_OFF);
   1985 
   1986 		/* This is necessary in order not to crash the board */
   1987 		VerticalRetraceWait(ba);
   1988 #else	/* CV_NO_INT */
   1989 		hwp = (u_short *) cv_cursor_storage;
   1990 #endif	/* CV_NO_INT */
   1991 
   1992 		/*
   1993 		 * setting it is slightly more difficult, because we can't
   1994 		 * force the application to not pass a *smaller* than
   1995 		 * supported bitmap
   1996 		 */
   1997 
   1998 		for (row = 0, mp = mask, imp = image;
   1999 		    row < info->size.y; row++) {
   2000 			u_short im1, im2, im3, im4, m1, m2, m3, m4;
   2001 
   2002 			m1  = ~(*(unsigned short *)mp);
   2003 			im1 = *(unsigned short *)imp & *(unsigned short *)mp;
   2004 			mp  += 2;
   2005 			imp += 2;
   2006 
   2007 			m2  = ~(*(unsigned short *)mp);
   2008 			im2 = *(unsigned short *)imp & *(unsigned short *)mp;
   2009 			mp  += 2;
   2010 			imp += 2;
   2011 
   2012 			if (info->size.x > 32) {
   2013 				m3  = ~(*(unsigned short *)mp);
   2014 				im3 = *(unsigned short *)imp & *(unsigned short *)mp;
   2015 				mp  += 2;
   2016 				imp += 2;
   2017 				m4  = ~(*(unsigned short *)mp);
   2018 				im4 = *(unsigned short *)imp & *(unsigned short *)mp;
   2019 				mp  += 2;
   2020 				imp += 2;
   2021 			} else {
   2022 				m3  = 0xffff;
   2023 				im3 = 0;
   2024 				m4  = 0xffff;
   2025 				im4 = 0;
   2026 			}
   2027 
   2028 			switch (depth) {
   2029 			    case 8:
   2030 				*hwp++ = m1;
   2031 				*hwp++ = im1;
   2032 				*hwp++ = m2;
   2033 				*hwp++ = im2;
   2034 				*hwp++ = m3;
   2035 				*hwp++ = im3;
   2036 				*hwp++ = m4;
   2037 				*hwp++ = im4;
   2038 				break;
   2039 			    case 15:
   2040 			    case 16:
   2041 				*hwp++ = M2I(m1);
   2042 				*hwp++ = M2I(im1);
   2043 				*hwp++ = M2I(m2);
   2044 				*hwp++ = M2I(im2);
   2045 				*hwp++ = M2I(m3);
   2046 				*hwp++ = M2I(im3);
   2047 				*hwp++ = M2I(m4);
   2048 				*hwp++ = M2I(im4);
   2049 				break;
   2050 			    case 24:
   2051 			    case 32:
   2052 				*hwp++ = M2I(im1);
   2053 				*hwp++ = M2I(m1);
   2054 				*hwp++ = M2I(im2);
   2055 				*hwp++ = M2I(m2);
   2056 				*hwp++ = M2I(im3);
   2057 				*hwp++ = M2I(m3);
   2058 				*hwp++ = M2I(im4);
   2059 				*hwp++ = M2I(m4);
   2060 				break;
   2061 			}
   2062 		}
   2063 
   2064 		if (depth < 24) {
   2065 			for (; row < 64; row++) {
   2066 				*hwp++ = 0xffff;
   2067 				*hwp++ = 0x0000;
   2068 				*hwp++ = 0xffff;
   2069 				*hwp++ = 0x0000;
   2070 				*hwp++ = 0xffff;
   2071 				*hwp++ = 0x0000;
   2072 				*hwp++ = 0xffff;
   2073 				*hwp++ = 0x0000;
   2074 			}
   2075 		} else {
   2076 			for (; row < 64; row++) {
   2077 				*hwp++ = 0x0000;
   2078 				*hwp++ = 0xffff;
   2079 				*hwp++ = 0x0000;
   2080 				*hwp++ = 0xffff;
   2081 				*hwp++ = 0x0000;
   2082 				*hwp++ = 0xffff;
   2083 				*hwp++ = 0x0000;
   2084 				*hwp++ = 0xffff;
   2085 			}
   2086 		}
   2087 
   2088 		free(image, M_TEMP);
   2089 		/* cv_setup_hwc(gp); */
   2090 		cv_hotx = info->hot.x;
   2091 		cv_hoty = info->hot.y;
   2092 
   2093 #ifdef CV_NO_INT
   2094 		/* One must not write twice per vertical blank :-( */
   2095 		VerticalRetraceWait(ba);
   2096 		cv_setspritepos (gp, &info->pos);
   2097 #else	/* CV_NO_INT */
   2098 		cv_setspritepos (gp, &info->pos);
   2099 		curs_update_flag = 1;
   2100 #endif	/* CV_NO_INT */
   2101 	}
   2102 	if (info->set & GRFSPRSET_CMAP) {
   2103 		volatile caddr_t hwc;
   2104 		int test;
   2105 
   2106 		/* reset colour stack */
   2107 		test = RCrt(ba, CRT_ID_HWGC_MODE);
   2108 		__asm __volatile("nop");
   2109 		switch (depth) {
   2110 		    case 8:
   2111 		    case 15:
   2112 		    case 16:
   2113 			WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
   2114 			hwc = ba + CRT_ADDRESS_W;
   2115 			*hwc = 0;
   2116 			break;
   2117 		    case 32:
   2118 		    case 24:
   2119 			WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
   2120 			hwc = ba + CRT_ADDRESS_W;
   2121 			*hwc = 0;
   2122 			*hwc = 0;
   2123 			break;
   2124 		}
   2125 
   2126 		test = RCrt(ba, CRT_ID_HWGC_MODE);
   2127 		__asm __volatile("nop");
   2128 		switch (depth) {
   2129 		    case 8:
   2130 			WCrt (ba, CRT_ID_HWGC_BG_STACK, 1);
   2131 			hwc = ba + CRT_ADDRESS_W;
   2132 			*hwc = 1;
   2133 			break;
   2134 		    case 15:
   2135 		    case 16:
   2136 			WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
   2137 			hwc = ba + CRT_ADDRESS_W;
   2138 			*hwc = 0xff;
   2139 			break;
   2140 		    case 32:
   2141 		    case 24:
   2142 			WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
   2143 			hwc = ba + CRT_ADDRESS_W;
   2144 			*hwc = 0xff;
   2145 			*hwc = 0xff;
   2146 			break;
   2147 		}
   2148 	}
   2149 
   2150 	if (info->set & GRFSPRSET_ENABLE) {
   2151 		if (info->enable) {
   2152 			cv_cursor_on = 1;
   2153 			cv_setup_hwc(gp);
   2154 			/* WCrt(ba, CRT_ID_HWGC_MODE, 0x01); */
   2155 		} else
   2156 			WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
   2157 	}
   2158 	if (info->set & GRFSPRSET_POS)
   2159 		cv_setspritepos(gp, &info->pos);
   2160 	if (info->set & GRFSPRSET_HOT) {
   2161 
   2162 		cv_hotx = info->hot.x;
   2163 		cv_hoty = info->hot.y;
   2164 		cv_setspritepos (gp, &info->pos);
   2165 	}
   2166 	return(0);
   2167 }
   2168 
   2169 
   2170 int
   2171 cv_getspritemax (struct grf_softc *gp, struct grf_position *pos)
   2172 {
   2173 
   2174 	pos->x = 64;
   2175 	pos->y = 64;
   2176 	return(0);
   2177 }
   2178 
   2179 #endif /* !CV_NO_HARDWARE_CURSOR */
   2180 
   2181 #endif  /* NGRFCV */
   2182