xref: /netbsd-src/sys/arch/hp300/dev/topcat.c (revision 6e9a937cb802caf4025a5f80eb377b2a1eb14bfa)
1 /*	$NetBSD: topcat.c,v 1.13 2024/12/20 22:42:57 tsutsui 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
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
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
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
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
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
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 officlal "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
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
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
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
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
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
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
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
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