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