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