1 /* $NetBSD: ffb.c,v 1.21 2005/12/12 02:44:31 christos 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.21 2005/12/12 02:44:31 christos 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 <sparc64/dev/ffbreg.h> 58 #include <sparc64/dev/ffbvar.h> 59 60 #include <dev/wsfont/wsfont.h> 61 62 #ifndef WS_DEFAULT_BG 63 /* Sun -> background should be white */ 64 #define WS_DEFAULT_BG 0xf 65 #endif 66 67 extern struct cfdriver ffb_cd; 68 69 struct wsscreen_descr ffb_stdscreen = { 70 "sunffb", 71 0, 0, /* will be filled in -- XXX shouldn't, it's global. */ 72 0, 73 0, 0, 74 WSSCREEN_REVERSE | WSSCREEN_WSCOLORS 75 }; 76 77 const struct wsscreen_descr *ffb_scrlist[] = { 78 &ffb_stdscreen, 79 /* XXX other formats? */ 80 }; 81 82 struct wsscreen_list ffb_screenlist = { 83 sizeof(ffb_scrlist) / sizeof(struct wsscreen_descr *), 84 ffb_scrlist 85 }; 86 87 static struct ffb_screen ffb_console_screen; 88 89 int ffb_ioctl(void *, u_long, caddr_t, int, struct lwp *); 90 static int ffb_blank(struct ffb_softc *, u_long, u_int *); 91 paddr_t ffb_mmap(void *, off_t, int); 92 void ffb_ras_fifo_wait(struct ffb_softc *, int); 93 void ffb_ras_wait(struct ffb_softc *); 94 void ffb_ras_init(struct ffb_softc *); 95 void ffb_ras_copyrows(void *, int, int, int); 96 void ffb_ras_copycols(void *, int, 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 int ffb_alloc_screen(void *, const struct wsscreen_descr *, void **, 104 int *, int *, long *); 105 void ffb_free_screen(void *, void *); 106 int ffb_show_screen(void *, void *, int, void (*)(void *, int, int), 107 void *); 108 void ffb_switch_screen(struct ffb_softc *); 109 void ffb_restore_screen(struct ffb_screen *, 110 const struct wsscreen_descr *, u_int16_t *); 111 void ffb_clearscreen(struct ffb_softc *); 112 int ffb_load_font(void *, void *, struct wsdisplay_font *); 113 void ffb_init_screen(struct ffb_softc *, struct ffb_screen *, int, 114 long *); 115 int ffb_allocattr(void *, int, int, int, long *); 116 void ffb_putchar(void *, int, int, u_int, long); 117 void ffb_cursor(void *, int, int, int); 118 119 /* frame buffer generic driver */ 120 static void ffbfb_unblank(struct device*); 121 dev_type_open(ffbfb_open); 122 dev_type_close(ffbfb_close); 123 dev_type_ioctl(ffbfb_ioctl); 124 dev_type_mmap(ffbfb_mmap); 125 126 static struct fbdriver ffb_fbdriver = { 127 ffbfb_unblank, ffbfb_open, ffbfb_close, ffbfb_ioctl, nopoll, 128 ffbfb_mmap, nokqfilter 129 }; 130 131 struct wsdisplay_accessops ffb_accessops = { 132 ffb_ioctl, 133 ffb_mmap, 134 ffb_alloc_screen, 135 ffb_free_screen, 136 ffb_show_screen, 137 NULL, /* load font */ 138 NULL, /* pollc */ 139 NULL, /* getwschar */ 140 NULL, /* putwschar */ 141 NULL, /* scroll */ 142 }; 143 144 void 145 ffb_attach(struct ffb_softc *sc) 146 { 147 struct wsemuldisplaydev_attach_args waa; 148 struct rasops_info *ri; 149 long defattr; 150 const char *model; 151 int btype; 152 int maxrow, maxcol; 153 u_int blank = WSDISPLAYIO_VIDEO_ON; 154 char buf[6+1]; 155 156 printf(":"); 157 158 sc->putchar = NULL; 159 sc->copycols = NULL; 160 161 if (sc->sc_type == FFB_CREATOR) { 162 btype = prom_getpropint(sc->sc_node, "board_type", 0); 163 if ((btype & 7) == 3) 164 printf(" Creator3D"); 165 else 166 printf(" Creator"); 167 } else 168 printf(" Elite3D"); 169 170 model = prom_getpropstring(sc->sc_node, "model"); 171 if (model == NULL || strlen(model) == 0) 172 model = "unknown"; 173 174 sc->sc_depth = 24; 175 sc->sc_linebytes = 8192; 176 sc->sc_height = prom_getpropint(sc->sc_node, "height", 0); 177 sc->sc_width = prom_getpropint(sc->sc_node, "width", 0); 178 179 maxcol = (prom_getoption("screen-#columns", buf, sizeof buf) == 0) 180 ? strtoul(buf, NULL, 10) 181 : 80; 182 183 maxrow = (prom_getoption("screen-#rows", buf, sizeof buf) != 0) 184 ? strtoul(buf, NULL, 10) 185 : 34; 186 187 ffb_ras_init(sc); 188 189 /* collect DAC version, as Elite3D cursor enable bit is reversed */ 190 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GVERS); 191 sc->sc_dacrev = DAC_READ(sc, FFB_DAC_VALUE) >> 28; 192 193 if (sc->sc_type == FFB_AFB) 194 sc->sc_dacrev = 10; 195 printf(", model %s, dac %u\n", model, sc->sc_dacrev); 196 197 ffb_blank(sc, WSDISPLAYIO_SVIDEO, &blank); 198 199 sc->sc_accel = ((sc->sc_dv.dv_cfdata->cf_flags & FFB_CFFLAG_NOACCEL) == 200 0); 201 202 wsfont_init(); 203 204 /* we mess with ffb_console_screen only once */ 205 if (sc->sc_console) { 206 ffb_init_screen(sc, &ffb_console_screen, 1, &defattr); 207 ffb_console_screen.active = 1; 208 sc->active = &ffb_console_screen; 209 } 210 ri = &ffb_console_screen.ri; 211 212 ffb_stdscreen.nrows = ri->ri_rows; 213 ffb_stdscreen.ncols = ri->ri_cols; 214 ffb_stdscreen.textops = &ri->ri_ops; 215 ffb_stdscreen.capabilities = ri->ri_caps; 216 217 sc->sc_fb.fb_driver = &ffb_fbdriver; 218 sc->sc_fb.fb_type.fb_cmsize = 0; 219 sc->sc_fb.fb_type.fb_size = maxrow * sc->sc_linebytes; 220 sc->sc_fb.fb_type.fb_type = FBTYPE_CREATOR; 221 sc->sc_fb.fb_type.fb_width = sc->sc_width; 222 sc->sc_fb.fb_type.fb_depth = sc->sc_depth; 223 sc->sc_fb.fb_type.fb_height = sc->sc_height; 224 sc->sc_fb.fb_device = &sc->sc_dv; 225 fb_attach(&sc->sc_fb, sc->sc_console); 226 227 if (sc->sc_console) { 228 wsdisplay_cnattach(&ffb_stdscreen, ri, 0, 0, defattr); 229 } 230 231 ffb_clearscreen(sc); 232 233 waa.console = sc->sc_console; 234 waa.scrdata = &ffb_screenlist; 235 waa.accessops = &ffb_accessops; 236 waa.accesscookie = sc; 237 config_found(&sc->sc_dv, &waa, wsemuldisplaydevprint); 238 } 239 240 int 241 ffb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct lwp *l) 242 { 243 struct ffb_softc *sc = v; 244 struct wsdisplay_fbinfo *wdf; 245 struct ffb_screen *ms = sc->active; 246 247 #ifdef FFBDEBUG 248 printf("ffb_ioctl: %s cmd _IO%s%s('%c', %lu)\n", 249 sc->sc_dv.dv_xname, 250 (cmd & IOC_IN) ? "W" : "", (cmd & IOC_OUT) ? "R" : "", 251 (char)IOCGROUP(cmd), cmd & 0xff); 252 #endif 253 254 switch (cmd) { 255 case FBIOGTYPE: 256 *(struct fbtype *)data = sc->sc_fb.fb_type; 257 break; 258 case FBIOGATTR: 259 #define fba ((struct fbgattr *)data) 260 fba->real_type = sc->sc_fb.fb_type.fb_type; 261 fba->owner = 0; /* XXX ??? */ 262 fba->fbtype = sc->sc_fb.fb_type; 263 fba->sattr.flags = 0; 264 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 265 fba->sattr.dev_specific[0] = -1; 266 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 267 fba->emu_types[1] = -1; 268 #undef fba 269 break; 270 271 case FBIOGETCMAP: 272 case FBIOPUTCMAP: 273 return EIO; 274 275 case FBIOGVIDEO: 276 case FBIOSVIDEO: 277 return ffb_blank(sc, cmd == FBIOGVIDEO? 278 WSDISPLAYIO_GVIDEO : WSDISPLAYIO_SVIDEO, 279 (u_int *)data); 280 break; 281 case FBIOGCURSOR: 282 case FBIOSCURSOR: 283 /* the console driver is not using the hardware cursor */ 284 break; 285 case FBIOGCURPOS: 286 printf("%s: FBIOGCURPOS not implemented\n", sc->sc_dv.dv_xname); 287 return EIO; 288 case FBIOSCURPOS: 289 printf("%s: FBIOSCURPOS not implemented\n", sc->sc_dv.dv_xname); 290 return EIO; 291 case FBIOGCURMAX: 292 printf("%s: FBIOGCURMAX not implemented\n", sc->sc_dv.dv_xname); 293 return EIO; 294 295 case WSDISPLAYIO_GTYPE: 296 *(u_int *)data = WSDISPLAY_TYPE_SUNFFB; 297 break; 298 case WSDISPLAYIO_SMODE: 299 { 300 if (sc->sc_mode != *(u_int *)data) { 301 sc->sc_mode = *(u_int *)data; 302 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 303 ffb_ras_init(sc); 304 ffb_restore_screen(ms, ms->type, 305 ms->chars); 306 ffb_cursor(ms, ms->cursoron, 307 ms->cursorrow, 308 ms->cursorcol); 309 } 310 } 311 } 312 break; 313 case WSDISPLAYIO_GINFO: 314 wdf = (void *)data; 315 wdf->height = sc->sc_height; 316 wdf->width = sc->sc_width; 317 wdf->depth = 32; 318 wdf->cmsize = 256; /* XXX */ 319 break; 320 #ifdef WSDISPLAYIO_LINEBYTES 321 case WSDISPLAYIO_LINEBYTES: 322 *(u_int *)data = sc->sc_linebytes; 323 break; 324 #endif 325 case WSDISPLAYIO_GETCMAP: 326 break;/* XXX */ 327 328 case WSDISPLAYIO_PUTCMAP: 329 break;/* XXX */ 330 331 case WSDISPLAYIO_SVIDEO: 332 case WSDISPLAYIO_GVIDEO: 333 return(ffb_blank(sc, cmd, (u_int *)data)); 334 break; 335 case WSDISPLAYIO_GCURPOS: 336 case WSDISPLAYIO_SCURPOS: 337 case WSDISPLAYIO_GCURMAX: 338 case WSDISPLAYIO_GCURSOR: 339 case WSDISPLAYIO_SCURSOR: 340 return EIO; /* not supported yet */ 341 default: 342 return EPASSTHROUGH; 343 } 344 345 return (0); 346 } 347 348 /* blank/unblank the screen */ 349 static int 350 ffb_blank(struct ffb_softc *sc, u_long cmd, u_int *data) 351 { 352 u_int val; 353 354 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK); 355 val = DAC_READ(sc, FFB_DAC_VALUE); 356 357 switch (cmd) { 358 case WSDISPLAYIO_GVIDEO: 359 *data = val & 1; 360 return(0); 361 break; 362 case WSDISPLAYIO_SVIDEO: 363 if (*data == WSDISPLAYIO_VIDEO_OFF) 364 val &= ~1; 365 else if (*data == WSDISPLAYIO_VIDEO_ON) 366 val |= 1; 367 else 368 return(EINVAL); 369 break; 370 default: 371 return(EINVAL); 372 } 373 374 DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_GSBLANK); 375 DAC_WRITE(sc, FFB_DAC_VALUE, val); 376 377 return(0); 378 } 379 380 paddr_t 381 ffb_mmap(void *vsc, off_t off, int prot) 382 { 383 struct ffb_softc *sc = vsc; 384 int i; 385 386 switch (sc->sc_mode) { 387 case WSDISPLAYIO_MODE_MAPPED: 388 for (i = 0; i < sc->sc_nreg; i++) { 389 /* Before this set? */ 390 if (off < sc->sc_addrs[i]) 391 continue; 392 /* After this set? */ 393 if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i])) 394 continue; 395 396 return (bus_space_mmap(sc->sc_bt, sc->sc_addrs[i], 397 off - sc->sc_addrs[i], prot, BUS_SPACE_MAP_LINEAR)); 398 } 399 break; 400 #ifdef WSDISPLAYIO_MODE_DUMBFB 401 case WSDISPLAYIO_MODE_DUMBFB: 402 if (sc->sc_nreg < FFB_REG_DFB24) 403 break; 404 if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24]) 405 return (bus_space_mmap(sc->sc_bt, 406 sc->sc_addrs[FFB_REG_DFB24], off, prot, 407 BUS_SPACE_MAP_LINEAR)); 408 break; 409 #endif 410 } 411 412 return (-1); 413 } 414 415 void 416 ffb_ras_fifo_wait(struct ffb_softc *sc, int n) 417 { 418 int32_t cache = sc->sc_fifo_cache; 419 420 if (cache < n) { 421 do { 422 cache = FBC_READ(sc, FFB_FBC_UCSR); 423 cache = (cache & FBC_UCSR_FIFO_MASK) - 8; 424 } while (cache < n); 425 } 426 sc->sc_fifo_cache = cache - n; 427 } 428 429 void 430 ffb_ras_wait(struct ffb_softc *sc) 431 { 432 u_int32_t ucsr, r; 433 434 while (1) { 435 ucsr = FBC_READ(sc, FFB_FBC_UCSR); 436 if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0) 437 break; 438 r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL); 439 if (r != 0) 440 FBC_WRITE(sc, FFB_FBC_UCSR, r); 441 } 442 } 443 444 void 445 ffb_ras_init(struct ffb_softc *sc) 446 { 447 ffb_ras_fifo_wait(sc, 7); 448 FBC_WRITE(sc, FFB_FBC_PPC, 449 FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE | 450 FBC_PPC_APE_DIS | FBC_PPC_CS_CONST); 451 FBC_WRITE(sc, FFB_FBC_FBC, 452 FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH | 453 FFB_FBC_XE_OFF | FFB_FBC_RGBE_MASK); 454 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW); 455 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE); 456 FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff); 457 FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000); 458 sc->sc_fg_cache = 0; 459 FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache); 460 ffb_ras_wait(sc); 461 } 462 463 void 464 ffb_ras_eraserows(void *cookie, int row, int n, long attr) 465 { 466 struct rasops_info *ri = cookie; 467 struct ffb_screen *scr = ri->ri_hw; 468 struct ffb_softc *sc = scr->sc;; 469 470 int start, end, i; 471 472 start = ri->ri_cols * row; 473 end = ri->ri_cols * (row + n); 474 475 for (i = start; i < end; i++) { 476 scr->attrs[i] = attr; 477 scr->chars[i] = 0x20; 478 } 479 480 if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 481 if (row < 0) { 482 n += row; 483 row = 0; 484 } 485 if (row + n > ri->ri_rows) 486 n = ri->ri_rows - row; 487 if (n <= 0) 488 return; 489 490 ffb_ras_fill(sc); 491 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]); 492 ffb_ras_fifo_wait(sc, 4); 493 if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) { 494 FBC_WRITE(sc, FFB_FBC_BY, 0); 495 FBC_WRITE(sc, FFB_FBC_BX, 0); 496 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height); 497 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width); 498 } else { 499 row *= ri->ri_font->fontheight; 500 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row); 501 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin); 502 FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight); 503 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth); 504 } 505 ffb_ras_wait(sc); 506 } 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_screen *scr = ri->ri_hw; 514 struct ffb_softc *sc = scr->sc;; 515 516 int start = col + row * ri->ri_cols; 517 int end = start + n, i; 518 519 for (i = start; i < end; i++) { 520 scr->attrs[i] = attr; 521 scr->chars[i] = 0x20; 522 } 523 if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 524 525 if ((row < 0) || (row >= ri->ri_rows)) 526 return; 527 if (col < 0) { 528 n += col; 529 col = 0; 530 } 531 if (col + n > ri->ri_cols) 532 n = ri->ri_cols - col; 533 if (n <= 0) 534 return; 535 n *= ri->ri_font->fontwidth; 536 col *= ri->ri_font->fontwidth; 537 row *= ri->ri_font->fontheight; 538 539 ffb_ras_fill(sc); 540 ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]); 541 ffb_ras_fifo_wait(sc, 4); 542 FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row); 543 FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col); 544 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight); 545 FBC_WRITE(sc, FFB_FBC_BW, n - 1); 546 ffb_ras_wait(sc); 547 } 548 } 549 550 void 551 ffb_ras_fill(struct ffb_softc *sc) 552 { 553 ffb_ras_fifo_wait(sc, 2); 554 FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW); 555 FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE); 556 ffb_ras_wait(sc); 557 } 558 559 void 560 ffb_ras_copyrows(void *cookie, int src, int dst, int n) 561 { 562 struct rasops_info *ri = cookie; 563 struct ffb_screen *scr = ri->ri_hw; 564 struct ffb_softc *sc = scr->sc; 565 566 int from, to, len; 567 568 from = ri->ri_cols * src; 569 to = ri->ri_cols * dst; 570 len = ri->ri_cols * n; 571 572 memmove(&scr->attrs[to], &scr->attrs[from], len * sizeof(long)); 573 memmove(&scr->chars[to], &scr->chars[from], len * sizeof(uint16_t)); 574 575 if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 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 ffb_ras_wait(sc); 607 } 608 } 609 610 void 611 ffb_ras_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 612 { 613 struct rasops_info *ri = cookie; 614 struct ffb_screen *scr = ri->ri_hw; 615 struct ffb_softc *sc = scr->sc; 616 int from = srccol + row * ri->ri_cols; 617 int to = dstcol + row * ri->ri_cols; 618 619 memmove(&scr->attrs[to], &scr->attrs[from], ncols * sizeof(long)); 620 memmove(&scr->chars[to], &scr->chars[from], ncols * sizeof(uint16_t)); 621 622 if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 623 ffb_ras_wait(sc); 624 sc->copycols(cookie, row, srccol, dstcol, ncols); 625 } 626 } 627 628 void 629 ffb_ras_setfg(struct ffb_softc *sc, int32_t fg) 630 { 631 ffb_ras_fifo_wait(sc, 1); 632 if (fg == sc->sc_fg_cache) 633 return; 634 sc->sc_fg_cache = fg; 635 FBC_WRITE(sc, FFB_FBC_FG, fg); 636 ffb_ras_wait(sc); 637 } 638 639 /* frame buffer generic driver support functions */ 640 static void 641 ffbfb_unblank(struct device *dev) 642 { 643 /* u_int on = 1; */ 644 645 if (dev && dev->dv_xname) 646 printf("%s: ffbfb_unblank\n", dev->dv_xname); 647 else 648 printf("ffbfb_unblank(%p)n", dev); 649 /* ffb_blank((struct ffb_softc*)dev, WSDISPLAYIO_SVIDEO, &on); */ 650 } 651 652 int 653 ffbfb_open(dev_t dev, int flags, int mode, struct lwp *l) 654 { 655 int unit = minor(dev); 656 657 if (unit >= ffb_cd.cd_ndevs || ffb_cd.cd_devs[unit] == NULL) 658 return ENXIO; 659 660 return 0; 661 } 662 663 int 664 ffbfb_close(dev_t dev, int flags, int mode, struct lwp *l) 665 { 666 return 0; 667 } 668 669 int 670 ffbfb_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct lwp *l) 671 { 672 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)]; 673 674 return ffb_ioctl(sc, cmd, data, flags, l); 675 } 676 677 paddr_t 678 ffbfb_mmap(dev_t dev, off_t off, int prot) 679 { 680 struct ffb_softc *sc = ffb_cd.cd_devs[minor(dev)]; 681 uint64_t size; 682 int i, reg; 683 off_t o; 684 685 /* 686 * off is a magic cookie (see xfree86/drivers/sunffb/ffb.h), 687 * which we map to an index into the "reg" property, and use 688 * our copy of the firmware data as arguments for the real 689 * mapping. 690 */ 691 static struct { unsigned long voff; int reg; } map[] = { 692 { 0x00000000, FFB_REG_SFB8R }, 693 { 0x00400000, FFB_REG_SFB8G }, 694 { 0x00800000, FFB_REG_SFB8B }, 695 { 0x00c00000, FFB_REG_SFB8X }, 696 { 0x01000000, FFB_REG_SFB32 }, 697 { 0x02000000, FFB_REG_SFB64 }, 698 { 0x04000000, FFB_REG_FBC }, 699 { 0x04004000, FFB_REG_DFB8R }, 700 { 0x04404000, FFB_REG_DFB8G }, 701 { 0x04804000, FFB_REG_DFB8B }, 702 { 0x04c04000, FFB_REG_DFB8X }, 703 { 0x05004000, FFB_REG_DFB24 }, 704 { 0x06004000, FFB_REG_DFB32 }, 705 { 0x07004000, FFB_REG_DFB422A }, 706 { 0x0bc06000, FFB_REG_DAC }, 707 { 0x0bc08000, FFB_REG_PROM }, 708 { 0x0bc18000, 0 } 709 }; 710 711 /* special value "FFB_EXP_VOFF" - not backed by any "reg" entry */ 712 if (off == 0x0bc18000) 713 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM], 714 0x00200000, prot, BUS_SPACE_MAP_LINEAR); 715 716 /* 717 * FFB_VOFF_FBC_KREGS - used by afbinit to upload firmware. We should 718 * probably mmap them only on afb boards 719 */ 720 if ((off >= 0x0bc04000) && (off < 0x0bc06000)) 721 return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM], 722 0x00610000 + (off - 0x0bc04000), prot, 723 BUS_SPACE_MAP_LINEAR); 724 725 #define NELEMS(arr) (sizeof(arr)/sizeof((arr)[0])) 726 727 /* the map is ordered by voff */ 728 for (i = 0; i < NELEMS(map)-1; i++) { 729 reg = map[i].reg; 730 /* the number of entries in reg seems to vary */ 731 if (reg < sc->sc_nreg) { 732 size = min((map[i + 1].voff - map[i].voff), 733 sc->sc_sizes[reg]); 734 if ((off >= map[i].voff) && 735 (off < (map[i].voff + size))) { 736 o = off - map[i].voff; 737 return bus_space_mmap(sc->sc_bt, 738 sc->sc_addrs[reg], o, prot, 739 BUS_SPACE_MAP_LINEAR); 740 } 741 } 742 } 743 744 return -1; 745 } 746 747 void 748 ffb_clearscreen(struct ffb_softc *sc) 749 { 750 struct rasops_info *ri = &ffb_console_screen.ri; 751 ffb_ras_fill(sc); 752 ffb_ras_setfg(sc, ri->ri_devcmap[WS_DEFAULT_BG]); 753 ffb_ras_fifo_wait(sc, 4); 754 FBC_WRITE(sc, FFB_FBC_BY, 0); 755 FBC_WRITE(sc, FFB_FBC_BX, 0); 756 FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height); 757 FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width); 758 } 759 760 void 761 ffb_switch_screen(struct ffb_softc *sc) 762 { 763 struct ffb_screen *scr, *oldscr; 764 765 scr = sc->wanted; 766 if (!scr) { 767 printf("ffb_switch_screen: disappeared\n"); 768 (*sc->switchcb)(sc->switchcbarg, EIO, 0); 769 return; 770 } 771 oldscr = sc->active; /* can be NULL! */ 772 #ifdef DIAGNOSTIC 773 if (oldscr) { 774 if (!oldscr->active) 775 panic("ffb_switch_screen: not active"); 776 } 777 #endif 778 if (scr == oldscr) 779 return; 780 781 #ifdef DIAGNOSTIC 782 if (scr->active) 783 panic("ffb_switch_screen: active"); 784 #endif 785 786 if (oldscr) 787 oldscr->active = 0; 788 #ifdef notyet 789 if (sc->currenttype != type) { 790 ffb_set_screentype(sc, type); 791 sc->currenttype = type; 792 } 793 #endif 794 795 /* Clear the entire screen. */ 796 797 scr->active = 1; 798 ffb_restore_screen(scr, &ffb_stdscreen, scr->chars); 799 800 sc->active = scr; 801 802 scr->ri.ri_ops.cursor(scr, scr->cursoron, scr->cursorrow, 803 scr->cursorcol); 804 805 sc->wanted = 0; 806 if (sc->switchcb) 807 (*sc->switchcb)(sc->switchcbarg, 0, 0); 808 } 809 810 void 811 ffb_restore_screen(struct ffb_screen *scr, 812 const struct wsscreen_descr *type, u_int16_t *mem) 813 { 814 int i, j, offset = 0; 815 uint16_t *charptr = scr->chars; 816 long *attrptr = scr->attrs; 817 818 ffb_clearscreen(scr->sc); 819 ffb_ras_wait(scr->sc); 820 for (i = 0; i < scr->ri.ri_rows; i++) { 821 for (j = 0; j < scr->ri.ri_cols; j++) { 822 scr->sc->putchar(scr, i, j, charptr[offset], 823 attrptr[offset]); 824 offset++; 825 } 826 } 827 scr->cursordrawn = 0; 828 } 829 830 void 831 ffb_cursor(void *cookie, int on, int row, int col) 832 { 833 struct rasops_info *ri = cookie; 834 struct ffb_screen *scr = ri->ri_hw; 835 struct ffb_softc *sc = scr->sc; 836 int x, y, wi, he, coffset; 837 838 wi = ri->ri_font->fontwidth; 839 he = ri->ri_font->fontheight; 840 841 if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 842 x = scr->cursorcol * wi + ri->ri_xorigin; 843 y = scr->cursorrow * he + ri->ri_yorigin; 844 845 if (scr->cursordrawn) { 846 /* remove cursor */ 847 coffset = scr->cursorcol + 848 (scr->cursorrow * ri->ri_cols); 849 ffb_ras_wait(sc); 850 sc->putchar(cookie, scr->cursorrow, scr->cursorcol, 851 scr->chars[coffset], scr->attrs[coffset]); 852 scr->cursordrawn = 0; 853 } 854 scr->cursorrow = row; 855 scr->cursorcol = col; 856 if ((scr->cursoron = on) != 0) 857 { 858 long attr, revattr; 859 x = scr->cursorcol * wi + ri->ri_xorigin; 860 y = scr->cursorrow * he + ri->ri_yorigin; 861 coffset = col + (row * ri->ri_cols); 862 attr = scr->attrs[coffset]; 863 #ifdef FFB_CURSOR_SWAP_COLOURS 864 revattr=((attr >> 8 ) & 0x000f0000) | ((attr & 865 0x000f0000)<<8) | (attr & 0x0000ffff); 866 #else 867 revattr = attr ^ 0xffff0000; 868 #endif 869 ffb_ras_wait(sc); 870 sc->putchar(cookie, scr->cursorrow, scr->cursorcol, 871 scr->chars[coffset], revattr); 872 scr->cursordrawn = 1; 873 } 874 } else { 875 scr->cursoron = on; 876 scr->cursorrow = row; 877 scr->cursorcol = col; 878 scr->cursordrawn = 0; 879 } 880 } 881 882 void 883 ffb_putchar(void *cookie, int row, int col, u_int c, long attr) 884 { 885 struct rasops_info *ri = cookie; 886 struct ffb_screen *scr = ri->ri_hw; 887 struct ffb_softc *sc = scr->sc; 888 int pos; 889 890 if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) && 891 (col < ri->ri_cols)) { 892 pos = col + row * ri->ri_cols; 893 scr->attrs[pos] = attr; 894 scr->chars[pos] = c; 895 896 #if 1 897 if ((sc->putchar != NULL) && ( scr->active) && 898 (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 899 ffb_ras_wait(sc); 900 sc->putchar(cookie, row, col, c, attr); 901 } 902 #else 903 if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 904 int fg, bg, uc, i; 905 uint8_t *data; 906 int x, y, wi,he; 907 908 wi = ri->ri_font->fontwidth; 909 he = ri->ri_font->fontheight; 910 911 if (!CHAR_IN_FONT(c, ri->ri_font)) 912 return; 913 bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xff]; 914 fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xff]; 915 x = ri->ri_xorigin + col * wi; 916 y = ri->ri_yorigin + row * he; 917 if (c == 0x20) { 918 ffb_rectfill(sc, x, y, wi, he, bg); 919 } else { 920 uc = c-ri->ri_font->firstchar; 921 data = (uint8_t *)ri->ri_font->data + uc * 922 ri->ri_fontscale; 923 924 ffb_setup_mono(sc, x, y, wi, 1, fg, bg); 925 for (i = 0; i < he; i++) { 926 ffb_feed_line(sc, ri->ri_font->stride, 927 data); 928 data += ri->ri_font->stride; 929 } 930 /*ffb_ras_wait(sc);*/ 931 } 932 } 933 #endif 934 } 935 } 936 937 int 938 ffb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp) 939 { 940 if ((fg == 0) && (bg == 0)) 941 { 942 fg = WS_DEFAULT_FG; 943 bg = WS_DEFAULT_BG; 944 } 945 if (flags & WSATTR_REVERSE) { 946 *attrp = (bg & 0xff) << 24 | (fg & 0xff) << 16 | 947 (flags & 0xff); 948 } else 949 *attrp = (fg & 0xff) << 24 | (bg & 0xff) << 16 | 950 (flags & 0xff); 951 return 0; 952 } 953 954 void 955 ffb_init_screen(struct ffb_softc *sc, struct ffb_screen *scr, 956 int existing, long *defattr) 957 { 958 struct rasops_info *ri = &scr->ri; 959 int cnt; 960 961 scr->sc = sc; 962 scr->cursorcol = 0; 963 scr->cursorrow = 0; 964 scr->cursordrawn=0; 965 966 ri->ri_depth = 32; 967 ri->ri_width = sc->sc_width; 968 ri->ri_height = sc->sc_height; 969 ri->ri_stride = sc->sc_linebytes; 970 ri->ri_flg = RI_CENTER; 971 972 ri->ri_bits = bus_space_vaddr(sc->sc_bt, sc->sc_pixel_h); 973 974 #ifdef DEBUG_FFB 975 printf("addr: %08lx\n",(ulong)ri->ri_bits); 976 #endif 977 rasops_init(ri, sc->sc_height/8, sc->sc_width/8); 978 ri->ri_caps = WSSCREEN_WSCOLORS; 979 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 980 sc->sc_width / ri->ri_font->fontwidth); 981 982 ffb_allocattr(ri, WS_DEFAULT_FG, WS_DEFAULT_BG, 0, defattr); 983 984 /* 985 * we allocate both chars and attributes in one chunk, attributes first 986 * because they have the (potentially) bigger alignment 987 */ 988 cnt=ri->ri_rows * ri->ri_cols; 989 scr->attrs = (long *)malloc(cnt * (sizeof(long) + sizeof(uint16_t)), 990 M_DEVBUF, M_WAITOK); 991 scr->chars = (uint16_t *)&scr->attrs[cnt]; 992 993 /* enable acceleration */ 994 ri->ri_hw = scr; 995 ri->ri_ops.copyrows = ffb_ras_copyrows; 996 ri->ri_ops.eraserows = ffb_ras_eraserows; 997 ri->ri_ops.erasecols = ffb_ras_erasecols; 998 ri->ri_ops.cursor = ffb_cursor; 999 ri->ri_ops.allocattr = ffb_allocattr; 1000 if (sc->putchar == NULL) 1001 sc->putchar = ri->ri_ops.putchar; 1002 sc->copycols = ri->ri_ops.copycols; 1003 ri->ri_ops.putchar = ffb_putchar; 1004 ri->ri_ops.copycols = ffb_ras_copycols; 1005 1006 1007 if (existing) { 1008 scr->active = 1; 1009 } else { 1010 scr->active = 0; 1011 } 1012 1013 ffb_ras_eraserows(&scr->ri, 0, ri->ri_rows, *defattr); 1014 1015 LIST_INSERT_HEAD(&sc->screens, scr, next); 1016 } 1017 1018 int 1019 ffb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 1020 int *curxp, int *curyp, long *defattrp) 1021 { 1022 struct ffb_softc *sc = v; 1023 struct ffb_screen *scr; 1024 1025 scr = malloc(sizeof(struct ffb_screen), M_DEVBUF, M_WAITOK | M_ZERO); 1026 ffb_init_screen(sc, scr, 0, defattrp); 1027 1028 if (sc->active == NULL) { 1029 scr->active = 1; 1030 sc->active = scr; 1031 sc->currenttype = type; 1032 } 1033 1034 *cookiep = scr; 1035 *curxp = scr->cursorcol; 1036 *curyp = scr->cursorrow; 1037 return 0; 1038 } 1039 1040 void 1041 ffb_free_screen(void *v, void *cookie) 1042 { 1043 struct ffb_softc *sc = v; 1044 struct ffb_screen *scr = cookie; 1045 1046 LIST_REMOVE(scr, next); 1047 if (scr != &ffb_console_screen) { 1048 free(scr->attrs, M_DEVBUF); 1049 free(scr, M_DEVBUF); 1050 } else 1051 panic("ffb_free_screen: console"); 1052 1053 if (sc->active == scr) 1054 sc->active = 0; 1055 } 1056 1057 int 1058 ffb_show_screen(void *v, void *cookie, int waitok, 1059 void (*cb)(void *, int, int), void *cbarg) 1060 { 1061 struct ffb_softc *sc = v; 1062 struct ffb_screen *scr, *oldscr; 1063 1064 scr = cookie; 1065 oldscr = sc->active; 1066 if (scr == oldscr) 1067 return 0; 1068 1069 sc->wanted = scr; 1070 sc->switchcb = cb; 1071 sc->switchcbarg = cbarg; 1072 if (cb) { 1073 callout_reset(&sc->switch_callout, 0, 1074 (void(*)(void *))ffb_switch_screen, sc); 1075 return EAGAIN; 1076 } 1077 1078 ffb_switch_screen(sc); 1079 return 0; 1080 } 1081 1082