1 /*        $NetBSD: topcat.c,v 1.14 2025/02/26 04:49:46 andvar Exp $   */
2 /*        $OpenBSD: topcat.c,v 1.15 2006/08/11 18:33:13 miod Exp $    */
3 
4 /*
5  * Copyright (c) 2005, Miodrag Vallat.
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  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  */
30 /*-
31  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
32  * All rights reserved.
33  *
34  * This code is derived from software contributed to The NetBSD Foundation
35  * by Jason R. Thorpe.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  *
46  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
47  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
48  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
49  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
50  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
51  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
52  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
53  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
54  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
56  * POSSIBILITY OF SUCH DAMAGE.
57  */
58 
59 /*
60  * Copyright (c) 1988 University of Utah.
61  * Copyright (c) 1990, 1993
62  *        The Regents of the University of California.  All rights reserved.
63  *
64  * This code is derived from software contributed to Berkeley by
65  * the Systems Programming Group of the University of Utah Computer
66  * Science Department.
67  *
68  * Redistribution and use in source and binary forms, with or without
69  * modification, are permitted provided that the following conditions
70  * are met:
71  * 1. Redistributions of source code must retain the above copyright
72  *    notice, this list of conditions and the following disclaimer.
73  * 2. Redistributions in binary form must reproduce the above copyright
74  *    notice, this list of conditions and the following disclaimer in the
75  *    documentation and/or other materials provided with the distribution.
76  * 3. Neither the name of the University nor the names of its contributors
77  *    may be used to endorse or promote products derived from this software
78  *    without specific prior written permission.
79  *
80  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
81  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
82  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
83  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
84  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
85  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
86  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
87  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
88  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
89  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
90  * SUCH DAMAGE.
91  *
92  * from: Utah $Hdr: grf_tc.c 1.20 93/08/13$
93  *
94  *        @(#)grf_tc.c        8.4 (Berkeley) 1/12/94
95  */
96 
97 /*
98  * Graphics routines for TOPCAT, CATSEYE and KATHMANDU frame buffers
99  */
100 
101 #include <sys/param.h>
102 #include <sys/systm.h>
103 #include <sys/conf.h>
104 #include <sys/device.h>
105 #include <sys/proc.h>
106 #include <sys/ioctl.h>
107 #include <sys/bus.h>
108 #include <sys/cpu.h>
109 
110 #include <machine/autoconf.h>
111 
112 #include <hp300/dev/dioreg.h>
113 #include <hp300/dev/diovar.h>
114 #include <hp300/dev/diodevs.h>
115 #include <hp300/dev/intiovar.h>
116 
117 #include <dev/wscons/wsconsio.h>
118 #include <dev/wscons/wsdisplayvar.h>
119 #include <dev/rasops/rasops.h>
120 
121 #include <hp300/dev/diofbreg.h>
122 #include <hp300/dev/diofbvar.h>
123 #include <hp300/dev/topcatreg.h>
124 
125 struct    topcat_softc {
126           device_t  sc_dev;
127           struct diofb        *sc_fb;
128           struct diofb        sc_fb_store;
129           int                 sc_scode;
130 };
131 
132 static int          topcat_dio_match(device_t, cfdata_t, void *);
133 static void         topcat_dio_attach(device_t, device_t, void *);
134 static int          topcat_intio_match(device_t, cfdata_t, void *);
135 static void         topcat_intio_attach(device_t, device_t, void *);
136 
137 CFATTACH_DECL_NEW(topcat_dio, sizeof(struct topcat_softc),
138     topcat_dio_match, topcat_dio_attach, NULL, NULL);
139 
140 CFATTACH_DECL_NEW(topcat_intio, sizeof(struct topcat_softc),
141     topcat_intio_match, topcat_intio_attach, NULL, NULL);
142 
143 static void         topcat_end_attach(struct topcat_softc *, uint8_t);
144 static int          topcat_reset(struct diofb *, int, struct diofbreg *);
145 static void         topcat_restore(struct diofb *);
146 static int          topcat_setcmap(struct diofb *, struct wsdisplay_cmap *);
147 static void         topcat_setcolor(struct diofb *, u_int);
148 static int          topcat_windowmove(struct diofb *, uint16_t, uint16_t, uint16_t,
149                         uint16_t, uint16_t, uint16_t, int16_t, int16_t);
150 
151 static int          topcat_ioctl(void *, void *, u_long, void *, int, struct lwp *);
152 static void         topcat_putchar8(void *, int, int, u_int, long);
153 static void         topcat_putchar1_4(void *, int, int, u_int, long);
154 
155 static struct wsdisplay_accessops topcat_accessops = {
156           topcat_ioctl,
157           diofb_mmap,
158           diofb_alloc_screen,
159           diofb_free_screen,
160           diofb_show_screen,
161           NULL,     /* load_font */
162 };
163 
164 /*
165  * Attachment glue
166  */
167 
168 int
topcat_intio_match(device_t parent,cfdata_t cf,void * aux)169 topcat_intio_match(device_t parent, cfdata_t cf, void *aux)
170 {
171           struct intio_attach_args *ia = aux;
172           struct diofbreg *fbr;
173 
174           if (strcmp("fb", ia->ia_modname) != 0)
175                     return 0;
176 
177           fbr = (struct diofbreg *)ia->ia_addr;
178 
179           if (badaddr((void *)fbr))
180                     return 0;
181 
182           if (fbr->id == GRFHWID) {
183                     switch (fbr->fbid) {
184                     case GID_TOPCAT:
185                     case GID_LRCATSEYE:
186                     case GID_HRCCATSEYE:
187                     case GID_HRMCATSEYE:
188 #if 0
189                     case GID_XXXCATSEYE:
190 #endif
191                               return 1;
192                     }
193           }
194 
195           return 0;
196 }
197 
198 void
topcat_intio_attach(device_t parent,device_t self,void * aux)199 topcat_intio_attach(device_t parent, device_t self, void *aux)
200 {
201           struct topcat_softc *sc = device_private(self);
202           struct intio_attach_args *ia = aux;
203           struct diofbreg *fbr;
204 
205           sc->sc_dev = self;
206           fbr = (struct diofbreg *)ia->ia_addr;
207           sc->sc_scode = CONSCODE_INTERNAL;
208 
209           if (sc->sc_scode == conscode) {
210                     sc->sc_fb = &diofb_cn;
211           } else {
212                     sc->sc_fb = &sc->sc_fb_store;
213                     topcat_reset(sc->sc_fb, sc->sc_scode, fbr);
214           }
215 
216           topcat_end_attach(sc, fbr->fbid);
217 }
218 
219 int
topcat_dio_match(device_t parent,cfdata_t cf,void * aux)220 topcat_dio_match(device_t parent, cfdata_t cf, void *aux)
221 {
222           struct dio_attach_args *da = aux;
223 
224           if (da->da_id == DIO_DEVICE_ID_FRAMEBUFFER) {
225                     switch (da->da_secid) {
226                     case DIO_DEVICE_SECID_TOPCAT:
227                     case DIO_DEVICE_SECID_LRCATSEYE:
228                     case DIO_DEVICE_SECID_HRCCATSEYE:
229                     case DIO_DEVICE_SECID_HRMCATSEYE:
230 #if 0
231                     case DIO_DEVICE_SECID_XXXCATSEYE:
232 #endif
233                               return 1;
234                     }
235           }
236 
237           return 0;
238 }
239 
240 void
topcat_dio_attach(device_t parent,device_t self,void * aux)241 topcat_dio_attach(device_t parent, device_t self, void *aux)
242 {
243           struct topcat_softc *sc = device_private(self);
244           struct dio_attach_args *da = aux;
245           bus_space_handle_t bsh;
246           struct diofbreg *fbr;
247 
248           sc->sc_dev = self;
249           sc->sc_scode = da->da_scode;
250           if (sc->sc_scode == conscode) {
251                     fbr = (struct diofbreg *)conaddr;       /* already mapped */
252                     sc->sc_fb = &diofb_cn;
253           } else {
254                     sc->sc_fb = &sc->sc_fb_store;
255                     if (bus_space_map(da->da_bst, da->da_addr, da->da_size, 0,
256                         &bsh)) {
257                               aprint_error(": can't map framebuffer\n");
258                               return;
259                     }
260                     fbr = bus_space_vaddr(da->da_bst, bsh);
261                     if (topcat_reset(sc->sc_fb, sc->sc_scode, fbr) != 0) {
262                               aprint_error(": can't reset framebuffer\n");
263                               return;
264                     }
265           }
266 
267           topcat_end_attach(sc, fbr->fbid);
268 }
269 
270 void
topcat_end_attach(struct topcat_softc * sc,uint8_t id)271 topcat_end_attach(struct topcat_softc *sc, uint8_t id)
272 {
273           const char *fbname = "unknown";
274 
275           switch (id) {
276           case GID_TOPCAT:
277                     switch (sc->sc_fb->planes) {
278                     case 1:
279                               if (sc->sc_fb->dheight == 400)
280                                         fbname = "HP98542 topcat";
281                               else
282                                         fbname = "HP98544 topcat";
283                               break;
284                     case 4:
285                               if (sc->sc_fb->dheight == 400)
286                                         fbname = "HP98543 topcat";
287                               else
288                                         fbname = "HP98545 topcat";
289                               break;
290                     case 6:
291                               fbname = "HP98547 topcat";
292                               break;
293                     }
294                     break;
295           case GID_HRCCATSEYE:
296                     fbname = "HP98550 catseye";   /* also A1416 kathmandu */
297                     break;
298           case GID_LRCATSEYE:
299                     fbname = "HP98549 catseye";
300                     break;
301           case GID_HRMCATSEYE:
302                     fbname = "HP98548 catseye";
303                     break;
304           }
305 
306           diofb_end_attach(sc->sc_dev, &topcat_accessops, sc->sc_fb,
307               sc->sc_scode == conscode, fbname);
308 }
309 
310 /*
311  * Initialize hardware and display routines.
312  */
313 int
topcat_reset(struct diofb * fb,int scode,struct diofbreg * fbr)314 topcat_reset(struct diofb *fb, int scode, struct diofbreg *fbr)
315 {
316           volatile struct tcboxfb *tc = (struct tcboxfb *)fbr;
317           struct rasops_info *ri = &fb->ri;
318           int rc;
319           u_int i;
320           bool sparse = false;
321 
322           if ((rc = diofb_fbinquire(fb, scode, fbr)) != 0)
323                     return rc;
324 
325           /*
326            * If we could not get a valid number of planes, determine it
327            * by writing to the first frame buffer display location,
328            * then reading it back.
329            */
330           if (fb->planes == 0) {
331                     volatile uint8_t *fbp;
332                     uint8_t save;
333 
334                     fbp = (uint8_t *)fb->fbkva;
335                     tc->fben = ~0;
336                     tc->wen = ~0;
337                     tc->ren = ~0;
338                     tc->prr = RR_COPY;
339                     save = *fbp;
340                     *fbp = 0xff;
341                     fb->planemask = *fbp;
342                     *fbp = save;
343 
344                     for (fb->planes = 1; fb->planemask >= (1 << fb->planes);
345                         fb->planes++);
346                     if (fb->planes > 8)
347                               fb->planes = 8;
348                     fb->planemask = (1 << fb->planes) - 1;
349           }
350 
351           /*
352            * Some displays, such as the HP332 and HP340 internal video
353            * and HP98542/98543 appear to return a display width of 1024
354            * instead of 512. It looks these boards have actually have
355            * enough 64KB (1bpp) or 256KB (4bpp) VRAM and RAMDAC capabilities
356            * to display 1024x400 pixels.
357            *
358            * However HP's official "Service Information Manual" for
359            * "HP 900 Series 300 Computers Models 330/350" says:
360            *  "The medium-resolution board uses eight memory chips per plane.
361            *   This is enough to display 512 doubled pixels by 400 scan lines."
362            *
363            * This "512 doubled pixels" implies that the native HP-UX treated
364            * these 1024x400 framebuffers as pseudo 512x400 ones because
365            * ancient 1980s CRTs (such as 35741) didn't display such higher
366            * resolution. Furthermore, even modern LCDs can only handle
367            * upto 720 pixels in the "400 line" as VGA compatible mode.
368            *
369            * As mentioned above, we treat these 1024x400 1 bit or 4 bit
370            * framebuffers as "2 bytes per pixel" ones, so we have to handle
371            * 512 pixels per line with 1024 bytes per line.
372            */
373           if (fb->planes <= 4 && fb->dwidth == 1024 && fb->dheight == 400) {
374                     fb->dwidth = 512;
375                     sparse = true;
376           }
377 
378           fb->bmv = topcat_windowmove;
379           topcat_restore(fb);
380           diofb_fbsetup(fb);
381           if (!sparse) {
382                     /* save original rasops putchar op */
383                     fb->wsputchar = ri->ri_ops.putchar;
384                     ri->ri_ops.putchar = topcat_putchar8;
385           } else {
386                     ri->ri_ops.putchar = topcat_putchar1_4;
387                     /* copycols and erasecols ops require byte size of fontwidth */
388                     fb->wsd.fontwidth *= 2;
389                     /* copyrows and eraserows ops require byte size per line */
390                     ri->ri_emuwidth *= 2;
391           }
392           for (i = 0; i <= fb->planemask; i++)
393                     topcat_setcolor(fb, i);
394 
395           return 0;
396 }
397 
398 void
topcat_restore(struct diofb * fb)399 topcat_restore(struct diofb *fb)
400 {
401           volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva;
402 
403           /*
404            * Catseye looks a lot like a topcat, but not completely.
405            * So, we set some bits to make it work.
406            */
407           if (tc->regs.fbid != GID_TOPCAT) {
408                     while ((tc->catseye_status & 1))
409                               ;
410                     tc->catseye_status = 0x0;
411                     tc->vb_select = 0x0;
412                     tc->tcntrl = 0x0;
413                     tc->acntrl = 0x0;
414                     tc->pncntrl = 0x0;
415                     tc->rug_cmdstat = 0x90;
416           }
417 
418           /*
419            * Enable reading/writing of all the planes.
420            */
421           tc->fben = fb->planemask;
422           tc->wen  = fb->planemask;
423           tc->ren  = fb->planemask;
424           tc->prr  = RR_COPY;
425 
426           /* Enable display */
427           tc->nblank = fb->planemask;
428 }
429 
430 int
topcat_ioctl(void * v,void * vs,u_long cmd,void * data,int flags,struct lwp * l)431 topcat_ioctl(void *v, void *vs, u_long cmd, void *data, int flags,
432     struct lwp *l)
433 {
434           struct diofb *fb = v;
435           struct wsdisplay_fbinfo *wdf;
436           u_int i;
437 
438           switch (cmd) {
439           case WSDISPLAYIO_GTYPE:
440                     *(u_int *)data = WSDISPLAY_TYPE_TOPCAT;
441                     return 0;
442           case WSDISPLAYIO_SMODE:
443                     fb->mapmode = *(u_int *)data;
444                     if (fb->mapmode == WSDISPLAYIO_MODE_EMUL) {
445                               topcat_restore(fb);
446                               for (i = 0; i <= fb->planemask; i++)
447                                         topcat_setcolor(fb, i);
448                     }
449                     return 0;
450           case WSDISPLAYIO_GINFO:
451                     wdf = (void *)data;
452                     wdf->width = fb->ri.ri_width;
453                     wdf->height = fb->ri.ri_height;
454                     wdf->depth = fb->ri.ri_depth;
455                     wdf->cmsize = 1 << fb->planes;
456                     return 0;
457           case WSDISPLAYIO_LINEBYTES:
458                     *(u_int *)data = fb->ri.ri_stride;
459                     return 0;
460           case WSDISPLAYIO_GETCMAP:
461                     if (fb->planemask == 1)
462                               return EPASSTHROUGH;
463                     return diofb_getcmap(fb, (struct wsdisplay_cmap *)data);
464           case WSDISPLAYIO_PUTCMAP:
465                     if (fb->planemask == 1)
466                               return EPASSTHROUGH;
467                     return topcat_setcmap(fb, (struct wsdisplay_cmap *)data);
468           case WSDISPLAYIO_GVIDEO:
469           case WSDISPLAYIO_SVIDEO:
470                     return EPASSTHROUGH;
471           }
472 
473           return EPASSTHROUGH;
474 }
475 
476 void
topcat_setcolor(struct diofb * fb,u_int index)477 topcat_setcolor(struct diofb *fb, u_int index)
478 {
479           volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva;
480 
481           /* No color map registers on monochrome framebuffers. */
482           if (fb->planemask == 1)
483                     return;
484 
485           tc_waitbusy(tc, fb->planemask);
486 
487           if (tc->regs.fbid != GID_TOPCAT) {
488                     tccm_waitbusy(tc);
489                     tc->plane_mask = fb->planemask;
490                     tc->cindex = ~index;
491                     tc->rdata  = fb->cmap.r[index];
492                     tc->gdata  = fb->cmap.g[index];
493                     tc->bdata  = fb->cmap.b[index];
494                     tc->strobe = 0xff;
495                     /* XXX delay required on 68020/30 to avoid bus error */
496                     DELAY(100);
497 
498                     tccm_waitbusy(tc);
499                     tc->cindex = 0;
500           } else {
501                     tccm_waitbusy(tc);
502                     tc->plane_mask = fb->planemask;
503                     tc->rdata  = fb->cmap.r[index];
504                     tc->gdata  = fb->cmap.g[index];
505                     tc->bdata  = fb->cmap.b[index];
506                     DELAY(1); /* necessary for at least old HP98543 */
507                     tc->cindex = ~index;
508                     DELAY(1); /* necessary for at least old HP98543 */
509                     tc->strobe = 0xff;
510                     /* XXX delay required on 68020/30 to avoid bus error */
511                     DELAY(100);
512 
513                     tccm_waitbusy(tc);
514                     tc->rdata  = 0;
515                     tc->gdata  = 0;
516                     tc->bdata  = 0;
517                     tc->cindex = 0;
518           }
519 }
520 
521 int
topcat_setcmap(struct diofb * fb,struct wsdisplay_cmap * cm)522 topcat_setcmap(struct diofb *fb, struct wsdisplay_cmap *cm)
523 {
524           uint8_t r[256], g[256], b[256];
525           u_int index = cm->index, count = cm->count;
526           u_int colcount = 1 << fb->planes;
527           int error;
528 
529           if (index >= colcount || count > colcount - index)
530                     return EINVAL;
531 
532           if ((error = copyin(cm->red, r, count)) != 0)
533                     return error;
534           if ((error = copyin(cm->green, g, count)) != 0)
535                     return error;
536           if ((error = copyin(cm->blue, b, count)) != 0)
537                     return error;
538 
539           memcpy(fb->cmap.r + index, r, count);
540           memcpy(fb->cmap.g + index, g, count);
541           memcpy(fb->cmap.b + index, b, count);
542 
543           while (count-- != 0)
544                     topcat_setcolor(fb, index++);
545 
546           return 0;
547 }
548 
549 /*
550  * Accelerated routines
551  */
552 
553 int
topcat_windowmove(struct diofb * fb,uint16_t sx,uint16_t sy,uint16_t dx,uint16_t dy,uint16_t cx,uint16_t cy,int16_t rop,int16_t planemask)554 topcat_windowmove(struct diofb *fb, uint16_t sx, uint16_t sy,
555     uint16_t dx, uint16_t dy, uint16_t cx, uint16_t cy, int16_t rop,
556     int16_t planemask)
557 {
558           volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva;
559 
560           tc_waitbusy(tc, fb->planemask);
561 
562           if (planemask != 0xff) {
563                     tc->wen = planemask ^ 0xff;
564                     tc->wmrr = rop ^ 0x0f;
565                     tc->wen = fb->planemask;
566           } else {
567                     tc->wen = planemask;
568                     tc->wmrr = rop;
569           }
570           tc->source_y = sy;
571           tc->source_x = sx;
572           tc->dest_y = dy;
573           tc->dest_x = dx;
574           tc->wheight = cy;
575           tc->wwidth = cx;
576           tc->wmove = fb->planemask;
577 
578           return 0;
579 }
580 
581 static void
topcat_putchar8(void * cookie,int row,int col,u_int uc,long attr)582 topcat_putchar8(void *cookie, int row, int col, u_int uc, long attr)
583 {
584           struct rasops_info *ri = (struct rasops_info *)cookie;
585           struct diofb *diofb = ri->ri_hw;
586           volatile struct tcboxfb *tc = (struct tcboxfb *)diofb->regkva;
587 
588           /* Wait windowmove ops complete before drawing a glyph */
589           tc_waitbusy(tc, diofb->planemask);
590 
591           /* Call the original rasops putchar */
592           (*diofb->wsputchar)(cookie, row, col, uc, attr);
593 }
594 
595 /*
596  * Put a single character on 1 bpp (98542) or 4 bpp (98543) variants
597  * with 1024x400 VRAM to treat them as a pseudo 512x400 bitmap.
598  */
599 static void
topcat_putchar1_4(void * cookie,int row,int col,u_int uc,long attr)600 topcat_putchar1_4(void *cookie, int row, int col, u_int uc, long attr)
601 {
602           int width, height, cnt, fs;
603           uint32_t fb;
604           uint8_t *fr, clr[2];
605           uint8_t *dp, *rp;
606           struct rasops_info *ri;
607           struct diofb *diofb;
608           volatile struct tcboxfb *tc;
609 
610           ri = (struct rasops_info *)cookie;
611 
612           if (!CHAR_IN_FONT(uc, ri->ri_font))
613                     return;
614 
615           rp = ri->ri_bits + (row * ri->ri_yscale) +
616               (col * ri->ri_xscale * 2);
617 
618           height = ri->ri_font->fontheight;
619           width = ri->ri_font->fontwidth;
620           clr[0] = (uint8_t)ri->ri_devcmap[(attr >> 16) & 0xf];
621           clr[1] = (uint8_t)ri->ri_devcmap[(attr >> 24) & 0xf];
622 
623           /* Wait windowmove ops complete before drawing a glyph */
624           diofb = ri->ri_hw;
625           tc = (struct tcboxfb *)diofb->regkva;
626           tc_waitbusy(tc, diofb->planemask);
627 
628           /*
629            * We have to put pixel data to both odd and even addresses
630            * to handle "doubled pixels" as noted above.
631            */
632           if (uc == ' ') {
633                     uint16_t c = clr[0];
634 
635                     c = c << 8 | c;
636                     while (height--) {
637                               dp = rp;
638                               rp += ri->ri_stride;
639 
640                               for (cnt = width; cnt; cnt--) {
641                                         *(uint16_t *)dp = c;
642                                         dp += 2;
643                               }
644                     }
645           } else {
646                     uc -= ri->ri_font->firstchar;
647                     fr = (uint8_t *)ri->ri_font->data + uc * ri->ri_fontscale;
648                     fs = ri->ri_font->stride;
649 
650                     while (height--) {
651                               dp = rp;
652                               fb = be32dec(fr);
653                               fr += fs;
654                               rp += ri->ri_stride;
655 
656                               for (cnt = width; cnt; cnt--) {
657                                         uint16_t c = clr[(fb >> 31) & 1];
658 
659                                         c = c << 8 | c;
660                                         *(uint16_t *)dp = c;
661                                         dp += 2;
662                                         fb <<= 1;
663                               }
664                     }
665           }
666 
667           /* Do underline */
668           if ((attr & WSATTR_UNDERLINE) != 0) {
669                     uint16_t c = clr[1];
670 
671                     c = c << 8 | c;
672                     rp -= ri->ri_stride * ri->ri_ul.off;
673 
674                     while (width--) {
675                               *(uint16_t *)rp = c;
676                               rp += 2;
677                     }
678           }
679 }
680 
681 /*
682  *   Topcat/catseye console attachment
683  */
684 
685 int
topcatcnattach(bus_space_tag_t bst,bus_addr_t addr,int scode)686 topcatcnattach(bus_space_tag_t bst, bus_addr_t addr, int scode)
687 {
688           bus_space_handle_t bsh;
689           void *va;
690           struct diofbreg *fbr;
691           struct diofb *fb = &diofb_cn;
692           int size;
693 
694           if (bus_space_map(bst, addr, PAGE_SIZE, 0, &bsh))
695                     return 1;
696           va = bus_space_vaddr(bst, bsh);
697           fbr = va;
698 
699           if (badaddr(va) || fbr->id != GRFHWID) {
700                     bus_space_unmap(bst, bsh, PAGE_SIZE);
701                     return 1;
702           }
703 
704           switch (fbr->fbid) {
705           case GID_TOPCAT:
706           case GID_LRCATSEYE:
707           case GID_HRCCATSEYE:
708           case GID_HRMCATSEYE:
709                     break;
710 
711           default:
712                     bus_space_unmap(bst, bsh, PAGE_SIZE);
713                     return 1;
714           }
715 
716           size = DIO_SIZE(scode, va);
717 
718           bus_space_unmap(bst, bsh, PAGE_SIZE);
719           if (bus_space_map(bst, addr, size, 0, &bsh))
720                     return 1;
721           va = bus_space_vaddr(bst, bsh);
722 
723           /*
724            * Initialize the framebuffer hardware.
725            */
726           conscode = scode;
727           conaddr = va;
728           topcat_reset(fb, conscode, (struct diofbreg *)conaddr);
729 
730           /*
731            * Initialize the terminal emulator.
732            */
733           diofb_cnattach(fb);
734           return 0;
735 }
736