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