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