xref: /netbsd-src/sys/arch/amiga/dev/grf_cv.c (revision 9573504567626934c7ee01c7dce0c4bb1dfe7403)
1 /*	$NetBSD: grf_cv.c,v 1.4 1995/11/30 00:56:57 jtc Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Michael Teske
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Ezra Story, by Kari
18  *      Mettinen and by Bernd Ernesti.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 #include "grfcv.h"
34 #if NGRFCV > 0
35 
36 #undef CV64CONSOLE /* DO NOT REMOVE THIS till ite5 is ready */
37 
38 /*
39  * Graphics routines for the CyberVision 64 board, using the S3 Trio64.
40  *
41  * Modified for CV64 from
42  * Kari Mettinen's Cirrus driver by Michael Teske 10/95
43  * For questions mail me at teske@dice2.desy.de
44  *
45  * Thanks to Tekelec Airtronic for providing me with a S3 Trio64 documentation.
46  * Thanks to Bernd 'the fabulous bug-finder' Ernesti for bringing my messy
47  * source to NetBSD style :)
48  *
49  * TODO:
50  *    Hardware Cursor support
51  *    Blitter support
52  *
53  * BUGS:
54  *    Xamiag24 and grf_cv can crash when you use fvwm with xterm's, you can
55  *    avoid this by starting the xterm with '-ah', see the manpage of xterm
56  *    for more informations about this switch.
57  *    There is a bug in the Trio64 which produce a small (1 or 2 pixel) white
58  *    vertical bar on the right side of an 8bit-Screen (only when you use more
59  *    then 80MHz pixelclock). This has to be fixed in the Xserver.
60  *
61  */
62 
63 #include <sys/param.h>
64 #include <sys/errno.h>
65 #include <sys/ioctl.h>
66 #include <sys/device.h>
67 #include <sys/malloc.h>
68 #include <sys/systm.h>
69 #include <machine/cpu.h>
70 #include <dev/cons.h>
71 #include <amiga/amiga/device.h>
72 #include <amiga/dev/grfioctl.h>
73 #include <amiga/dev/grfvar.h>
74 #include <amiga/dev/grf_cvreg.h>
75 #include <amiga/dev/zbusvar.h>
76 
77 int	grfcvmatch  __P((struct device *, struct cfdata *, void *));
78 void	grfcvattach __P((struct device *, struct device *, void *));
79 int	grfcvprint  __P((void *, char *));
80 
81 static int cv_has_4mb __P((volatile char *));
82 static unsigned short compute_clock __P((unsigned long));
83 void	cv_boardinit __P((struct grf_softc *));
84 int	cv_getvmode __P((struct grf_softc *, struct grfvideo_mode *));
85 int	cv_setvmode __P((struct grf_softc *, unsigned int));
86 int	cv_blank __P((struct grf_softc *, int *));
87 int	cv_mode __P((register struct grf_softc *, int, void *, int, int));
88 int	cv_ioctl __P((register struct grf_softc *gp, int cmd, void *data));
89 int	cv_setmonitor __P((struct grf_softc *, struct grfvideo_mode *));
90 int	cv_getcmap __P((struct grf_softc *, struct grf_colormap *));
91 int	cv_putcmap __P((struct grf_softc *, struct grf_colormap *));
92 int	cv_toggle __P((struct grf_softc *));
93 int	cv_mondefok __P((struct grfvideo_mode *));
94 int	cv_load_mon __P((struct grf_softc *, struct grfcvtext_mode *));
95 void	cv_inittextmode __P((struct grf_softc *));
96 void	cv_memset __P((unsigned char *, unsigned char, int));
97 
98 #ifdef CV64CONSOLE
99 extern void grfcv_iteinit __P((struct grf_softc *));
100 #endif
101 
102 /* Graphics display definitions.
103  * These are filled by 'grfconfig' using GRFIOCSETMON.
104  */
105 #define monitor_def_max 8
106 static struct grfvideo_mode monitor_def[8] = {
107 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}
108 };
109 static struct grfvideo_mode *monitor_current = &monitor_def[0];
110 #define MAXPIXELCLOCK 135000000 /* safety */
111 
112 
113 /* Console display definition.
114  *   Default hardcoded text mode.  This grf_cv is set up to
115  *   use one text mode only, and this is it.  You may use
116  *   grfconfig to change the mode after boot.
117  */
118 
119 /* Console font */
120 #define S3FONT kernel_font_8x8
121 #define S3FONTX 8
122 #define S3FONTY 8
123 extern unsigned char S3FONT[];
124 
125 struct grfcvtext_mode cvconsole_mode = {
126 	{255, "", 25000000, 640, 400, 4, 640, 656, 672, 720, 760, 406,
127 	441, 412, 426, 447},
128 	S3FONTX, S3FONTY, 80, 506/S3FONTY, S3FONT, 32, 255
129 };
130 
131 /* Console colors */
132 unsigned char cvconscolors[3][3] = {	/* background, foreground, hilite */
133 	{0,0x40,0x50}, {152,152,152}, {255,255,255}
134 };
135 
136 
137 /* Board Address of CV64 */
138 
139 static volatile caddr_t cv_boardaddr;
140 static int cv_fbsize;
141 
142 int
143 grfcv_cnprobe()
144 {
145 	int rv;
146 	rv = CN_DEAD;
147 	return (rv);
148 }
149 
150 /* standard driver stuff */
151 struct cfdriver grfcvcd = {
152 	NULL, "grfcv", (cfmatch_t)grfcvmatch, grfcvattach,
153 	DV_DULL, sizeof(struct grf_softc), NULL, 0
154 };
155 static struct cfdata *cfdata;
156 
157 
158 /* Reads from the fb must be done at addr + 0x02000000 */
159 #define READ_OFFSET 0x02000000
160 
161 /*
162  * Get frambuffer memory size.
163  * phase5 didn't provide the bit in CR36,
164  * so we have to do it this way.
165  * Return 0 for 2MB, 1 for 4MB
166  */
167 
168 static int
169 cv_has_4mb (volatile char *fb)
170 {
171 	volatile unsigned long *testfbw, *testfbr;
172 
173 	/* write patterns in memory and test if they can be read */
174 	testfbw = (volatile unsigned long *) fb;
175 	*testfbw = 0x87654321;
176 	testfbr = (volatile unsigned long *)(fb + READ_OFFSET);
177 	if (*testfbr != 0x87654321)
178 		return (0);
179 	/* upper memory region */
180 	testfbw = (volatile unsigned long *)(fb + 0x00200000);
181 	testfbr = (volatile unsigned long *)(fb + 0x00200000 + READ_OFFSET);
182 	*testfbw = 0x87654321;
183 	if (*testfbr != 0x87654321)
184 		return (0);
185 	*testfbw = 0xAAAAAAAA;
186 	if (*testfbr != 0xAAAAAAAA)
187 		return (0);
188 	*testfbw = 0x55555555;
189 	if (*testfbr != 0x55555555)
190 		return (0);
191 	return (1);
192 }
193 
194 int
195 grfcvmatch(pdp, cfp, auxp)
196 	struct device *pdp;
197 	struct cfdata *cfp;
198 	void *auxp;
199 {
200 	struct zbus_args *zap;
201 
202 	zap = auxp;
203 
204 #ifndef CV64CONSOLE
205 	if (amiga_realconfig == 0)
206 		 return (0);
207 #endif
208 
209         /* Lets be Paranoid: Test man and prod id */
210 	if (zap->manid != 8512 || zap->prodid != 34)
211 		return (0);
212 
213 	cv_boardaddr = zap->va;
214 
215 #ifdef CV64CONSOLE
216 	if (amiga_realconfig == 0) {
217 		cfdata = cfp;
218 	}
219 #endif
220 
221 	return (1);
222 }
223 
224 void
225 grfcvattach(pdp, dp, auxp)
226 	struct device *pdp, *dp;
227 	void *auxp;
228 {
229 	struct zbus_args *zap;
230 	struct grf_softc *gp;
231 
232 	zap = auxp;
233 
234 	printf("\n");
235 
236 	gp = (struct grf_softc *)dp;
237 
238 	gp->g_regkva = (volatile caddr_t)cv_boardaddr + READ_OFFSET;
239 	gp->g_fbkva = (volatile caddr_t)cv_boardaddr + 0x01400000;
240 
241 	gp->g_unit = GRF_CV64_UNIT;
242 	gp->g_mode = cv_mode;
243 	gp->g_conpri = grfcv_cnprobe();
244 	gp->g_flags = GF_ALIVE;
245 
246 	/* wakeup the board */
247 	cv_boardinit(gp);
248 
249 #ifdef CV64CONSOLE
250 	grfcv_iteinit(gp);
251 	(void)cv_load_mon(gp, &cvconsole_mode);
252 #endif
253 
254 	/*
255 	 * attach grf
256 	 */
257 	if (amiga_config_found(cfdata, &gp->g_device, gp, grfcvprint))
258 		printf("grfcv: CyberVision64 with %dMB being used\n", cv_fbsize/0x100000);
259 }
260 
261 int
262 grfcvprint(auxp, pnp)
263 	void *auxp;
264 	char *pnp;
265 {
266 	if (pnp)
267 		printf("ite at %s: ", pnp);
268 	return (UNCONF);
269 }
270 
271 
272 /*
273  * Computes M, N, and R values from
274  * given input frequency. It uses a table of
275  * precomputed values, to keep CPU time low.
276  *
277  * The return value consist of:
278  * lower byte:  Bits 4-0: N Divider Value
279  *	        Bits 5-6: R Value          for e.g. SR10 or SR12
280  * higher byte: Bits 0-6: M divider value  for e.g. SR11 or SR13
281  */
282 
283 static unsigned short
284 compute_clock(freq)
285 	unsigned long freq;
286 {
287 
288 	static unsigned char *mnr, *save;	/* M, N + R vals */
289 	unsigned long work_freq, r;
290 	unsigned short erg;
291 	long diff, d2;
292 
293 	/* 0xBEBC20 = 12.5M */
294 	/* 0x080BEFC0 = 135M */
295 	if (freq < 0x00BEBC20 || freq > 0x080BEFC0) {
296 		printf("grfcv: Wrong clock frequency: %dMHz", freq/1000000);
297 		printf("grfcv: Using default frequency: 25MHz");
298 		freq = 0x017D7840;
299 	}
300 
301 	mnr = clocks;	/* there the vals are stored */
302 	d2 = 0x7fffffff;
303 
304 	while (*mnr) {	/* mnr vals are 0-terminated */
305 		work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
306 
307 		r = (mnr[1] >> 5) & 0x03;
308     		if (r != 0)
309 			work_freq=work_freq >> r;	/* r is the freq divider */
310 
311 		work_freq *= 0x3E8;	/* 2nd part of OSC */
312 
313 		diff = abs(freq - work_freq);
314 
315 		if (d2 >= diff) {
316 			d2 = diff;
317 			/* In save are the vals for minimal diff */
318 			save = mnr;
319 		}
320 		mnr += 2;
321 	}
322 	erg = *((unsigned short *)save);
323 
324 	return (erg);
325 }
326 
327 
328 void
329 cv_boardinit(gp)
330 	struct grf_softc *gp;
331 {
332 	volatile caddr_t ba = gp->g_regkva;
333 	unsigned char test;
334 	unsigned int clockpar;
335 	int i;
336 	struct grfinfo *gi;
337 
338 	/* Reset board */
339 	for (i = 0; i < 6; i++)
340 		cv_write_port (0xff, ba - READ_OFFSET);	/* Clear all bits */
341 
342 	/* Return to operational Mode */
343 	cv_write_port(0x8004, ba - READ_OFFSET);
344 
345 	/* Wakeup Chip */
346 	vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x10);
347 	vgaw(ba, SREG_OPTION_SELECT, 0x1);
348 	vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x8);
349 
350 	vgaw(ba, GREG_MISC_OUTPUT_W, 0x23);
351 
352 	WCrt(ba, CRT_ID_REGISTER_LOCK_1, 0x48);	/* unlock S3 VGA regs */
353 	WCrt(ba, CRT_ID_REGISTER_LOCK_2, 0xA5);	/* unlock syscontrol */
354 
355 	test = RCrt(ba, CRT_ID_SYSTEM_CONFIG);
356 	test = test | 0x01;	/* enable enhaced register access */
357 	test = test & 0xEF;	/* clear bit 4, 0 wait state */
358 	WCrt(ba, CRT_ID_SYSTEM_CONFIG, test);
359 
360 	/*
361 	 * bit 1=1: enable enhanced mode functions
362 	 * bit 4=1: enable linear adressing
363  	 */
364 	vgaw(ba, ECR_ADV_FUNC_CNTL, 0x11);
365 
366 	/* enable cpu acess, color mode, high 64k page */
367 	vgaw(ba, GREG_MISC_OUTPUT_W, 0x23);
368 
369 	/* Cpu base addr */
370 	WCrt(ba, CRT_ID_EXT_SYS_CNTL_4, 0x0);
371 
372 	/* Reset. This does nothing, but everyone does it:) */
373 	WSeq(ba, SEQ_ID_RESET, 0x3);
374 
375 	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x1);	/* 8 Dot Clock */
376 	WSeq(ba, SEQ_ID_MAP_MASK, 0xF);		/* Enable write planes */
377 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x0);	/* Character Font */
378 
379 	WSeq(ba, SEQ_ID_MEMORY_MODE, 0x2);	/* Complete mem access */
380 
381 	WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x6);	/* Unlock extensions */
382 	test = RSeq(ba, SEQ_ID_BUS_REQ_CNTL);	/* Bus Request */
383 
384 	/* enable 4MB fast Page Mode */
385 	test = test | 1 << 6;
386 	WSeq(ba, SEQ_ID_BUS_REQ_CNTL, test);
387 	/* faster LUT write */
388 	WSeq(ba, SEQ_ID_RAMDAC_CNTL, 0x40);
389 
390 	test = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);	/* Clksyn2 read */
391 
392 	/* immediately Clkload bit clear */
393 	test = test & 0xDF;
394 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, test);
395 
396 	clockpar = compute_clock(0x3473BC0);
397 	test = (clockpar & 0xFF00) >> 8;
398 	WSeq(ba, SEQ_ID_MCLK_HI, test);		/* PLL N-Divider Value */
399 
400 	test = clockpar & 0xFF;
401 	WSeq(ba, SEQ_ID_MCLK_LO, test);		/* PLL M-Divider Value */
402 
403 	/* We now load an 25 MHz, 31 kHz, 640x480 standard VGA Mode. */
404 	/* DCLK */
405 	WSeq(ba, SEQ_ID_DCLK_HI, 0x13);
406 	WSeq(ba, SEQ_ID_DCLK_LO, 0x41);
407 
408 	test = RSeq (ba, SEQ_ID_CLKSYN_CNTL_2);
409 	test = test | 0x22;
410 
411 	/* DCLK + MCLK Clock immediate load! */
412 	WSeq(ba,SEQ_ID_CLKSYN_CNTL_2, test);
413 
414 	/* DCLK load */
415 	test = vgar(ba, 0x3cc);
416 	test = test | 0x0c;
417 	vgaw(ba, 0x3c2, test);
418 
419 	/* Clear bit 5 again, prevent further loading. */
420 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, 0x2);
421 
422 	WCrt(ba, CRT_ID_HOR_TOTAL, 0x5F);
423 	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, 0x4F);
424 	WCrt(ba, CRT_ID_START_HOR_BLANK, 0x50);
425 	WCrt(ba, CRT_ID_END_HOR_BLANK, 0x82);
426 	WCrt(ba, CRT_ID_START_HOR_RETR, 0x54);
427 	WCrt(ba, CRT_ID_END_HOR_RETR, 0x80);
428 	WCrt(ba, CRT_ID_VER_TOTAL, 0xBF);
429 
430 	WCrt(ba, CRT_ID_OVERFLOW, 0x1F);	/* overflow reg */
431 
432 	WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x0);	/* no panning */
433 
434 	WCrt(ba, CRT_ID_MAX_SCAN_LINE, 0x40);	/* vscan */
435 
436 	WCrt(ba, CRT_ID_CURSOR_START, 0x00);
437 	WCrt(ba, CRT_ID_CURSOR_END, 0x00);
438 
439 	/* Display start adress */
440 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
441 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
442 
443 	/* Cursor location */
444 	WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
445 	WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
446 
447 	/* Vertical retrace */
448 	WCrt(ba, CRT_ID_START_VER_RETR, 0x9C);
449 	WCrt(ba, CRT_ID_END_VER_RETR, 0x0E);
450 
451 	WCrt(ba, CRT_ID_VER_DISP_ENA_END, 0x8F);
452 	WCrt(ba, CRT_ID_SCREEN_OFFSET, 0x50);
453 
454 	WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x00);
455 
456 	WCrt(ba, CRT_ID_START_VER_BLANK, 0x96);
457 	WCrt(ba, CRT_ID_END_VER_BLANK, 0xB9);
458 
459 	WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3);
460 
461 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xFF);
462 
463 	WCrt(ba, CRT_ID_BACKWAD_COMP_3, 0x10);	/* FIFO enabled */
464 
465 	/* Refresh count 1, High speed text font, enhanced color mode */
466 	WCrt(ba, CRT_ID_MISC_1, 0x35);
467 
468 	/* start fifo position */
469 	WCrt(ba, CRT_ID_DISPLAY_FIFO, 0x5a);
470 
471 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, 0x70);
472 
473 	/* address window position */
474 	WCrt(ba, CRT_ID_LAW_POS_LO, 0x40);
475 
476 	/* N Parameter for Display FIFO */
477 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
478 
479 	WGfx(ba, GCT_ID_SET_RESET, 0x0);
480 	WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x0);
481 	WGfx(ba, GCT_ID_COLOR_COMPARE, 0x0);
482 	WGfx(ba, GCT_ID_DATA_ROTATE, 0x0);
483 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x0);
484 	WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40);
485 	WGfx(ba, GCT_ID_MISC, 0x01);
486 	WGfx(ba, GCT_ID_COLOR_XCARE, 0x0F);
487 	WGfx(ba, GCT_ID_BITMASK, 0xFF);
488 
489 	/* colors for text mode */
490 	for (i = 0; i <= 0xf; i++)
491 		WAttr (ba, i, i);
492 
493 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x41);
494 	WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x01);
495 	WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0F);
496 	WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x0);
497 	WAttr(ba, ACT_ID_COLOR_SELECT, 0x0);
498 
499 	vgaw(ba, VDAC_MASK, 0xFF);	/* DAC Mask */
500 
501 	*((unsigned long *)(ba + ECR_FRGD_COLOR)) = 0xFF;
502 	*((unsigned long *)(ba + ECR_BKGD_COLOR)) = 0;
503 
504 	/* colors initially set to greyscale */
505 
506 	vgaw(ba, VDAC_ADDRESS_W, 0);
507 	for (i = 255; i >= 0 ; i--) {
508 		vgaw(ba, VDAC_DATA, i);
509 		vgaw(ba, VDAC_DATA, i);
510 		vgaw(ba, VDAC_DATA, i);
511 	}
512 
513 	/* GFx hardware cursor off */
514 	WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
515 
516 	/* Set first to 4 MB, so test will work */
517 	WCrt(ba, CRT_ID_LAW_CNTL, 0x13);
518 
519 	/* find *correct* fbsize of z3 board */
520 	if (cv_has_4mb((volatile char *)cv_boardaddr + 0x01400000)) {
521 		cv_fbsize = 1024 * 1024 * 4;
522 		WCrt(ba, CRT_ID_LAW_CNTL, 0x13); /* 4 MB */
523 	} else {
524 		cv_fbsize = 1024 * 1024 * 2;
525 		WCrt(ba, CRT_ID_LAW_CNTL, 0x12); /* 2 MB */
526 	}
527 
528 	/* If I knew what this really does... but it _is_ necessary
529 	to get any gfx on the screen!! Undocumented register? */
530 	WAttr(ba, 0x33, 0);
531 
532 	gi = &gp->g_display;
533 	gi->gd_regaddr	= (caddr_t) kvtop (ba);
534 	gi->gd_regsize	= 64 * 1024;
535 	gi->gd_fbaddr	= (caddr_t) kvtop (gp->g_fbkva);
536 	gi->gd_fbsize	= cv_fbsize;
537 }
538 
539 
540 int
541 cv_getvmode(gp, vm)
542 	struct grf_softc *gp;
543 	struct grfvideo_mode *vm;
544 {
545 	struct grfvideo_mode *gv;
546 
547 #ifdef CV64CONSOLE
548 	/* Handle grabbing console mode */
549 	if (vm->mode_num == 255) {
550 		bcopy(&cvconsole_mode, vm, sizeof(struct grfvideo_mode));
551 		/* XXX so grfconfig can tell us the correct text dimensions. */
552 		vm->depth = cvconsole_mode.fy;
553 	} else
554 #endif
555 	{
556 		if (vm->mode_num == 0)
557 			vm->mode_num = (monitor_current - monitor_def) + 1;
558 		if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
559 			return (EINVAL);
560 		gv = monitor_def + (vm->mode_num - 1);
561 		if (gv->mode_num == 0)
562 			return (EINVAL);
563 
564 		bcopy(gv, vm, sizeof(struct grfvideo_mode));
565 	}
566 
567 	/* adjust internal values to pixel values */
568 
569 	vm->hblank_start *= 8;
570 	vm->hblank_stop *= 8;
571 	vm->hsync_start *= 8;
572 	vm->hsync_stop *= 8;
573 	vm->htotal *= 8;
574 
575 	return (0);
576 }
577 
578 
579 int
580 cv_setvmode(gp, mode)
581 	struct grf_softc *gp;
582 	unsigned mode;
583 {
584 	if (!mode || (mode > monitor_def_max) ||
585 	    monitor_def[mode - 1].mode_num == 0)
586 		return (EINVAL);
587 
588 	monitor_current = monitor_def + (mode - 1);
589 
590 	return (0);
591 }
592 
593 
594 int
595 cv_blank(gp, on)
596 	struct grf_softc *gp;
597 	int *on;
598 {
599 	volatile caddr_t ba = gp->g_regkva;
600 
601 	gfx_on_off(*on ? 1 : 0, ba);
602 	return (0);
603 }
604 
605 
606 /*
607  * Change the mode of the display.
608  * Return a UNIX error number or 0 for success.
609  */
610 int
611 cv_mode(gp, cmd, arg, a2, a3)
612 	register struct grf_softc *gp;
613 	int cmd;
614 	void *arg;
615 	int a2, a3;
616 {
617 	int error;
618 
619 	switch (cmd) {
620 	case GM_GRFON:
621 		error = cv_load_mon (gp,
622 		    (struct grfcvtext_mode *) monitor_current) ? 0 : EINVAL;
623 		return (error);
624 
625 	case GM_GRFOFF:
626 #ifndef CV64CONSOLE
627 		(void)cv_toggle(gp);
628 #else
629 		cv_load_mon(gp, &cvconsole_mode);
630 #endif
631 		return (0);
632 
633 	case GM_GRFCONFIG:
634 		return (0);
635 
636 	case GM_GRFGETVMODE:
637 		return (cv_getvmode (gp, (struct grfvideo_mode *) arg));
638 
639 	case GM_GRFSETVMODE:
640 		error = cv_setvmode (gp, *(unsigned *) arg);
641 		if (!error && (gp->g_flags & GF_GRFON))
642 			cv_load_mon(gp,
643 			    (struct grfcvtext_mode *) monitor_current);
644 		return (error);
645 
646 	case GM_GRFGETNUMVM:
647 		*(int *)arg = monitor_def_max;
648 		return (0);
649 
650 	case GM_GRFIOCTL:
651 		return (cv_ioctl (gp, (int) arg, (caddr_t) a2));
652 
653 	default:
654 		break;
655 	}
656 
657 	return (EINVAL);
658 }
659 
660 int
661 cv_ioctl (gp, cmd, data)
662 	register struct grf_softc *gp;
663 	int cmd;
664 	void *data;
665 {
666 	switch (cmd) {
667 	case GRFIOCGSPRITEPOS:
668 	case GRFIOCSSPRITEPOS:
669 	case GRFIOCSSPRITEINF:
670 	case GRFIOCGSPRITEINF:
671 	case GRFIOCGSPRITEMAX:
672 		break;
673 
674 	case GRFIOCGETCMAP:
675 		return (cv_getcmap (gp, (struct grf_colormap *) data));
676 
677 	case GRFIOCPUTCMAP:
678 		return (cv_putcmap (gp, (struct grf_colormap *) data));
679 
680 	case GRFIOCBITBLT:
681 		break;
682 
683 	case GRFTOGGLE:
684 		return (cv_toggle (gp));
685 
686 	case GRFIOCSETMON:
687 		return (cv_setmonitor (gp, (struct grfvideo_mode *)data));
688 
689 	case GRFIOCBLANK:
690 		return (cv_blank (gp, (int *)data));
691 	}
692 	return (EINVAL);
693 }
694 
695 int
696 cv_setmonitor(gp, gv)
697 	struct grf_softc *gp;
698 	struct grfvideo_mode *gv;
699 {
700 	struct grfvideo_mode *md;
701 
702 	if (!cv_mondefok(gv))
703 		return (EINVAL);
704 
705 #ifdef CV64CONSOLE
706 	/* handle interactive setting of console mode */
707 	if (gv->mode_num == 255) {
708 		bcopy(gv, &cvconsole_mode.gv, sizeof(struct grfvideo_mode));
709 		cvconsole_mode.gv.hblank_start /= 8;
710 		cvconsole_mode.gv.hblank_stop /= 8;
711 		cvconsole_mode.gv.hsync_start /= 8;
712 		cvconsole_mode.gv.hsync_stop /= 8;
713 		cvconsole_mode.gv.htotal /= 8;
714 		cvconsole_mode.rows = gv->disp_height / cvconsole_mode.fy;
715 		cvconsole_mode.cols = gv->disp_width / cvconsole_mode.fx;
716 		if (!(gp->g_flags & GF_GRFON))
717 			cv_load_mon(gp, &cvconsole_mode);
718 		ite_reinit(gp->g_itedev);
719 		return (0);
720 	}
721 #endif
722 
723 	md = monitor_def + (gv->mode_num - 1);
724 	bcopy(gv, md, sizeof(struct grfvideo_mode));
725 
726 	/* adjust pixel oriented values to internal rep. */
727 
728 	md->hblank_start /= 8;
729 	md->hblank_stop /= 8;
730 	md->hsync_start /= 8;
731 	md->hsync_stop /= 8;
732 	md->htotal /= 8;
733 
734 	return (0);
735 }
736 
737 int
738 cv_getcmap(gfp, cmap)
739 	struct grf_softc *gfp;
740 	struct grf_colormap *cmap;
741 {
742 	volatile caddr_t ba;
743 	u_char red[256], green[256], blue[256], *rp, *gp, *bp;
744 	short x;
745 	int error;
746 
747 	if (cmap->count == 0 || cmap->index >= 256)
748 		return (0);
749 
750 	if (cmap->index + cmap->count > 256)
751 		cmap->count = 256 - cmap->index;
752 
753 	ba = gfp->g_regkva;
754 	/* first read colors out of the chip, then copyout to userspace */
755 	vgaw (ba, VDAC_ADDRESS_W, cmap->index);
756 	x = cmap->count - 1;
757 
758 	rp = red + cmap->index;
759 	gp = green + cmap->index;
760 	bp = blue + cmap->index;
761 
762 	do {
763 		*rp++ = vgar (ba, VDAC_DATA) << 2;
764 		*gp++ = vgar (ba, VDAC_DATA) << 2;
765 		*bp++ = vgar (ba, VDAC_DATA) << 2;
766 	} while (x-- > 0);
767 
768 	if (!(error = copyout (red + cmap->index, cmap->red, cmap->count))
769 	    && !(error = copyout (green + cmap->index, cmap->green, cmap->count))
770 	    && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count)))
771 		return (0);
772 
773 	return (error);
774 }
775 
776 int
777 cv_putcmap(gfp, cmap)
778 	struct grf_softc *gfp;
779 	struct grf_colormap *cmap;
780 {
781 	volatile caddr_t ba;
782 	u_char red[256], green[256], blue[256], *rp, *gp, *bp;
783 	short x;
784 	int error;
785 
786 	if (cmap->count == 0 || cmap->index >= 256)
787 		return (0);
788 
789 	if (cmap->index + cmap->count > 256)
790 		cmap->count = 256 - cmap->index;
791 
792 	/* first copy the colors into kernelspace */
793 	if (!(error = copyin (cmap->red, red + cmap->index, cmap->count))
794 	    && !(error = copyin (cmap->green, green + cmap->index, cmap->count))
795 	    && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count))) {
796 		ba = gfp->g_regkva;
797 		vgaw (ba, VDAC_ADDRESS_W, cmap->index);
798 		x = cmap->count - 1;
799 
800 		rp = red + cmap->index;
801 		gp = green + cmap->index;
802 		bp = blue + cmap->index;
803 
804 		do {
805 			vgaw (ba, VDAC_DATA, *rp++ >> 2);
806 			vgaw (ba, VDAC_DATA, *gp++ >> 2);
807 			vgaw (ba, VDAC_DATA, *bp++ >> 2);
808 		} while (x-- > 0);
809 		return (0);
810 	} else
811 		return (error);
812 }
813 
814 
815 int
816 cv_toggle(gp)
817 	struct grf_softc *gp;
818 {
819 	volatile caddr_t ba;
820 
821 	ba = gp->g_regkva;
822 	cvscreen(1, ba - READ_OFFSET);
823 
824 	return (0);
825 }
826 
827 
828 int
829 cv_mondefok(gv)
830 	struct grfvideo_mode *gv;
831 {
832 	unsigned long maxpix;
833 
834 	if (gv->mode_num < 1 || gv->mode_num > monitor_def_max)
835 		if (gv->mode_num != 255 || gv->depth != 4)
836 			return (0);
837 
838 	switch(gv->depth) {
839 	   case 1:
840 	   case 4:
841 		/* Remove this comment when ite5 is ready */
842 		/* if (gv->mode_num != 255) */
843 			return (0);
844 	   case 8:
845 		maxpix = MAXPIXELCLOCK;
846 		break;
847 	   case 15:
848 	   case 16:
849 		maxpix = MAXPIXELCLOCK - 55000000;
850 		break;
851 	   case 24:
852 		maxpix = MAXPIXELCLOCK - 85000000;
853 		break;
854 	   default:
855 		return (0);
856 	}
857 
858 	if (gv->pixel_clock > maxpix)
859 		return (0);
860 	return (1);
861 }
862 
863 int
864 cv_load_mon(gp, md)
865 	struct grf_softc *gp;
866 	struct grfcvtext_mode *md;
867 {
868 	struct grfvideo_mode *gv;
869 	struct grfinfo *gi;
870 	volatile caddr_t ba, fb;
871 	unsigned short mnr;
872 	unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
873 		VSE, VT;
874 	char LACE, DBLSCAN, TEXT;
875 	int uplim, lowlim;
876 	int cr33, sr15, sr18, clock_mode, test;
877 	int m, n, clock;	/* For calc'ing display FIFO */
878 
879 	/* identity */
880 	gv = &md->gv;
881 	TEXT = (gv->depth == 4);
882 
883 	if (!cv_mondefok(gv)) {
884 		printf("mondef not ok\n");
885 		return (0);
886 	}
887 	ba = gp->g_regkva;
888 	fb = gp->g_fbkva;
889 
890 	/* turn gfx off, don't mess up the display */
891 	gfx_on_off(1, ba);
892 
893 	/* provide all needed information in grf device-independant locations */
894 	gp->g_data		= (caddr_t) gv;
895 	gi = &gp->g_display;
896 	gi->gd_colors		= 1 << gv->depth;
897 	gi->gd_planes		= gv->depth;
898 	gi->gd_fbwidth		= gv->disp_width;
899 	gi->gd_fbheight		= gv->disp_height;
900 	gi->gd_fbx		= 0;
901 	gi->gd_fby		= 0;
902 	if (TEXT) {
903 		gi->gd_dwidth	= md->fx * md->cols;
904 		gi->gd_dheight	= md->fy * md->rows;
905 	} else {
906 		gi->gd_dwidth	= gv->disp_width;
907 		gi->gd_dheight	= gv->disp_height;
908 	}
909 	gi->gd_dx		= 0;
910 	gi->gd_dy		= 0;
911 
912 	/* get display mode parameters */
913 
914 	HBS = gv->hblank_start;
915 	HBE = gv->hblank_stop;
916 	HSS = gv->hsync_start;
917 	HSE = gv->hsync_stop;
918 	HT  = gv->htotal - 5;
919 	VBS = gv->vblank_start - 1;
920 	VSS = gv->vsync_start;
921 	VSE = gv->vsync_stop;
922 	VBE = gv->vblank_stop;
923 	VT  = gv->vtotal - 2;
924 
925 	if (TEXT)
926 		HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
927 	else
928 		HDE = (gv->disp_width + 3) / 8 - 1; /*HBS;*/
929 	VDE = gv->disp_height - 1;
930 
931 	/* figure out whether lace or dblscan is needed */
932 
933 	uplim = gv->disp_height + (gv->disp_height / 4);
934 	lowlim = gv->disp_height - (gv->disp_height / 4);
935 	LACE = (((VT * 2) > lowlim) && ((VT * 2) < uplim)) ? 1 : 0;
936 	DBLSCAN = (((VT / 2) > lowlim) && ((VT / 2) < uplim)) ? 1 : 0;
937 
938 	/* adjustments */
939 
940 	if (LACE)
941 		VDE /= 2;
942 
943 	WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
944 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
945 	WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
946 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
947 
948 	/* Set clock */
949 
950 	switch (gv->depth) {
951 	   case 15:
952 	   case 16:
953 		mnr = compute_clock(gv->pixel_clock * 2);
954 		break;
955 	   case 24:
956 		mnr = compute_clock(gv->pixel_clock * 3);
957 		break;
958 	   default:
959 		mnr = compute_clock(gv->pixel_clock);
960 		break;
961 	}
962 
963 	WSeq(ba, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8) );
964 	WSeq(ba, SEQ_ID_DCLK_LO, (mnr & 0xFF));
965 
966 	/* load display parameters into board */
967 
968 	WCrt(ba, CRT_ID_EXT_HOR_OVF,
969 	   ((HT & 0x100) ? 0x01 : 0x00) |
970 	   ((HDE & 0x100) ? 0x02 : 0x00) |
971 	   ((HBS & 0x100) ? 0x04 : 0x00) |
972 	/* ((HBE & 0x40) ? 0x08 : 0x00) | */  /* Later... */
973 	   ((HSS & 0x100) ? 0x10 : 0x00) |
974 	/* ((HSE & 0x20) ? 0x20 : 0x00) | */
975 	   (((HT-5) & 0x100) ? 0x40 : 0x00) );
976 
977 	WCrt(ba, CRT_ID_EXT_VER_OVF,
978 	    0x40 |	/* Line compare */
979 	    ((VT  & 0x400) ? 0x01 : 0x00) |
980 	    ((VDE & 0x400) ? 0x02 : 0x00) |
981 	    ((VBS & 0x400) ? 0x04 : 0x00) |
982 	    ((VSS & 0x400) ? 0x10 : 0x00) );
983 
984 	WCrt(ba, CRT_ID_HOR_TOTAL, HT);
985 	WCrt(ba, CRT_ID_DISPLAY_FIFO, HT - 5);
986 
987 	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
988 	WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
989 	WCrt(ba, CRT_ID_END_HOR_BLANK, ((HBE & 0x1f) | 0x80));
990 	WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
991 	WCrt(ba, CRT_ID_END_HOR_RETR,
992 	    (HSE & 0x1f) |
993 	    ((HBE & 0x20) ? 0x80 : 0x00) );
994 	WCrt(ba, CRT_ID_VER_TOTAL, VT);
995 	WCrt(ba, CRT_ID_OVERFLOW,
996 	    0x10 |
997 	    ((VT  & 0x100) ? 0x01 : 0x00) |
998 	    ((VDE & 0x100) ? 0x02 : 0x00) |
999 	    ((VSS & 0x100) ? 0x04 : 0x00) |
1000 	    ((VBS & 0x100) ? 0x08 : 0x00) |
1001 	    ((VT  & 0x200) ? 0x20 : 0x00) |
1002 	    ((VDE & 0x200) ? 0x40 : 0x00) |
1003 	    ((VSS & 0x200) ? 0x80 : 0x00) );
1004 
1005 	WCrt(ba, CRT_ID_MAX_SCAN_LINE,
1006 	    0x40 |  /* TEXT ? 0x00 ??? */
1007 	    (DBLSCAN ? 0x80 : 0x00) |
1008 	    ((VBS & 0x200) ? 0x20 : 0x00) |
1009 	    (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
1010 
1011 	WCrt(ba, CRT_ID_MODE_CONTROL,
1012 	    ((TEXT || (gv->depth == 1)) ? 0xc3 : 0xe3));
1013 
1014 	/* text cursor */
1015 
1016 	if (TEXT) {
1017 #if 1
1018 		WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
1019 		WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
1020 #else
1021 		WCrt(ba, CRT_ID_CURSOR_START, 0x00);
1022 		WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
1023 #endif
1024 		WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f);
1025 
1026 		WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1027 		WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
1028 	}
1029 
1030 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
1031 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
1032 
1033 	WCrt(ba, CRT_ID_START_VER_RETR, VSS);
1034 	WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f));
1035 	WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
1036 	WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
1037 	WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
1038 
1039 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
1040 	WCrt(ba, CRT_ID_LACE_RETR_START, HT / 2);
1041 	WCrt(ba, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
1042 
1043 	WGfx(ba, GCT_ID_GRAPHICS_MODE,
1044 	    ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
1045 	WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
1046 
1047 	WSeq (ba, SEQ_ID_MEMORY_MODE,
1048 	    ((TEXT || (gv->depth == 1)) ? 0x6 : 0x02));
1049 
1050 	vgaw(ba, VDAC_MASK, 0xff);
1051 
1052 	sr15 = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);
1053 	sr15 &= 0xef;
1054 	sr18 = RSeq(ba, SEQ_ID_RAMDAC_CNTL);
1055 	sr18 &= 0x7f;
1056 	cr33 = RCrt(ba, CRT_ID_BACKWAD_COMP_2);
1057 	cr33 &= 0xdf;
1058 	clock_mode = 0x00;
1059 
1060 	test = RCrt(ba, CRT_ID_EXT_MISC_CNTL_2);
1061 	test &= 0xd;
1062 
1063 	switch (gv->depth) {
1064 	   case 1:
1065 	   case 4: /* text */
1066 		HDE = gv->disp_width / 16;
1067 		break;
1068 	   case 8:
1069 		if (gv->pixel_clock > 80000000) {
1070 			clock_mode = 0x10 | 0x02;
1071 			sr15 |= 0x10;
1072 			sr18 |= 0x80;
1073 			cr33 |= 0x20;
1074 		}
1075 		HDE = gv->disp_width / 8;
1076 		break;
1077 	   case 15:
1078 		clock_mode = 0x30;
1079 		HDE = gv->disp_width / 4;
1080 		break;
1081 	   case 16:
1082 		clock_mode = 0x50;
1083 		HDE = gv->disp_width / 4;
1084 		break;
1085 	   case 24:
1086 		clock_mode = 0xd0;
1087 		HDE = (gv->disp_width / 8) * 3;
1088 		break;
1089 	}
1090 
1091 	WCrt(ba, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
1092 	WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, sr15);
1093 	WSeq(ba, SEQ_ID_RAMDAC_CNTL, sr18);
1094 	WCrt(ba, CRT_ID_BACKWAD_COMP_2, cr33);
1095 	WCrt(ba, CRT_ID_SCREEN_OFFSET, HDE);
1096 
1097 	test = RCrt(ba, CRT_ID_EXT_SYS_CNTL_2);
1098 	/* HDE Overflow in bits 4-5 */
1099 	test |= (HDE >> 4) & 0x30;
1100 	WCrt(ba, CRT_ID_EXT_SYS_CNTL_2, test);
1101 
1102 	delay(100000);
1103 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x0a : 0x41));
1104 	delay(100000);
1105 	WAttr(ba, ACT_ID_COLOR_PLANE_ENA,
1106 	    (gv->depth == 1) ? 0x01 : 0x0f);
1107 	delay(100000);
1108 
1109 	/*
1110 	 * Calc. display fifo m and n parameters
1111 	 * Dont't ask me what the hell these values mean.
1112 	 */
1113 
1114 	n = 0xff;
1115 	if (gv->depth < 9)
1116 		clock = gv->pixel_clock / 500000.0;
1117 	else if (gv->depth == 15)
1118 		clock = gv->pixel_clock / 250000.0;
1119 	else
1120 		clock = (gv->pixel_clock * (gv->depth / 8)) / 500000.0;
1121 
1122 	m = ((int)((55 * .72 + 16.867) * 89.736 / (clock + 39) - 21.1543) / 2) - 1;
1123 
1124 	if (m > 31)
1125 		m = 31;
1126 	else if (m <= 0) {
1127 		m = 0;
1128 		n = 16;
1129 	}
1130 
1131 	m = m << 3;
1132 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, m);
1133 	WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, n);
1134 	delay(10000);
1135 
1136 	/* text initialization */
1137 
1138 	if (TEXT) {
1139 		cv_inittextmode(gp);
1140 	}
1141 
1142 	/* Some kind of Magic */
1143 	WAttr(ba, 0x33, 0);
1144 
1145 	/* turn gfx on again */
1146 	gfx_on_off(0, ba);
1147 
1148 	/* Pass-through */
1149 	cvscreen(0, ba - READ_OFFSET);
1150 
1151 	return (1);
1152 }
1153 
1154 void
1155 cv_inittextmode(gp)
1156 	struct grf_softc *gp;
1157 {
1158 	struct grfcvtext_mode *tm = (struct grfcvtext_mode *)gp->g_data;
1159 	volatile caddr_t ba = gp->g_regkva;
1160 	volatile caddr_t fb = gp->g_fbkva;
1161 	unsigned char *c, *f, y;
1162 	unsigned short z;
1163 
1164 
1165 	/* load text font into beginning of display memory.
1166 	 * Each character cell is 32 bytes long (enough for 4 planes)
1167 	 */
1168 
1169 	SetTextPlane(ba, 0x02);
1170 	cv_memset(fb, 0, 256 * 32);
1171 	c = (unsigned char *) (fb) + (32 * tm->fdstart);
1172 	f = tm->fdata;
1173 	for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy))
1174 		for (y = 0; y < tm->fy; y++)
1175 			*c++ = *f++;
1176 
1177 	/* clear out text/attr planes (three screens worth) */
1178 
1179 	SetTextPlane(ba, 0x01);
1180 	cv_memset(fb, 0x07, tm->cols * tm->rows * 3);
1181 	SetTextPlane(ba, 0x00);
1182 	cv_memset(fb, 0x20, tm->cols * tm->rows * 3);
1183 
1184 	/* print out a little init msg */
1185 
1186 	c = (unsigned char *)(fb) + (tm->cols-16);
1187 	strcpy(c, "CV64");
1188 	c[6] = 0x20;
1189 
1190 	/* set colors (B&W) */
1191 
1192 	vgaw(ba, VDAC_ADDRESS_W, 0);
1193 	for (z=0; z<256; z++) {
1194 		unsigned char r, g, b;
1195 
1196 		y = (z & 1) ? ((z > 7) ? 2 : 1) : 0;
1197 
1198 		r = cvconscolors[y][0];
1199 		g = cvconscolors[y][1];
1200 		b = cvconscolors[y][2];
1201 		vgaw(ba, VDAC_DATA, r >> 2);
1202 		vgaw(ba, VDAC_DATA, g >> 2);
1203 		vgaw(ba, VDAC_DATA, b >> 2);
1204 	}
1205 }
1206 
1207 void
1208 cv_memset(d, c, l)
1209 	unsigned char *d;
1210 	unsigned char c;
1211 	int l;
1212 {
1213 	for(; l > 0; l--)
1214 		*d++ = c;
1215 }
1216 
1217 #endif  /* NGRFCV */
1218