topcat.c revision 1.7 1 /* $NetBSD: topcat.c,v 1.7 2024/04/29 15:34: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
153 static struct wsdisplay_accessops topcat_accessops = {
154 topcat_ioctl,
155 diofb_mmap,
156 diofb_alloc_screen,
157 diofb_free_screen,
158 diofb_show_screen,
159 NULL, /* load_font */
160 };
161
162 /*
163 * Attachment glue
164 */
165
166 int
167 topcat_intio_match(device_t parent, cfdata_t cf, void *aux)
168 {
169 struct intio_attach_args *ia = aux;
170 struct diofbreg *fbr;
171
172 if (strcmp("fb", ia->ia_modname) != 0)
173 return 0;
174
175 fbr = (struct diofbreg *)ia->ia_addr;
176
177 if (badaddr((void *)fbr))
178 return 0;
179
180 if (fbr->id == GRFHWID) {
181 switch (fbr->fbid) {
182 case GID_TOPCAT:
183 case GID_LRCATSEYE:
184 case GID_HRCCATSEYE:
185 case GID_HRMCATSEYE:
186 #if 0
187 case GID_XXXCATSEYE:
188 #endif
189 return 1;
190 }
191 }
192
193 return 0;
194 }
195
196 void
197 topcat_intio_attach(device_t parent, device_t self, void *aux)
198 {
199 struct topcat_softc *sc = device_private(self);
200 struct intio_attach_args *ia = aux;
201 struct diofbreg *fbr;
202
203 sc->sc_dev = self;
204 fbr = (struct diofbreg *)ia->ia_addr;
205 sc->sc_scode = CONSCODE_INTERNAL;
206
207 if (sc->sc_scode == conscode) {
208 sc->sc_fb = &diofb_cn;
209 } else {
210 sc->sc_fb = &sc->sc_fb_store;
211 topcat_reset(sc->sc_fb, sc->sc_scode, fbr);
212 }
213
214 topcat_end_attach(sc, fbr->fbid);
215 }
216
217 int
218 topcat_dio_match(device_t parent, cfdata_t cf, void *aux)
219 {
220 struct dio_attach_args *da = aux;
221
222 if (da->da_id == DIO_DEVICE_ID_FRAMEBUFFER) {
223 switch (da->da_secid) {
224 case DIO_DEVICE_SECID_TOPCAT:
225 case DIO_DEVICE_SECID_LRCATSEYE:
226 case DIO_DEVICE_SECID_HRCCATSEYE:
227 case DIO_DEVICE_SECID_HRMCATSEYE:
228 #if 0
229 case DIO_DEVICE_SECID_XXXCATSEYE:
230 #endif
231 return 1;
232 }
233 }
234
235 return 0;
236 }
237
238 void
239 topcat_dio_attach(device_t parent, device_t self, void *aux)
240 {
241 struct topcat_softc *sc = device_private(self);
242 struct dio_attach_args *da = aux;
243 bus_space_handle_t bsh;
244 struct diofbreg *fbr;
245
246 sc->sc_dev = self;
247 sc->sc_scode = da->da_scode;
248 if (sc->sc_scode == conscode) {
249 fbr = (struct diofbreg *)conaddr; /* already mapped */
250 sc->sc_fb = &diofb_cn;
251 } else {
252 sc->sc_fb = &sc->sc_fb_store;
253 if (bus_space_map(da->da_bst, da->da_addr, da->da_size, 0,
254 &bsh)) {
255 aprint_error(": can't map framebuffer\n");
256 return;
257 }
258 fbr = bus_space_vaddr(da->da_bst, bsh);
259 if (topcat_reset(sc->sc_fb, sc->sc_scode, fbr) != 0) {
260 aprint_error(": can't reset framebuffer\n");
261 return;
262 }
263 }
264
265 topcat_end_attach(sc, fbr->fbid);
266 }
267
268 void
269 topcat_end_attach(struct topcat_softc *sc, uint8_t id)
270 {
271 const char *fbname = "unknown";
272
273 switch (id) {
274 case GID_TOPCAT:
275 switch (sc->sc_fb->planes) {
276 case 1:
277 if (sc->sc_fb->dheight == 400)
278 fbname = "HP98542 topcat";
279 else
280 fbname = "HP98544 topcat";
281 break;
282 case 4:
283 if (sc->sc_fb->dheight == 400)
284 fbname = "HP98543 topcat";
285 else
286 fbname = "HP98545 topcat";
287 break;
288 case 6:
289 fbname = "HP98547 topcat";
290 break;
291 }
292 break;
293 case GID_HRCCATSEYE:
294 fbname = "HP98550 catseye"; /* also A1416 kathmandu */
295 break;
296 case GID_LRCATSEYE:
297 fbname = "HP98549 catseye";
298 break;
299 case GID_HRMCATSEYE:
300 fbname = "HP98548 catseye";
301 break;
302 }
303
304 diofb_end_attach(sc->sc_dev, &topcat_accessops, sc->sc_fb,
305 sc->sc_scode == conscode, fbname);
306 }
307
308 /*
309 * Initialize hardware and display routines.
310 */
311 int
312 topcat_reset(struct diofb *fb, int scode, struct diofbreg *fbr)
313 {
314 volatile struct tcboxfb *tc = (struct tcboxfb *)fbr;
315 int rc;
316 u_int i;
317
318 if ((rc = diofb_fbinquire(fb, scode, fbr)) != 0)
319 return rc;
320
321 /*
322 * If we could not get a valid number of planes, determine it
323 * by writing to the first frame buffer display location,
324 * then reading it back.
325 */
326 if (fb->planes == 0) {
327 volatile uint8_t *fbp;
328 uint8_t save;
329
330 fbp = (uint8_t *)fb->fbkva;
331 tc->fben = ~0;
332 tc->wen = ~0;
333 tc->ren = ~0;
334 tc->prr = RR_COPY;
335 save = *fbp;
336 *fbp = 0xff;
337 fb->planemask = *fbp;
338 *fbp = save;
339
340 for (fb->planes = 1; fb->planemask >= (1 << fb->planes);
341 fb->planes++);
342 if (fb->planes > 8)
343 fb->planes = 8;
344 fb->planemask = (1 << fb->planes) - 1;
345 }
346
347 /*
348 * Some displays, such as the HP332 and HP340 internal video
349 * and HP98542/98543 appear to return a display width of 1024
350 * instead of 512.
351 *
352 * It looks these boards have VRAM with sparse address layout,
353 * i.e. 1 bit or 4 bits per pixel but 2 bytes per pixel, so
354 * we have to handle 512 pixels per line with 1024 bytes per line.
355 */
356 if (fb->planes <= 4 && fb->dwidth == 1024 && fb->dheight == 400) {
357 fb->dwidth = 512;
358 }
359
360 fb->bmv = topcat_windowmove;
361 topcat_restore(fb);
362 diofb_fbsetup(fb);
363 for (i = 0; i <= fb->planemask; i++)
364 topcat_setcolor(fb, i);
365
366 return 0;
367 }
368
369 void
370 topcat_restore(struct diofb *fb)
371 {
372 volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva;
373
374 /*
375 * Catseye looks a lot like a topcat, but not completely.
376 * So, we set some bits to make it work.
377 */
378 if (tc->regs.fbid != GID_TOPCAT) {
379 while ((tc->catseye_status & 1))
380 ;
381 tc->catseye_status = 0x0;
382 tc->vb_select = 0x0;
383 tc->tcntrl = 0x0;
384 tc->acntrl = 0x0;
385 tc->pncntrl = 0x0;
386 tc->rug_cmdstat = 0x90;
387 }
388
389 /*
390 * Enable reading/writing of all the planes.
391 */
392 tc->fben = fb->planemask;
393 tc->wen = fb->planemask;
394 tc->ren = fb->planemask;
395 tc->prr = RR_COPY;
396
397 /* Enable display */
398 tc->nblank = 0xff;
399 }
400
401 int
402 topcat_ioctl(void *v, void *vs, u_long cmd, void *data, int flags,
403 struct lwp *l)
404 {
405 struct diofb *fb = v;
406 struct wsdisplay_fbinfo *wdf;
407 u_int i;
408
409 switch (cmd) {
410 case WSDISPLAYIO_GTYPE:
411 *(u_int *)data = WSDISPLAY_TYPE_TOPCAT;
412 return 0;
413 case WSDISPLAYIO_SMODE:
414 fb->mapmode = *(u_int *)data;
415 if (fb->mapmode == WSDISPLAYIO_MODE_EMUL) {
416 topcat_restore(fb);
417 for (i = 0; i <= fb->planemask; i++)
418 topcat_setcolor(fb, i);
419 }
420 return 0;
421 case WSDISPLAYIO_GINFO:
422 wdf = (void *)data;
423 wdf->width = fb->ri.ri_width;
424 wdf->height = fb->ri.ri_height;
425 wdf->depth = fb->ri.ri_depth;
426 wdf->cmsize = 1 << fb->planes;
427 return 0;
428 case WSDISPLAYIO_LINEBYTES:
429 *(u_int *)data = fb->ri.ri_stride;
430 return 0;
431 case WSDISPLAYIO_GETCMAP:
432 if (fb->planemask == 1)
433 return EPASSTHROUGH;
434 return diofb_getcmap(fb, (struct wsdisplay_cmap *)data);
435 case WSDISPLAYIO_PUTCMAP:
436 if (fb->planemask == 1)
437 return EPASSTHROUGH;
438 return topcat_setcmap(fb, (struct wsdisplay_cmap *)data);
439 case WSDISPLAYIO_GVIDEO:
440 case WSDISPLAYIO_SVIDEO:
441 return EPASSTHROUGH;
442 }
443
444 return EPASSTHROUGH;
445 }
446
447 void
448 topcat_setcolor(struct diofb *fb, u_int index)
449 {
450 volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva;
451
452 /* No color map registers on monochrome framebuffers. */
453 if (fb->planemask == 1)
454 return;
455
456 if (tc->regs.fbid != GID_TOPCAT) {
457 tccm_waitbusy(tc);
458 tc->plane_mask = 0xff;
459 tc->cindex = ~index;
460 tc->rdata = fb->cmap.r[index];
461 tc->gdata = fb->cmap.g[index];
462 tc->bdata = fb->cmap.b[index];
463 tc->strobe = 0xff;
464 /* XXX delay required on 68020/30 to avoid bus error */
465 DELAY(100);
466
467 tccm_waitbusy(tc);
468 tc->cindex = 0;
469 } else {
470 tccm_waitbusy(tc);
471 tc->plane_mask = 0xff;
472 tc->rdata = fb->cmap.r[index];
473 tc->gdata = fb->cmap.g[index];
474 tc->bdata = fb->cmap.b[index];
475 tc->cindex = ~index;
476 tc->strobe = 0xff;
477 /* XXX delay required on 68020/30 to avoid bus error */
478 DELAY(100);
479
480 tccm_waitbusy(tc);
481 tc->rdata = 0;
482 tc->gdata = 0;
483 tc->bdata = 0;
484 tc->cindex = 0;
485 }
486 }
487
488 int
489 topcat_setcmap(struct diofb *fb, struct wsdisplay_cmap *cm)
490 {
491 uint8_t r[256], g[256], b[256];
492 u_int index = cm->index, count = cm->count;
493 u_int colcount = 1 << fb->planes;
494 int error;
495
496 if (index >= colcount || count > colcount - index)
497 return EINVAL;
498
499 if ((error = copyin(cm->red, r, count)) != 0)
500 return error;
501 if ((error = copyin(cm->green, g, count)) != 0)
502 return error;
503 if ((error = copyin(cm->blue, b, count)) != 0)
504 return error;
505
506 memcpy(fb->cmap.r + index, r, count);
507 memcpy(fb->cmap.g + index, g, count);
508 memcpy(fb->cmap.b + index, b, count);
509
510 while (count-- != 0)
511 topcat_setcolor(fb, index++);
512
513 return 0;
514 }
515
516 /*
517 * Accelerated routines
518 */
519
520 int
521 topcat_windowmove(struct diofb *fb, uint16_t sx, uint16_t sy,
522 uint16_t dx, uint16_t dy, uint16_t cx, uint16_t cy, int16_t rop,
523 int16_t planemask)
524 {
525 volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva;
526
527 tc_waitbusy(tc, fb->planemask);
528
529 tc->wen = planemask;
530 tc->wmrr = rop;
531 if (planemask != 0xff) {
532 tc->wen = planemask ^ 0xff;
533 tc->wmrr = rop ^ 0x0f;
534 tc->wen = fb->planemask;
535 }
536 tc->source_y = sy;
537 tc->source_x = sx;
538 tc->dest_y = dy;
539 tc->dest_x = dx;
540 tc->wheight = cy;
541 tc->wwidth = cx;
542 tc->wmove = fb->planemask;
543
544 tc_waitbusy(tc, fb->planemask);
545
546 return 0;
547 }
548
549
550 /*
551 * Topcat/catseye console attachment
552 */
553
554 int
555 topcatcnattach(bus_space_tag_t bst, bus_addr_t addr, int scode)
556 {
557 bus_space_handle_t bsh;
558 void *va;
559 struct diofbreg *fbr;
560 struct diofb *fb = &diofb_cn;
561 int size;
562
563 if (bus_space_map(bst, addr, PAGE_SIZE, 0, &bsh))
564 return 1;
565 va = bus_space_vaddr(bst, bsh);
566 fbr = va;
567
568 if (badaddr(va) || fbr->id != GRFHWID) {
569 bus_space_unmap(bst, bsh, PAGE_SIZE);
570 return 1;
571 }
572
573 switch (fbr->fbid) {
574 case GID_TOPCAT:
575 case GID_LRCATSEYE:
576 case GID_HRCCATSEYE:
577 case GID_HRMCATSEYE:
578 break;
579
580 default:
581 bus_space_unmap(bst, bsh, PAGE_SIZE);
582 return 1;
583 }
584
585 size = DIO_SIZE(scode, va);
586
587 bus_space_unmap(bst, bsh, PAGE_SIZE);
588 if (bus_space_map(bst, addr, size, 0, &bsh))
589 return 1;
590 va = bus_space_vaddr(bst, bsh);
591
592 /*
593 * Initialize the framebuffer hardware.
594 */
595 conscode = scode;
596 conaddr = va;
597 topcat_reset(fb, conscode, (struct diofbreg *)conaddr);
598
599 /*
600 * Initialize the terminal emulator.
601 */
602 diofb_cnattach(fb);
603 return 0;
604 }
605