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