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