1 /*        $NetBSD: gpx.c,v 1.4 2024/09/30 00:34:04 rin Exp $ */
2 /*        $OpenBSD: gpx.c,v 1.25 2014/12/23 21:39:12 miod Exp $       */
3 /*
4  * Copyright (c) 2006 Miodrag Vallat.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice, this permission notice, and the disclaimer below
9  * appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 /*-
20  * Copyright (c) 1988 Regents of the University of California.
21  * All rights reserved.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. Neither the name of the University nor the names of its contributors
32  *    may be used to endorse or promote products derived from this software
33  *    without specific prior written permission.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45  * SUCH DAMAGE.
46  *
47  *        @(#)qd.c  7.1 (Berkeley) 6/28/91
48  */
49 
50 /************************************************************************
51 *                                                                                         *
52 *                             Copyright (c) 1985-1988 by                        *
53 *                   Digital Equipment Corporation, Maynard, MA                  *
54 *                             All rights reserved.                                        *
55 *                                                                                         *
56 *   This software is furnished under a license and may be used and    *
57 *   copied  only  in accordance with the terms of such license and    *
58 *   with the  inclusion  of  the  above  copyright  notice.   This    *
59 *   software  or  any  other copies thereof may not be provided or    *
60 *   otherwise made available to any other person.  No title to and    *
61 *   ownership of the software is hereby transferred.                            *
62 *                                                                                         *
63 *   The information in this software is subject to change  without    *
64 *   notice  and should not be construed as a commitment by Digital    *
65 *   Equipment Corporation.                                                      *
66 *                                                                                         *
67 *   Digital assumes no responsibility for the use  or  reliability    *
68 *   of its software on equipment which is not supplied by Digital.    *
69 *                                                                                         *
70 *************************************************************************/
71 
72 /*
73  * Driver for the GPX color option on VAXstation 3100, based on the
74  * MicroVAX II qdss driver.
75  *
76  * The frame buffer memory itself is not directly accessible (unlike
77  * the on-board monochrome smg frame buffer), and writes through the
78  * Dragon chip can only happen in multiples of 16 pixels, horizontally.
79  *
80  * Because of this limitation, the font image is copied to offscreen
81  * memory (which there is plenty of), and screen to screen blt operations
82  * are done for everything.
83  */
84 
85 #include "dzkbd.h"
86 #include "wsdisplay.h"
87 
88 #include <sys/param.h>
89 #include <sys/device.h>
90 #include <sys/systm.h>
91 #include <sys/kmem.h>
92 #include <sys/conf.h>
93 
94 #include <machine/sid.h>
95 #include <machine/cpu.h>
96 #include <machine/ka420.h>
97 #include <machine/scb.h>
98 #include <machine/vsbus.h>
99 #include <machine/qdreg.h>
100 
101 #include <dev/cons.h>
102 
103 #include <dev/dec/dzreg.h>
104 #include <dev/dec/dzvar.h>
105 #include <dev/dec/dzkbdvar.h>
106 
107 #include <dev/wscons/wsconsio.h>
108 #include <dev/wscons/wscons_callbacks.h>
109 #include <dev/wscons/wsdisplayvar.h>
110 #include <dev/rasops/rasops.h>
111 #include <dev/wsfont/wsfont.h>
112 
113 #if 0
114 #include <dev/ic/bt458reg.h>
115 #include <dev/ic/dc503reg.h>
116 #endif
117 
118 #define   GPXADDR             0x3c000000          /* base address on VAXstation 3100 */
119 
120 #define   GPX_ADDER_OFFSET    0x0000
121 #define   GPX_VDAC_OFFSET               0x0300
122 #define   GPX_CURSOR_OFFSET   0x0400    /* DC503 */
123 #define   GPX_READBACK_OFFSET 0x0500
124 
125 #define   GPX_WIDTH 1024
126 #define   GPX_VISHEIGHT       864
127 #define   GPX_HEIGHT          2048
128 
129 /* XXX these should be in <dev/ic/bt458reg.h> */
130 /*
131  * Brooktree Bt451, Bt457, Bt458 register definitions
132  */
133 #define BT_OV0      0x00                /* overlay 0 */
134 #define BT_OV1      0x01                /* overlay 1 */
135 #define BT_OV2      0x02                /* overlay 2 */
136 #define BT_OV3      0x03                /* overlay 3 */
137 #define BT_RMR      0x04                /* read mask */
138 #define BT_BMR      0x05                /* blink mask */
139 #define BT_CR       0x06                /* control */
140 #define BT_CTR      0x07                /* control/test */
141 
142 #define BTCR_MPLX_5           0x80      /* multiplex select, 5:1 */
143 #define BTCR_MPLX_4           0x00      /* multiplex select, 4:1 */
144 #define BTCR_RAMENA           0x40      /* use color palette RAM */
145 #define BTCR_BLINK_M                    0x30      /* blink mask */
146 #define BTCR_BLINK_1648                 0x00      /*  16 on, 48 off */
147 #define BTCR_BLINK_1616                 0x10      /*  16 on, 16 off */
148 #define BTCR_BLINK_3232                 0x20      /*  32 on, 32 off */
149 #define BTCR_BLINK_6464                 0x30      /*  64 on, 64 off */
150 #define BTCR_BLINKENA_OV1     0x08      /* OV1 blink enable */
151 #define BTCR_BLINKENA_OV0     0x04      /* OV0 blink enable */
152 #define BTCR_DISPENA_OV1      0x02      /* OV1 display enable */
153 #define BTCR_DISPENA_OV0      0x01      /* OV0 display enable */
154 
155 #define BTCTR_R_ENA           0x01      /* red channel enable */
156 #define BTCTR_G_ENA           0x02      /* green channel enable */
157 #define BTCTR_B_ENA           0x04      /* blue channel enable */
158 #define BTCTR_NIB_M           0x08      /* nibble mask: */
159 #define BTCTR_NIB_LOW                   0x08      /*  low */
160 #define BTCTR_NIB_HIGH                  0x00      /*  high */
161 
162 /* 4 plane option RAMDAC */
163 struct    ramdac4 {
164           uint16_t  colormap[16];
165           uint8_t             unknown[0x20];
166           uint16_t  cursormap[4];
167           uint8_t             unknown2[0x18];
168           uint16_t  control;
169 #define   RAMDAC4_INIT        0x0047
170 #define   RAMDAC4_ENABLE      0x0002
171 };
172 
173 /* 8 plane option RAMDAC - Bt458 or compatible */
174 struct    ramdac8 {
175           uint16_t  address;
176           uint16_t  cmapdata;
177           uint16_t  control;
178           uint16_t  omapdata;
179 };
180 
181 struct    gpx_screen {
182           struct rasops_info ss_ri;
183           int                 ss_console;
184           u_int               ss_depth;
185           u_int               ss_gpr;             /* font glyphs per row */
186           struct adder        *ss_adder;
187           void                *ss_vdac;
188           uint8_t             ss_cmap[256 * 3];
189 #if 0
190           struct dc503reg     *ss_cursor;
191           uint16_t  ss_curcmd;
192 #endif
193 };
194 
195 struct    gpx_softc {
196           device_t sc_dev;
197           struct gpx_screen *sc_scr;
198           int       sc_nscreens;
199 };
200 
201 static int gpx_match(device_t, cfdata_t, void *);
202 static void gpx_attach(device_t, device_t, void *);
203 
204 static int gpx_ioctl(void *, void *, u_long, void *, int, struct lwp *);
205 static paddr_t gpx_mmap(void *, void *, off_t, int);
206 static int gpx_alloc_screen(void *, const struct wsscreen_descr *,
207     void **, int *, int *, long *);
208 static void gpx_free_screen(void *, void *);
209 static int gpx_show_screen(void *, void *, int,
210     void (*) (void *, int, int), void *);
211 
212 static void gpx_putchar(void *, int, int, u_int, long);
213 static void gpx_copycols(void *, int, int, int, int);
214 static void gpx_erasecols(void *, int, int, int, long);
215 static void gpx_copyrows(void *, int, int, int);
216 static void gpx_eraserows(void *, int, int, long);
217 static void gpx_do_cursor(struct rasops_info *);
218 
219 static int gpx_wait(struct gpx_screen *, int);
220 static int gpx_viper_write(struct gpx_screen *, u_int, uint16_t);
221 static void gpx_reset_viper(struct gpx_screen *);
222 static void gpx_clear_screen(struct gpx_screen *);
223 static int gpx_setup_screen(struct gpx_screen *);
224 static void gpx_upload_font(struct gpx_screen *);
225 static void gpx_copyrect(struct gpx_screen *, int, int, int, int, int, int);
226 static void gpx_fillrect(struct gpx_screen *, int, int, int, int, long, u_int);
227 static int gpx_getcmap(struct gpx_screen *, struct wsdisplay_cmap *);
228 static int gpx_putcmap(struct gpx_screen *, struct wsdisplay_cmap *);
229 static void gpx_loadcmap(struct gpx_screen *, int, int);
230 static void gpx_resetcmap(struct gpx_screen *);
231 
232 /* for console */
233 static struct gpx_screen gpx_consscr;
234 
235 CFATTACH_DECL_NEW(gpx, sizeof(struct gpx_softc),
236     gpx_match, gpx_attach, NULL, NULL);
237 
238 static struct wsscreen_descr gpx_stdscreen = {
239           "std",
240 };
241 
242 static const struct wsscreen_descr *_gpx_scrlist[] = {
243           &gpx_stdscreen,
244 };
245 
246 static const struct wsscreen_list gpx_screenlist = {
247           sizeof(_gpx_scrlist) / sizeof(struct wsscreen_descr *),
248           _gpx_scrlist,
249 };
250 
251 static const struct wsdisplay_accessops gpx_accessops = {
252           .ioctl = gpx_ioctl,
253           .mmap = gpx_mmap,
254           .alloc_screen = gpx_alloc_screen,
255           .free_screen = gpx_free_screen,
256           .show_screen = gpx_show_screen,
257           .load_font = NULL
258 };
259 
260 /*
261  * Autoconf glue
262  */
263 
264 static int
gpx_match(device_t parent,cfdata_t match,void * aux)265 gpx_match(device_t parent, cfdata_t match, void *aux)
266 {
267           struct vsbus_attach_args *va = aux;
268           volatile struct adder *adder;
269           vaddr_t tmp;
270           u_int depth;
271           u_short status;
272 
273           switch (vax_boardtype) {
274           default:
275                     return 0;
276 
277           case VAX_BTYP_410:
278           case VAX_BTYP_420:
279           case VAX_BTYP_43:
280                     if (va->va_paddr != GPXADDR)
281                               return 0;
282 
283                     /* not present on microvaxes */
284                     if ((vax_confdata & KA420_CFG_MULTU) != 0)
285                               return 0;
286 
287                     if ((vax_confdata & KA420_CFG_VIDOPT) == 0)
288                               return 0;
289                     break;
290           }
291 
292           /* Check for hardware */
293           adder = (volatile struct adder *)
294               vax_map_physmem(va->va_paddr + GPX_ADDER_OFFSET, 1);
295           if (adder == NULL)
296                     return 0;
297           adder->status = 0;
298           status = adder->status;
299           vax_unmap_physmem((vaddr_t)adder, 1);
300           if (status == offsetof(struct adder, status))
301                     return 0;
302 
303           /* Check for a recognized color depth */
304           tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1);
305           if (tmp == 0L)
306                     return 0;
307           depth = (*(volatile uint16_t *)tmp) & 0x00f0;
308           vax_unmap_physmem(tmp, 1);
309           if (depth != 0x00f0 && depth != 0x0080)
310                     return 0;
311 
312           /* when already running as console, always fake things */
313           if ((vax_confdata & KA420_CFG_L3CON) == 0
314 #if NWSDISPLAY > 0
315               && cn_tab->cn_putc == wsdisplay_cnputc
316 #endif
317           ) {
318                     struct vsbus_softc *sc = device_private(parent);
319                     sc->sc_mask = 0x08;
320                     scb_fake(0x44, 0x15);
321           } else {
322                     adder = (struct adder *)vax_map_physmem(va->va_paddr +
323                         GPX_ADDER_OFFSET, 1);
324                     if (adder == NULL)
325                               return 0;
326                     adder->interrupt_enable = FRAME_SYNC;
327                     DELAY(100000);      /* enough to get a retrace interrupt */
328                     adder->interrupt_enable = 0;
329                     vax_unmap_physmem((vaddr_t)adder, 1);
330           }
331           return 20;
332 }
333 
334 static void
gpx_attach(device_t parent,device_t self,void * aux)335 gpx_attach(device_t parent, device_t self, void *aux)
336 {
337           struct gpx_softc *sc = device_private(self);
338           struct vsbus_attach_args *va = aux;
339           struct gpx_screen *scr;
340           struct wsemuldisplaydev_attach_args aa;
341           int console;
342           vaddr_t tmp;
343 
344           sc->sc_dev = self;
345           console =
346 #if NWSDISPLAY > 0
347               (vax_confdata & KA420_CFG_L3CON) == 0 &&
348               cn_tab->cn_putc == wsdisplay_cnputc;
349 #else
350               (vax_confdata & KA420_CFG_L3CON) == 0;
351 #endif
352           if (console) {
353                     scr = &gpx_consscr;
354                     sc->sc_nscreens = 1;
355           } else {
356                     scr = kmem_zalloc(sizeof(*scr), KM_SLEEP);
357 
358                     tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1);
359                     if (tmp == 0L) {
360                               printf(": can not probe depth\n");
361                               goto bad1;
362                     }
363                     scr->ss_depth = (*(uint16_t *)tmp & 0x00f0) == 0x00f0 ? 4 : 8;
364                     vax_unmap_physmem(tmp, 1);
365 
366                     scr->ss_adder = (struct adder *)vax_map_physmem(va->va_paddr +
367                         GPX_ADDER_OFFSET, 1);
368                     if (scr->ss_adder == NULL) {
369                               aprint_error(": can not map frame buffer registers\n");
370                               goto bad1;
371                     }
372 
373                     scr->ss_vdac = (void *)vax_map_physmem(va->va_paddr +
374                         GPX_VDAC_OFFSET, 1);
375                     if (scr->ss_vdac == NULL) {
376                               aprint_error(": can not map RAMDAC\n");
377                               goto bad2;
378                     }
379 
380 #if 0
381                     scr->ss_cursor =
382                         (struct dc503reg *)vax_map_physmem(va->va_paddr +
383                         GPX_CURSOR_OFFSET, 1);
384                     if (scr->ss_cursor == NULL) {
385                               aprint_error(": can not map cursor chip\n");
386                               goto bad3;
387                     }
388 #endif
389 
390                     if (gpx_setup_screen(scr) != 0) {
391                               aprint_error(": initialization failed\n");
392                               goto bad4;
393                     }
394           }
395           sc->sc_scr = scr;
396 
397           aprint_normal("\n");
398           aprint_normal_dev(self, "%dx%d %d plane color framebuffer\n",
399               GPX_WIDTH, GPX_VISHEIGHT, scr->ss_depth);
400 
401           aa.console = console;
402           aa.scrdata = &gpx_screenlist;
403           aa.accessops = &gpx_accessops;
404           aa.accesscookie = sc;
405 
406           config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE);
407 
408           return;
409 
410  bad4:
411 #if 0
412           vax_unmap_physmem((vaddr_t)scr->ss_cursor, 1);
413  bad3:
414 #endif
415           vax_unmap_physmem((vaddr_t)scr->ss_vdac, 1);
416  bad2:
417           vax_unmap_physmem((vaddr_t)scr->ss_adder, 1);
418  bad1:
419           kmem_free(scr, sizeof(*scr));
420 }
421 
422 /*
423  * wsdisplay accessops
424  */
425 
426 static int
gpx_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)427 gpx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
428 {
429           struct gpx_softc *sc = v;
430           struct gpx_screen *ss = sc->sc_scr;
431           struct wsdisplay_fbinfo *wdf;
432           struct wsdisplay_cmap *cm;
433           int error;
434 
435           switch (cmd) {
436           case WSDISPLAYIO_GTYPE:
437                     *(u_int *)data = WSDISPLAY_TYPE_GPX;
438                     break;
439 
440           case WSDISPLAYIO_GINFO:
441                     wdf = (struct wsdisplay_fbinfo *)data;
442                     wdf->height = ss->ss_ri.ri_height;
443                     wdf->width = ss->ss_ri.ri_width;
444                     wdf->depth = ss->ss_depth;
445                     wdf->cmsize = 1 << ss->ss_depth;
446                     break;
447 
448           case WSDISPLAYIO_GETCMAP:
449                     cm = (struct wsdisplay_cmap *)data;
450                     error = gpx_getcmap(ss, cm);
451                     if (error != 0)
452                               return error;
453                     break;
454           case WSDISPLAYIO_PUTCMAP:
455                     cm = (struct wsdisplay_cmap *)data;
456                     error = gpx_putcmap(ss, cm);
457                     if (error != 0)
458                               return error;
459                     gpx_loadcmap(ss, cm->index, cm->count);
460                     break;
461 
462           case WSDISPLAYIO_GVIDEO:
463           case WSDISPLAYIO_SVIDEO:
464                     break;
465 
466           case WSDISPLAYIO_LINEBYTES:   /* no linear mapping */
467                     return -1;
468 
469           default:
470                     return EPASSTHROUGH;
471           }
472           return 0;
473 }
474 
475 static paddr_t
gpx_mmap(void * v,void * vs,off_t offset,int prot)476 gpx_mmap(void *v, void *vs, off_t offset, int prot)
477 {
478 
479           return -1;
480 }
481 
482 static int
gpx_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * defattrp)483 gpx_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
484     int *curxp, int *curyp, long *defattrp)
485 {
486           struct gpx_softc *sc = v;
487           struct gpx_screen *ss = sc->sc_scr;
488           struct rasops_info *ri = &ss->ss_ri;
489 
490           if (sc->sc_nscreens > 0)
491                     return ENOMEM;
492 
493           *cookiep = ri;
494           *curxp = *curyp = 0;
495           ri->ri_ops.allocattr(ri, 0, 0, 0, defattrp);
496           sc->sc_nscreens++;
497 
498           return 0;
499 }
500 
501 static void
gpx_free_screen(void * v,void * cookie)502 gpx_free_screen(void *v, void *cookie)
503 {
504           struct gpx_softc *sc = v;
505 
506           sc->sc_nscreens--;
507 }
508 
509 static int
gpx_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)510 gpx_show_screen(void *v, void *cookie, int waitok,
511     void (*cb)(void *, int, int), void *cbarg)
512 {
513 
514           return 0;
515 }
516 
517 /*
518  * wsdisplay emulops
519  */
520 
521 static void
gpx_putchar(void * v,int row,int col,u_int uc,long attr)522 gpx_putchar(void *v, int row, int col, u_int uc, long attr)
523 {
524           struct rasops_info *ri = v;
525           struct gpx_screen *ss = ri->ri_hw;
526           struct wsdisplay_font *font = ri->ri_font;
527           int dx, dy, sx, sy, fg, bg, ul;
528 
529           rasops_unpack_attr(attr, &fg, &bg, &ul);
530 
531           /* find where to output the glyph... */
532           dx = col * font->fontwidth + ri->ri_xorigin;
533           dy = row * font->fontheight + ri->ri_yorigin;
534           /* ... and where to pick it from */
535           uc -= font->firstchar;
536           sx = (uc % ss->ss_gpr) * font->stride * NBBY;
537           sy = GPX_HEIGHT - (1 + uc / ss->ss_gpr) * font->fontheight;
538 
539           /* setup VIPER operand control registers */
540           while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff))
541                     continue;
542           gpx_viper_write(ss, SRC1_OCR_B,
543               EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
544           gpx_viper_write(ss, DST_OCR_B,
545               EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
546           gpx_viper_write(ss, MASK_1, 0xffff);
547           gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg);
548           gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg);
549           ss->ss_adder->x_clip_min = 0;
550           ss->ss_adder->x_clip_max = GPX_WIDTH;
551           ss->ss_adder->y_clip_min = 0;
552           ss->ss_adder->y_clip_max = GPX_VISHEIGHT;
553           /* load DESTINATION origin and vectors */
554           ss->ss_adder->fast_dest_dy = 0;
555           ss->ss_adder->slow_dest_dx = 0;
556           ss->ss_adder->error_1 = 0;
557           ss->ss_adder->error_2 = 0;
558           ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
559           gpx_wait(ss, RASTEROP_COMPLETE);
560           ss->ss_adder->destination_x = dx;
561           ss->ss_adder->fast_dest_dx = font->fontwidth;
562           ss->ss_adder->destination_y = dy;
563           ss->ss_adder->slow_dest_dy = font->fontheight;
564           /* load SOURCE origin and vectors */
565           ss->ss_adder->source_1_x = sx;
566           ss->ss_adder->source_1_y = sy;
567           ss->ss_adder->source_1_dx = font->fontwidth;
568           ss->ss_adder->source_1_dy = font->fontheight;
569           ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1;
570 
571           if (ul != 0) {
572                     gpx_fillrect(ss, dx, dy + font->fontheight - 2, font->fontwidth,
573                         1, attr, LF_R3);          /* fg fill */
574           }
575 }
576 
577 static void
gpx_copycols(void * v,int row,int src,int dst,int cnt)578 gpx_copycols(void *v, int row, int src, int dst, int cnt)
579 {
580           struct rasops_info *ri = v;
581           struct gpx_screen *ss = ri->ri_hw;
582           struct wsdisplay_font *font = ri->ri_font;
583           int sx, y, dx, w, h;
584 
585           sx = ri->ri_xorigin + src * font->fontwidth;
586           dx = ri->ri_xorigin + dst * font->fontwidth;
587           w = cnt * font->fontwidth;
588           y = ri->ri_yorigin + row * font->fontheight;
589           h = font->fontheight;
590 
591           gpx_copyrect(ss, sx, y, dx, y, w, h);
592 }
593 
594 static void
gpx_erasecols(void * v,int row,int col,int cnt,long attr)595 gpx_erasecols(void *v, int row, int col, int cnt, long attr)
596 {
597           struct rasops_info *ri = v;
598           struct gpx_screen *ss = ri->ri_hw;
599           struct wsdisplay_font *font = ri->ri_font;
600           int x, y, dx, dy;
601 
602           x = ri->ri_xorigin + col * font->fontwidth;
603           dx = cnt * font->fontwidth;
604           y = ri->ri_yorigin + row * font->fontheight;
605           dy = font->fontheight;
606 
607           gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */
608 }
609 
610 static void
gpx_copyrows(void * v,int src,int dst,int cnt)611 gpx_copyrows(void *v, int src, int dst, int cnt)
612 {
613           struct rasops_info *ri = v;
614           struct gpx_screen *ss = ri->ri_hw;
615           struct wsdisplay_font *font = ri->ri_font;
616           int x, sy, dy, w, h;
617 
618           x = ri->ri_xorigin;
619           w = ri->ri_emustride;
620           sy = ri->ri_yorigin + src * font->fontheight;
621           dy = ri->ri_yorigin + dst * font->fontheight;
622           h = cnt * font->fontheight;
623 
624           gpx_copyrect(ss, x, sy, x, dy, w, h);
625 }
626 
627 static void
gpx_eraserows(void * v,int row,int cnt,long attr)628 gpx_eraserows(void *v, int row, int cnt, long attr)
629 {
630           struct rasops_info *ri = v;
631           struct gpx_screen *ss = ri->ri_hw;
632           struct wsdisplay_font *font = ri->ri_font;
633           int x, y, dx, dy;
634 
635           x = ri->ri_xorigin;
636           dx = ri->ri_emustride;
637           y = ri->ri_yorigin + row * font->fontheight;
638           dy = cnt * font->fontheight;
639 
640           gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */
641 }
642 
643 static void
gpx_do_cursor(struct rasops_info * ri)644 gpx_do_cursor(struct rasops_info *ri)
645 {
646           struct gpx_screen *ss = ri->ri_hw;
647           int x, y, w, h;
648 
649           x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
650           y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
651           w = ri->ri_font->fontwidth;
652           h = ri->ri_font->fontheight;
653 
654           gpx_fillrect(ss, x, y, w, h, WSCOL_WHITE << 24, LF_R4);     /* invert */
655 }
656 
657 /*
658  * low-level programming routines
659  */
660 
661 static int
gpx_wait(struct gpx_screen * ss,int bits)662 gpx_wait(struct gpx_screen *ss, int bits)
663 {
664           int i;
665 
666           ss->ss_adder->status = 0;
667           for (i = 100000; i != 0; i--) {
668                     if ((ss->ss_adder->status & bits) == bits)
669                               break;
670                     DELAY(1);
671           }
672 
673           return i == 0;
674 }
675 
676 static int
gpx_viper_write(struct gpx_screen * ss,u_int reg,uint16_t val)677 gpx_viper_write(struct gpx_screen *ss, u_int reg, uint16_t val)
678 {
679           if (gpx_wait(ss, ADDRESS_COMPLETE) == 0 &&
680               gpx_wait(ss, TX_READY) == 0) {
681                     ss->ss_adder->id_data = val;
682                     ss->ss_adder->command = ID_LOAD | reg;
683                     return 0;
684           }
685 #ifdef DEBUG
686           if (ss->ss_console == 0)      /* don't make things worse! */
687                     printf("gpx_viper_write failure, reg %x val %x\n", reg, val);
688 #endif
689           return 1;
690 }
691 
692 /* Initialize the damned beast. Straight from qdss. */
693 static void
gpx_reset_viper(struct gpx_screen * ss)694 gpx_reset_viper(struct gpx_screen *ss)
695 {
696           int i;
697 
698           ss->ss_adder->interrupt_enable = 0;
699           ss->ss_adder->command = CANCEL;
700           /* set monitor timing */
701           ss->ss_adder->x_scan_count_0 = 0x2800;
702           ss->ss_adder->x_scan_count_1 = 0x1020;
703           ss->ss_adder->x_scan_count_2 = 0x003a;
704           ss->ss_adder->x_scan_count_3 = 0x38f0;
705           ss->ss_adder->x_scan_count_4 = 0x6128;
706           ss->ss_adder->x_scan_count_5 = 0x093a;
707           ss->ss_adder->x_scan_count_6 = 0x313c;
708           ss->ss_adder->sync_phase_adj = 0x0100;
709           ss->ss_adder->x_scan_conf = 0x00c8;
710           /*
711            * got a bug in second pass ADDER! lets take care of it...
712            *
713            * normally, just use the code in the following bug fix code, but to
714            * make repeated demos look pretty, load the registers as if there was
715            * no bug and then test to see if we are getting sync
716            */
717           ss->ss_adder->y_scan_count_0 = 0x135f;
718           ss->ss_adder->y_scan_count_1 = 0x3363;
719           ss->ss_adder->y_scan_count_2 = 0x2366;
720           ss->ss_adder->y_scan_count_3 = 0x0388;
721           /*
722            * if no sync, do the bug fix code
723            */
724           if (gpx_wait(ss, FRAME_SYNC) != 0) {
725                     /*
726                      * First load all Y scan registers with very short frame and
727                      * wait for scroll service.  This guarantees at least one SYNC
728                      * to fix the pass 2 Adder initialization bug (synchronizes
729                      * XCINCH with DMSEEDH)
730                      */
731                     ss->ss_adder->y_scan_count_0 = 0x01;
732                     ss->ss_adder->y_scan_count_1 = 0x01;
733                     ss->ss_adder->y_scan_count_2 = 0x01;
734                     ss->ss_adder->y_scan_count_3 = 0x01;
735                     /* delay at least 1 full frame time */
736                     gpx_wait(ss, FRAME_SYNC);
737                     gpx_wait(ss, FRAME_SYNC);
738                     /*
739                      * now load the REAL sync values (in reverse order just to
740                      * be safe).
741                      */
742                     ss->ss_adder->y_scan_count_3 = 0x0388;
743                     ss->ss_adder->y_scan_count_2 = 0x2366;
744                     ss->ss_adder->y_scan_count_1 = 0x3363;
745                     ss->ss_adder->y_scan_count_0 = 0x135f;
746           }
747           /* zero the index registers */
748           ss->ss_adder->x_index_pending = 0;
749           ss->ss_adder->y_index_pending = 0;
750           ss->ss_adder->x_index_new = 0;
751           ss->ss_adder->y_index_new = 0;
752           ss->ss_adder->x_index_old = 0;
753           ss->ss_adder->y_index_old = 0;
754           ss->ss_adder->pause = 0;
755           /* set rasterop mode to normal pen down */
756           ss->ss_adder->rasterop_mode =
757               DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
758           /* set the rasterop registers to default values */
759           ss->ss_adder->source_1_dx = 1;
760           ss->ss_adder->source_1_dy = 1;
761           ss->ss_adder->source_1_x = 0;
762           ss->ss_adder->source_1_y = 0;
763           ss->ss_adder->destination_x = 0;
764           ss->ss_adder->destination_y = 0;
765           ss->ss_adder->fast_dest_dx = 1;
766           ss->ss_adder->fast_dest_dy = 0;
767           ss->ss_adder->slow_dest_dx = 0;
768           ss->ss_adder->slow_dest_dy = 1;
769           ss->ss_adder->error_1 = 0;
770           ss->ss_adder->error_2 = 0;
771           /* scale factor = UNITY */
772           ss->ss_adder->fast_scale = UNITY;
773           ss->ss_adder->slow_scale = UNITY;
774           /* set the source 2 parameters */
775           ss->ss_adder->source_2_x = 0;
776           ss->ss_adder->source_2_y = 0;
777           ss->ss_adder->source_2_size = 0x0022;
778           /* initialize plane addresses for eight vipers */
779           for (i = 0; i < 8; i++) {
780                     gpx_viper_write(ss, CS_UPDATE_MASK, 1 << i);
781                     gpx_viper_write(ss, PLANE_ADDRESS, i);
782           }
783           /* initialize the external registers. */
784           gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff);
785           gpx_viper_write(ss, CS_SCROLL_MASK, 0x00ff);
786           /* initialize resolution mode */
787           gpx_viper_write(ss, MEMORY_BUS_WIDTH, 0x000c);    /* bus width = 16 */
788           gpx_viper_write(ss, RESOLUTION_MODE, 0x0000);     /* one bit/pixel */
789           /* initialize viper registers */
790           gpx_viper_write(ss, SCROLL_CONSTANT,
791               SCROLL_ENABLE | VIPER_LEFT | VIPER_UP);
792           gpx_viper_write(ss, SCROLL_FILL, 0x0000);
793           /* set clipping and scrolling limits to full screen */
794           gpx_wait(ss, ADDRESS_COMPLETE);
795           ss->ss_adder->x_clip_min = 0;
796           ss->ss_adder->x_clip_max = GPX_WIDTH;
797           ss->ss_adder->y_clip_min = 0;
798           ss->ss_adder->y_clip_max = GPX_HEIGHT;
799           ss->ss_adder->scroll_x_min = 0;
800           ss->ss_adder->scroll_x_max = GPX_WIDTH;
801           ss->ss_adder->scroll_y_min = 0;
802           ss->ss_adder->scroll_y_max = GPX_HEIGHT;
803           gpx_wait(ss, FRAME_SYNC);     /* wait at LEAST 1 full frame */
804           gpx_wait(ss, FRAME_SYNC);
805           ss->ss_adder->x_index_pending = 0;
806           ss->ss_adder->y_index_pending = 0;
807           ss->ss_adder->x_index_new = 0;
808           ss->ss_adder->y_index_new = 0;
809           ss->ss_adder->x_index_old = 0;
810           ss->ss_adder->y_index_old = 0;
811           gpx_wait(ss, ADDRESS_COMPLETE);
812           gpx_viper_write(ss, LEFT_SCROLL_MASK, 0x0000);
813           gpx_viper_write(ss, RIGHT_SCROLL_MASK, 0x0000);
814           /* set source and the mask register to all ones */
815           gpx_viper_write(ss, SOURCE, 0xffff);
816           gpx_viper_write(ss, MASK_1, 0xffff);
817           gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
818           gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
819           /* initialize Operand Control Register banks for fill command */
820           gpx_viper_write(ss, SRC1_OCR_A,
821               EXT_NONE | INT_M1_M2  | NO_ID | WAIT);
822           gpx_viper_write(ss, SRC2_OCR_A,
823               EXT_NONE | INT_SOURCE | NO_ID | NO_WAIT);
824           gpx_viper_write(ss, DST_OCR_A,
825               EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
826           gpx_viper_write(ss, SRC1_OCR_B,
827               EXT_NONE | INT_SOURCE | NO_ID | WAIT);
828           gpx_viper_write(ss, SRC2_OCR_B,
829               EXT_NONE | INT_M1_M2  | NO_ID | NO_WAIT);
830           gpx_viper_write(ss, DST_OCR_B,
831               EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
832 
833           /*
834            * Init Logic Unit Function registers.
835            */
836           /* putchar */
837           gpx_viper_write(ss, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
838           /* erase{cols,rows} */
839           gpx_viper_write(ss, LU_FUNCTION_R2, FULL_SRC_RESOLUTION | LF_ZEROS);
840           /* underline */
841           gpx_viper_write(ss, LU_FUNCTION_R3, FULL_SRC_RESOLUTION | LF_ONES);
842           /* cursor */
843           gpx_viper_write(ss, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_NOT_D);
844 }
845 
846 /* Clear the whole screen. Straight from qdss. */
847 static void
gpx_clear_screen(struct gpx_screen * ss)848 gpx_clear_screen(struct gpx_screen *ss)
849 {
850 
851           ss->ss_adder->x_limit = GPX_WIDTH;
852           ss->ss_adder->y_limit = GPX_HEIGHT;
853           ss->ss_adder->y_offset_pending = 0;
854           gpx_wait(ss, FRAME_SYNC);     /* wait at LEAST 1 full frame */
855           gpx_wait(ss, FRAME_SYNC);
856           ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
857           gpx_wait(ss, FRAME_SYNC);
858           gpx_wait(ss, FRAME_SYNC);
859           ss->ss_adder->y_offset_pending = GPX_VISHEIGHT;
860           gpx_wait(ss, FRAME_SYNC);
861           gpx_wait(ss, FRAME_SYNC);
862           ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
863           gpx_wait(ss, FRAME_SYNC);
864           gpx_wait(ss, FRAME_SYNC);
865           ss->ss_adder->y_offset_pending = 2 * GPX_VISHEIGHT;
866           gpx_wait(ss, FRAME_SYNC);
867           gpx_wait(ss, FRAME_SYNC);
868           ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
869           gpx_wait(ss, FRAME_SYNC);
870           gpx_wait(ss, FRAME_SYNC);
871           ss->ss_adder->y_offset_pending = 0;      /* back to normal */
872           gpx_wait(ss, FRAME_SYNC);
873           gpx_wait(ss, FRAME_SYNC);
874           ss->ss_adder->x_limit = GPX_WIDTH;
875           ss->ss_adder->y_limit = GPX_VISHEIGHT;
876 }
877 
878 static int
gpx_setup_screen(struct gpx_screen * ss)879 gpx_setup_screen(struct gpx_screen *ss)
880 {
881           struct rasops_info *ri = &ss->ss_ri;
882           int cookie;
883 
884           memset(ri, 0, sizeof(*ri));
885           ri->ri_depth = 8;   /* masquerade as a 8 bit device for rasops */
886           ri->ri_width = GPX_WIDTH;
887           ri->ri_height = GPX_VISHEIGHT;
888           ri->ri_stride = GPX_WIDTH;
889           ri->ri_flg = RI_CENTER;                 /* no RI_CLEAR as ri_bits is NULL! */
890           ri->ri_hw = ss;
891           if (ss == &gpx_consscr)
892                     ri->ri_flg |= RI_NO_AUTO;
893 
894           /*
895            * We can not let rasops select our font, because we need to use
896            * a font with right-to-left bit order on this frame buffer.
897            */
898           wsfont_init();
899           cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
900               WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
901           if (cookie < 0)
902                     cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L,
903                         WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
904           if (cookie < 0)
905                     cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
906                         WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
907           if (cookie < 0)
908                     return -1;
909           if (wsfont_lock(cookie, &ri->ri_font) != 0)
910                     return -1;
911           ri->ri_wsfcookie = cookie;
912 
913           /*
914            * Ask for an unholy big display, rasops will trim this to more
915            * reasonable values.
916            */
917           if (rasops_init(ri, 160, 160) != 0)
918                     return -1;
919 
920           /*
921            * Override the rasops emulops.
922            */
923           ri->ri_ops.copyrows = gpx_copyrows;
924           ri->ri_ops.copycols = gpx_copycols;
925           ri->ri_ops.eraserows = gpx_eraserows;
926           ri->ri_ops.erasecols = gpx_erasecols;
927           ri->ri_ops.putchar = gpx_putchar;
928           ri->ri_do_cursor = gpx_do_cursor;
929 
930           gpx_stdscreen.ncols = ri->ri_cols;
931           gpx_stdscreen.nrows = ri->ri_rows;
932           gpx_stdscreen.textops = &ri->ri_ops;
933           gpx_stdscreen.fontwidth = ri->ri_font->fontwidth;
934           gpx_stdscreen.fontheight = ri->ri_font->fontheight;
935           gpx_stdscreen.capabilities = ri->ri_caps;
936 
937           /*
938            * Initialize RAMDAC.
939            */
940           if (ss->ss_depth == 8) {
941                     struct ramdac8 *rd = ss->ss_vdac;
942                     rd->address = BT_CR;
943                     rd->control = BTCR_RAMENA | BTCR_BLINK_1648 | BTCR_MPLX_4;
944           } else {
945                     struct ramdac4 *rd = ss->ss_vdac;
946                     rd->control = RAMDAC4_INIT;
947           }
948 
949           /*
950            * Put the ADDER and VIPER in a good state.
951            */
952           gpx_reset_viper(ss);
953 
954           /*
955            * Initialize colormap.
956            */
957           gpx_resetcmap(ss);
958 
959           /*
960            * Clear display (including non-visible area), in 864 lines chunks.
961            */
962           gpx_clear_screen(ss);
963 
964           /*
965            * Copy our font to the offscreen area.
966            */
967           gpx_upload_font(ss);
968 
969 #if 0
970           ss->ss_cursor->cmdr = ss->ss_curcmd = PCCCMD_HSHI;
971 #endif
972 
973           return 0;
974 }
975 
976 /*
977  * Copy the selected wsfont to non-visible frame buffer area.
978  * This is necessary since the only way to send data to the frame buffer
979  * is through the ID interface, which is slow and needs 16 bit wide data.
980  * Adapted from qdss.
981  */
982 static void
gpx_upload_font(struct gpx_screen * ss)983 gpx_upload_font(struct gpx_screen *ss)
984 {
985           struct rasops_info *ri = &ss->ss_ri;
986           struct wsdisplay_font *font = ri->ri_font;
987           uint8_t *fontbits, *fb;
988           u_int remaining, nchars, row;
989           u_int i, j;
990           uint16_t data;
991 
992           /* setup VIPER operand control registers */
993 
994           gpx_viper_write(ss, MASK_1, 0xffff);
995           gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
996           gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
997 
998           gpx_viper_write(ss, SRC1_OCR_B,
999               EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
1000           gpx_viper_write(ss, SRC2_OCR_B,
1001               EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
1002           gpx_viper_write(ss, DST_OCR_B,
1003               EXT_SOURCE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
1004 
1005           ss->ss_adder->rasterop_mode =
1006               DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
1007           gpx_wait(ss, RASTEROP_COMPLETE);
1008 
1009           /*
1010            * Load font data. The font is uploaded in 8 or 16 bit wide cells, on
1011            * as many ``lines'' as necessary at the end of the display.
1012            */
1013           ss->ss_gpr = MIN(GPX_WIDTH / (NBBY * font->stride), font->numchars);
1014           if ((ss->ss_gpr & 1) != 0)
1015                     ss->ss_gpr--;
1016           fontbits = font->data;
1017           for (row = 1, remaining = font->numchars; remaining != 0;
1018               row++, remaining -= nchars) {
1019                     nchars = MIN(ss->ss_gpr, remaining);
1020 
1021                     ss->ss_adder->destination_x = 0;
1022                     ss->ss_adder->destination_y =
1023                         GPX_HEIGHT - row * font->fontheight;
1024                     ss->ss_adder->fast_dest_dx = nchars * 16;
1025                     ss->ss_adder->slow_dest_dy = font->fontheight;
1026 
1027                     /* setup for processor to bitmap xfer */
1028                     gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff);
1029                     ss->ss_adder->cmd = PBT | OCRB | DTE | LF_R1 | 2; /*XXX why 2?*/
1030 
1031                     /* iteratively do the processor to bitmap xfer */
1032                     for (i = font->fontheight; i != 0; i--) {
1033                               fb = fontbits;
1034                               fontbits += font->stride;
1035                               /* PTOB a scan line */
1036                               for (j = nchars; j != 0; j--) {
1037                                         /* PTOB one scan of a char cell */
1038                                         if (font->stride == 1) {
1039                                                   data = *fb;
1040                                                   fb += font->fontheight;
1041                                                   /*
1042                                                    * Do not access past font memory if
1043                                                    * it has an odd number of characters
1044                                                    * and this is the last pair.
1045                                                    */
1046                                                   if (j != 1 || (nchars & 1) == 0 ||
1047                                                       remaining != nchars) {
1048                                                             data |= ((uint16_t)*fb) << 8;
1049                                                             fb += font->fontheight;
1050                                                   }
1051                                         } else {
1052                                                   data =
1053                                                       fb[0] | (((uint16_t)fb[1]) << 8);
1054                                                   fb += font->fontheight * font->stride;
1055                                         }
1056 
1057                                         gpx_wait(ss, TX_READY);
1058                                         ss->ss_adder->id_data = data;
1059                               }
1060                     }
1061                     fontbits += (nchars - 1) * font->stride * font->fontheight;
1062           }
1063 }
1064 
1065 static void
gpx_copyrect(struct gpx_screen * ss,int sx,int sy,int dx,int dy,int w,int h)1066 gpx_copyrect(struct gpx_screen *ss,
1067     int sx, int sy, int dx, int dy, int w, int h)
1068 {
1069 
1070           while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff))
1071                     continue;
1072           gpx_viper_write(ss, MASK_1, 0xffff);
1073           gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
1074           gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
1075           gpx_viper_write(ss, SRC1_OCR_B,
1076               EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
1077           gpx_viper_write(ss, DST_OCR_B,
1078               EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
1079           ss->ss_adder->fast_dest_dy = 0;
1080           ss->ss_adder->slow_dest_dx = 0;
1081           ss->ss_adder->error_1 = 0;
1082           ss->ss_adder->error_2 = 0;
1083           ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
1084           gpx_wait(ss, RASTEROP_COMPLETE);
1085           ss->ss_adder->destination_x = dx;
1086           ss->ss_adder->fast_dest_dx = w;
1087           ss->ss_adder->destination_y = dy;
1088           ss->ss_adder->slow_dest_dy = h;
1089           ss->ss_adder->source_1_x = sx;
1090           ss->ss_adder->source_1_dx = w;
1091           ss->ss_adder->source_1_y = sy;
1092           ss->ss_adder->source_1_dy = h;
1093           ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1;
1094 }
1095 
1096 /*
1097  * Fill a rectangle with the given attribute and function (i.e. rop).
1098  */
1099 static void
gpx_fillrect(struct gpx_screen * ss,int x,int y,int dx,int dy,long attr,u_int function)1100 gpx_fillrect(struct gpx_screen *ss, int x, int y, int dx, int dy, long attr,
1101     u_int function)
1102 {
1103           int fg, bg;
1104 
1105           rasops_unpack_attr(attr, &fg, &bg, NULL);
1106 
1107           while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff))
1108                     continue;
1109           gpx_viper_write(ss, MASK_1, 0xffff);
1110           gpx_viper_write(ss, SOURCE, 0xffff);
1111           gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg);
1112           gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg);
1113           gpx_viper_write(ss, SRC1_OCR_B,
1114               EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
1115           gpx_viper_write(ss, DST_OCR_B,
1116               EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
1117           ss->ss_adder->fast_dest_dx = 0;
1118           ss->ss_adder->fast_dest_dy = 0;
1119           ss->ss_adder->slow_dest_dx = 0;
1120           ss->ss_adder->error_1 = 0;
1121           ss->ss_adder->error_2 = 0;
1122           ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
1123           gpx_wait(ss, RASTEROP_COMPLETE);
1124           ss->ss_adder->destination_x = x;
1125           ss->ss_adder->fast_dest_dx = dx;
1126           ss->ss_adder->destination_y = y;
1127           ss->ss_adder->slow_dest_dy = dy;
1128           ss->ss_adder->source_1_x = x;
1129           ss->ss_adder->source_1_dx = dx;
1130           ss->ss_adder->source_1_y = y;
1131           ss->ss_adder->source_1_dy = dy;
1132           ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | function;
1133 }
1134 
1135 /*
1136  * Colormap handling routines
1137  */
1138 
1139 static int
gpx_getcmap(struct gpx_screen * ss,struct wsdisplay_cmap * cm)1140 gpx_getcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm)
1141 {
1142           u_int index = cm->index, count = cm->count, i;
1143           u_int colcount = 1 << ss->ss_depth;
1144           int error;
1145           uint8_t ramp[256], *c, *r;
1146 
1147           if (index >= colcount || count > colcount - index)
1148                     return EINVAL;
1149 
1150           if (count == 0)
1151                     return 0;
1152 
1153           /* extract reds */
1154           c = ss->ss_cmap + 0 + index * 3;
1155           for (i = count, r = ramp; i != 0; i--)
1156                     *r++ = *c << (8 - ss->ss_depth), c += 3;
1157           if ((error = copyout(ramp, cm->red, count)) != 0)
1158                     return error;
1159 
1160           /* extract greens */
1161           c = ss->ss_cmap + 1 + index * 3;
1162           for (i = count, r = ramp; i != 0; i--)
1163                     *r++ = *c << (8 - ss->ss_depth), c += 3;
1164           if ((error = copyout(ramp, cm->green, count)) != 0)
1165                     return error;
1166 
1167           /* extract blues */
1168           c = ss->ss_cmap + 2 + index * 3;
1169           for (i = count, r = ramp; i != 0; i--)
1170                     *r++ = *c << (8 - ss->ss_depth), c += 3;
1171           if ((error = copyout(ramp, cm->blue, count)) != 0)
1172                     return error;
1173 
1174           return 0;
1175 }
1176 
1177 static int
gpx_putcmap(struct gpx_screen * ss,struct wsdisplay_cmap * cm)1178 gpx_putcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm)
1179 {
1180           u_int index = cm->index, count = cm->count;
1181           u_int colcount = 1 << ss->ss_depth;
1182           int i, error;
1183           uint8_t r[256], g[256], b[256], *nr, *ng, *nb, *c;
1184 
1185           if (index >= colcount || count > colcount - index)
1186                     return EINVAL;
1187 
1188           if ((error = copyin(cm->red, r, count)) != 0)
1189                     return error;
1190           if ((error = copyin(cm->green, g, count)) != 0)
1191                     return error;
1192           if ((error = copyin(cm->blue, b, count)) != 0)
1193                     return error;
1194 
1195           nr = r, ng = g, nb = b;
1196           c = ss->ss_cmap + index * 3;
1197           for (i = count; i != 0; i--) {
1198                     *c++ = *nr++ >> (8 - ss->ss_depth);
1199                     *c++ = *ng++ >> (8 - ss->ss_depth);
1200                     *c++ = *nb++ >> (8 - ss->ss_depth);
1201           }
1202 
1203           return 0;
1204 }
1205 
1206 static void
gpx_loadcmap(struct gpx_screen * ss,int from,int count)1207 gpx_loadcmap(struct gpx_screen *ss, int from, int count)
1208 {
1209           uint8_t *cmap = ss->ss_cmap;
1210           int i, color12;
1211 
1212           gpx_wait(ss, FRAME_SYNC);
1213           if (ss->ss_depth == 8) {
1214                     struct ramdac8 *rd = ss->ss_vdac;
1215 
1216                     cmap += from * 3;
1217                     rd->address = from;
1218                     for (i = 0; i < count * 3; i++)
1219                               rd->cmapdata = *cmap++;
1220           } else {
1221                     struct ramdac4 *rd = ss->ss_vdac;
1222 
1223                     cmap = ss->ss_cmap + from;
1224                     for (i = from; i < from + count; i++) {
1225                               color12  = (*cmap++ >> 4) << 0;
1226                               color12 |= (*cmap++ >> 4) << 8;
1227                               color12 |= (*cmap++ >> 4) << 4;
1228                               rd->colormap[i] = color12;
1229                     }
1230           }
1231 }
1232 
1233 static void
gpx_resetcmap(struct gpx_screen * ss)1234 gpx_resetcmap(struct gpx_screen *ss)
1235 {
1236 
1237           if (ss->ss_depth == 8)
1238                     memcpy(ss->ss_cmap, rasops_cmap, sizeof(ss->ss_cmap));
1239           else {
1240                     memcpy(ss->ss_cmap, rasops_cmap, 8 * 3);
1241                     memcpy(ss->ss_cmap + 8 * 3, rasops_cmap + 0xf8 * 3, 8 * 3);
1242           }
1243           gpx_loadcmap(ss, 0, 1 << ss->ss_depth);
1244 
1245           /*
1246            * On the 4bit RAMDAC, make the hardware cursor black on black
1247            */
1248           if (ss->ss_depth != 8) {
1249                     struct ramdac4 *rd = ss->ss_vdac;
1250 
1251                     rd->cursormap[0] = rd->cursormap[1] =
1252                         rd->cursormap[2] = rd->cursormap[3] = 0x0000;
1253           }
1254 }
1255 
1256 /*
1257  * Console support code
1258  */
1259 
1260 cons_decl(gpx);
1261 
1262 /*
1263  * Called very early to setup the glass tty as console.
1264  * Because it's called before the VM system is initialized, virtual memory
1265  * for the framebuffer can be stolen directly without disturbing anything.
1266  */
1267 void
gpxcnprobe(struct consdev * cndev)1268 gpxcnprobe(struct consdev *cndev)
1269 {
1270           extern vaddr_t virtual_avail;
1271           extern const struct cdevsw wsdisplay_cdevsw;
1272           volatile struct adder *adder;
1273           vaddr_t tmp;
1274           int depth;
1275           u_short status;
1276 
1277           switch (vax_boardtype) {
1278           case VAX_BTYP_410:
1279           case VAX_BTYP_420:
1280           case VAX_BTYP_43:
1281                     if ((vax_confdata & (KA420_CFG_L3CON | KA420_CFG_MULTU)) != 0)
1282                               break; /* doesn't use graphics console */
1283 
1284                     if ((vax_confdata & KA420_CFG_VIDOPT) == 0)
1285                               break; /* no color option */
1286 
1287                     /* Check for hardware */
1288                     tmp = virtual_avail;
1289                     ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_ADDER_OFFSET), 1);
1290                     adder = (struct adder *)tmp;
1291                     adder->status = 0;
1292                     status = adder->status;
1293                     iounaccess(tmp, 1);
1294                     if (status == offsetof(struct adder, status))
1295                               return;
1296 
1297                     /* Check for a recognized color depth */
1298                     tmp = virtual_avail;
1299                     ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1);
1300                     depth = *(uint16_t *)
1301                         (tmp + (GPX_READBACK_OFFSET & VAX_PGOFSET)) & 0x00f0;
1302                     iounaccess(tmp, 1);
1303                     if (depth != 0x00f0 && depth != 0x0080)
1304                               return;
1305 
1306                     cndev->cn_pri = CN_INTERNAL;
1307                     cndev->cn_dev =
1308                         makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0);
1309                     break;
1310 
1311           default:
1312                     break;
1313           }
1314 }
1315 
1316 /*
1317  * Called very early to setup the glass tty as console.
1318  * Because it's called before the VM system is initialized, virtual memory
1319  * for the framebuffer can be stolen directly without disturbing anything.
1320  */
1321 void
gpxcninit(struct consdev * cndev)1322 gpxcninit(struct consdev *cndev)
1323 {
1324           struct gpx_screen *ss = &gpx_consscr;
1325           extern vaddr_t virtual_avail;
1326           vaddr_t ova;
1327           long defattr;
1328           struct rasops_info *ri;
1329 
1330           ova = virtual_avail;
1331 
1332           ioaccess(virtual_avail,
1333               vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1);
1334           ss->ss_depth = (0x00f0 & *(uint16_t *)(virtual_avail +
1335               (GPX_READBACK_OFFSET & VAX_PGOFSET))) == 0x00f0 ? 4 : 8;
1336 
1337           ioaccess(virtual_avail, GPXADDR + GPX_ADDER_OFFSET, 1);
1338           ss->ss_adder = (struct adder *)virtual_avail;
1339           virtual_avail += VAX_NBPG;
1340 
1341           ioaccess(virtual_avail, vax_trunc_page(GPXADDR + GPX_VDAC_OFFSET), 1);
1342           ss->ss_vdac = (void *)(virtual_avail + (GPX_VDAC_OFFSET & VAX_PGOFSET));
1343           virtual_avail += VAX_NBPG;
1344 
1345 #if 0
1346           ioaccess(virtual_avail, GPXADDR + GPX_CURSOR_OFFSET, 1);
1347           ss->ss_cursor = (struct dc503reg *)virtual_avail;
1348           virtual_avail += VAX_NBPG;
1349 #endif
1350 
1351           virtual_avail = round_page(virtual_avail);
1352 
1353           /* this had better not fail */
1354           if (gpx_setup_screen(ss) != 0) {
1355 #if 0
1356                     iounaccess((vaddr_t)ss->ss_cursor, 1);
1357 #endif
1358                     iounaccess((vaddr_t)ss->ss_vdac, 1);
1359                     iounaccess((vaddr_t)ss->ss_adder, 1);
1360                     virtual_avail = ova;
1361                     return;
1362           }
1363 
1364           ri = &ss->ss_ri;
1365           ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr);
1366           wsdisplay_cnattach(&gpx_stdscreen, ri, 0, 0, defattr);
1367           cn_tab->cn_pri = CN_INTERNAL;
1368 
1369 #if NDZKBD > 0
1370           dzkbd_cnattach(0); /* Connect keyboard and screen together */
1371 #endif
1372 }
1373