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