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