No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / sparc64 / dev / ffb.c
blobce09c84ea4d86c114e4ec32c88c1d34bdf54cc47
1 /* $NetBSD: ffb.c,v 1.36 2008/11/16 05:10:46 macallan Exp $ */
2 /* $OpenBSD: creator.c,v 1.20 2002/07/30 19:48:15 jason Exp $ */
4 /*
5 * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
6 * All rights reserved.
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 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Jason L. Wright
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: ffb.c,v 1.36 2008/11/16 05:10:46 macallan Exp $");
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <sys/conf.h>
44 #include <sys/ioctl.h>
45 #include <sys/malloc.h>
46 #include <sys/mman.h>
48 #include <machine/bus.h>
49 #include <machine/autoconf.h>
50 #include <machine/openfirm.h>
51 #include <machine/vmparam.h>
53 #include <dev/wscons/wsconsio.h>
54 #include <dev/sun/fbio.h>
55 #include <dev/sun/fbvar.h>
57 #include <dev/wsfont/wsfont.h>
58 #include <dev/wscons/wsdisplay_vconsvar.h>
60 #include <sparc64/dev/ffbreg.h>
61 #include <sparc64/dev/ffbvar.h>
63 #ifndef WS_DEFAULT_BG
64 /* Sun -> background should be white */
65 #define WS_DEFAULT_BG 0xf
66 #endif
68 extern struct cfdriver ffb_cd;
70 struct wsscreen_descr ffb_stdscreen = {
71 "sunffb",
72 0, 0, /* will be filled in -- XXX shouldn't, it's global. */
74 0, 0,
75 WSSCREEN_REVERSE | WSSCREEN_WSCOLORS,
76 NULL /* modecookie */
79 const struct wsscreen_descr *ffb_scrlist[] = {
80 &ffb_stdscreen,
81 /* XXX other formats? */
84 struct wsscreen_list ffb_screenlist = {
85 sizeof(ffb_scrlist) / sizeof(struct wsscreen_descr *),
86 ffb_scrlist
89 static struct vcons_screen ffb_console_screen;
91 int ffb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
92 static int ffb_blank(struct ffb_softc *, u_long, u_int *);
93 paddr_t ffb_mmap(void *, void *, off_t, int);
94 void ffb_ras_fifo_wait(struct ffb_softc *, int);
95 void ffb_ras_wait(struct ffb_softc *);
96 void ffb_ras_init(struct ffb_softc *);
97 void ffb_ras_copyrows(void *, int, int, int);
98 void ffb_ras_erasecols(void *, int, int, int, long int);
99 void ffb_ras_eraserows(void *, int, int, long int);
100 void ffb_ras_do_cursor(struct rasops_info *);
101 void ffb_ras_fill(struct ffb_softc *);
102 void ffb_ras_setfg(struct ffb_softc *, int32_t);
104 void ffb_clearscreen(struct ffb_softc *);
105 int ffb_load_font(void *, void *, struct wsdisplay_font *);
106 void ffb_init_screen(void *, struct vcons_screen *, int,
107 long *);
108 int ffb_allocattr(void *, int, int, int, long *);
109 void ffb_putchar(void *, int, int, u_int, long);
110 void ffb_cursor(void *, int, int, int);
112 /* frame buffer generic driver */
113 static void ffbfb_unblank(struct device*);
114 dev_type_open(ffbfb_open);
115 dev_type_close(ffbfb_close);
116 dev_type_ioctl(ffbfb_ioctl);
117 dev_type_mmap(ffbfb_mmap);
119 static struct fbdriver ffb_fbdriver = {
120 ffbfb_unblank, ffbfb_open, ffbfb_close, ffbfb_ioctl, nopoll,
121 ffbfb_mmap, nokqfilter
124 struct wsdisplay_accessops ffb_accessops = {
125 .ioctl = ffb_ioctl,
126 .mmap = ffb_mmap,
129 void
130 ffb_attach(struct ffb_softc *sc)
132 struct wsemuldisplaydev_attach_args waa;
133 struct rasops_info *ri;
134 long defattr;
135 const char *model;
136 int btype;
137 uint32_t dac;
138 int maxrow, maxcol;
139 u_int blank = WSDISPLAYIO_VIDEO_ON;
140 char buf[6+1];
142 printf(":");
144 sc->putchar = NULL;
146 if (sc->sc_type == FFB_CREATOR) {
147 btype = prom_getpropint(sc->sc_node, "board_type", 0);
148 if ((btype & 7) == 3)
149 printf(" Creator3D");
150 else
151 printf(" Creator");
152 } else
153 printf(" Elite3D");
155 model = prom_getpropstring(sc->sc_node, "model");
156 if (model == NULL || strlen(model) == 0)
157 model = "unknown";
159 sc->sc_depth = 24;
160 sc->sc_linebytes = 8192;
161 sc->sc_height = prom_getpropint(sc->sc_node, "height", 0);
162 sc->sc_width = prom_getpropint(sc->sc_node, "width", 0);
164 sc->sc_locked = 0;
165 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
167 maxcol = (prom_getoption("screen-#columns", buf, sizeof buf) == 0)
168 ? strtoul(buf, NULL, 10)
169 : 80;
171 maxrow = (prom_getoption("screen-#rows", buf, sizeof buf) != 0)
172 ? strtoul(buf, NULL, 10)
173 : 34;
175 ffb_ras_init(sc);
177 /* collect DAC version, as Elite3D cursor enable bit is reversed */
178 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GVERS);
179 dac = DAC_READ(sc, FFB_DAC_VALUE);
180 sc->sc_dacrev = (dac >> 28) & 0xf;
182 if (sc->sc_type == FFB_AFB) {
183 sc->sc_dacrev = 10;
184 sc->sc_needredraw = 0;
185 } else {
186 /* see what kind of DAC we have */
187 int pnum = (dac & 0x0ffff000) >> 12;
188 if (pnum == 0x236e) {
189 sc->sc_needredraw = 0;
190 } else {
191 sc->sc_needredraw = 1;
194 printf(", model %s, dac %u\n", model, sc->sc_dacrev);
195 if (sc->sc_needredraw)
196 printf("%s: found old DAC, enabling redraw on unblank\n",
197 device_xname(&sc->sc_dv));
199 ffb_blank(sc, WSDISPLAYIO_SVIDEO, &blank);
201 sc->sc_accel = ((device_cfdata(&sc->sc_dv)->cf_flags &
202 FFB_CFFLAG_NOACCEL) == 0);
204 wsfont_init();
206 vcons_init(&sc->vd, sc, &ffb_stdscreen, &ffb_accessops);
207 sc->vd.init_screen = ffb_init_screen;
209 /* we mess with ffb_console_screen only once */
210 if (sc->sc_console) {
211 vcons_init_screen(&sc->vd, &ffb_console_screen, 1, &defattr);
212 SCREEN_VISIBLE((&ffb_console_screen));
214 * XXX we shouldn't use a global variable for the console
215 * screen
217 sc->vd.active = &ffb_console_screen;
218 ffb_console_screen.scr_flags = VCONS_SCREEN_IS_STATIC;
219 } else {
220 if (ffb_console_screen.scr_ri.ri_rows == 0) {
221 /* do some minimal setup to avoid weirdnesses later */
222 vcons_init_screen(&sc->vd, &ffb_console_screen, 1, &defattr);
225 ri = &ffb_console_screen.scr_ri;
227 ffb_stdscreen.nrows = ri->ri_rows;
228 ffb_stdscreen.ncols = ri->ri_cols;
229 ffb_stdscreen.textops = &ri->ri_ops;
230 ffb_stdscreen.capabilities = ri->ri_caps;
232 sc->sc_fb.fb_driver = &ffb_fbdriver;
233 sc->sc_fb.fb_type.fb_cmsize = 0;
234 sc->sc_fb.fb_type.fb_size = maxrow * sc->sc_linebytes;
235 sc->sc_fb.fb_type.fb_type = FBTYPE_CREATOR;
236 sc->sc_fb.fb_type.fb_width = sc->sc_width;
237 sc->sc_fb.fb_type.fb_depth = sc->sc_depth;
238 sc->sc_fb.fb_type.fb_height = sc->sc_height;
239 sc->sc_fb.fb_device = &sc->sc_dv;
240 fb_attach(&sc->sc_fb, sc->sc_console);
242 ffb_clearscreen(sc);
244 if (sc->sc_console) {
245 wsdisplay_cnattach(&ffb_stdscreen, ri, 0, 0, defattr);
246 vcons_replay_msgbuf(&ffb_console_screen);
249 waa.console = sc->sc_console;
250 waa.scrdata = &ffb_screenlist;
251 waa.accessops = &ffb_accessops;
252 waa.accesscookie = &sc->vd;
253 config_found(&sc->sc_dv, &waa, wsemuldisplaydevprint);
257 ffb_ioctl(void *v, void *vs, u_long cmd, void *data, int flags, struct lwp *l)
259 struct vcons_data *vd = v;
260 struct ffb_softc *sc = vd->cookie;
261 struct wsdisplay_fbinfo *wdf;
262 struct vcons_screen *ms = vd->active;
264 #ifdef FFBDEBUG
265 printf("ffb_ioctl: %s cmd _IO%s%s('%c', %lu)\n",
266 device_xname(&sc->sc_dv),
267 (cmd & IOC_IN) ? "W" : "", (cmd & IOC_OUT) ? "R" : "",
268 (char)IOCGROUP(cmd), cmd & 0xff);
269 #endif
271 switch (cmd) {
272 case FBIOGTYPE:
273 *(struct fbtype *)data = sc->sc_fb.fb_type;
274 break;
275 case FBIOGATTR:
276 #define fba ((struct fbgattr *)data)
277 fba->real_type = sc->sc_fb.fb_type.fb_type;
278 fba->owner = 0; /* XXX ??? */
279 fba->fbtype = sc->sc_fb.fb_type;
280 fba->sattr.flags = 0;
281 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
282 fba->sattr.dev_specific[0] = -1;
283 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
284 fba->emu_types[1] = -1;
285 #undef fba
286 break;
288 case FBIOGETCMAP:
289 case FBIOPUTCMAP:
290 return EIO;
292 case FBIOGVIDEO:
293 case FBIOSVIDEO:
294 return ffb_blank(sc, cmd == FBIOGVIDEO?
295 WSDISPLAYIO_GVIDEO : WSDISPLAYIO_SVIDEO,
296 (u_int *)data);
297 break;
298 case FBIOGCURSOR:
299 case FBIOSCURSOR:
300 /* the console driver is not using the hardware cursor */
301 break;
302 case FBIOGCURPOS:
303 printf("%s: FBIOGCURPOS not implemented\n", device_xname(&sc->sc_dv));
304 return EIO;
305 case FBIOSCURPOS:
306 printf("%s: FBIOSCURPOS not implemented\n", device_xname(&sc->sc_dv));
307 return EIO;
308 case FBIOGCURMAX:
309 printf("%s: FBIOGCURMAX not implemented\n", device_xname(&sc->sc_dv));
310 return EIO;
312 case WSDISPLAYIO_GTYPE:
313 *(u_int *)data = WSDISPLAY_TYPE_SUNFFB;
314 break;
315 case WSDISPLAYIO_SMODE:
317 if (sc->sc_mode != *(u_int *)data) {
318 sc->sc_mode = *(u_int *)data;
319 if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) &&
320 (sc->sc_locked == 0)) {
321 ffb_ras_init(sc);
322 vcons_redraw_screen(ms);
326 break;
327 case WSDISPLAYIO_GINFO:
328 wdf = (void *)data;
329 wdf->height = sc->sc_height;
330 wdf->width = sc->sc_width;
331 wdf->depth = 32;
332 wdf->cmsize = 256; /* XXX */
333 break;
334 #ifdef WSDISPLAYIO_LINEBYTES
335 case WSDISPLAYIO_LINEBYTES:
336 *(u_int *)data = sc->sc_linebytes;
337 break;
338 #endif
339 case WSDISPLAYIO_GETCMAP:
340 break;/* XXX */
342 case WSDISPLAYIO_PUTCMAP:
343 break;/* XXX */
345 case WSDISPLAYIO_SVIDEO:
346 case WSDISPLAYIO_GVIDEO:
347 return(ffb_blank(sc, cmd, (u_int *)data));
348 break;
349 case WSDISPLAYIO_GCURPOS:
350 case WSDISPLAYIO_SCURPOS:
351 case WSDISPLAYIO_GCURMAX:
352 case WSDISPLAYIO_GCURSOR:
353 case WSDISPLAYIO_SCURSOR:
354 return EIO; /* not supported yet */
355 default:
356 return EPASSTHROUGH;
359 return (0);
362 /* blank/unblank the screen */
363 static int
364 ffb_blank(struct ffb_softc *sc, u_long cmd, u_int *data)
366 struct vcons_screen *ms = sc->vd.active;
367 u_int val;
369 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
370 val = DAC_READ(sc, FFB_DAC_VALUE);
372 switch (cmd) {
373 case WSDISPLAYIO_GVIDEO:
374 *data = val & 1;
375 return(0);
376 break;
377 case WSDISPLAYIO_SVIDEO:
378 if (*data == WSDISPLAYIO_VIDEO_OFF)
379 val &= ~1;
380 else if (*data == WSDISPLAYIO_VIDEO_ON)
381 val |= 1;
382 else
383 return(EINVAL);
384 break;
385 default:
386 return(EINVAL);
389 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
390 DAC_WRITE(sc, FFB_DAC_VALUE, val);
392 if ((val & 1) && sc->sc_needredraw) {
393 if (ms != NULL) {
394 if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) &&
395 (sc->sc_locked == 0)) {
396 ffb_ras_init(sc);
397 vcons_redraw_screen(ms);
402 return(0);
405 paddr_t
406 ffb_mmap(void *vsc, void *vs, off_t off, int prot)
408 struct vcons_data *vd = vsc;
409 struct ffb_softc *sc = vd->cookie;
410 int i;
412 switch (sc->sc_mode) {
413 case WSDISPLAYIO_MODE_MAPPED:
414 for (i = 0; i < sc->sc_nreg; i++) {
415 /* Before this set? */
416 if (off < sc->sc_addrs[i])
417 continue;
418 /* After this set? */
419 if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i]))
420 continue;
422 return (bus_space_mmap(sc->sc_bt, sc->sc_addrs[i],
423 off - sc->sc_addrs[i], prot, BUS_SPACE_MAP_LINEAR));
425 break;
426 #ifdef WSDISPLAYIO_MODE_DUMBFB
427 case WSDISPLAYIO_MODE_DUMBFB:
428 if (sc->sc_nreg < FFB_REG_DFB24)
429 break;
430 if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24])
431 return (bus_space_mmap(sc->sc_bt,
432 sc->sc_addrs[FFB_REG_DFB24], off, prot,
433 BUS_SPACE_MAP_LINEAR));
434 break;
435 #endif
437 return (-1);
440 void
441 ffb_ras_fifo_wait(struct ffb_softc *sc, int n)
443 int32_t cache = sc->sc_fifo_cache;
445 if (cache < n) {
446 do {
447 cache = FBC_READ(sc, FFB_FBC_UCSR);
448 cache = (cache & FBC_UCSR_FIFO_MASK) - 8;
449 } while (cache < n);
451 sc->sc_fifo_cache = cache - n;
454 void
455 ffb_ras_wait(struct ffb_softc *sc)
457 uint32_t ucsr, r;
459 while (1) {
460 ucsr = FBC_READ(sc, FFB_FBC_UCSR);
461 if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0)
462 break;
463 r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL);
464 if (r != 0)
465 FBC_WRITE(sc, FFB_FBC_UCSR, r);
469 void
470 ffb_ras_init(struct ffb_softc *sc)
472 ffb_ras_fifo_wait(sc, 7);
473 FBC_WRITE(sc, FFB_FBC_PPC,
474 FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE |
475 FBC_PPC_APE_DIS | FBC_PPC_CS_CONST);
476 FBC_WRITE(sc, FFB_FBC_FBC,
477 FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH |
478 FFB_FBC_XE_OFF | FFB_FBC_RGBE_MASK);
479 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
480 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
481 FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff);
482 FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000);
483 sc->sc_fg_cache = 0;
484 FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache);
485 ffb_ras_wait(sc);
488 void
489 ffb_ras_eraserows(void *cookie, int row, int n, long attr)
491 struct rasops_info *ri = cookie;
492 struct vcons_screen *scr = ri->ri_hw;
493 struct ffb_softc *sc = scr->scr_cookie;
495 if (row < 0) {
496 n += row;
497 row = 0;
499 if (row + n > ri->ri_rows)
500 n = ri->ri_rows - row;
501 if (n <= 0)
502 return;
504 ffb_ras_fill(sc);
505 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]);
506 ffb_ras_fifo_wait(sc, 4);
507 if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
508 FBC_WRITE(sc, FFB_FBC_BY, 0);
509 FBC_WRITE(sc, FFB_FBC_BX, 0);
510 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height);
511 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width);
512 } else {
513 row *= ri->ri_font->fontheight;
514 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
515 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
516 FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight);
517 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
519 ffb_ras_wait(sc);
522 void
523 ffb_ras_erasecols(void *cookie, int row, int col, int n, long attr)
525 struct rasops_info *ri = cookie;
526 struct vcons_screen *scr = ri->ri_hw;
527 struct ffb_softc *sc = scr->scr_cookie;
529 if ((row < 0) || (row >= ri->ri_rows))
530 return;
531 if (col < 0) {
532 n += col;
533 col = 0;
535 if (col + n > ri->ri_cols)
536 n = ri->ri_cols - col;
537 if (n <= 0)
538 return;
539 n *= ri->ri_font->fontwidth;
540 col *= ri->ri_font->fontwidth;
541 row *= ri->ri_font->fontheight;
543 ffb_ras_fill(sc);
544 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]);
545 ffb_ras_fifo_wait(sc, 4);
546 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
547 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col);
548 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight);
549 FBC_WRITE(sc, FFB_FBC_BW, n - 1);
550 ffb_ras_wait(sc);
553 void
554 ffb_ras_fill(struct ffb_softc *sc)
556 ffb_ras_fifo_wait(sc, 2);
557 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
558 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
559 ffb_ras_wait(sc);
562 void
563 ffb_ras_copyrows(void *cookie, int src, int dst, int n)
565 struct rasops_info *ri = cookie;
566 struct vcons_screen *scr = ri->ri_hw;
567 struct ffb_softc *sc = scr->scr_cookie;
569 if (dst == src)
570 return;
571 if (src < 0) {
572 n += src;
573 src = 0;
575 if ((src + n) > ri->ri_rows)
576 n = ri->ri_rows - src;
577 if (dst < 0) {
578 n += dst;
579 dst = 0;
581 if ((dst + n) > ri->ri_rows)
582 n = ri->ri_rows - dst;
583 if (n <= 0)
584 return;
585 n *= ri->ri_font->fontheight;
586 src *= ri->ri_font->fontheight;
587 dst *= ri->ri_font->fontheight;
589 ffb_ras_fifo_wait(sc, 8);
590 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_OLD | (FBC_ROP_OLD << 8));
591 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_VSCROLL);
592 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + src);
593 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
594 FBC_WRITE(sc, FFB_FBC_DY, ri->ri_yorigin + dst);
595 FBC_WRITE(sc, FFB_FBC_DX, ri->ri_xorigin);
596 FBC_WRITE(sc, FFB_FBC_BH, n);
597 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
598 ffb_ras_wait(sc);
601 void
602 ffb_ras_setfg(struct ffb_softc *sc, int32_t fg)
604 ffb_ras_fifo_wait(sc, 1);
605 if (fg == sc->sc_fg_cache)
606 return;
607 sc->sc_fg_cache = fg;
608 FBC_WRITE(sc, FFB_FBC_FG, fg);
609 ffb_ras_wait(sc);
612 /* frame buffer generic driver support functions */
613 static void
614 ffbfb_unblank(struct device *dev)
616 struct ffb_softc *sc = device_private(dev);
617 struct vcons_screen *ms = sc->vd.active;
618 u_int on = 1;
619 int redraw = 0;
621 ffb_ras_init(sc);
622 if (sc->sc_locked) {
623 sc->sc_locked = 0;
624 redraw = 1;
627 ffb_blank(sc, WSDISPLAYIO_SVIDEO, &on);
628 #if 0
629 if ((sc->vd.active != &ffb_console_screen) &&
630 (ffb_console_screen.scr_flags & VCONS_SCREEN_IS_STATIC)) {
632 * force-switch to the console screen.
633 * Caveat: the higher layer will think we're still on the
634 * other screen
637 SCREEN_INVISIBLE(sc->vd.active);
638 sc->vd.active = &ffb_console_screen;
639 SCREEN_VISIBLE(sc->vd.active);
640 ms = sc->vd.active;
641 redraw = 1;
643 #endif
644 if (redraw) {
645 vcons_redraw_screen(ms);
650 ffbfb_open(dev_t dev, int flags, int mode, struct lwp *l)
652 struct ffb_softc *sc;
654 sc = device_lookup_private(&ffb_cd, minor(dev));
655 if (sc == NULL)
656 return ENXIO;
658 sc->sc_locked = 1;
659 return 0;
663 ffbfb_close(dev_t dev, int flags, int mode, struct lwp *l)
665 struct ffb_softc *sc = device_lookup_private(&ffb_cd, minor(dev));
666 struct vcons_screen *ms = sc->vd.active;
668 sc->sc_locked = 0;
669 if (ms != NULL) {
670 if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) &&
671 (sc->sc_locked == 0)) {
672 ffb_ras_init(sc);
673 vcons_redraw_screen(ms);
676 return 0;
680 ffbfb_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
682 struct ffb_softc *sc = device_lookup_private(&ffb_cd, minor(dev));
684 return ffb_ioctl(&sc->vd, NULL, cmd, data, flags, l);
687 paddr_t
688 ffbfb_mmap(dev_t dev, off_t off, int prot)
690 struct ffb_softc *sc = device_lookup_private(&ffb_cd, minor(dev));
691 uint64_t size;
692 int i, reg;
693 off_t o;
696 * off is a magic cookie (see xfree86/drivers/sunffb/ffb.h),
697 * which we map to an index into the "reg" property, and use
698 * our copy of the firmware data as arguments for the real
699 * mapping.
701 static struct { unsigned long voff; int reg; } map[] = {
702 { 0x00000000, FFB_REG_SFB8R },
703 { 0x00400000, FFB_REG_SFB8G },
704 { 0x00800000, FFB_REG_SFB8B },
705 { 0x00c00000, FFB_REG_SFB8X },
706 { 0x01000000, FFB_REG_SFB32 },
707 { 0x02000000, FFB_REG_SFB64 },
708 { 0x04000000, FFB_REG_FBC },
709 { 0x04004000, FFB_REG_DFB8R },
710 { 0x04404000, FFB_REG_DFB8G },
711 { 0x04804000, FFB_REG_DFB8B },
712 { 0x04c04000, FFB_REG_DFB8X },
713 { 0x05004000, FFB_REG_DFB24 },
714 { 0x06004000, FFB_REG_DFB32 },
715 { 0x07004000, FFB_REG_DFB422A },
716 { 0x0bc06000, FFB_REG_DAC },
717 { 0x0bc08000, FFB_REG_PROM },
718 { 0x0bc18000, 0 }
721 /* special value "FFB_EXP_VOFF" - not backed by any "reg" entry */
722 if (off == 0x0bc18000)
723 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM],
724 0x00200000, prot, BUS_SPACE_MAP_LINEAR);
727 * FFB_VOFF_FBC_KREGS - used by afbinit to upload firmware. We should
728 * probably mmap them only on afb boards
730 if ((off >= 0x0bc04000) && (off < 0x0bc06000))
731 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM],
732 0x00610000 + (off - 0x0bc04000), prot,
733 BUS_SPACE_MAP_LINEAR);
735 #define NELEMS(arr) (sizeof(arr)/sizeof((arr)[0]))
737 /* the map is ordered by voff */
738 for (i = 0; i < NELEMS(map)-1; i++) {
739 reg = map[i].reg;
740 /* the number of entries in reg seems to vary */
741 if (reg < sc->sc_nreg) {
742 size = min((map[i + 1].voff - map[i].voff),
743 sc->sc_sizes[reg]);
744 if ((off >= map[i].voff) &&
745 (off < (map[i].voff + size))) {
746 o = off - map[i].voff;
747 return bus_space_mmap(sc->sc_bt,
748 sc->sc_addrs[reg], o, prot,
749 BUS_SPACE_MAP_LINEAR);
754 return -1;
757 void
758 ffb_clearscreen(struct ffb_softc *sc)
760 struct rasops_info *ri = &ffb_console_screen.scr_ri;
761 ffb_ras_fill(sc);
762 ffb_ras_setfg(sc, ri->ri_devcmap[WS_DEFAULT_BG]);
763 ffb_ras_fifo_wait(sc, 4);
764 FBC_WRITE(sc, FFB_FBC_BY, 0);
765 FBC_WRITE(sc, FFB_FBC_BX, 0);
766 FBC_WRITE(sc, FFB_FBC_BH, sc->sc_height);
767 FBC_WRITE(sc, FFB_FBC_BW, sc->sc_width);
770 void
771 ffb_cursor(void *cookie, int on, int row, int col)
773 struct rasops_info *ri = cookie;
774 struct vcons_screen *scr;
775 struct ffb_softc *sc;
776 int x, y, wi, he, coffset;
778 if (cookie != NULL) {
779 scr = ri->ri_hw;
780 sc = scr->scr_cookie;
782 wi = ri->ri_font->fontwidth;
783 he = ri->ri_font->fontheight;
785 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
786 x = ri->ri_ccol * wi + ri->ri_xorigin;
787 y = ri->ri_crow * he + ri->ri_yorigin;
789 if (ri->ri_flg & RI_CURSOR) {
790 /* remove cursor */
791 coffset = ri->ri_ccol + (ri->ri_crow *
792 ri->ri_cols);
793 #ifdef WSDISPLAY_SCROLLSUPPORT
794 coffset += scr->scr_offset_to_zero;
795 #endif
796 ffb_ras_wait(sc);
797 sc->putchar(cookie, ri->ri_crow,
798 ri->ri_ccol, scr->scr_chars[coffset],
799 scr->scr_attrs[coffset]);
800 ri->ri_flg &= ~RI_CURSOR;
802 ri->ri_crow = row;
803 ri->ri_ccol = col;
804 if (on)
806 long attr, revattr;
807 x = ri->ri_ccol * wi + ri->ri_xorigin;
808 y = ri->ri_crow * he + ri->ri_yorigin;
809 coffset = col + (row * ri->ri_cols);
810 #ifdef WSDISPLAY_SCROLLSUPPORT
811 coffset += scr->scr_offset_to_zero;
812 #endif
813 attr = scr->scr_attrs[coffset];
814 #ifdef FFB_CURSOR_SWAP_COLOURS
815 revattr=((attr >> 8 ) & 0x000f0000) | ((attr &
816 0x000f0000)<<8) | (attr & 0x0000ffff);
817 #else
818 revattr = attr ^ 0xffff0000;
819 #endif
820 ffb_ras_wait(sc);
821 sc->putchar(cookie, ri->ri_crow, ri->ri_ccol,
822 scr->scr_chars[coffset], revattr);
823 ri->ri_flg |= RI_CURSOR;
825 } else {
826 ri->ri_crow = row;
827 ri->ri_ccol = col;
828 ri->ri_flg &= ~RI_CURSOR;
833 void
834 ffb_putchar(void *cookie, int row, int col, u_int c, long attr)
836 struct rasops_info *ri = cookie;
837 struct vcons_screen *scr = ri->ri_hw;
838 struct ffb_softc *sc = scr->scr_cookie;
840 if (sc->putchar != NULL) {
842 * the only reason why we need to hook putchar - wait for
843 * the drawing engine to be idle so we don't interfere
844 * ( and we should really use the colour expansion hardware )
846 ffb_ras_wait(sc);
847 sc->putchar(cookie, row, col, c, attr);
852 ffb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
854 if ((fg == 0) && (bg == 0))
856 fg = WS_DEFAULT_FG;
857 bg = WS_DEFAULT_BG;
859 if (flags & WSATTR_REVERSE) {
860 *attrp = (bg & 0xff) << 24 | (fg & 0xff) << 16 |
861 (flags & 0xff);
862 } else
863 *attrp = (fg & 0xff) << 24 | (bg & 0xff) << 16 |
864 (flags & 0xff);
865 return 0;
868 void
869 ffb_init_screen(void *cookie, struct vcons_screen *scr,
870 int existing, long *defattr)
872 struct ffb_softc *sc = cookie;
873 struct rasops_info *ri = &scr->scr_ri;
875 ri->ri_depth = 32;
876 ri->ri_width = sc->sc_width;
877 ri->ri_height = sc->sc_height;
878 ri->ri_stride = sc->sc_linebytes;
879 ri->ri_flg = RI_CENTER;
881 ri->ri_bits = bus_space_vaddr(sc->sc_bt, sc->sc_pixel_h);
883 #ifdef FFBDEBUG
884 printf("addr: %08lx\n",(ulong)ri->ri_bits);
885 #endif
886 rasops_init(ri, sc->sc_height/8, sc->sc_width/8);
887 ri->ri_caps = WSSCREEN_WSCOLORS;
888 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
889 sc->sc_width / ri->ri_font->fontwidth);
891 /* enable acceleration */
892 ri->ri_ops.copyrows = ffb_ras_copyrows;
893 ri->ri_ops.eraserows = ffb_ras_eraserows;
894 ri->ri_ops.erasecols = ffb_ras_erasecols;
895 ri->ri_ops.cursor = ffb_cursor;
896 ri->ri_ops.allocattr = ffb_allocattr;
897 if (sc->putchar == NULL)
898 sc->putchar = ri->ri_ops.putchar;
899 ri->ri_ops.putchar = ffb_putchar;