1 /* $OpenBSD: ifb.c,v 1.15 2009/01/19 22:12:11 miod Exp $ */ 2 3 /* 4 * Copyright (c) 2007, 2008, 2009 Miodrag Vallat. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Least-effort driver for the Sun Expert3D cards (based on the 21 * ``Wildcat'' chips). 22 * 23 * There is no public documentation for these chips available. 24 * Since they are no longer supported by 3DLabs (which got bought by 25 * Creative), and Sun does not want to publish even minimal information 26 * or source code, the best we can do is experiment. 27 * 28 * Quoting Alan Coopersmith in 29 * http://mail.opensolaris.org/pipermail/opensolaris-discuss/2005-December/011885.html 30 * ``Unfortunately, the lawyers have asked we not give details about why 31 * specific components are not being released.'' 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/device.h> 37 #include <sys/errno.h> 38 #include <sys/ioctl.h> 39 #include <sys/malloc.h> 40 #include <sys/pciio.h> 41 42 #include <uvm/uvm_extern.h> 43 44 #include <machine/autoconf.h> 45 #include <machine/bus.h> 46 #include <machine/intr.h> 47 #include <machine/openfirm.h> 48 49 #include <dev/pci/pcireg.h> 50 #include <dev/pci/pcivar.h> 51 #include <dev/pci/pcidevs.h> 52 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/wscons/wsdisplayvar.h> 55 56 #include <dev/rasops/rasops.h> 57 58 #include <machine/fbvar.h> 59 60 #ifdef APERTURE 61 extern int allowaperture; 62 #endif 63 64 /* 65 * Parts of the following hardware knowledge come from David S. Miller's 66 * XVR-500 Linux driver (drivers/video/sunxvr500.c). 67 */ 68 69 /* 70 * The Expert3D and Expert3d-Lite cards are built around the Wildcat 71 * 5110, 6210 and 7210 chips. 72 * 73 * The card exposes the following resources: 74 * - a 32MB aperture window in which views to the different frame buffer 75 * areas can be mapped, in the first BAR. 76 * - a 64KB PROM and registers area, in the second BAR, with the registers 77 * starting 32KB within this area. 78 * - a 8MB memory mapping, which purpose is unknown, in the third BAR. 79 * 80 * In the state the PROM leaves us in, the 8MB frame buffer windows map 81 * the video memory as interleaved stripes, of which the non-visible parts 82 * can still be addressed (probably for fast screen switching). 83 * 84 * Unfortunately, since we do not know how to reconfigure the stripes 85 * to provide at least a linear frame buffer, we have to write to both 86 * windows and have them provide the complete image. 87 * 88 * Moreover, high pixel values in the overlay planes (such as 0xff or 0xfe) 89 * seem to enable other planes with random contents, so we'll limit ourselves 90 * to 7bpp opration. 91 */ 92 93 /* 94 * The Expert3D has an extra BAR that is not present on the -Lite 95 * version. This register contains bits that tell us how many BARs to 96 * skip before we get to the BARs that interest us. 97 */ 98 #define IFB_PCI_CFG 0x5c 99 #define IFB_PCI_CFG_BAR_OFFSET(x) ((x & 0x000000e0) >> 3) 100 101 #define IFB_REG_OFFSET 0x8000 102 103 /* 104 * 0000 magic 105 * This register seems to be used to issue commands to the 106 * acceleration hardware. 107 * 108 */ 109 #define IFB_REG_MAGIC 0x0000 110 #define IFB_REG_MAGIC_DIR_BACKWARDS_Y (0x08 | 0x02) 111 #define IFB_REG_MAGIC_DIR_BACKWARDS_X (0x04 | 0x01) 112 113 /* 114 * 0040 component configuration 115 * This register controls which parts of the board will be addressed by 116 * writes to other configuration registers. 117 * Apparently the low two bytes control the frame buffer windows for the 118 * given head (starting at 1). 119 * The high two bytes are texture related. 120 */ 121 #define IFB_REG_COMPONENT_SELECT 0x0040 122 123 /* 124 * 0044 status 125 * This register has a bit that signals completion of commands issued 126 * to the acceleration hardware. 127 */ 128 #define IFB_REG_STATUS 0x0044 129 #define IFB_REG_STATUS_DONE 0x00000004 130 131 /* 132 * 0058 magnifying configuration 133 * This register apparently controls magnifying. 134 * bits 5-6 select the window width divider (00: by 2, 01: by 4, 10: by 8, 135 * 11: by 16) 136 * bits 7-8 select the zoom factor (00: disabled, 01: x2, 10: x4, 11: x8) 137 */ 138 #define IFB_REG_MAGNIFY 0x0058 139 #define IFB_REG_MAGNIFY_DISABLE 0x00000000 140 #define IFB_REG_MAGNIFY_X2 0x00000040 141 #define IFB_REG_MAGNIFY_X4 0x00000080 142 #define IFB_REG_MAGNIFY_X8 0x000000c0 143 #define IFB_REG_MAGNIFY_WINDIV2 0x00000000 144 #define IFB_REG_MAGNIFY_WINDIV4 0x00000010 145 #define IFB_REG_MAGNIFY_WINDIV8 0x00000020 146 #define IFB_REG_MAGNIFY_WINDIV16 0x00000030 147 148 /* 149 * 0070 display resolution 150 * Contains the size of the display, as ((height - 1) << 16) | (width - 1) 151 */ 152 #define IFB_REG_RESOLUTION 0x0070 153 /* 154 * 0074 configuration register 155 * Contains 0x1a000088 | ((Log2 stride) << 16) 156 */ 157 #define IFB_REG_CONFIG 0x0074 158 /* 159 * 0078 32bit frame buffer window #0 (8 to 9 MB) 160 * Contains the offset (relative to BAR0) of the 32 bit frame buffer window. 161 */ 162 #define IFB_REG_FB32_0 0x0078 163 /* 164 * 007c 32bit frame buffer window #1 (8 to 9 MB) 165 * Contains the offset (relative to BAR0) of the 32 bit frame buffer window. 166 */ 167 #define IFB_REG_FB32_1 0x007c 168 /* 169 * 0080 8bit frame buffer window #0 (2 to 2.2 MB) 170 * Contains the offset (relative to BAR0) of the 8 bit frame buffer window. 171 */ 172 #define IFB_REG_FB8_0 0x0080 173 /* 174 * 0084 8bit frame buffer window #1 (2 to 2.2 MB) 175 * Contains the offset (relative to BAR0) of the 8 bit frame buffer window. 176 */ 177 #define IFB_REG_FB8_1 0x0084 178 /* 179 * 0088 unknown window (as large as a 32 bit frame buffer) 180 */ 181 #define IFB_REG_FB_UNK0 0x0088 182 /* 183 * 008c unknown window (as large as a 8 bit frame buffer) 184 */ 185 #define IFB_REG_FB_UNK1 0x008c 186 /* 187 * 0090 unknown window (as large as a 8 bit frame buffer) 188 */ 189 #define IFB_REG_FB_UNK2 0x0090 190 191 /* 192 * 00bc RAMDAC palette index register 193 */ 194 #define IFB_REG_CMAP_INDEX 0x00bc 195 /* 196 * 00c0 RAMDAC palette data register 197 */ 198 #define IFB_REG_CMAP_DATA 0x00c0 199 200 /* 201 * 00e4 DPMS state register 202 * States ``off'' and ``suspend'' need chip reprogramming before video can 203 * be enabled again. 204 */ 205 #define IFB_REG_DPMS_STATE 0x00e4 206 #define IFB_REG_DPMS_OFF 0x00000000 207 #define IFB_REG_DPMS_SUSPEND 0x00000001 208 #define IFB_REG_DPMS_STANDBY 0x00000002 209 #define IFB_REG_DPMS_ON 0x00000003 210 211 /* 212 * (some) ROP codes 213 */ 214 215 #define IFB_ROP_CLEAR 0x00000000 /* clear bits in rop mask */ 216 #define IFB_ROP_SRC 0x00330000 /* copy src bits matching rop mask */ 217 #define IFB_ROP_XOR 0x00cc0000 /* xor src bits with rop mask */ 218 #define IFB_ROP_SET 0x00ff0000 /* set bits in rop mask */ 219 220 #define IFB_COORDS(x, y) ((x) | (y) << 16) 221 222 #define IFB_PIXELMASK 0x7f /* 7bpp */ 223 224 struct ifb_softc { 225 struct sunfb sc_sunfb; 226 227 bus_space_tag_t sc_mem_t; 228 pcitag_t sc_pcitag; 229 230 bus_space_handle_t sc_mem_h; 231 bus_addr_t sc_membase, sc_fb8bank0_base, sc_fb8bank1_base; 232 bus_size_t sc_memlen; 233 vaddr_t sc_memvaddr, sc_fb8bank0_vaddr, sc_fb8bank1_vaddr; 234 235 bus_space_handle_t sc_reg_h; 236 bus_addr_t sc_regbase; 237 bus_size_t sc_reglen; 238 239 u_int sc_mode; 240 u_int sc_accel; 241 242 struct wsdisplay_emulops sc_old_ops; 243 void (*sc_old_cursor)(struct rasops_info *); 244 245 int sc_console; 246 u_int8_t sc_cmap_red[256]; 247 u_int8_t sc_cmap_green[256]; 248 u_int8_t sc_cmap_blue[256]; 249 }; 250 251 int ifb_ioctl(void *, u_long, caddr_t, int, struct proc *); 252 paddr_t ifb_mmap(void *, off_t, int); 253 void ifb_burner(void *, u_int, u_int); 254 255 struct wsdisplay_accessops ifb_accessops = { 256 ifb_ioctl, 257 ifb_mmap, 258 NULL, /* alloc_screen */ 259 NULL, /* free_screen */ 260 NULL, /* show_screen */ 261 NULL, /* load_font */ 262 NULL, /* scrollback */ 263 NULL, /* getchar */ 264 ifb_burner, 265 NULL /* pollc */ 266 }; 267 268 int ifbmatch(struct device *, void *, void *); 269 void ifbattach(struct device *, struct device *, void *); 270 271 struct cfattach ifb_ca = { 272 sizeof (struct ifb_softc), ifbmatch, ifbattach 273 }; 274 275 struct cfdriver ifb_cd = { 276 NULL, "ifb", DV_DULL 277 }; 278 279 int ifb_getcmap(struct ifb_softc *, struct wsdisplay_cmap *); 280 int ifb_is_console(int); 281 int ifb_mapregs(struct ifb_softc *, struct pci_attach_args *); 282 int ifb_putcmap(struct ifb_softc *, struct wsdisplay_cmap *); 283 void ifb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); 284 void ifb_setcolormap(struct sunfb *, 285 void (*)(void *, u_int, u_int8_t, u_int8_t, u_int8_t)); 286 287 void ifb_copyrect(struct ifb_softc *, int, int, int, int, int, int); 288 void ifb_fillrect(struct ifb_softc *, int, int, int, int, int); 289 void ifb_rop(struct ifb_softc *, int, int, int, int, int, int, uint32_t, 290 int32_t); 291 int ifb_rop_wait(struct ifb_softc *); 292 293 void ifb_putchar_dumb(void *, int, int, u_int, long); 294 void ifb_copycols_dumb(void *, int, int, int, int); 295 void ifb_erasecols_dumb(void *, int, int, int, long); 296 void ifb_copyrows_dumb(void *, int, int, int); 297 void ifb_eraserows_dumb(void *, int, int, long); 298 void ifb_do_cursor_dumb(struct rasops_info *); 299 300 void ifb_putchar(void *, int, int, u_int, long); 301 void ifb_copycols(void *, int, int, int, int); 302 void ifb_erasecols(void *, int, int, int, long); 303 void ifb_copyrows(void *, int, int, int); 304 void ifb_eraserows(void *, int, int, long); 305 void ifb_do_cursor(struct rasops_info *); 306 307 int 308 ifbmatch(struct device *parent, void *cf, void *aux) 309 { 310 struct pci_attach_args *paa = aux; 311 int rc; 312 313 if ((rc = ifb_ident(aux)) == 0) 314 return 0; 315 316 /* 317 * Multiple heads appear as PCI subfunctions. 318 * However, the ofw node for it lacks most properties, 319 * and its BAR only give access to registers, not 320 * frame buffer memory. 321 */ 322 if (node_has_property(PCITAG_NODE(paa->pa_tag), "device_type")) 323 return rc; 324 325 return 0; 326 } 327 328 void 329 ifbattach(struct device *parent, struct device *self, void *aux) 330 { 331 struct ifb_softc *sc = (struct ifb_softc *)self; 332 struct pci_attach_args *paa = aux; 333 struct rasops_info *ri; 334 int node; 335 336 sc->sc_mem_t = paa->pa_memt; 337 sc->sc_pcitag = paa->pa_tag; 338 339 printf("\n"); 340 341 if (ifb_mapregs(sc, paa)) 342 return; 343 344 sc->sc_fb8bank0_base = bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h, 345 IFB_REG_OFFSET + IFB_REG_FB8_0); 346 sc->sc_fb8bank1_base = bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h, 347 IFB_REG_OFFSET + IFB_REG_FB8_1); 348 349 sc->sc_memvaddr = (vaddr_t)bus_space_vaddr(sc->sc_mem_t, sc->sc_mem_h); 350 sc->sc_fb8bank0_vaddr = sc->sc_memvaddr + 351 sc->sc_fb8bank0_base - sc->sc_membase; 352 sc->sc_fb8bank1_vaddr = sc->sc_memvaddr + 353 sc->sc_fb8bank1_base - sc->sc_membase; 354 355 node = PCITAG_NODE(paa->pa_tag); 356 sc->sc_console = ifb_is_console(node); 357 358 fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0); 359 360 printf("%s: %dx%d\n", 361 self->dv_xname, sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); 362 363 #if 0 364 /* 365 * Make sure the frame buffer is configured to sane values. 366 * So much more is needed there... documentation permitting. 367 */ 368 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 369 IFB_REG_OFFSET + IFB_REG_COMPONENT_SELECT, 0x00000101); 370 delay(1000); 371 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 372 IFB_REG_OFFSET + IFB_REG_MAGNIFY, IFB_REG_MAGNIFY_DISABLE); 373 #endif 374 375 ri = &sc->sc_sunfb.sf_ro; 376 ri->ri_bits = NULL; 377 ri->ri_hw = sc; 378 379 fbwscons_init(&sc->sc_sunfb, RI_BSWAP, sc->sc_console); 380 381 /* 382 * Clear the unwanted pixel planes: all if non console (thus 383 * white background), and all planes above 7bpp otherwise. 384 * This also allows to check whether the accelerated code works, 385 * or not. 386 */ 387 ifb_rop(sc, 0, 0, 0, 0, sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height, 388 IFB_ROP_CLEAR, sc->sc_console ? ~IFB_PIXELMASK : ~0); 389 if (ifb_rop_wait(sc) != 0) { 390 sc->sc_accel = 1; 391 } else { 392 /* due to the way we will handle updates */ 393 ri->ri_flg &= ~RI_FULLCLEAR; 394 395 if (!sc->sc_console) { 396 bzero((void *)sc->sc_fb8bank0_vaddr, 397 sc->sc_sunfb.sf_fbsize); 398 bzero((void *)sc->sc_fb8bank1_vaddr, 399 sc->sc_sunfb.sf_fbsize); 400 } 401 } 402 403 /* pick centering delta */ 404 sc->sc_fb8bank0_vaddr += ri->ri_bits - ri->ri_origbits; 405 sc->sc_fb8bank1_vaddr += ri->ri_bits - ri->ri_origbits; 406 407 sc->sc_old_ops = ri->ri_ops; /* structure copy */ 408 sc->sc_old_cursor = ri->ri_do_cursor; 409 410 if (sc->sc_accel) { 411 ri->ri_ops.copyrows = ifb_copyrows; 412 ri->ri_ops.copycols = ifb_copycols; 413 ri->ri_ops.eraserows = ifb_eraserows; 414 ri->ri_ops.erasecols = ifb_erasecols; 415 ri->ri_ops.putchar = ifb_putchar_dumb; 416 ri->ri_do_cursor = ifb_do_cursor; 417 } else { 418 ri->ri_ops.copyrows = ifb_copyrows_dumb; 419 ri->ri_ops.copycols = ifb_copycols_dumb; 420 ri->ri_ops.eraserows = ifb_eraserows_dumb; 421 ri->ri_ops.erasecols = ifb_erasecols_dumb; 422 ri->ri_ops.putchar = ifb_putchar_dumb; 423 ri->ri_do_cursor = ifb_do_cursor_dumb; 424 } 425 426 ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor); 427 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 428 429 if (sc->sc_console) 430 fbwscons_console_init(&sc->sc_sunfb, -1); 431 fbwscons_attach(&sc->sc_sunfb, &ifb_accessops, sc->sc_console); 432 } 433 434 int 435 ifb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p) 436 { 437 struct ifb_softc *sc = v; 438 struct wsdisplay_fbinfo *wdf; 439 struct pcisel *sel; 440 int mode; 441 442 switch (cmd) { 443 case WSDISPLAYIO_GTYPE: 444 *(u_int *)data = WSDISPLAY_TYPE_IFB; 445 break; 446 447 case WSDISPLAYIO_SMODE: 448 mode = *(u_int *)data; 449 if (mode == WSDISPLAYIO_MODE_EMUL) 450 ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor); 451 sc->sc_mode = mode; 452 break; 453 case WSDISPLAYIO_GINFO: 454 wdf = (void *)data; 455 wdf->height = sc->sc_sunfb.sf_height; 456 wdf->width = sc->sc_sunfb.sf_width; 457 wdf->depth = sc->sc_sunfb.sf_depth; 458 wdf->cmsize = 256; 459 break; 460 case WSDISPLAYIO_LINEBYTES: 461 *(u_int *)data = sc->sc_sunfb.sf_linebytes; 462 break; 463 464 case WSDISPLAYIO_GETCMAP: 465 return ifb_getcmap(sc, (struct wsdisplay_cmap *)data); 466 case WSDISPLAYIO_PUTCMAP: 467 return ifb_putcmap(sc, (struct wsdisplay_cmap *)data); 468 469 case WSDISPLAYIO_GPCIID: 470 sel = (struct pcisel *)data; 471 sel->pc_bus = PCITAG_BUS(sc->sc_pcitag); 472 sel->pc_dev = PCITAG_DEV(sc->sc_pcitag); 473 sel->pc_func = PCITAG_FUN(sc->sc_pcitag); 474 break; 475 476 case WSDISPLAYIO_SVIDEO: 477 case WSDISPLAYIO_GVIDEO: 478 break; 479 480 case WSDISPLAYIO_GCURPOS: 481 case WSDISPLAYIO_SCURPOS: 482 case WSDISPLAYIO_GCURMAX: 483 case WSDISPLAYIO_GCURSOR: 484 case WSDISPLAYIO_SCURSOR: 485 default: 486 return -1; /* not supported yet */ 487 } 488 489 return 0; 490 } 491 492 int 493 ifb_getcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm) 494 { 495 u_int index = cm->index; 496 u_int count = cm->count; 497 int error; 498 499 if (index >= 256 || count > 256 - index) 500 return EINVAL; 501 502 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 503 if (error) 504 return error; 505 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 506 if (error) 507 return error; 508 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 509 if (error) 510 return error; 511 return 0; 512 } 513 514 int 515 ifb_putcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm) 516 { 517 u_int index = cm->index; 518 u_int count = cm->count; 519 u_int i; 520 int error; 521 u_char *r, *g, *b; 522 523 if (index >= 256 || count > 256 - index) 524 return EINVAL; 525 526 if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0) 527 return error; 528 if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0) 529 return error; 530 if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0) 531 return error; 532 533 r = &sc->sc_cmap_red[index]; 534 g = &sc->sc_cmap_green[index]; 535 b = &sc->sc_cmap_blue[index]; 536 537 for (i = 0; i < count; i++) { 538 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 539 IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index); 540 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 541 IFB_REG_OFFSET + IFB_REG_CMAP_DATA, 542 (((u_int)*b) << 22) | (((u_int)*g) << 12) | (((u_int)*r) << 2)); 543 r++, g++, b++, index++; 544 } 545 return 0; 546 } 547 548 void 549 ifb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) 550 { 551 struct ifb_softc *sc = v; 552 553 sc->sc_cmap_red[index] = r; 554 sc->sc_cmap_green[index] = g; 555 sc->sc_cmap_blue[index] = b; 556 557 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 558 IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index); 559 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 560 IFB_REG_OFFSET + IFB_REG_CMAP_DATA, 561 (((u_int)b) << 22) | (((u_int)g) << 12) | (((u_int)r) << 2)); 562 } 563 564 /* similar in spirit to fbwscons_setcolormap() */ 565 void 566 ifb_setcolormap(struct sunfb *sf, 567 void (*setcolor)(void *, u_int, u_int8_t, u_int8_t, u_int8_t)) 568 { 569 struct rasops_info *ri = &sf->sf_ro; 570 int i; 571 const u_char *color; 572 573 /* 574 * Compensate for overlay plane limitations. Since we'll operate 575 * in 7bpp mode, our basic colors will use positions 00 to 0f, 576 * and the inverted colors will use positions 7f to 70. 577 */ 578 579 for (i = 0x00; i < 0x10; i++) { 580 color = &rasops_cmap[i * 3]; 581 setcolor(sf, i, color[0], color[1], color[2]); 582 } 583 for (i = 0x70; i < 0x80; i++) { 584 color = &rasops_cmap[(0xf0 | i) * 3]; 585 setcolor(sf, i, color[0], color[1], color[2]); 586 } 587 588 /* 589 * Proper operation apparently needs black to be 01, always. 590 * Replace black, red and white with white, black and red. 591 * Kind of ugly, but it works. 592 */ 593 ri->ri_devcmap[WSCOL_WHITE] = 0x00000000; 594 ri->ri_devcmap[WSCOL_BLACK] = 0x01010101; 595 ri->ri_devcmap[WSCOL_RED] = 0x07070707; 596 597 color = &rasops_cmap[(WSCOL_WHITE + 8) * 3]; /* real white */ 598 setcolor(sf, 0, color[0], color[1], color[2]); 599 setcolor(sf, IFB_PIXELMASK ^ 0, ~color[0], ~color[1], ~color[2]); 600 color = &rasops_cmap[WSCOL_BLACK * 3]; 601 setcolor(sf, 1, color[0], color[1], color[2]); 602 setcolor(sf, IFB_PIXELMASK ^ 1, ~color[0], ~color[1], ~color[2]); 603 color = &rasops_cmap[WSCOL_RED * 3]; 604 setcolor(sf, 7, color[0], color[1], color[2]); 605 setcolor(sf, IFB_PIXELMASK ^ 7, ~color[0], ~color[1], ~color[2]); 606 } 607 608 paddr_t 609 ifb_mmap(void *v, off_t off, int prot) 610 { 611 struct ifb_softc *sc = (struct ifb_softc *)v; 612 613 switch (sc->sc_mode) { 614 case WSDISPLAYIO_MODE_MAPPED: 615 /* 616 * In mapped mode, provide access to the two overlays, 617 * followed by the control registers, at the following 618 * addresses: 619 * 00000000 overlay 0, size up to 2MB (visible fb size) 620 * 01000000 overlay 1, size up to 2MB (visible fb size) 621 * 02000000 control registers 622 */ 623 off -= 0x00000000; 624 if (off >= 0 && off < round_page(sc->sc_sunfb.sf_fbsize)) { 625 return bus_space_mmap(sc->sc_mem_t, 626 sc->sc_fb8bank0_base, 627 off, prot, BUS_SPACE_MAP_LINEAR); 628 } 629 off -= 0x01000000; 630 if (off >= 0 && off < round_page(sc->sc_sunfb.sf_fbsize)) { 631 return bus_space_mmap(sc->sc_mem_t, 632 sc->sc_fb8bank1_base, 633 off, prot, BUS_SPACE_MAP_LINEAR); 634 } 635 #ifdef APERTURE 636 off -= 0x01000000; 637 if (allowaperture != 0 && sc->sc_accel) { 638 if (off >= 0 && off < round_page(sc->sc_reglen)) { 639 return bus_space_mmap(sc->sc_mem_t, 640 sc->sc_regbase, 641 off, prot, BUS_SPACE_MAP_LINEAR); 642 } 643 } 644 #endif 645 break; 646 } 647 648 return -1; 649 } 650 651 void 652 ifb_burner(void *v, u_int on, u_int flags) 653 { 654 struct ifb_softc *sc = (struct ifb_softc *)v; 655 int s; 656 uint32_t dpms; 657 658 s = splhigh(); 659 if (on) 660 dpms = IFB_REG_DPMS_ON; 661 else { 662 #ifdef notyet 663 if (flags & WSDISPLAY_BURN_VBLANK) 664 dpms = IFB_REG_DPMS_SUSPEND; 665 else 666 #endif 667 dpms = IFB_REG_DPMS_STANDBY; 668 } 669 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 670 IFB_REG_OFFSET + IFB_REG_DPMS_STATE, dpms); 671 splx(s); 672 } 673 674 int 675 ifb_is_console(int node) 676 { 677 extern int fbnode; 678 679 return fbnode == node; 680 } 681 682 int 683 ifb_mapregs(struct ifb_softc *sc, struct pci_attach_args *pa) 684 { 685 u_int32_t cf; 686 int bar, rc; 687 688 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, IFB_PCI_CFG); 689 bar = PCI_MAPREG_START + IFB_PCI_CFG_BAR_OFFSET(cf); 690 691 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar); 692 if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO) 693 rc = EINVAL; 694 else { 695 rc = pci_mapreg_map(pa, bar, cf, 696 BUS_SPACE_MAP_LINEAR, NULL, &sc->sc_mem_h, 697 &sc->sc_membase, &sc->sc_memlen, 0); 698 } 699 if (rc != 0) { 700 printf("%s: can't map video memory\n", 701 sc->sc_sunfb.sf_dev.dv_xname); 702 return rc; 703 } 704 705 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar + 4); 706 if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO) 707 rc = EINVAL; 708 else { 709 rc = pci_mapreg_map(pa, bar + 4, cf, 710 0, NULL, &sc->sc_reg_h, 711 &sc->sc_regbase, &sc->sc_reglen, 0x9000); 712 } 713 if (rc != 0) { 714 printf("%s: can't map register space\n", 715 sc->sc_sunfb.sf_dev.dv_xname); 716 return rc; 717 } 718 719 return 0; 720 } 721 722 /* 723 * Non accelerated routines. 724 */ 725 726 void 727 ifb_putchar_dumb(void *cookie, int row, int col, u_int uc, long attr) 728 { 729 struct rasops_info *ri = cookie; 730 struct ifb_softc *sc = ri->ri_hw; 731 732 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 733 sc->sc_old_ops.putchar(cookie, row, col, uc, attr); 734 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 735 sc->sc_old_ops.putchar(cookie, row, col, uc, attr); 736 } 737 738 void 739 ifb_copycols_dumb(void *cookie, int row, int src, int dst, int num) 740 { 741 struct rasops_info *ri = cookie; 742 struct ifb_softc *sc = ri->ri_hw; 743 744 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 745 sc->sc_old_ops.copycols(cookie, row, src, dst, num); 746 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 747 sc->sc_old_ops.copycols(cookie, row, src, dst, num); 748 } 749 750 void 751 ifb_erasecols_dumb(void *cookie, int row, int col, int num, long attr) 752 { 753 struct rasops_info *ri = cookie; 754 struct ifb_softc *sc = ri->ri_hw; 755 756 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 757 sc->sc_old_ops.erasecols(cookie, row, col, num, attr); 758 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 759 sc->sc_old_ops.erasecols(cookie, row, col, num, attr); 760 } 761 762 void 763 ifb_copyrows_dumb(void *cookie, int src, int dst, int num) 764 { 765 struct rasops_info *ri = cookie; 766 struct ifb_softc *sc = ri->ri_hw; 767 768 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 769 sc->sc_old_ops.copyrows(cookie, src, dst, num); 770 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 771 sc->sc_old_ops.copyrows(cookie, src, dst, num); 772 } 773 774 void 775 ifb_eraserows_dumb(void *cookie, int row, int num, long attr) 776 { 777 struct rasops_info *ri = cookie; 778 struct ifb_softc *sc = ri->ri_hw; 779 780 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 781 sc->sc_old_ops.eraserows(cookie, row, num, attr); 782 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 783 sc->sc_old_ops.eraserows(cookie, row, num, attr); 784 } 785 786 /* Similar to rasops_do_cursor(), but using a 7bit pixel mask. */ 787 788 #define CURSOR_MASK 0x7f7f7f7f 789 790 void 791 ifb_do_cursor_dumb(struct rasops_info *ri) 792 { 793 struct ifb_softc *sc = ri->ri_hw; 794 int full1, height, cnt, slop1, slop2, row, col; 795 int ovl_offset = sc->sc_fb8bank1_vaddr - sc->sc_fb8bank0_vaddr; 796 u_char *dp0, *dp1, *rp; 797 798 row = ri->ri_crow; 799 col = ri->ri_ccol; 800 801 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 802 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 803 height = ri->ri_font->fontheight; 804 slop1 = (4 - ((long)rp & 3)) & 3; 805 806 if (slop1 > ri->ri_xscale) 807 slop1 = ri->ri_xscale; 808 809 slop2 = (ri->ri_xscale - slop1) & 3; 810 full1 = (ri->ri_xscale - slop1 - slop2) >> 2; 811 812 if ((slop1 | slop2) == 0) { 813 /* A common case */ 814 while (height--) { 815 dp0 = rp; 816 dp1 = dp0 + ovl_offset; 817 rp += ri->ri_stride; 818 819 for (cnt = full1; cnt; cnt--) { 820 *(int32_t *)dp0 ^= CURSOR_MASK; 821 *(int32_t *)dp1 ^= CURSOR_MASK; 822 dp0 += 4; 823 dp1 += 4; 824 } 825 } 826 } else { 827 /* XXX this is stupid.. use masks instead */ 828 while (height--) { 829 dp0 = rp; 830 dp1 = dp0 + ovl_offset; 831 rp += ri->ri_stride; 832 833 if (slop1 & 1) { 834 *dp0++ ^= (u_char)CURSOR_MASK; 835 *dp1++ ^= (u_char)CURSOR_MASK; 836 } 837 838 if (slop1 & 2) { 839 *(int16_t *)dp0 ^= (int16_t)CURSOR_MASK; 840 *(int16_t *)dp1 ^= (int16_t)CURSOR_MASK; 841 dp0 += 2; 842 dp1 += 2; 843 } 844 845 for (cnt = full1; cnt; cnt--) { 846 *(int32_t *)dp0 ^= CURSOR_MASK; 847 *(int32_t *)dp1 ^= CURSOR_MASK; 848 dp0 += 4; 849 dp1 += 4; 850 } 851 852 if (slop2 & 1) { 853 *dp0++ ^= (u_char)CURSOR_MASK; 854 *dp1++ ^= (u_char)CURSOR_MASK; 855 } 856 857 if (slop2 & 2) { 858 *(int16_t *)dp0 ^= (int16_t)CURSOR_MASK; 859 *(int16_t *)dp1 ^= (int16_t)CURSOR_MASK; 860 } 861 } 862 } 863 } 864 865 /* 866 * Accelerated routines. 867 */ 868 869 void 870 ifb_copycols(void *cookie, int row, int src, int dst, int num) 871 { 872 struct rasops_info *ri = cookie; 873 struct ifb_softc *sc = ri->ri_hw; 874 875 num *= ri->ri_font->fontwidth; 876 src *= ri->ri_font->fontwidth; 877 dst *= ri->ri_font->fontwidth; 878 row *= ri->ri_font->fontheight; 879 880 ifb_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row, 881 ri->ri_xorigin + dst, ri->ri_yorigin + row, 882 num, ri->ri_font->fontheight); 883 } 884 885 void 886 ifb_erasecols(void *cookie, int row, int col, int num, long attr) 887 { 888 struct rasops_info *ri = cookie; 889 struct ifb_softc *sc = ri->ri_hw; 890 int bg, fg; 891 892 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 893 894 row *= ri->ri_font->fontheight; 895 col *= ri->ri_font->fontwidth; 896 num *= ri->ri_font->fontwidth; 897 898 ifb_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row, 899 num, ri->ri_font->fontheight, ri->ri_devcmap[bg]); 900 } 901 902 void 903 ifb_copyrows(void *cookie, int src, int dst, int num) 904 { 905 struct rasops_info *ri = cookie; 906 struct ifb_softc *sc = ri->ri_hw; 907 908 num *= ri->ri_font->fontheight; 909 src *= ri->ri_font->fontheight; 910 dst *= ri->ri_font->fontheight; 911 912 ifb_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src, 913 ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num); 914 } 915 916 void 917 ifb_eraserows(void *cookie, int row, int num, long attr) 918 { 919 struct rasops_info *ri = cookie; 920 struct ifb_softc *sc = ri->ri_hw; 921 int bg, fg; 922 int x, y, w; 923 924 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 925 926 if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) { 927 num = ri->ri_height; 928 x = y = 0; 929 w = ri->ri_width; 930 } else { 931 num *= ri->ri_font->fontheight; 932 x = ri->ri_xorigin; 933 y = ri->ri_yorigin + row * ri->ri_font->fontheight; 934 w = ri->ri_emuwidth; 935 } 936 ifb_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]); 937 } 938 939 void 940 ifb_copyrect(struct ifb_softc *sc, int sx, int sy, int dx, int dy, int w, int h) 941 { 942 ifb_rop(sc, sx, sy, dx, dy, w, h, IFB_ROP_SRC, IFB_PIXELMASK); 943 ifb_rop_wait(sc); 944 } 945 946 void 947 ifb_fillrect(struct ifb_softc *sc, int x, int y, int w, int h, int bg) 948 { 949 int32_t mask; 950 951 /* pixels to set... */ 952 mask = IFB_PIXELMASK & bg; 953 if (mask != 0) { 954 ifb_rop(sc, x, y, x, y, w, h, IFB_ROP_SET, mask); 955 ifb_rop_wait(sc); 956 } 957 958 /* pixels to clear... */ 959 mask = IFB_PIXELMASK & ~bg; 960 if (mask != 0) { 961 ifb_rop(sc, x, y, x, y, w, h, IFB_ROP_CLEAR, mask); 962 ifb_rop_wait(sc); 963 } 964 } 965 966 /* 967 * Perform a raster operation on both overlay planes. 968 * Puzzled by all the magic numbers in there? So are we. Isn't a dire 969 * lack of documentation wonderful? 970 */ 971 void 972 ifb_rop(struct ifb_softc *sc, int sx, int sy, int dx, int dy, int w, int h, 973 uint32_t rop, int32_t planemask) 974 { 975 int dir = 0; 976 977 /* 978 * Compute rop direction. This only really matters for 979 * screen-to-screen copies. 980 */ 981 if (sy < dy /* && sy + h > dy */) { 982 sy += h - 1; 983 dy += h; 984 dir |= IFB_REG_MAGIC_DIR_BACKWARDS_Y; 985 } 986 if (sx < dx /* && sx + w > dx */) { 987 sx += w - 1; 988 dx += w; 989 dir |= IFB_REG_MAGIC_DIR_BACKWARDS_X; 990 } 991 992 /* Which one of those below is your magic number for today? */ 993 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 994 IFB_REG_OFFSET + IFB_REG_MAGIC, 2); 995 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 996 IFB_REG_OFFSET + IFB_REG_MAGIC, 1); 997 /* the ``0101'' part is probably a component selection */ 998 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 999 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x540101ff); 1000 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1001 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x61000001); 1002 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1003 IFB_REG_OFFSET + IFB_REG_MAGIC, 0); 1004 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1005 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x6301c080); 1006 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1007 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x80000000); 1008 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1009 IFB_REG_OFFSET + IFB_REG_MAGIC, rop); 1010 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1011 IFB_REG_OFFSET + IFB_REG_MAGIC, planemask); 1012 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1013 IFB_REG_OFFSET + IFB_REG_MAGIC, 0); 1014 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1015 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x64000303); 1016 /* 1017 * This value is a pixel offset within the destination area. It is 1018 * probably used to define complex polygon shapes, with the 1019 * last pixel in the list being back to (0,0). 1020 */ 1021 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1022 IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(0, 0)); 1023 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1024 IFB_REG_OFFSET + IFB_REG_MAGIC, 0); 1025 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1026 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x00030000); 1027 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1028 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x2200010d); 1029 1030 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1031 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x33f01000 | dir); 1032 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1033 IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(dx, dy)); 1034 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1035 IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(w, h)); 1036 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 1037 IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(sx, sy)); 1038 } 1039 1040 int 1041 ifb_rop_wait(struct ifb_softc *sc) 1042 { 1043 int i; 1044 1045 for (i = 1000000; i != 0; i--) { 1046 if (bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h, 1047 IFB_REG_OFFSET + IFB_REG_STATUS) & IFB_REG_STATUS_DONE) 1048 break; 1049 DELAY(1); 1050 } 1051 1052 return i; 1053 } 1054 1055 void 1056 ifb_do_cursor(struct rasops_info *ri) 1057 { 1058 struct ifb_softc *sc = ri->ri_hw; 1059 int y, x; 1060 1061 y = ri->ri_yorigin + ri->ri_crow * ri->ri_font->fontheight; 1062 x = ri->ri_xorigin + ri->ri_ccol * ri->ri_font->fontwidth; 1063 1064 ifb_rop(sc, x, y, x, y, ri->ri_font->fontwidth, ri->ri_font->fontheight, 1065 IFB_ROP_XOR, IFB_PIXELMASK); 1066 ifb_rop_wait(sc); 1067 } 1068