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