1 /* $NetBSD: mgx.c,v 1.24 2023/07/19 10:22:15 macallan Exp $ */ 2 3 /*- 4 * Copyright (c) 2014 Michael Lorenz 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* a console driver for the SSB 4096V-MGX graphics card */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: mgx.c,v 1.24 2023/07/19 10:22:15 macallan Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/buf.h> 37 #include <sys/device.h> 38 #include <sys/ioctl.h> 39 #include <sys/conf.h> 40 #include <sys/kmem.h> 41 #include <sys/kauth.h> 42 #include <sys/atomic.h> 43 44 #include <sys/bus.h> 45 #include <machine/autoconf.h> 46 47 #include <dev/sbus/sbusvar.h> 48 #include <dev/sun/fbio.h> 49 #include <dev/sun/fbvar.h> 50 51 #include <dev/wscons/wsdisplayvar.h> 52 #include <dev/wscons/wsconsio.h> 53 #include <dev/wsfont/wsfont.h> 54 #include <dev/rasops/rasops.h> 55 56 #include <dev/wscons/wsdisplay_vconsvar.h> 57 #include <dev/wscons/wsdisplay_glyphcachevar.h> 58 59 #include <dev/ic/vgareg.h> 60 #include <dev/sbus/mgxreg.h> 61 62 #include "ioconf.h" 63 64 #include "opt_wsemul.h" 65 #include "opt_mgx.h" 66 67 struct mgx_softc { 68 device_t sc_dev; 69 struct fbdevice sc_fb; /* frame buffer device */ 70 bus_space_tag_t sc_tag; 71 bus_space_handle_t sc_blith; 72 bus_space_handle_t sc_vgah; 73 bus_addr_t sc_paddr, sc_rpaddr; 74 void *sc_fbaddr; 75 uint8_t *sc_cursor; 76 int sc_width; 77 int sc_height; 78 int sc_stride; 79 int sc_depth; 80 int sc_fbsize; 81 int sc_mode; 82 char sc_name[8]; 83 uint32_t sc_dec, sc_r_dec, sc_r_fg; 84 u_char sc_cmap_red[256]; 85 u_char sc_cmap_green[256]; 86 u_char sc_cmap_blue[256]; 87 int sc_cursor_x, sc_cursor_y; 88 int sc_hotspot_x, sc_hotspot_y; 89 int sc_video, sc_buf; 90 void (*sc_putchar)(void *, int, int, u_int, long); 91 struct vcons_screen sc_console_screen; 92 struct wsscreen_descr sc_defaultscreen_descr; 93 const struct wsscreen_descr *sc_screens[1]; 94 struct wsscreen_list sc_screenlist; 95 struct vcons_data vd; 96 glyphcache sc_gc; 97 uint8_t sc_in[256]; 98 }; 99 100 static int mgx_match(device_t, cfdata_t, void *); 101 static void mgx_attach(device_t, device_t, void *); 102 static int mgx_ioctl(void *, void *, u_long, void *, int, 103 struct lwp*); 104 static paddr_t mgx_mmap(void *, void *, off_t, int); 105 static void mgx_init_screen(void *, struct vcons_screen *, int, 106 long *); 107 static void mgx_write_dac(struct mgx_softc *, int, int, int, int); 108 static void mgx_setup(struct mgx_softc *, int); 109 static void mgx_init_palette(struct mgx_softc *); 110 static int mgx_putcmap(struct mgx_softc *, struct wsdisplay_cmap *); 111 static int mgx_getcmap(struct mgx_softc *, struct wsdisplay_cmap *); 112 static int mgx_wait_engine(struct mgx_softc *); 113 __unused static int mgx_wait_host(struct mgx_softc *); 114 /*static*/ int mgx_wait_fifo(struct mgx_softc *, unsigned int); 115 116 static void mgx_bitblt(void *, int, int, int, int, int, int, int); 117 static void mgx_rectfill(void *, int, int, int, int, long); 118 119 static void mgx_putchar_aa(void *, int, int, u_int, long); 120 static void mgx_putchar_mono(void *, int, int, u_int, long); 121 static void mgx_cursor(void *, int, int, int); 122 static void mgx_copycols(void *, int, int, int, int); 123 static void mgx_erasecols(void *, int, int, int, long); 124 static void mgx_copyrows(void *, int, int, int); 125 static void mgx_eraserows(void *, int, int, long); 126 static void mgx_adapt(struct vcons_screen *, void *); 127 128 static int mgx_do_cursor(struct mgx_softc *, struct wsdisplay_cursor *); 129 static void mgx_set_cursor(struct mgx_softc *); 130 static void mgx_set_video(struct mgx_softc *, int); 131 132 CFATTACH_DECL_NEW(mgx, sizeof(struct mgx_softc), 133 mgx_match, mgx_attach, NULL, NULL); 134 135 struct wsdisplay_accessops mgx_accessops = { 136 mgx_ioctl, 137 mgx_mmap, 138 NULL, /* vcons_alloc_screen */ 139 NULL, /* vcons_free_screen */ 140 NULL, /* vcons_show_screen */ 141 NULL, /* load_font */ 142 NULL, /* polls */ 143 NULL, /* scroll */ 144 }; 145 146 static void mgx_unblank(device_t); 147 148 dev_type_open(mgxopen); 149 dev_type_close(mgxclose); 150 dev_type_ioctl(mgxioctl); 151 dev_type_mmap(mgxmmap); 152 153 const struct cdevsw mgx_cdevsw = { 154 .d_open = mgxopen, 155 .d_close = mgxclose, 156 .d_read = noread, 157 .d_write = nowrite, 158 .d_ioctl = mgxioctl, 159 .d_stop = nostop, 160 .d_tty = notty, 161 .d_poll = nopoll, 162 .d_mmap = mgxmmap, 163 .d_kqfilter = nokqfilter, 164 .d_discard = nodiscard, 165 .d_flag = D_OTHER 166 }; 167 168 /* frame buffer generic driver */ 169 static struct fbdriver mgx_fbdriver = { 170 mgx_unblank, mgxopen, mgxclose, mgxioctl, nopoll, mgxmmap, 171 nokqfilter 172 }; 173 174 175 static inline void 176 mgx_write_vga(struct mgx_softc *sc, uint32_t reg, uint8_t val) 177 { 178 bus_space_write_1(sc->sc_tag, sc->sc_vgah, reg ^ 3, val); 179 } 180 181 static inline uint8_t 182 mgx_read_vga(struct mgx_softc *sc, uint32_t reg) 183 { 184 return bus_space_read_1(sc->sc_tag, sc->sc_vgah, reg ^ 3); 185 } 186 187 static inline void 188 mgx_write_1(struct mgx_softc *sc, uint32_t reg, uint8_t val) 189 { 190 bus_space_write_1(sc->sc_tag, sc->sc_blith, reg ^ 3, val); 191 } 192 193 static inline uint8_t 194 mgx_read_1(struct mgx_softc *sc, uint32_t reg) 195 { 196 return bus_space_read_1(sc->sc_tag, sc->sc_blith, reg ^ 3); 197 } 198 199 #if 0 200 static inline uint32_t 201 mgx_read_4(struct mgx_softc *sc, uint32_t reg) 202 { 203 return bus_space_read_4(sc->sc_tag, sc->sc_blith, reg); 204 } 205 #endif 206 207 static inline void 208 mgx_write_2(struct mgx_softc *sc, uint32_t reg, uint16_t val) 209 { 210 bus_space_write_2(sc->sc_tag, sc->sc_blith, reg ^ 2, val); 211 } 212 213 static inline void 214 mgx_write_4(struct mgx_softc *sc, uint32_t reg, uint32_t val) 215 { 216 bus_space_write_4(sc->sc_tag, sc->sc_blith, reg, val); 217 } 218 219 static inline void 220 mgx_set_dec(struct mgx_softc *sc, uint32_t dec) 221 { 222 if (dec == sc->sc_r_dec) return; 223 sc->sc_r_dec = dec; 224 mgx_wait_engine(sc); 225 mgx_write_4(sc, ATR_DEC, dec); 226 } 227 228 static inline void 229 mgx_set_fg(struct mgx_softc *sc, uint32_t fg) 230 { 231 if (fg == sc->sc_r_fg) return; 232 sc->sc_r_fg = fg; 233 mgx_wait_fifo(sc, 1); 234 mgx_write_4(sc, ATR_FG, fg); 235 } 236 237 static int 238 mgx_match(device_t parent, cfdata_t cf, void *aux) 239 { 240 struct sbus_attach_args *sa = aux; 241 242 if (strcmp("SMSI,mgx", sa->sa_name) == 0) 243 return 100; 244 return 0; 245 } 246 247 /* 248 * Attach a display. We need to notice if it is the console, too. 249 */ 250 static void 251 mgx_attach(device_t parent, device_t self, void *args) 252 { 253 struct mgx_softc *sc = device_private(self); 254 struct sbus_attach_args *sa = args; 255 struct wsemuldisplaydev_attach_args aa; 256 struct fbdevice *fb = &sc->sc_fb; 257 struct rasops_info *ri; 258 unsigned long defattr; 259 bus_space_handle_t bh; 260 int node = sa->sa_node, bsize; 261 int isconsole; 262 263 aprint_normal("\n"); 264 sc->sc_dev = self; 265 sc->sc_tag = sa->sa_bustag; 266 267 sc->sc_paddr = sbus_bus_addr(sa->sa_bustag, sa->sa_slot, 268 sa->sa_reg[8].oa_base); 269 sc->sc_rpaddr = sbus_bus_addr(sa->sa_bustag, sa->sa_slot, 270 sa->sa_reg[5].oa_base + MGX_REG_ATREG_OFFSET); 271 272 /* read geometry information from the device tree */ 273 sc->sc_width = prom_getpropint(sa->sa_node, "width", 1152); 274 sc->sc_height = prom_getpropint(sa->sa_node, "height", 900); 275 sc->sc_stride = prom_getpropint(sa->sa_node, "linebytes", 1152); 276 sc->sc_fbsize = prom_getpropint(sa->sa_node, "fb_size", 0x00400000); 277 sc->sc_fbaddr = NULL; 278 if (sc->sc_fbaddr == NULL) { 279 if (sbus_bus_map(sa->sa_bustag, 280 sa->sa_slot, 281 sa->sa_reg[8].oa_base, 282 sc->sc_fbsize, 283 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE, 284 &bh) != 0) { 285 aprint_error_dev(self, "couldn't map framebuffer\n"); 286 return; 287 } 288 sc->sc_fbaddr = bus_space_vaddr(sa->sa_bustag, bh); 289 } 290 291 if (sbus_bus_map(sa->sa_bustag, 292 sa->sa_slot, 293 sa->sa_reg[4].oa_base, 0x1000, 0, 294 &sc->sc_vgah) != 0) { 295 aprint_error("%s: couldn't map VGA registers\n", 296 device_xname(sc->sc_dev)); 297 return; 298 } 299 300 if (sbus_bus_map(sa->sa_bustag, 301 sa->sa_slot, 302 sa->sa_reg[5].oa_base + MGX_REG_ATREG_OFFSET, 0x1000, 303 0, &sc->sc_blith) != 0) { 304 aprint_error("%s: couldn't map blitter registers\n", 305 device_xname(sc->sc_dev)); 306 return; 307 } 308 309 mgx_setup(sc, MGX_DEPTH); 310 311 aprint_normal_dev(self, "[%s] %d MB framebuffer, %d x %d\n", 312 sc->sc_name, sc->sc_fbsize >> 20, sc->sc_width, sc->sc_height); 313 314 315 sc->sc_defaultscreen_descr = (struct wsscreen_descr) { 316 "default", 317 0, 0, 318 NULL, 319 8, 16, 320 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 321 WSSCREEN_RESIZE, 322 NULL 323 }; 324 325 sc->sc_cursor_x = 0; 326 sc->sc_cursor_y = 0; 327 sc->sc_hotspot_x = 0; 328 sc->sc_hotspot_y = 0; 329 sc->sc_video = WSDISPLAYIO_VIDEO_ON; 330 331 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 332 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 333 334 isconsole = fb_is_console(node); 335 336 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 337 wsfont_init(); 338 339 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, &mgx_accessops); 340 sc->vd.init_screen = mgx_init_screen; 341 sc->vd.show_screen_cookie = sc; 342 sc->vd.show_screen_cb = mgx_adapt; 343 344 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, &defattr); 345 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 346 347 ri = &sc->sc_console_screen.scr_ri; 348 349 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 350 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 351 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 352 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 353 354 sc->sc_gc.gc_bitblt = mgx_bitblt; 355 sc->sc_gc.gc_rectfill = mgx_rectfill; 356 sc->sc_gc.gc_blitcookie = sc; 357 sc->sc_gc.gc_rop = ROP_SRC; 358 359 /* 360 * leave some room between visible screen and glyph cache for upload 361 * buffers used by putchar_mono() 362 */ 363 bsize = (32 * 1024 + sc->sc_stride - 1) / sc->sc_stride; 364 glyphcache_init(&sc->sc_gc, 365 sc->sc_height + bsize, 366 (0x400000 / sc->sc_stride) - (sc->sc_height + bsize), 367 sc->sc_width, 368 ri->ri_font->fontwidth, 369 ri->ri_font->fontheight, 370 defattr); 371 372 mgx_init_palette(sc); 373 374 if(isconsole) { 375 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 376 defattr); 377 vcons_replay_msgbuf(&sc->sc_console_screen); 378 } 379 380 aa.console = isconsole; 381 aa.scrdata = &sc->sc_screenlist; 382 aa.accessops = &mgx_accessops; 383 aa.accesscookie = &sc->vd; 384 385 config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE); 386 387 /* now the Sun fb goop */ 388 fb->fb_driver = &mgx_fbdriver; 389 fb->fb_device = sc->sc_dev; 390 fb->fb_flags = device_cfdata(sc->sc_dev)->cf_flags & FB_USERMASK; 391 fb->fb_type.fb_type = FBTYPE_MGX; 392 fb->fb_pixels = NULL; 393 394 fb->fb_type.fb_depth = 32; 395 fb->fb_type.fb_width = sc->sc_width; 396 fb->fb_type.fb_height = sc->sc_height; 397 fb->fb_linebytes = sc->sc_stride * 4; 398 399 fb->fb_type.fb_cmsize = 256; 400 fb->fb_type.fb_size = sc->sc_fbsize; 401 fb_attach(&sc->sc_fb, isconsole); 402 } 403 404 static void 405 mgx_write_dac(struct mgx_softc *sc, int idx, int r, int g, int b) 406 { 407 mgx_write_vga(sc, VGA_BASE + VGA_DAC_ADDRW, idx); 408 mgx_write_vga(sc, VGA_BASE + VGA_DAC_PALETTE, r); 409 mgx_write_vga(sc, VGA_BASE + VGA_DAC_PALETTE, g); 410 mgx_write_vga(sc, VGA_BASE + VGA_DAC_PALETTE, b); 411 } 412 413 static void 414 mgx_init_palette(struct mgx_softc *sc) 415 { 416 struct rasops_info *ri = &sc->sc_console_screen.scr_ri; 417 int i, j = 0; 418 uint8_t cmap[768]; 419 420 if (sc->sc_depth == 8) { 421 rasops_get_cmap(ri, cmap, sizeof(cmap)); 422 for (i = 0; i < 256; i++) { 423 sc->sc_cmap_red[i] = cmap[j]; 424 sc->sc_cmap_green[i] = cmap[j + 1]; 425 sc->sc_cmap_blue[i] = cmap[j + 2]; 426 mgx_write_dac(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 427 j += 3; 428 } 429 } else { 430 /* linear ramp for true colour modes */ 431 for (i = 0; i < 256; i++) { 432 mgx_write_dac(sc, i, i, i, i); 433 } 434 } 435 } 436 437 static int 438 mgx_putcmap(struct mgx_softc *sc, struct wsdisplay_cmap *cm) 439 { 440 u_char *r, *g, *b; 441 u_int index = cm->index; 442 u_int count = cm->count; 443 int i, error; 444 u_char rbuf[256], gbuf[256], bbuf[256]; 445 446 if (cm->index >= 256 || cm->count > 256 || 447 (cm->index + cm->count) > 256) 448 return EINVAL; 449 error = copyin(cm->red, &rbuf[index], count); 450 if (error) 451 return error; 452 error = copyin(cm->green, &gbuf[index], count); 453 if (error) 454 return error; 455 error = copyin(cm->blue, &bbuf[index], count); 456 if (error) 457 return error; 458 459 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 460 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 461 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 462 463 r = &sc->sc_cmap_red[index]; 464 g = &sc->sc_cmap_green[index]; 465 b = &sc->sc_cmap_blue[index]; 466 467 for (i = 0; i < count; i++) { 468 mgx_write_dac(sc, index, *r, *g, *b); 469 index++; 470 r++, g++, b++; 471 } 472 return 0; 473 } 474 475 static int 476 mgx_getcmap(struct mgx_softc *sc, struct wsdisplay_cmap *cm) 477 { 478 u_int index = cm->index; 479 u_int count = cm->count; 480 int error; 481 482 if (index >= 255 || count > 256 || index + count > 256) 483 return EINVAL; 484 485 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 486 if (error) 487 return error; 488 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 489 if (error) 490 return error; 491 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 492 if (error) 493 return error; 494 495 return 0; 496 } 497 498 static int 499 mgx_wait_engine(struct mgx_softc *sc) 500 { 501 unsigned int i; 502 uint8_t stat; 503 504 for (i = 100000; i != 0; i--) { 505 stat = mgx_read_1(sc, ATR_BLT_STATUS); 506 if ((stat & (BLT_HOST_BUSY | BLT_ENGINE_BUSY)) == 0) 507 break; 508 } 509 510 return i; 511 } 512 513 static inline int 514 mgx_wait_host(struct mgx_softc *sc) 515 { 516 unsigned int i; 517 uint8_t stat; 518 519 for (i = 10000; i != 0; i--) { 520 stat = mgx_read_1(sc, ATR_BLT_STATUS); 521 if ((stat & BLT_HOST_BUSY) == 0) 522 break; 523 } 524 525 return i; 526 } 527 528 /*static inline*/ int 529 mgx_wait_fifo(struct mgx_softc *sc, unsigned int nfifo) 530 { 531 unsigned int i; 532 uint8_t stat; 533 534 for (i = 100000; i != 0; i--) { 535 stat = mgx_read_1(sc, ATR_FIFO_STATUS); 536 stat = (stat & FIFO_MASK) >> FIFO_SHIFT; 537 if (stat >= nfifo) 538 break; 539 mgx_write_1(sc, ATR_FIFO_STATUS, 0); 540 } 541 542 return i; 543 } 544 545 static void 546 mgx_setup(struct mgx_softc *sc, int depth) 547 { 548 uint32_t stride; 549 int i; 550 uint8_t reg; 551 552 sc->sc_r_dec = 0xffffffff; 553 sc->sc_r_fg = 0x12345678; 554 /* wait for everything to go idle */ 555 if (mgx_wait_engine(sc) == 0) 556 return; 557 if (mgx_wait_fifo(sc, FIFO_AT24) == 0) 558 return; 559 560 sc->sc_buf = 0; 561 /* read name from sequencer */ 562 for (i = 0; i < 8; i++) { 563 mgx_write_vga(sc, SEQ_INDEX, i + 0x11); 564 sc->sc_name[i] = mgx_read_vga(sc, SEQ_DATA); 565 } 566 sc->sc_name[7] = 0; 567 568 reg = mgx_read_1(sc, ATR_PIXEL); 569 reg &= ~PIXEL_DEPTH_MASK; 570 571 switch (depth) { 572 case 8: 573 sc->sc_dec = DEC_DEPTH_8 << DEC_DEPTH_SHIFT; 574 reg |= PIXEL_8; 575 break; 576 case 15: 577 sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT; 578 reg |= PIXEL_15; 579 break; 580 case 16: 581 sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT; 582 reg |= PIXEL_16; 583 break; 584 case 32: 585 sc->sc_dec = DEC_DEPTH_32 << DEC_DEPTH_SHIFT; 586 reg |= PIXEL_32; 587 break; 588 default: 589 return; /* not supported */ 590 } 591 592 /* the chip wants stride in units of 8 bytes */ 593 sc->sc_stride = sc->sc_width * (depth >> 3); 594 stride = sc->sc_stride >> 3; 595 #ifdef MGX_DEBUG 596 sc->sc_height -= 150; 597 #endif 598 599 sc->sc_depth = depth; 600 601 switch (sc->sc_width) { 602 case 640: 603 sc->sc_dec |= DEC_WIDTH_640 << DEC_WIDTH_SHIFT; 604 break; 605 case 800: 606 sc->sc_dec |= DEC_WIDTH_800 << DEC_WIDTH_SHIFT; 607 break; 608 case 1024: 609 sc->sc_dec |= DEC_WIDTH_1024 << DEC_WIDTH_SHIFT; 610 break; 611 case 1152: 612 sc->sc_dec |= DEC_WIDTH_1152 << DEC_WIDTH_SHIFT; 613 break; 614 case 1280: 615 sc->sc_dec |= DEC_WIDTH_1280 << DEC_WIDTH_SHIFT; 616 break; 617 case 1600: 618 sc->sc_dec |= DEC_WIDTH_1600 << DEC_WIDTH_SHIFT; 619 break; 620 default: 621 return; /* not supported */ 622 } 623 mgx_wait_fifo(sc, 4); 624 mgx_write_1(sc, ATR_CLIP_CONTROL, 0); 625 mgx_write_1(sc, ATR_BYTEMASK, 0xff); 626 mgx_write_1(sc, ATR_PIXEL, reg); 627 mgx_write_4(sc, ATR_OFFSET, 0); 628 mgx_wait_fifo(sc, 4); 629 mgx_write_vga(sc, CRTC_INDEX, 0x13); 630 mgx_write_vga(sc, CRTC_DATA, stride & 0xff); 631 mgx_write_vga(sc, CRTC_INDEX, 0x1c); 632 mgx_write_vga(sc, CRTC_DATA, (stride & 0xf00) >> 4); 633 634 /* clean up the screen if we're switching to != 8bit */ 635 if (depth != MGX_DEPTH) 636 mgx_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 0); 637 638 mgx_wait_fifo(sc, 4); 639 /* initialize hardware cursor stuff */ 640 mgx_write_2(sc, ATR_CURSOR_ADDRESS, (sc->sc_fbsize - 1024) >> 10); 641 mgx_write_1(sc, ATR_CURSOR_ENABLE, 0); 642 sc->sc_cursor = (uint8_t *)sc->sc_fbaddr + sc->sc_fbsize - 1024; 643 memset(sc->sc_cursor, 0xf0, 1024); 644 memset(sc->sc_in, 0, sizeof(sc->sc_in)); 645 } 646 647 static void 648 mgx_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi, int he, 649 int rop) 650 { 651 struct mgx_softc *sc = cookie; 652 uint32_t dec = sc->sc_dec; 653 654 dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | 655 (DEC_START_DIMX << DEC_START_SHIFT); 656 if (xs < xd) { 657 xs += wi - 1; 658 xd += wi - 1; 659 dec |= DEC_DIR_X_REVERSE; 660 } 661 if (ys < yd) { 662 ys += he - 1; 663 yd += he - 1; 664 dec |= DEC_DIR_Y_REVERSE; 665 } 666 mgx_set_dec(sc, dec); 667 mgx_wait_fifo(sc, 4); 668 mgx_write_1(sc, ATR_ROP, rop); 669 mgx_write_4(sc, ATR_SRC_XY, (ys << 16) | xs); 670 mgx_write_4(sc, ATR_DST_XY, (yd << 16) | xd); 671 mgx_write_4(sc, ATR_WH, (he << 16) | wi); 672 } 673 674 static void 675 mgx_rectfill(void *cookie, int x, int y, int wi, int he, long fg) 676 { 677 struct mgx_softc *sc = cookie; 678 struct vcons_screen *scr = sc->vd.active; 679 uint32_t dec = sc->sc_dec; 680 uint32_t col; 681 682 if (scr == NULL) 683 return; 684 col = scr->scr_ri.ri_devcmap[fg]; 685 686 dec = sc->sc_dec; 687 dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) | 688 (DEC_START_DIMX << DEC_START_SHIFT); 689 mgx_set_dec(sc, dec); 690 mgx_set_fg(sc, col); 691 mgx_wait_fifo(sc, 3); 692 mgx_write_1(sc, ATR_ROP, ROP_SRC); 693 mgx_write_4(sc, ATR_DST_XY, (y << 16) | x); 694 mgx_write_4(sc, ATR_WH, (he << 16) | wi); 695 } 696 697 static void 698 mgx_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 699 { 700 struct rasops_info *ri = cookie; 701 struct wsdisplay_font *font = PICK_FONT(ri, c); 702 struct vcons_screen *scr = ri->ri_hw; 703 struct mgx_softc *sc = scr->scr_cookie; 704 uint32_t fg, bg; 705 int x, y, wi, he, rv; 706 707 wi = font->fontwidth; 708 he = font->fontheight; 709 710 bg = (attr >> 16) & 0xf; 711 fg = (attr >> 24) & 0xf; 712 713 x = ri->ri_xorigin + col * wi; 714 y = ri->ri_yorigin + row * he; 715 716 if (c == 0x20) { 717 mgx_rectfill(sc, x, y, wi, he, bg); 718 if (attr & 1) 719 mgx_rectfill(sc, x, y + he - 2, wi, 1, fg); 720 return; 721 } 722 723 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 724 if (rv != GC_OK) { 725 volatile uint32_t junk; 726 727 mgx_wait_engine(sc); 728 sc->sc_putchar(cookie, row, col, c, attr & ~1); 729 if (rv == GC_ADD) { 730 /* 731 * try to make sure the glyph made it all the way to 732 * video memory before trying to blit it into the cache 733 */ 734 junk = *(uint32_t *)sc->sc_fbaddr; 735 __USE(junk); 736 glyphcache_add(&sc->sc_gc, c, x, y); 737 } 738 } 739 if (attr & 1) 740 mgx_rectfill(sc, x, y + he - 2, wi, 1, fg); 741 } 742 743 static void 744 mgx_putchar_mono(void *cookie, int row, int col, u_int c, long attr) 745 { 746 struct rasops_info *ri = cookie; 747 struct wsdisplay_font *font = PICK_FONT(ri, c); 748 struct vcons_screen *scr = ri->ri_hw; 749 struct mgx_softc *sc = scr->scr_cookie; 750 uint8_t *s, *d; 751 uint32_t fg, bg, scratch = ((sc->sc_stride * sc->sc_height) + 7) & ~7; 752 int x, y, wi, he, len, i; 753 754 wi = font->fontwidth; 755 he = font->fontheight; 756 757 bg = (attr >> 16) & 0xf; 758 fg = (attr >> 24) & 0xf; 759 760 x = ri->ri_xorigin + col * wi; 761 y = ri->ri_yorigin + row * he; 762 763 if (!CHAR_IN_FONT(c, font)) { 764 c = 0x20; 765 #ifdef MGX_DEBUG 766 bg = WSCOL_LIGHT_BLUE; 767 #endif 768 } 769 if (c == 0x20) { 770 mgx_rectfill(sc, x, y, wi, he, bg); 771 if (attr & 1) 772 mgx_rectfill(sc, x, y + he - 2, wi, 1, fg); 773 return; 774 } 775 776 mgx_set_fg(sc, ri->ri_devcmap[fg]); 777 mgx_wait_fifo(sc, 2); 778 mgx_write_4(sc, ATR_BG, ri->ri_devcmap[bg]); 779 mgx_write_1(sc, ATR_ROP, ROP_SRC); 780 781 /* 782 * do hardware colour expansion 783 * there has to be an upload port somewhere, since there are host blit 784 * commands, but it's not used or mentioned in the xf86-video-apm driver 785 * so for now we use the vram-to-vram blits to draw characters. 786 * stash most of the font in vram for speed, also: 787 * - the sbus-pci bridge doesn't seem to support 64bit accesses, 788 * they will cause occasional data corruption and all sorts of weird 789 * side effects, so copy font bitmaps byte-wise 790 * - at least it doesn't seem to need any kind of buffer flushing 791 * - still use rotation buffers for characters that don't fall into the 792 * 8 bit range 793 */ 794 795 len = (ri->ri_fontscale + 7) & ~7; 796 s = WSFONT_GLYPH(c, font); 797 if ((c > 32) && (c < 256)) { 798 scratch += len * c; 799 if (sc->sc_in[c] == 0) { 800 d = (uint8_t *)sc->sc_fbaddr + scratch; 801 for (i = 0; i < ri->ri_fontscale; i++) 802 d[i] = s[i]; 803 sc->sc_in[c] = 1; 804 } 805 } else { 806 sc->sc_buf = (sc->sc_buf + 1) & 7; /* rotate through 8 buffers */ 807 scratch += sc->sc_buf * len; 808 d = (uint8_t *)sc->sc_fbaddr + scratch; 809 for (i = 0; i < ri->ri_fontscale; i++) 810 d[i] = s[i]; 811 } 812 mgx_set_dec(sc, sc->sc_dec | (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | 813 (DEC_START_DIMX << DEC_START_SHIFT) | 814 DEC_SRC_LINEAR | DEC_SRC_CONTIGUOUS | DEC_MONOCHROME); 815 mgx_wait_fifo(sc, 3); 816 mgx_write_4(sc, ATR_SRC_XY, ((scratch & 0xfff000) << 4) | (scratch & 0xfff)); 817 mgx_write_4(sc, ATR_DST_XY, (y << 16) | x); 818 mgx_write_4(sc, ATR_WH, (he << 16) | wi); 819 820 if (attr & 1) 821 mgx_rectfill(sc, x, y + he - 2, wi, 1, fg); 822 } 823 824 static void 825 mgx_cursor(void *cookie, int on, int row, int col) 826 { 827 struct rasops_info *ri = cookie; 828 struct vcons_screen *scr = ri->ri_hw; 829 struct mgx_softc *sc = scr->scr_cookie; 830 int x, y, wi,he; 831 832 wi = ri->ri_font->fontwidth; 833 he = ri->ri_font->fontheight; 834 835 if (ri->ri_flg & RI_CURSOR) { 836 x = ri->ri_ccol * wi + ri->ri_xorigin; 837 y = ri->ri_crow * he + ri->ri_yorigin; 838 mgx_bitblt(sc, x, y, x, y, wi, he, ROP_INV); 839 ri->ri_flg &= ~RI_CURSOR; 840 } 841 842 ri->ri_crow = row; 843 ri->ri_ccol = col; 844 845 if (on) 846 { 847 x = ri->ri_ccol * wi + ri->ri_xorigin; 848 y = ri->ri_crow * he + ri->ri_yorigin; 849 mgx_bitblt(sc, x, y, x, y, wi, he, ROP_INV); 850 ri->ri_flg |= RI_CURSOR; 851 } 852 } 853 854 static void 855 mgx_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 856 { 857 struct rasops_info *ri = cookie; 858 struct vcons_screen *scr = ri->ri_hw; 859 struct mgx_softc *sc = scr->scr_cookie; 860 int32_t xs, xd, y, width, height; 861 862 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 863 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 864 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 865 width = ri->ri_font->fontwidth * ncols; 866 height = ri->ri_font->fontheight; 867 mgx_bitblt(sc, xs, y, xd, y, width, height, ROP_SRC); 868 } 869 870 static void 871 mgx_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 872 { 873 struct rasops_info *ri = cookie; 874 struct vcons_screen *scr = ri->ri_hw; 875 struct mgx_softc *sc = scr->scr_cookie; 876 int32_t x, y, width, height, bg; 877 878 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 879 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 880 width = ri->ri_font->fontwidth * ncols; 881 height = ri->ri_font->fontheight; 882 bg = (fillattr >> 16) & 0xff; 883 mgx_rectfill(sc, x, y, width, height, bg); 884 } 885 886 static void 887 mgx_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 888 { 889 struct rasops_info *ri = cookie; 890 struct vcons_screen *scr = ri->ri_hw; 891 struct mgx_softc *sc = scr->scr_cookie; 892 int32_t x, ys, yd, width, height; 893 894 x = ri->ri_xorigin; 895 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 896 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 897 width = ri->ri_emuwidth; 898 height = ri->ri_font->fontheight * nrows; 899 mgx_bitblt(sc, x, ys, x, yd, width, height, ROP_SRC); 900 } 901 902 static void 903 mgx_eraserows(void *cookie, int row, int nrows, long fillattr) 904 { 905 struct rasops_info *ri = cookie; 906 struct vcons_screen *scr = ri->ri_hw; 907 struct mgx_softc *sc = scr->scr_cookie; 908 int32_t x, y, width, height, bg; 909 910 if ((row == 0) && (nrows == ri->ri_rows)) { 911 x = y = 0; 912 width = ri->ri_width; 913 height = ri->ri_height; 914 } else { 915 x = ri->ri_xorigin; 916 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 917 width = ri->ri_emuwidth; 918 height = ri->ri_font->fontheight * nrows; 919 } 920 bg = (fillattr >> 16) & 0xff; 921 mgx_rectfill(sc, x, y, width, height, bg); 922 } 923 924 static void 925 mgx_adapt(struct vcons_screen *scr, void *cookie) 926 { 927 struct mgx_softc *sc = cookie; 928 memset(sc->sc_in, 0, sizeof(sc->sc_in)); 929 glyphcache_adapt(scr, &sc->sc_gc); 930 } 931 932 static void 933 mgx_init_screen(void *cookie, struct vcons_screen *scr, 934 int existing, long *defattr) 935 { 936 struct mgx_softc *sc = cookie; 937 struct rasops_info *ri = &scr->scr_ri; 938 939 ri->ri_depth = sc->sc_depth; 940 ri->ri_width = sc->sc_width; 941 ri->ri_height = sc->sc_height; 942 ri->ri_stride = sc->sc_stride; 943 ri->ri_flg = RI_CENTER | RI_ENABLE_ALPHA; 944 945 if (ri->ri_depth == 8) 946 ri->ri_flg |= RI_8BIT_IS_RGB; 947 948 #ifdef MGX_NOACCEL 949 scr->scr_flags |= VCONS_DONT_READ; 950 #endif 951 scr->scr_flags |= VCONS_LOADFONT; 952 953 ri->ri_rnum = 8; 954 ri->ri_rpos = 0; 955 ri->ri_gnum = 8; 956 ri->ri_gpos = 8; 957 ri->ri_bnum = 8; 958 ri->ri_bpos = 16; 959 960 ri->ri_bits = sc->sc_fbaddr; 961 962 rasops_init(ri, 0, 0); 963 964 ri->ri_caps = WSSCREEN_REVERSE | WSSCREEN_WSCOLORS | 965 WSSCREEN_UNDERLINE | WSSCREEN_RESIZE; 966 967 rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight, 968 ri->ri_width / ri->ri_font->fontwidth); 969 970 ri->ri_hw = scr; 971 972 #ifdef MGX_NOACCEL 973 if (0) 974 #endif 975 { 976 if (FONT_IS_ALPHA(ri->ri_font)) { 977 sc->sc_putchar = ri->ri_ops.putchar; 978 ri->ri_ops.putchar = mgx_putchar_aa; 979 } else { 980 ri->ri_ops.putchar = mgx_putchar_mono; 981 } 982 ri->ri_ops.cursor = mgx_cursor; 983 ri->ri_ops.copyrows = mgx_copyrows; 984 ri->ri_ops.eraserows = mgx_eraserows; 985 ri->ri_ops.copycols = mgx_copycols; 986 ri->ri_ops.erasecols = mgx_erasecols; 987 } 988 } 989 990 static int 991 mgx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 992 struct lwp *l) 993 { 994 struct vcons_data *vd = v; 995 struct mgx_softc *sc = vd->cookie; 996 struct wsdisplay_fbinfo *wdf; 997 struct vcons_screen *ms = vd->active; 998 999 switch (cmd) { 1000 case WSDISPLAYIO_GTYPE: 1001 *(u_int *)data = WSDISPLAY_TYPE_MGX; 1002 return 0; 1003 1004 case WSDISPLAYIO_GINFO: 1005 wdf = (void *)data; 1006 wdf->height = sc->sc_height; 1007 wdf->width = sc->sc_width; 1008 wdf->depth = 8; 1009 wdf->cmsize = 256; 1010 return 0; 1011 1012 case FBIOGTYPE: 1013 *(struct fbtype *)data = sc->sc_fb.fb_type; 1014 return 0; 1015 1016 case FBIOGATTR: 1017 #define fba ((struct fbgattr *)data) 1018 fba->real_type = sc->sc_fb.fb_type.fb_type; 1019 fba->owner = 0; /* XXX ??? */ 1020 fba->fbtype = sc->sc_fb.fb_type; 1021 fba->sattr.flags = 0; 1022 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 1023 fba->sattr.dev_specific[0] = -1; 1024 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 1025 fba->emu_types[1] = -1; 1026 #undef fba 1027 return 0; 1028 case FBIOGVIDEO: 1029 case WSDISPLAYIO_GVIDEO: 1030 *(int *)data = sc->sc_video; 1031 return 0; 1032 1033 case WSDISPLAYIO_SVIDEO: 1034 case FBIOSVIDEO: 1035 mgx_set_video(sc, *(int *)data); 1036 return 0; 1037 1038 case WSDISPLAYIO_LINEBYTES: 1039 { 1040 int *ret = (int *)data; 1041 *ret = sc->sc_stride; 1042 } 1043 return 0; 1044 1045 case WSDISPLAYIO_SMODE: 1046 { 1047 int new_mode = *(int*)data; 1048 if (new_mode != sc->sc_mode) 1049 { 1050 sc->sc_mode = new_mode; 1051 if (new_mode == WSDISPLAYIO_MODE_EMUL) 1052 { 1053 mgx_setup(sc, MGX_DEPTH); 1054 glyphcache_wipe(&sc->sc_gc); 1055 mgx_init_palette(sc); 1056 vcons_redraw_screen(ms); 1057 } else { 1058 mgx_setup(sc, MGX_X_DEPTH); 1059 mgx_init_palette(sc); 1060 } 1061 } 1062 } 1063 return 0; 1064 1065 case WSDISPLAYIO_GETCMAP: 1066 return mgx_getcmap(sc, (struct wsdisplay_cmap *)data); 1067 1068 case WSDISPLAYIO_PUTCMAP: 1069 return mgx_putcmap(sc, (struct wsdisplay_cmap *)data); 1070 1071 case FBIOGETCMAP: 1072 #define p ((struct fbcmap *)data) 1073 { 1074 struct wsdisplay_cmap c = { 1075 .index = p->index, 1076 .count = p->count, 1077 .red = p->red, 1078 .green = p->green, 1079 .blue = p->blue 1080 }; 1081 return mgx_getcmap(sc, &c); 1082 } 1083 break; 1084 case FBIOPUTCMAP: 1085 { 1086 struct wsdisplay_cmap c = { 1087 .index = p->index, 1088 .count = p->count, 1089 .red = p->red, 1090 .green = p->green, 1091 .blue = p->blue 1092 }; 1093 return mgx_putcmap(sc, &c); 1094 } 1095 break; 1096 #undef p 1097 case WSDISPLAYIO_GCURPOS: 1098 { 1099 struct wsdisplay_curpos *cp = (void *)data; 1100 1101 cp->x = sc->sc_cursor_x; 1102 cp->y = sc->sc_cursor_y; 1103 } 1104 return 0; 1105 1106 case WSDISPLAYIO_SCURPOS: 1107 { 1108 struct wsdisplay_curpos *cp = (void *)data; 1109 1110 sc->sc_cursor_x = cp->x; 1111 sc->sc_cursor_y = cp->y; 1112 mgx_set_cursor(sc); 1113 } 1114 return 0; 1115 1116 case WSDISPLAYIO_GCURMAX: 1117 { 1118 struct wsdisplay_curpos *cp = (void *)data; 1119 1120 cp->x = 64; 1121 cp->y = 64; 1122 } 1123 return 0; 1124 1125 case WSDISPLAYIO_SCURSOR: 1126 { 1127 struct wsdisplay_cursor *cursor = (void *)data; 1128 1129 return mgx_do_cursor(sc, cursor); 1130 } 1131 1132 case WSDISPLAYIO_GET_FBINFO: 1133 { 1134 struct wsdisplayio_fbinfo *fbi = data; 1135 1136 fbi->fbi_fbsize = sc->sc_fbsize - 1024; 1137 fbi->fbi_width = sc->sc_width; 1138 fbi->fbi_height = sc->sc_height; 1139 fbi->fbi_bitsperpixel = sc->sc_depth; 1140 fbi->fbi_stride = sc->sc_stride; 1141 fbi->fbi_pixeltype = WSFB_RGB; 1142 fbi->fbi_subtype.fbi_rgbmasks.red_offset = 8; 1143 fbi->fbi_subtype.fbi_rgbmasks.red_size = 8; 1144 fbi->fbi_subtype.fbi_rgbmasks.green_offset = 16; 1145 fbi->fbi_subtype.fbi_rgbmasks.green_size = 8; 1146 fbi->fbi_subtype.fbi_rgbmasks.blue_offset = 24; 1147 fbi->fbi_subtype.fbi_rgbmasks.blue_size = 8; 1148 fbi->fbi_subtype.fbi_rgbmasks.alpha_offset = 0; 1149 fbi->fbi_subtype.fbi_rgbmasks.alpha_size = 8; 1150 return 0; 1151 } 1152 } 1153 return EPASSTHROUGH; 1154 } 1155 1156 static paddr_t 1157 mgx_mmap(void *v, void *vs, off_t offset, int prot) 1158 { 1159 struct vcons_data *vd = v; 1160 struct mgx_softc *sc = vd->cookie; 1161 uint32_t flags = BUS_SPACE_MAP_LINEAR; 1162 1163 #ifdef BUS_SPACE_MAP_LITTLE 1164 if (offset & MGX_FLIPOFFSET) { 1165 offset &= ~MGX_FLIPOFFSET; 1166 flags |= BUS_SPACE_MAP_LITTLE; 1167 } 1168 #endif 1169 1170 /* regular fb mapping at 0 */ 1171 if ((offset >= 0) && (offset < sc->sc_fbsize)) { 1172 return bus_space_mmap(sc->sc_tag, sc->sc_paddr, 1173 offset, prot, flags); 1174 } 1175 1176 /* 1177 * Blitter registers at 0x00800000, only in mapped mode. 1178 * Restrict to root, even though I'm fairly sure the DMA engine lives 1179 * elsewhere ( and isn't documented anyway ) 1180 */ 1181 if (kauth_authorize_machdep(kauth_cred_get(), 1182 KAUTH_MACHDEP_UNMANAGEDMEM, 1183 NULL, NULL, NULL, NULL) != 0) { 1184 aprint_normal("%s: mmap() rejected.\n", 1185 device_xname(sc->sc_dev)); 1186 return -1; 1187 } 1188 if ((sc->sc_mode == WSDISPLAYIO_MODE_MAPPED) && 1189 (offset >= MGX_BLTOFFSET) && (offset < MGX_BLTOFFSET + 0x1000)) { 1190 return bus_space_mmap(sc->sc_tag, sc->sc_rpaddr, 1191 offset - MGX_BLTOFFSET, prot, BUS_SPACE_MAP_LINEAR); 1192 } 1193 return -1; 1194 } 1195 1196 static int 1197 mgx_do_cursor(struct mgx_softc *sc, struct wsdisplay_cursor *cur) 1198 { 1199 int i; 1200 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 1201 1202 if (cur->enable) { 1203 mgx_set_cursor(sc); 1204 mgx_write_1(sc, ATR_CURSOR_ENABLE, 1); 1205 } else { 1206 mgx_write_1(sc, ATR_CURSOR_ENABLE, 0); 1207 } 1208 } 1209 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 1210 1211 sc->sc_hotspot_x = cur->hot.x; 1212 sc->sc_hotspot_y = cur->hot.y; 1213 mgx_set_cursor(sc); 1214 } 1215 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 1216 1217 sc->sc_cursor_x = cur->pos.x; 1218 sc->sc_cursor_y = cur->pos.y; 1219 mgx_set_cursor(sc); 1220 } 1221 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 1222 int cnt = uimin(2, cur->cmap.count); 1223 uint8_t c; 1224 uint8_t r[2], g[2], b[2]; 1225 1226 copyin(cur->cmap.red, r, cnt); 1227 copyin(cur->cmap.green, g, cnt); 1228 copyin(cur->cmap.blue, b, cnt); 1229 1230 for (i = 0; i < cnt; i++) { 1231 c = r[i] & 0xe0; 1232 c |= (g[i] & 0xe0) >> 3; 1233 c |= (b[i] & 0xc0) >> 6; 1234 mgx_write_1(sc, ATR_CURSOR_FG + i, c); 1235 } 1236 } 1237 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 1238 int j; 1239 uint8_t *fb = sc->sc_cursor; 1240 uint8_t temp; 1241 uint8_t im, ma, px; 1242 1243 for (i = 0; i < 512; i++) { 1244 temp = 0; 1245 copyin(&cur->image[i], &im, 1); 1246 copyin(&cur->mask[i], &ma, 1); 1247 for (j = 0; j < 4; j++) { 1248 temp >>= 2; 1249 px = (ma & 1) ? 0 : 0x80; 1250 if (px == 0) 1251 px |= (im & 1) ? 0 : 0x40; 1252 temp |= px; 1253 im >>= 1; 1254 ma >>= 1; 1255 } 1256 *fb = temp; 1257 fb++; 1258 temp = 0; 1259 for (j = 0; j < 4; j++) { 1260 temp >>= 2; 1261 px = (ma & 1) ? 0 : 0x80; 1262 if (px == 0) 1263 px |= (im & 1) ? 0 : 0x40; 1264 temp |= px; 1265 im >>= 1; 1266 ma >>= 1; 1267 } 1268 *fb = temp; 1269 fb++; 1270 } 1271 } 1272 return 0; 1273 } 1274 1275 static void 1276 mgx_set_cursor(struct mgx_softc *sc) 1277 { 1278 uint32_t reg; 1279 uint16_t hot; 1280 1281 reg = (sc->sc_cursor_y << 16) | (sc->sc_cursor_x & 0xffff); 1282 mgx_write_4(sc, ATR_CURSOR_POSITION, reg); 1283 hot = (sc->sc_hotspot_y << 8) | (sc->sc_hotspot_x & 0xff); 1284 mgx_write_2(sc, ATR_CURSOR_HOTSPOT, hot); 1285 } 1286 1287 static void 1288 mgx_set_video(struct mgx_softc *sc, int v) 1289 { 1290 uint8_t reg; 1291 1292 if (sc->sc_video == v) 1293 return; 1294 1295 sc->sc_video = v; 1296 reg = mgx_read_1(sc, ATR_DPMS); 1297 1298 if (v == WSDISPLAYIO_VIDEO_ON) { 1299 reg &= ~DPMS_SYNC_DISABLE_ALL; 1300 } else { 1301 reg |= DPMS_SYNC_DISABLE_ALL; 1302 } 1303 mgx_write_1(sc, ATR_DPMS, reg); 1304 } 1305 1306 /* Sun fb dev goop */ 1307 static void 1308 mgx_unblank(device_t dev) 1309 { 1310 struct mgx_softc *sc = device_private(dev); 1311 1312 mgx_set_video(sc, WSDISPLAYIO_VIDEO_ON); 1313 } 1314 1315 paddr_t 1316 mgxmmap(dev_t dev, off_t offset, int prot) 1317 { 1318 struct mgx_softc *sc = device_lookup_private(&mgx_cd, minor(dev)); 1319 uint32_t flags = BUS_SPACE_MAP_LINEAR; 1320 1321 #ifdef BUS_SPACE_MAP_LITTLE 1322 if (offset & MGX_FLIPOFFSET) { 1323 offset &= ~MGX_FLIPOFFSET; 1324 flags |= BUS_SPACE_MAP_LITTLE; 1325 } 1326 #endif 1327 1328 /* regular fb mapping at 0 */ 1329 if ((offset >= 0) && (offset < sc->sc_fbsize)) { 1330 return bus_space_mmap(sc->sc_tag, sc->sc_paddr, 1331 offset, prot, flags); 1332 } 1333 1334 /* 1335 * Blitter registers at 0x00800000, only in mapped mode. 1336 * Restrict to root, even though I'm fairly sure the DMA engine lives 1337 * elsewhere ( and isn't documented anyway ) 1338 */ 1339 if (kauth_authorize_machdep(kauth_cred_get(), 1340 KAUTH_MACHDEP_UNMANAGEDMEM, 1341 NULL, NULL, NULL, NULL) != 0) { 1342 aprint_normal("%s: mmap() rejected.\n", 1343 device_xname(sc->sc_dev)); 1344 return -1; 1345 } 1346 if ((sc->sc_mode == WSDISPLAYIO_MODE_MAPPED) && 1347 (offset >= MGX_BLTOFFSET) && (offset < MGX_BLTOFFSET + 0x1000)) { 1348 return bus_space_mmap(sc->sc_tag, sc->sc_rpaddr, 1349 offset - MGX_BLTOFFSET, prot, BUS_SPACE_MAP_LINEAR); 1350 } 1351 return -1; 1352 } 1353 1354 int 1355 mgxopen(dev_t dev, int flags, int mode, struct lwp *l) 1356 { 1357 device_t dv = device_lookup(&mgx_cd, minor(dev)); 1358 struct mgx_softc *sc = device_private(dv); 1359 1360 if (dv == NULL) 1361 return ENXIO; 1362 if (sc->sc_mode == WSDISPLAYIO_MODE_MAPPED) 1363 return 0; 1364 sc->sc_mode = WSDISPLAYIO_MODE_MAPPED; 1365 mgx_setup(sc, MGX_X_DEPTH); 1366 mgx_init_palette(sc); 1367 return 0; 1368 } 1369 1370 int 1371 mgxclose(dev_t dev, int flags, int mode, struct lwp *l) 1372 { 1373 device_t dv = device_lookup(&mgx_cd, minor(dev)); 1374 struct mgx_softc *sc = device_private(dv); 1375 struct vcons_screen *ms = sc->vd.active; 1376 1377 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) 1378 return 0; 1379 1380 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 1381 1382 mgx_setup(sc, MGX_DEPTH); 1383 glyphcache_wipe(&sc->sc_gc); 1384 mgx_init_palette(sc); 1385 if (ms != NULL) { 1386 vcons_redraw_screen(ms); 1387 } 1388 return 0; 1389 } 1390 1391 int 1392 mgxioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 1393 { 1394 struct mgx_softc *sc = device_lookup_private(&mgx_cd, minor(dev)); 1395 1396 return mgx_ioctl(&sc->vd, NULL, cmd, data, flags, l); 1397 } 1398