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