ffb.c revision 1.33 1 /* $NetBSD: ffb.c,v 1.33 2008/04/05 13:40:05 cegger Exp $ */
2 /* $OpenBSD: creator.c,v 1.20 2002/07/30 19:48:15 jason Exp $ */
3
4 /*
5 * Copyright (c) 2002 Jason L. Wright (jason (at) thought.net)
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 * 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.
21 *
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.
33 */
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: ffb.c,v 1.33 2008/04/05 13:40:05 cegger Exp $");
37
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>
47
48 #include <machine/bus.h>
49 #include <machine/autoconf.h>
50 #include <machine/openfirm.h>
51 #include <machine/vmparam.h>
52
53 #include <dev/wscons/wsconsio.h>
54 #include <dev/sun/fbio.h>
55 #include <dev/sun/fbvar.h>
56
57 #include <dev/wsfont/wsfont.h>
58 #include <dev/wscons/wsdisplay_vconsvar.h>
59
60 #include <sparc64/dev/ffbreg.h>
61 #include <sparc64/dev/ffbvar.h>
62
63 #ifndef WS_DEFAULT_BG
64 /* Sun -> background should be white */
65 #define WS_DEFAULT_BG 0xf
66 #endif
67
68 extern struct cfdriver ffb_cd;
69
70 struct wsscreen_descr ffb_stdscreen = {
71 "sunffb",
72 0, 0, /* will be filled in -- XXX shouldn't, it's global. */
73 0,
74 0, 0,
75 WSSCREEN_REVERSE | WSSCREEN_WSCOLORS,
76 NULL /* modecookie */
77 };
78
79 const struct wsscreen_descr *ffb_scrlist[] = {
80 &ffb_stdscreen,
81 /* XXX other formats? */
82 };
83
84 struct wsscreen_list ffb_screenlist = {
85 sizeof(ffb_scrlist) / sizeof(struct wsscreen_descr *),
86 ffb_scrlist
87 };
88
89 static struct vcons_screen ffb_console_screen;
90
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);
103
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);
111
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);
118
119 static struct fbdriver ffb_fbdriver = {
120 ffbfb_unblank, ffbfb_open, ffbfb_close, ffbfb_ioctl, nopoll,
121 ffbfb_mmap, nokqfilter
122 };
123
124 struct wsdisplay_accessops ffb_accessops = {
125 .ioctl = ffb_ioctl,
126 .mmap = ffb_mmap,
127 };
128
129 void
130 ffb_attach(struct ffb_softc *sc)
131 {
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];
141
142 printf(":");
143
144 sc->putchar = NULL;
145
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");
154
155 model = prom_getpropstring(sc->sc_node, "model");
156 if (model == NULL || strlen(model) == 0)
157 model = "unknown";
158
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);
163
164 sc->sc_locked = 0;
165 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
166
167 maxcol = (prom_getoption("screen-#columns", buf, sizeof buf) == 0)
168 ? strtoul(buf, NULL, 10)
169 : 80;
170
171 maxrow = (prom_getoption("screen-#rows", buf, sizeof buf) != 0)
172 ? strtoul(buf, NULL, 10)
173 : 34;
174
175 ffb_ras_init(sc);
176
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;
181
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;
192 }
193 }
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));
198
199 ffb_blank(sc, WSDISPLAYIO_SVIDEO, &blank);
200
201 sc->sc_accel = ((device_cfdata(&sc->sc_dv)->cf_flags &
202 FFB_CFFLAG_NOACCEL) == 0);
203
204 wsfont_init();
205
206 vcons_init(&sc->vd, sc, &ffb_stdscreen, &ffb_accessops);
207 sc->vd.init_screen = ffb_init_screen;
208
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));
213 /*
214 * XXX we shouldn't use a global variable for the console
215 * screen
216 */
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);
223 }
224 }
225 ri = &ffb_console_screen.scr_ri;
226
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;
231
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);
241
242 if (sc->sc_console) {
243 wsdisplay_cnattach(&ffb_stdscreen, ri, 0, 0, defattr);
244 }
245
246 ffb_clearscreen(sc);
247
248 waa.console = sc->sc_console;
249 waa.scrdata = &ffb_screenlist;
250 waa.accessops = &ffb_accessops;
251 waa.accesscookie = &sc->vd;
252 config_found(&sc->sc_dv, &waa, wsemuldisplaydevprint);
253 }
254
255 int
256 ffb_ioctl(void *v, void *vs, u_long cmd, void *data, int flags, struct lwp *l)
257 {
258 struct vcons_data *vd = v;
259 struct ffb_softc *sc = vd->cookie;
260 struct wsdisplay_fbinfo *wdf;
261 struct vcons_screen *ms = vd->active;
262
263 #ifdef FFBDEBUG
264 printf("ffb_ioctl: %s cmd _IO%s%s('%c', %lu)\n",
265 device_xname(&sc->sc_dv),
266 (cmd & IOC_IN) ? "W" : "", (cmd & IOC_OUT) ? "R" : "",
267 (char)IOCGROUP(cmd), cmd & 0xff);
268 #endif
269
270 switch (cmd) {
271 case FBIOGTYPE:
272 *(struct fbtype *)data = sc->sc_fb.fb_type;
273 break;
274 case FBIOGATTR:
275 #define fba ((struct fbgattr *)data)
276 fba->real_type = sc->sc_fb.fb_type.fb_type;
277 fba->owner = 0; /* XXX ??? */
278 fba->fbtype = sc->sc_fb.fb_type;
279 fba->sattr.flags = 0;
280 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
281 fba->sattr.dev_specific[0] = -1;
282 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
283 fba->emu_types[1] = -1;
284 #undef fba
285 break;
286
287 case FBIOGETCMAP:
288 case FBIOPUTCMAP:
289 return EIO;
290
291 case FBIOGVIDEO:
292 case FBIOSVIDEO:
293 return ffb_blank(sc, cmd == FBIOGVIDEO?
294 WSDISPLAYIO_GVIDEO : WSDISPLAYIO_SVIDEO,
295 (u_int *)data);
296 break;
297 case FBIOGCURSOR:
298 case FBIOSCURSOR:
299 /* the console driver is not using the hardware cursor */
300 break;
301 case FBIOGCURPOS:
302 printf("%s: FBIOGCURPOS not implemented\n", device_xname(&sc->sc_dv));
303 return EIO;
304 case FBIOSCURPOS:
305 printf("%s: FBIOSCURPOS not implemented\n", device_xname(&sc->sc_dv));
306 return EIO;
307 case FBIOGCURMAX:
308 printf("%s: FBIOGCURMAX not implemented\n", device_xname(&sc->sc_dv));
309 return EIO;
310
311 case WSDISPLAYIO_GTYPE:
312 *(u_int *)data = WSDISPLAY_TYPE_SUNFFB;
313 break;
314 case WSDISPLAYIO_SMODE:
315 {
316 if (sc->sc_mode != *(u_int *)data) {
317 sc->sc_mode = *(u_int *)data;
318 if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) &&
319 (sc->sc_locked == 0)) {
320 ffb_ras_init(sc);
321 vcons_redraw_screen(ms);
322 }
323 }
324 }
325 break;
326 case WSDISPLAYIO_GINFO:
327 wdf = (void *)data;
328 wdf->height = sc->sc_height;
329 wdf->width = sc->sc_width;
330 wdf->depth = 32;
331 wdf->cmsize = 256; /* XXX */
332 break;
333 #ifdef WSDISPLAYIO_LINEBYTES
334 case WSDISPLAYIO_LINEBYTES:
335 *(u_int *)data = sc->sc_linebytes;
336 break;
337 #endif
338 case WSDISPLAYIO_GETCMAP:
339 break;/* XXX */
340
341 case WSDISPLAYIO_PUTCMAP:
342 break;/* XXX */
343
344 case WSDISPLAYIO_SVIDEO:
345 case WSDISPLAYIO_GVIDEO:
346 return(ffb_blank(sc, cmd, (u_int *)data));
347 break;
348 case WSDISPLAYIO_GCURPOS:
349 case WSDISPLAYIO_SCURPOS:
350 case WSDISPLAYIO_GCURMAX:
351 case WSDISPLAYIO_GCURSOR:
352 case WSDISPLAYIO_SCURSOR:
353 return EIO; /* not supported yet */
354 default:
355 return EPASSTHROUGH;
356 }
357
358 return (0);
359 }
360
361 /* blank/unblank the screen */
362 static int
363 ffb_blank(struct ffb_softc *sc, u_long cmd, u_int *data)
364 {
365 struct vcons_screen *ms = sc->vd.active;
366 u_int val;
367
368 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
369 val = DAC_READ(sc, FFB_DAC_VALUE);
370
371 switch (cmd) {
372 case WSDISPLAYIO_GVIDEO:
373 *data = val & 1;
374 return(0);
375 break;
376 case WSDISPLAYIO_SVIDEO:
377 if (*data == WSDISPLAYIO_VIDEO_OFF)
378 val &= ~1;
379 else if (*data == WSDISPLAYIO_VIDEO_ON)
380 val |= 1;
381 else
382 return(EINVAL);
383 break;
384 default:
385 return(EINVAL);
386 }
387
388 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
389 DAC_WRITE(sc, FFB_DAC_VALUE, val);
390
391 if ((val & 1) && sc->sc_needredraw) {
392 if (ms != NULL) {
393 if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) &&
394 (sc->sc_locked == 0)) {
395 ffb_ras_init(sc);
396 vcons_redraw_screen(ms);
397 }
398 }
399 }
400
401 return(0);
402 }
403
404 paddr_t
405 ffb_mmap(void *vsc, void *vs, off_t off, int prot)
406 {
407 struct vcons_data *vd = vsc;
408 struct ffb_softc *sc = vd->cookie;
409 int i;
410
411 switch (sc->sc_mode) {
412 case WSDISPLAYIO_MODE_MAPPED:
413 for (i = 0; i < sc->sc_nreg; i++) {
414 /* Before this set? */
415 if (off < sc->sc_addrs[i])
416 continue;
417 /* After this set? */
418 if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i]))
419 continue;
420
421 return (bus_space_mmap(sc->sc_bt, sc->sc_addrs[i],
422 off - sc->sc_addrs[i], prot, BUS_SPACE_MAP_LINEAR));
423 }
424 break;
425 #ifdef WSDISPLAYIO_MODE_DUMBFB
426 case WSDISPLAYIO_MODE_DUMBFB:
427 if (sc->sc_nreg < FFB_REG_DFB24)
428 break;
429 if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24])
430 return (bus_space_mmap(sc->sc_bt,
431 sc->sc_addrs[FFB_REG_DFB24], off, prot,
432 BUS_SPACE_MAP_LINEAR));
433 break;
434 #endif
435 }
436
437 return (-1);
438 }
439
440 void
441 ffb_ras_fifo_wait(struct ffb_softc *sc, int n)
442 {
443 int32_t cache = sc->sc_fifo_cache;
444
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);
450 }
451 sc->sc_fifo_cache = cache - n;
452 }
453
454 void
455 ffb_ras_wait(struct ffb_softc *sc)
456 {
457 uint32_t ucsr, r;
458
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);
466 }
467 }
468
469 void
470 ffb_ras_init(struct ffb_softc *sc)
471 {
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);
486 }
487
488 void
489 ffb_ras_eraserows(void *cookie, int row, int n, long attr)
490 {
491 struct rasops_info *ri = cookie;
492 struct vcons_screen *scr = ri->ri_hw;
493 struct ffb_softc *sc = scr->scr_cookie;
494
495 if (row < 0) {
496 n += row;
497 row = 0;
498 }
499 if (row + n > ri->ri_rows)
500 n = ri->ri_rows - row;
501 if (n <= 0)
502 return;
503
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);
518 }
519 ffb_ras_wait(sc);
520 }
521
522 void
523 ffb_ras_erasecols(void *cookie, int row, int col, int n, long attr)
524 {
525 struct rasops_info *ri = cookie;
526 struct vcons_screen *scr = ri->ri_hw;
527 struct ffb_softc *sc = scr->scr_cookie;
528
529 if ((row < 0) || (row >= ri->ri_rows))
530 return;
531 if (col < 0) {
532 n += col;
533 col = 0;
534 }
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;
542
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);
551 }
552
553 void
554 ffb_ras_fill(struct ffb_softc *sc)
555 {
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);
560 }
561
562 void
563 ffb_ras_copyrows(void *cookie, int src, int dst, int n)
564 {
565 struct rasops_info *ri = cookie;
566 struct vcons_screen *scr = ri->ri_hw;
567 struct ffb_softc *sc = scr->scr_cookie;
568
569 if (dst == src)
570 return;
571 if (src < 0) {
572 n += src;
573 src = 0;
574 }
575 if ((src + n) > ri->ri_rows)
576 n = ri->ri_rows - src;
577 if (dst < 0) {
578 n += dst;
579 dst = 0;
580 }
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;
588
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);
599 }
600
601 void
602 ffb_ras_setfg(struct ffb_softc *sc, int32_t fg)
603 {
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);
610 }
611
612 /* frame buffer generic driver support functions */
613 static void
614 ffbfb_unblank(struct device *dev)
615 {
616 struct ffb_softc *sc = (struct ffb_softc *)dev;
617 struct vcons_screen *ms = sc->vd.active;
618 u_int on = 1;
619 int redraw = 0;
620
621 ffb_ras_init(sc);
622 if (sc->sc_locked) {
623 sc->sc_locked = 0;
624 redraw = 1;
625 }
626
627 ffb_blank((struct ffb_softc*)dev, WSDISPLAYIO_SVIDEO, &on);
628 if ((sc->vd.active != &ffb_console_screen) &&
629 (ffb_console_screen.scr_flags & VCONS_SCREEN_IS_STATIC)) {
630 /*
631 * force-switch to the console screen.
632 * Caveat: the higher layer will think we're still on the
633 * other screen
634 */
635
636 SCREEN_INVISIBLE(sc->vd.active);
637 sc->vd.active = &ffb_console_screen;
638 SCREEN_VISIBLE(sc->vd.active);
639 ms = sc->vd.active;
640 redraw = 1;
641 }
642
643 if (redraw) {
644 vcons_redraw_screen(ms);
645 }
646 }
647
648 int
649 ffbfb_open(dev_t dev, int flags, int mode, struct lwp *l)
650 {
651 struct ffb_softc *sc;
652 int unit = minor(dev);
653
654 sc = ffb_cd.cd_devs[unit];
655 if (unit >= ffb_cd.cd_ndevs || ffb_cd.cd_devs[unit] == NULL)
656 return ENXIO;
657
658 sc->sc_locked = 1;
659 return 0;
660 }
661
662 int
663 ffbfb_close(dev_t dev, int flags, int mode, struct lwp *l)
664 {
665 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)];
666 struct vcons_screen *ms = sc->vd.active;
667
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);
674 }
675 }
676 return 0;
677 }
678
679 int
680 ffbfb_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
681 {
682 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)];
683
684 return ffb_ioctl(&sc->vd, NULL, cmd, data, flags, l);
685 }
686
687 paddr_t
688 ffbfb_mmap(dev_t dev, off_t off, int prot)
689 {
690 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)];
691 uint64_t size;
692 int i, reg;
693 off_t o;
694
695 /*
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.
700 */
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 }
719 };
720
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);
725
726 /*
727 * FFB_VOFF_FBC_KREGS - used by afbinit to upload firmware. We should
728 * probably mmap them only on afb boards
729 */
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);
734
735 #define NELEMS(arr) (sizeof(arr)/sizeof((arr)[0]))
736
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);
750 }
751 }
752 }
753
754 return -1;
755 }
756
757 void
758 ffb_clearscreen(struct ffb_softc *sc)
759 {
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);
768 }
769
770 void
771 ffb_cursor(void *cookie, int on, int row, int col)
772 {
773 struct rasops_info *ri = cookie;
774 struct vcons_screen *scr;
775 struct ffb_softc *sc;
776 int x, y, wi, he, coffset;
777
778 if (cookie != NULL) {
779 scr = ri->ri_hw;
780 sc = scr->scr_cookie;
781
782 wi = ri->ri_font->fontwidth;
783 he = ri->ri_font->fontheight;
784
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;
788
789 if (ri->ri_flg & RI_CURSOR) {
790 /* remove cursor */
791 coffset = ri->ri_ccol + (ri->ri_crow *
792 ri->ri_cols);
793 ffb_ras_wait(sc);
794 sc->putchar(cookie, ri->ri_crow,
795 ri->ri_ccol, scr->scr_chars[coffset],
796 scr->scr_attrs[coffset]);
797 ri->ri_flg &= ~RI_CURSOR;
798 }
799 ri->ri_crow = row;
800 ri->ri_ccol = col;
801 if (on)
802 {
803 long attr, revattr;
804 x = ri->ri_ccol * wi + ri->ri_xorigin;
805 y = ri->ri_crow * he + ri->ri_yorigin;
806 coffset = col + (row * ri->ri_cols);
807 attr = scr->scr_attrs[coffset];
808 #ifdef FFB_CURSOR_SWAP_COLOURS
809 revattr=((attr >> 8 ) & 0x000f0000) | ((attr &
810 0x000f0000)<<8) | (attr & 0x0000ffff);
811 #else
812 revattr = attr ^ 0xffff0000;
813 #endif
814 ffb_ras_wait(sc);
815 sc->putchar(cookie, ri->ri_crow, ri->ri_ccol,
816 scr->scr_chars[coffset], revattr);
817 ri->ri_flg |= RI_CURSOR;
818 }
819 } else {
820 ri->ri_crow = row;
821 ri->ri_ccol = col;
822 ri->ri_flg &= ~RI_CURSOR;
823 }
824 }
825 }
826
827 void
828 ffb_putchar(void *cookie, int row, int col, u_int c, long attr)
829 {
830 struct rasops_info *ri = cookie;
831 struct vcons_screen *scr = ri->ri_hw;
832 struct ffb_softc *sc = scr->scr_cookie;
833
834 if (sc->putchar != NULL) {
835 /*
836 * the only reason why we need to hook putchar - wait for
837 * the drawing engine to be idle so we don't interfere
838 * ( and we should really use the colour expansion hardware )
839 */
840 ffb_ras_wait(sc);
841 sc->putchar(cookie, row, col, c, attr);
842 }
843 }
844
845 int
846 ffb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
847 {
848 if ((fg == 0) && (bg == 0))
849 {
850 fg = WS_DEFAULT_FG;
851 bg = WS_DEFAULT_BG;
852 }
853 if (flags & WSATTR_REVERSE) {
854 *attrp = (bg & 0xff) << 24 | (fg & 0xff) << 16 |
855 (flags & 0xff);
856 } else
857 *attrp = (fg & 0xff) << 24 | (bg & 0xff) << 16 |
858 (flags & 0xff);
859 return 0;
860 }
861
862 void
863 ffb_init_screen(void *cookie, struct vcons_screen *scr,
864 int existing, long *defattr)
865 {
866 struct ffb_softc *sc = cookie;
867 struct rasops_info *ri = &scr->scr_ri;
868
869 ri->ri_depth = 32;
870 ri->ri_width = sc->sc_width;
871 ri->ri_height = sc->sc_height;
872 ri->ri_stride = sc->sc_linebytes;
873 ri->ri_flg = RI_CENTER;
874
875 ri->ri_bits = bus_space_vaddr(sc->sc_bt, sc->sc_pixel_h);
876
877 #ifdef FFBDEBUG
878 printf("addr: %08lx\n",(ulong)ri->ri_bits);
879 #endif
880 rasops_init(ri, sc->sc_height/8, sc->sc_width/8);
881 ri->ri_caps = WSSCREEN_WSCOLORS;
882 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
883 sc->sc_width / ri->ri_font->fontwidth);
884
885 /* enable acceleration */
886 ri->ri_ops.copyrows = ffb_ras_copyrows;
887 ri->ri_ops.eraserows = ffb_ras_eraserows;
888 ri->ri_ops.erasecols = ffb_ras_erasecols;
889 ri->ri_ops.cursor = ffb_cursor;
890 ri->ri_ops.allocattr = ffb_allocattr;
891 if (sc->putchar == NULL)
892 sc->putchar = ri->ri_ops.putchar;
893 ri->ri_ops.putchar = ffb_putchar;
894 }
895