ffb.c revision 1.11 1 /* $NetBSD: ffb.c,v 1.11 2005/05/04 14:38:44 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.11 2005/05/04 14:38:44 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
45 #include <machine/bus.h>
46 #include <machine/autoconf.h>
47 #include <machine/openfirm.h>
48 #include <machine/vmparam.h>
49
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/sun/fbio.h>
52 #include <dev/sun/fbvar.h>
53
54 #include <sparc64/dev/ffbreg.h>
55 #include <sparc64/dev/ffbvar.h>
56
57 extern struct cfdriver ffb_cd;
58
59 struct wsscreen_descr ffb_stdscreen = {
60 "sunffb",
61 0, 0, /* will be filled in -- XXX shouldn't, it's global. */
62 0,
63 0, 0,
64 WSSCREEN_REVERSE | WSSCREEN_WSCOLORS
65 };
66
67 const struct wsscreen_descr *ffb_scrlist[] = {
68 &ffb_stdscreen,
69 /* XXX other formats? */
70 };
71
72 struct wsscreen_list ffb_screenlist = {
73 sizeof(ffb_scrlist) / sizeof(struct wsscreen_descr *),
74 ffb_scrlist
75 };
76
77 int ffb_ioctl(void *, u_long, caddr_t, int, struct proc *);
78 int ffb_alloc_screen(void *, const struct wsscreen_descr *, void **,
79 int *, int *, long *);
80 static int ffb_blank(struct ffb_softc *, u_long, u_int *);
81 void ffb_free_screen(void *, void *);
82 int ffb_show_screen(void *, void *, int, void (*cb)(void *, int, int),
83 void *);
84 paddr_t ffb_mmap(void *, off_t, int);
85 void ffb_ras_fifo_wait(struct ffb_softc *, int);
86 void ffb_ras_wait(struct ffb_softc *);
87 void ffb_ras_init(struct ffb_softc *);
88 void ffb_ras_copyrows(void *, int, int, int);
89 void ffb_ras_erasecols(void *, int, int, int, long int);
90 void ffb_ras_eraserows(void *, int, int, long int);
91 void ffb_ras_do_cursor(struct rasops_info *);
92 void ffb_ras_fill(struct ffb_softc *);
93 void ffb_ras_setfg(struct ffb_softc *, int32_t);
94
95 /* frame buffer generic driver */
96 static void ffbfb_unblank(struct device*);
97 dev_type_open(ffbfb_open);
98 dev_type_close(ffbfb_close);
99 dev_type_ioctl(ffbfb_ioctl);
100 dev_type_mmap(ffbfb_mmap);
101 static struct fbdriver ffb_fbdriver = {
102 ffbfb_unblank, ffbfb_open, ffbfb_close, ffbfb_ioctl, nopoll,
103 ffbfb_mmap, nokqfilter
104 };
105
106 struct wsdisplay_accessops ffb_accessops = {
107 ffb_ioctl,
108 ffb_mmap,
109 ffb_alloc_screen,
110 ffb_free_screen,
111 ffb_show_screen,
112 NULL, /* load font */
113 NULL, /* pollc */
114 NULL, /* getwschar */
115 NULL, /* putwschar */
116 NULL, /* scroll */
117 };
118
119 void
120 ffb_attach(struct ffb_softc *sc)
121 {
122 struct wsemuldisplaydev_attach_args waa;
123 char *model;
124 int btype;
125 int maxrow, maxcol;
126 u_int blank = WSDISPLAYIO_VIDEO_ON;
127 char buf[6+1];
128
129 printf(":");
130
131 if (sc->sc_type == FFB_CREATOR) {
132 btype = prom_getpropint(sc->sc_node, "board_type", 0);
133 if ((btype & 7) == 3)
134 printf(" Creator3D");
135 else
136 printf(" Creator");
137 } else
138 printf(" Elite3D");
139
140 model = prom_getpropstring(sc->sc_node, "model");
141 if (model == NULL || strlen(model) == 0)
142 model = "unknown";
143
144 sc->sc_depth = 24;
145 sc->sc_linebytes = 8192;
146 sc->sc_height = prom_getpropint(sc->sc_node, "height", 0);
147 sc->sc_width = prom_getpropint(sc->sc_node, "width", 0);
148
149 sc->sc_fb.fb_rinfo.ri_depth = 32;
150 sc->sc_fb.fb_rinfo.ri_stride = sc->sc_linebytes;
151 sc->sc_fb.fb_rinfo.ri_flg = RI_CENTER;
152 sc->sc_fb.fb_rinfo.ri_bits = (void *)bus_space_vaddr(sc->sc_bt,
153 sc->sc_pixel_h);
154
155 sc->sc_fb.fb_rinfo.ri_width = sc->sc_width;
156 sc->sc_fb.fb_rinfo.ri_height = sc->sc_height;
157 sc->sc_fb.fb_rinfo.ri_hw = sc;
158
159 maxcol = (prom_getoption("screen-#columns", buf, sizeof buf) == 0)
160 ? strtoul(buf, NULL, 10)
161 : 80;
162
163 maxrow = (prom_getoption("screen-#rows", buf, sizeof buf) != 0)
164 ? strtoul(buf, NULL, 10)
165 : 34;
166
167 rasops_init(&sc->sc_fb.fb_rinfo, maxrow, maxcol);
168
169 if ((sc->sc_dv.dv_cfdata->cf_flags & FFB_CFFLAG_NOACCEL) == 0) {
170 sc->sc_fb.fb_rinfo.ri_hw = sc;
171 sc->sc_fb.fb_rinfo.ri_ops.eraserows = ffb_ras_eraserows;
172 sc->sc_fb.fb_rinfo.ri_ops.erasecols = ffb_ras_erasecols;
173 sc->sc_fb.fb_rinfo.ri_ops.copyrows = ffb_ras_copyrows;
174 ffb_ras_init(sc);
175 }
176
177 ffb_stdscreen.nrows = sc->sc_fb.fb_rinfo.ri_rows;
178 ffb_stdscreen.ncols = sc->sc_fb.fb_rinfo.ri_cols;
179 ffb_stdscreen.textops = &sc->sc_fb.fb_rinfo.ri_ops;
180
181 /* collect DAC version, as Elite3D cursor enable bit is reversed */
182 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GVERS);
183 sc->sc_dacrev = DAC_READ(sc, FFB_DAC_VALUE) >> 28;
184
185 if (sc->sc_type == FFB_AFB)
186 sc->sc_dacrev = 10;
187 printf(", model %s, dac %u\n", model, sc->sc_dacrev);
188
189 ffb_blank(sc, WSDISPLAYIO_SVIDEO, &blank);
190
191 sc->sc_fb.fb_driver = &ffb_fbdriver;
192 sc->sc_fb.fb_type.fb_cmsize = 0;
193 sc->sc_fb.fb_type.fb_size = maxrow * sc->sc_linebytes;
194 sc->sc_fb.fb_type.fb_type = FBTYPE_CREATOR;
195 sc->sc_fb.fb_device = &sc->sc_dv;
196 fb_attach(&sc->sc_fb, sc->sc_console);
197
198 if (sc->sc_console) {
199 int *ccolp, *crowp;
200 long defattr;
201
202 if (romgetcursoraddr(&crowp, &ccolp))
203 ccolp = crowp = NULL;
204 if (ccolp != NULL)
205 sc->sc_fb.fb_rinfo.ri_ccol = *ccolp;
206 if (crowp != NULL)
207 sc->sc_fb.fb_rinfo.ri_crow = *crowp;
208
209 sc->sc_fb.fb_rinfo.ri_ops.allocattr(&sc->sc_fb.fb_rinfo,
210 0, 0, 0, &defattr);
211
212 wsdisplay_cnattach(&ffb_stdscreen, &sc->sc_fb.fb_rinfo,
213 sc->sc_fb.fb_rinfo.ri_ccol, sc->sc_fb.fb_rinfo.ri_crow, defattr);
214 }
215
216 waa.console = sc->sc_console;
217 waa.scrdata = &ffb_screenlist;
218 waa.accessops = &ffb_accessops;
219 waa.accesscookie = sc;
220 config_found(&sc->sc_dv, &waa, wsemuldisplaydevprint);
221 }
222
223 int
224 ffb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
225 {
226 struct ffb_softc *sc = v;
227 struct wsdisplay_fbinfo *wdf;
228
229 #ifdef FFBDEBUG
230 printf("ffb_ioctl: %s cmd _IO%s%s('%c', %lu)\n",
231 sc->sc_dv.dv_xname,
232 (cmd & IOC_IN) ? "W" : "", (cmd & IOC_OUT) ? "R" : "",
233 (char)IOCGROUP(cmd), cmd & 0xff);
234 #endif
235
236 switch (cmd) {
237 case FBIOGTYPE:
238 *(struct fbtype *)data = sc->sc_fb.fb_type;
239 break;
240 case FBIOGATTR:
241 #define fba ((struct fbgattr *)data)
242 fba->real_type = sc->sc_fb.fb_type.fb_type;
243 fba->owner = 0; /* XXX ??? */
244 fba->fbtype = sc->sc_fb.fb_type;
245 fba->sattr.flags = 0;
246 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
247 fba->sattr.dev_specific[0] = -1;
248 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
249 fba->emu_types[1] = -1;
250 #undef fba
251 break;
252
253 case FBIOGETCMAP:
254 case FBIOPUTCMAP:
255 return EIO;
256
257 case FBIOGVIDEO:
258 case FBIOSVIDEO:
259 return ffb_blank(sc, cmd == FBIOGVIDEO?
260 WSDISPLAYIO_GVIDEO : WSDISPLAYIO_SVIDEO,
261 (u_int *)data);
262 break;
263 case FBIOGCURSOR:
264 printf("%s: FBIOGCURSOR not implemented\n", sc->sc_dv.dv_xname);
265 return EIO;
266 case FBIOSCURSOR:
267 printf("%s: FBIOSCURSOR not implemented\n", sc->sc_dv.dv_xname);
268 return EIO;
269 case FBIOGCURPOS:
270 printf("%s: FBIOGCURPOS not implemented\n", sc->sc_dv.dv_xname);
271 return EIO;
272 case FBIOSCURPOS:
273 printf("%s: FBIOSCURPOS not implemented\n", sc->sc_dv.dv_xname);
274 return EIO;
275 case FBIOGCURMAX:
276 printf("%s: FBIOGCURMAX not implemented\n", sc->sc_dv.dv_xname);
277 return EIO;
278
279 case WSDISPLAYIO_GTYPE:
280 *(u_int *)data = WSDISPLAY_TYPE_SUNFFB;
281 break;
282 case WSDISPLAYIO_SMODE:
283 sc->sc_mode = *(u_int *)data;
284 break;
285 case WSDISPLAYIO_GINFO:
286 wdf = (void *)data;
287 wdf->height = sc->sc_height;
288 wdf->width = sc->sc_width;
289 wdf->depth = 32;
290 wdf->cmsize = 256; /* XXX */
291 break;
292 #ifdef WSDISPLAYIO_LINEBYTES
293 case WSDISPLAYIO_LINEBYTES:
294 *(u_int *)data = sc->sc_linebytes;
295 break;
296 #endif
297 case WSDISPLAYIO_GETCMAP:
298 break;/* XXX */
299
300 case WSDISPLAYIO_PUTCMAP:
301 break;/* XXX */
302
303 case WSDISPLAYIO_SVIDEO:
304 case WSDISPLAYIO_GVIDEO:
305 return(ffb_blank(sc, cmd, (u_int *)data));
306 break;
307 case WSDISPLAYIO_GCURPOS:
308 case WSDISPLAYIO_SCURPOS:
309 case WSDISPLAYIO_GCURMAX:
310 case WSDISPLAYIO_GCURSOR:
311 case WSDISPLAYIO_SCURSOR:
312 return EIO; /* not supported yet */
313 default:
314 return EPASSTHROUGH;
315 }
316
317 return (0);
318 }
319
320 int
321 ffb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
322 int *curxp, int *curyp, long *attrp)
323 {
324 struct ffb_softc *sc = v;
325
326 if (sc->sc_nscreens > 0)
327 return (ENOMEM);
328
329 *cookiep = &sc->sc_fb.fb_rinfo;
330 *curyp = 0;
331 *curxp = 0;
332
333 sc->sc_fb.fb_rinfo.ri_ops.allocattr(&sc->sc_fb.fb_rinfo, 0, 0, 0, attrp);
334
335 sc->sc_nscreens++;
336 return (0);
337 }
338
339 /* blank/unblank the screen */
340 static int
341 ffb_blank(struct ffb_softc *sc, u_long cmd, u_int *data)
342 {
343 u_int val;
344
345 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
346 val = DAC_READ(sc, FFB_DAC_VALUE);
347
348 switch (cmd) {
349 case WSDISPLAYIO_GVIDEO:
350 *data = val & 1;
351 return(0);
352 break;
353 case WSDISPLAYIO_SVIDEO:
354 if (*data == WSDISPLAYIO_VIDEO_OFF)
355 val &= ~1;
356 else if (*data == WSDISPLAYIO_VIDEO_ON)
357 val |= 1;
358 else
359 return(EINVAL);
360 break;
361 default:
362 return(EINVAL);
363 }
364
365 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
366 DAC_WRITE(sc, FFB_DAC_VALUE, val);
367
368 return(0);
369 }
370
371 void
372 ffb_free_screen(void *v, void *cookie)
373 {
374 struct ffb_softc *sc = v;
375
376 sc->sc_nscreens--;
377 }
378
379 int
380 ffb_show_screen(void *v, void *cookie, int waitok,
381 void (*cb)(void *, int, int), void *cbarg)
382 {
383 return (0);
384 }
385
386 paddr_t
387 ffb_mmap(void *vsc, off_t off, int prot)
388 {
389 struct ffb_softc *sc = vsc;
390 int i;
391
392 switch (sc->sc_mode) {
393 case WSDISPLAYIO_MODE_MAPPED:
394 for (i = 0; i < sc->sc_nreg; i++) {
395 /* Before this set? */
396 if (off < sc->sc_addrs[i])
397 continue;
398 /* After this set? */
399 if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i]))
400 continue;
401
402 return (bus_space_mmap(sc->sc_bt, sc->sc_addrs[i],
403 off - sc->sc_addrs[i], prot, BUS_SPACE_MAP_LINEAR));
404 }
405 break;
406 #ifdef WSDISPLAYIO_MODE_DUMBFB
407 case WSDISPLAYIO_MODE_DUMBFB:
408 if (sc->sc_nreg < FFB_REG_DFB24)
409 break;
410 if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24])
411 return (bus_space_mmap(sc->sc_bt,
412 sc->sc_addrs[FFB_REG_DFB24], off, prot,
413 BUS_SPACE_MAP_LINEAR));
414 break;
415 #endif
416 }
417
418 return (-1);
419 }
420
421 void
422 ffb_ras_fifo_wait(struct ffb_softc *sc, int n)
423 {
424 int32_t cache = sc->sc_fifo_cache;
425
426 if (cache < n) {
427 do {
428 cache = FBC_READ(sc, FFB_FBC_UCSR);
429 cache = (cache & FBC_UCSR_FIFO_MASK) - 8;
430 } while (cache < n);
431 }
432 sc->sc_fifo_cache = cache - n;
433 }
434
435 void
436 ffb_ras_wait(struct ffb_softc *sc)
437 {
438 u_int32_t ucsr, r;
439
440 while (1) {
441 ucsr = FBC_READ(sc, FFB_FBC_UCSR);
442 if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0)
443 break;
444 r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL);
445 if (r != 0)
446 FBC_WRITE(sc, FFB_FBC_UCSR, r);
447 }
448 }
449
450 void
451 ffb_ras_init(struct ffb_softc *sc)
452 {
453 ffb_ras_fifo_wait(sc, 7);
454 FBC_WRITE(sc, FFB_FBC_PPC,
455 FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE |
456 FBC_PPC_APE_DIS | FBC_PPC_CS_CONST);
457 FBC_WRITE(sc, FFB_FBC_FBC,
458 FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH |
459 FFB_FBC_XE_OFF | FFB_FBC_RGBE_MASK);
460 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
461 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
462 FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff);
463 FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000);
464 sc->sc_fg_cache = 0;
465 FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache);
466 ffb_ras_wait(sc);
467 }
468
469 void
470 ffb_ras_eraserows(void *cookie, int row, int n, long attr)
471 {
472 struct rasops_info *ri = cookie;
473 struct ffb_softc *sc = ri->ri_hw;
474
475 if (row < 0) {
476 n += row;
477 row = 0;
478 }
479 if (row + n > ri->ri_rows)
480 n = ri->ri_rows - row;
481 if (n <= 0)
482 return;
483
484 ffb_ras_fill(sc);
485 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]);
486 ffb_ras_fifo_wait(sc, 4);
487 if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
488 FBC_WRITE(sc, FFB_FBC_BY, 0);
489 FBC_WRITE(sc, FFB_FBC_BX, 0);
490 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height);
491 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width);
492 } else {
493 row *= ri->ri_font->fontheight;
494 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
495 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
496 FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight);
497 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
498 }
499 ffb_ras_wait(sc);
500 }
501
502 void
503 ffb_ras_erasecols(void *cookie, int row, int col, int n, long attr)
504 {
505 struct rasops_info *ri = cookie;
506 struct ffb_softc *sc = ri->ri_hw;
507
508 if ((row < 0) || (row >= ri->ri_rows))
509 return;
510 if (col < 0) {
511 n += col;
512 col = 0;
513 }
514 if (col + n > ri->ri_cols)
515 n = ri->ri_cols - col;
516 if (n <= 0)
517 return;
518 n *= ri->ri_font->fontwidth;
519 col *= ri->ri_font->fontwidth;
520 row *= ri->ri_font->fontheight;
521
522 ffb_ras_fill(sc);
523 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]);
524 ffb_ras_fifo_wait(sc, 4);
525 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
526 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col);
527 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight);
528 FBC_WRITE(sc, FFB_FBC_BW, n - 1);
529 ffb_ras_wait(sc);
530 }
531
532 void
533 ffb_ras_fill(struct ffb_softc *sc)
534 {
535 ffb_ras_fifo_wait(sc, 2);
536 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
537 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
538 ffb_ras_wait(sc);
539 }
540
541 void
542 ffb_ras_copyrows(void *cookie, int src, int dst, int n)
543 {
544 struct rasops_info *ri = cookie;
545 struct ffb_softc *sc = ri->ri_hw;
546
547 if (dst == src)
548 return;
549 if (src < 0) {
550 n += src;
551 src = 0;
552 }
553 if ((src + n) > ri->ri_rows)
554 n = ri->ri_rows - src;
555 if (dst < 0) {
556 n += dst;
557 dst = 0;
558 }
559 if ((dst + n) > ri->ri_rows)
560 n = ri->ri_rows - dst;
561 if (n <= 0)
562 return;
563 n *= ri->ri_font->fontheight;
564 src *= ri->ri_font->fontheight;
565 dst *= ri->ri_font->fontheight;
566
567 ffb_ras_fifo_wait(sc, 8);
568 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_OLD | (FBC_ROP_OLD << 8));
569 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_VSCROLL);
570 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + src);
571 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
572 FBC_WRITE(sc, FFB_FBC_DY, ri->ri_yorigin + dst);
573 FBC_WRITE(sc, FFB_FBC_DX, ri->ri_xorigin);
574 FBC_WRITE(sc, FFB_FBC_BH, n);
575 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
576 ffb_ras_wait(sc);
577 }
578
579 void
580 ffb_ras_setfg(struct ffb_softc *sc, int32_t fg)
581 {
582 ffb_ras_fifo_wait(sc, 1);
583 if (fg == sc->sc_fg_cache)
584 return;
585 sc->sc_fg_cache = fg;
586 FBC_WRITE(sc, FFB_FBC_FG, fg);
587 ffb_ras_wait(sc);
588 }
589
590 /* frame buffer generic driver support functions */
591 static void
592 ffbfb_unblank(struct device *dev)
593 {
594 /* u_int on = 1; */
595
596 if (dev && dev->dv_xname)
597 printf("%s: ffbfb_unblank\n", dev->dv_xname);
598 else
599 printf("ffbfb_unblank(%p)n", dev);
600 /* ffb_blank((struct ffb_softc*)dev, WSDISPLAYIO_SVIDEO, &on); */
601 }
602
603 int
604 ffbfb_open(dev_t dev, int flags, int mode, struct proc *p)
605 {
606 int unit = minor(dev);
607
608 if (unit >= ffb_cd.cd_ndevs || ffb_cd.cd_devs[unit] == NULL)
609 return ENXIO;
610
611 return 0;
612 }
613
614 int
615 ffbfb_close(dev_t dev, int flags, int mode, struct proc *p)
616 {
617 return 0;
618 }
619
620 int
621 ffbfb_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
622 {
623 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)];
624
625 return ffb_ioctl(sc, cmd, data, flags, p);
626 }
627
628 paddr_t
629 ffbfb_mmap(dev_t dev, off_t off, int prot)
630 {
631 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)];
632 int i, reg;
633 off_t o;
634
635 /*
636 * off is a magic cookie (see xfree86/drivers/sunffb/ffb.h),
637 * which we map to an index into the "reg" property, and use
638 * our copy of the firmware data as arguments for the real
639 * mapping.
640 */
641 static struct { unsigned long voff; int reg; } map[] = {
642 { 0x00000000, FFB_REG_SFB8R },
643 { 0x00400000, FFB_REG_SFB8G },
644 { 0x00800000, FFB_REG_SFB8B },
645 { 0x00c00000, FFB_REG_SFB8X },
646 { 0x01000000, FFB_REG_SFB32 },
647 { 0x02000000, FFB_REG_SFB64 },
648 { 0x04000000, FFB_REG_FBC },
649 { 0x04004000, FFB_REG_DFB8R },
650 { 0x04404000, FFB_REG_DFB8G },
651 { 0x04804000, FFB_REG_DFB8B },
652 { 0x04c04000, FFB_REG_DFB8X },
653 { 0x05004000, FFB_REG_DFB24 },
654 { 0x06004000, FFB_REG_DFB32 },
655 { 0x07004000, FFB_REG_DFB422A },
656 { 0x0bc06000, FFB_REG_DAC },
657 { 0x0bc08000, FFB_REG_PROM },
658 };
659
660 /* special value "FFB_EXP_VOFF" - not backed by any "reg" entry */
661 if (off == 0x0bc18000)
662 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM],
663 0x00200000, prot, BUS_SPACE_MAP_LINEAR);
664
665 #define NELEMS(arr) (sizeof(arr)/sizeof((arr)[0]))
666
667 /* the map is ordered by voff */
668 for (i = 0; i < NELEMS(map); i++) {
669 if (map[i].voff > off)
670 break; /* beyound */
671 reg = map[i].reg;
672 if (map[i].voff + sc->sc_sizes[reg] < off)
673 continue; /* not there yet */
674 if (off > map[i].voff + sc->sc_sizes[reg])
675 break; /* out of range */
676 o = off - map[i].voff;
677 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[reg], o, prot,
678 BUS_SPACE_MAP_LINEAR);
679 }
680
681 return -1;
682 }
683