grf_ul.c revision 1.21 1 /* $NetBSD: grf_ul.c,v 1.21 1996/10/10 23:55:53 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 kprintf("\ndownloading TMS code");
277 i=0;
278 while ((j = tmscode[i++])) {
279 kprintf(".");
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 kprintf("\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 kprintf("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