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