ffb.c revision 1.12 1 /* $NetBSD: ffb.c,v 1.12 2005/05/13 06:33:32 mhitch 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.12 2005/05/13 06:33:32 mhitch 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_type.fb_width = sc->sc_width;
196 sc->sc_fb.fb_type.fb_depth = sc->sc_depth;
197 sc->sc_fb.fb_type.fb_height = sc->sc_height;
198 sc->sc_fb.fb_device = &sc->sc_dv;
199 fb_attach(&sc->sc_fb, sc->sc_console);
200
201 if (sc->sc_console) {
202 int *ccolp, *crowp;
203 long defattr;
204
205 if (romgetcursoraddr(&crowp, &ccolp))
206 ccolp = crowp = NULL;
207 if (ccolp != NULL)
208 sc->sc_fb.fb_rinfo.ri_ccol = *ccolp;
209 if (crowp != NULL)
210 sc->sc_fb.fb_rinfo.ri_crow = *crowp;
211
212 sc->sc_fb.fb_rinfo.ri_ops.allocattr(&sc->sc_fb.fb_rinfo,
213 0, 0, 0, &defattr);
214
215 wsdisplay_cnattach(&ffb_stdscreen, &sc->sc_fb.fb_rinfo,
216 sc->sc_fb.fb_rinfo.ri_ccol, sc->sc_fb.fb_rinfo.ri_crow, defattr);
217 }
218
219 waa.console = sc->sc_console;
220 waa.scrdata = &ffb_screenlist;
221 waa.accessops = &ffb_accessops;
222 waa.accesscookie = sc;
223 config_found(&sc->sc_dv, &waa, wsemuldisplaydevprint);
224 }
225
226 int
227 ffb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
228 {
229 struct ffb_softc *sc = v;
230 struct wsdisplay_fbinfo *wdf;
231
232 #ifdef FFBDEBUG
233 printf("ffb_ioctl: %s cmd _IO%s%s('%c', %lu)\n",
234 sc->sc_dv.dv_xname,
235 (cmd & IOC_IN) ? "W" : "", (cmd & IOC_OUT) ? "R" : "",
236 (char)IOCGROUP(cmd), cmd & 0xff);
237 #endif
238
239 switch (cmd) {
240 case FBIOGTYPE:
241 *(struct fbtype *)data = sc->sc_fb.fb_type;
242 break;
243 case FBIOGATTR:
244 #define fba ((struct fbgattr *)data)
245 fba->real_type = sc->sc_fb.fb_type.fb_type;
246 fba->owner = 0; /* XXX ??? */
247 fba->fbtype = sc->sc_fb.fb_type;
248 fba->sattr.flags = 0;
249 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
250 fba->sattr.dev_specific[0] = -1;
251 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
252 fba->emu_types[1] = -1;
253 #undef fba
254 break;
255
256 case FBIOGETCMAP:
257 case FBIOPUTCMAP:
258 return EIO;
259
260 case FBIOGVIDEO:
261 case FBIOSVIDEO:
262 return ffb_blank(sc, cmd == FBIOGVIDEO?
263 WSDISPLAYIO_GVIDEO : WSDISPLAYIO_SVIDEO,
264 (u_int *)data);
265 break;
266 case FBIOGCURSOR:
267 printf("%s: FBIOGCURSOR not implemented\n", sc->sc_dv.dv_xname);
268 return EIO;
269 case FBIOSCURSOR:
270 printf("%s: FBIOSCURSOR not implemented\n", sc->sc_dv.dv_xname);
271 return EIO;
272 case FBIOGCURPOS:
273 printf("%s: FBIOGCURPOS not implemented\n", sc->sc_dv.dv_xname);
274 return EIO;
275 case FBIOSCURPOS:
276 printf("%s: FBIOSCURPOS not implemented\n", sc->sc_dv.dv_xname);
277 return EIO;
278 case FBIOGCURMAX:
279 printf("%s: FBIOGCURMAX not implemented\n", sc->sc_dv.dv_xname);
280 return EIO;
281
282 case WSDISPLAYIO_GTYPE:
283 *(u_int *)data = WSDISPLAY_TYPE_SUNFFB;
284 break;
285 case WSDISPLAYIO_SMODE:
286 sc->sc_mode = *(u_int *)data;
287 break;
288 case WSDISPLAYIO_GINFO:
289 wdf = (void *)data;
290 wdf->height = sc->sc_height;
291 wdf->width = sc->sc_width;
292 wdf->depth = 32;
293 wdf->cmsize = 256; /* XXX */
294 break;
295 #ifdef WSDISPLAYIO_LINEBYTES
296 case WSDISPLAYIO_LINEBYTES:
297 *(u_int *)data = sc->sc_linebytes;
298 break;
299 #endif
300 case WSDISPLAYIO_GETCMAP:
301 break;/* XXX */
302
303 case WSDISPLAYIO_PUTCMAP:
304 break;/* XXX */
305
306 case WSDISPLAYIO_SVIDEO:
307 case WSDISPLAYIO_GVIDEO:
308 return(ffb_blank(sc, cmd, (u_int *)data));
309 break;
310 case WSDISPLAYIO_GCURPOS:
311 case WSDISPLAYIO_SCURPOS:
312 case WSDISPLAYIO_GCURMAX:
313 case WSDISPLAYIO_GCURSOR:
314 case WSDISPLAYIO_SCURSOR:
315 return EIO; /* not supported yet */
316 default:
317 return EPASSTHROUGH;
318 }
319
320 return (0);
321 }
322
323 int
324 ffb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
325 int *curxp, int *curyp, long *attrp)
326 {
327 struct ffb_softc *sc = v;
328
329 if (sc->sc_nscreens > 0)
330 return (ENOMEM);
331
332 *cookiep = &sc->sc_fb.fb_rinfo;
333 *curyp = 0;
334 *curxp = 0;
335
336 sc->sc_fb.fb_rinfo.ri_ops.allocattr(&sc->sc_fb.fb_rinfo, 0, 0, 0, attrp);
337
338 sc->sc_nscreens++;
339 return (0);
340 }
341
342 /* blank/unblank the screen */
343 static int
344 ffb_blank(struct ffb_softc *sc, u_long cmd, u_int *data)
345 {
346 u_int val;
347
348 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
349 val = DAC_READ(sc, FFB_DAC_VALUE);
350
351 switch (cmd) {
352 case WSDISPLAYIO_GVIDEO:
353 *data = val & 1;
354 return(0);
355 break;
356 case WSDISPLAYIO_SVIDEO:
357 if (*data == WSDISPLAYIO_VIDEO_OFF)
358 val &= ~1;
359 else if (*data == WSDISPLAYIO_VIDEO_ON)
360 val |= 1;
361 else
362 return(EINVAL);
363 break;
364 default:
365 return(EINVAL);
366 }
367
368 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK);
369 DAC_WRITE(sc, FFB_DAC_VALUE, val);
370
371 return(0);
372 }
373
374 void
375 ffb_free_screen(void *v, void *cookie)
376 {
377 struct ffb_softc *sc = v;
378
379 sc->sc_nscreens--;
380 }
381
382 int
383 ffb_show_screen(void *v, void *cookie, int waitok,
384 void (*cb)(void *, int, int), void *cbarg)
385 {
386 return (0);
387 }
388
389 paddr_t
390 ffb_mmap(void *vsc, off_t off, int prot)
391 {
392 struct ffb_softc *sc = vsc;
393 int i;
394
395 switch (sc->sc_mode) {
396 case WSDISPLAYIO_MODE_MAPPED:
397 for (i = 0; i < sc->sc_nreg; i++) {
398 /* Before this set? */
399 if (off < sc->sc_addrs[i])
400 continue;
401 /* After this set? */
402 if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i]))
403 continue;
404
405 return (bus_space_mmap(sc->sc_bt, sc->sc_addrs[i],
406 off - sc->sc_addrs[i], prot, BUS_SPACE_MAP_LINEAR));
407 }
408 break;
409 #ifdef WSDISPLAYIO_MODE_DUMBFB
410 case WSDISPLAYIO_MODE_DUMBFB:
411 if (sc->sc_nreg < FFB_REG_DFB24)
412 break;
413 if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24])
414 return (bus_space_mmap(sc->sc_bt,
415 sc->sc_addrs[FFB_REG_DFB24], off, prot,
416 BUS_SPACE_MAP_LINEAR));
417 break;
418 #endif
419 }
420
421 return (-1);
422 }
423
424 void
425 ffb_ras_fifo_wait(struct ffb_softc *sc, int n)
426 {
427 int32_t cache = sc->sc_fifo_cache;
428
429 if (cache < n) {
430 do {
431 cache = FBC_READ(sc, FFB_FBC_UCSR);
432 cache = (cache & FBC_UCSR_FIFO_MASK) - 8;
433 } while (cache < n);
434 }
435 sc->sc_fifo_cache = cache - n;
436 }
437
438 void
439 ffb_ras_wait(struct ffb_softc *sc)
440 {
441 u_int32_t ucsr, r;
442
443 while (1) {
444 ucsr = FBC_READ(sc, FFB_FBC_UCSR);
445 if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0)
446 break;
447 r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL);
448 if (r != 0)
449 FBC_WRITE(sc, FFB_FBC_UCSR, r);
450 }
451 }
452
453 void
454 ffb_ras_init(struct ffb_softc *sc)
455 {
456 ffb_ras_fifo_wait(sc, 7);
457 FBC_WRITE(sc, FFB_FBC_PPC,
458 FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE |
459 FBC_PPC_APE_DIS | FBC_PPC_CS_CONST);
460 FBC_WRITE(sc, FFB_FBC_FBC,
461 FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH |
462 FFB_FBC_XE_OFF | FFB_FBC_RGBE_MASK);
463 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
464 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
465 FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff);
466 FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000);
467 sc->sc_fg_cache = 0;
468 FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache);
469 ffb_ras_wait(sc);
470 }
471
472 void
473 ffb_ras_eraserows(void *cookie, int row, int n, long attr)
474 {
475 struct rasops_info *ri = cookie;
476 struct ffb_softc *sc = ri->ri_hw;
477
478 if (row < 0) {
479 n += row;
480 row = 0;
481 }
482 if (row + n > ri->ri_rows)
483 n = ri->ri_rows - row;
484 if (n <= 0)
485 return;
486
487 ffb_ras_fill(sc);
488 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]);
489 ffb_ras_fifo_wait(sc, 4);
490 if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
491 FBC_WRITE(sc, FFB_FBC_BY, 0);
492 FBC_WRITE(sc, FFB_FBC_BX, 0);
493 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height);
494 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width);
495 } else {
496 row *= ri->ri_font->fontheight;
497 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
498 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
499 FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight);
500 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
501 }
502 ffb_ras_wait(sc);
503 }
504
505 void
506 ffb_ras_erasecols(void *cookie, int row, int col, int n, long attr)
507 {
508 struct rasops_info *ri = cookie;
509 struct ffb_softc *sc = ri->ri_hw;
510
511 if ((row < 0) || (row >= ri->ri_rows))
512 return;
513 if (col < 0) {
514 n += col;
515 col = 0;
516 }
517 if (col + n > ri->ri_cols)
518 n = ri->ri_cols - col;
519 if (n <= 0)
520 return;
521 n *= ri->ri_font->fontwidth;
522 col *= ri->ri_font->fontwidth;
523 row *= ri->ri_font->fontheight;
524
525 ffb_ras_fill(sc);
526 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]);
527 ffb_ras_fifo_wait(sc, 4);
528 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
529 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col);
530 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight);
531 FBC_WRITE(sc, FFB_FBC_BW, n - 1);
532 ffb_ras_wait(sc);
533 }
534
535 void
536 ffb_ras_fill(struct ffb_softc *sc)
537 {
538 ffb_ras_fifo_wait(sc, 2);
539 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
540 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
541 ffb_ras_wait(sc);
542 }
543
544 void
545 ffb_ras_copyrows(void *cookie, int src, int dst, int n)
546 {
547 struct rasops_info *ri = cookie;
548 struct ffb_softc *sc = ri->ri_hw;
549
550 if (dst == src)
551 return;
552 if (src < 0) {
553 n += src;
554 src = 0;
555 }
556 if ((src + n) > ri->ri_rows)
557 n = ri->ri_rows - src;
558 if (dst < 0) {
559 n += dst;
560 dst = 0;
561 }
562 if ((dst + n) > ri->ri_rows)
563 n = ri->ri_rows - dst;
564 if (n <= 0)
565 return;
566 n *= ri->ri_font->fontheight;
567 src *= ri->ri_font->fontheight;
568 dst *= ri->ri_font->fontheight;
569
570 ffb_ras_fifo_wait(sc, 8);
571 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_OLD | (FBC_ROP_OLD << 8));
572 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_VSCROLL);
573 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + src);
574 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
575 FBC_WRITE(sc, FFB_FBC_DY, ri->ri_yorigin + dst);
576 FBC_WRITE(sc, FFB_FBC_DX, ri->ri_xorigin);
577 FBC_WRITE(sc, FFB_FBC_BH, n);
578 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
579 ffb_ras_wait(sc);
580 }
581
582 void
583 ffb_ras_setfg(struct ffb_softc *sc, int32_t fg)
584 {
585 ffb_ras_fifo_wait(sc, 1);
586 if (fg == sc->sc_fg_cache)
587 return;
588 sc->sc_fg_cache = fg;
589 FBC_WRITE(sc, FFB_FBC_FG, fg);
590 ffb_ras_wait(sc);
591 }
592
593 /* frame buffer generic driver support functions */
594 static void
595 ffbfb_unblank(struct device *dev)
596 {
597 /* u_int on = 1; */
598
599 if (dev && dev->dv_xname)
600 printf("%s: ffbfb_unblank\n", dev->dv_xname);
601 else
602 printf("ffbfb_unblank(%p)n", dev);
603 /* ffb_blank((struct ffb_softc*)dev, WSDISPLAYIO_SVIDEO, &on); */
604 }
605
606 int
607 ffbfb_open(dev_t dev, int flags, int mode, struct proc *p)
608 {
609 int unit = minor(dev);
610
611 if (unit >= ffb_cd.cd_ndevs || ffb_cd.cd_devs[unit] == NULL)
612 return ENXIO;
613
614 return 0;
615 }
616
617 int
618 ffbfb_close(dev_t dev, int flags, int mode, struct proc *p)
619 {
620 return 0;
621 }
622
623 int
624 ffbfb_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
625 {
626 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)];
627
628 return ffb_ioctl(sc, cmd, data, flags, p);
629 }
630
631 paddr_t
632 ffbfb_mmap(dev_t dev, off_t off, int prot)
633 {
634 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)];
635 int i, reg;
636 off_t o;
637
638 /*
639 * off is a magic cookie (see xfree86/drivers/sunffb/ffb.h),
640 * which we map to an index into the "reg" property, and use
641 * our copy of the firmware data as arguments for the real
642 * mapping.
643 */
644 static struct { unsigned long voff; int reg; } map[] = {
645 { 0x00000000, FFB_REG_SFB8R },
646 { 0x00400000, FFB_REG_SFB8G },
647 { 0x00800000, FFB_REG_SFB8B },
648 { 0x00c00000, FFB_REG_SFB8X },
649 { 0x01000000, FFB_REG_SFB32 },
650 { 0x02000000, FFB_REG_SFB64 },
651 { 0x04000000, FFB_REG_FBC },
652 { 0x04004000, FFB_REG_DFB8R },
653 { 0x04404000, FFB_REG_DFB8G },
654 { 0x04804000, FFB_REG_DFB8B },
655 { 0x04c04000, FFB_REG_DFB8X },
656 { 0x05004000, FFB_REG_DFB24 },
657 { 0x06004000, FFB_REG_DFB32 },
658 { 0x07004000, FFB_REG_DFB422A },
659 { 0x0bc06000, FFB_REG_DAC },
660 { 0x0bc08000, FFB_REG_PROM },
661 };
662
663 /* special value "FFB_EXP_VOFF" - not backed by any "reg" entry */
664 if (off == 0x0bc18000)
665 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM],
666 0x00200000, prot, BUS_SPACE_MAP_LINEAR);
667
668 #define NELEMS(arr) (sizeof(arr)/sizeof((arr)[0]))
669
670 /* the map is ordered by voff */
671 for (i = 0; i < NELEMS(map); i++) {
672 if (map[i].voff > off)
673 break; /* beyound */
674 reg = map[i].reg;
675 if (map[i].voff + sc->sc_sizes[reg] < off)
676 continue; /* not there yet */
677 if (off > map[i].voff + sc->sc_sizes[reg])
678 break; /* out of range */
679 o = off - map[i].voff;
680 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[reg], o, prot,
681 BUS_SPACE_MAP_LINEAR);
682 }
683
684 return -1;
685 }
686