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