1 /* $OpenBSD: mgx.c,v 1.13 2013/10/20 20:07:31 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 .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, long int); 150 int mgx_ras_eraserows(void *, int, int, long int); 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 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->cmsize = 256; 363 break; 364 case WSDISPLAYIO_LINEBYTES: 365 *(u_int *)data = sc->sc_sunfb.sf_linebytes; 366 break; 367 368 case WSDISPLAYIO_GETCMAP: 369 cm = (struct wsdisplay_cmap *)data; 370 error = mgx_getcmap(sc->sc_cmap, cm); 371 if (error != 0) 372 return (error); 373 break; 374 case WSDISPLAYIO_PUTCMAP: 375 cm = (struct wsdisplay_cmap *)data; 376 error = mgx_putcmap(sc->sc_cmap, cm); 377 if (error != 0) 378 return (error); 379 mgx_loadcmap(sc, cm->index, cm->count); 380 break; 381 382 case WSDISPLAYIO_SVIDEO: 383 case WSDISPLAYIO_GVIDEO: 384 break; 385 386 default: 387 return (-1); 388 } 389 390 return (0); 391 } 392 393 paddr_t 394 mgx_mmap(void *v, off_t offset, int prot) 395 { 396 struct mgx_softc *sc = v; 397 398 if (offset & PGOFSET) 399 return (-1); 400 401 /* Allow mapping as a dumb framebuffer from offset 0 */ 402 if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { 403 return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, 404 offset, prot, BUS_SPACE_MAP_LINEAR)); 405 } 406 407 return (-1); 408 } 409 410 void 411 mgx_burner(void *v, u_int on, u_int flags) 412 { 413 struct mgx_softc *sc = v; 414 uint mode; 415 416 #ifdef notyet 417 if (sc->sc_xreg != 0) { 418 mode = mgx_read_1(sc->sc_xreg, ATR_DPMS); 419 if (on) 420 CLR(mode, DPMS_HSYNC_DISABLE | DPMS_VSYNC_DISABLE); 421 else { 422 SET(mode, DPMS_HSYNC_DISABLE); 423 #if 0 /* needs ramdac reprogramming on resume */ 424 if (flags & WSDISPLAY_BURN_VBLANK) 425 SET(mode, DPMS_VSYNC_DISABLE); 426 #endif 427 } 428 mgx_write_1(sc->sc_xreg, ATR_DPMS, mode); 429 return; 430 } 431 #endif 432 433 mgx_write_1(sc->sc_vidc, TS_INDEX, 1); /* TS mode register */ 434 mode = mgx_read_1(sc->sc_vidc, TS_DATA); 435 if (on) 436 mode &= ~CD_DISABLEVIDEO; 437 else 438 mode |= CD_DISABLEVIDEO; 439 mgx_write_1(sc->sc_vidc, TS_DATA, mode); 440 } 441 442 /* 443 * Colormap Handling Routines 444 */ 445 446 void 447 mgx_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) 448 { 449 struct mgx_softc *sc = v; 450 u_int i = index * 3; 451 452 sc->sc_cmap[i++] = r; 453 sc->sc_cmap[i++] = g; 454 sc->sc_cmap[i] = b; 455 456 mgx_loadcmap(sc, index, 1); 457 } 458 459 void 460 mgx_loadcmap(struct mgx_softc *sc, int start, int ncolors) 461 { 462 u_int8_t *color; 463 int i; 464 465 mgx_write_1(sc->sc_vidc, CMAP_WRITE_INDEX, start); 466 color = sc->sc_cmap + start * 3; 467 for (i = ncolors * 3; i != 0; i--) 468 mgx_write_1(sc->sc_vidc, CMAP_DATA, *color++); 469 } 470 471 int 472 mgx_getcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm) 473 { 474 u_int index = rcm->index, count = rcm->count, i; 475 int error; 476 477 if (index >= 256 || count > 256 - index) 478 return (EINVAL); 479 480 index *= 3; 481 for (i = 0; i < count; i++) { 482 if ((error = 483 copyout(cm + index++, &rcm->red[i], 1)) != 0) 484 return (error); 485 if ((error = 486 copyout(cm + index++, &rcm->green[i], 1)) != 0) 487 return (error); 488 if ((error = 489 copyout(cm + index++, &rcm->blue[i], 1)) != 0) 490 return (error); 491 } 492 493 return (0); 494 } 495 496 int 497 mgx_putcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm) 498 { 499 u_int index = rcm->index, count = rcm->count, i; 500 int error; 501 502 if (index >= 256 || count > 256 - index) 503 return (EINVAL); 504 505 index *= 3; 506 for (i = 0; i < count; i++) { 507 if ((error = 508 copyin(&rcm->red[i], cm + index++, 1)) != 0) 509 return (error); 510 if ((error = 511 copyin(&rcm->green[i], cm + index++, 1)) != 0) 512 return (error); 513 if ((error = 514 copyin(&rcm->blue[i], cm + index++, 1)) != 0) 515 return (error); 516 } 517 518 return (0); 519 } 520 521 /* 522 * Accelerated Text Console Code 523 * 524 * The X driver makes sure there are at least as many FIFOs available as 525 * registers to write. They can thus be considered as write slots. 526 * 527 * The code below expects to run on at least an AT24 chip, and does not 528 * care for the AP6422 which has fewer FIFOs; some operations would need 529 * to be done in two steps to support this chip. 530 */ 531 532 int 533 mgx_wait_engine(struct mgx_softc *sc) 534 { 535 uint i; 536 uint stat; 537 538 for (i = 10000; i != 0; i--) { 539 stat = mgx_read_1(sc->sc_xreg, ATR_BLT_STATUS); 540 if (!ISSET(stat, BLT_HOST_BUSY | BLT_ENGINE_BUSY)) 541 break; 542 } 543 544 return i; 545 } 546 547 int 548 mgx_wait_fifo(struct mgx_softc *sc, uint nfifo) 549 { 550 uint i; 551 uint stat; 552 553 for (i = 10000; i != 0; i--) { 554 stat = (mgx_read_1(sc->sc_xreg, ATR_FIFO_STATUS) & FIFO_MASK) >> 555 FIFO_SHIFT; 556 if (stat >= nfifo) 557 break; 558 mgx_write_1(sc->sc_xreg, ATR_FIFO_STATUS, 0); 559 } 560 561 return i; 562 } 563 564 void 565 mgx_ras_init(struct mgx_softc *sc, uint chipid) 566 { 567 /* 568 * Check the chip ID. If it's not a 6424, do not plug the 569 * accelerated routines. 570 */ 571 572 if (chipid != ID_AT24) 573 return; 574 575 /* 576 * Wait until the chip is completely idle. 577 */ 578 579 if (mgx_wait_engine(sc) == 0) 580 return; 581 if (mgx_wait_fifo(sc, FIFO_AT24) == 0) 582 return; 583 584 /* 585 * Compute the invariant bits of the DEC register. 586 */ 587 588 switch (sc->sc_sunfb.sf_depth) { 589 case 8: 590 sc->sc_dec = DEC_DEPTH_8 << DEC_DEPTH_SHIFT; 591 break; 592 case 15: 593 case 16: 594 sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT; 595 break; 596 case 32: 597 sc->sc_dec = DEC_DEPTH_32 << DEC_DEPTH_SHIFT; 598 break; 599 default: 600 return; /* not supported */ 601 } 602 603 switch (sc->sc_sunfb.sf_width) { 604 case 640: 605 sc->sc_dec |= DEC_WIDTH_640 << DEC_WIDTH_SHIFT; 606 break; 607 case 800: 608 sc->sc_dec |= DEC_WIDTH_800 << DEC_WIDTH_SHIFT; 609 break; 610 case 1024: 611 sc->sc_dec |= DEC_WIDTH_1024 << DEC_WIDTH_SHIFT; 612 break; 613 case 1152: 614 sc->sc_dec |= DEC_WIDTH_1152 << DEC_WIDTH_SHIFT; 615 break; 616 case 1280: 617 sc->sc_dec |= DEC_WIDTH_1280 << DEC_WIDTH_SHIFT; 618 break; 619 case 1600: 620 sc->sc_dec |= DEC_WIDTH_1600 << DEC_WIDTH_SHIFT; 621 break; 622 default: 623 return; /* not supported */ 624 } 625 626 sc->sc_sunfb.sf_ro.ri_ops.copycols = mgx_ras_copycols; 627 sc->sc_sunfb.sf_ro.ri_ops.copyrows = mgx_ras_copyrows; 628 sc->sc_sunfb.sf_ro.ri_ops.erasecols = mgx_ras_erasecols; 629 sc->sc_sunfb.sf_ro.ri_ops.eraserows = mgx_ras_eraserows; 630 sc->sc_sunfb.sf_ro.ri_do_cursor = mgx_ras_do_cursor; 631 632 #ifdef notneeded 633 mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 1); 634 mgx_write_4(sc->sc_xreg, ATR_CLIP_LEFTTOP, ATR_DUAL(0, 0)); 635 mgx_write_4(sc->sc_xreg, ATR_CLIP_RIGHTBOTTOM, 636 ATR_DUAL(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_depth - 1)); 637 #else 638 mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 0); 639 #endif 640 mgx_write_1(sc->sc_xreg, ATR_BYTEMASK, 0xff); 641 } 642 643 int 644 mgx_ras_copycols(void *v, int row, int src, int dst, int n) 645 { 646 struct rasops_info *ri = v; 647 struct mgx_softc *sc = ri->ri_hw; 648 uint dec = sc->sc_dec; 649 650 n *= ri->ri_font->fontwidth; 651 src *= ri->ri_font->fontwidth; 652 src += ri->ri_xorigin; 653 dst *= ri->ri_font->fontwidth; 654 dst += ri->ri_xorigin; 655 row *= ri->ri_font->fontheight; 656 row += ri->ri_yorigin; 657 658 dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | 659 (DEC_START_DIMX << DEC_START_SHIFT); 660 if (src < dst) { 661 src += n - 1; 662 dst += n - 1; 663 dec |= DEC_DIR_X_REVERSE; 664 } 665 mgx_wait_fifo(sc, 5); 666 mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); 667 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 668 mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, src)); 669 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, dst)); 670 mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n)); 671 mgx_wait_engine(sc); 672 673 return 0; 674 } 675 676 int 677 mgx_ras_copyrows(void *v, int src, int dst, int n) 678 { 679 struct rasops_info *ri = v; 680 struct mgx_softc *sc = ri->ri_hw; 681 uint dec = sc->sc_dec; 682 683 n *= ri->ri_font->fontheight; 684 src *= ri->ri_font->fontheight; 685 src += ri->ri_yorigin; 686 dst *= ri->ri_font->fontheight; 687 dst += ri->ri_yorigin; 688 689 dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | 690 (DEC_START_DIMX << DEC_START_SHIFT); 691 if (src < dst) { 692 src += n - 1; 693 dst += n - 1; 694 dec |= DEC_DIR_Y_REVERSE; 695 } 696 mgx_wait_fifo(sc, 5); 697 mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); 698 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 699 mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(src, ri->ri_xorigin)); 700 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(dst, ri->ri_xorigin)); 701 mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth)); 702 mgx_wait_engine(sc); 703 704 return 0; 705 } 706 707 int 708 mgx_ras_erasecols(void *v, int row, int col, int n, long int attr) 709 { 710 struct rasops_info *ri = v; 711 struct mgx_softc *sc = ri->ri_hw; 712 int fg, bg; 713 uint dec = sc->sc_dec; 714 715 ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL); 716 bg = ri->ri_devcmap[bg]; 717 718 n *= ri->ri_font->fontwidth; 719 col *= ri->ri_font->fontwidth; 720 col += ri->ri_xorigin; 721 row *= ri->ri_font->fontheight; 722 row += ri->ri_yorigin; 723 724 dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) | 725 (DEC_START_DIMX << DEC_START_SHIFT); 726 mgx_wait_fifo(sc, 5); 727 mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); 728 mgx_write_4(sc->sc_xreg, ATR_FG, bg); 729 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 730 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col)); 731 mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n)); 732 mgx_wait_engine(sc); 733 734 return 0; 735 } 736 737 int 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 return 0; 770 } 771 772 int 773 mgx_ras_do_cursor(struct rasops_info *ri) 774 { 775 struct mgx_softc *sc = ri->ri_hw; 776 int row, col; 777 uint dec = sc->sc_dec; 778 779 row = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; 780 col = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; 781 782 dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | 783 (DEC_START_DIMX << DEC_START_SHIFT); 784 mgx_wait_fifo(sc, 5); 785 mgx_write_1(sc->sc_xreg, ATR_ROP, (uint8_t)~ROP_SRC); 786 mgx_write_4(sc->sc_xreg, ATR_DEC, dec); 787 mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, col)); 788 mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col)); 789 mgx_write_4(sc->sc_xreg, ATR_WH, 790 ATR_DUAL(ri->ri_font->fontheight, ri->ri_font->fontwidth)); 791 mgx_wait_engine(sc); 792 793 return 0; 794 } 795