1 /* $OpenBSD: ifb.c,v 1.12 2009/01/01 19:25:39 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 /* 61 * Parts of the following hardware knowledge come from David S. Miller's 62 * XVR-500 Linux driver (drivers/video/sunxvr500.c). 63 */ 64 65 /* 66 * The Expert3D and Expert3d-Lite cards are built around the Wildcat 67 * 5110, 6210 and 7210 chips. 68 * 69 * The card exposes the following resources: 70 * - a 32MB aperture window in which views to the different frame buffer 71 * areas can be mapped, in the first BAR. 72 * - a 64KB PROM and registers area, in the second BAR, with the registers 73 * starting 32KB within this area. 74 * - a 8MB memory mapping, which purpose is unknown, in the third BAR. 75 * 76 * In the state the PROM leaves us in, the 8MB frame buffer windows map 77 * the video memory as interleaved stripes, of which the non-visible parts 78 * can still be addressed (probably for fast screen switching). 79 * 80 * Unfortunately, since we do not know how to reconfigure the stripes 81 * to provide at least a linear frame buffer, we have to write to both 82 * windows and have them provide the complete image. 83 * 84 * Moreover, high pixel values in the overlay planes (such as 0xff or 0xfe) 85 * seem to enable other planes with random contents, so we'll limit ourselves 86 * to 7bpp opration. 87 */ 88 89 /* 90 * The Expert3D has an extra BAR that is not present on the -Lite 91 * version. This register contains bits that tell us how many BARs to 92 * skip before we get to the BARs that interest us. 93 */ 94 #define IFB_PCI_CFG 0x5c 95 #define IFB_PCI_CFG_BAR_OFFSET(x) ((x & 0x000000e0) >> 3) 96 97 #define IFB_REG_OFFSET 0x8000 98 99 /* 100 * 0000 magic 101 * This register seems to be used to issue commands to the 102 * acceleration hardware. 103 * 104 */ 105 #define IFB_REG_MAGIC 0x0000 106 #define IFB_REG_MAGIC_DIR_BACKWARDS_Y (0x08 | 0x02) 107 #define IFB_REG_MAGIC_DIR_BACKWARDS_X (0x04 | 0x01) 108 109 /* 110 * 0040 component configuration 111 * This register controls which parts of the board will be addressed by 112 * writes to other configuration registers. 113 * Apparently the low two bytes control the frame buffer windows for the 114 * given head (starting at 1). 115 * The high two bytes are texture related. 116 */ 117 #define IFB_REG_COMPONENT_SELECT 0x0040 118 119 /* 120 * 0044 status 121 * This register has a bit that signals completion of commands issued 122 * to the acceleration hardware. 123 */ 124 #define IFB_REG_STATUS 0x0044 125 #define IFB_REG_STATUS_DONE 0x00000004 126 127 /* 128 * 0058 magnifying configuration 129 * This register apparently controls magnifying. 130 * bits 5-6 select the window width divider (00: by 2, 01: by 4, 10: by 8, 131 * 11: by 16) 132 * bits 7-8 select the zoom factor (00: disabled, 01: x2, 10: x4, 11: x8) 133 */ 134 #define IFB_REG_MAGNIFY 0x0058 135 #define IFB_REG_MAGNIFY_DISABLE 0x00000000 136 #define IFB_REG_MAGNIFY_X2 0x00000040 137 #define IFB_REG_MAGNIFY_X4 0x00000080 138 #define IFB_REG_MAGNIFY_X8 0x000000c0 139 #define IFB_REG_MAGNIFY_WINDIV2 0x00000000 140 #define IFB_REG_MAGNIFY_WINDIV4 0x00000010 141 #define IFB_REG_MAGNIFY_WINDIV8 0x00000020 142 #define IFB_REG_MAGNIFY_WINDIV16 0x00000030 143 144 /* 145 * 0070 display resolution 146 * Contains the size of the display, as ((height - 1) << 16) | (width - 1) 147 */ 148 #define IFB_REG_RESOLUTION 0x0070 149 /* 150 * 0074 configuration register 151 * Contains 0x1a000088 | ((Log2 stride) << 16) 152 */ 153 #define IFB_REG_CONFIG 0x0074 154 /* 155 * 0078 32bit frame buffer window #0 (8 to 9 MB) 156 * Contains the offset (relative to BAR0) of the 32 bit frame buffer window. 157 */ 158 #define IFB_REG_FB32_0 0x0078 159 /* 160 * 007c 32bit frame buffer window #1 (8 to 9 MB) 161 * Contains the offset (relative to BAR0) of the 32 bit frame buffer window. 162 */ 163 #define IFB_REG_FB32_1 0x007c 164 /* 165 * 0080 8bit frame buffer window #0 (2 to 2.2 MB) 166 * Contains the offset (relative to BAR0) of the 8 bit frame buffer window. 167 */ 168 #define IFB_REG_FB8_0 0x0080 169 /* 170 * 0084 8bit frame buffer window #1 (2 to 2.2 MB) 171 * Contains the offset (relative to BAR0) of the 8 bit frame buffer window. 172 */ 173 #define IFB_REG_FB8_1 0x0084 174 /* 175 * 0088 unknown window (as large as a 32 bit frame buffer) 176 */ 177 #define IFB_REG_FB_UNK0 0x0088 178 /* 179 * 008c unknown window (as large as a 8 bit frame buffer) 180 */ 181 #define IFB_REG_FB_UNK1 0x008c 182 /* 183 * 0090 unknown window (as large as a 8 bit frame buffer) 184 */ 185 #define IFB_REG_FB_UNK2 0x0090 186 187 /* 188 * 00bc RAMDAC palette index register 189 */ 190 #define IFB_REG_CMAP_INDEX 0x00bc 191 /* 192 * 00c0 RAMDAC palette data register 193 */ 194 #define IFB_REG_CMAP_DATA 0x00c0 195 196 /* 197 * 00e4 DPMS state register 198 * States ``off'' and ``suspend'' need chip reprogramming before video can 199 * be enabled again. 200 */ 201 #define IFB_REG_DPMS_STATE 0x00e4 202 #define IFB_REG_DPMS_OFF 0x00000000 203 #define IFB_REG_DPMS_SUSPEND 0x00000001 204 #define IFB_REG_DPMS_STANDBY 0x00000002 205 #define IFB_REG_DPMS_ON 0x00000003 206 207 #define IFB_COORDS(x, y) ((x) | (y) << 16) 208 209 struct ifb_softc { 210 struct sunfb sc_sunfb; 211 212 bus_space_tag_t sc_mem_t; 213 pcitag_t sc_pcitag; 214 215 bus_space_handle_t sc_mem_h; 216 bus_addr_t sc_membase, sc_fb8bank0_base, sc_fb8bank1_base; 217 bus_size_t sc_memlen; 218 vaddr_t sc_memvaddr, sc_fb8bank0_vaddr, sc_fb8bank1_vaddr; 219 220 bus_space_handle_t sc_reg_h; 221 bus_addr_t sc_regbase; 222 bus_size_t sc_reglen; 223 224 u_int sc_mode; 225 226 struct wsdisplay_emulops sc_old_ops; 227 void (*sc_old_cursor)(struct rasops_info *); 228 229 int sc_console; 230 u_int8_t sc_cmap_red[256]; 231 u_int8_t sc_cmap_green[256]; 232 u_int8_t sc_cmap_blue[256]; 233 }; 234 235 int ifb_ioctl(void *, u_long, caddr_t, int, struct proc *); 236 paddr_t ifb_mmap(void *, off_t, int); 237 void ifb_burner(void *, u_int, u_int); 238 239 struct wsdisplay_accessops ifb_accessops = { 240 ifb_ioctl, 241 ifb_mmap, 242 NULL, /* alloc_screen */ 243 NULL, /* free_screen */ 244 NULL, /* show_screen */ 245 NULL, /* load_font */ 246 NULL, /* scrollback */ 247 NULL, /* getchar */ 248 ifb_burner, 249 NULL /* pollc */ 250 }; 251 252 int ifbmatch(struct device *, void *, void *); 253 void ifbattach(struct device *, struct device *, void *); 254 255 struct cfattach ifb_ca = { 256 sizeof (struct ifb_softc), ifbmatch, ifbattach 257 }; 258 259 struct cfdriver ifb_cd = { 260 NULL, "ifb", DV_DULL 261 }; 262 263 int ifb_getcmap(struct ifb_softc *, struct wsdisplay_cmap *); 264 int ifb_is_console(int); 265 int ifb_mapregs(struct ifb_softc *, struct pci_attach_args *); 266 int ifb_putcmap(struct ifb_softc *, struct wsdisplay_cmap *); 267 void ifb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); 268 void ifb_setcolormap(struct sunfb *, 269 void (*)(void *, u_int, u_int8_t, u_int8_t, u_int8_t)); 270 271 void ifb_copyrect(struct ifb_softc *, int, int, int, int, int, int); 272 void ifb_putchar(void *, int, int, u_int, long); 273 void ifb_copycols(void *, int, int, int, int); 274 void ifb_erasecols(void *, int, int, int, long); 275 void ifb_copyrows(void *, int, int, int); 276 void ifb_eraserows(void *, int, int, long); 277 void ifb_do_cursor(struct rasops_info *); 278 279 int 280 ifbmatch(struct device *parent, void *cf, void *aux) 281 { 282 return ifb_ident(aux); 283 } 284 285 void 286 ifbattach(struct device *parent, struct device *self, void *aux) 287 { 288 struct ifb_softc *sc = (struct ifb_softc *)self; 289 struct pci_attach_args *paa = aux; 290 struct rasops_info *ri; 291 int node; 292 293 sc->sc_mem_t = paa->pa_memt; 294 sc->sc_pcitag = paa->pa_tag; 295 296 printf("\n"); 297 298 if (ifb_mapregs(sc, paa)) 299 return; 300 301 sc->sc_fb8bank0_base = bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h, 302 IFB_REG_OFFSET + IFB_REG_FB8_0); 303 sc->sc_fb8bank1_base = bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h, 304 IFB_REG_OFFSET + IFB_REG_FB8_1); 305 306 sc->sc_memvaddr = (vaddr_t)bus_space_vaddr(sc->sc_mem_t, sc->sc_mem_h); 307 sc->sc_fb8bank0_vaddr = sc->sc_memvaddr + 308 sc->sc_fb8bank0_base - sc->sc_membase; 309 sc->sc_fb8bank1_vaddr = sc->sc_memvaddr + 310 sc->sc_fb8bank1_base - sc->sc_membase; 311 312 node = PCITAG_NODE(paa->pa_tag); 313 sc->sc_console = ifb_is_console(node); 314 315 fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0); 316 317 printf("%s: %dx%d\n", 318 self->dv_xname, sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); 319 320 #if 0 321 /* 322 * Make sure the frame buffer is configured to sane values. 323 * So much more is needed there... documentation permitting. 324 */ 325 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 326 IFB_REG_OFFSET + IFB_REG_COMPONENT_SELECT, 0x00000101); 327 delay(1000); 328 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 329 IFB_REG_OFFSET + IFB_REG_MAGNIFY, IFB_REG_MAGNIFY_DISABLE); 330 #endif 331 332 ri = &sc->sc_sunfb.sf_ro; 333 ri->ri_bits = NULL; 334 ri->ri_hw = sc; 335 336 fbwscons_init(&sc->sc_sunfb, RI_BSWAP, sc->sc_console); 337 ri->ri_flg &= ~RI_FULLCLEAR; /* due to the way we handle updates */ 338 339 if (!sc->sc_console) { 340 bzero((void *)sc->sc_fb8bank0_vaddr, sc->sc_sunfb.sf_fbsize); 341 bzero((void *)sc->sc_fb8bank1_vaddr, sc->sc_sunfb.sf_fbsize); 342 } 343 344 /* pick centering delta */ 345 sc->sc_fb8bank0_vaddr += ri->ri_bits - ri->ri_origbits; 346 sc->sc_fb8bank1_vaddr += ri->ri_bits - ri->ri_origbits; 347 348 sc->sc_old_ops = ri->ri_ops; /* structure copy */ 349 sc->sc_old_cursor = ri->ri_do_cursor; 350 ri->ri_ops.copyrows = ifb_copyrows; 351 ri->ri_ops.copycols = ifb_copycols; 352 ri->ri_ops.eraserows = ifb_eraserows; 353 ri->ri_ops.erasecols = ifb_erasecols; 354 ri->ri_ops.putchar = ifb_putchar; 355 ri->ri_do_cursor = ifb_do_cursor; 356 357 ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor); 358 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 359 360 if (sc->sc_console) 361 fbwscons_console_init(&sc->sc_sunfb, -1); 362 fbwscons_attach(&sc->sc_sunfb, &ifb_accessops, sc->sc_console); 363 } 364 365 int 366 ifb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p) 367 { 368 struct ifb_softc *sc = v; 369 struct wsdisplay_fbinfo *wdf; 370 struct pcisel *sel; 371 int mode; 372 373 switch (cmd) { 374 case WSDISPLAYIO_GTYPE: 375 *(u_int *)data = WSDISPLAY_TYPE_IFB; 376 break; 377 378 case WSDISPLAYIO_SMODE: 379 mode = *(u_int *)data; 380 if (mode == WSDISPLAYIO_MODE_EMUL) 381 ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor); 382 sc->sc_mode = mode; 383 break; 384 case WSDISPLAYIO_GINFO: 385 wdf = (void *)data; 386 wdf->height = sc->sc_sunfb.sf_height; 387 wdf->width = sc->sc_sunfb.sf_width; 388 wdf->depth = sc->sc_sunfb.sf_depth; 389 wdf->cmsize = 256; 390 break; 391 case WSDISPLAYIO_LINEBYTES: 392 *(u_int *)data = sc->sc_sunfb.sf_linebytes; 393 break; 394 395 case WSDISPLAYIO_GETCMAP: 396 return ifb_getcmap(sc, (struct wsdisplay_cmap *)data); 397 case WSDISPLAYIO_PUTCMAP: 398 return ifb_putcmap(sc, (struct wsdisplay_cmap *)data); 399 400 case WSDISPLAYIO_GPCIID: 401 sel = (struct pcisel *)data; 402 sel->pc_bus = PCITAG_BUS(sc->sc_pcitag); 403 sel->pc_dev = PCITAG_DEV(sc->sc_pcitag); 404 sel->pc_func = PCITAG_FUN(sc->sc_pcitag); 405 break; 406 407 case WSDISPLAYIO_SVIDEO: 408 case WSDISPLAYIO_GVIDEO: 409 break; 410 411 case WSDISPLAYIO_GCURPOS: 412 case WSDISPLAYIO_SCURPOS: 413 case WSDISPLAYIO_GCURMAX: 414 case WSDISPLAYIO_GCURSOR: 415 case WSDISPLAYIO_SCURSOR: 416 default: 417 return -1; /* not supported yet */ 418 } 419 420 return 0; 421 } 422 423 int 424 ifb_getcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm) 425 { 426 u_int index = cm->index; 427 u_int count = cm->count; 428 int error; 429 430 if (index >= 256 || count > 256 - index) 431 return EINVAL; 432 433 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 434 if (error) 435 return error; 436 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 437 if (error) 438 return error; 439 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 440 if (error) 441 return error; 442 return 0; 443 } 444 445 int 446 ifb_putcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm) 447 { 448 u_int index = cm->index; 449 u_int count = cm->count; 450 u_int i; 451 int error; 452 u_char *r, *g, *b; 453 454 if (index >= 256 || count > 256 - index) 455 return EINVAL; 456 457 if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0) 458 return error; 459 if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0) 460 return error; 461 if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0) 462 return error; 463 464 r = &sc->sc_cmap_red[index]; 465 g = &sc->sc_cmap_green[index]; 466 b = &sc->sc_cmap_blue[index]; 467 468 for (i = 0; i < count; i++) { 469 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 470 IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index); 471 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 472 IFB_REG_OFFSET + IFB_REG_CMAP_DATA, 473 (((u_int)*b) << 22) | (((u_int)*g) << 12) | (((u_int)*r) << 2)); 474 r++, g++, b++, index++; 475 } 476 return 0; 477 } 478 479 void 480 ifb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) 481 { 482 struct ifb_softc *sc = v; 483 484 sc->sc_cmap_red[index] = r; 485 sc->sc_cmap_green[index] = g; 486 sc->sc_cmap_blue[index] = b; 487 488 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 489 IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index); 490 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 491 IFB_REG_OFFSET + IFB_REG_CMAP_DATA, 492 (((u_int)b) << 22) | (((u_int)g) << 12) | (((u_int)r) << 2)); 493 } 494 495 /* similar in spirit to fbwscons_setcolormap() */ 496 void 497 ifb_setcolormap(struct sunfb *sf, 498 void (*setcolor)(void *, u_int, u_int8_t, u_int8_t, u_int8_t)) 499 { 500 struct rasops_info *ri = &sf->sf_ro; 501 int i; 502 const u_char *color; 503 504 /* 505 * Compensate for overlay plane limitations. Since we'll operate 506 * in 7bpp mode, our basic colors will use positions 00 to 0f, 507 * and the inverted colors will use positions 7f to 70. 508 */ 509 510 for (i = 0x00; i < 0x10; i++) { 511 color = &rasops_cmap[i * 3]; 512 setcolor(sf, i, color[0], color[1], color[2]); 513 } 514 for (i = 0x70; i < 0x80; i++) { 515 color = &rasops_cmap[(0xf0 | i) * 3]; 516 setcolor(sf, i, color[0], color[1], color[2]); 517 } 518 519 /* 520 * Proper operation apparently needs black to be 01, always. 521 * Replace black, red and white with white, black and red. 522 * Kind of ugly, but it works. 523 */ 524 ri->ri_devcmap[WSCOL_WHITE] = 0x00000000; 525 ri->ri_devcmap[WSCOL_BLACK] = 0x01010101; 526 ri->ri_devcmap[WSCOL_RED] = 0x07070707; 527 528 color = &rasops_cmap[(WSCOL_WHITE + 8) * 3]; /* real white */ 529 setcolor(sf, 0, color[0], color[1], color[2]); 530 setcolor(sf, 0x7f ^ 0, ~color[0], ~color[1], ~color[2]); 531 color = &rasops_cmap[WSCOL_BLACK * 3]; 532 setcolor(sf, 1, color[0], color[1], color[2]); 533 setcolor(sf, 0x7f ^ 1, ~color[0], ~color[1], ~color[2]); 534 color = &rasops_cmap[WSCOL_RED * 3]; 535 setcolor(sf, 7, color[0], color[1], color[2]); 536 setcolor(sf, 0x7f ^ 7, ~color[0], ~color[1], ~color[2]); 537 } 538 539 paddr_t 540 ifb_mmap(void *v, off_t off, int prot) 541 { 542 struct ifb_softc *sc = (struct ifb_softc *)v; 543 544 switch (sc->sc_mode) { 545 case WSDISPLAYIO_MODE_MAPPED: 546 /* 547 * In mapped mode, provide access to the two overlays, 548 * followed by the control registers, at the following 549 * addresses: 550 * 00000000 overlay 0, size up to 2MB (visible fb size) 551 * 01000000 overlay 1, size up to 2MB (visible fb size) 552 * 02000000 control registers 553 */ 554 off -= 0x00000000; 555 if (off >= 0 && off < round_page(sc->sc_sunfb.sf_fbsize)) { 556 return bus_space_mmap(sc->sc_mem_t, 557 sc->sc_fb8bank0_base, 558 off, prot, BUS_SPACE_MAP_LINEAR); 559 } 560 off -= 0x01000000; 561 if (off >= 0 && off < round_page(sc->sc_sunfb.sf_fbsize)) { 562 return bus_space_mmap(sc->sc_mem_t, 563 sc->sc_fb8bank1_base, 564 off, prot, BUS_SPACE_MAP_LINEAR); 565 } 566 #ifdef notyet /* not needed so far, will require an aperture check */ 567 off -= 0x01000000; 568 if (off >= 0 && off < round_page(sc->sc_reglen)) { 569 return bus_space_mmap(sc->sc_mem_t, sc->sc_regbase, 570 off, prot, BUS_SPACE_MAP_LINEAR); 571 } 572 #endif 573 break; 574 } 575 576 return -1; 577 } 578 579 void 580 ifb_burner(void *v, u_int on, u_int flags) 581 { 582 struct ifb_softc *sc = (struct ifb_softc *)v; 583 int s; 584 uint32_t dpms; 585 586 s = splhigh(); 587 if (on) 588 dpms = IFB_REG_DPMS_ON; 589 else { 590 #ifdef notyet 591 if (flags & WSDISPLAY_BURN_VBLANK) 592 dpms = IFB_REG_DPMS_SUSPEND; 593 else 594 #endif 595 dpms = IFB_REG_DPMS_STANDBY; 596 } 597 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 598 IFB_REG_OFFSET + IFB_REG_DPMS_STATE, dpms); 599 splx(s); 600 } 601 602 int 603 ifb_is_console(int node) 604 { 605 extern int fbnode; 606 607 return fbnode == node; 608 } 609 610 int 611 ifb_mapregs(struct ifb_softc *sc, struct pci_attach_args *pa) 612 { 613 u_int32_t cf; 614 int bar, rc; 615 616 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, IFB_PCI_CFG); 617 bar = PCI_MAPREG_START + IFB_PCI_CFG_BAR_OFFSET(cf); 618 619 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar); 620 if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO) 621 rc = EINVAL; 622 else { 623 rc = pci_mapreg_map(pa, bar, cf, 624 BUS_SPACE_MAP_LINEAR, NULL, &sc->sc_mem_h, 625 &sc->sc_membase, &sc->sc_memlen, 0); 626 } 627 if (rc != 0) { 628 printf("%s: can't map video memory\n", 629 sc->sc_sunfb.sf_dev.dv_xname); 630 return rc; 631 } 632 633 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar + 4); 634 if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO) 635 rc = EINVAL; 636 else { 637 rc = pci_mapreg_map(pa, bar + 4, cf, 638 0, NULL, &sc->sc_reg_h, 639 &sc->sc_regbase, &sc->sc_reglen, 0x9000); 640 } 641 if (rc != 0) { 642 printf("%s: can't map register space\n", 643 sc->sc_sunfb.sf_dev.dv_xname); 644 return rc; 645 } 646 647 return 0; 648 } 649 650 void 651 ifb_putchar(void *cookie, int row, int col, u_int uc, long attr) 652 { 653 struct rasops_info *ri = cookie; 654 struct ifb_softc *sc = ri->ri_hw; 655 656 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 657 sc->sc_old_ops.putchar(cookie, row, col, uc, attr); 658 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 659 sc->sc_old_ops.putchar(cookie, row, col, uc, attr); 660 } 661 662 void 663 ifb_copycols(void *cookie, int row, int src, int dst, int num) 664 { 665 struct rasops_info *ri = cookie; 666 struct ifb_softc *sc = ri->ri_hw; 667 668 num *= ri->ri_font->fontwidth; 669 src *= ri->ri_font->fontwidth; 670 dst *= ri->ri_font->fontwidth; 671 row *= ri->ri_font->fontheight; 672 673 ifb_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row, 674 ri->ri_xorigin + dst, ri->ri_yorigin + row, 675 num, ri->ri_font->fontheight); 676 } 677 678 void 679 ifb_erasecols(void *cookie, int row, int col, int num, long attr) 680 { 681 struct rasops_info *ri = cookie; 682 struct ifb_softc *sc = ri->ri_hw; 683 684 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 685 sc->sc_old_ops.erasecols(cookie, row, col, num, attr); 686 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 687 sc->sc_old_ops.erasecols(cookie, row, col, num, attr); 688 } 689 690 void 691 ifb_copyrows(void *cookie, int src, int dst, int num) 692 { 693 struct rasops_info *ri = cookie; 694 struct ifb_softc *sc = ri->ri_hw; 695 696 num *= ri->ri_font->fontheight; 697 src *= ri->ri_font->fontheight; 698 dst *= ri->ri_font->fontheight; 699 700 ifb_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src, 701 ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num); 702 } 703 704 void 705 ifb_eraserows(void *cookie, int row, int num, long attr) 706 { 707 struct rasops_info *ri = cookie; 708 struct ifb_softc *sc = ri->ri_hw; 709 int bg, fg, done, cnt; 710 711 /* 712 * Perform the first line with plain rasops code (adapted below)... 713 */ 714 715 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 716 717 memset((void *)(sc->sc_fb8bank0_vaddr + row * ri->ri_yscale), 718 ri->ri_devcmap[bg], ri->ri_emustride); 719 memset((void *)(sc->sc_fb8bank1_vaddr + row * ri->ri_yscale), 720 ri->ri_devcmap[bg], ri->ri_emustride); 721 722 /* 723 * ...then copy it over and over until the whole area is done. 724 */ 725 726 row *= ri->ri_font->fontheight; 727 num *= ri->ri_font->fontheight; 728 row += ri->ri_yorigin; 729 730 for (done = 1, num -= done; num != 0;) { 731 cnt = min(done, num); 732 733 ifb_copyrect(sc, ri->ri_xorigin, row, 734 ri->ri_xorigin, row + done, ri->ri_emuwidth, cnt); 735 736 done += cnt; 737 num -= cnt; 738 } 739 } 740 741 void 742 ifb_copyrect(struct ifb_softc *sc, int sx, int sy, int dx, int dy, int w, int h) 743 { 744 int i, dir = 0; 745 746 if (sy < dy /* && sy + h > dy */) { 747 sy += h - 1; 748 dy += h; 749 dir |= IFB_REG_MAGIC_DIR_BACKWARDS_Y; 750 } 751 if (sx < dx /* && sx + w > dx */) { 752 sx += w - 1; 753 dx += w; 754 dir |= IFB_REG_MAGIC_DIR_BACKWARDS_X; 755 } 756 757 /* Lots of magic numbers. */ 758 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 759 IFB_REG_OFFSET + IFB_REG_MAGIC, 2); 760 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 761 IFB_REG_OFFSET + IFB_REG_MAGIC, 1); 762 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 763 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x540101ff); 764 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 765 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x61000001); 766 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 767 IFB_REG_OFFSET + IFB_REG_MAGIC, 0); 768 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 769 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x6301c080); 770 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 771 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x80000000); 772 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 773 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x00330000); 774 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 775 IFB_REG_OFFSET + IFB_REG_MAGIC, 0xff); 776 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 777 IFB_REG_OFFSET + IFB_REG_MAGIC, 0); 778 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 779 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x64000303); 780 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 781 IFB_REG_OFFSET + IFB_REG_MAGIC, 0); 782 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 783 IFB_REG_OFFSET + IFB_REG_MAGIC, 0); 784 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 785 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x00030000); 786 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 787 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x2200010d); 788 789 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 790 IFB_REG_OFFSET + IFB_REG_MAGIC, 0x33f01000 | dir); 791 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 792 IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(dx, dy)); 793 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 794 IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(w, h)); 795 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 796 IFB_REG_OFFSET + IFB_REG_MAGIC, IFB_COORDS(sx, sy)); 797 798 for (i = 1000000; i > 0; i--) { 799 if (bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h, 800 IFB_REG_OFFSET + IFB_REG_STATUS) & IFB_REG_STATUS_DONE) 801 break; 802 DELAY(1); 803 } 804 } 805 806 /* 807 * Similar to rasops_do_cursor(), but using a 7bit pixel mask. 808 */ 809 810 #define CURSOR_MASK 0x7f7f7f7f 811 812 void 813 ifb_do_cursor(struct rasops_info *ri) 814 { 815 struct ifb_softc *sc = ri->ri_hw; 816 int full1, height, cnt, slop1, slop2, row, col; 817 int ovl_offset = sc->sc_fb8bank1_vaddr - sc->sc_fb8bank0_vaddr; 818 u_char *dp0, *dp1, *rp; 819 820 row = ri->ri_crow; 821 col = ri->ri_ccol; 822 823 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 824 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 825 height = ri->ri_font->fontheight; 826 slop1 = (4 - ((long)rp & 3)) & 3; 827 828 if (slop1 > ri->ri_xscale) 829 slop1 = ri->ri_xscale; 830 831 slop2 = (ri->ri_xscale - slop1) & 3; 832 full1 = (ri->ri_xscale - slop1 - slop2) >> 2; 833 834 if ((slop1 | slop2) == 0) { 835 /* A common case */ 836 while (height--) { 837 dp0 = rp; 838 dp1 = dp0 + ovl_offset; 839 rp += ri->ri_stride; 840 841 for (cnt = full1; cnt; cnt--) { 842 *(int32_t *)dp0 ^= CURSOR_MASK; 843 *(int32_t *)dp1 ^= CURSOR_MASK; 844 dp0 += 4; 845 dp1 += 4; 846 } 847 } 848 } else { 849 /* XXX this is stupid.. use masks instead */ 850 while (height--) { 851 dp0 = rp; 852 dp1 = dp0 + ovl_offset; 853 rp += ri->ri_stride; 854 855 if (slop1 & 1) { 856 *dp0++ ^= (u_char)CURSOR_MASK; 857 *dp1++ ^= (u_char)CURSOR_MASK; 858 } 859 860 if (slop1 & 2) { 861 *(int16_t *)dp0 ^= (int16_t)CURSOR_MASK; 862 *(int16_t *)dp1 ^= (int16_t)CURSOR_MASK; 863 dp0 += 2; 864 dp1 += 2; 865 } 866 867 for (cnt = full1; cnt; cnt--) { 868 *(int32_t *)dp0 ^= CURSOR_MASK; 869 *(int32_t *)dp1 ^= CURSOR_MASK; 870 dp0 += 4; 871 dp1 += 4; 872 } 873 874 if (slop2 & 1) { 875 *dp0++ ^= (u_char)CURSOR_MASK; 876 *dp1++ ^= (u_char)CURSOR_MASK; 877 } 878 879 if (slop2 & 2) { 880 *(int16_t *)dp0 ^= (int16_t)CURSOR_MASK; 881 *(int16_t *)dp1 ^= (int16_t)CURSOR_MASK; 882 } 883 } 884 } 885 } 886