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