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