topcat.c revision 1.2 1 /* $NetBSD: topcat.c,v 1.2 2011/02/12 16:40:29 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 int topcat_dio_match(device_t, cfdata_t, void *);
133 void topcat_dio_attach(device_t, device_t, void *);
134 int topcat_intio_match(device_t, cfdata_t, void *);
135 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 void topcat_end_attach(struct topcat_softc *, uint8_t);
144 int topcat_reset(struct diofb *, int, struct diofbreg *);
145 void topcat_restore(struct diofb *);
146 int topcat_setcmap(struct diofb *, struct wsdisplay_cmap *);
147 void topcat_setcolor(struct diofb *, u_int);
148 int topcat_windowmove(struct diofb *, uint16_t, uint16_t, uint16_t,
149 uint16_t, uint16_t, uint16_t, int16_t, int16_t);
150
151 int topcat_ioctl(void *, void *, u_long, void *, int, struct lwp *);
152
153 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 printf(": can't map 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 fbname = "HP98544 topcat";
278 break;
279 case 4:
280 if (sc->sc_fb->dheight == 400)
281 fbname = "HP98543 topcat";
282 else
283 fbname = "HP98545 topcat";
284 break;
285 case 6:
286 fbname = "HP98547 topcat";
287 break;
288 }
289 break;
290 case GID_HRCCATSEYE:
291 fbname = "HP98550 catseye"; /* also A1416 kathmandu */
292 break;
293 case GID_LRCATSEYE:
294 fbname = "HP98549 catseye";
295 break;
296 case GID_HRMCATSEYE:
297 fbname = "HP98548 catseye";
298 break;
299 }
300
301 diofb_end_attach(sc->sc_dev, &topcat_accessops, sc->sc_fb,
302 sc->sc_scode == conscode, fbname);
303 }
304
305 /*
306 * Initialize hardware and display routines.
307 */
308 int
309 topcat_reset(struct diofb *fb, int scode, struct diofbreg *fbr)
310 {
311 volatile struct tcboxfb *tc = (struct tcboxfb *)fbr;
312 int rc;
313 u_int i;
314
315 if ((rc = diofb_fbinquire(fb, scode, fbr)) != 0)
316 return rc;
317
318 /*
319 * If we could not get a valid number of planes, determine it
320 * by writing to the first frame buffer display location,
321 * then reading it back.
322 */
323 if (fb->planes == 0) {
324 volatile uint8_t *fbp;
325 uint8_t save;
326
327 fbp = (uint8_t *)fb->fbkva;
328 tc->fben = ~0;
329 tc->wen = ~0;
330 tc->ren = ~0;
331 tc->prr = RR_COPY;
332 save = *fbp;
333 *fbp = 0xff;
334 fb->planemask = *fbp;
335 *fbp = save;
336
337 for (fb->planes = 1; fb->planemask >= (1 << fb->planes);
338 fb->planes++);
339 if (fb->planes > 8)
340 fb->planes = 8;
341 fb->planemask = (1 << fb->planes) - 1;
342 }
343
344 fb->bmv = topcat_windowmove;
345 topcat_restore(fb);
346 diofb_fbsetup(fb);
347 for (i = 0; i <= fb->planemask; i++)
348 topcat_setcolor(fb, i);
349
350 return 0;
351 }
352
353 void
354 topcat_restore(struct diofb *fb)
355 {
356 volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva;
357
358 /*
359 * Catseye looks a lot like a topcat, but not completely.
360 * So, we set some bits to make it work.
361 */
362 if (tc->regs.fbid != GID_TOPCAT) {
363 while ((tc->catseye_status & 1))
364 ;
365 tc->catseye_status = 0x0;
366 tc->vb_select = 0x0;
367 tc->tcntrl = 0x0;
368 tc->acntrl = 0x0;
369 tc->pncntrl = 0x0;
370 tc->rug_cmdstat = 0x90;
371 }
372
373 /*
374 * Enable reading/writing of all the planes.
375 */
376 tc->fben = fb->planemask;
377 tc->wen = fb->planemask;
378 tc->ren = fb->planemask;
379 tc->prr = RR_COPY;
380
381 /* Enable display */
382 tc->nblank = 0xff;
383 }
384
385 int
386 topcat_ioctl(void *v, void *vs, u_long cmd, void *data, int flags,
387 struct lwp *l)
388 {
389 struct diofb *fb = v;
390 struct wsdisplay_fbinfo *wdf;
391 u_int i;
392
393 switch (cmd) {
394 case WSDISPLAYIO_GTYPE:
395 *(u_int *)data = WSDISPLAY_TYPE_TOPCAT;
396 return 0;
397 case WSDISPLAYIO_SMODE:
398 fb->mapmode = *(u_int *)data;
399 if (fb->mapmode == WSDISPLAYIO_MODE_EMUL) {
400 topcat_restore(fb);
401 for (i = 0; i <= fb->planemask; i++)
402 topcat_setcolor(fb, i);
403 }
404 return 0;
405 case WSDISPLAYIO_GINFO:
406 wdf = (void *)data;
407 wdf->width = fb->ri.ri_width;
408 wdf->height = fb->ri.ri_height;
409 wdf->depth = fb->ri.ri_depth;
410 wdf->cmsize = 1 << fb->planes;
411 return 0;
412 case WSDISPLAYIO_LINEBYTES:
413 *(u_int *)data = fb->ri.ri_stride;
414 return 0;
415 case WSDISPLAYIO_GETCMAP:
416 return diofb_getcmap(fb, (struct wsdisplay_cmap *)data);
417 case WSDISPLAYIO_PUTCMAP:
418 return topcat_setcmap(fb, (struct wsdisplay_cmap *)data);
419 case WSDISPLAYIO_GVIDEO:
420 case WSDISPLAYIO_SVIDEO:
421 return EPASSTHROUGH;
422 }
423
424 return EPASSTHROUGH;
425 }
426
427 void
428 topcat_setcolor(struct diofb *fb, u_int index)
429 {
430 volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva;
431
432 if (tc->regs.fbid != GID_TOPCAT) {
433 tccm_waitbusy(tc);
434 tc->plane_mask = 0xff;
435 tc->cindex = ~index;
436 tc->rdata = fb->cmap.r[index];
437 tc->gdata = fb->cmap.g[index];
438 tc->bdata = fb->cmap.b[index];
439 tc->strobe = 0xff;
440
441 tccm_waitbusy(tc);
442 tc->cindex = 0;
443 } else {
444 tccm_waitbusy(tc);
445 tc->plane_mask = 0xff;
446 tc->rdata = fb->cmap.r[index];
447 tc->gdata = fb->cmap.g[index];
448 tc->bdata = fb->cmap.b[index];
449 tc->cindex = ~index;
450 tc->strobe = 0xff;
451
452 tccm_waitbusy(tc);
453 tc->rdata = 0;
454 tc->gdata = 0;
455 tc->bdata = 0;
456 tc->cindex = 0;
457 }
458 }
459
460 int
461 topcat_setcmap(struct diofb *fb, struct wsdisplay_cmap *cm)
462 {
463 uint8_t r[256], g[256], b[256];
464 u_int index = cm->index, count = cm->count;
465 u_int colcount = 1 << fb->planes;
466 int error;
467
468 if (index >= colcount || count > colcount - index)
469 return EINVAL;
470
471 if ((error = copyin(cm->red, r, count)) != 0)
472 return error;
473 if ((error = copyin(cm->green, g, count)) != 0)
474 return error;
475 if ((error = copyin(cm->blue, b, count)) != 0)
476 return error;
477
478 memcpy(fb->cmap.r + index, r, count);
479 memcpy(fb->cmap.g + index, g, count);
480 memcpy(fb->cmap.b + index, b, count);
481
482 while (count-- != 0)
483 topcat_setcolor(fb, index++);
484
485 return 0;
486 }
487
488 /*
489 * Accelerated routines
490 */
491
492 int
493 topcat_windowmove(struct diofb *fb, uint16_t sx, uint16_t sy,
494 uint16_t dx, uint16_t dy, uint16_t cx, uint16_t cy, int16_t rop,
495 int16_t planemask)
496 {
497 volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva;
498
499 tc_waitbusy(tc, fb->planemask);
500
501 tc->wen = planemask;
502 tc->wmrr = rop;
503 if (planemask != 0xff) {
504 tc->wen = planemask ^ 0xff;
505 tc->wmrr = rop ^ 0x0f;
506 tc->wen = fb->planemask;
507 }
508 tc->source_y = sy;
509 tc->source_x = sx;
510 tc->dest_y = dy;
511 tc->dest_x = dx;
512 tc->wheight = cy;
513 tc->wwidth = cx;
514 tc->wmove = fb->planemask;
515
516 tc_waitbusy(tc, fb->planemask);
517
518 return 0;
519 }
520
521
522 /*
523 * Topcat/catseye console attachment
524 */
525
526 int
527 topcatcnattach(bus_space_tag_t bst, bus_addr_t addr, int scode)
528 {
529 bus_space_handle_t bsh;
530 void *va;
531 struct diofbreg *fbr;
532 struct diofb *fb = &diofb_cn;
533 int size;
534
535 if (bus_space_map(bst, addr, PAGE_SIZE, 0, &bsh))
536 return 1;
537 va = bus_space_vaddr(bst, bsh);
538 fbr = va;
539
540 if (badaddr(va) || fbr->id != GRFHWID) {
541 bus_space_unmap(bst, bsh, PAGE_SIZE);
542 return 1;
543 }
544
545 switch (fbr->fbid) {
546 case GID_TOPCAT:
547 case GID_LRCATSEYE:
548 case GID_HRCCATSEYE:
549 case GID_HRMCATSEYE:
550 break;
551
552 default:
553 bus_space_unmap(bst, bsh, PAGE_SIZE);
554 return 1;
555 }
556
557 size = DIO_SIZE(scode, va);
558
559 bus_space_unmap(bst, bsh, PAGE_SIZE);
560 if (bus_space_map(bst, addr, size, 0, &bsh))
561 return 1;
562 va = bus_space_vaddr(bst, bsh);
563
564 /*
565 * Initialize the framebuffer hardware.
566 */
567 conscode = scode;
568 conaddr = va;
569 topcat_reset(fb, conscode, (struct diofbreg *)conaddr);
570
571 /*
572 * Initialize the terminal emulator.
573 */
574 diofb_cnattach(fb);
575 return 0;
576 }
577