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