1 /* $OpenBSD: gfxp.c,v 1.16 2022/07/15 17:57:26 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Mark Kettenis. 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 #include <sys/param.h> 20 #include <sys/device.h> 21 #include <sys/pciio.h> 22 #include <sys/systm.h> 23 24 #include <machine/autoconf.h> 25 #include <machine/bus.h> 26 #include <machine/openfirm.h> 27 28 #include <dev/pci/pcireg.h> 29 #include <dev/pci/pcivar.h> 30 #include <dev/pci/pcidevs.h> 31 32 #include <dev/wscons/wsconsio.h> 33 #include <dev/wscons/wsdisplayvar.h> 34 35 #include <dev/rasops/rasops.h> 36 37 #include <machine/fbvar.h> 38 39 /* 40 * The Permedia 2 provides two views into its 64k register file. The 41 * first view is little-endian, the second is big-endian and 42 * immediately follows the little-endian view. Since bus_space(9) 43 * already does the byte order conversion for us, we use the 44 * little-endian view. 45 * 46 * There are also little-endian and big-endian views into the 47 * framebuffer. These are made available through separate BARs. We 48 * use the big-endian view in this driver to avoid unnecessary byte 49 * swapping in rasops(9). 50 */ 51 #define PM2_PCI_MMIO 0x10 /* Registers */ 52 #define PM2_PCI_MEM_LE 0x14 /* Framebuffer (little-endian) */ 53 #define PM2_PCI_MEM_BE 0x18 /* Framebuffer (big-endian) */ 54 55 #define PM2_IN_FIFO_SPACE 0x0018 56 #define PM2_OUT_FIFO_SPACE 0x0020 57 #define PM2_DMA_COUNT 0x0030 58 59 #define PM2_OUT_FIFO 0x2000 60 #define PM2_SYNC_TAG 0x00000188 61 62 #define PM2_PALETTE_WRITE_ADDR 0x4000 63 #define PM2_PALETTE_DATA 0x4008 64 65 #define PM2V_INDEX_LOW 0x4020 66 #define PM2V_INDEX_HIGH 0x4028 67 #define PM2V_INDEX_DATA 0x4030 68 #define PM2V_CURSOR_MODE 0x0005 69 #define PM2V_CURSOR_PATTERN 0x0400 70 71 #define PM2_RENDER 0x8038 72 #define PM2_RENDER_FASTFILL 0x00000008 73 #define PM2_RENDER_RECT 0x000000c0 74 #define PM2_INCREASE_X 0x00200000 75 #define PM2_INCREASE_Y 0x00400000 76 #define PM2_RECT_ORIG 0x80d0 77 #define PM2_RECT_SIZE 0x80d8 78 79 #define PM2_FB_READ_MODE 0x8a80 80 #define PM2_FB_BLOCK_COLOR 0x8ac8 81 #define PM2_FB_READ_PIXEL 0x8ad0 82 83 #define PM2_FILTER_MODE 0x8c00 84 #define PM2_FM_PASS_SYNC_TAG 0x00000400 85 #define PM2_SYNC 0x8c40 86 87 #define PM2_FB_SRC_DELTA 0x8d88 88 #define PM2_CONFIG 0x8d90 89 #define PM2_CONFIG_FB_READ_SRC_EN 0x00000001 90 #define PM2_CONFIG_FB_WRITE_EN 0x00000008 91 92 #define PM2_COORDS(x, y) ((y) << 16 | (x)) 93 94 95 #ifdef APERTURE 96 extern int allowaperture; 97 #endif 98 99 struct gfxp_softc { 100 struct sunfb sc_sunfb; 101 102 bus_space_tag_t sc_memt; 103 bus_space_handle_t sc_memh; 104 bus_addr_t sc_membase_le; 105 bus_size_t sc_memsize_le; 106 bus_addr_t sc_membase_be; 107 bus_size_t sc_memsize_be; 108 109 bus_space_tag_t sc_mmiot; 110 bus_space_handle_t sc_mmioh; 111 bus_addr_t sc_mmiobase; 112 bus_size_t sc_mmiosize; 113 114 pcitag_t sc_pcitag; 115 116 int sc_mode; 117 u_int8_t sc_cmap_red[256]; 118 u_int8_t sc_cmap_green[256]; 119 u_int8_t sc_cmap_blue[256]; 120 121 /* Saved state to clean up after X11. */ 122 uint32_t sc_read_mode; 123 uint32_t sc_read_pixel; 124 }; 125 126 int gfxp_ioctl(void *, u_long, caddr_t, int, struct proc *); 127 paddr_t gfxp_mmap(void *, off_t, int); 128 129 struct wsdisplay_accessops gfxp_accessops = { 130 .ioctl = gfxp_ioctl, 131 .mmap = gfxp_mmap 132 }; 133 134 int gfxp_match(struct device *, void *, void *); 135 void gfxp_attach(struct device *, struct device *, void *); 136 137 const struct cfattach gfxp_ca = { 138 sizeof(struct gfxp_softc), gfxp_match, gfxp_attach 139 }; 140 141 struct cfdriver gfxp_cd = { 142 NULL, "gfxp", DV_DULL 143 }; 144 145 int gfxp_is_console(int); 146 int gfxp_getcmap(struct gfxp_softc *, struct wsdisplay_cmap *); 147 int gfxp_putcmap(struct gfxp_softc *, struct wsdisplay_cmap *); 148 void gfxp_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); 149 150 int gfxp_copycols(void *, int, int, int, int); 151 int gfxp_erasecols(void *, int, int, int, uint32_t); 152 int gfxp_copyrows(void *, int, int, int); 153 int gfxp_eraserows(void *, int, int, uint32_t); 154 155 void gfxp_init(struct gfxp_softc *); 156 void gfxp_reinit(struct gfxp_softc *); 157 158 void gfxp_indexed_write(struct gfxp_softc *, bus_size_t, uint32_t); 159 int gfxp_wait(struct gfxp_softc *); 160 int gfxp_wait_fifo(struct gfxp_softc *, int); 161 void gfxp_copyrect(struct gfxp_softc *, int, int, int, int, int, int); 162 void gfxp_fillrect(struct gfxp_softc *, int, int, int, int, int); 163 164 int 165 gfxp_match(struct device *parent, void *cf, void *aux) 166 { 167 struct pci_attach_args *pa = aux; 168 int node; 169 char *name; 170 171 node = PCITAG_NODE(pa->pa_tag); 172 name = getpropstring(node, "name"); 173 if (strcmp(name, "TECH-SOURCE,gfxp") == 0 || 174 strcmp(name, "TSI,gfxp") == 0) 175 return (10); 176 177 return (0); 178 } 179 180 void 181 gfxp_attach(struct device *parent, struct device *self, void *aux) 182 { 183 struct gfxp_softc *sc = (struct gfxp_softc *)self; 184 struct pci_attach_args *pa = aux; 185 struct rasops_info *ri; 186 int node, console, flags; 187 char *model; 188 189 sc->sc_pcitag = pa->pa_tag; 190 191 node = PCITAG_NODE(pa->pa_tag); 192 console = gfxp_is_console(node); 193 194 printf("\n"); 195 196 model = getpropstring(node, "model"); 197 printf("%s: %s", self->dv_xname, model); 198 199 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, PM2_PCI_MEM_LE, 200 PCI_MAPREG_TYPE_MEM, &sc->sc_membase_le, &sc->sc_memsize_le, NULL)) 201 sc->sc_memsize_le = 0; 202 203 if (pci_mapreg_map(pa, PM2_PCI_MEM_BE, PCI_MAPREG_TYPE_MEM, 204 BUS_SPACE_MAP_LINEAR, &sc->sc_memt, &sc->sc_memh, 205 &sc->sc_membase_be, &sc->sc_memsize_be, 0)) { 206 printf("\n%s: can't map video memory\n", self->dv_xname); 207 return; 208 } 209 210 if (pci_mapreg_map(pa, PM2_PCI_MMIO, PCI_MAPREG_TYPE_MEM, 0, 211 &sc->sc_mmiot, &sc->sc_mmioh, &sc->sc_mmiobase, 212 &sc->sc_mmiosize, 0)) { 213 bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_memsize_be); 214 printf("\n%s: can't map mmio\n", self->dv_xname); 215 return; 216 } 217 218 fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0); 219 220 printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); 221 222 ri = &sc->sc_sunfb.sf_ro; 223 ri->ri_bits = bus_space_vaddr(sc->sc_memt, sc->sc_memh); 224 ri->ri_hw = sc; 225 226 flags = RI_BSWAP; 227 if (sc->sc_sunfb.sf_depth == 32) { 228 ri->ri_rnum = 8; 229 ri->ri_rpos = 16; 230 ri->ri_gnum = 8; 231 ri->ri_gpos = 8; 232 ri->ri_bnum = 8; 233 ri->ri_bpos = 0; 234 flags &= ~RI_BSWAP; 235 } 236 237 fbwscons_init(&sc->sc_sunfb, flags, console); 238 fbwscons_setcolormap(&sc->sc_sunfb, gfxp_setcolor); 239 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 240 241 gfxp_init(sc); 242 ri->ri_ops.copyrows = gfxp_copyrows; 243 ri->ri_ops.copycols = gfxp_copycols; 244 ri->ri_ops.eraserows = gfxp_eraserows; 245 ri->ri_ops.erasecols = gfxp_erasecols; 246 247 if (console) 248 fbwscons_console_init(&sc->sc_sunfb, -1); 249 fbwscons_attach(&sc->sc_sunfb, &gfxp_accessops, console); 250 } 251 252 int 253 gfxp_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p) 254 { 255 struct gfxp_softc *sc = v; 256 struct wsdisplay_fbinfo *wdf; 257 struct pcisel *sel; 258 259 switch (cmd) { 260 case WSDISPLAYIO_GTYPE: 261 *(u_int *)data = WSDISPLAY_TYPE_GFXP; 262 break; 263 case WSDISPLAYIO_SMODE: 264 sc->sc_mode = *(u_int *)data; 265 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 266 fbwscons_setcolormap(&sc->sc_sunfb, gfxp_setcolor); 267 268 /* Clean up the mess left behind by X. */ 269 gfxp_reinit(sc); 270 } 271 break; 272 case WSDISPLAYIO_GINFO: 273 wdf = (void *)data; 274 wdf->height = sc->sc_sunfb.sf_height; 275 wdf->width = sc->sc_sunfb.sf_width; 276 wdf->depth = sc->sc_sunfb.sf_depth; 277 wdf->stride = sc->sc_sunfb.sf_linebytes; 278 wdf->offset = 0; 279 if (sc->sc_sunfb.sf_depth == 32) 280 wdf->cmsize = 0; 281 else 282 wdf->cmsize = 256; 283 break; 284 case WSDISPLAYIO_GETSUPPORTEDDEPTH: 285 if (sc->sc_sunfb.sf_depth == 32) 286 *(u_int *)data = WSDISPLAYIO_DEPTH_24_32; 287 else 288 return (-1); 289 break; 290 case WSDISPLAYIO_LINEBYTES: 291 *(u_int *)data = sc->sc_sunfb.sf_linebytes; 292 break; 293 294 case WSDISPLAYIO_GETCMAP: 295 return gfxp_getcmap(sc, (struct wsdisplay_cmap *)data); 296 case WSDISPLAYIO_PUTCMAP: 297 return gfxp_putcmap(sc, (struct wsdisplay_cmap *)data); 298 299 case WSDISPLAYIO_GPCIID: 300 sel = (struct pcisel *)data; 301 sel->pc_bus = PCITAG_BUS(sc->sc_pcitag); 302 sel->pc_dev = PCITAG_DEV(sc->sc_pcitag); 303 sel->pc_func = PCITAG_FUN(sc->sc_pcitag); 304 break; 305 306 case WSDISPLAYIO_SVIDEO: 307 case WSDISPLAYIO_GVIDEO: 308 break; 309 310 case WSDISPLAYIO_GCURPOS: 311 case WSDISPLAYIO_SCURPOS: 312 case WSDISPLAYIO_GCURMAX: 313 case WSDISPLAYIO_GCURSOR: 314 case WSDISPLAYIO_SCURSOR: 315 default: 316 return -1; /* not supported yet */ 317 } 318 319 return (0); 320 } 321 322 paddr_t 323 gfxp_mmap(void *v, off_t off, int prot) 324 { 325 struct gfxp_softc *sc = v; 326 327 if (off & PGOFSET) 328 return (-1); 329 330 switch (sc->sc_mode) { 331 case WSDISPLAYIO_MODE_MAPPED: 332 #ifdef APERTURE 333 if (allowaperture == 0) 334 return (-1); 335 #endif 336 337 if (sc->sc_mmiosize == 0) 338 return (-1); 339 340 if (off >= sc->sc_membase_be && 341 off < (sc->sc_membase_be + sc->sc_memsize_be)) 342 return (bus_space_mmap(sc->sc_memt, 343 sc->sc_membase_be, off - sc->sc_membase_be, 344 prot, BUS_SPACE_MAP_LINEAR)); 345 346 if (off >= sc->sc_mmiobase && 347 off < (sc->sc_mmiobase + sc->sc_mmiosize)) 348 return (bus_space_mmap(sc->sc_mmiot, 349 sc->sc_mmiobase, off - sc->sc_mmiobase, 350 prot, BUS_SPACE_MAP_LINEAR)); 351 break; 352 353 case WSDISPLAYIO_MODE_DUMBFB: 354 if (off >= 0 && off < sc->sc_memsize_le) 355 return (bus_space_mmap(sc->sc_memt, sc->sc_membase_le, 356 off, prot, BUS_SPACE_MAP_LINEAR)); 357 break; 358 } 359 360 return (-1); 361 } 362 363 int 364 gfxp_is_console(int node) 365 { 366 extern int fbnode; 367 368 return (fbnode == node); 369 } 370 371 int 372 gfxp_getcmap(struct gfxp_softc *sc, struct wsdisplay_cmap *cm) 373 { 374 u_int index = cm->index; 375 u_int count = cm->count; 376 int error; 377 378 if (index >= 256 || count > 256 - index) 379 return (EINVAL); 380 381 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 382 if (error) 383 return (error); 384 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 385 if (error) 386 return (error); 387 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 388 if (error) 389 return (error); 390 return (0); 391 } 392 393 int 394 gfxp_putcmap(struct gfxp_softc *sc, struct wsdisplay_cmap *cm) 395 { 396 u_int index = cm->index; 397 u_int count = cm->count; 398 u_int i; 399 int error; 400 u_char *r, *g, *b; 401 402 if (index >= 256 || count > 256 - index) 403 return (EINVAL); 404 405 if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0) 406 return (error); 407 if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0) 408 return (error); 409 if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0) 410 return (error); 411 412 r = &sc->sc_cmap_red[index]; 413 g = &sc->sc_cmap_green[index]; 414 b = &sc->sc_cmap_blue[index]; 415 416 gfxp_wait_fifo(sc, 1); 417 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, 418 PM2_PALETTE_WRITE_ADDR, index); 419 for (i = 0; i < count; i++) { 420 gfxp_wait_fifo(sc, 3); 421 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, 422 PM2_PALETTE_DATA, *r); 423 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, 424 PM2_PALETTE_DATA, *g); 425 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, 426 PM2_PALETTE_DATA, *b); 427 r++, g++, b++; 428 } 429 return (0); 430 } 431 432 void 433 gfxp_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) 434 { 435 struct gfxp_softc *sc = v; 436 437 sc->sc_cmap_red[index] = r; 438 sc->sc_cmap_green[index] = g; 439 sc->sc_cmap_blue[index] = b; 440 441 gfxp_wait_fifo(sc, 4); 442 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, 443 PM2_PALETTE_WRITE_ADDR, index); 444 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_PALETTE_DATA, r); 445 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_PALETTE_DATA, g); 446 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_PALETTE_DATA, b); 447 } 448 449 /* 450 * Accelerated routines. 451 */ 452 453 int 454 gfxp_copycols(void *cookie, int row, int src, int dst, int num) 455 { 456 struct rasops_info *ri = cookie; 457 struct gfxp_softc *sc = ri->ri_hw; 458 459 num *= ri->ri_font->fontwidth; 460 src *= ri->ri_font->fontwidth; 461 dst *= ri->ri_font->fontwidth; 462 row *= ri->ri_font->fontheight; 463 464 gfxp_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row, 465 ri->ri_xorigin + dst, ri->ri_yorigin + row, 466 num, ri->ri_font->fontheight); 467 468 return 0; 469 } 470 471 int 472 gfxp_erasecols(void *cookie, int row, int col, int num, uint32_t attr) 473 { 474 struct rasops_info *ri = cookie; 475 struct gfxp_softc *sc = ri->ri_hw; 476 int bg, fg; 477 478 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 479 480 row *= ri->ri_font->fontheight; 481 col *= ri->ri_font->fontwidth; 482 num *= ri->ri_font->fontwidth; 483 484 gfxp_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row, 485 num, ri->ri_font->fontheight, ri->ri_devcmap[bg]); 486 487 return 0; 488 } 489 490 int 491 gfxp_copyrows(void *cookie, int src, int dst, int num) 492 { 493 struct rasops_info *ri = cookie; 494 struct gfxp_softc *sc = ri->ri_hw; 495 496 num *= ri->ri_font->fontheight; 497 src *= ri->ri_font->fontheight; 498 dst *= ri->ri_font->fontheight; 499 500 gfxp_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src, 501 ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num); 502 503 return 0; 504 } 505 506 int 507 gfxp_eraserows(void *cookie, int row, int num, uint32_t attr) 508 { 509 struct rasops_info *ri = cookie; 510 struct gfxp_softc *sc = ri->ri_hw; 511 int bg, fg; 512 int x, y, w; 513 514 ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 515 516 if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) { 517 num = ri->ri_height; 518 x = y = 0; 519 w = ri->ri_width; 520 } else { 521 num *= ri->ri_font->fontheight; 522 x = ri->ri_xorigin; 523 y = ri->ri_yorigin + row * ri->ri_font->fontheight; 524 w = ri->ri_emuwidth; 525 } 526 gfxp_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]); 527 528 return 0; 529 } 530 531 void 532 gfxp_init(struct gfxp_softc *sc) 533 { 534 /* XXX Save. */ 535 sc->sc_read_mode = bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, 536 PM2_FB_READ_MODE); 537 sc->sc_read_pixel = bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, 538 PM2_FB_READ_PIXEL); 539 } 540 541 void 542 gfxp_reinit(struct gfxp_softc *sc) 543 { 544 struct rasops_info *ri = &sc->sc_sunfb.sf_ro; 545 int i; 546 547 /* XXX Restore. */ 548 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, 549 PM2_FB_READ_MODE, sc->sc_read_mode); 550 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, 551 PM2_FB_READ_PIXEL, sc->sc_read_pixel); 552 553 /* Disable cursor. */ 554 gfxp_indexed_write(sc, PM2V_CURSOR_MODE, 0x10); 555 556 /* Clear cursor image. */ 557 for (i = 0; i < 1024; i++) 558 gfxp_indexed_write(sc, PM2V_CURSOR_PATTERN + i, 0x00); 559 560 /* Clear screen. */ 561 gfxp_fillrect(sc, 0, 0, ri->ri_width, ri->ri_height, 562 ri->ri_devcmap[WSCOL_WHITE]); 563 } 564 565 void 566 gfxp_indexed_write(struct gfxp_softc *sc, bus_size_t offset, uint32_t value) 567 { 568 gfxp_wait_fifo(sc, 3); 569 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, 570 PM2V_INDEX_HIGH, offset >> 8); 571 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, 572 PM2V_INDEX_LOW, offset & 0xff); 573 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2V_INDEX_DATA, value); 574 } 575 576 int 577 gfxp_wait_fifo(struct gfxp_softc *sc, int n) 578 { 579 int i; 580 581 for (i = 1000000; i != 0; i--) { 582 if (bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, 583 PM2_IN_FIFO_SPACE) >= n) 584 break; 585 DELAY(1); 586 } 587 588 return i; 589 } 590 591 int 592 gfxp_wait(struct gfxp_softc *sc) 593 { 594 int i; 595 596 for (i = 1000000; i != 0; i--) { 597 if (bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, 598 PM2_DMA_COUNT) == 0) 599 break; 600 DELAY(1); 601 } 602 603 /* 604 * Insert a sync into the FIFO... 605 */ 606 gfxp_wait_fifo(sc, 2); 607 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, 608 PM2_FILTER_MODE, PM2_FM_PASS_SYNC_TAG); 609 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_SYNC, 0); 610 611 /* 612 * ...and wait for it to appear on the other end, indicating 613 * completion of the operations before it. 614 */ 615 for (i = 1000000; i != 0; i--) { 616 if (bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, 617 PM2_OUT_FIFO_SPACE) > 0 && 618 bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, 619 PM2_OUT_FIFO) == PM2_SYNC_TAG) 620 break; 621 DELAY(1); 622 } 623 624 return i; 625 } 626 627 void 628 gfxp_copyrect(struct gfxp_softc *sc, int sx, int sy, int dx, int dy, 629 int w, int h) 630 { 631 int dir = 0; 632 633 if (sx > dx) 634 dir |= PM2_INCREASE_X; 635 if (sy > dy) 636 dir |= PM2_INCREASE_Y; 637 638 gfxp_wait_fifo(sc, 5); 639 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_CONFIG, 640 PM2_CONFIG_FB_WRITE_EN | PM2_CONFIG_FB_READ_SRC_EN); 641 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_FB_SRC_DELTA, 642 PM2_COORDS((sx - dx) & 0xffff, (sy - dy) & 0xffff)); 643 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_ORIG, 644 PM2_COORDS(dx, dy)); 645 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_SIZE, 646 PM2_COORDS(w, h)); 647 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RENDER, 648 PM2_RENDER_RECT | dir); 649 650 gfxp_wait(sc); 651 } 652 653 void 654 gfxp_fillrect(struct gfxp_softc *sc, int x, int y, int w, int h, int color) 655 { 656 gfxp_wait_fifo(sc, 5); 657 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_CONFIG, 658 PM2_CONFIG_FB_WRITE_EN); 659 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_ORIG, 660 PM2_COORDS(x, y)); 661 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_SIZE, 662 PM2_COORDS(w, h)); 663 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_FB_BLOCK_COLOR, 664 color); 665 bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RENDER, 666 PM2_RENDER_RECT | PM2_RENDER_FASTFILL); 667 668 gfxp_wait(sc); 669 } 670