1 /* $NetBSD: igsfb.c,v 1.44 2008/04/08 12:07:26 cegger Exp $ */ 2 3 /* 4 * Copyright (c) 2002, 2003 Valeriy E. Ushakov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * Integraphics Systems IGA 168x and CyberPro series. 32 */ 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: igsfb.c,v 1.44 2008/04/08 12:07:26 cegger Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 #include <sys/ioctl.h> 42 43 #include <sys/bus.h> 44 45 #include <dev/wscons/wsdisplayvar.h> 46 #include <dev/wscons/wsconsio.h> 47 #include <dev/wsfont/wsfont.h> 48 #include <dev/rasops/rasops.h> 49 50 #include <dev/wscons/wsdisplay_vconsvar.h> 51 52 #include <dev/ic/igsfbreg.h> 53 #include <dev/ic/igsfbvar.h> 54 55 56 struct igsfb_devconfig igsfb_console_dc; 57 58 /* 59 * wsscreen 60 */ 61 62 /* filled from rasops_info in igsfb_init_wsdisplay */ 63 static struct wsscreen_descr igsfb_stdscreen = { 64 .name = "std", 65 }; 66 67 static const struct wsscreen_descr *_igsfb_scrlist[] = { 68 &igsfb_stdscreen, 69 }; 70 71 static const struct wsscreen_list igsfb_screenlist = { 72 .nscreens = sizeof(_igsfb_scrlist) / sizeof(_igsfb_scrlist[0]), 73 .screens = _igsfb_scrlist, 74 }; 75 76 77 /* 78 * wsdisplay_accessops 79 */ 80 81 static int igsfb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 82 static paddr_t igsfb_mmap(void *, void *, off_t, int); 83 84 static struct wsdisplay_accessops igsfb_accessops = { 85 .ioctl = igsfb_ioctl, 86 .mmap = igsfb_mmap, 87 }; 88 89 90 /* 91 * acceleration 92 */ 93 static int igsfb_make_text_cursor(struct igsfb_devconfig *, 94 struct vcons_screen *); 95 static void igsfb_accel_cursor(void *, int, int, int); 96 97 static int igsfb_accel_wait(struct igsfb_devconfig *); 98 static void igsfb_accel_fill(struct igsfb_devconfig *, 99 uint32_t, uint32_t, uint16_t, uint16_t); 100 static void igsfb_accel_copy(struct igsfb_devconfig *, 101 uint32_t, uint32_t, uint16_t, uint16_t); 102 103 static void igsfb_accel_copycols(void *, int, int, int, int); 104 static void igsfb_accel_erasecols(void *, int, int, int, long); 105 static void igsfb_accel_copyrows(void *, int, int, int); 106 static void igsfb_accel_eraserows(void *, int, int, long); 107 static void igsfb_accel_putchar(void *, int, int, u_int, long); 108 109 110 /* 111 * internal functions 112 */ 113 static int igsfb_init_video(struct igsfb_devconfig *); 114 static void igsfb_init_cmap(struct igsfb_devconfig *); 115 static uint16_t igsfb_spread_bits_8(uint8_t); 116 static void igsfb_init_bit_table(struct igsfb_devconfig *); 117 static void igsfb_init_wsdisplay(void *, struct vcons_screen *, int, 118 long *); 119 120 121 static void igsfb_blank_screen(struct igsfb_devconfig *, int); 122 static int igsfb_get_cmap(struct igsfb_devconfig *, 123 struct wsdisplay_cmap *); 124 static int igsfb_set_cmap(struct igsfb_devconfig *, 125 const struct wsdisplay_cmap *); 126 static void igsfb_update_cmap(struct igsfb_devconfig *, u_int, u_int); 127 static void igsfb_set_curpos(struct igsfb_devconfig *, 128 const struct wsdisplay_curpos *); 129 static void igsfb_update_curpos(struct igsfb_devconfig *); 130 static int igsfb_get_cursor(struct igsfb_devconfig *, 131 struct wsdisplay_cursor *); 132 static int igsfb_set_cursor(struct igsfb_devconfig *, 133 const struct wsdisplay_cursor *); 134 static void igsfb_update_cursor(struct igsfb_devconfig *, u_int); 135 static void igsfb_convert_cursor_data(struct igsfb_devconfig *, 136 u_int, u_int); 137 138 139 int 140 igsfb_cnattach_subr(struct igsfb_devconfig *dc) 141 { 142 struct rasops_info *ri; 143 long defattr; 144 145 KASSERT(dc == &igsfb_console_dc); 146 147 igsfb_init_video(dc); 148 dc->dc_vd.active = NULL; 149 igsfb_init_wsdisplay(dc, &dc->dc_console, 1, &defattr); 150 151 ri = &dc->dc_console.scr_ri; 152 ri->ri_hw = &dc->dc_console; 153 dc->dc_console.scr_cookie = dc; 154 155 (*ri->ri_ops.allocattr)(ri, 156 WS_DEFAULT_FG, /* fg */ 157 WS_DEFAULT_BG, /* bg */ 158 0, /* wsattrs */ 159 &defattr); 160 161 wsdisplay_cnattach(&igsfb_stdscreen, 162 ri, /* emulcookie */ 163 0, 0, /* cursor position */ 164 defattr); 165 return 0; 166 } 167 168 169 /* 170 * Finish off the attach. Bus specific attach method should have 171 * enabled io and memory accesses and mapped io (and cop?) registers. 172 */ 173 void 174 igsfb_attach_subr(struct igsfb_softc *sc, int isconsole) 175 { 176 struct igsfb_devconfig *dc = sc->sc_dc; 177 struct wsemuldisplaydev_attach_args waa; 178 struct rasops_info *ri; 179 long defattr; 180 181 KASSERT(dc != NULL); 182 183 if (!isconsole) { 184 igsfb_init_video(dc); 185 } 186 187 vcons_init(&dc->dc_vd, dc, &igsfb_stdscreen, &igsfb_accessops); 188 dc->dc_vd.init_screen = igsfb_init_wsdisplay; 189 190 vcons_init_screen(&dc->dc_vd, &dc->dc_console, 1, &defattr); 191 dc->dc_console.scr_flags |= VCONS_SCREEN_IS_STATIC; 192 193 printf("%s: %dMB, %s%dx%d, %dbpp\n", 194 device_xname(&sc->sc_dev), 195 (uint32_t)(dc->dc_vmemsz >> 20), 196 (dc->dc_hwflags & IGSFB_HW_BSWAP) 197 ? (dc->dc_hwflags & IGSFB_HW_BE_SELECT) 198 ? "hardware bswap, " : "software bswap, " 199 : "", 200 dc->dc_width, dc->dc_height, dc->dc_depth); 201 202 ri = &dc->dc_console.scr_ri; 203 ri->ri_ops.eraserows(ri, 0, ri->ri_rows, defattr); 204 205 /* attach wsdisplay */ 206 waa.console = isconsole; 207 waa.scrdata = &igsfb_screenlist; 208 waa.accessops = &igsfb_accessops; 209 waa.accesscookie = &dc->dc_vd; 210 211 config_found(&sc->sc_dev, &waa, wsemuldisplaydevprint); 212 } 213 214 215 static int 216 igsfb_init_video(struct igsfb_devconfig *dc) 217 { 218 bus_space_handle_t tmph; 219 uint8_t *p; 220 int need_bswap; 221 bus_addr_t fbaddr, craddr; 222 off_t croffset; 223 uint8_t busctl, curctl; 224 void *va; 225 226 /* Total amount of video memory. */ 227 busctl = igs_ext_read(dc->dc_iot, dc->dc_ioh, IGS_EXT_BUS_CTL); 228 if (busctl & 0x2) 229 dc->dc_vmemsz = 4; 230 else if (busctl & 0x1) 231 dc->dc_vmemsz = 2; 232 else 233 dc->dc_vmemsz = 1; 234 dc->dc_vmemsz <<= 20; /* megabytes -> bytes */ 235 236 /* 237 * Check for endianness mismatch by writing a word at the end of 238 * the video memory (off-screen) and reading it back byte-by-byte. 239 */ 240 if (bus_space_map(dc->dc_memt, 241 dc->dc_memaddr + dc->dc_vmemsz - sizeof(uint32_t), 242 sizeof(uint32_t), 243 dc->dc_memflags | BUS_SPACE_MAP_LINEAR, 244 &tmph) != 0) 245 { 246 printf("unable to map video memory for endianness test\n"); 247 return 1; 248 } 249 250 p = bus_space_vaddr(dc->dc_memt, tmph); 251 #if BYTE_ORDER == BIG_ENDIAN 252 *((uint32_t *)p) = 0x12345678; 253 #else 254 *((uint32_t *)p) = 0x78563412; 255 #endif 256 if (p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78) 257 need_bswap = 0; 258 else 259 need_bswap = 1; 260 261 bus_space_unmap(dc->dc_memt, tmph, sizeof(uint32_t)); 262 263 /* 264 * On CyberPro we can use magic bswap bit in linear address. 265 */ 266 fbaddr = dc->dc_memaddr; 267 if (need_bswap) { 268 dc->dc_hwflags |= IGSFB_HW_BSWAP; 269 if (dc->dc_id >= 0x2000) { 270 dc->dc_hwflags |= IGSFB_HW_BE_SELECT; 271 fbaddr |= IGS_MEM_BE_SELECT; 272 } 273 } 274 275 /* 276 * XXX: TODO: make it possible to select the desired video mode. 277 * For now - hardcode to 1024x768/8bpp. This is what Krups OFW uses. 278 */ 279 igsfb_hw_setup(dc); 280 281 dc->dc_width = 1024; 282 dc->dc_height = 768; 283 dc->dc_depth = 8; 284 dc->dc_stride = dc->dc_width; 285 286 /* 287 * Don't map in all N megs, just the amount we need for the wsscreen. 288 */ 289 dc->dc_fbsz = dc->dc_width * dc->dc_height; /* XXX: 8bpp specific */ 290 if (bus_space_map(dc->dc_memt, fbaddr, dc->dc_fbsz, 291 dc->dc_memflags | BUS_SPACE_MAP_LINEAR, 292 &dc->dc_fbh) != 0) 293 { 294 bus_space_unmap(dc->dc_iot, dc->dc_ioh, IGS_REG_SIZE); 295 printf("unable to map framebuffer\n"); 296 return 1; 297 } 298 299 igsfb_init_cmap(dc); 300 301 /* 302 * 1KB for cursor sprite data at the very end of the video memory. 303 */ 304 croffset = dc->dc_vmemsz - IGS_CURSOR_DATA_SIZE; 305 craddr = fbaddr + croffset; 306 if (bus_space_map(dc->dc_memt, craddr, IGS_CURSOR_DATA_SIZE, 307 dc->dc_memflags | BUS_SPACE_MAP_LINEAR, 308 &dc->dc_crh) != 0) 309 { 310 bus_space_unmap(dc->dc_iot, dc->dc_ioh, IGS_REG_SIZE); 311 bus_space_unmap(dc->dc_memt, dc->dc_fbh, dc->dc_fbsz); 312 printf("unable to map cursor sprite region\n"); 313 return 1; 314 } 315 316 /* 317 * Tell the device where cursor sprite data are located in the 318 * linear space (it takes data offset in 1KB units). 319 */ 320 croffset >>= 10; /* bytes -> kilobytes */ 321 igs_ext_write(dc->dc_iot, dc->dc_ioh, 322 IGS_EXT_SPRITE_DATA_LO, croffset & 0xff); 323 igs_ext_write(dc->dc_iot, dc->dc_ioh, 324 IGS_EXT_SPRITE_DATA_HI, (croffset >> 8) & 0xf); 325 326 /* init the bit expansion table for cursor sprite data conversion */ 327 igsfb_init_bit_table(dc); 328 329 /* XXX: fill dc_cursor and use igsfb_update_cursor() instead? */ 330 memset(&dc->dc_cursor, 0, sizeof(struct igs_hwcursor)); 331 va = bus_space_vaddr(dc->dc_memt, dc->dc_crh); 332 memset(va, /* transparent */ 0xaa, IGS_CURSOR_DATA_SIZE); 333 334 curctl = igs_ext_read(dc->dc_iot, dc->dc_ioh, IGS_EXT_SPRITE_CTL); 335 curctl |= IGS_EXT_SPRITE_64x64; 336 curctl &= ~IGS_EXT_SPRITE_VISIBLE; 337 igs_ext_write(dc->dc_iot, dc->dc_ioh, IGS_EXT_SPRITE_CTL, curctl); 338 dc->dc_curenb = 0; 339 340 /* 341 * Map and init graphic coprocessor for accelerated rasops. 342 */ 343 if (dc->dc_id >= 0x2000) { /* XXX */ 344 if (bus_space_map(dc->dc_iot, 345 dc->dc_iobase + IGS_COP_BASE_B, IGS_COP_SIZE, 346 dc->dc_ioflags, 347 &dc->dc_coph) != 0) 348 { 349 printf("unable to map COP registers\n"); 350 return 1; 351 } 352 353 /* XXX: hardcoded 8bpp */ 354 bus_space_write_2(dc->dc_iot, dc->dc_coph, 355 IGS_COP_SRC_MAP_WIDTH_REG, 356 dc->dc_width - 1); 357 bus_space_write_2(dc->dc_iot, dc->dc_coph, 358 IGS_COP_DST_MAP_WIDTH_REG, 359 dc->dc_width - 1); 360 361 bus_space_write_1(dc->dc_iot, dc->dc_coph, 362 IGS_COP_MAP_FMT_REG, 363 IGS_COP_MAP_8BPP); 364 } 365 366 /* make sure screen is not blanked */ 367 dc->dc_blanked = 0; 368 igsfb_blank_screen(dc, dc->dc_blanked); 369 370 return 0; 371 } 372 373 374 static void 375 igsfb_init_cmap(struct igsfb_devconfig *dc) 376 { 377 bus_space_tag_t iot = dc->dc_iot; 378 bus_space_handle_t ioh = dc->dc_ioh; 379 const uint8_t *p; 380 int i; 381 382 p = rasops_cmap; /* "ANSI" color map */ 383 384 /* init software copy */ 385 for (i = 0; i < IGS_CMAP_SIZE; ++i, p += 3) { 386 dc->dc_cmap.r[i] = p[0]; 387 dc->dc_cmap.g[i] = p[1]; 388 dc->dc_cmap.b[i] = p[2]; 389 } 390 391 /* propagate to the device */ 392 igsfb_update_cmap(dc, 0, IGS_CMAP_SIZE); 393 394 /* set overscan color (XXX: use defattr's background?) */ 395 igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_RED, 0); 396 igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_GREEN, 0); 397 igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_BLUE, 0); 398 } 399 400 401 static void 402 igsfb_init_wsdisplay(void *cookie, struct vcons_screen *scr, int existing, 403 long *defattr) 404 { 405 struct igsfb_devconfig *dc = cookie; 406 struct rasops_info *ri = &scr->scr_ri; 407 int wsfcookie; 408 409 if ((scr == &dc->dc_console) && (dc->dc_vd.active != NULL)) 410 return; 411 412 413 ri->ri_flg = RI_CENTER | RI_FULLCLEAR; 414 if (IGSFB_HW_SOFT_BSWAP(dc)) 415 ri->ri_flg |= RI_BSWAP; 416 417 ri->ri_depth = dc->dc_depth; 418 ri->ri_width = dc->dc_width; 419 ri->ri_height = dc->dc_height; 420 ri->ri_stride = dc->dc_stride; 421 ri->ri_bits = bus_space_vaddr(dc->dc_memt, dc->dc_fbh); 422 423 /* 424 * Initialize wsfont related stuff. 425 */ 426 wsfont_init(); 427 428 /* prefer gallant that is identical to the one the prom uses */ 429 wsfcookie = wsfont_find("Gallant", 12, 22, 0, 430 WSDISPLAY_FONTORDER_L2R, 431 WSDISPLAY_FONTORDER_L2R); 432 if (wsfcookie <= 0) { 433 #ifdef DIAGNOSTIC 434 printf("unable to find font Gallant 12x22\n"); 435 #endif 436 wsfcookie = wsfont_find(NULL, 0, 0, 0, /* any font at all? */ 437 WSDISPLAY_FONTORDER_L2R, 438 WSDISPLAY_FONTORDER_L2R); 439 } 440 441 if (wsfcookie <= 0) { 442 printf("unable to find any fonts\n"); 443 return; 444 } 445 446 if (wsfont_lock(wsfcookie, &ri->ri_font) != 0) { 447 printf("unable to lock font\n"); 448 return; 449 } 450 ri->ri_wsfcookie = wsfcookie; 451 452 453 /* XXX: TODO: compute term size based on font dimensions? */ 454 rasops_init(ri, 34, 80); 455 rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight, 456 ri->ri_width / ri->ri_font->fontwidth); 457 458 459 /* use the sprite for the text mode cursor */ 460 igsfb_make_text_cursor(dc, scr); 461 462 /* the cursor is "busy" while we are in the text mode */ 463 dc->dc_hwflags |= IGSFB_HW_TEXT_CURSOR; 464 465 /* propagate sprite data to the device */ 466 igsfb_update_cursor(dc, WSDISPLAY_CURSOR_DOSHAPE); 467 468 /* accelerated text cursor */ 469 ri->ri_ops.cursor = igsfb_accel_cursor; 470 471 if (dc->dc_id >= 0x2000) { /* XXX */ 472 /* accelerated erase/copy */ 473 ri->ri_ops.copycols = igsfb_accel_copycols; 474 ri->ri_ops.erasecols = igsfb_accel_erasecols; 475 ri->ri_ops.copyrows = igsfb_accel_copyrows; 476 ri->ri_ops.eraserows = igsfb_accel_eraserows; 477 478 /* putchar hook to sync with the cop */ 479 dc->dc_ri_putchar = ri->ri_ops.putchar; 480 ri->ri_ops.putchar = igsfb_accel_putchar; 481 } 482 483 igsfb_stdscreen.nrows = ri->ri_rows; 484 igsfb_stdscreen.ncols = ri->ri_cols; 485 igsfb_stdscreen.textops = &ri->ri_ops; 486 igsfb_stdscreen.capabilities = ri->ri_caps; 487 } 488 489 490 /* 491 * Init cursor data in dc_cursor for the accelerated text cursor. 492 */ 493 static int 494 igsfb_make_text_cursor(struct igsfb_devconfig *dc, struct vcons_screen *scr) 495 { 496 struct rasops_info *ri = &scr->scr_ri; 497 struct wsdisplay_font *f = ri->ri_font; 498 uint16_t cc_scan[8]; /* one sprite scanline */ 499 uint16_t s; 500 int w, i; 501 502 KASSERT(f->fontwidth <= IGS_CURSOR_MAX_SIZE); 503 KASSERT(f->fontheight <= IGS_CURSOR_MAX_SIZE); 504 505 w = f->fontwidth; 506 for (i = 0; i < f->stride; ++i) { 507 if (w >= 8) { 508 s = 0xffff; /* all inverted */ 509 w -= 8; 510 } else { 511 /* first w pixels inverted, the rest is transparent */ 512 s = ~(0x5555 << (w * 2)); 513 s = htole16(s); 514 w = 0; 515 } 516 cc_scan[i] = s; 517 } 518 519 dc->dc_cursor.cc_size.x = f->fontwidth; 520 dc->dc_cursor.cc_size.y = f->fontheight; 521 522 dc->dc_cursor.cc_hot.x = 0; 523 dc->dc_cursor.cc_hot.y = 0; 524 525 /* init sprite array to be all transparent */ 526 memset(dc->dc_cursor.cc_sprite, 0xaa, IGS_CURSOR_DATA_SIZE); 527 528 for (i = 0; i < f->fontheight; ++i) 529 memcpy(&dc->dc_cursor.cc_sprite[i * 8], 530 cc_scan, f->stride * sizeof(uint16_t)); 531 532 return 0; 533 } 534 535 536 /* 537 * Spread a byte (abcd.efgh) into two (0a0b.0c0d 0e0f.0g0h). 538 * Helper function for igsfb_init_bit_table(). 539 */ 540 static uint16_t 541 igsfb_spread_bits_8(uint8_t b) 542 { 543 uint16_t s = b; 544 545 s = ((s & 0x00f0) << 4) | (s & 0x000f); 546 s = ((s & 0x0c0c) << 2) | (s & 0x0303); 547 s = ((s & 0x2222) << 1) | (s & 0x1111); 548 return s; 549 } 550 551 552 /* 553 * Cursor sprite data are in 2bpp. Incoming image/mask are in 1bpp. 554 * Prebuild the table to expand 1bpp->2bpp, with bswapping if necessary. 555 */ 556 static void 557 igsfb_init_bit_table(struct igsfb_devconfig *dc) 558 { 559 uint16_t *expand = dc->dc_bexpand; 560 uint16_t s; 561 u_int i; 562 563 for (i = 0; i < 256; ++i) { 564 s = igsfb_spread_bits_8(i); 565 expand[i] = htole16(s); 566 } 567 } 568 569 570 /* 571 * wsdisplay_accessops: mmap() 572 * XXX: allow mmapping i/o mapped i/o regs if INSECURE??? 573 */ 574 static paddr_t 575 igsfb_mmap(void *v, void *vs, off_t offset, int prot) 576 { 577 struct vcons_data *vd = v; 578 struct igsfb_devconfig *dc = vd->cookie; 579 580 if (offset >= dc->dc_memsz || offset < 0) 581 return -1; 582 583 return bus_space_mmap(dc->dc_memt, dc->dc_memaddr, offset, prot, 584 dc->dc_memflags | BUS_SPACE_MAP_LINEAR); 585 } 586 587 588 /* 589 * wsdisplay_accessops: ioctl() 590 */ 591 static int 592 igsfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 593 struct lwp *l) 594 { 595 struct vcons_data *vd = v; 596 struct igsfb_devconfig *dc = vd->cookie; 597 int cursor_busy; 598 int turnoff; 599 600 /* don't permit cursor ioctls if we use sprite for text cursor */ 601 cursor_busy = !dc->dc_mapped 602 && (dc->dc_hwflags & IGSFB_HW_TEXT_CURSOR); 603 604 switch (cmd) { 605 606 case WSDISPLAYIO_GTYPE: 607 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 608 return 0; 609 610 case WSDISPLAYIO_GINFO: 611 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 612 wsd_fbip->height = dc->dc_height; 613 wsd_fbip->width = dc->dc_width; 614 wsd_fbip->depth = dc->dc_depth; 615 wsd_fbip->cmsize = IGS_CMAP_SIZE; 616 #undef wsd_fbip 617 return 0; 618 619 case WSDISPLAYIO_LINEBYTES: 620 *(int *)data = dc->dc_stride; 621 return 0; 622 623 case WSDISPLAYIO_SMODE: 624 #define d (*(int *)data) 625 if (d != WSDISPLAYIO_MODE_EMUL) { 626 dc->dc_mapped = 1; 627 /* turn off hardware cursor */ 628 if (dc->dc_hwflags & IGSFB_HW_TEXT_CURSOR) { 629 dc->dc_curenb = 0; 630 igsfb_update_cursor(dc, 631 WSDISPLAY_CURSOR_DOCUR); 632 } 633 } else { 634 dc->dc_mapped = 0; 635 /* reinit sprite for text cursor */ 636 if (dc->dc_hwflags & IGSFB_HW_TEXT_CURSOR) { 637 igsfb_make_text_cursor(dc, dc->dc_vd.active); 638 dc->dc_curenb = 0; 639 igsfb_update_cursor(dc, 640 WSDISPLAY_CURSOR_DOSHAPE 641 | WSDISPLAY_CURSOR_DOCUR); 642 } 643 vcons_redraw_screen(vd->active); 644 } 645 return 0; 646 647 case WSDISPLAYIO_GVIDEO: 648 *(u_int *)data = dc->dc_blanked ? 649 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 650 return 0; 651 652 case WSDISPLAYIO_SVIDEO: 653 turnoff = (*(u_int *)data == WSDISPLAYIO_VIDEO_OFF); 654 if (dc->dc_blanked != turnoff) { 655 dc->dc_blanked = turnoff; 656 igsfb_blank_screen(dc, dc->dc_blanked); 657 } 658 return 0; 659 660 case WSDISPLAYIO_GETCMAP: 661 return igsfb_get_cmap(dc, (struct wsdisplay_cmap *)data); 662 663 case WSDISPLAYIO_PUTCMAP: 664 return igsfb_set_cmap(dc, (struct wsdisplay_cmap *)data); 665 666 case WSDISPLAYIO_GCURMAX: 667 ((struct wsdisplay_curpos *)data)->x = IGS_CURSOR_MAX_SIZE; 668 ((struct wsdisplay_curpos *)data)->y = IGS_CURSOR_MAX_SIZE; 669 return 0; 670 671 case WSDISPLAYIO_GCURPOS: 672 if (cursor_busy) 673 return EBUSY; 674 *(struct wsdisplay_curpos *)data = dc->dc_cursor.cc_pos; 675 return 0; 676 677 case WSDISPLAYIO_SCURPOS: 678 if (cursor_busy) 679 return EBUSY; 680 igsfb_set_curpos(dc, (struct wsdisplay_curpos *)data); 681 return 0; 682 683 case WSDISPLAYIO_GCURSOR: 684 if (cursor_busy) 685 return EBUSY; 686 return igsfb_get_cursor(dc, (struct wsdisplay_cursor *)data); 687 688 case WSDISPLAYIO_SCURSOR: 689 if (cursor_busy) 690 return EBUSY; 691 return igsfb_set_cursor(dc, (struct wsdisplay_cursor *)data); 692 } 693 694 return EPASSTHROUGH; 695 } 696 697 698 /* 699 * wsdisplay_accessops: ioctl(WSDISPLAYIO_SVIDEO) 700 */ 701 static void 702 igsfb_blank_screen(struct igsfb_devconfig *dc, int blank) 703 { 704 705 igs_ext_write(dc->dc_iot, dc->dc_ioh, 706 IGS_EXT_SYNC_CTL, 707 blank ? IGS_EXT_SYNC_H0 | IGS_EXT_SYNC_V0 708 : 0); 709 } 710 711 712 /* 713 * wsdisplay_accessops: ioctl(WSDISPLAYIO_GETCMAP) 714 * Served from the software cmap copy. 715 */ 716 static int 717 igsfb_get_cmap(struct igsfb_devconfig *dc, struct wsdisplay_cmap *p) 718 { 719 u_int index, count; 720 int err; 721 722 index = p->index; 723 count = p->count; 724 725 if (index >= IGS_CMAP_SIZE || count > IGS_CMAP_SIZE - index) 726 return EINVAL; 727 728 err = copyout(&dc->dc_cmap.r[index], p->red, count); 729 if (err) 730 return err; 731 err = copyout(&dc->dc_cmap.g[index], p->green, count); 732 if (err) 733 return err; 734 err = copyout(&dc->dc_cmap.b[index], p->blue, count); 735 if (err) 736 return err; 737 738 return 0; 739 } 740 741 742 /* 743 * wsdisplay_accessops: ioctl(WSDISPLAYIO_PUTCMAP) 744 * Set the software cmap copy and propagate changed range to the device. 745 */ 746 static int 747 igsfb_set_cmap(struct igsfb_devconfig *dc, const struct wsdisplay_cmap *p) 748 { 749 u_int index, count; 750 uint8_t r[IGS_CMAP_SIZE]; 751 uint8_t g[IGS_CMAP_SIZE]; 752 uint8_t b[IGS_CMAP_SIZE]; 753 int error; 754 755 index = p->index; 756 count = p->count; 757 if (index >= IGS_CMAP_SIZE || count > IGS_CMAP_SIZE - index) 758 return EINVAL; 759 error = copyin(p->red, &r[index], count); 760 if (error) 761 return error; 762 error = copyin(p->green, &g[index], count); 763 if (error) 764 return error; 765 error = copyin(p->blue, &b[index], count); 766 if (error) 767 return error; 768 769 memcpy(&dc->dc_cmap.r[index], &r[index], count); 770 memcpy(&dc->dc_cmap.g[index], &g[index], count); 771 memcpy(&dc->dc_cmap.b[index], &b[index], count); 772 773 /* propagate changes to the device */ 774 igsfb_update_cmap(dc, index, count); 775 return 0; 776 } 777 778 779 /* 780 * Propagate specified part of the software cmap copy to the device. 781 */ 782 static void 783 igsfb_update_cmap(struct igsfb_devconfig *dc, u_int index, u_int count) 784 { 785 bus_space_tag_t t; 786 bus_space_handle_t h; 787 u_int last, i; 788 789 if (index >= IGS_CMAP_SIZE) 790 return; 791 792 last = index + count; 793 if (last > IGS_CMAP_SIZE) 794 last = IGS_CMAP_SIZE; 795 796 t = dc->dc_iot; 797 h = dc->dc_ioh; 798 799 /* start palette writing, index is autoincremented by hardware */ 800 bus_space_write_1(t, h, IGS_DAC_PEL_WRITE_IDX, index); 801 802 for (i = index; i < last; ++i) { 803 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.r[i]); 804 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.g[i]); 805 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.b[i]); 806 } 807 } 808 809 810 /* 811 * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURPOS) 812 */ 813 static void 814 igsfb_set_curpos(struct igsfb_devconfig *dc, 815 const struct wsdisplay_curpos *curpos) 816 { 817 struct rasops_info *ri = &dc->dc_vd.active->scr_ri; 818 u_int x = curpos->x, y = curpos->y; 819 820 if (x >= ri->ri_width) 821 x = ri->ri_width - 1; 822 if (y >= ri->ri_height) 823 y = ri->ri_height - 1; 824 825 dc->dc_cursor.cc_pos.x = x; 826 dc->dc_cursor.cc_pos.y = y; 827 828 /* propagate changes to the device */ 829 igsfb_update_curpos(dc); 830 } 831 832 833 static void 834 igsfb_update_curpos(struct igsfb_devconfig *dc) 835 { 836 bus_space_tag_t t; 837 bus_space_handle_t h; 838 int x, xoff, y, yoff; 839 840 xoff = 0; 841 x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x; 842 if (x < 0) { 843 xoff = -x; 844 x = 0; 845 } 846 847 yoff = 0; 848 y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y; 849 if (y < 0) { 850 yoff = -y; 851 y = 0; 852 } 853 854 t = dc->dc_iot; 855 h = dc->dc_ioh; 856 857 igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_LO, x & 0xff); 858 igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_HI, (x >> 8) & 0x07); 859 igs_ext_write(t, h, IGS_EXT_SPRITE_HPRESET, xoff & 0x3f); 860 861 igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_LO, y & 0xff); 862 igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_HI, (y >> 8) & 0x07); 863 igs_ext_write(t, h, IGS_EXT_SPRITE_VPRESET, yoff & 0x3f); 864 } 865 866 867 /* 868 * wsdisplay_accessops: ioctl(WSDISPLAYIO_GCURSOR) 869 */ 870 static int 871 igsfb_get_cursor(struct igsfb_devconfig *dc, struct wsdisplay_cursor *p) 872 { 873 874 /* XXX: TODO */ 875 return 0; 876 } 877 878 879 /* 880 * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURSOR) 881 */ 882 static int 883 igsfb_set_cursor(struct igsfb_devconfig *dc, const struct wsdisplay_cursor *p) 884 { 885 struct igs_hwcursor *cc; 886 struct wsdisplay_curpos pos, hot; 887 u_int v, index, count, icount, iwidth; 888 uint8_t r[2], g[2], b[2], image[512], mask[512]; 889 int error; 890 891 cc = &dc->dc_cursor; 892 v = p->which; 893 index = count = icount = iwidth = 0; /* XXX: gcc */ 894 pos.x = pos.y = 0; /* XXX: gcc */ 895 896 /* copy in the new cursor colormap */ 897 if (v & WSDISPLAY_CURSOR_DOCMAP) { 898 index = p->cmap.index; 899 count = p->cmap.count; 900 if (index >= 2 || (index + count) > 2) 901 return EINVAL; 902 error = copyin(p->cmap.red, &r[index], count); 903 if (error) 904 return error; 905 error = copyin(p->cmap.green, &g[index], count); 906 if (error) 907 return error; 908 error = copyin(p->cmap.blue, &b[index], count); 909 if (error) 910 return error; 911 } 912 913 /* verify that the new cursor data are valid */ 914 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 915 if (p->size.x > IGS_CURSOR_MAX_SIZE 916 || p->size.y > IGS_CURSOR_MAX_SIZE) 917 return EINVAL; 918 919 iwidth = (p->size.x + 7) >> 3; /* bytes per scan line */ 920 icount = iwidth * p->size.y; 921 error = copyin(p->image, image, icount); 922 if (error) 923 return error; 924 error = copyin(p->mask, mask, icount); 925 if (error) 926 return error; 927 } 928 929 /* enforce that the position is within screen bounds */ 930 if (v & WSDISPLAY_CURSOR_DOPOS) { 931 struct rasops_info *ri = &dc->dc_vd.active->scr_ri; 932 933 pos = p->pos; /* local copy we can write to */ 934 if (pos.x >= ri->ri_width) 935 pos.x = ri->ri_width - 1; 936 if (pos.y >= ri->ri_height) 937 pos.y = ri->ri_height - 1; 938 } 939 940 /* enforce that the hot spot is within sprite bounds */ 941 if (v & WSDISPLAY_CURSOR_DOHOT) 942 hot = p->hot; /* local copy we can write to */ 943 944 if (v & (WSDISPLAY_CURSOR_DOHOT | WSDISPLAY_CURSOR_DOSHAPE)) { 945 const struct wsdisplay_curpos *nsize; 946 struct wsdisplay_curpos *nhot; 947 948 nsize = (v & WSDISPLAY_CURSOR_DOSHAPE) ? 949 &p->size : &cc->cc_size; 950 nhot = (v & WSDISPLAY_CURSOR_DOHOT) ? &hot : &cc->cc_hot; 951 952 if (nhot->x >= nsize->x) 953 nhot->x = nsize->x - 1; 954 if (nhot->y >= nsize->y) 955 nhot->y = nsize->y - 1; 956 } 957 958 /* copy data to the driver's cursor info */ 959 if (v & WSDISPLAY_CURSOR_DOCUR) 960 dc->dc_curenb = p->enable; 961 if (v & WSDISPLAY_CURSOR_DOPOS) 962 cc->cc_pos = pos; /* local copy, possibly corrected */ 963 if (v & WSDISPLAY_CURSOR_DOHOT) 964 cc->cc_hot = hot; /* local copy, possibly corrected */ 965 if (v & WSDISPLAY_CURSOR_DOCMAP) { 966 memcpy(&cc->cc_color[index], &r[index], count); 967 memcpy(&cc->cc_color[index + 2], &g[index], count); 968 memcpy(&cc->cc_color[index + 4], &b[index], count); 969 } 970 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 971 u_int trailing_bits; 972 973 memcpy(cc->cc_image, image, icount); 974 memcpy(cc->cc_mask, mask, icount); 975 cc->cc_size = p->size; 976 977 /* clear trailing bits in the "partial" mask bytes */ 978 trailing_bits = p->size.x & 0x07; 979 if (trailing_bits != 0) { 980 const u_int cutmask = ~((~0) << trailing_bits); 981 u_char *mp; 982 u_int i; 983 984 mp = cc->cc_mask + iwidth - 1; 985 for (i = 0; i < p->size.y; ++i) { 986 *mp &= cutmask; 987 mp += iwidth; 988 } 989 } 990 igsfb_convert_cursor_data(dc, iwidth, p->size.y); 991 } 992 993 /* propagate changes to the device */ 994 igsfb_update_cursor(dc, v); 995 996 return 0; 997 } 998 999 1000 /* 1001 * Convert incoming 1bpp cursor image/mask into native 2bpp format. 1002 */ 1003 static void 1004 igsfb_convert_cursor_data(struct igsfb_devconfig *dc, 1005 u_int width, u_int height) 1006 { 1007 struct igs_hwcursor *cc = &dc->dc_cursor; 1008 uint16_t *expand = dc->dc_bexpand; 1009 uint8_t *ip, *mp; 1010 uint16_t is, ms, *dp; 1011 u_int line, i; 1012 1013 /* init sprite to be all transparent */ 1014 memset(cc->cc_sprite, 0xaa, IGS_CURSOR_DATA_SIZE); 1015 1016 /* first scanline */ 1017 ip = cc->cc_image; 1018 mp = cc->cc_mask; 1019 dp = cc->cc_sprite; 1020 1021 for (line = 0; line < height; ++line) { 1022 for (i = 0; i < width; ++i) { 1023 is = expand[ip[i]]; /* image: 0 -> 00, 1 -> 01 */ 1024 ms = expand[mp[i]]; /* mask: 0 -> 00, 1 -> 11 */ 1025 ms |= (ms << 1); 1026 dp[i] = (0xaaaa & ~ms) | (is & ms); 1027 } 1028 1029 /* next scanline */ 1030 ip += width; 1031 mp += width; 1032 dp += 8; /* 64 pixels, 2bpp, 8 pixels per short = 8 shorts */ 1033 } 1034 } 1035 1036 1037 /* 1038 * Propagate cursor changes to the device. 1039 * "which" is composed of WSDISPLAY_CURSOR_DO* bits. 1040 */ 1041 static void 1042 igsfb_update_cursor(struct igsfb_devconfig *dc, u_int which) 1043 { 1044 bus_space_tag_t iot = dc->dc_iot; 1045 bus_space_handle_t ioh = dc->dc_ioh; 1046 uint8_t curctl; 1047 1048 curctl = 0; /* XXX: gcc */ 1049 1050 /* 1051 * We will need to tweak sprite control register for cursor 1052 * visibility and cursor color map manipulation. 1053 */ 1054 if (which & (WSDISPLAY_CURSOR_DOCUR | WSDISPLAY_CURSOR_DOCMAP)) { 1055 curctl = igs_ext_read(iot, ioh, IGS_EXT_SPRITE_CTL); 1056 } 1057 1058 if (which & WSDISPLAY_CURSOR_DOSHAPE) { 1059 uint8_t *dst = bus_space_vaddr(dc->dc_memt, dc->dc_crh); 1060 1061 /* 1062 * memcpy between spaces of different endianness would 1063 * be ... special. We cannot be sure if memcpy gonna 1064 * push data in 4-byte chunks, we can't pre-bswap it, 1065 * so do it byte-by-byte to preserve byte ordering. 1066 */ 1067 if (IGSFB_HW_SOFT_BSWAP(dc)) { 1068 uint8_t *src = (uint8_t *)dc->dc_cursor.cc_sprite; 1069 int i; 1070 1071 for (i = 0; i < IGS_CURSOR_DATA_SIZE; ++i) 1072 *dst++ = *src++; 1073 } else { 1074 memcpy(dst, dc->dc_cursor.cc_sprite, 1075 IGS_CURSOR_DATA_SIZE); 1076 } 1077 } 1078 1079 if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 1080 /* code shared with WSDISPLAYIO_SCURPOS */ 1081 igsfb_update_curpos(dc); 1082 } 1083 1084 if (which & WSDISPLAY_CURSOR_DOCMAP) { 1085 uint8_t *p; 1086 1087 /* tell DAC we want access to the cursor palette */ 1088 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, 1089 curctl | IGS_EXT_SPRITE_DAC_PEL); 1090 1091 p = dc->dc_cursor.cc_color; 1092 1093 bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 0); 1094 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[0]); 1095 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[2]); 1096 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[4]); 1097 1098 bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 1); 1099 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[1]); 1100 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[3]); 1101 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[5]); 1102 1103 /* restore access to the normal palette */ 1104 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, curctl); 1105 } 1106 1107 if (which & WSDISPLAY_CURSOR_DOCUR) { 1108 if ((curctl & IGS_EXT_SPRITE_VISIBLE) == 0 1109 && dc->dc_curenb) 1110 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, 1111 curctl | IGS_EXT_SPRITE_VISIBLE); 1112 else if ((curctl & IGS_EXT_SPRITE_VISIBLE) != 0 1113 && !dc->dc_curenb) 1114 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, 1115 curctl & ~IGS_EXT_SPRITE_VISIBLE); 1116 } 1117 } 1118 1119 1120 /* 1121 * Accelerated text mode cursor that uses hardware sprite. 1122 */ 1123 static void 1124 igsfb_accel_cursor(void *cookie, int on, int row, int col) 1125 { 1126 struct rasops_info *ri = (struct rasops_info *)cookie; 1127 struct vcons_screen *scr = ri->ri_hw; 1128 struct igsfb_devconfig *dc = scr->scr_cookie; 1129 struct igs_hwcursor *cc = &dc->dc_cursor; 1130 u_int which; 1131 1132 ri->ri_crow = row; 1133 ri->ri_ccol = col; 1134 1135 which = 0; 1136 if (on) { 1137 ri->ri_flg |= RI_CURSOR; 1138 1139 /* only bother to move the cursor if it's visible */ 1140 cc->cc_pos.x = ri->ri_xorigin 1141 + ri->ri_ccol * ri->ri_font->fontwidth; 1142 cc->cc_pos.y = ri->ri_yorigin 1143 + ri->ri_crow * ri->ri_font->fontheight; 1144 which |= WSDISPLAY_CURSOR_DOPOS; 1145 } else 1146 ri->ri_flg &= ~RI_CURSOR; 1147 1148 if (dc->dc_curenb != on) { 1149 dc->dc_curenb = on; 1150 which |= WSDISPLAY_CURSOR_DOCUR; 1151 } 1152 1153 /* propagate changes to the device */ 1154 igsfb_update_cursor(dc, which); 1155 } 1156 1157 1158 1159 /* 1160 * Accelerated raster ops that use graphic coprocessor. 1161 */ 1162 1163 static int 1164 igsfb_accel_wait(struct igsfb_devconfig *dc) 1165 { 1166 bus_space_tag_t t = dc->dc_iot; 1167 bus_space_handle_t h = dc->dc_coph; 1168 int timo = 100000; 1169 uint8_t reg; 1170 1171 while (timo--) { 1172 reg = bus_space_read_1(t, h, IGS_COP_CTL_REG); 1173 if ((reg & IGS_COP_CTL_BUSY) == 0) 1174 return 0; 1175 } 1176 1177 return 1; 1178 } 1179 1180 1181 static void 1182 igsfb_accel_copy(struct igsfb_devconfig *dc, uint32_t src, uint32_t dst, 1183 uint16_t width, uint16_t height) 1184 { 1185 bus_space_tag_t t = dc->dc_iot; 1186 bus_space_handle_t h = dc->dc_coph; 1187 uint32_t toend; 1188 uint8_t drawcmd; 1189 1190 drawcmd = IGS_COP_DRAW_ALL; 1191 if (dst > src) { 1192 toend = dc->dc_vd.active->scr_ri.ri_width * (height - 1) + (width - 1); 1193 src += toend; 1194 dst += toend; 1195 drawcmd |= IGS_COP_OCTANT_X_NEG | IGS_COP_OCTANT_Y_NEG; 1196 } 1197 1198 igsfb_accel_wait(dc); 1199 bus_space_write_1(t, h, IGS_COP_CTL_REG, 0); 1200 1201 bus_space_write_1(t, h, IGS_COP_FG_MIX_REG, IGS_COP_MIX_S); 1202 1203 bus_space_write_2(t, h, IGS_COP_WIDTH_REG, width - 1); 1204 bus_space_write_2(t, h, IGS_COP_HEIGHT_REG, height - 1); 1205 1206 bus_space_write_4(t, h, IGS_COP_SRC_START_REG, src); 1207 bus_space_write_4(t, h, IGS_COP_DST_START_REG, dst); 1208 1209 bus_space_write_1(t, h, IGS_COP_PIXEL_OP_0_REG, drawcmd); 1210 bus_space_write_1(t, h, IGS_COP_PIXEL_OP_1_REG, IGS_COP_PPM_FIXED_FG); 1211 bus_space_write_1(t, h, IGS_COP_PIXEL_OP_2_REG, 0); 1212 bus_space_write_1(t, h, IGS_COP_PIXEL_OP_3_REG, 1213 IGS_COP_OP_PXBLT | IGS_COP_OP_FG_FROM_SRC); 1214 } 1215 1216 1217 static void 1218 igsfb_accel_fill(struct igsfb_devconfig *dc, uint32_t color, uint32_t dst, 1219 uint16_t width, uint16_t height) 1220 { 1221 bus_space_tag_t t = dc->dc_iot; 1222 bus_space_handle_t h = dc->dc_coph; 1223 1224 igsfb_accel_wait(dc); 1225 bus_space_write_1(t, h, IGS_COP_CTL_REG, 0); 1226 1227 bus_space_write_1(t, h, IGS_COP_FG_MIX_REG, IGS_COP_MIX_S); 1228 1229 bus_space_write_2(t, h, IGS_COP_WIDTH_REG, width - 1); 1230 bus_space_write_2(t, h, IGS_COP_HEIGHT_REG, height - 1); 1231 1232 bus_space_write_4(t, h, IGS_COP_DST_START_REG, dst); 1233 bus_space_write_4(t, h, IGS_COP_FG_REG, color); 1234 1235 bus_space_write_1(t, h, IGS_COP_PIXEL_OP_0_REG, IGS_COP_DRAW_ALL); 1236 bus_space_write_1(t, h, IGS_COP_PIXEL_OP_1_REG, IGS_COP_PPM_FIXED_FG); 1237 bus_space_write_1(t, h, IGS_COP_PIXEL_OP_2_REG, 0); 1238 bus_space_write_1(t, h, IGS_COP_PIXEL_OP_3_REG, IGS_COP_OP_PXBLT); 1239 } 1240 1241 1242 static void 1243 igsfb_accel_copyrows(void *cookie, int src, int dst, int num) 1244 { 1245 struct rasops_info *ri = (struct rasops_info *)cookie; 1246 struct vcons_screen *scr = ri->ri_hw; 1247 struct igsfb_devconfig *dc = (struct igsfb_devconfig *)scr->scr_cookie; 1248 uint32_t srp, dsp; 1249 uint16_t width, height; 1250 1251 width = ri->ri_emuwidth; 1252 height = num * ri->ri_font->fontheight; 1253 1254 srp = ri->ri_xorigin 1255 + ri->ri_width * (ri->ri_yorigin 1256 + src * ri->ri_font->fontheight); 1257 dsp = ri->ri_xorigin 1258 + ri->ri_width * (ri->ri_yorigin 1259 + dst * ri->ri_font->fontheight); 1260 1261 igsfb_accel_copy(dc, srp, dsp, width, height); 1262 } 1263 1264 1265 static void 1266 igsfb_accel_copycols(void *cookie, int row, int src, int dst, int num) 1267 { 1268 struct rasops_info *ri = (struct rasops_info *)cookie; 1269 struct vcons_screen *scr = ri->ri_hw; 1270 struct igsfb_devconfig *dc = (struct igsfb_devconfig *)scr->scr_cookie; 1271 uint32_t rowp, srp, dsp; 1272 uint16_t width, height; 1273 1274 width = num * ri->ri_font->fontwidth; 1275 height = ri->ri_font->fontheight; 1276 1277 rowp = ri->ri_xorigin 1278 + ri->ri_width * (ri->ri_yorigin 1279 + row * ri->ri_font->fontheight); 1280 1281 srp = rowp + src * ri->ri_font->fontwidth; 1282 dsp = rowp + dst * ri->ri_font->fontwidth; 1283 1284 igsfb_accel_copy(dc, srp, dsp, width, height); 1285 } 1286 1287 1288 static void 1289 igsfb_accel_eraserows(void *cookie, int row, int num, long attr) 1290 { 1291 struct rasops_info *ri = (struct rasops_info *)cookie; 1292 struct vcons_screen *scr = ri->ri_hw; 1293 struct igsfb_devconfig *dc = (struct igsfb_devconfig *)scr->scr_cookie; 1294 uint32_t color; 1295 uint32_t dsp; 1296 uint16_t width, height; 1297 1298 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) { 1299 width = ri->ri_width; 1300 height = ri->ri_height; 1301 dsp = 0; 1302 } else { 1303 width = ri->ri_emuwidth; 1304 height = num * ri->ri_font->fontheight; 1305 1306 dsp = ri->ri_xorigin 1307 + ri->ri_width * (ri->ri_yorigin 1308 + row * ri->ri_font->fontheight); 1309 } 1310 1311 /* XXX: we "know" the encoding that rasops' allocattr uses */ 1312 color = (attr >> 16) & 0xff; 1313 1314 igsfb_accel_fill(dc, color, dsp, width, height); 1315 } 1316 1317 1318 static void 1319 igsfb_accel_erasecols(void *cookie, int row, int col, int num, long attr) 1320 { 1321 struct rasops_info *ri = (struct rasops_info *)cookie; 1322 struct vcons_screen *scr = ri->ri_hw; 1323 struct igsfb_devconfig *dc = (struct igsfb_devconfig *)scr->scr_cookie; 1324 uint32_t color; 1325 uint32_t rowp, dsp; 1326 uint16_t width, height; 1327 1328 width = num * ri->ri_font->fontwidth; 1329 height = ri->ri_font->fontheight; 1330 1331 rowp = ri->ri_xorigin 1332 + ri->ri_width * (ri->ri_yorigin 1333 + row * ri->ri_font->fontheight); 1334 1335 dsp = rowp + col * ri->ri_font->fontwidth; 1336 1337 /* XXX: we "know" the encoding that rasops' allocattr uses */ 1338 color = (attr >> 16) & 0xff; 1339 1340 igsfb_accel_fill(dc, color, dsp, width, height); 1341 } 1342 1343 1344 /* 1345 * Not really implemented here, but we need to hook into the one 1346 * supplied by rasops so that we can synchronize with the COP. 1347 */ 1348 static void 1349 igsfb_accel_putchar(void *cookie, int row, int col, u_int uc, long attr) 1350 { 1351 struct rasops_info *ri = (struct rasops_info *)cookie; 1352 struct vcons_screen *scr = ri->ri_hw; 1353 struct igsfb_devconfig *dc = (struct igsfb_devconfig *)scr->scr_cookie; 1354 1355 igsfb_accel_wait(dc); 1356 (*dc->dc_ri_putchar)(cookie, row, col, uc, attr); 1357 } 1358