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