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