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