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