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