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