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