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@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