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