ffb.c revision 1.30 1 /* $NetBSD: ffb.c,v 1.30 2006/09/14 16:05:18 martin 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.30 2006/09/14 16:05:18 martin 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 };
77
78 const struct wsscreen_descr *ffb_scrlist[] = {
79 &ffb_stdscreen,
80 /* XXX other formats? */
81 };
82
83 struct wsscreen_list ffb_screenlist = {
84 sizeof(ffb_scrlist) / sizeof(struct wsscreen_descr *),
85 ffb_scrlist
86 };
87
88 static struct vcons_screen ffb_console_screen;
89
90 int ffb_ioctl(void *, void *, u_long, caddr_t, int, struct lwp *);
91 static int ffb_blank(struct ffb_softc *, u_long, u_int *);
92 paddr_t ffb_mmap(void *, void *, off_t, int);
93 void ffb_ras_fifo_wait(struct ffb_softc *, int);
94 void ffb_ras_wait(struct ffb_softc *);
95 void ffb_ras_init(struct ffb_softc *);
96 void ffb_ras_copyrows(void *, int, int, int);
97 void ffb_ras_erasecols(void *, int, int, int, long int);
98 void ffb_ras_eraserows(void *, int, int, long int);
99 void ffb_ras_do_cursor(struct rasops_info *);
100 void ffb_ras_fill(struct ffb_softc *);
101 void ffb_ras_setfg(struct ffb_softc *, int32_t);
102
103 void ffb_clearscreen(struct ffb_softc *);
104 int ffb_load_font(void *, void *, struct wsdisplay_font *);
105 void ffb_init_screen(void *, struct vcons_screen *, int,
106 long *);
107 int ffb_allocattr(void *, int, int, int, long *);
108 void ffb_putchar(void *, int, int, u_int, long);
109 void ffb_cursor(void *, int, int, int);
110
111 /* frame buffer generic driver */
112 static void ffbfb_unblank(struct device*);
113 dev_type_open(ffbfb_open);
114 dev_type_close(ffbfb_close);
115 dev_type_ioctl(ffbfb_ioctl);
116 dev_type_mmap(ffbfb_mmap);
117
118 static struct fbdriver ffb_fbdriver = {
119 ffbfb_unblank, ffbfb_open, ffbfb_close, ffbfb_ioctl, nopoll,
120 ffbfb_mmap, nokqfilter
121 };
122
123 struct wsdisplay_accessops ffb_accessops = {
124 .ioctl = ffb_ioctl,
125 .mmap = ffb_mmap,
126 };
127
128 void
129 ffb_attach(struct ffb_softc *sc)
130 {
131 struct wsemuldisplaydev_attach_args waa;
132 struct rasops_info *ri;
133 long defattr;
134 const char *model;
135 int btype;
136 uint32_t dac;
137 int maxrow, maxcol;
138 u_int blank = WSDISPLAYIO_VIDEO_ON;
139 char buf[6+1];
140
141 printf(":");
142
143 sc->putchar = NULL;
144
145 if (sc->sc_type == FFB_CREATOR) {
146 btype = prom_getpropint(sc->sc_node, "board_type", 0);
147 if ((btype & 7) == 3)
148 printf(" Creator3D");
149 else
150 printf(" Creator");
151 } else
152 printf(" Elite3D");
153
154 model = prom_getpropstring(sc->sc_node, "model");
155 if (model == NULL || strlen(model) == 0)
156 model = "unknown";
157
158 sc->sc_depth = 24;
159 sc->sc_linebytes = 8192;
160 sc->sc_height = prom_getpropint(sc->sc_node, "height", 0);
161 sc->sc_width = prom_getpropint(sc->sc_node, "width", 0);
162
163 sc->sc_locked = 0;
164 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
165
166 maxcol = (prom_getoption("screen-#columns", buf, sizeof buf) == 0)
167 ? strtoul(buf, NULL, 10)
168 : 80;
169
170 maxrow = (prom_getoption("screen-#rows", buf, sizeof buf) != 0)
171 ? strtoul(buf, NULL, 10)
172 : 34;
173
174 ffb_ras_init(sc);
175
176 /* collect DAC version, as Elite3D cursor enable bit is reversed */
177 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GVERS);
178 dac = DAC_READ(sc, FFB_DAC_VALUE);
179 sc->sc_dacrev = (dac >> 28) & 0xf;
180
181 if (sc->sc_type == FFB_AFB) {
182 sc->sc_dacrev = 10;
183 sc->sc_needredraw = 0;
184 } else {
185 /* see what kind of DAC we have */
186 int pnum = (dac & 0x0ffff000) >> 12;
187 if (pnum == 0x236e) {
188 sc->sc_needredraw = 0;
189 } else {
190 sc->sc_needredraw = 1;
191 }
192 }
193 printf(", model %s, dac %u\n", model, sc->sc_dacrev);
194 if (sc->sc_needredraw)
195 printf("%s: found old DAC, enabling redraw on unblank\n",
196 sc->sc_dv.dv_xname);
197
198 ffb_blank(sc, WSDISPLAYIO_SVIDEO, &blank);
199
200 sc->sc_accel = ((device_cfdata(&sc->sc_dv)->cf_flags &
201 FFB_CFFLAG_NOACCEL) == 0);
202
203 wsfont_init();
204
205 vcons_init(&sc->vd, sc, &ffb_stdscreen, &ffb_accessops);
206 sc->vd.init_screen = ffb_init_screen;
207
208 /* we mess with ffb_console_screen only once */
209 if (sc->sc_console) {
210 vcons_init_screen(&sc->vd, &ffb_console_screen, 1, &defattr);
211 SCREEN_VISIBLE((&ffb_console_screen));
212 /*
213 * XXX we shouldn't use a global variable for the console
214 * screen
215 */
216 sc->vd.active = &ffb_console_screen;
217 ffb_console_screen.scr_flags = VCONS_SCREEN_IS_STATIC;
218 } else {
219 if (ffb_console_screen.scr_ri.ri_rows == 0) {
220 /* do some minimal setup to avoid weirdnesses later */
221 vcons_init_screen(&sc->vd, &ffb_console_screen, 1, &defattr);
222 }
223 }
224 ri = &ffb_console_screen.scr_ri;
225
226 ffb_stdscreen.nrows = ri->ri_rows;
227 ffb_stdscreen.ncols = ri->ri_cols;
228 ffb_stdscreen.textops = &ri->ri_ops;
229 ffb_stdscreen.capabilities = ri->ri_caps;
230
231 sc->sc_fb.fb_driver = &ffb_fbdriver;
232 sc->sc_fb.fb_type.fb_cmsize = 0;
233 sc->sc_fb.fb_type.fb_size = maxrow * sc->sc_linebytes;
234 sc->sc_fb.fb_type.fb_type = FBTYPE_CREATOR;
235 sc->sc_fb.fb_type.fb_width = sc->sc_width;
236 sc->sc_fb.fb_type.fb_depth = sc->sc_depth;
237 sc->sc_fb.fb_type.fb_height = sc->sc_height;
238 sc->sc_fb.fb_device = &sc->sc_dv;
239 fb_attach(&sc->sc_fb, sc->sc_console);
240
241 if (sc->sc_console) {
242 wsdisplay_cnattach(&ffb_stdscreen, ri, 0, 0, defattr);
243 }
244
245 ffb_clearscreen(sc);
246
247 waa.console = sc->sc_console;
248 waa.scrdata = &ffb_screenlist;
249 waa.accessops = &ffb_accessops;
250 waa.accesscookie = &sc->vd;
251 config_found(&sc->sc_dv, &waa, wsemuldisplaydevprint);
252 }
253
254 int
255 ffb_ioctl(void *v, void *vs, u_long cmd, caddr_t data, int flags, struct lwp *l)
256 {
257 struct vcons_data *vd = v;
258 struct ffb_softc *sc = vd->cookie;
259 struct wsdisplay_fbinfo *wdf;
260 struct vcons_screen *ms = vd->active;
261
262 #ifdef FFBDEBUG
263 printf("ffb_ioctl: %s cmd _IO%s%s('%c', %lu)\n",
264 sc->sc_dv.dv_xname,
265 (cmd & IOC_IN) ? "W" : "", (cmd & IOC_OUT) ? "R" : "",
266 (char)IOCGROUP(cmd), cmd & 0xff);
267 #endif
268
269 switch (cmd) {
270 case FBIOGTYPE:
271 *(struct fbtype *)data = sc->sc_fb.fb_type;
272 break;
273 case FBIOGATTR:
274 #define fba ((struct fbgattr *)data)
275 fba->real_type = sc->sc_fb.fb_type.fb_type;
276 fba->owner = 0; /* XXX ??? */
277 fba->fbtype = sc->sc_fb.fb_type;
278 fba->sattr.flags = 0;
279 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
280 fba->sattr.dev_specific[0] = -1;
281 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
282 fba->emu_types[1] = -1;
283 #undef fba
284 break;
285
286 case FBIOGETCMAP:
287 case FBIOPUTCMAP:
288 return EIO;
289
290 case FBIOGVIDEO:
291 case FBIOSVIDEO:
292 return ffb_blank(sc, cmd == FBIOGVIDEO?
293 WSDISPLAYIO_GVIDEO : WSDISPLAYIO_SVIDEO,
294 (u_int *)data);
295 break;
296 case FBIOGCURSOR:
297 case FBIOSCURSOR:
298 /* the console driver is not using the hardware cursor */
299 break;
300 case FBIOGCURPOS:
301 printf("%s: FBIOGCURPOS not implemented\n", sc->sc_dv.dv_xname);
302 return EIO;
303 case FBIOSCURPOS:
304 printf("%s: FBIOSCURPOS not implemented\n", sc->sc_dv.dv_xname);
305 return EIO;
306 case FBIOGCURMAX:
307 printf("%s: FBIOGCURMAX not implemented\n", sc->sc_dv.dv_xname);
308 return EIO;
309
310 case WSDISPLAYIO_GTYPE:
311 *(u_int *)data = WSDISPLAY_TYPE_SUNFFB;
312 break;
313 case WSDISPLAYIO_SMODE:
314 {
315 if (sc->sc_mode != *(u_int *)data) {
316 sc->sc_mode = *(u_int *)data;
317 if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) &&
318 (sc->sc_locked == 0)) {
319 ffb_ras_init(sc);
320 vcons_redraw_screen(ms);
321 }
322 }
323 }
324 break;
325 case WSDISPLAYIO_GINFO:
326 wdf = (void *)data;
327 wdf->height = sc->sc_height;
328 wdf->width = sc->sc_width;
329 wdf->depth = 32;
330 wdf->cmsize = 256; /* XXX */
331 break;
332 #ifdef WSDISPLAYIO_LINEBYTES
333 case WSDISPLAYIO_LINEBYTES:
334 *(u_int *)data = sc->sc_linebytes;
335 break;
336 #endif
337 case WSDISPLAYIO_GETCMAP:
338 break;/* XXX */
339
340 case WSDISPLAYIO_PUTCMAP:
341 break;/* XXX */
342
343 case WSDISPLAYIO_SVIDEO:
344 case WSDISPLAYIO_GVIDEO:
345 return(ffb_blank(sc, cmd, (u_int *)data));
346 break;
347 case WSDISPLAYIO_GCURPOS:
348 case WSDISPLAYIO_SCURPOS:
349 case WSDISPLAYIO_GCURMAX:
350 case WSDISPLAYIO_GCURSOR:
351 case WSDISPLAYIO_SCURSOR:
352 return EIO; /* not supported yet */
353 default:
354 return EPASSTHROUGH;
355 }
356
357 return (0);
358 }
359
360 /* blank/unblank the screen */
361 static int
362 ffb_blank(struct ffb_softc *sc, u_long cmd, u_int *data)
363 {
364 struct vcons_screen *ms = sc->vd.active;
365 u_int val;
366
367 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
368 val = DAC_READ(sc, FFB_DAC_VALUE);
369
370 switch (cmd) {
371 case WSDISPLAYIO_GVIDEO:
372 *data = val & 1;
373 return(0);
374 break;
375 case WSDISPLAYIO_SVIDEO:
376 if (*data == WSDISPLAYIO_VIDEO_OFF)
377 val &= ~1;
378 else if (*data == WSDISPLAYIO_VIDEO_ON)
379 val |= 1;
380 else
381 return(EINVAL);
382 break;
383 default:
384 return(EINVAL);
385 }
386
387 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
388 DAC_WRITE(sc, FFB_DAC_VALUE, val);
389
390 if ((val & 1) && sc->sc_needredraw) {
391 if (ms != NULL) {
392 if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) &&
393 (sc->sc_locked == 0)) {
394 ffb_ras_init(sc);
395 vcons_redraw_screen(ms);
396 }
397 }
398 }
399
400 return(0);
401 }
402
403 paddr_t
404 ffb_mmap(void *vsc, void *vs, off_t off, int prot)
405 {
406 struct vcons_data *vd = vsc;
407 struct ffb_softc *sc = vd->cookie;
408 int i;
409
410 switch (sc->sc_mode) {
411 case WSDISPLAYIO_MODE_MAPPED:
412 for (i = 0; i < sc->sc_nreg; i++) {
413 /* Before this set? */
414 if (off < sc->sc_addrs[i])
415 continue;
416 /* After this set? */
417 if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i]))
418 continue;
419
420 return (bus_space_mmap(sc->sc_bt, sc->sc_addrs[i],
421 off - sc->sc_addrs[i], prot, BUS_SPACE_MAP_LINEAR));
422 }
423 break;
424 #ifdef WSDISPLAYIO_MODE_DUMBFB
425 case WSDISPLAYIO_MODE_DUMBFB:
426 if (sc->sc_nreg < FFB_REG_DFB24)
427 break;
428 if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24])
429 return (bus_space_mmap(sc->sc_bt,
430 sc->sc_addrs[FFB_REG_DFB24], off, prot,
431 BUS_SPACE_MAP_LINEAR));
432 break;
433 #endif
434 }
435
436 return (-1);
437 }
438
439 void
440 ffb_ras_fifo_wait(struct ffb_softc *sc, int n)
441 {
442 int32_t cache = sc->sc_fifo_cache;
443
444 if (cache < n) {
445 do {
446 cache = FBC_READ(sc, FFB_FBC_UCSR);
447 cache = (cache & FBC_UCSR_FIFO_MASK) - 8;
448 } while (cache < n);
449 }
450 sc->sc_fifo_cache = cache - n;
451 }
452
453 void
454 ffb_ras_wait(struct ffb_softc *sc)
455 {
456 uint32_t ucsr, r;
457
458 while (1) {
459 ucsr = FBC_READ(sc, FFB_FBC_UCSR);
460 if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0)
461 break;
462 r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL);
463 if (r != 0)
464 FBC_WRITE(sc, FFB_FBC_UCSR, r);
465 }
466 }
467
468 void
469 ffb_ras_init(struct ffb_softc *sc)
470 {
471 ffb_ras_fifo_wait(sc, 7);
472 FBC_WRITE(sc, FFB_FBC_PPC,
473 FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE |
474 FBC_PPC_APE_DIS | FBC_PPC_CS_CONST);
475 FBC_WRITE(sc, FFB_FBC_FBC,
476 FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH |
477 FFB_FBC_XE_OFF | FFB_FBC_RGBE_MASK);
478 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
479 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
480 FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff);
481 FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000);
482 sc->sc_fg_cache = 0;
483 FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache);
484 ffb_ras_wait(sc);
485 }
486
487 void
488 ffb_ras_eraserows(void *cookie, int row, int n, long attr)
489 {
490 struct rasops_info *ri = cookie;
491 struct vcons_screen *scr = ri->ri_hw;
492 struct ffb_softc *sc = scr->scr_cookie;
493
494 if (row < 0) {
495 n += row;
496 row = 0;
497 }
498 if (row + n > ri->ri_rows)
499 n = ri->ri_rows - row;
500 if (n <= 0)
501 return;
502
503 ffb_ras_fill(sc);
504 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]);
505 ffb_ras_fifo_wait(sc, 4);
506 if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
507 FBC_WRITE(sc, FFB_FBC_BY, 0);
508 FBC_WRITE(sc, FFB_FBC_BX, 0);
509 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height);
510 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width);
511 } else {
512 row *= ri->ri_font->fontheight;
513 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
514 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
515 FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight);
516 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
517 }
518 ffb_ras_wait(sc);
519 }
520
521 void
522 ffb_ras_erasecols(void *cookie, int row, int col, int n, long attr)
523 {
524 struct rasops_info *ri = cookie;
525 struct vcons_screen *scr = ri->ri_hw;
526 struct ffb_softc *sc = scr->scr_cookie;
527
528 if ((row < 0) || (row >= ri->ri_rows))
529 return;
530 if (col < 0) {
531 n += col;
532 col = 0;
533 }
534 if (col + n > ri->ri_cols)
535 n = ri->ri_cols - col;
536 if (n <= 0)
537 return;
538 n *= ri->ri_font->fontwidth;
539 col *= ri->ri_font->fontwidth;
540 row *= ri->ri_font->fontheight;
541
542 ffb_ras_fill(sc);
543 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]);
544 ffb_ras_fifo_wait(sc, 4);
545 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
546 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col);
547 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight);
548 FBC_WRITE(sc, FFB_FBC_BW, n - 1);
549 ffb_ras_wait(sc);
550 }
551
552 void
553 ffb_ras_fill(struct ffb_softc *sc)
554 {
555 ffb_ras_fifo_wait(sc, 2);
556 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
557 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
558 ffb_ras_wait(sc);
559 }
560
561 void
562 ffb_ras_copyrows(void *cookie, int src, int dst, int n)
563 {
564 struct rasops_info *ri = cookie;
565 struct vcons_screen *scr = ri->ri_hw;
566 struct ffb_softc *sc = scr->scr_cookie;
567
568 if (dst == src)
569 return;
570 if (src < 0) {
571 n += src;
572 src = 0;
573 }
574 if ((src + n) > ri->ri_rows)
575 n = ri->ri_rows - src;
576 if (dst < 0) {
577 n += dst;
578 dst = 0;
579 }
580 if ((dst + n) > ri->ri_rows)
581 n = ri->ri_rows - dst;
582 if (n <= 0)
583 return;
584 n *= ri->ri_font->fontheight;
585 src *= ri->ri_font->fontheight;
586 dst *= ri->ri_font->fontheight;
587
588 ffb_ras_fifo_wait(sc, 8);
589 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_OLD | (FBC_ROP_OLD << 8));
590 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_VSCROLL);
591 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + src);
592 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
593 FBC_WRITE(sc, FFB_FBC_DY, ri->ri_yorigin + dst);
594 FBC_WRITE(sc, FFB_FBC_DX, ri->ri_xorigin);
595 FBC_WRITE(sc, FFB_FBC_BH, n);
596 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
597 ffb_ras_wait(sc);
598 }
599
600 void
601 ffb_ras_setfg(struct ffb_softc *sc, int32_t fg)
602 {
603 ffb_ras_fifo_wait(sc, 1);
604 if (fg == sc->sc_fg_cache)
605 return;
606 sc->sc_fg_cache = fg;
607 FBC_WRITE(sc, FFB_FBC_FG, fg);
608 ffb_ras_wait(sc);
609 }
610
611 /* frame buffer generic driver support functions */
612 static void
613 ffbfb_unblank(struct device *dev)
614 {
615 struct ffb_softc *sc = (struct ffb_softc *)dev;
616 struct vcons_screen *ms = sc->vd.active;
617 u_int on = 1;
618 int redraw = 0;
619
620 ffb_ras_init(sc);
621 if (sc->sc_locked) {
622 sc->sc_locked = 0;
623 redraw = 1;
624 }
625
626 ffb_blank((struct ffb_softc*)dev, WSDISPLAYIO_SVIDEO, &on);
627 if ((sc->vd.active != &ffb_console_screen) &&
628 (ffb_console_screen.scr_flags & VCONS_SCREEN_IS_STATIC)) {
629 /*
630 * force-switch to the console screen.
631 * Caveat: the higher layer will think we're still on the
632 * other screen
633 */
634
635 SCREEN_INVISIBLE(sc->vd.active);
636 sc->vd.active = &ffb_console_screen;
637 SCREEN_VISIBLE(sc->vd.active);
638 ms = sc->vd.active;
639 redraw = 1;
640 }
641
642 if (redraw) {
643 vcons_redraw_screen(ms);
644 }
645 }
646
647 int
648 ffbfb_open(dev_t dev, int flags, int mode, struct lwp *l)
649 {
650 struct ffb_softc *sc;
651 int unit = minor(dev);
652
653 sc = ffb_cd.cd_devs[unit];
654 if (unit >= ffb_cd.cd_ndevs || ffb_cd.cd_devs[unit] == NULL)
655 return ENXIO;
656
657 sc->sc_locked = 1;
658 return 0;
659 }
660
661 int
662 ffbfb_close(dev_t dev, int flags, int mode, struct lwp *l)
663 {
664 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)];
665 struct vcons_screen *ms = sc->vd.active;
666
667 sc->sc_locked = 0;
668 if (ms != NULL) {
669 if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) &&
670 (sc->sc_locked == 0)) {
671 ffb_ras_init(sc);
672 vcons_redraw_screen(ms);
673 }
674 }
675 return 0;
676 }
677
678 int
679 ffbfb_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct lwp *l)
680 {
681 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)];
682
683 return ffb_ioctl(&sc->vd, NULL, cmd, data, flags, l);
684 }
685
686 paddr_t
687 ffbfb_mmap(dev_t dev, off_t off, int prot)
688 {
689 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)];
690 uint64_t size;
691 int i, reg;
692 off_t o;
693
694 /*
695 * off is a magic cookie (see xfree86/drivers/sunffb/ffb.h),
696 * which we map to an index into the "reg" property, and use
697 * our copy of the firmware data as arguments for the real
698 * mapping.
699 */
700 static struct { unsigned long voff; int reg; } map[] = {
701 { 0x00000000, FFB_REG_SFB8R },
702 { 0x00400000, FFB_REG_SFB8G },
703 { 0x00800000, FFB_REG_SFB8B },
704 { 0x00c00000, FFB_REG_SFB8X },
705 { 0x01000000, FFB_REG_SFB32 },
706 { 0x02000000, FFB_REG_SFB64 },
707 { 0x04000000, FFB_REG_FBC },
708 { 0x04004000, FFB_REG_DFB8R },
709 { 0x04404000, FFB_REG_DFB8G },
710 { 0x04804000, FFB_REG_DFB8B },
711 { 0x04c04000, FFB_REG_DFB8X },
712 { 0x05004000, FFB_REG_DFB24 },
713 { 0x06004000, FFB_REG_DFB32 },
714 { 0x07004000, FFB_REG_DFB422A },
715 { 0x0bc06000, FFB_REG_DAC },
716 { 0x0bc08000, FFB_REG_PROM },
717 { 0x0bc18000, 0 }
718 };
719
720 /* special value "FFB_EXP_VOFF" - not backed by any "reg" entry */
721 if (off == 0x0bc18000)
722 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM],
723 0x00200000, prot, BUS_SPACE_MAP_LINEAR);
724
725 /*
726 * FFB_VOFF_FBC_KREGS - used by afbinit to upload firmware. We should
727 * probably mmap them only on afb boards
728 */
729 if ((off >= 0x0bc04000) && (off < 0x0bc06000))
730 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM],
731 0x00610000 + (off - 0x0bc04000), prot,
732 BUS_SPACE_MAP_LINEAR);
733
734 #define NELEMS(arr) (sizeof(arr)/sizeof((arr)[0]))
735
736 /* the map is ordered by voff */
737 for (i = 0; i < NELEMS(map)-1; i++) {
738 reg = map[i].reg;
739 /* the number of entries in reg seems to vary */
740 if (reg < sc->sc_nreg) {
741 size = min((map[i + 1].voff - map[i].voff),
742 sc->sc_sizes[reg]);
743 if ((off >= map[i].voff) &&
744 (off < (map[i].voff + size))) {
745 o = off - map[i].voff;
746 return bus_space_mmap(sc->sc_bt,
747 sc->sc_addrs[reg], o, prot,
748 BUS_SPACE_MAP_LINEAR);
749 }
750 }
751 }
752
753 return -1;
754 }
755
756 void
757 ffb_clearscreen(struct ffb_softc *sc)
758 {
759 struct rasops_info *ri = &ffb_console_screen.scr_ri;
760 ffb_ras_fill(sc);
761 ffb_ras_setfg(sc, ri->ri_devcmap[WS_DEFAULT_BG]);
762 ffb_ras_fifo_wait(sc, 4);
763 FBC_WRITE(sc, FFB_FBC_BY, 0);
764 FBC_WRITE(sc, FFB_FBC_BX, 0);
765 FBC_WRITE(sc, FFB_FBC_BH, sc->sc_height);
766 FBC_WRITE(sc, FFB_FBC_BW, sc->sc_width);
767 }
768
769 void
770 ffb_cursor(void *cookie, int on, int row, int col)
771 {
772 struct rasops_info *ri = cookie;
773 struct vcons_screen *scr;
774 struct ffb_softc *sc;
775 int x, y, wi, he, coffset;
776
777 if (cookie != NULL) {
778 scr = ri->ri_hw;
779 sc = scr->scr_cookie;
780
781 wi = ri->ri_font->fontwidth;
782 he = ri->ri_font->fontheight;
783
784 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
785 x = ri->ri_ccol * wi + ri->ri_xorigin;
786 y = ri->ri_crow * he + ri->ri_yorigin;
787
788 if (ri->ri_flg & RI_CURSOR) {
789 /* remove cursor */
790 coffset = ri->ri_ccol + (ri->ri_crow *
791 ri->ri_cols);
792 ffb_ras_wait(sc);
793 sc->putchar(cookie, ri->ri_crow,
794 ri->ri_ccol, scr->scr_chars[coffset],
795 scr->scr_attrs[coffset]);
796 ri->ri_flg &= ~RI_CURSOR;
797 }
798 ri->ri_crow = row;
799 ri->ri_ccol = col;
800 if (on)
801 {
802 long attr, revattr;
803 x = ri->ri_ccol * wi + ri->ri_xorigin;
804 y = ri->ri_crow * he + ri->ri_yorigin;
805 coffset = col + (row * ri->ri_cols);
806 attr = scr->scr_attrs[coffset];
807 #ifdef FFB_CURSOR_SWAP_COLOURS
808 revattr=((attr >> 8 ) & 0x000f0000) | ((attr &
809 0x000f0000)<<8) | (attr & 0x0000ffff);
810 #else
811 revattr = attr ^ 0xffff0000;
812 #endif
813 ffb_ras_wait(sc);
814 sc->putchar(cookie, ri->ri_crow, ri->ri_ccol,
815 scr->scr_chars[coffset], revattr);
816 ri->ri_flg |= RI_CURSOR;
817 }
818 } else {
819 ri->ri_crow = row;
820 ri->ri_ccol = col;
821 ri->ri_flg &= ~RI_CURSOR;
822 }
823 }
824 }
825
826 void
827 ffb_putchar(void *cookie, int row, int col, u_int c, long attr)
828 {
829 struct rasops_info *ri = cookie;
830 struct vcons_screen *scr = ri->ri_hw;
831 struct ffb_softc *sc = scr->scr_cookie;
832
833 if (sc->putchar != NULL) {
834 /*
835 * the only reason why we need to hook putchar - wait for
836 * the drawing engine to be idle so we don't interfere
837 * ( and we should really use the colour expansion hardware )
838 */
839 ffb_ras_wait(sc);
840 sc->putchar(cookie, row, col, c, attr);
841 }
842 }
843
844 int
845 ffb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
846 {
847 if ((fg == 0) && (bg == 0))
848 {
849 fg = WS_DEFAULT_FG;
850 bg = WS_DEFAULT_BG;
851 }
852 if (flags & WSATTR_REVERSE) {
853 *attrp = (bg & 0xff) << 24 | (fg & 0xff) << 16 |
854 (flags & 0xff);
855 } else
856 *attrp = (fg & 0xff) << 24 | (bg & 0xff) << 16 |
857 (flags & 0xff);
858 return 0;
859 }
860
861 void
862 ffb_init_screen(void *cookie, struct vcons_screen *scr,
863 int existing, long *defattr)
864 {
865 struct ffb_softc *sc = cookie;
866 struct rasops_info *ri = &scr->scr_ri;
867
868 ri->ri_depth = 32;
869 ri->ri_width = sc->sc_width;
870 ri->ri_height = sc->sc_height;
871 ri->ri_stride = sc->sc_linebytes;
872 ri->ri_flg = RI_CENTER;
873
874 ri->ri_bits = bus_space_vaddr(sc->sc_bt, sc->sc_pixel_h);
875
876 #ifdef FFBDEBUG
877 printf("addr: %08lx\n",(ulong)ri->ri_bits);
878 #endif
879 rasops_init(ri, sc->sc_height/8, sc->sc_width/8);
880 ri->ri_caps = WSSCREEN_WSCOLORS;
881 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
882 sc->sc_width / ri->ri_font->fontwidth);
883
884 /* enable acceleration */
885 ri->ri_ops.copyrows = ffb_ras_copyrows;
886 ri->ri_ops.eraserows = ffb_ras_eraserows;
887 ri->ri_ops.erasecols = ffb_ras_erasecols;
888 ri->ri_ops.cursor = ffb_cursor;
889 ri->ri_ops.allocattr = ffb_allocattr;
890 if (sc->putchar == NULL)
891 sc->putchar = ri->ri_ops.putchar;
892 ri->ri_ops.putchar = ffb_putchar;
893 }
894