1 /* $OpenBSD: mgx.c,v 1.11 2008/12/27 17:23:03 miod Exp $ */ 2 /* 3 * Copyright (c) 2003, Miodrag Vallat. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 29 /* 30 * Driver for the Southland Media Systems (now Quantum 3D) MGX and MGXPlus 31 * frame buffers. 32 * 33 * This board is built of an Alliance Promotion AT24 chip, and a simple 34 * SBus-PCI glue logic. It also sports an EEPROM to store configuration 35 * parameters, which can be controlled from SunOS or Solaris with the 36 * mgxconfig utility. 37 * 38 * We currently don't reprogram the video mode at all, so only the resolution 39 * and depth set by the PROM (or mgxconfig) will be used. 40 * 41 * Also, interrupts are not handled. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/buf.h> 47 #include <sys/device.h> 48 #include <sys/ioctl.h> 49 #include <sys/malloc.h> 50 #include <sys/mman.h> 51 #include <sys/tty.h> 52 #include <sys/conf.h> 53 54 #include <uvm/uvm_extern.h> 55 56 #include <machine/autoconf.h> 57 #include <machine/pmap.h> 58 #include <machine/cpu.h> 59 #include <machine/conf.h> 60 61 #include <dev/wscons/wsconsio.h> 62 #include <dev/wscons/wsdisplayvar.h> 63 #include <dev/rasops/rasops.h> 64 #include <machine/fbvar.h> 65 66 #include <dev/ic/vgareg.h> 67 #include <dev/ic/atxxreg.h> 68 69 #include <dev/sbus/sbusvar.h> 70 71 /* 72 * MGX PROM register layout 73 * 74 * The cards FCode registers 9 regions: 75 * 76 * region offset size description 77 * 0 00000000 00010000 FCode (32KB only) 78 * 1 00100000 00010000 FCode, repeated 79 * 2 00200000 00001000 unknown, repeats every 0x100 80 * with little differences, could be the EEPROM image 81 * 3 00400000 00001000 PCI configuration space 82 * 4 00500000 00001000 CRTC 83 * 5 00600000 00001000 AT24 registers (offset 0xb0000) 84 * 6 00700000 00010000 unknown 85 * 7 00800000 00800000 unknown 86 * 8 01000000 00400000 video memory 87 */ 88 89 #define MGX_NREG 9 90 #define MGX_REG_CRTC 4 /* video control and ramdac */ 91 #define MGX_REG_ATREG 5 /* AT24 registers */ 92 #define MGX_REG_ATREG_OFFSET 0x000b0000 93 #define MGX_REG_ATREG_SIZE 0x00000400 94 #define MGX_REG_VRAM8 8 /* 8-bit memory space */ 95 96 /* 97 * MGX CRTC access 98 * 99 * The CRTC only answers to the following ``port'' locations: 100 * - a subset of the VGA registers: 101 * 3c0, 3c1 (ATC) 102 * 3c4, 3c5 (TS sequencer) 103 * 3c6-3c9 (DAC) 104 * 3c2, 3cc (Misc) 105 * 3ce, 3cf (GDC) 106 * 107 * - the CRTC (6845-style) registers: 108 * 3d4 index register 109 * 3d5 data register 110 */ 111 112 #define VGA_BASE 0x03c0 113 #define TS_INDEX (VGA_BASE + VGA_TS_INDEX) 114 #define TS_DATA (VGA_BASE + VGA_TS_DATA) 115 #define CD_DISABLEVIDEO 0x0020 116 #define CMAP_WRITE_INDEX (VGA_BASE + 0x08) 117 #define CMAP_DATA (VGA_BASE + 0x09) 118 119 /* per-display variables */ 120 struct mgx_softc { 121 struct sunfb sc_sunfb; /* common base device */ 122 bus_space_tag_t sc_bustag; 123 bus_addr_t sc_paddr; /* for mmap() */ 124 u_int8_t sc_cmap[256 * 3]; /* shadow colormap */ 125 vaddr_t sc_vidc; /* ramdac registers */ 126 vaddr_t sc_xreg; /* AT24 registers */ 127 uint32_t sc_dec; /* dec register template */ 128 int sc_nscreens; 129 }; 130 131 void mgx_burner(void *, u_int ,u_int); 132 int mgx_ioctl(void *, u_long, caddr_t, int, struct proc *); 133 paddr_t mgx_mmap(void *, off_t, int); 134 135 struct wsdisplay_accessops mgx_accessops = { 136 mgx_ioctl, 137 mgx_mmap, 138 NULL, /* alloc_screen */ 139 NULL, /* free_screen */ 140 NULL, /* show_screen */ 141 NULL, /* load_font */ 142 NULL, /* scrollback */ 143 NULL, /* getchar */ 144 mgx_burner 145 }; 146 147 int mgx_getcmap(u_int8_t *, struct wsdisplay_cmap *); 148 void mgx_loadcmap(struct mgx_softc *, int, int); 149 int mgx_putcmap(u_int8_t *, struct wsdisplay_cmap *); 150 void mgx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); 151 152 void mgx_ras_copycols(void *, int, int, int, int); 153 void mgx_ras_copyrows(void *, int, int, int); 154 void mgx_ras_do_cursor(struct rasops_info *); 155 void mgx_ras_erasecols(void *, int, int, int, long int); 156 void mgx_ras_eraserows(void *, int, int, long int); 157 void mgx_ras_init(struct mgx_softc *, uint); 158 159 uint8_t mgx_read_1(vaddr_t, uint); 160 uint16_t mgx_read_2(vaddr_t, uint); 161 void mgx_write_1(vaddr_t, uint, uint8_t); 162 void mgx_write_4(vaddr_t, uint, uint32_t); 163 164 int mgx_wait_engine(struct mgx_softc *); 165 int mgx_wait_fifo(struct mgx_softc *, uint); 166 167 /* 168 * Attachment Glue 169 */ 170 171 int mgxmatch(struct device *, void *, void *); 172 void mgxattach(struct device *, struct device *, void *); 173 174 struct cfattach mgx_ca = { 175 sizeof(struct mgx_softc), mgxmatch, mgxattach 176 }; 177 178 struct cfdriver mgx_cd = { 179 NULL, "mgx", DV_DULL 180 }; 181 182 /* 183 * Match an MGX or MGX+ card. 184 */ 185 int 186 mgxmatch(struct device *parent, void *vcf, void *aux) 187 { 188 struct sbus_attach_args *sa = aux; 189 190 if (strcmp(sa->sa_name, "SMSI,mgx") != 0 && 191 strcmp(sa->sa_name, "mgx") != 0) 192 return (0); 193 194 return (1); 195 } 196 197 /* 198 * Attach an MGX frame buffer. 199 * This will keep the frame buffer in the actual PROM mode, and attach 200 * a wsdisplay child device to itself. 201 */ 202 void 203 mgxattach(struct device *parent, struct device *self, void *args) 204 { 205 struct mgx_softc *sc = (struct mgx_softc *)self; 206 struct sbus_attach_args *sa = args; 207 bus_space_tag_t bt; 208 bus_space_handle_t bh; 209 int node, fbsize; 210 int isconsole; 211 uint16_t chipid; 212 213 bt = sa->sa_bustag; 214 node = sa->sa_node; 215 216 printf(": %s", getpropstring(node, "model")); 217 218 isconsole = node == fbnode; 219 220 /* Check registers */ 221 if (sa->sa_nreg < MGX_NREG) { 222 printf("\n%s: expected %d registers, got %d\n", 223 self->dv_xname, MGX_NREG, sa->sa_nreg); 224 return; 225 } 226 227 sc->sc_bustag = bt; 228 if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_CRTC].sbr_slot, 229 sa->sa_reg[MGX_REG_CRTC].sbr_offset, PAGE_SIZE, 230 BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { 231 printf("\n%s: couldn't map crtc registers\n", self->dv_xname); 232 return; 233 } 234 sc->sc_vidc = (vaddr_t)bus_space_vaddr(bt, bh); 235 236 sc->sc_bustag = bt; 237 if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_ATREG].sbr_slot, 238 sa->sa_reg[MGX_REG_ATREG].sbr_offset + MGX_REG_ATREG_OFFSET, 239 MGX_REG_ATREG_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { 240 printf("\n%s: couldn't map crtc registers\n", self->dv_xname); 241 /* XXX unmap vidc */ 242 return; 243 } 244 sc->sc_xreg = (vaddr_t)bus_space_vaddr(bt, bh); 245 246 /* 247 * Check the chip ID. If it's not an AT24, prefer not to access 248 * the extended registers at all. 249 */ 250 chipid = mgx_read_2(sc->sc_xreg, ATR_ID); 251 if (chipid != ID_AT24) { 252 sc->sc_xreg = (vaddr_t)0; 253 } 254 255 /* enable video */ 256 mgx_burner(sc, 1, 0); 257 258 fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0); 259 260 /* Sanity check frame buffer memory */ 261 fbsize = getpropint(node, "fb_size", 0); 262 if (fbsize != 0 && sc->sc_sunfb.sf_fbsize > fbsize) { 263 printf("\n%s: expected at least %d bytes of vram, but card " 264 "only provides %d\n", 265 self->dv_xname, sc->sc_sunfb.sf_fbsize, fbsize); 266 return; 267 } 268 269 /* Map the frame buffer memory area we're interested in */ 270 sc->sc_paddr = sbus_bus_addr(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot, 271 sa->sa_reg[MGX_REG_VRAM8].sbr_offset); 272 if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot, 273 sa->sa_reg[MGX_REG_VRAM8].sbr_offset, 274 round_page(sc->sc_sunfb.sf_fbsize), 275 BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { 276 printf("\n%s: couldn't map video memory\n", self->dv_xname); 277 /* XXX unmap vidc and xreg */ 278 return; 279 } 280 sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh); 281 sc->sc_sunfb.sf_ro.ri_hw = sc; 282 283 printf(", %dx%d\n", 284 sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); 285 286 fbwscons_init(&sc->sc_sunfb, 0, isconsole); 287 288 bzero(sc->sc_cmap, sizeof(sc->sc_cmap)); 289 fbwscons_setcolormap(&sc->sc_sunfb, mgx_setcolor); 290 291 if (chipid != ID_AT24) { 292 printf("%s: unexpected engine id %04x\n", 293 self->dv_xname, chipid); 294 } 295 296 mgx_ras_init(sc, chipid); 297 298 if (isconsole) 299 fbwscons_console_init(&sc->sc_sunfb, -1); 300 301 fbwscons_attach(&sc->sc_sunfb, &mgx_accessops, isconsole); 302 } 303 304 /* 305 * Register Access 306 * 307 * On big-endian systems such as the sparc, it is necessary to flip 308 * the low-order bits of the addresses to reach the right register. 309 */ 310 311 uint8_t 312 mgx_read_1(vaddr_t regs, uint offs) 313 { 314 #if _BYTE_ORDER == _LITTLE_ENDIAN 315 return *(volatile uint8_t *)(regs + offs); 316 #else 317 return *(volatile uint8_t *)(regs + (offs ^ 3)); 318 #endif 319 } 320 321 uint16_t 322 mgx_read_2(vaddr_t regs, uint offs) 323 { 324 #if _BYTE_ORDER == _LITTLE_ENDIAN 325 return *(volatile uint16_t *)(regs + offs); 326 #else 327 return *(volatile uint16_t *)(regs + (offs ^ 2)); 328 #endif 329 } 330 331 void 332 mgx_write_1(vaddr_t regs, uint offs, uint8_t val) 333 { 334 #if _BYTE_ORDER == _LITTLE_ENDIAN 335 *(volatile uint8_t *)(regs + offs) = val; 336 #else 337 *(volatile uint8_t *)(regs + (offs ^ 3)) = val; 338 #endif 339 } 340 341 void 342 mgx_write_4(vaddr_t regs, uint offs, uint32_t val) 343 { 344 *(volatile uint32_t *)(regs + offs) = val; 345 } 346 347 /* 348 * Wsdisplay Operations 349 */ 350 351 int 352 mgx_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p) 353 { 354 struct mgx_softc *sc = dev; 355 struct wsdisplay_cmap *cm; 356 struct wsdisplay_fbinfo *wdf; 357 int error; 358 359 switch (cmd) { 360 case WSDISPLAYIO_GTYPE: 361 *(u_int *)data = WSDISPLAY_TYPE_MGX; 362 break; 363 case WSDISPLAYIO_GINFO: 364 wdf = (struct wsdisplay_fbinfo *)data; 365 wdf->height = sc->sc_sunfb.sf_height; 366 wdf->width = sc->sc_sunfb.sf_width; 367 wdf->depth = sc->sc_sunfb.sf_depth; 368 wdf->cmsize = 256; 369 break; 370 case WSDISPLAYIO_LINEBYTES: 371 *(u_int *)data = sc->sc_sunfb.sf_linebytes; 372 break; 373 374 case WSDISPLAYIO_GETCMAP: 375 cm = (struct wsdisplay_cmap *)data; 376 error = mgx_getcmap(sc->sc_cmap, cm); 377 if (error != 0) 378 return (error); 379 break; 380 case WSDISPLAYIO_PUTCMAP: 381 cm = (struct wsdisplay_cmap *)data; 382 error = mgx_putcmap(sc->sc_cmap, cm); 383 if (error != 0) 384 return (error); 385 mgx_loadcmap(sc, cm->index, cm->count); 386 break; 387 388 case WSDISPLAYIO_SVIDEO: 389 case WSDISPLAYIO_GVIDEO: 390 break; 391 392 default: 393 return (-1); 394 } 395 396 return (0); 397 } 398 399 paddr_t 400 mgx_mmap(void *v, off_t offset, int prot) 401 { 402 struct mgx_softc *sc = v; 403 404 if (offset & PGOFSET) 405 return (-1); 406 407 /* Allow mapping as a dumb framebuffer from offset 0 */ 408 if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { 409 return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, 410 offset, prot, BUS_SPACE_MAP_LINEAR)); 411 } 412 413 return (-1); 414 } 415 416 void 417 mgx_burner(void *v, u_int on, u_int flags) 418 { 419 struct mgx_softc *sc = v; 420 uint mode; 421 422 #ifdef notyet 423 if (sc->sc_xreg != 0) { 424 mode = mgx_read_1(sc->sc_xreg, ATR_DPMS); 425 if (on) 426 CLR(mode, DPMS_HSYNC_DISABLE | DPMS_VSYNC_DISABLE); 427 else { 428 SET(mode, DPMS_HSYNC_DISABLE); 429 #if 0 /* needs ramdac reprogramming on resume */ 430 if (flags & WSDISPLAY_BURN_VBLANK) 431 SET(mode, DPMS_VSYNC_DISABLE); 432 #endif 433 } 434 mgx_write_1(sc->sc_xreg, ATR_DPMS, mode); 435 return; 436 } 437 #endif 438 439 mgx_write_1(sc->sc_vidc, TS_INDEX, 1); /* TS mode register */ 440 mode = mgx_read_1(sc->sc_vidc, TS_DATA); 441 if (on) 442 mode &= ~CD_DISABLEVIDEO; 443 else 444 mode |= CD_DISABLEVIDEO; 445 mgx_write_1(sc->sc_vidc, TS_DATA, mode); 446 } 447 448 /* 449 * Colormap Handling Routines 450 */ 451 452 void 453 mgx_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) 454 { 455 struct mgx_softc *sc = v; 456 u_int i = index * 3; 457 458 sc->sc_cmap[i++] = r; 459 sc->sc_cmap[i++] = g; 460 sc->sc_cmap[i] = b; 461 462 mgx_loadcmap(sc, index, 1); 463 } 464 465 void 466 mgx_loadcmap(struct mgx_softc *sc, int start, int ncolors) 467 { 468 u_int8_t *color; 469 int i; 470 471 mgx_write_1(sc->sc_vidc, CMAP_WRITE_INDEX, start); 472 color = sc->sc_cmap + start * 3; 473 for (i = ncolors * 3; i != 0; i--) 474 mgx_write_1(sc->sc_vidc, CMAP_DATA, *color++); 475 } 476 477 int 478 mgx_getcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm) 479 { 480 u_int index = rcm->index, count = rcm->count, i; 481 int error; 482 483 if (index >= 256 || count > 256 - index) 484 return (EINVAL); 485 486 index *= 3; 487 for (i = 0; i < count; i++) { 488 if ((error = 489 copyout(cm + index++, &rcm->red[i], 1)) != 0) 490 return (error); 491 if ((error = 492 copyout(cm + index++, &rcm->green[i], 1)) != 0) 493 return (error); 494 if ((error = 495 copyout(cm + index++, &rcm->blue[i], 1)) != 0) 496 return (error); 497 } 498 499 return (0); 500 } 501 502 int 503 mgx_putcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm) 504 { 505 u_int index = rcm->index, count = rcm->count, i; 506 int error; 507 508 if (index >= 256 || count > 256 - index) 509 return (EINVAL); 510 511 index *= 3; 512 for (i = 0; i < count; i++) { 513 if ((error = 514 copyin(&rcm->red[i], cm + index++, 1)) != 0) 515 return (error); 516 if ((error = 517 copyin(&rcm->green[i], cm + index++, 1)) != 0) 518 return (error); 519 if ((error = 520 copyin(&rcm->blue[i], cm + index++, 1)) != 0) 521 return (error); 522 } 523 524 return (0); 525 } 526 527 /* 528 * Accelerated Text Console Code 529 * 530 * The X driver makes sure there are at least as many FIFOs available as 531 * registers to write. They can thus be considered as write slots. 532 * 533 * The code below expects to run on at least an AT24 chip, and does not 534 * care for the AP6422 which has fewer FIFOs; some operations would need 535 * to be done in two steps to support this chip. 536 */ 537 538 int 539 mgx_wait_engine(struct mgx_softc *sc) 540 { 541 uint i; 542 uint stat; 543 544 for (i = 10000; i != 0; i--) { 545 stat = mgx_read_1(sc->sc_xreg, ATR_BLT_STATUS); 546 if (!ISSET(stat, BLT_HOST_BUSY | BLT_ENGINE_BUSY)) 547 break; 548 } 549 550 return i; 551 } 552 553 int 554 mgx_wait_fifo(struct mgx_softc *sc, uint nfifo) 555 { 556 uint i; 557 uint stat; 558 559 for (i = 10000; i != 0; i--) { 560 stat = (mgx_read_1(sc->sc_xreg, ATR_FIFO_STATUS) & FIFO_MASK) >> 561 FIFO_SHIFT; 562 if (stat >= nfifo) 563 break; 564 mgx_write_1(sc->sc_xreg, ATR_FIFO_STATUS, 0); 565 } 566 567 return i; 568 } 569 570 void 571 mgx_ras_init(struct mgx_softc *sc, uint chipid) 572 { 573 /* 574 * Check the chip ID. If it's not a 6424, do not plug the 575 * accelerated routines. 576 */ 577 578 if (chipid != ID_AT24) 579 return; 580 581 /* 582 * Wait until the chip is completely idle. 583 */ 584 585 if (mgx_wait_engine(sc) == 0) 586 return; 587 if (mgx_wait_fifo(sc, FIFO_AT24) == 0) 588 return; 589 590 /* 591 * Compute the invariant bits of the DEC register. 592 */ 593 594 switch (sc->sc_sunfb.sf_depth) { 595 case 8: 596 sc->sc_dec = DEC_DEPTH_8 << DEC_DEPTH_SHIFT; 597 break; 598 case 15: 599 case 16: 600 sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT; 601 break; 602 case 32: 603 sc->sc_dec = DEC_DEPTH_32 << DEC_DEPTH_SHIFT; 604 break; 605 default: 606 return; /* not supported */ 607 } 608 609 switch (sc->sc_sunfb.sf_width) { 610 case 640: 611 sc->sc_dec |= DEC_WIDTH_640 << DEC_WIDTH_SHIFT; 612 break; 613 case 800: 614 sc->sc_dec |= DEC_WIDTH_800 << DEC_WIDTH_SHIFT; 615 break; 616 case 1024: 617 sc->sc_dec |= DEC_WIDTH_1024 << DEC_WIDTH_SHIFT; 618 break; 619 case 1152: 620 sc->sc_dec |= DEC_WIDTH_1152 << DEC_WIDTH_SHIFT; 621 break; 622 case 1280: 623 sc->sc_dec |= DEC_WIDTH_1280 << DEC_WIDTH_SHIFT; 624 break; 625 case 1600: 626 sc->sc_dec |= DEC_WIDTH_1600 << DEC_WIDTH_SHIFT; 627 break; 628 default: 629 return; /* not supported */ 630 } 631 632 sc->sc_sunfb.sf_ro.ri_ops.copycols = mgx_ras_copycols; 633 sc->sc_sunfb.sf_ro.ri_ops.copyrows = mgx_ras_copyrows; 634 sc->sc_sunfb.sf_ro.ri_ops.erasecols = mgx_ras_erasecols; 635 sc->sc_sunfb.sf_ro.ri_ops.eraserows = mgx_ras_eraserows; 636 sc->sc_sunfb.sf_ro.ri_do_cursor = mgx_ras_do_cursor; 637 638 #ifdef notneeded 639 mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 1); 640 mgx_write_4(sc->sc_xreg, ATR_CLIP_LEFTTOP, ATR_DUAL(0, 0)); 641 mgx_write_4(sc->sc_xreg, ATR_CLIP_RIGHTBOTTOM, 642 ATR_DUAL(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_depth - 1)); 643 #else 644 mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 0); 645 #endif 646 mgx_write_1(sc->sc_xreg, ATR_BYTEMASK, 0xff); 647 } 648 649 void 650 mgx_ras_copycols(void *v, int row, int src, int dst, int n) 651 { 652 struct rasops_info *ri = v; 653 struct mgx_softc *sc = ri->ri_hw; 654 uint dec = sc->sc_dec; 655 656 n *= ri->ri_font->fontwidth; 657 src *= ri->ri_font->fontwidth; 658 src += ri->ri_xorigin; 659 dst *= ri->ri_font->fontwidth; 660 dst += ri->ri_xorigin; 661 row *= ri->ri_font->fontheight; 662 row += ri->ri_yorigin; 663 664 dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | 665 (DEC_START_DIMX << DEC_START_SHIFT); 666 if (src < dst) { 667 src += n - 1; 668 dst += n - 1; 669 dec |= DEC_DIR_X_REVERSE; 670 } 671 mgx_wait_fifo(sc, 5); 672 mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); 673 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 674 mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, src)); 675 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, dst)); 676 mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n)); 677 mgx_wait_engine(sc); 678 } 679 680 void 681 mgx_ras_copyrows(void *v, int src, int dst, int n) 682 { 683 struct rasops_info *ri = v; 684 struct mgx_softc *sc = ri->ri_hw; 685 uint dec = sc->sc_dec; 686 687 n *= ri->ri_font->fontheight; 688 src *= ri->ri_font->fontheight; 689 src += ri->ri_yorigin; 690 dst *= ri->ri_font->fontheight; 691 dst += ri->ri_yorigin; 692 693 dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | 694 (DEC_START_DIMX << DEC_START_SHIFT); 695 if (src < dst) { 696 src += n - 1; 697 dst += n - 1; 698 dec |= DEC_DIR_Y_REVERSE; 699 } 700 mgx_wait_fifo(sc, 5); 701 mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); 702 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 703 mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(src, ri->ri_xorigin)); 704 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(dst, ri->ri_xorigin)); 705 mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth)); 706 mgx_wait_engine(sc); 707 } 708 709 void 710 mgx_ras_erasecols(void *v, int row, int col, int n, long int attr) 711 { 712 struct rasops_info *ri = v; 713 struct mgx_softc *sc = ri->ri_hw; 714 int fg, bg; 715 uint dec = sc->sc_dec; 716 717 ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL); 718 bg = ri->ri_devcmap[bg]; 719 720 n *= ri->ri_font->fontwidth; 721 col *= ri->ri_font->fontwidth; 722 col += ri->ri_xorigin; 723 row *= ri->ri_font->fontheight; 724 row += ri->ri_yorigin; 725 726 dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) | 727 (DEC_START_DIMX << DEC_START_SHIFT); 728 mgx_wait_fifo(sc, 5); 729 mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); 730 mgx_write_4(sc->sc_xreg, ATR_FG, bg); 731 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 732 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col)); 733 mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n)); 734 mgx_wait_engine(sc); 735 } 736 737 void 738 mgx_ras_eraserows(void *v, int row, int n, long int attr) 739 { 740 struct rasops_info *ri = v; 741 struct mgx_softc *sc = ri->ri_hw; 742 int fg, bg; 743 uint dec = sc->sc_dec; 744 745 ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL); 746 bg = ri->ri_devcmap[bg]; 747 748 dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) | 749 (DEC_START_DIMX << DEC_START_SHIFT); 750 mgx_wait_fifo(sc, 5); 751 mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); 752 mgx_write_4(sc->sc_xreg, ATR_FG, bg); 753 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 754 if (n == ri->ri_rows && ISSET(ri->ri_flg, RI_FULLCLEAR)) { 755 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(0, 0)); 756 mgx_write_4(sc->sc_xreg, ATR_WH, 757 ATR_DUAL(ri->ri_height, ri->ri_width)); 758 } else { 759 n *= ri->ri_font->fontheight; 760 row *= ri->ri_font->fontheight; 761 row += ri->ri_yorigin; 762 763 mgx_write_4(sc->sc_xreg, ATR_DST_XY, 764 ATR_DUAL(row, ri->ri_xorigin)); 765 mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth)); 766 } 767 mgx_wait_engine(sc); 768 } 769 770 void 771 mgx_ras_do_cursor(struct rasops_info *ri) 772 { 773 struct mgx_softc *sc = ri->ri_hw; 774 int row, col; 775 uint dec = sc->sc_dec; 776 777 row = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; 778 col = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; 779 780 dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | 781 (DEC_START_DIMX << DEC_START_SHIFT); 782 mgx_wait_fifo(sc, 5); 783 mgx_write_1(sc->sc_xreg, ATR_ROP, (uint8_t)~ROP_SRC); 784 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 785 mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, col)); 786 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col)); 787 mgx_write_4(sc->sc_xreg, ATR_WH, 788 ATR_DUAL(ri->ri_font->fontheight, ri->ri_font->fontwidth)); 789 mgx_wait_engine(sc); 790 } 791