1 /* $OpenBSD: mgx.c,v 1.16 2022/07/15 17:57:27 kettenis 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 .ioctl = mgx_ioctl, 137 .mmap = mgx_mmap, 138 .burn_screen = mgx_burner 139 }; 140 141 int mgx_getcmap(u_int8_t *, struct wsdisplay_cmap *); 142 void mgx_loadcmap(struct mgx_softc *, int, int); 143 int mgx_putcmap(u_int8_t *, struct wsdisplay_cmap *); 144 void mgx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); 145 146 int mgx_ras_copycols(void *, int, int, int, int); 147 int mgx_ras_copyrows(void *, int, int, int); 148 int mgx_ras_do_cursor(struct rasops_info *); 149 int mgx_ras_erasecols(void *, int, int, int, uint32_t); 150 int mgx_ras_eraserows(void *, int, int, uint32_t); 151 void mgx_ras_init(struct mgx_softc *, uint); 152 153 uint8_t mgx_read_1(vaddr_t, uint); 154 uint16_t mgx_read_2(vaddr_t, uint); 155 void mgx_write_1(vaddr_t, uint, uint8_t); 156 void mgx_write_4(vaddr_t, uint, uint32_t); 157 158 int mgx_wait_engine(struct mgx_softc *); 159 int mgx_wait_fifo(struct mgx_softc *, uint); 160 161 /* 162 * Attachment Glue 163 */ 164 165 int mgxmatch(struct device *, void *, void *); 166 void mgxattach(struct device *, struct device *, void *); 167 168 const struct cfattach mgx_ca = { 169 sizeof(struct mgx_softc), mgxmatch, mgxattach 170 }; 171 172 struct cfdriver mgx_cd = { 173 NULL, "mgx", DV_DULL 174 }; 175 176 /* 177 * Match an MGX or MGX+ card. 178 */ 179 int 180 mgxmatch(struct device *parent, void *vcf, void *aux) 181 { 182 struct sbus_attach_args *sa = aux; 183 184 if (strcmp(sa->sa_name, "SMSI,mgx") != 0 && 185 strcmp(sa->sa_name, "mgx") != 0) 186 return (0); 187 188 return (1); 189 } 190 191 /* 192 * Attach an MGX frame buffer. 193 * This will keep the frame buffer in the actual PROM mode, and attach 194 * a wsdisplay child device to itself. 195 */ 196 void 197 mgxattach(struct device *parent, struct device *self, void *args) 198 { 199 struct mgx_softc *sc = (struct mgx_softc *)self; 200 struct sbus_attach_args *sa = args; 201 bus_space_tag_t bt; 202 bus_space_handle_t bh; 203 int node, fbsize; 204 int isconsole; 205 uint16_t chipid; 206 207 bt = sa->sa_bustag; 208 node = sa->sa_node; 209 210 printf(": %s", getpropstring(node, "model")); 211 212 isconsole = node == fbnode; 213 214 /* Check registers */ 215 if (sa->sa_nreg < MGX_NREG) { 216 printf("\n%s: expected %d registers, got %d\n", 217 self->dv_xname, MGX_NREG, sa->sa_nreg); 218 return; 219 } 220 221 sc->sc_bustag = bt; 222 if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_CRTC].sbr_slot, 223 sa->sa_reg[MGX_REG_CRTC].sbr_offset, PAGE_SIZE, 224 BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { 225 printf("\n%s: couldn't map crtc registers\n", self->dv_xname); 226 return; 227 } 228 sc->sc_vidc = (vaddr_t)bus_space_vaddr(bt, bh); 229 230 sc->sc_bustag = bt; 231 if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_ATREG].sbr_slot, 232 sa->sa_reg[MGX_REG_ATREG].sbr_offset + MGX_REG_ATREG_OFFSET, 233 MGX_REG_ATREG_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { 234 printf("\n%s: couldn't map crtc registers\n", self->dv_xname); 235 /* XXX unmap vidc */ 236 return; 237 } 238 sc->sc_xreg = (vaddr_t)bus_space_vaddr(bt, bh); 239 240 /* 241 * Check the chip ID. If it's not an AT24, prefer not to access 242 * the extended registers at all. 243 */ 244 chipid = mgx_read_2(sc->sc_xreg, ATR_ID); 245 if (chipid != ID_AT24) { 246 sc->sc_xreg = (vaddr_t)0; 247 } 248 249 /* enable video */ 250 mgx_burner(sc, 1, 0); 251 252 fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0); 253 254 /* Sanity check frame buffer memory */ 255 fbsize = getpropint(node, "fb_size", 0); 256 if (fbsize != 0 && sc->sc_sunfb.sf_fbsize > fbsize) { 257 printf("\n%s: expected at least %d bytes of vram, but card " 258 "only provides %d\n", 259 self->dv_xname, sc->sc_sunfb.sf_fbsize, fbsize); 260 return; 261 } 262 263 /* Map the frame buffer memory area we're interested in */ 264 sc->sc_paddr = sbus_bus_addr(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot, 265 sa->sa_reg[MGX_REG_VRAM8].sbr_offset); 266 if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot, 267 sa->sa_reg[MGX_REG_VRAM8].sbr_offset, 268 round_page(sc->sc_sunfb.sf_fbsize), 269 BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { 270 printf("\n%s: couldn't map video memory\n", self->dv_xname); 271 /* XXX unmap vidc and xreg */ 272 return; 273 } 274 sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh); 275 sc->sc_sunfb.sf_ro.ri_hw = sc; 276 277 printf(", %dx%d\n", 278 sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); 279 280 fbwscons_init(&sc->sc_sunfb, 0, isconsole); 281 282 bzero(sc->sc_cmap, sizeof(sc->sc_cmap)); 283 fbwscons_setcolormap(&sc->sc_sunfb, mgx_setcolor); 284 285 if (chipid != ID_AT24) { 286 printf("%s: unexpected engine id %04x\n", 287 self->dv_xname, chipid); 288 } 289 290 mgx_ras_init(sc, chipid); 291 292 if (isconsole) 293 fbwscons_console_init(&sc->sc_sunfb, -1); 294 295 fbwscons_attach(&sc->sc_sunfb, &mgx_accessops, isconsole); 296 } 297 298 /* 299 * Register Access 300 * 301 * On big-endian systems such as the sparc, it is necessary to flip 302 * the low-order bits of the addresses to reach the right register. 303 */ 304 305 uint8_t 306 mgx_read_1(vaddr_t regs, uint offs) 307 { 308 #if _BYTE_ORDER == _LITTLE_ENDIAN 309 return *(volatile uint8_t *)(regs + offs); 310 #else 311 return *(volatile uint8_t *)(regs + (offs ^ 3)); 312 #endif 313 } 314 315 uint16_t 316 mgx_read_2(vaddr_t regs, uint offs) 317 { 318 #if _BYTE_ORDER == _LITTLE_ENDIAN 319 return *(volatile uint16_t *)(regs + offs); 320 #else 321 return *(volatile uint16_t *)(regs + (offs ^ 2)); 322 #endif 323 } 324 325 void 326 mgx_write_1(vaddr_t regs, uint offs, uint8_t val) 327 { 328 #if _BYTE_ORDER == _LITTLE_ENDIAN 329 *(volatile uint8_t *)(regs + offs) = val; 330 #else 331 *(volatile uint8_t *)(regs + (offs ^ 3)) = val; 332 #endif 333 } 334 335 void 336 mgx_write_4(vaddr_t regs, uint offs, uint32_t val) 337 { 338 *(volatile uint32_t *)(regs + offs) = val; 339 } 340 341 /* 342 * Wsdisplay Operations 343 */ 344 345 int 346 mgx_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p) 347 { 348 struct mgx_softc *sc = dev; 349 struct wsdisplay_cmap *cm; 350 struct wsdisplay_fbinfo *wdf; 351 int error; 352 353 switch (cmd) { 354 case WSDISPLAYIO_GTYPE: 355 *(u_int *)data = WSDISPLAY_TYPE_MGX; 356 break; 357 case WSDISPLAYIO_GINFO: 358 wdf = (struct wsdisplay_fbinfo *)data; 359 wdf->height = sc->sc_sunfb.sf_height; 360 wdf->width = sc->sc_sunfb.sf_width; 361 wdf->depth = sc->sc_sunfb.sf_depth; 362 wdf->stride = sc->sc_sunfb.sf_linebytes; 363 wdf->offset = 0; 364 wdf->cmsize = 256; 365 break; 366 case WSDISPLAYIO_LINEBYTES: 367 *(u_int *)data = sc->sc_sunfb.sf_linebytes; 368 break; 369 370 case WSDISPLAYIO_GETCMAP: 371 cm = (struct wsdisplay_cmap *)data; 372 error = mgx_getcmap(sc->sc_cmap, cm); 373 if (error != 0) 374 return (error); 375 break; 376 case WSDISPLAYIO_PUTCMAP: 377 cm = (struct wsdisplay_cmap *)data; 378 error = mgx_putcmap(sc->sc_cmap, cm); 379 if (error != 0) 380 return (error); 381 mgx_loadcmap(sc, cm->index, cm->count); 382 break; 383 384 case WSDISPLAYIO_SVIDEO: 385 case WSDISPLAYIO_GVIDEO: 386 break; 387 388 default: 389 return (-1); 390 } 391 392 return (0); 393 } 394 395 paddr_t 396 mgx_mmap(void *v, off_t offset, int prot) 397 { 398 struct mgx_softc *sc = v; 399 400 if (offset & PGOFSET) 401 return (-1); 402 403 /* Allow mapping as a dumb framebuffer from offset 0 */ 404 if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { 405 return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, 406 offset, prot, BUS_SPACE_MAP_LINEAR)); 407 } 408 409 return (-1); 410 } 411 412 void 413 mgx_burner(void *v, u_int on, u_int flags) 414 { 415 struct mgx_softc *sc = v; 416 uint mode; 417 418 #ifdef notyet 419 if (sc->sc_xreg != 0) { 420 mode = mgx_read_1(sc->sc_xreg, ATR_DPMS); 421 if (on) 422 CLR(mode, DPMS_HSYNC_DISABLE | DPMS_VSYNC_DISABLE); 423 else { 424 SET(mode, DPMS_HSYNC_DISABLE); 425 #if 0 /* needs ramdac reprogramming on resume */ 426 if (flags & WSDISPLAY_BURN_VBLANK) 427 SET(mode, DPMS_VSYNC_DISABLE); 428 #endif 429 } 430 mgx_write_1(sc->sc_xreg, ATR_DPMS, mode); 431 return; 432 } 433 #endif 434 435 mgx_write_1(sc->sc_vidc, TS_INDEX, 1); /* TS mode register */ 436 mode = mgx_read_1(sc->sc_vidc, TS_DATA); 437 if (on) 438 mode &= ~CD_DISABLEVIDEO; 439 else 440 mode |= CD_DISABLEVIDEO; 441 mgx_write_1(sc->sc_vidc, TS_DATA, mode); 442 } 443 444 /* 445 * Colormap Handling Routines 446 */ 447 448 void 449 mgx_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) 450 { 451 struct mgx_softc *sc = v; 452 u_int i = index * 3; 453 454 sc->sc_cmap[i++] = r; 455 sc->sc_cmap[i++] = g; 456 sc->sc_cmap[i] = b; 457 458 mgx_loadcmap(sc, index, 1); 459 } 460 461 void 462 mgx_loadcmap(struct mgx_softc *sc, int start, int ncolors) 463 { 464 u_int8_t *color; 465 int i; 466 467 mgx_write_1(sc->sc_vidc, CMAP_WRITE_INDEX, start); 468 color = sc->sc_cmap + start * 3; 469 for (i = ncolors * 3; i != 0; i--) 470 mgx_write_1(sc->sc_vidc, CMAP_DATA, *color++); 471 } 472 473 int 474 mgx_getcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm) 475 { 476 u_int index = rcm->index, count = rcm->count, i; 477 int error; 478 479 if (index >= 256 || count > 256 - index) 480 return (EINVAL); 481 482 index *= 3; 483 for (i = 0; i < count; i++) { 484 if ((error = 485 copyout(cm + index++, &rcm->red[i], 1)) != 0) 486 return (error); 487 if ((error = 488 copyout(cm + index++, &rcm->green[i], 1)) != 0) 489 return (error); 490 if ((error = 491 copyout(cm + index++, &rcm->blue[i], 1)) != 0) 492 return (error); 493 } 494 495 return (0); 496 } 497 498 int 499 mgx_putcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm) 500 { 501 u_int index = rcm->index, count = rcm->count, i; 502 int error; 503 504 if (index >= 256 || count > 256 - index) 505 return (EINVAL); 506 507 index *= 3; 508 for (i = 0; i < count; i++) { 509 if ((error = 510 copyin(&rcm->red[i], cm + index++, 1)) != 0) 511 return (error); 512 if ((error = 513 copyin(&rcm->green[i], cm + index++, 1)) != 0) 514 return (error); 515 if ((error = 516 copyin(&rcm->blue[i], cm + index++, 1)) != 0) 517 return (error); 518 } 519 520 return (0); 521 } 522 523 /* 524 * Accelerated Text Console Code 525 * 526 * The X driver makes sure there are at least as many FIFOs available as 527 * registers to write. They can thus be considered as write slots. 528 * 529 * The code below expects to run on at least an AT24 chip, and does not 530 * care for the AP6422 which has fewer FIFOs; some operations would need 531 * to be done in two steps to support this chip. 532 */ 533 534 int 535 mgx_wait_engine(struct mgx_softc *sc) 536 { 537 uint i; 538 uint stat; 539 540 for (i = 10000; i != 0; i--) { 541 stat = mgx_read_1(sc->sc_xreg, ATR_BLT_STATUS); 542 if (!ISSET(stat, BLT_HOST_BUSY | BLT_ENGINE_BUSY)) 543 break; 544 } 545 546 return i; 547 } 548 549 int 550 mgx_wait_fifo(struct mgx_softc *sc, uint nfifo) 551 { 552 uint i; 553 uint stat; 554 555 for (i = 10000; i != 0; i--) { 556 stat = (mgx_read_1(sc->sc_xreg, ATR_FIFO_STATUS) & FIFO_MASK) >> 557 FIFO_SHIFT; 558 if (stat >= nfifo) 559 break; 560 mgx_write_1(sc->sc_xreg, ATR_FIFO_STATUS, 0); 561 } 562 563 return i; 564 } 565 566 void 567 mgx_ras_init(struct mgx_softc *sc, uint chipid) 568 { 569 /* 570 * Check the chip ID. If it's not a 6424, do not plug the 571 * accelerated routines. 572 */ 573 574 if (chipid != ID_AT24) 575 return; 576 577 /* 578 * Wait until the chip is completely idle. 579 */ 580 581 if (mgx_wait_engine(sc) == 0) 582 return; 583 if (mgx_wait_fifo(sc, FIFO_AT24) == 0) 584 return; 585 586 /* 587 * Compute the invariant bits of the DEC register. 588 */ 589 590 switch (sc->sc_sunfb.sf_depth) { 591 case 8: 592 sc->sc_dec = DEC_DEPTH_8 << DEC_DEPTH_SHIFT; 593 break; 594 case 15: 595 case 16: 596 sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT; 597 break; 598 case 32: 599 sc->sc_dec = DEC_DEPTH_32 << DEC_DEPTH_SHIFT; 600 break; 601 default: 602 return; /* not supported */ 603 } 604 605 switch (sc->sc_sunfb.sf_width) { 606 case 640: 607 sc->sc_dec |= DEC_WIDTH_640 << DEC_WIDTH_SHIFT; 608 break; 609 case 800: 610 sc->sc_dec |= DEC_WIDTH_800 << DEC_WIDTH_SHIFT; 611 break; 612 case 1024: 613 sc->sc_dec |= DEC_WIDTH_1024 << DEC_WIDTH_SHIFT; 614 break; 615 case 1152: 616 sc->sc_dec |= DEC_WIDTH_1152 << DEC_WIDTH_SHIFT; 617 break; 618 case 1280: 619 sc->sc_dec |= DEC_WIDTH_1280 << DEC_WIDTH_SHIFT; 620 break; 621 case 1600: 622 sc->sc_dec |= DEC_WIDTH_1600 << DEC_WIDTH_SHIFT; 623 break; 624 default: 625 return; /* not supported */ 626 } 627 628 sc->sc_sunfb.sf_ro.ri_ops.copycols = mgx_ras_copycols; 629 sc->sc_sunfb.sf_ro.ri_ops.copyrows = mgx_ras_copyrows; 630 sc->sc_sunfb.sf_ro.ri_ops.erasecols = mgx_ras_erasecols; 631 sc->sc_sunfb.sf_ro.ri_ops.eraserows = mgx_ras_eraserows; 632 sc->sc_sunfb.sf_ro.ri_do_cursor = mgx_ras_do_cursor; 633 634 #ifdef notneeded 635 mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 1); 636 mgx_write_4(sc->sc_xreg, ATR_CLIP_LEFTTOP, ATR_DUAL(0, 0)); 637 mgx_write_4(sc->sc_xreg, ATR_CLIP_RIGHTBOTTOM, 638 ATR_DUAL(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_depth - 1)); 639 #else 640 mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 0); 641 #endif 642 mgx_write_1(sc->sc_xreg, ATR_BYTEMASK, 0xff); 643 } 644 645 int 646 mgx_ras_copycols(void *v, int row, int src, int dst, int n) 647 { 648 struct rasops_info *ri = v; 649 struct mgx_softc *sc = ri->ri_hw; 650 uint dec = sc->sc_dec; 651 652 n *= ri->ri_font->fontwidth; 653 src *= ri->ri_font->fontwidth; 654 src += ri->ri_xorigin; 655 dst *= ri->ri_font->fontwidth; 656 dst += ri->ri_xorigin; 657 row *= ri->ri_font->fontheight; 658 row += ri->ri_yorigin; 659 660 dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | 661 (DEC_START_DIMX << DEC_START_SHIFT); 662 if (src < dst) { 663 src += n - 1; 664 dst += n - 1; 665 dec |= DEC_DIR_X_REVERSE; 666 } 667 mgx_wait_fifo(sc, 5); 668 mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); 669 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 670 mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, src)); 671 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, dst)); 672 mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n)); 673 mgx_wait_engine(sc); 674 675 return 0; 676 } 677 678 int 679 mgx_ras_copyrows(void *v, int src, int dst, int n) 680 { 681 struct rasops_info *ri = v; 682 struct mgx_softc *sc = ri->ri_hw; 683 uint dec = sc->sc_dec; 684 685 n *= ri->ri_font->fontheight; 686 src *= ri->ri_font->fontheight; 687 src += ri->ri_yorigin; 688 dst *= ri->ri_font->fontheight; 689 dst += ri->ri_yorigin; 690 691 dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | 692 (DEC_START_DIMX << DEC_START_SHIFT); 693 if (src < dst) { 694 src += n - 1; 695 dst += n - 1; 696 dec |= DEC_DIR_Y_REVERSE; 697 } 698 mgx_wait_fifo(sc, 5); 699 mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); 700 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 701 mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(src, ri->ri_xorigin)); 702 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(dst, ri->ri_xorigin)); 703 mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth)); 704 mgx_wait_engine(sc); 705 706 return 0; 707 } 708 709 int 710 mgx_ras_erasecols(void *v, int row, int col, int n, uint32_t 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 return 0; 737 } 738 739 int 740 mgx_ras_eraserows(void *v, int row, int n, uint32_t attr) 741 { 742 struct rasops_info *ri = v; 743 struct mgx_softc *sc = ri->ri_hw; 744 int fg, bg; 745 uint dec = sc->sc_dec; 746 747 ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL); 748 bg = ri->ri_devcmap[bg]; 749 750 dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) | 751 (DEC_START_DIMX << DEC_START_SHIFT); 752 mgx_wait_fifo(sc, 5); 753 mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); 754 mgx_write_4(sc->sc_xreg, ATR_FG, bg); 755 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 756 if (n == ri->ri_rows && ISSET(ri->ri_flg, RI_FULLCLEAR)) { 757 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(0, 0)); 758 mgx_write_4(sc->sc_xreg, ATR_WH, 759 ATR_DUAL(ri->ri_height, ri->ri_width)); 760 } else { 761 n *= ri->ri_font->fontheight; 762 row *= ri->ri_font->fontheight; 763 row += ri->ri_yorigin; 764 765 mgx_write_4(sc->sc_xreg, ATR_DST_XY, 766 ATR_DUAL(row, ri->ri_xorigin)); 767 mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth)); 768 } 769 mgx_wait_engine(sc); 770 771 return 0; 772 } 773 774 int 775 mgx_ras_do_cursor(struct rasops_info *ri) 776 { 777 struct mgx_softc *sc = ri->ri_hw; 778 int row, col; 779 uint dec = sc->sc_dec; 780 781 row = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; 782 col = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; 783 784 dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | 785 (DEC_START_DIMX << DEC_START_SHIFT); 786 mgx_wait_fifo(sc, 5); 787 mgx_write_1(sc->sc_xreg, ATR_ROP, (uint8_t)~ROP_SRC); 788 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 789 mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, col)); 790 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col)); 791 mgx_write_4(sc->sc_xreg, ATR_WH, 792 ATR_DUAL(ri->ri_font->fontheight, ri->ri_font->fontwidth)); 793 mgx_wait_engine(sc); 794 795 return 0; 796 } 797