xref: /netbsd-src/sys/arch/amiga/dev/grf_cl.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: grf_cl.c,v 1.34 2003/01/01 00:28:58 thorpej Exp $ */
2 
3 /*
4  * Copyright (c) 1997 Klaus Burkert
5  * Copyright (c) 1995 Ezra Story
6  * Copyright (c) 1995 Kari Mettinen
7  * Copyright (c) 1994 Markus Wild
8  * Copyright (c) 1994 Lutz Vieweg
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by Lutz Vieweg.
22  * 4. The name of the author may not be used to endorse or promote products
23  *    derived from this software without specific prior written permission
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 #include "opt_amigacons.h"
37 
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: grf_cl.c,v 1.34 2003/01/01 00:28:58 thorpej Exp $");
40 
41 #include "grfcl.h"
42 #if NGRFCL > 0
43 
44 /*
45  * Graphics routines for Cirrus CL GD 5426 boards,
46  *
47  * This code offers low-level routines to access Cirrus Cl GD 5426
48  * graphics-boards from within NetBSD for the Amiga.
49  * No warranties for any kind of function at all - this
50  * code may crash your hardware and scratch your harddisk.  Use at your
51  * own risk.  Freely distributable.
52  *
53  * Modified for Cirrus CL GD 5426 from
54  * Lutz Vieweg's retina driver by Kari Mettinen 08/94
55  * Contributions by Ill, ScottE, MiL
56  * Extensively hacked and rewritten by Ezra Story (Ezy) 01/95
57  * Picasso/040 patches (wee!) by crest 01/96
58  *
59  * PicassoIV support bz Klaus "crest" Burkert.
60  * Fixed interlace and doublescan, added clockdoubling and
61  * HiColor&TrueColor suuport by crest 01/97
62  *
63  * Thanks to Village Tronic Marketing Gmbh for providing me with
64  * a Picasso-II board.
65  * Thanks for Integrated Electronics Oy Ab for providing me with
66  * Cirrus CL GD 542x family documentation.
67  *
68  * TODO:
69  *    Mouse support (almost there! :-))
70  *    Blitter support
71  *
72  */
73 
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/errno.h>
77 #include <sys/ioctl.h>
78 #include <sys/device.h>
79 #include <sys/malloc.h>
80 
81 #include <machine/cpu.h>
82 #include <dev/cons.h>
83 #include <amiga/dev/itevar.h>
84 #include <amiga/amiga/device.h>
85 #include <amiga/dev/grfioctl.h>
86 #include <amiga/dev/grfvar.h>
87 #include <amiga/dev/grf_clreg.h>
88 #include <amiga/dev/zbusvar.h>
89 
90 int	cl_mondefok(struct grfvideo_mode *);
91 void	cl_boardinit(struct grf_softc *);
92 static void cl_CompFQ(u_int, u_char *, u_char *, u_char *);
93 int	cl_getvmode(struct grf_softc *, struct grfvideo_mode *);
94 int	cl_setvmode(struct grf_softc *, unsigned int);
95 int	cl_toggle(struct grf_softc *, unsigned short);
96 int	cl_getcmap(struct grf_softc *, struct grf_colormap *);
97 int	cl_putcmap(struct grf_softc *, struct grf_colormap *);
98 #ifndef CL5426CONSOLE
99 void	cl_off(struct grf_softc *);
100 #endif
101 void	cl_inittextmode(struct grf_softc *);
102 int	cl_ioctl(register struct grf_softc *, u_long, void *);
103 int	cl_getmousepos(struct grf_softc *, struct grf_position *);
104 int	cl_setmousepos(struct grf_softc *, struct grf_position *);
105 static int cl_setspriteinfo(struct grf_softc *, struct grf_spriteinfo *);
106 int	cl_getspriteinfo(struct grf_softc *, struct grf_spriteinfo *);
107 static int cl_getspritemax(struct grf_softc *, struct grf_position *);
108 int	cl_blank(struct grf_softc *, int *);
109 int	cl_setmonitor(struct grf_softc *, struct grfvideo_mode *);
110 void	cl_writesprpos(volatile char *, short, short);
111 void	writeshifted(volatile char *, char, char);
112 
113 static void	RegWakeup(volatile caddr_t);
114 static void	RegOnpass(volatile caddr_t);
115 static void	RegOffpass(volatile caddr_t);
116 
117 void	grfclattach(struct device *, struct device *, void *);
118 int	grfclprint(void *, const char *);
119 int	grfclmatch(struct device *, struct cfdata *, void *);
120 void	cl_memset(unsigned char *, unsigned char, int);
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 
133 /* Patchable maximum pixel clock */
134 unsigned long cl_maxpixelclock = 86000000;
135 
136 /* Console display definition.
137  *   Default hardcoded text mode.  This grf_cl is set up to
138  *   use one text mode only, and this is it.  You may use
139  *   grfconfig to change the mode after boot.
140  */
141 /* Console font */
142 #ifdef KFONT_8X11
143 #define CIRRUSFONT kernel_font_8x11
144 #define CIRRUSFONTY 11
145 #else
146 #define CIRRUSFONT kernel_font_8x8
147 #define CIRRUSFONTY 8
148 #endif
149 extern unsigned char CIRRUSFONT[];
150 
151 struct grfcltext_mode clconsole_mode = {
152 	{255, "", 25000000, 640, 480, 4, 640/8, 680/8, 768/8, 800/8,
153 	 481, 490, 498, 522, 0},
154 	8, CIRRUSFONTY, 80, 480 / CIRRUSFONTY, CIRRUSFONT, 32, 255
155 };
156 /* Console colors */
157 unsigned char clconscolors[3][3] = {	/* background, foreground, hilite */
158 	{0, 0x40, 0x50}, {152, 152, 152}, {255, 255, 255}
159 };
160 
161 int	cltype = 0;		/* Picasso, Spectrum or Piccolo */
162 int	cl_64bit = 0;		/* PiccoloSD64 or PicassoIV */
163 unsigned char cl_pass_toggle;	/* passthru status tracker */
164 
165 /*
166  * because all 542x-boards have 2 configdev entries, one for
167  * framebuffer mem and the other for regs, we have to hold onto
168  * the pointers globally until we match on both.  This and 'cltype'
169  * are the primary obsticles to multiple board support, but if you
170  * have multiple boards you have bigger problems than grf_cl.
171  */
172 static void *cl_fbaddr = 0;	/* framebuffer */
173 static void *cl_regaddr = 0;	/* registers */
174 static int cl_fbsize;		/* framebuffer size */
175 static int cl_fbautosize;	/* framebuffer autoconfig size */
176 
177 
178 /*
179  * current sprite info, if you add support for multiple boards
180  * make this an array or something
181  */
182 struct grf_spriteinfo cl_cursprite;
183 
184 /* sprite bitmaps in kernel stack, you'll need to arrayize these too if
185  * you add multiple board support
186  */
187 static unsigned char cl_imageptr[8 * 64], cl_maskptr[8 * 64];
188 static unsigned char cl_sprred[2], cl_sprgreen[2], cl_sprblue[2];
189 
190 /* standard driver stuff */
191 CFATTACH_DECL(grfcl, sizeof(struct grf_softc),
192     grfclmatch, grfclattach, NULL, NULL);
193 
194 static struct cfdata *cfdata;
195 
196 int
197 grfclmatch(pdp, cfp, auxp)
198 	struct device *pdp;
199 	struct cfdata *cfp;
200 	void   *auxp;
201 {
202 	struct zbus_args *zap;
203 	static int regprod, fbprod, fbprod2;
204 	int error;
205 
206 	fbprod2 = 0;
207 	zap = auxp;
208 
209 #ifndef CL5426CONSOLE
210 	if (amiga_realconfig == 0)
211 		return (0);
212 #endif
213 
214 	/* Grab the first board we encounter as the preferred one.  This will
215 	 * allow one board to work in a multiple 5426 board system, but not
216 	 * multiple boards at the same time.  */
217 	if (cltype == 0) {
218 		switch (zap->manid) {
219 		    case PICASSO:
220 			switch (zap->prodid) {
221 			    case 11:
222 			    case 12:
223 				regprod = 12;
224 				fbprod = 11;
225 				error = 0;
226 				break;
227 			    case 22:
228 				fbprod2 = 22;
229 				error = 0;
230 				break;
231 			    case 21:
232 			    case 23:
233 				regprod = 23;
234 				fbprod = 21;
235 				cl_64bit = 1;
236 				error = 0;
237 				break;
238 			    case 24:
239 				regprod = 24;
240 				fbprod = 24;
241 				cl_64bit = 1;
242 				error = 0;
243 				break;
244 		    	    default:
245 				error = 1;
246 				break;
247 			}
248 			if (error == 1)
249 			    return (0);
250 			else
251 			    break;
252 		    case SPECTRUM:
253 			if (zap->prodid != 2 && zap->prodid != 1)
254 				return (0);
255 			regprod = 2;
256 			fbprod = 1;
257 			break;
258 		    case PICCOLO:
259 			switch (zap->prodid) {
260 			    case 5:
261 			    case 6:
262 				regprod = 6;
263 				fbprod = 5;
264 				error = 0;
265 				break;
266 			    case 10:
267 			    case 11:
268 				regprod = 11;
269 				fbprod = 10;
270 				cl_64bit = 1;
271 				error = 0;
272 				break;
273 		    	    default:
274 				error = 1;
275 				break;
276 			}
277 			if (error == 1)
278 			    return (0);
279 			else
280 			    break;
281 		    default:
282 			return (0);
283 		}
284 		cltype = zap->manid;
285 	} else {
286 		if (cltype != zap->manid) {
287 			return (0);
288 		}
289 	}
290 
291 	/* Configure either registers or framebuffer in any order */
292 	if ((cltype == PICASSO) && (cl_64bit == 1)) {
293 		switch (zap->prodid) {
294 		    case 21:
295 			cl_fbaddr = zap->va;
296 			cl_fbautosize = zap->size;
297 			break;
298 		    case 22:
299 			cl_fbautosize += zap->size;
300 			break;
301 		    case 23:
302 			cl_regaddr = (void *)((unsigned long)(zap->va) + 0x10000);
303 			break;
304 		    case 24:
305 			cl_regaddr = (void *)((unsigned long)(zap->va) + 0x600000);
306 			/* check for PicassoIV with 64MB config and handle it */
307 			if (zap->size == 0x04000000) {
308 			    cl_fbaddr = (void *)((unsigned long)(zap->va) + 0x02000000);
309 			} else {
310 			    cl_fbaddr = (void *)((unsigned long)(zap->va) + 0x01000000);
311 			}
312 			cl_fbautosize = 0x400000;
313 			break;
314 		    default:
315 			return (0);
316 		}
317 	}
318 	else {
319 		if (zap->prodid == regprod)
320 			cl_regaddr = zap->va;
321 		else
322 			if (zap->prodid == fbprod) {
323 				cl_fbaddr = zap->va;
324 				cl_fbautosize = zap->size;
325 			} else
326 				return (0);
327 	}
328 
329 #ifdef CL5426CONSOLE
330 		if (amiga_realconfig == 0) {
331 			cfdata = cfp;
332 		}
333 #endif
334 
335 	return (1);
336 }
337 
338 void
339 grfclattach(pdp, dp, auxp)
340 	struct device *pdp, *dp;
341 	void   *auxp;
342 {
343 	static struct grf_softc congrf;
344 	struct zbus_args *zap;
345 	struct grf_softc *gp;
346 	static char attachflag = 0;
347 
348 	zap = auxp;
349 
350 	printf("\n");
351 
352 	/* make sure both halves have matched */
353 	if (!cl_regaddr || !cl_fbaddr)
354 		return;
355 
356 	/* do all that messy console/grf stuff */
357 	if (dp == NULL)
358 		gp = &congrf;
359 	else
360 		gp = (struct grf_softc *) dp;
361 
362 	if (dp != NULL && congrf.g_regkva != 0) {
363 		/*
364 		 * inited earlier, just copy (not device struct)
365 		 */
366 		bcopy(&congrf.g_display, &gp->g_display,
367 		    (char *) &gp[1] - (char *) &gp->g_display);
368 	} else {
369 		gp->g_regkva = (volatile caddr_t) cl_regaddr;
370 		gp->g_fbkva = (volatile caddr_t) cl_fbaddr;
371 
372 		gp->g_unit = GRF_CL5426_UNIT;
373 		gp->g_mode = cl_mode;
374 		gp->g_conpri = grfcl_cnprobe();
375 		gp->g_flags = GF_ALIVE;
376 
377 		/* wakeup the board */
378 		cl_boardinit(gp);
379 #ifdef CL5426CONSOLE
380 		grfcl_iteinit(gp);
381 		(void) cl_load_mon(gp, &clconsole_mode);
382 #endif
383 
384 	}
385 
386 	/*
387 	 * attach grf (once)
388 	 */
389 	if (amiga_config_found(cfdata, &gp->g_device, gp, grfclprint)) {
390 		attachflag = 1;
391 		printf("grfcl: %dMB ", cl_fbsize / 0x100000);
392 		switch (cltype) {
393 		    case PICASSO:
394 			if (cl_64bit == 1) {
395 				printf("Picasso IV");
396 				/* 135MHz will be supported if we
397 				 * have a palette doubling mode.
398 				 */
399 				cl_maxpixelclock = 86000000;
400 			}
401 			else {
402 				printf("Picasso II");
403 
404 				/* check for PicassoII+ (crest) */
405 				if(zap->serno == 0x00100000)
406 				    printf("+");
407 
408 				/* determine used Gfx/chipset (crest) */
409 				vgaw(gp->g_regkva, CRT_ADDRESS, 0x27); /* Chip ID */
410 				switch(vgar(gp->g_regkva, CRT_ADDRESS_R)>>2) {
411 				    case 0x24:
412 					printf(" (with CL-GD5426)");
413 					break;
414 				    case 0x26:
415 					printf(" (with CL-GD5428)");
416 					break;
417 				    case 0x27:
418 					printf(" (with CL-GD5429)");
419 					break;
420 				}
421 	                        cl_maxpixelclock = 86000000;
422 			}
423 			break;
424 		    case SPECTRUM:
425 			printf("Spectrum");
426                         cl_maxpixelclock = 90000000;
427 			break;
428 		    case PICCOLO:
429 			if (cl_64bit == 1) {
430 				printf("Piccolo SD64");
431 				/* 110MHz will be supported if we
432 				 * have a palette doubling mode.
433 				 */
434 				cl_maxpixelclock = 90000000;
435 			} else {
436 				printf("Piccolo");
437 				cl_maxpixelclock = 90000000;
438 			}
439 			break;
440 		}
441 		printf(" being used\n");
442 #ifdef CL_OVERCLOCK
443                 cl_maxpixelclock = 115000000;
444 #endif
445 	} else {
446 		if (!attachflag)
447 			printf("grfcl unattached!!\n");
448 	}
449 }
450 
451 int
452 grfclprint(auxp, pnp)
453 	void   *auxp;
454 	const char *pnp;
455 {
456 	if (pnp)
457 		aprint_normal("ite at %s: ", pnp);
458 	return (UNCONF);
459 }
460 
461 void
462 cl_boardinit(gp)
463 	struct grf_softc *gp;
464 {
465 	unsigned char *ba = gp->g_regkva;
466 	int     x;
467 
468 	if ((cltype == PICASSO) && (cl_64bit == 1)) { /* PicassoIV */
469 		WCrt(ba, 0x51, 0x00);		/* disable capture (FlickerFixer) */
470 		delay(200000);		/* wait some time (two frames as of now) */
471 		WGfx(ba, 0x2f, 0x00);			/* get Blitter into 542x  */
472 		WGfx(ba, GCT_ID_RESERVED, 0x00);	/* compatibility mode     */
473 		WGfx(ba, GCT_ID_BLT_STAT_START, 0x00);	/* or at least, try so... */
474 		cl_fbsize = cl_fbautosize;
475 	} else {
476 
477 		/* wakeup board and flip passthru OFF */
478 		RegWakeup(ba);
479 		RegOnpass(ba);
480 
481 		vgaw(ba, 0x46e8, 0x16);
482 		vgaw(ba, 0x102, 1);
483 		vgaw(ba, 0x46e8, 0x0e);
484 		if (cl_64bit != 1)
485 			vgaw(ba, 0x3c3, 1);
486 
487 		cl_fbsize = cl_fbautosize;
488 
489 		/* setup initial unchanging parameters */
490 
491 		WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x21);	/* 8 dot - display off */
492 		vgaw(ba, GREG_MISC_OUTPUT_W, 0xed);	/* mem disable */
493 
494 		WGfx(ba, GCT_ID_OFFSET_1, 0xec);	/* magic cookie */
495 		WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x12);	/* yum! cookies! */
496 
497 		if (cl_64bit == 1) {
498 			WSeq(ba, SEQ_ID_CONF_RBACK, 0x00);
499 			WSeq(ba, SEQ_ID_DRAM_CNTL, (cl_fbsize / 0x100000 == 2) ? 0x38 : 0xb8);
500 		} else {
501 			WSeq(ba, SEQ_ID_DRAM_CNTL, 0xb0);
502 		}
503 		WSeq(ba, SEQ_ID_RESET, 0x03);
504 		WSeq(ba, SEQ_ID_MAP_MASK, 0xff);
505 		WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
506 		WSeq(ba, SEQ_ID_MEMORY_MODE, 0x0e);	/* a or 6? */
507 		WSeq(ba, SEQ_ID_EXT_SEQ_MODE, (cltype == PICASSO) ? 0x21 : 0x81);
508 		WSeq(ba, SEQ_ID_EEPROM_CNTL, 0x00);
509 		if (cl_64bit == 1)
510 			WSeq(ba, SEQ_ID_PERF_TUNE, 0x5a);
511 		else
512 			WSeq(ba, SEQ_ID_PERF_TUNE, 0x0a);	/* mouse 0a fa */
513 		WSeq(ba, SEQ_ID_SIG_CNTL, 0x02);
514 		WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x04);
515 
516 		if (cl_64bit == 1)
517 			WSeq(ba, SEQ_ID_MCLK_SELECT, 0x1c);
518 		else
519 		WSeq(ba, SEQ_ID_MCLK_SELECT, 0x22);
520 
521 		WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00);
522 		WCrt(ba, CRT_ID_CURSOR_START, 0x00);
523 		WCrt(ba, CRT_ID_CURSOR_END, 0x08);
524 		WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
525 		WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
526 		WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
527 		WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
528 
529 		WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x07);
530 		WCrt(ba, CRT_ID_MODE_CONTROL, 0xe3);
531 		WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);	/* ff */
532 		WCrt(ba, CRT_ID_EXT_DISP_CNTL, 0x22);
533 		if (cl_64bit == 1) {
534 			WCrt(ba, CRT_ID_SYNC_ADJ_GENLOCK, 0x00);
535 			WCrt(ba, CRT_ID_OVERLAY_EXT_CTRL_REG, 0x40);
536 		}
537 		WSeq(ba, SEQ_ID_CURSOR_STORE, 0x3c);	/* mouse 0x00 */
538 
539 		WGfx(ba, GCT_ID_SET_RESET, 0x00);
540 		WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x00);
541 		WGfx(ba, GCT_ID_DATA_ROTATE, 0x00);
542 		WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
543 		WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x00);
544 		WGfx(ba, GCT_ID_MISC, 0x01);
545 		WGfx(ba, GCT_ID_COLOR_XCARE, 0x0f);
546 		WGfx(ba, GCT_ID_BITMASK, 0xff);
547 		WGfx(ba, GCT_ID_MODE_EXT, 0x28);
548 
549 		for (x = 0; x < 0x10; x++)
550 			WAttr(ba, x, x);
551 		WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x01);
552 		WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x00);
553 		WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0f);
554 		WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x00);
555 		WAttr(ba, ACT_ID_COLOR_SELECT, 0x00);
556 		WAttr(ba, 0x34, 0x00);
557 
558 		vgaw(ba, VDAC_MASK, 0xff);
559 		vgaw(ba, GREG_MISC_OUTPUT_W, 0xef);
560 
561 		WGfx(ba, GCT_ID_BLT_STAT_START, 0x04);
562 		WGfx(ba, GCT_ID_BLT_STAT_START, 0x00);
563 	}
564 
565 	/* colors initially set to greyscale */
566 	vgaw(ba, VDAC_ADDRESS_W, 0);
567 	for (x = 255; x >= 0; x--) {
568 		vgaw(ba, VDAC_DATA, x);
569 		vgaw(ba, VDAC_DATA, x);
570 		vgaw(ba, VDAC_DATA, x);
571 	}
572 	/* set sprite bitmap pointers */
573 	cl_cursprite.image = cl_imageptr;
574 	cl_cursprite.mask = cl_maskptr;
575 	cl_cursprite.cmap.red = cl_sprred;
576 	cl_cursprite.cmap.green = cl_sprgreen;
577 	cl_cursprite.cmap.blue = cl_sprblue;
578 
579 	if (cl_64bit == 0) {
580 
581 		/* check for 1MB or 2MB board (crest) */
582 		volatile unsigned long *cl_fbtestaddr;
583 		cl_fbtestaddr = (volatile unsigned long *)gp->g_fbkva;
584 
585 		WGfx(ba, GCT_ID_OFFSET_0, 0x40);
586 		*cl_fbtestaddr = 0x12345678;
587 
588 		if (*cl_fbtestaddr != 0x12345678) {
589 			WSeq(ba, SEQ_ID_DRAM_CNTL, 0x30);
590 			cl_fbsize = 0x100000;
591 		}
592 		else
593 		{
594 			cl_fbsize = 0x200000;
595 		}
596 	}
597 	WGfx(ba, GCT_ID_OFFSET_0, 0x00);
598 }
599 
600 
601 int
602 cl_getvmode(gp, vm)
603 	struct grf_softc *gp;
604 	struct grfvideo_mode *vm;
605 {
606 	struct grfvideo_mode *gv;
607 
608 #ifdef CL5426CONSOLE
609 	/* Handle grabbing console mode */
610 	if (vm->mode_num == 255) {
611 		bcopy(&clconsole_mode, vm, sizeof(struct grfvideo_mode));
612 		/* XXX so grfconfig can tell us the correct text dimensions. */
613 		vm->depth = clconsole_mode.fy;
614 	} else
615 #endif
616         {
617                 if (vm->mode_num == 0)
618                         vm->mode_num = (monitor_current - monitor_def) + 1;
619                 if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
620                         return (EINVAL);
621                 gv = monitor_def + (vm->mode_num - 1);
622                 if (gv->mode_num == 0)
623                         return (EINVAL);
624 
625                 bcopy(gv, vm, sizeof(struct grfvideo_mode));
626         }
627 
628         /* adjust internal values to pixel values */
629 
630         vm->hblank_start *= 8;
631         vm->hsync_start *= 8;
632         vm->hsync_stop *= 8;
633         vm->htotal *= 8;
634 
635 	return (0);
636 }
637 
638 
639 int
640 cl_setvmode(gp, mode)
641 	struct grf_softc *gp;
642 	unsigned mode;
643 {
644 	if (!mode || (mode > monitor_def_max) ||
645 	    monitor_def[mode - 1].mode_num == 0)
646 		return (EINVAL);
647 
648 	monitor_current = monitor_def + (mode - 1);
649 
650 	return (0);
651 }
652 
653 #ifndef CL5426CONSOLE
654 void
655 cl_off(gp)
656 	struct grf_softc *gp;
657 {
658 	char   *ba = gp->g_regkva;
659 
660 	/*
661 	 * we'll put the pass-through on for cc ite and set Full Bandwidth bit
662 	 * on just in case it didn't work...but then it doesn't matter does
663 	 * it? =)
664 	 */
665 	RegOnpass(ba);
666 	vgaw(ba, SEQ_ADDRESS, SEQ_ID_CLOCKING_MODE);
667 	vgaw(ba, SEQ_ADDRESS_W, vgar(ba, SEQ_ADDRESS_W) | 0x20);
668 }
669 #endif
670 
671 int
672 cl_blank(gp, on)
673         struct grf_softc *gp;
674         int *on;
675 {
676         WSeq(gp->g_regkva, SEQ_ID_CLOCKING_MODE, *on > 0 ? 0x01 : 0x21);
677         return(0);
678 }
679 
680 /*
681  * Change the mode of the display.
682  * Return a UNIX error number or 0 for success.
683  */
684 int
685 cl_mode(gp, cmd, arg, a2, a3)
686 	register struct grf_softc *gp;
687 	u_long cmd;
688 	void *arg;
689 	u_long a2;
690 	int a3;
691 {
692 	int     error;
693 
694 	switch (cmd) {
695 	    case GM_GRFON:
696 		error = cl_load_mon(gp,
697 		    (struct grfcltext_mode *) monitor_current) ? 0 : EINVAL;
698 		return (error);
699 
700 	    case GM_GRFOFF:
701 #ifndef CL5426CONSOLE
702 		cl_off(gp);
703 #else
704 		cl_load_mon(gp, &clconsole_mode);
705 #endif
706 		return (0);
707 
708 	    case GM_GRFCONFIG:
709 		return (0);
710 
711 	    case GM_GRFGETVMODE:
712 		return (cl_getvmode(gp, (struct grfvideo_mode *) arg));
713 
714 	    case GM_GRFSETVMODE:
715 		error = cl_setvmode(gp, *(unsigned *) arg);
716 		if (!error && (gp->g_flags & GF_GRFON))
717 			cl_load_mon(gp,
718 			    (struct grfcltext_mode *) monitor_current);
719 		return (error);
720 
721 	    case GM_GRFGETNUMVM:
722 		*(int *) arg = monitor_def_max;
723 		return (0);
724 
725 	    case GM_GRFIOCTL:
726 		return (cl_ioctl(gp, a2, arg));
727 
728 	    default:
729 		break;
730 	}
731 
732 	return (EPASSTHROUGH);
733 }
734 
735 int
736 cl_ioctl(gp, cmd, data)
737 	register struct grf_softc *gp;
738 	u_long cmd;
739 	void   *data;
740 {
741 	switch (cmd) {
742 	    case GRFIOCGSPRITEPOS:
743 		return (cl_getmousepos(gp, (struct grf_position *) data));
744 
745 	    case GRFIOCSSPRITEPOS:
746 		return (cl_setmousepos(gp, (struct grf_position *) data));
747 
748 	    case GRFIOCSSPRITEINF:
749 		return (cl_setspriteinfo(gp, (struct grf_spriteinfo *) data));
750 
751 	    case GRFIOCGSPRITEINF:
752 		return (cl_getspriteinfo(gp, (struct grf_spriteinfo *) data));
753 
754 	    case GRFIOCGSPRITEMAX:
755 		return (cl_getspritemax(gp, (struct grf_position *) data));
756 
757 	    case GRFIOCGETCMAP:
758 		return (cl_getcmap(gp, (struct grf_colormap *) data));
759 
760 	    case GRFIOCPUTCMAP:
761 		return (cl_putcmap(gp, (struct grf_colormap *) data));
762 
763 	    case GRFIOCBITBLT:
764 		break;
765 
766 	    case GRFTOGGLE:
767 		return (cl_toggle(gp, 0));
768 
769 	    case GRFIOCSETMON:
770 		return (cl_setmonitor(gp, (struct grfvideo_mode *) data));
771 
772             case GRFIOCBLANK:
773                 return (cl_blank(gp, (int *)data));
774 
775 	}
776 	return (EPASSTHROUGH);
777 }
778 
779 int
780 cl_getmousepos(gp, data)
781 	struct grf_softc *gp;
782 	struct grf_position *data;
783 {
784 	data->x = cl_cursprite.pos.x;
785 	data->y = cl_cursprite.pos.y;
786 	return (0);
787 }
788 
789 void
790 cl_writesprpos(ba, x, y)
791 	volatile char *ba;
792 	short   x;
793 	short   y;
794 {
795 	/* we want to use a 16-bit write to 3c4 so no macros used */
796 	volatile unsigned char *cwp;
797         volatile unsigned short *wp;
798 
799 	cwp = ba + 0x3c4;
800         wp = (unsigned short *)cwp;
801 
802 	/*
803 	 * don't ask me why, but apparently you can't do a 16-bit write with
804 	 * x-position like with y-position below (dagge)
805 	 */
806         cwp[0] = 0x10 | ((x << 5) & 0xff);
807         cwp[1] = (x >> 3) & 0xff;
808 
809         *wp = 0x1100 | ((y & 7) << 13) | ((y >> 3) & 0xff);
810 }
811 
812 void
813 writeshifted(to, shiftx, shifty)
814 	volatile char *to;
815 	char    shiftx;
816 	char    shifty;
817 {
818 	int y;
819 	unsigned long long *tptr, *iptr, *mptr, line;
820 
821 	tptr = (unsigned long long *) to;
822         iptr = (unsigned long long *) cl_cursprite.image;
823         mptr = (unsigned long long *) cl_cursprite.mask;
824 
825         shiftx = shiftx < 0 ? 0 : shiftx;
826         shifty = shifty < 0 ? 0 : shifty;
827 
828         /* start reading shifty lines down, and
829          * shift each line in by shiftx
830          */
831         for (y = shifty; y < 64; y++) {
832 
833                 /* image */
834                 line = iptr[y];
835 		*tptr++ = line << shiftx;
836 
837                 /* mask */
838                 line = mptr[y];
839 		*tptr++ = line << shiftx;
840 	}
841 
842         /* clear the remainder */
843         for (y = shifty; y > 0; y--) {
844                 *tptr++ = 0;
845                 *tptr++ = 0;
846         }
847 }
848 
849 int
850 cl_setmousepos(gp, data)
851 	struct grf_softc *gp;
852 	struct grf_position *data;
853 {
854 	volatile char *ba = gp->g_regkva;
855         short rx, ry, prx, pry;
856 #ifdef CL_SHIFTSPRITE
857 	volatile char *fb = gp->g_fbkva;
858         volatile char *sprite = fb + (cl_fbsize - 1024);
859 #endif
860 
861         /* no movement */
862 	if (cl_cursprite.pos.x == data->x && cl_cursprite.pos.y == data->y)
863 		return (0);
864 
865         /* current and previous real coordinates */
866 	rx = data->x - cl_cursprite.hot.x;
867 	ry = data->y - cl_cursprite.hot.y;
868 	prx = cl_cursprite.pos.x - cl_cursprite.hot.x;
869 	pry = cl_cursprite.pos.y - cl_cursprite.hot.y;
870 
871         /*
872 	 * if we are/were on an edge, create (un)shifted bitmap --
873          * ripped out optimization (not extremely worthwhile,
874          * and kind of buggy anyhow).
875          */
876 #ifdef CL_SHIFTSPRITE
877         if (rx < 0 || ry < 0 || prx < 0 || pry < 0) {
878                 writeshifted(sprite, rx < 0 ? -rx : 0, ry < 0 ? -ry : 0);
879         }
880 #endif
881 
882         /* do movement, save position */
883         cl_writesprpos(ba, rx < 0 ? 0 : rx, ry < 0 ? 0 : ry);
884 	cl_cursprite.pos.x = data->x;
885 	cl_cursprite.pos.y = data->y;
886 
887 	return (0);
888 }
889 
890 int
891 cl_getspriteinfo(gp, data)
892 	struct grf_softc *gp;
893 	struct grf_spriteinfo *data;
894 {
895 	copyout(&cl_cursprite, data, sizeof(struct grf_spriteinfo));
896 	copyout(cl_cursprite.image, data->image, 64 * 8);
897 	copyout(cl_cursprite.mask, data->mask, 64 * 8);
898 	return (0);
899 }
900 
901 static int
902 cl_setspriteinfo(gp, data)
903 	struct grf_softc *gp;
904 	struct grf_spriteinfo *data;
905 {
906 	volatile unsigned char *ba = gp->g_regkva, *fb = gp->g_fbkva;
907         volatile char *sprite = fb + (cl_fbsize - 1024);
908 
909 	if (data->set & GRFSPRSET_SHAPE) {
910 
911                 unsigned short dsx, dsy, i;
912                 unsigned long *di, *dm, *si, *sm;
913                 unsigned long ssi[128], ssm[128];
914                 struct grf_position gpos;
915 
916 
917                 /* check for a too large sprite (no clipping!) */
918                 dsy = data->size.y;
919                 dsx = data->size.x;
920                 if (dsy > 64 || dsx > 64)
921                         return(EINVAL);
922 
923                 /* prepare destination */
924                 di = (unsigned long *)cl_cursprite.image;
925                 dm = (unsigned long *)cl_cursprite.mask;
926                 cl_memset((unsigned char *)di, 0, 8*64);
927                 cl_memset((unsigned char *)dm, 0, 8*64);
928 
929                 /* two alternatives:  64 across, then it's
930                  * the same format we use, just copy.  Otherwise,
931                  * copy into tmp buf and recopy skipping the
932                  * unused 32 bits.
933                  */
934                 if ((dsx - 1) / 32) {
935                         copyin(data->image, di, 8 * dsy);
936                         copyin(data->mask, dm, 8 * dsy);
937                 } else {
938                         si = ssi; sm = ssm;
939                         copyin(data->image, si, 4 * dsy);
940                         copyin(data->mask, sm, 4 * dsy);
941                         for (i = 0; i < dsy; i++) {
942                                 *di = *si++;
943                                 *dm = *sm++;
944                                 di += 2;
945                                 dm += 2;
946                         }
947                 }
948 
949                 /* set size */
950 		cl_cursprite.size.x = data->size.x;
951 		cl_cursprite.size.y = data->size.y;
952 
953                 /* forcably load into board */
954                 gpos.x = cl_cursprite.pos.x;
955                 gpos.y = cl_cursprite.pos.y;
956                 cl_cursprite.pos.x = -1;
957                 cl_cursprite.pos.y = -1;
958                 writeshifted(sprite, 0, 0);
959                 cl_setmousepos(gp, &gpos);
960 
961 	}
962 	if (data->set & GRFSPRSET_HOT) {
963 
964 		cl_cursprite.hot = data->hot;
965 
966 	}
967 	if (data->set & GRFSPRSET_CMAP) {
968 
969 		u_char  red[2], green[2], blue[2];
970 
971 		copyin(data->cmap.red, red, 2);
972 		copyin(data->cmap.green, green, 2);
973 		copyin(data->cmap.blue, blue, 2);
974 		bcopy(red, cl_cursprite.cmap.red, 2);
975 		bcopy(green, cl_cursprite.cmap.green, 2);
976 		bcopy(blue, cl_cursprite.cmap.blue, 2);
977 
978                 /* enable and load colors 256 & 257 */
979 		WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x06);
980 
981                 /* 256 */
982 		vgaw(ba, VDAC_ADDRESS_W, 0x00);
983 		if (cltype == PICASSO) {
984 			vgaw(ba, VDAC_DATA, (u_char) (red[0] >> 2));
985 			vgaw(ba, VDAC_DATA, (u_char) (green[0] >> 2));
986 			vgaw(ba, VDAC_DATA, (u_char) (blue[0] >> 2));
987 		} else {
988 			vgaw(ba, VDAC_DATA, (u_char) (blue[0] >> 2));
989 			vgaw(ba, VDAC_DATA, (u_char) (green[0] >> 2));
990 			vgaw(ba, VDAC_DATA, (u_char) (red[0] >> 2));
991 		}
992 
993                 /* 257 */
994 		vgaw(ba, VDAC_ADDRESS_W, 0x0f);
995 		if (cltype == PICASSO) {
996 			vgaw(ba, VDAC_DATA, (u_char) (red[1] >> 2));
997 			vgaw(ba, VDAC_DATA, (u_char) (green[1] >> 2));
998 			vgaw(ba, VDAC_DATA, (u_char) (blue[1] >> 2));
999 		} else {
1000 			vgaw(ba, VDAC_DATA, (u_char) (blue[1] >> 2));
1001 			vgaw(ba, VDAC_DATA, (u_char) (green[1] >> 2));
1002 			vgaw(ba, VDAC_DATA, (u_char) (red[1] >> 2));
1003 		}
1004 
1005                 /* turn on/off sprite */
1006 		if (cl_cursprite.enable) {
1007 			WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x05);
1008 		} else {
1009 			WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x04);
1010 		}
1011 
1012 	}
1013 	if (data->set & GRFSPRSET_ENABLE) {
1014 
1015 		if (data->enable == 1) {
1016 			WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x05);
1017 			cl_cursprite.enable = 1;
1018 		} else {
1019 			WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x04);
1020 			cl_cursprite.enable = 0;
1021 		}
1022 
1023 	}
1024 	if (data->set & GRFSPRSET_POS) {
1025 
1026                 /* force placement */
1027                 cl_cursprite.pos.x = -1;
1028                 cl_cursprite.pos.y = -1;
1029 
1030                 /* do it */
1031                 cl_setmousepos(gp, &data->pos);
1032 
1033 	}
1034 	return (0);
1035 }
1036 
1037 static int
1038 cl_getspritemax(gp, data)
1039 	struct grf_softc *gp;
1040 	struct grf_position *data;
1041 {
1042 	if (gp->g_display.gd_planes == 24)
1043 		return (EINVAL);
1044 	data->x = 64;
1045 	data->y = 64;
1046 	return (0);
1047 }
1048 
1049 int
1050 cl_setmonitor(gp, gv)
1051 	struct grf_softc *gp;
1052 	struct grfvideo_mode *gv;
1053 {
1054 	struct grfvideo_mode *md;
1055 
1056         if (!cl_mondefok(gv))
1057                 return(EINVAL);
1058 
1059 #ifdef CL5426CONSOLE
1060 	/* handle interactive setting of console mode */
1061 	if (gv->mode_num == 255) {
1062 		bcopy(gv, &clconsole_mode.gv, sizeof(struct grfvideo_mode));
1063 		clconsole_mode.gv.hblank_start /= 8;
1064 		clconsole_mode.gv.hsync_start /= 8;
1065 		clconsole_mode.gv.hsync_stop /= 8;
1066 		clconsole_mode.gv.htotal /= 8;
1067 		clconsole_mode.rows = gv->disp_height / clconsole_mode.fy;
1068 		clconsole_mode.cols = gv->disp_width / clconsole_mode.fx;
1069 		if (!(gp->g_flags & GF_GRFON))
1070 			cl_load_mon(gp, &clconsole_mode);
1071 		ite_reinit(gp->g_itedev);
1072 		return (0);
1073 	}
1074 #endif
1075 
1076 	md = monitor_def + (gv->mode_num - 1);
1077 	bcopy(gv, md, sizeof(struct grfvideo_mode));
1078 
1079 	/* adjust pixel oriented values to internal rep. */
1080 
1081 	md->hblank_start /= 8;
1082 	md->hsync_start /= 8;
1083 	md->hsync_stop /= 8;
1084 	md->htotal /= 8;
1085 
1086 	return (0);
1087 }
1088 
1089 int
1090 cl_getcmap(gfp, cmap)
1091 	struct grf_softc *gfp;
1092 	struct grf_colormap *cmap;
1093 {
1094 	volatile unsigned char *ba;
1095 	u_char  red[256], green[256], blue[256], *rp, *gp, *bp;
1096 	short   x;
1097 	int     error;
1098 
1099 	if (cmap->count == 0 || cmap->index >= 256)
1100 		return 0;
1101 
1102 	if (cmap->count > 256 - cmap->index)
1103 		cmap->count = 256 - cmap->index;
1104 
1105 	ba = gfp->g_regkva;
1106 	/* first read colors out of the chip, then copyout to userspace */
1107 	vgaw(ba, VDAC_ADDRESS_R, cmap->index);
1108 	x = cmap->count - 1;
1109 
1110 /*
1111  * Some sort 'o Magic. Spectrum has some changes on the board to speed
1112  * up 15 and 16Bit modes. They can access these modes with easy-to-programm
1113  * rgbrgbrgb instead of rrrgggbbb. Side effect: when in 8Bit mode, rgb
1114  * is swapped to bgr. I wonder if we need to check for 8Bit though, ill
1115  */
1116 
1117 /*
1118  * The source for the above comment is somewhat unknow to me.
1119  * The Spectrum, Piccolo and PiccoloSD64 have the analog Red and Blue
1120  * lines swapped. In 24BPP this provides RGB instead of BGR as it would
1121  * be native to the chipset. This requires special programming for the
1122  * CLUT in 8BPP to compensate and avoid false colors.
1123  * I didn't find any special stuff for 15 and 16BPP though, crest.
1124  */
1125 
1126 	switch (cltype) {
1127 	    case SPECTRUM:
1128 	    case PICCOLO:
1129 		rp = blue + cmap->index;
1130 		gp = green + cmap->index;
1131 		bp = red + cmap->index;
1132 		break;
1133 	    case PICASSO:
1134 		rp = red + cmap->index;
1135 		gp = green + cmap->index;
1136 		bp = blue + cmap->index;
1137 		break;
1138 	    default:
1139 		rp = gp = bp = 0;
1140 		break;
1141 	}
1142 
1143 	do {
1144 		*rp++ = vgar(ba, VDAC_DATA) << 2;
1145 		*gp++ = vgar(ba, VDAC_DATA) << 2;
1146 		*bp++ = vgar(ba, VDAC_DATA) << 2;
1147 	} while (x-- > 0);
1148 
1149 	if (!(error = copyout(red + cmap->index, cmap->red, cmap->count))
1150 	    && !(error = copyout(green + cmap->index, cmap->green, cmap->count))
1151 	    && !(error = copyout(blue + cmap->index, cmap->blue, cmap->count)))
1152 		return (0);
1153 
1154 	return (error);
1155 }
1156 
1157 int
1158 cl_putcmap(gfp, cmap)
1159 	struct grf_softc *gfp;
1160 	struct grf_colormap *cmap;
1161 {
1162 	volatile unsigned char *ba;
1163 	u_char  red[256], green[256], blue[256], *rp, *gp, *bp;
1164 	short   x;
1165 	int     error;
1166 
1167 	if (cmap->count == 0 || cmap->index >= 256)
1168 		return (0);
1169 
1170 	if (cmap->count > 256 - cmap->index)
1171 		cmap->count = 256 - cmap->index;
1172 
1173 	/* first copy the colors into kernelspace */
1174 	if (!(error = copyin(cmap->red, red + cmap->index, cmap->count))
1175 	    && !(error = copyin(cmap->green, green + cmap->index, cmap->count))
1176 	    && !(error = copyin(cmap->blue, blue + cmap->index, cmap->count))) {
1177 		ba = gfp->g_regkva;
1178 		vgaw(ba, VDAC_ADDRESS_W, cmap->index);
1179 		x = cmap->count - 1;
1180 
1181 		switch (cltype) {
1182 		    case SPECTRUM:
1183 		    case PICCOLO:
1184 			rp = blue + cmap->index;
1185 			gp = green + cmap->index;
1186 			bp = red + cmap->index;
1187 			break;
1188 		    case PICASSO:
1189 			rp = red + cmap->index;
1190 			gp = green + cmap->index;
1191 			bp = blue + cmap->index;
1192 			break;
1193 		    default:
1194 			rp = gp = bp = 0;
1195 			break;
1196 		}
1197 
1198 		do {
1199 			vgaw(ba, VDAC_DATA, *rp++ >> 2);
1200 			vgaw(ba, VDAC_DATA, *gp++ >> 2);
1201 			vgaw(ba, VDAC_DATA, *bp++ >> 2);
1202 		} while (x-- > 0);
1203 		return (0);
1204 	} else
1205 		return (error);
1206 }
1207 
1208 
1209 int
1210 cl_toggle(gp, wopp)
1211 	struct grf_softc *gp;
1212 	unsigned short wopp;	/* don't need that one yet, ill */
1213 {
1214 	volatile caddr_t ba;
1215 
1216 	ba = gp->g_regkva;
1217 
1218 	if (cl_pass_toggle) {
1219 		RegOffpass(ba);
1220 	} else {
1221 		RegOnpass(ba);
1222 	}
1223 	return (0);
1224 }
1225 
1226 static void
1227 cl_CompFQ(fq, num, denom, clkdoub)
1228 	u_int   fq;
1229 	u_char *num;
1230 	u_char *denom;
1231 	u_char *clkdoub;
1232 {
1233 #define OSC     14318180
1234 /* OK, here's what we're doing here:
1235  *
1236  *             OSC * NUMERATOR
1237  *      VCLK = -------------------  Hz
1238  *             DENOMINATOR * (1+P)
1239  *
1240  * so we're given VCLK and we should give out some useful
1241  * values....
1242  *
1243  * NUMERATOR is 7 bits wide
1244  * DENOMINATOR is 5 bits wide with bit P in the same char as bit 0.
1245  *
1246  * We run through all the possible combinations and
1247  * return the values which deviate the least from the chosen frequency.
1248  *
1249  */
1250 #define OSC     14318180
1251 #define count(n,d,p)    ((OSC * n)/(d * (1+p)))
1252 
1253 	unsigned char n, d, p, minn, mind, minp = 0;
1254 	unsigned long err, minerr;
1255 
1256 /*
1257 numer = 0x00 - 0x7f
1258 denom = 0x00 - 0x1f (1) 0x20 - 0x3e (even)
1259 */
1260 
1261 	/* find lowest error in 6144 iterations. */
1262 	minerr = fq;
1263 	minn = 0;
1264 	mind = 0;
1265 	p = 0;
1266 
1267 	if ((cl_64bit == 1) && (fq >= 86000000))
1268 	{
1269 		for (d = 1; d < 0x20; d++) {
1270 			for (n = 1; n < 0x80; n++) {
1271 				err = abs(count(n, d, 0) - fq);
1272 				if (err < minerr) {
1273 					minerr = err;
1274 					minn = n;
1275 					mind = d;
1276 					minp = 1;
1277 				}
1278 			}
1279 		}
1280 		*clkdoub = 1;
1281 	}
1282 	else {
1283 		for (d = 1; d < 0x20; d++) {
1284 			for (n = 1; n < 0x80; n++) {
1285 				err = abs(count(n, d, p) - fq);
1286 				if (err < minerr) {
1287 					minerr = err;
1288 					minn = n;
1289 					mind = d;
1290 					minp = p;
1291 				}
1292 			}
1293 			if (d == 0x1f && p == 0) {
1294 				p = 1;
1295 				d = 0x0f;
1296 			}
1297 		}
1298 		*clkdoub = 0;
1299 	}
1300 
1301 	*num = minn;
1302 	*denom = (mind << 1) | minp;
1303 	if (minerr > 500000)
1304 		printf("Warning: CompFQ minimum error = %ld\n", minerr);
1305 	return;
1306 }
1307 
1308 int
1309 cl_mondefok(gv)
1310 	struct grfvideo_mode *gv;
1311 {
1312         unsigned long maxpix;
1313 
1314 	if (gv->mode_num < 1 || gv->mode_num > monitor_def_max)
1315                 if (gv->mode_num != 255 || gv->depth != 4)
1316                         return(0);
1317 
1318 	switch (gv->depth) {
1319 	    case 4:
1320                 if (gv->mode_num != 255)
1321                         return(0);
1322 	    case 1:
1323 	    case 8:
1324 		maxpix = cl_maxpixelclock;
1325 		if (cl_64bit == 1)
1326 		{
1327 			if (cltype == PICASSO) /* Picasso IV */
1328 				maxpix = 135000000;
1329 			else                   /* Piccolo SD64 */
1330 				maxpix = 110000000;
1331 		}
1332                 break;
1333 	    case 15:
1334 	    case 16:
1335 		if (cl_64bit == 1)
1336 	                maxpix = 85000000;
1337 		else
1338 	                maxpix = cl_maxpixelclock - (cl_maxpixelclock / 3);
1339                 break;
1340 	    case 24:
1341 		if ((cltype == PICASSO) && (cl_64bit == 1))
1342 	                maxpix = 85000000;
1343 		else
1344 	                maxpix = cl_maxpixelclock / 3;
1345                 break;
1346 	    case 32:
1347 		if ((cltype == PICCOLO) && (cl_64bit == 1))
1348 	                maxpix = 50000000;
1349 		else
1350 	                maxpix = 0;
1351                 break;
1352 	default:
1353 		printf("grfcl: Illegal depth in mode %d\n",
1354 			(int) gv->mode_num);
1355 		return (0);
1356 	}
1357 
1358         if (gv->pixel_clock > maxpix) {
1359 		printf("grfcl: Pixelclock too high in mode %d\n",
1360 			(int) gv->mode_num);
1361                 return (0);
1362 	}
1363 
1364 	if (gv->disp_flags & GRF_FLAGS_SYNC_ON_GREEN) {
1365 		printf("grfcl: sync-on-green is not supported\n");
1366 		return (0);
1367 	}
1368 
1369         return (1);
1370 }
1371 
1372 int
1373 cl_load_mon(gp, md)
1374 	struct grf_softc *gp;
1375 	struct grfcltext_mode *md;
1376 {
1377 	struct grfvideo_mode *gv;
1378 	struct grfinfo *gi;
1379 	volatile caddr_t ba, fb;
1380 	unsigned char num0, denom0, clkdoub;
1381 	unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
1382 	        VSE, VT;
1383 	int	clkmul, offsmul, clkmode;
1384 	int	vmul;
1385 	int	sr15;
1386 	unsigned char hvsync_pulse;
1387 	char    TEXT;
1388 
1389 	/* identity */
1390 	gv = &md->gv;
1391 	TEXT = (gv->depth == 4);
1392 
1393 	if (!cl_mondefok(gv)) {
1394 		printf("grfcl: Monitor definition not ok\n");
1395 		return (0);
1396 	}
1397 
1398 	ba = gp->g_regkva;
1399 	fb = gp->g_fbkva;
1400 
1401 	/* provide all needed information in grf device-independant locations */
1402 	gp->g_data = (caddr_t) gv;
1403 	gi = &gp->g_display;
1404 	gi->gd_regaddr = (caddr_t) kvtop(ba);
1405 	gi->gd_regsize = 64 * 1024;
1406 	gi->gd_fbaddr = (caddr_t) kvtop(fb);
1407 	gi->gd_fbsize = cl_fbsize;
1408 	gi->gd_colors = 1 << gv->depth;
1409 	gi->gd_planes = gv->depth;
1410 	gi->gd_fbwidth = gv->disp_width;
1411 	gi->gd_fbheight = gv->disp_height;
1412 	gi->gd_fbx = 0;
1413 	gi->gd_fby = 0;
1414 	if (TEXT) {
1415 		gi->gd_dwidth = md->fx * md->cols;
1416 		gi->gd_dheight = md->fy * md->rows;
1417 	} else {
1418 		gi->gd_dwidth = gv->disp_width;
1419 		gi->gd_dheight = gv->disp_height;
1420 	}
1421 	gi->gd_dx = 0;
1422 	gi->gd_dy = 0;
1423 
1424 	/* get display mode parameters */
1425 
1426 	HBS = gv->hblank_start;
1427 	HSS = gv->hsync_start;
1428 	HSE = gv->hsync_stop;
1429 	HBE = gv->htotal - 1;
1430 	HT = gv->htotal;
1431 	VBS = gv->vblank_start;
1432 	VSS = gv->vsync_start;
1433 	VSE = gv->vsync_stop;
1434 	VBE = gv->vtotal - 1;
1435 	VT = gv->vtotal;
1436 
1437 	if (TEXT)
1438 		HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
1439 	else
1440 		HDE = (gv->disp_width + 3) / 8 - 1;	/* HBS; */
1441 	VDE = gv->disp_height - 1;
1442 
1443 	/* adjustments */
1444 	switch (gv->depth) {
1445 	    case 8:
1446 		clkmul = 1;
1447 		offsmul = 1;
1448 		clkmode = 0x0;
1449 		break;
1450 	    case 15:
1451 	    case 16:
1452 		clkmul = 1;
1453 		offsmul = 2;
1454 		clkmode = 0x6;
1455 		break;
1456 	    case 24:
1457 		if ((cltype == PICASSO) && (cl_64bit == 1))	/* Picasso IV */
1458 			clkmul = 1;
1459 		else
1460 			clkmul = 3;
1461 		offsmul = 3;
1462 		clkmode = 0x4;
1463 		break;
1464 	    case 32:
1465 		clkmul = 1;
1466 		offsmul = 2;
1467 		clkmode = 0x8;
1468 		break;
1469 	    default:
1470 		clkmul = 1;
1471 		offsmul = 1;
1472 		clkmode = 0x0;
1473 		break;
1474 	}
1475 
1476 	if ((VT > 1023) && (!(gv->disp_flags & GRF_FLAGS_LACE))) {
1477 		WCrt(ba, CRT_ID_MODE_CONTROL, 0xe7);
1478 	} else
1479 		WCrt(ba, CRT_ID_MODE_CONTROL, 0xe3);
1480 
1481 	vmul = 2;
1482 	if ((VT > 1023) || (gv->disp_flags & GRF_FLAGS_LACE))
1483 		vmul = 1;
1484 	if (gv->disp_flags & GRF_FLAGS_DBLSCAN)
1485 		vmul = 4;
1486 
1487 	VDE = VDE * vmul / 2;
1488 	VBS = VBS * vmul / 2;
1489 	VSS = VSS * vmul / 2;
1490 	VSE = VSE * vmul / 2;
1491 	VBE = VBE * vmul / 2;
1492 	VT  = VT * vmul / 2;
1493 
1494 	WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
1495 	if (cl_64bit == 1) {
1496 	    if (TEXT || (gv->depth == 1))
1497 		sr15 = 0xd0;
1498 	    else
1499 		sr15 = ((cl_fbsize / 0x100000 == 2) ? 0x38 : 0xb8);
1500 	    WSeq(ba, SEQ_ID_CONF_RBACK, 0x00);
1501 	} else {
1502 		sr15 = (TEXT || (gv->depth == 1)) ? 0xd0 : 0xb0;
1503 		sr15 &= ((cl_fbsize / 0x100000) == 2) ? 0xff : 0x7f;
1504 	}
1505 	WSeq(ba, SEQ_ID_DRAM_CNTL, sr15);
1506 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
1507 	WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
1508 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
1509 
1510 	/* Set clock */
1511 
1512 	cl_CompFQ(gv->pixel_clock * clkmul, &num0, &denom0, &clkdoub);
1513 
1514 	/* Horizontal/Vertical Sync Pulse */
1515 	hvsync_pulse = vgar(ba, GREG_MISC_OUTPUT_R);
1516 	if (gv->disp_flags & GRF_FLAGS_PHSYNC)
1517 		hvsync_pulse &= ~0x40;
1518 	else
1519 		hvsync_pulse |= 0x40;
1520 	if (gv->disp_flags & GRF_FLAGS_PVSYNC)
1521 		hvsync_pulse &= ~0x80;
1522 	else
1523 		hvsync_pulse |= 0x80;
1524 	vgaw(ba, GREG_MISC_OUTPUT_W, hvsync_pulse);
1525 
1526 	if (clkdoub) {
1527 		HDE /= 2;
1528 		HBS /= 2;
1529 		HSS /= 2;
1530 		HSE /= 2;
1531 		HBE /= 2;
1532 		HT  /= 2;
1533 		clkmode = 0x6;
1534 	}
1535 
1536 	WSeq(ba, SEQ_ID_VCLK_3_NUM, num0);
1537 	WSeq(ba, SEQ_ID_VCLK_3_DENOM, denom0);
1538 
1539 	/* load display parameters into board */
1540 
1541 	WCrt(ba, CRT_ID_HOR_TOTAL, HT);
1542 	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? HBS - 1 : HDE));
1543 	WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
1544 	WCrt(ba, CRT_ID_END_HOR_BLANK, (HBE & 0x1f) | 0x80);	/* | 0x80? */
1545 	WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
1546 	WCrt(ba, CRT_ID_END_HOR_RETR,
1547 	    (HSE & 0x1f) |
1548 	    ((HBE & 0x20) ? 0x80 : 0x00));
1549 	WCrt(ba, CRT_ID_VER_TOTAL, VT);
1550 	WCrt(ba, CRT_ID_OVERFLOW,
1551 	    0x10 |
1552 	    ((VT & 0x100) ? 0x01 : 0x00) |
1553 	    ((VDE & 0x100) ? 0x02 : 0x00) |
1554 	    ((VSS & 0x100) ? 0x04 : 0x00) |
1555 	    ((VBS & 0x100) ? 0x08 : 0x00) |
1556 	    ((VT & 0x200) ? 0x20 : 0x00) |
1557 	    ((VDE & 0x200) ? 0x40 : 0x00) |
1558 	    ((VSS & 0x200) ? 0x80 : 0x00));
1559 
1560 	WCrt(ba, CRT_ID_CHAR_HEIGHT,
1561 	    0x40 |		/* TEXT ? 0x00 ??? */
1562 	    ((gv->disp_flags & GRF_FLAGS_DBLSCAN) ? 0x80 : 0x00) |
1563 	    ((VBS & 0x200) ? 0x20 : 0x00) |
1564 	    (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
1565 
1566 	/* text cursor */
1567 
1568 	if (TEXT) {
1569 #if CL_ULCURSOR
1570 		WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
1571 		WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
1572 #else
1573 		WCrt(ba, CRT_ID_CURSOR_START, 0x00);
1574 		WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
1575 #endif
1576 		WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f);
1577 
1578 		WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1579 		WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
1580 	}
1581 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
1582 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
1583 
1584 	WCrt(ba, CRT_ID_START_VER_RETR, VSS);
1585 	WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f) | 0x20);
1586 	WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
1587 	WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
1588 	WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
1589 
1590 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
1591 	WCrt(ba, CRT_ID_LACE_END, HT / 2);	/* MW/16 */
1592 	WCrt(ba, CRT_ID_LACE_CNTL,
1593 	    ((gv->disp_flags & GRF_FLAGS_LACE) ? 0x01 : 0x00) |
1594 	    ((HBE & 0x40) ? 0x10 : 0x00) |
1595 	    ((HBE & 0x80) ? 0x20 : 0x00) |
1596 	    ((VBE & 0x100) ? 0x40 : 0x00) |
1597 	    ((VBE & 0x200) ? 0x80 : 0x00));
1598 
1599 	WGfx(ba, GCT_ID_GRAPHICS_MODE,
1600 	    ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
1601 	WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
1602 
1603 	WSeq(ba, SEQ_ID_EXT_SEQ_MODE,
1604 	    ((TEXT || (gv->depth == 1)) ? 0x00 : 0x01) |
1605 	    ((cltype == PICASSO) ? 0x20 : 0x80) | clkmode);
1606 
1607 	/* write 0x00 to VDAC_MASK before accessing HDR this helps
1608 	   sometimes, out of "secret" application note (crest) */
1609 	vgaw(ba, VDAC_MASK, 0);
1610 	/* reset HDR "magic" access counter (crest) */
1611 	vgar(ba, VDAC_ADDRESS);
1612 
1613 	delay(200000);
1614 	vgar(ba, VDAC_MASK);
1615 	delay(200000);
1616 	vgar(ba, VDAC_MASK);
1617 	delay(200000);
1618 	vgar(ba, VDAC_MASK);
1619 	delay(200000);
1620 	vgar(ba, VDAC_MASK);
1621 	delay(200000);
1622 	switch (gv->depth) {
1623 	    case 1:
1624 	    case 4:		/* text */
1625 		vgaw(ba, VDAC_MASK, 0);
1626 		HDE = gv->disp_width / 16;
1627 		break;
1628 	    case 8:
1629 		if (clkdoub)
1630 			vgaw(ba, VDAC_MASK, 0x4a); /* Clockdouble Magic */
1631 		else
1632 			vgaw(ba, VDAC_MASK, 0);
1633 		HDE = gv->disp_width / 8;
1634 		break;
1635 	    case 15:
1636 		vgaw(ba, VDAC_MASK, 0xd0);
1637 		HDE = gv->disp_width / 4;
1638 		break;
1639 	    case 16:
1640 		vgaw(ba, VDAC_MASK, 0xc1);
1641 		HDE = gv->disp_width / 4;
1642 		break;
1643 	    case 24:
1644 		vgaw(ba, VDAC_MASK, 0xc5);
1645 		HDE = (gv->disp_width / 8) * 3;
1646 		break;
1647 	    case 32:
1648 		vgaw(ba, VDAC_MASK, 0xc5);
1649 		HDE = (gv->disp_width / 4);
1650 		break;
1651 	}
1652 
1653 	/* reset HDR "magic" access counter (crest) */
1654 	vgar(ba, VDAC_ADDRESS);
1655 	/* then enable all bit in VDAC_MASK afterwards (crest) */
1656 	vgaw(ba, VDAC_MASK, 0xff);
1657 
1658 	WCrt(ba, CRT_ID_OFFSET, HDE);
1659 	if (cl_64bit == 1) {
1660 		WCrt(ba, CRT_ID_SYNC_ADJ_GENLOCK, 0x00);
1661 		WCrt(ba, CRT_ID_OVERLAY_EXT_CTRL_REG, 0x40);
1662 	}
1663 	WCrt(ba, CRT_ID_EXT_DISP_CNTL,
1664 	    ((TEXT && gv->pixel_clock > 29000000) ? 0x40 : 0x00) |
1665 	    0x22 |
1666 	    ((HDE > 0xff) ? 0x10 : 0x00));
1667 
1668 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x0a : 0x01));
1669 	WAttr(ba, 0x20 | ACT_ID_COLOR_PLANE_ENA,
1670 	    (gv->depth == 1) ? 0x01 : 0x0f);
1671 
1672 	/* text initialization */
1673 
1674 	if (TEXT) {
1675 		cl_inittextmode(gp);
1676 	}
1677 	WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x14);
1678 	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x01);
1679 
1680 	/* Pass-through */
1681 
1682 	RegOffpass(ba);
1683 
1684 	return (1);
1685 }
1686 
1687 void
1688 cl_inittextmode(gp)
1689 	struct grf_softc *gp;
1690 {
1691 	struct grfcltext_mode *tm = (struct grfcltext_mode *) gp->g_data;
1692 	volatile unsigned char *ba = gp->g_regkva;
1693 	unsigned char *fb = gp->g_fbkva;
1694 	unsigned char *c, *f, y;
1695 	unsigned short z;
1696 
1697 
1698 	/* load text font into beginning of display memory. Each character
1699 	 * cell is 32 bytes long (enough for 4 planes) */
1700 
1701 	SetTextPlane(ba, 0x02);
1702         cl_memset(fb, 0, 256 * 32);
1703 	c = (unsigned char *) (fb) + (32 * tm->fdstart);
1704 	f = tm->fdata;
1705 	for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy))
1706 		for (y = 0; y < tm->fy; y++)
1707 			*c++ = *f++;
1708 
1709 	/* clear out text/attr planes (three screens worth) */
1710 
1711 	SetTextPlane(ba, 0x01);
1712 	cl_memset(fb, 0x07, tm->cols * tm->rows * 3);
1713 	SetTextPlane(ba, 0x00);
1714 	cl_memset(fb, 0x20, tm->cols * tm->rows * 3);
1715 
1716 	/* print out a little init msg */
1717 
1718 	c = (unsigned char *) (fb) + (tm->cols - 16);
1719 	strcpy(c, "CIRRUS");
1720 	c[6] = 0x20;
1721 
1722 	/* set colors (B&W) */
1723 
1724 	vgaw(ba, VDAC_ADDRESS_W, 0);
1725 	for (z = 0; z < 256; z++) {
1726 		unsigned char r, g, b;
1727 
1728 		y = (z & 1) ? ((z > 7) ? 2 : 1) : 0;
1729 
1730 		if (cltype == PICASSO) {
1731 			r = clconscolors[y][0];
1732 			g = clconscolors[y][1];
1733 			b = clconscolors[y][2];
1734 		} else {
1735 			b = clconscolors[y][0];
1736 			g = clconscolors[y][1];
1737 			r = clconscolors[y][2];
1738 		}
1739 		vgaw(ba, VDAC_DATA, r >> 2);
1740 		vgaw(ba, VDAC_DATA, g >> 2);
1741 		vgaw(ba, VDAC_DATA, b >> 2);
1742 	}
1743 }
1744 
1745 void
1746 cl_memset(d, c, l)
1747 	unsigned char *d;
1748 	unsigned char c;
1749 	int     l;
1750 {
1751 	for (; l > 0; l--)
1752 		*d++ = c;
1753 }
1754 
1755 /*
1756  * Special wakeup/passthrough registers on graphics boards
1757  *
1758  * The methods have diverged a bit for each board, so
1759  * WPass(P) has been converted into a set of specific
1760  * inline functions.
1761  */
1762 static void
1763 RegWakeup(ba)
1764 	volatile caddr_t ba;
1765 {
1766 
1767 	switch (cltype) {
1768 	    case SPECTRUM:
1769 		vgaw(ba, PASS_ADDRESS_W, 0x1f);
1770 		break;
1771 	    case PICASSO:
1772 		/* Picasso needs no wakeup */
1773 		break;
1774 	    case PICCOLO:
1775 		if (cl_64bit == 1)
1776 			vgaw(ba, PASS_ADDRESS_W, 0x1f);
1777 		else
1778 			vgaw(ba, PASS_ADDRESS_W, vgar(ba, PASS_ADDRESS) | 0x10);
1779 		break;
1780 	}
1781 	delay(200000);
1782 }
1783 
1784 static void
1785 RegOnpass(ba)
1786 	volatile caddr_t ba;
1787 {
1788 
1789 	switch (cltype) {
1790 	    case SPECTRUM:
1791 		vgaw(ba, PASS_ADDRESS_W, 0x4f);
1792 		break;
1793 	    case PICASSO:
1794 		if (cl_64bit == 0)
1795 			vgaw(ba, PASS_ADDRESS_WP, 0x01);
1796 		break;
1797 	    case PICCOLO:
1798 		if (cl_64bit == 1)
1799 			vgaw(ba, PASS_ADDRESS_W, 0x4f);
1800 		else
1801 			vgaw(ba, PASS_ADDRESS_W, vgar(ba, PASS_ADDRESS) & 0xdf);
1802 		break;
1803 	}
1804 	cl_pass_toggle = 1;
1805 	delay(200000);
1806 }
1807 
1808 static void
1809 RegOffpass(ba)
1810 	volatile caddr_t ba;
1811 {
1812 
1813 	switch (cltype) {
1814 	    case SPECTRUM:
1815 		vgaw(ba, PASS_ADDRESS_W, 0x6f);
1816 		break;
1817 	    case PICASSO:
1818 		if (cl_64bit == 0)
1819 			vgaw(ba, PASS_ADDRESS_W, 0xff);
1820 		break;
1821 	    case PICCOLO:
1822 		if (cl_64bit == 1)
1823 			vgaw(ba, PASS_ADDRESS_W, 0x6f);
1824 		else
1825 			vgaw(ba, PASS_ADDRESS_W, vgar(ba, PASS_ADDRESS) | 0x20);
1826 		break;
1827 	}
1828 	cl_pass_toggle = 0;
1829 	delay(200000);
1830 }
1831 
1832 #endif /* NGRFCL */
1833