xref: /netbsd-src/sys/arch/amiga/dev/grf_ul.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
1 /*	$NetBSD: grf_ul.c,v 1.22 1996/10/13 03:07:07 christos Exp $	*/
2 #define UL_DEBUG
3 
4 /*
5  * Copyright (c) 1995 Ignatios Souvatzis
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by Ignatios Souvatzis for
19  *      the NetBSD project.
20  * 4. The name of the authors may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 #include "grful.h"
35 #if NGRFUL > 0
36 
37 /* Graphics routines for the University of Lowell A2410 board,
38    using the TMS34010 processor. */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/errno.h>
43 #include <sys/ioctl.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
46 #include <sys/syslog.h>
47 
48 #include <machine/cpu.h>
49 
50 #include <amiga/amiga/device.h>
51 #include <amiga/amiga/isr.h>
52 #include <amiga/dev/zbusvar.h>
53 #include <amiga/dev/grfioctl.h>
54 #include <amiga/dev/grfvar.h>
55 #include <amiga/dev/grf_ulreg.h>
56 
57 extern u_int16_t tmscode[];
58 
59 int ul_ioctl __P((struct grf_softc *, u_long, void *, dev_t));
60 int ul_getcmap __P((struct grf_softc *, struct grf_colormap *, dev_t));
61 int ul_putcmap __P((struct grf_softc *, struct grf_colormap *, dev_t));
62 int ul_bitblt __P((struct grf_softc *, struct grf_bitblt *, dev_t));
63 int ul_blank __P((struct grf_softc *, int *, dev_t));
64 
65 static int ulisr __P((void *));
66 int ulowell_alive __P((struct grfvideo_mode *));
67 static void ul_load_code __P((struct grf_softc *));
68 static int ul_load_mon __P((struct grf_softc *, struct grfvideo_mode *));
69 static int ul_getvmode __P((struct grf_softc *, struct grfvideo_mode *));
70 static int ul_setvmode __P((struct grf_softc *, unsigned));
71 static __inline void ul_setfb __P((struct grf_softc *, u_long));
72 
73 /*
74  * marked true early so that ulowell_cnprobe() can tell if we are alive.
75  */
76 int ulowell_inited;
77 
78 /* standard-palette definition */
79 u_int8_t ul_std_palette[] = {
80 	0,128,  0,128,   0,128,  0,128,  0,255,  0,255,   0,255,  0,255,
81 	0,  0,128,128,   0,  0,128,128,  0,  0,255,255,   0,  0,255,255,
82 	0,  0,  0,  0, 128,128,128,128,  0,  0,  0,  0, 255,255,255,255};
83 
84 u_int8_t ul_ovl_palette[] = {
85 	128, 0, 0, 0,
86 	128, 0, 0, 0,
87 	128, 0, 0, 0};
88 
89 struct grfvideo_mode ul_monitor_defs[] = {
90 
91  	/*
92 	 * Horizontal values are given in TMS units, that is, for the
93 	 * A2410 board, units of 16 pixels. The ioctl multiplies (when
94 	 * exporting) or divides (when importing) them by 16 to conform to.
95 	 *
96 	 * XXX This used to be in units of 8 pixel times. We
97 	 * must also change amiga/stand/grfconfig/grfconfig.c,
98 	 * grf_{rt,rh,cl,cv}.c and egsgrfconfig (the latter to generate the
99 	 * horizontal timings in units of pixels instead of 8 pixels.
100 	 * You will also have to write warnings in BIG BOLD RED BLINKING
101 	 * LETTERS all over the docs, and still people will fry their monitors.
102 	 *
103 	 * btw, the _totals are always sync_start+1, to compute the frequencies
104 	 * correctly. (see TMS34010 manual)
105 	 */
106 
107 	/* 1024x768, 60Hz */
108 	{1, "1024x768",   66667000, 1024, 768, 8,
109 		82, 18, 86, 12, 87, 794, 26, 797, 2, 798},
110 
111 	/* 864x648, 70Hz */
112 	{2, "864x648",    50000000,  864, 648, 8,
113 		61,  7, 65,  3, 66, 667, 19, 677, 4, 678},
114 
115 	/* 800x600, 60Hz */
116 	{3, "800x600",    36000000,  800, 600, 8,
117 		57,  7, 61,  3, 62, 619, 19, 629, 4, 630},
118 
119 	/* 640x400, 60 Hz, interlaced */
120 	{4, "640x400I",   14318000,  640, 400, 8,
121 		48,  8, 56,  3, 57, 239, 39, 262, 2, 240},
122 
123 	/* 1024x768, 65Hz interlaced, s.th. is strange */
124 	{5, "1024x768?I", 44980000, 1024, 768, 8,
125 		76, 12, 79,  3, 80, 512, 24, 533, 2, 534},
126 
127 	/* 1024x1024, 60Hz */
128 	{6, "1024x1024", 80000000, 1024,1024, 8,
129 		77, 13, 78,  5, 78,1051, 27,1054, 2,1055},
130 
131 	/* 736x480, 60 Hz */
132 	{7, "736x480", 28636300, 736, 480, 8,
133 		54,  8, 57,  3, 58, 503, 23, 514, 3, 515},
134 };
135 
136 int ulowell_mon_max = sizeof (ul_monitor_defs)/sizeof (ul_monitor_defs[0]);
137 
138 /* option settable */
139 #ifndef ULOWELL_OSC1
140 #define ULOWELL_OSC1 36000000
141 #endif
142 
143 #ifndef ULOWELL_OSC2
144 #define ULOWELL_OSC2 66667000
145 #endif
146 
147 #ifndef ULOWELL_DEFAULT_MON
148 #define ULOWELL_DEFAULT_MON 1
149 #endif
150 
151 /* patchable */
152 int ulowell_default_mon = ULOWELL_DEFAULT_MON;
153 int ulowell_default_gfx = ULOWELL_DEFAULT_MON;
154 
155 /*
156  * yes, this should be per board. We don't pay service to multiple boards,
157  * anyway.
158  */
159 
160 u_long ulowell_clock[2] = { ULOWELL_OSC2, ULOWELL_OSC1 };
161 
162 static struct grfvideo_mode *current_mon;
163 
164 /*
165  * We dont use ints at the moment, but will need this later to avoid
166  * busy_waiting in gsp_write, and we use it for spurious int warnings.
167  */
168 
169 static int
170 ulisr(arg)
171 	void *arg;
172 {
173 	struct grf_softc *gp = arg;
174 	struct gspregs *ba;
175 	u_int16_t	thebits;
176 
177 	if (gp == NULL)
178 		return 0;
179 
180 	ba = (struct gspregs *)gp->g_regkva;
181 
182 	if (ba == NULL)
183 		return 0;
184 
185 	thebits = ba->ctrl;
186 	if (thebits & INTOUT) {
187 		log(LOG_INFO, "grf4: got interrupt, ctrl=0x%4x\n", thebits);
188 		/* clear int */
189 		ba->ctrl = thebits & ~INTOUT;
190 		return 1;
191 	}
192 	return 0;
193 }
194 
195 /*
196  * used to query the ulowell board to see if its alive.
197  * for the moment, a NOP.
198  */
199 int
200 ulowell_alive(mdp)
201 	struct grfvideo_mode *mdp;
202 {
203 	return 1;
204 }
205 
206 /*
207  * Load the (mostly) ite support code and the default colormaps.
208  */
209 static void
210 ul_load_code(gp)
211 	struct grf_softc *gp;
212 {
213 	struct grf_ul_softc *gup;
214 	struct gspregs *ba;
215 	struct grfinfo *gi;
216 	int i,j;
217 #if 0
218 	struct grf_colormap gcm;
219 #endif
220 
221 	gup = (struct grf_ul_softc *)gp;
222 	ba = (struct gspregs *)gp->g_regkva;
223 	gi = &gp->g_display;
224 
225 	gi->gd_regaddr	= ztwopa((caddr_t)ba);
226 	gi->gd_regsize	= sizeof(struct gspregs);
227 	gi->gd_fbaddr	= NULL;
228 	gi->gd_fbsize	= 0;
229 	gi->gd_fbwidth	= 1024;
230 	gi->gd_fbheight	= 1024;
231 	gi->gd_colors	= 256;
232 
233 	ba->ctrl = (ba->ctrl & ~INCR) | (LBL | INCW);
234 	ba->hstadrh = 0xC000;
235 	ba->hstadrl = 0x0080;
236 	ba->data = 0x0;		/* disable screen refresh and video output */
237 	ba->data = 0xFFFC;	/* screen refresh base address */
238 	ba->data = 0xFFFF;	/* no display int possible */
239 	ba->data = 0x000C;	/* CAS before RAS refresh each 64 local clks */
240 
241 	ba->ctrl = (ba->ctrl & ~INCW) | LBL;
242 	ba->hstadrh = 0xfe80;
243 	ba->hstadrl = 0;
244 	ba->data = 4;
245 	ba->hstadrl = 0x20;
246 	ba->data = 0xFF;	/* all color planes visible */
247 
248 	ba->hstadrl = 0;
249 	ba->data = 5;
250 	ba->hstadrl = 0x20;
251 	ba->data = 0;		/* no color planes blinking */
252 
253 	ba->hstadrl = 0;
254 	ba->data = 6;
255 	ba->hstadrl = 0x20;
256 	ba->data = gup->gus_ovslct = 0x43;
257 	/* overlay visible, no overlay blinking, overlay color 0 transparent */
258 
259 	ba->hstadrl = 0;
260 	ba->data = 7;
261 	ba->hstadrl = 0x20;
262 	ba->data = 0;		/* voodoo */
263 
264 	/* clear overlay planes */
265 	ba->ctrl |= INCW;
266 	ba->hstadrh = 0xff80;
267 	ba->hstadrl = 0x0000;
268 	for (i=0xff80000; i< 0xffa0000; ++i) {
269 		ba->data = 0;
270 	}
271 
272 	/* download tms code */
273 
274 	ba->ctrl = LBL | INCW | NMI | NMIM | HLT | CF;
275 
276 	printf("\ndownloading TMS code");
277 	i=0;
278 	while ((j = tmscode[i++])) {
279 		printf(".");
280 		ba->hstadrh = tmscode[i++];
281 		ba->hstadrl = tmscode[i++];
282 		while (j-- > 0) {
283 			ba->data = tmscode[i++];
284 		}
285 	}
286 
287 	/* font info was uploaded in ite_ul.c(ite_ulinit). */
288 
289 #if 1
290 	/* XXX load image palette with some initial values, slightly hacky */
291 
292 	ba->hstadrh = 0xfe80;
293 	ba->hstadrl = 0x0000;
294 	ba->ctrl |= INCW;
295 	ba->data = 0;
296 	ba->ctrl &= ~INCW;
297 
298 	for (i=0; i<16; ++i) {
299 		ba->data = gup->gus_imcmap[i+  0] = ul_std_palette[i+ 0];
300 		ba->data = gup->gus_imcmap[i+256] = ul_std_palette[i+16];
301 		ba->data = gup->gus_imcmap[i+512] = ul_std_palette[i+32];
302 	}
303 
304 	/*
305 	 * XXX load shadow overlay palette with what the TMS code will load
306 	 * into the real one some time after the TMS code is started below.
307 	 * This might be considered a rude hack.
308 	 */
309 	bcopy(ul_ovl_palette, gup->gus_ovcmap, 3*4);
310 
311 	/*
312 	 * Unflush cache, unhalt cpu -> nmi starts to run. This MUST NOT BE
313 	 * DONE before the image color map initialization above, to guarantee
314 	 * the index register in the BT458 is not used by more than one CPU
315 	 * at once.
316 	 *
317 	 * XXX For the same reason, we'll have to rething ul_putcmap(). For
318 	 * details, look at comment there.
319 	 */
320 	ba->ctrl &= ~(HLT|CF);
321 
322 #else
323 	/*
324 	 * XXX I wonder why this partially ever worked.
325 	 *
326 	 * This can't possibly work this way, as we are copyin()ing data in
327 	 * ul_putcmap.
328 	 *
329 	 * I guess this partially worked because SFC happened to point to
330 	 * to supervisor data space on 68030 machines coming from the old
331 	 * boot loader.
332 	 *
333 	 * While this looks more correct than the hack in the other part of the
334 	 * loop, we would have to do our own version of the loop through
335 	 * colormap entries, set up command buffer, and call gsp_write(), or
336 	 * factor out some code.
337 	 */
338 
339 	/*
340 	 * XXX This version will work for the overlay, if our queue codes
341 	 * initial conditions are set at load time (not start time).
342 	 * It further assumes that ul_putcmap only uses the
343 	 * GRFIMDEV/GRFOVDEV bits of the dev parameter.
344 	 */
345 
346 
347 	/* unflush cache, unhalt cpu first -> nmi starts to run */
348 	ba->ctrl &= ~(HLT|CF);
349 
350 	gcm.index = 0;
351 	gcm.count = 16;
352 	gcm.red   = ul_std_palette +  0;
353 	gcm.green = ul_std_palette + 16;
354 	gcm.blue  = ul_std_palette + 32;
355 	ul_putcmap(gp, &gcm, GRFIMDEV);
356 
357 	gcm.index = 0;
358 	gcm.count = 4;
359 	gcm.red   = ul_ovl_palette + 0;
360 	gcm.green = ul_ovl_palette + 4;
361 	gcm.blue  = ul_ovl_palette + 8;
362 	ul_putcmap(gp, &gcm, GRFOVDEV);
363 #endif
364 
365 }
366 
367 static int
368 ul_load_mon(gp, md)
369 	struct grf_softc *gp;
370 	struct grfvideo_mode *md;
371 {
372 	struct grf_ul_softc *gup;
373 	struct grfinfo *gi;
374 	struct gspregs *ba;
375 	u_int16_t buf[8];
376 
377 	gup = (struct grf_ul_softc *)gp;
378 	gi = &gp->g_display;
379 	ba = (struct gspregs *)gp->g_regkva;
380 
381 	gi->gd_dyn.gdi_fbx	= 0;
382 	gi->gd_dyn.gdi_fby	= 0;
383 	gi->gd_dyn.gdi_dwidth	= md->disp_width;
384 	gi->gd_dyn.gdi_dheight	= md->disp_height;
385 	gi->gd_dyn.gdi_dx	= 0;
386 	gi->gd_dyn.gdi_dy	= 0;
387 
388 	ba->ctrl = (ba->ctrl & ~INCR) | (LBL | INCW); /* XXX */
389 
390 	ba->hstadrh = 0xC000;
391 	ba->hstadrl = 0x0000;
392 	ba->data = md->hsync_stop;
393 	ba->data = md->hblank_stop;
394 	ba->data = md->hblank_start;
395 	ba->data = md->hsync_start;
396 	ba->data = md->vsync_stop;
397 	ba->data = md->vblank_stop;
398 	ba->data = md->vblank_start;
399 	ba->data = md->vsync_start;
400 
401 	ba->ctrl &= ~INCW;
402 	ba->hstadrh = 0xFE90;
403 	ba->hstadrl = 0x0000;
404 
405 	if (abs(md->pixel_clock - ulowell_clock[0]) >
406 	    abs(md->pixel_clock - ulowell_clock[1])) {
407 
408 		ba->data = (ba->data & 0xFC) | 2 | 1;
409 		md->pixel_clock = ulowell_clock[1];
410 
411 	} else {
412 		ba->data = (ba->data & 0xFC) | 2 | 0;
413 		md->pixel_clock = ulowell_clock[0];
414 	}
415 
416 	ba->ctrl |= LBL | INCW;
417 	ba->hstadrh = 0xC000;
418 	ba->hstadrl = 0x0080;
419 	ba->data = (md->vblank_start - md->vblank_stop == md->disp_height ?
420 	    0xf020 : 0xb020);
421 
422 	/* I guess this should be in the yet unimplemented mode select ioctl */
423 	/* Hm.. maybe not. We always put the console on overlay plane no 0. */
424 	/* Anyway, this _IS_ called in the mode select ioctl. */
425 
426 	/* ite support code parameters: */
427 	buf[0] = GCMD_MCHG;
428 	buf[1] = md->disp_width;	/* display width */
429 	buf[2] = md->disp_height;	/* display height */
430 	buf[3] = 0;			/* LSW of frame buffer origin */
431 	buf[4] = 0xFF80;		/* MSW of frame buffer origin */
432 	buf[5] = gi->gd_fbwidth * 1;	/* frame buffer pitch */
433 	buf[6] = 1;			/* frame buffer depth */
434 	gsp_write(ba, buf, 7);
435 
436 	return(1);
437 }
438 
439 int ul_mode __P((struct grf_softc *, u_long, void *, u_long, int));
440 
441 void grfulattach __P((struct device *, struct device *, void *));
442 int grfulprint __P((void *, const char *));
443 int grfulmatch __P((struct device *, void *, void *));
444 
445 struct cfattach grful_ca = {
446 	sizeof(struct grf_ul_softc), grfulmatch, grfulattach
447 };
448 
449 struct cfdriver grful_cd = {
450 	NULL, "grful", DV_DULL, NULL, 0
451 };
452 
453 /*
454  * only used in console init
455  */
456 static struct cfdata *cfdata;
457 
458 /*
459  * we make sure to only init things once.  this is somewhat
460  * tricky regarding the console.
461  */
462 int
463 grfulmatch(pdp, match, auxp)
464 	struct device *pdp;
465 	void *match, *auxp;
466 {
467 #ifdef ULOWELLCONSOLE
468 	struct cfdata *cfp = match;
469 	static int ulconunit = -1;
470 #endif
471 	struct zbus_args *zap;
472 
473 	zap = auxp;
474 
475 	/*
476 	 * allow only one ulowell console
477 	 */
478         if (amiga_realconfig == 0)
479 #ifdef ULOWELLCONSOLE
480 		if (ulconunit != -1)
481 #endif
482 			return(0);
483 
484 	if (zap->manid != 1030 || zap->prodid != 0)
485 		return(0);
486 
487 #ifdef ULOWELLCONSOLE
488 	if (amiga_realconfig == 0 || ulconunit != cfp->cf_unit) {
489 #endif
490 		if ((unsigned)ulowell_default_mon > ulowell_mon_max)
491 			ulowell_default_mon = 1;
492 
493 		current_mon = ul_monitor_defs + ulowell_default_mon - 1;
494 		if (ulowell_alive(current_mon) == 0)
495 			return(0);
496 #ifdef ULOWELLCONSOLE
497 		if (amiga_realconfig == 0) {
498 			ulconunit = cfp->cf_unit;
499 			cfdata = cfp;
500 		}
501 	}
502 #endif
503 	return(1);
504 }
505 
506 /*
507  * attach to the grfbus (zbus)
508  */
509 void
510 grfulattach(pdp, dp, auxp)
511 	struct device *pdp, *dp;
512 	void *auxp;
513 {
514 	static struct grf_ul_softc congrf;
515 	struct zbus_args *zap;
516 	struct grf_softc *gp;
517 	struct grf_ul_softc *gup;
518 
519 	zap = auxp;
520 
521 	if (dp == NULL)
522 		gup = &congrf;
523 	else
524 		gup = (struct grf_ul_softc *)dp;
525 
526 	gp = &gup->gus_sc;
527 
528 	if (dp != NULL && congrf.gus_sc.g_regkva != 0) {
529 		/*
530 		 * inited earlier, just copy (not device struct)
531 		 */
532 		bcopy(&congrf.gus_sc.g_display, &gp->g_display,
533 		    (char *)&gup->gus_isr - (char *)&gp->g_display);
534 
535 		/* ...and transfer the isr */
536 		gup->gus_isr.isr_ipl = 2;
537 		gup->gus_isr.isr_intr = ulisr;
538 		gup->gus_isr.isr_arg = (void *)gp;
539 		/*
540 		 * To make sure ints are always catched, first add new isr
541 		 * then remove old:
542 		 */
543 		add_isr(&gup->gus_isr);
544 		remove_isr(&congrf.gus_isr);
545 	} else {
546 		gp->g_regkva = (caddr_t)zap->va;
547 		gp->g_fbkva = NULL;
548 		gp->g_unit = GRF_ULOWELL_UNIT;
549 		gp->g_flags = GF_ALIVE;
550 		gp->g_mode = ul_mode;
551 		gp->g_conpri = grful_cnprobe();
552 		gp->g_data = NULL;
553 
554 		gup->gus_isr.isr_ipl = 2;
555 		gup->gus_isr.isr_intr = ulisr;
556 		gup->gus_isr.isr_arg = (void *)gp;
557 		add_isr(&gup->gus_isr);
558 
559 		(void)ul_load_code(gp);
560 		(void)ul_load_mon(gp, current_mon);
561 		grful_iteinit(gp);
562 	}
563 	if (dp != NULL)
564 		printf("\n");
565 	/*
566 	 * attach grf
567 	 */
568 	amiga_config_found(cfdata, &gp->g_device, gp, grfulprint);
569 }
570 
571 int
572 grfulprint(auxp, pnp)
573 	void *auxp;
574 	const char *pnp;
575 {
576 	if (pnp)
577 		printf("grf%d at %s", ((struct grf_softc *)auxp)->g_unit,
578 			pnp);
579 	return(UNCONF);
580 }
581 
582 static int
583 ul_getvmode (gp, vm)
584 	struct grf_softc *gp;
585 	struct grfvideo_mode *vm;
586 {
587 	struct grfvideo_mode *md;
588 
589 	if (vm->mode_num && vm->mode_num > ulowell_mon_max)
590 		return EINVAL;
591 
592 	if (! vm->mode_num)
593 		vm->mode_num = current_mon - ul_monitor_defs + 1;
594 
595 	md = ul_monitor_defs + vm->mode_num - 1;
596 	strncpy (vm->mode_descr, md->mode_descr,
597 		sizeof (vm->mode_descr));
598 
599 	/* XXX should tell TMS to measure it */
600 	vm->pixel_clock  = md->pixel_clock;
601 	vm->disp_width   = md->disp_width;
602 	vm->disp_height  = md->disp_height;
603 	vm->depth        = md->depth;
604 
605 	vm->hblank_start = (md->hblank_start - md->hblank_stop) * 16;
606 	vm->hblank_stop  = (md->htotal - 1) * 16;
607 	vm->hsync_start  = (md->hsync_start  - md->hblank_stop) * 16;
608 	vm->hsync_stop   = (md->hsync_stop + md->htotal - md->hblank_stop) * 16;
609 	vm->htotal       = md->htotal * 16;
610 
611 	vm->vblank_start = md->vblank_start - md->vblank_stop;
612 	vm->vblank_stop  = md->vtotal - 1;
613 	vm->vsync_start  = md->vsync_start - md->vblank_stop;
614 	vm->vsync_stop   = md->vsync_stop + md->vtotal - md->vblank_stop;
615 	vm->vtotal       = md->vtotal;
616 
617 	return 0;
618 }
619 
620 
621 static int
622 ul_setvmode (gp, mode)
623 	struct grf_softc *gp;
624 	unsigned mode;
625 {
626 	struct grf_ul_softc *gup;
627 	struct gspregs *ba;
628 	int error;
629 
630 	if (!mode || mode > ulowell_mon_max)
631 		return EINVAL;
632 
633 	ba = (struct gspregs *)gp->g_regkva;
634 	gup = (struct grf_ul_softc *)gp;
635 	current_mon = ul_monitor_defs + mode - 1;
636 
637 	error = ul_load_mon (gp, current_mon) ? 0 : EINVAL;
638 
639 	return error;
640 }
641 
642 /*
643  * Set the frame buffer or overlay planes on or off.
644  * Always succeeds.
645  */
646 
647 static __inline void
648 ul_setfb(gp, cmd)
649 	struct grf_softc *gp;
650 	u_long cmd;
651 {
652 	struct grf_ul_softc *gup;
653 	struct gspregs *ba;
654 
655 	gup = (struct grf_ul_softc *)gp;
656 
657 	ba = (struct gspregs *)gp->g_regkva;
658 	ba->ctrl = LBL;
659 	ba->hstadrh = 0xfe80;
660 	ba->hstadrl = 0x0000;
661 	ba->data = 6;
662 	ba->hstadrl = 0x0020;
663 
664 	switch (cmd) {
665 	case GM_GRFON:
666 		gup->gus_ovslct |= 0x40;
667 		break;
668 	case GM_GRFOFF:
669 		gup->gus_ovslct &= ~0x40;
670 		break;
671 	case GM_GRFOVON:
672 		gup->gus_ovslct |= 3;
673 		break;
674 	case GM_GRFOVOFF:
675 		gup->gus_ovslct &= ~3;
676 		break;
677 	}
678 	ba->data = gup->gus_ovslct;
679 }
680 
681 /*
682  * Change the mode of the display.
683  * Return a UNIX error number or 0 for success.
684  */
685 int
686 ul_mode(gp, cmd, arg, a2, a3)
687 	struct grf_softc *gp;
688 	u_long cmd;
689 	void *arg;
690 	u_long a2;
691 	int a3;
692 {
693 	int i;
694 	struct grfdyninfo *gd;
695 
696 	switch (cmd) {
697 	case GM_GRFON:
698 	case GM_GRFOFF:
699 	case GM_GRFOVON:
700 	case GM_GRFOVOFF:
701 		ul_setfb (gp, cmd);
702 		return 0;
703 
704 	case GM_GRFCONFIG:
705 		gd = (struct grfdyninfo *)arg;
706 		for (i=0; i<ulowell_mon_max; ++i) {
707 			if (ul_monitor_defs[i].disp_width == gd->gdi_dwidth &&
708 			    ul_monitor_defs[i].disp_height == gd->gdi_dheight)
709 				return ul_setvmode(gp, i+1);
710 		}
711 		return EINVAL;
712 
713 	case GM_GRFGETVMODE:
714 		return ul_getvmode (gp, (struct grfvideo_mode *) arg);
715 
716 	case GM_GRFSETVMODE:
717 		return ul_setvmode (gp, *(unsigned *) arg);
718 
719 	case GM_GRFGETNUMVM:
720 		*(int *)arg = ulowell_mon_max;
721 		return 0;
722 
723 	case GM_GRFIOCTL:
724 		return ul_ioctl (gp, a2, arg, (dev_t)a3);
725 
726 	default:
727 		break;
728 	}
729 
730 	return EINVAL;
731 }
732 
733 int
734 ul_ioctl (gp, cmd, data, dev)
735 	register struct grf_softc *gp;
736 	u_long cmd;
737 	void *data;
738 	dev_t dev;
739 {
740 	switch (cmd) {
741 #if 0
742 	/*
743 	 * XXX we have no hardware sprites, but might implement them
744 	 * later in TMS code.
745 	 */
746 
747 	case GRFIOCGSPRITEPOS:
748 		return ul_getspritepos (gp, (struct grf_position *) data);
749 
750 	case GRFIOCSSPRITEPOS:
751 		return ul_setspritepos (gp, (struct grf_position *) data);
752 
753 	case GRFIOCSSPRITEINF:
754 		return ul_setspriteinfo (gp, (struct grf_spriteinfo *) data);
755 
756 	case GRFIOCGSPRITEINF:
757 		return ul_getspriteinfo (gp, (struct grf_spriteinfo *) data);
758 
759 	case GRFIOCGSPRITEMAX:
760 		return ul_getspritemax (gp, (struct grf_position *) data);
761 
762 #endif
763 
764 	case GRFIOCGETCMAP:
765 		return ul_getcmap (gp, (struct grf_colormap *) data, dev);
766 
767 	case GRFIOCPUTCMAP:
768 		return ul_putcmap (gp, (struct grf_colormap *) data, dev);
769 
770 	case GRFIOCBITBLT:
771 		return ul_bitblt (gp, (struct grf_bitblt *) data, dev);
772 
773 	case GRFIOCBLANK:
774 		return ul_blank (gp, (int *) data, dev);
775 	}
776 
777 	return EINVAL;
778 }
779 
780 int
781 ul_getcmap (gp, cmap, dev)
782 	struct grf_softc *gp;
783 	struct grf_colormap *cmap;
784 	dev_t dev;
785 {
786 	struct grf_ul_softc *gup;
787 	u_int8_t *mymap;
788 	int mxidx, error;
789 
790 	gup = (struct grf_ul_softc *)gp;
791 
792 	if (minor(dev) & GRFIMDEV) {
793 		mxidx = 256;
794 		mymap = gup->gus_imcmap;
795 	} else {
796 		mxidx = 4;
797 		mymap = gup->gus_ovcmap;
798 	}
799 
800 	if (cmap->count == 0 || cmap->index >= mxidx)
801 		return 0;
802 
803 	if (cmap->index + cmap->count > mxidx)
804 		cmap->count = mxidx - cmap->index;
805 
806 	/* just copyout from the shadow color map */
807 
808 	if ((error = copyout(mymap + cmap->index, cmap->red, cmap->count))
809 
810 	    || (error = copyout(mymap + mxidx + cmap->index, cmap->green,
811 		cmap->count))
812 
813 	    || (error = copyout(mymap + mxidx * 2 + cmap->index, cmap->blue,
814 		cmap->count)))
815 
816 		return(error);
817 
818 	return(0);
819 }
820 
821 int
822 ul_putcmap (gp, cmap, dev)
823 	struct grf_softc *gp;
824 	struct grf_colormap *cmap;
825 	dev_t dev;
826 {
827 	struct grf_ul_softc *gup;
828 	struct gspregs *ba;
829 	u_int16_t cmd[8];
830 	int x, mxidx, error;
831 	u_int8_t *mymap;
832 
833 	gup = (struct grf_ul_softc *)gp;
834 
835 	if (minor(dev) & GRFIMDEV) {
836 		mxidx = 256;
837 		mymap = gup->gus_imcmap;
838 	} else {
839 		mxidx = 4;
840 		mymap = gup->gus_ovcmap;
841 	}
842 
843 	if (cmap->count == 0 || cmap->index >= mxidx)
844 		return 0;
845 
846 	if (cmap->index + cmap->count > mxidx)
847 		cmap->count = mxidx - cmap->index;
848 
849 	/* first copyin to our shadow color map */
850 
851 	if ((error = copyin(cmap->red, mymap + cmap->index, cmap->count))
852 
853 	    || (error = copyin(cmap->green, mymap + cmap->index + mxidx,
854 		cmap->count))
855 
856 	    || (error = copyin(cmap->blue,  mymap + cmap->index + mxidx*2,
857 		cmap->count)))
858 
859 		return error;
860 
861 
862 	/* then write from there to the hardware */
863 	ba = (struct gspregs *)gp->g_regkva;
864 	/*
865 	 * XXX This is a bad thing to do.
866 	 * We should always use the gsp call, or have a means to arbitrate
867 	 * the usage of the BT458 index register. Else there might be a
868 	 * race condition (when writing both colormaps at nearly the same
869 	 * time), where one CPU changes the index register when the other
870 	 * one has not finished using it.
871 	 */
872 	if (mxidx > 4) {
873 		/* image color map: we can write, with a hack, directly */
874 		ba->ctrl = LBL;
875 		ba->hstadrh = 0xfe80;
876 		ba->hstadrl = 0x0000;
877 		ba->ctrl |= INCW;
878 		ba->data = cmap->index;
879 		ba->ctrl &= ~INCW;
880 
881 		for (x=cmap->index; x < cmap->index + cmap->count; ++x) {
882 			ba->data = (u_int16_t) mymap[x];
883 			ba->data = (u_int16_t) mymap[x + mxidx];
884 			ba->data = (u_int16_t) mymap[x + mxidx * 2];
885 		}
886 	} else {
887 
888 		/* overlay planes color map: have to call tms to do it */
889 		cmd[0] = GCMD_CMAP;
890 		cmd[1] = 1;
891 		for (x=cmap->index; x < cmap->index + cmap->count; ++x) {
892 			cmd[2] = x;
893 			cmd[3] = mymap[x];
894 			cmd[4] = mymap[x + mxidx];
895 			cmd[5] = mymap[x + mxidx * 2];
896 			gsp_write(ba, cmd, 6);
897 		}
898 	}
899 	return 0;
900 }
901 
902 int
903 ul_blank(gp, onoff, dev)
904 	struct grf_softc *gp;
905 	int *onoff;
906 	dev_t dev;
907 {
908 	struct gspregs *gsp;
909 
910 	gsp = (struct gspregs *)gp->g_regkva;
911 	gsp->ctrl = (gsp->ctrl & ~(INCR | INCW)) | LBL;
912 	gsp->hstadrh = 0xC000;
913 	gsp->hstadrl = 0x0080;
914 	if (*onoff > 0)
915 		gsp->data |= 0x9000;
916 	else
917 		gsp->data &= ~0x9000;
918 
919 	return 0;
920 }
921 /*
922  * !!! THIS AREA UNDER CONSTRUCTION !!!
923  */
924 int ul_BltOpMap[16] = {
925 	3, 1, 2, 0, 11,  9, 10, 8,
926 	7, 5, 6, 4, 15, 13, 14, 12
927 };
928 
929 int
930 ul_bitblt (gp, bb, dev)
931 	struct grf_softc *gp;
932 	struct grf_bitblt *bb;
933 	dev_t dev;
934 {
935 	/* XXX not yet implemented, but pretty trivial */
936 	return EINVAL;
937 }
938 
939 void
940 gsp_write(gsp, ptr, size)
941 	struct gspregs *gsp;
942 	u_short *ptr;
943 	size_t size;
944 {
945 	u_short put, new_put, next, oc;
946 	u_long put_hi, oa;
947 	size_t n;
948 
949 	if (size == 0 || size > 8)
950 	        return;
951 
952 	n = size;
953 
954 	oc = gsp->ctrl;
955 	oa = GSPGETHADRS(gsp);
956 
957 	gsp->ctrl = (oc & ~INCR) | LBL | INCW;
958 	GSPSETHADRS(gsp, GSP_MODE_ADRS);
959 	gsp->data &= ~GMODE_FLUSH;
960 
961 	GSPSETHADRS(gsp, PUT_HI_PTR_ADRS);
962 	put_hi = gsp->data << 16;
963 
964 	GSPSETHADRS(gsp, PUT_PTR_ADRS);
965 	put = gsp->data;
966 	new_put = put + (8<<4);
967 
968 	GSPSETHADRS(gsp, GET_PTR_ADRS);
969 	next = gsp->data;
970 
971 	while (next == new_put) {
972 		/*
973 		 * we should use an intr. here. unfortunately, we already
974 		 * are called from an interupt and can't use tsleep.
975 		 * so we do busy waiting, at least for the moment.
976 		 */
977 
978 		GSPSETHADRS(gsp,GET_PTR_ADRS);
979 		next = gsp->data;
980 	}
981 
982 	GSPSETHADRS(gsp,put|put_hi);
983 	gsp->data = *ptr++ | 8<<4;
984 	while ( --n > 0) {
985 		gsp->data = *ptr++;
986 	}
987 
988 	GSPSETHADRS(gsp,PUT_PTR_ADRS);
989 	gsp->data = new_put;
990 	GSPSETHADRS(gsp,oa);
991 	gsp->ctrl = oc;
992 
993 	return;
994 }
995 
996 #endif	/* NGRF */
997