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