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