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