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