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