1 /* $NetBSD: voyagerfb.c,v 1.33 2021/08/07 16:19:14 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2009, 2011 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * A console driver for Silicon Motion SM502 / Voyager GX graphics controllers 30 * tested on GDIUM only so far 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: voyagerfb.c,v 1.33 2021/08/07 16:19:14 thorpej Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 #include <sys/lwp.h> 42 #include <sys/kauth.h> 43 44 #include <dev/videomode/videomode.h> 45 46 #include <dev/pci/pcivar.h> 47 #include <dev/pci/pcireg.h> 48 #include <dev/pci/pcidevs.h> 49 #include <dev/pci/pciio.h> 50 #include <dev/ic/sm502reg.h> 51 52 #include <dev/wscons/wsdisplayvar.h> 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/wsfont/wsfont.h> 55 #include <dev/rasops/rasops.h> 56 #include <dev/wscons/wsdisplay_vconsvar.h> 57 #include <dev/pci/wsdisplay_pci.h> 58 59 #include <dev/i2c/i2cvar.h> 60 #include <dev/pci/voyagervar.h> 61 #include <dev/wscons/wsdisplay_glyphcachevar.h> 62 63 #include "opt_voyagerfb.h" 64 65 #ifdef VOYAGERFB_DEBUG 66 #define DPRINTF aprint_error 67 #else 68 #define DPRINTF while (0) printf 69 #endif 70 71 /* XXX these are gdium-specific */ 72 #define GPIO_BACKLIGHT 0x20000000 73 74 struct voyagerfb_softc { 75 device_t sc_dev; 76 77 pci_chipset_tag_t sc_pc; 78 pcitag_t sc_pcitag; 79 bus_space_tag_t sc_memt; 80 81 bus_space_handle_t sc_fbh; 82 bus_space_handle_t sc_regh; 83 bus_addr_t sc_fb, sc_reg; 84 bus_size_t sc_fbsize, sc_regsize; 85 86 int sc_width, sc_height, sc_depth, sc_stride; 87 int sc_locked; 88 void *sc_fbaddr; 89 struct vcons_screen sc_console_screen; 90 struct wsscreen_descr sc_defaultscreen_descr; 91 const struct wsscreen_descr *sc_screens[1]; 92 struct wsscreen_list sc_screenlist; 93 struct vcons_data vd; 94 uint8_t *sc_dataport; 95 int sc_mode; 96 int sc_bl_on, sc_bl_level; 97 void *sc_gpio_cookie; 98 99 /* cursor stuff */ 100 int sc_cur_x; 101 int sc_cur_y; 102 int sc_hot_x; 103 int sc_hot_y; 104 uint32_t sc_cursor_addr; 105 uint32_t *sc_cursor; 106 107 /* colour map */ 108 u_char sc_cmap_red[256]; 109 u_char sc_cmap_green[256]; 110 u_char sc_cmap_blue[256]; 111 112 glyphcache sc_gc; 113 }; 114 115 static int voyagerfb_match(device_t, cfdata_t, void *); 116 static void voyagerfb_attach(device_t, device_t, void *); 117 118 CFATTACH_DECL_NEW(voyagerfb, sizeof(struct voyagerfb_softc), 119 voyagerfb_match, voyagerfb_attach, NULL, NULL); 120 121 extern const u_char rasops_cmap[768]; 122 123 static int voyagerfb_ioctl(void *, void *, u_long, void *, int, 124 struct lwp *); 125 static paddr_t voyagerfb_mmap(void *, void *, off_t, int); 126 static void voyagerfb_init_screen(void *, struct vcons_screen *, int, 127 long *); 128 129 static int voyagerfb_putcmap(struct voyagerfb_softc *, 130 struct wsdisplay_cmap *); 131 static int voyagerfb_getcmap(struct voyagerfb_softc *, 132 struct wsdisplay_cmap *); 133 static void voyagerfb_restore_palette(struct voyagerfb_softc *); 134 static int voyagerfb_putpalreg(struct voyagerfb_softc *, int, uint8_t, 135 uint8_t, uint8_t); 136 137 static void voyagerfb_init(struct voyagerfb_softc *); 138 139 static void voyagerfb_rectfill(struct voyagerfb_softc *, int, int, int, int, 140 uint32_t); 141 static void voyagerfb_bitblt(void *, int, int, int, int, 142 int, int, int); 143 144 static void voyagerfb_cursor(void *, int, int, int); 145 static void voyagerfb_putchar_mono(void *, int, int, u_int, long); 146 static void voyagerfb_putchar_aa32(void *, int, int, u_int, long); 147 static void voyagerfb_putchar_aa8(void *, int, int, u_int, long); 148 static void voyagerfb_copycols(void *, int, int, int, int); 149 static void voyagerfb_erasecols(void *, int, int, int, long); 150 static void voyagerfb_copyrows(void *, int, int, int); 151 static void voyagerfb_eraserows(void *, int, int, long); 152 153 static int voyagerfb_set_curpos(struct voyagerfb_softc *, int, int); 154 static int voyagerfb_gcursor(struct voyagerfb_softc *, 155 struct wsdisplay_cursor *); 156 static int voyagerfb_scursor(struct voyagerfb_softc *, 157 struct wsdisplay_cursor *); 158 159 struct wsdisplay_accessops voyagerfb_accessops = { 160 voyagerfb_ioctl, 161 voyagerfb_mmap, 162 NULL, /* alloc_screen */ 163 NULL, /* free_screen */ 164 NULL, /* show_screen */ 165 NULL, /* load_font */ 166 NULL, /* pollc */ 167 NULL /* scroll */ 168 }; 169 170 static void voyagerfb_setup_backlight(struct voyagerfb_softc *); 171 static void voyagerfb_brightness_up(device_t); 172 static void voyagerfb_brightness_down(device_t); 173 /* set backlight level */ 174 static void voyagerfb_set_backlight(struct voyagerfb_softc *, int); 175 /* turn backlight on and off without messing with the level */ 176 static void voyagerfb_switch_backlight(struct voyagerfb_softc *, int); 177 178 /* wait for FIFO empty so we can feed it another command */ 179 static inline void 180 voyagerfb_ready(struct voyagerfb_softc *sc) 181 { 182 do {} while ((bus_space_read_4(sc->sc_memt, sc->sc_regh, 183 SM502_SYSTEM_CTRL) & SM502_SYSCTL_FIFO_EMPTY) == 0); 184 } 185 186 /* wait for the drawing engine to be idle */ 187 static inline void 188 voyagerfb_wait(struct voyagerfb_softc *sc) 189 { 190 do {} while ((bus_space_read_4(sc->sc_memt, sc->sc_regh, 191 SM502_SYSTEM_CTRL) & SM502_SYSCTL_ENGINE_BUSY) != 0); 192 } 193 194 static int 195 voyagerfb_match(device_t parent, cfdata_t match, void *aux) 196 { 197 struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux; 198 199 if (strcmp(vaa->vaa_name, "voyagerfb") == 0) return 100; 200 return 0; 201 } 202 203 static void 204 voyagerfb_attach(device_t parent, device_t self, void *aux) 205 { 206 struct voyagerfb_softc *sc = device_private(self); 207 struct voyager_attach_args *vaa = aux; 208 struct rasops_info *ri; 209 struct wsemuldisplaydev_attach_args aa; 210 prop_dictionary_t dict; 211 unsigned long defattr; 212 uint32_t reg; 213 bool is_console; 214 int i, j; 215 uint8_t cmap[768]; 216 217 sc->sc_pc = vaa->vaa_pc; 218 sc->sc_pcitag = vaa->vaa_pcitag; 219 sc->sc_memt = vaa->vaa_tag; 220 sc->sc_dev = self; 221 222 aprint_normal("\n"); 223 224 dict = device_properties(self); 225 prop_dictionary_get_bool(dict, "is_console", &is_console); 226 227 sc->sc_fb = vaa->vaa_mem_pa; 228 sc->sc_fbh = vaa->vaa_memh; 229 sc->sc_fbaddr = bus_space_vaddr(sc->sc_memt, sc->sc_fbh); 230 231 sc->sc_reg = vaa->vaa_reg_pa; 232 sc->sc_regh = vaa->vaa_regh; 233 sc->sc_regsize = 2 * 1024 * 1024; 234 sc->sc_dataport = bus_space_vaddr(sc->sc_memt, sc->sc_regh); 235 sc->sc_dataport += SM502_DATAPORT; 236 237 sc->sc_gpio_cookie = device_private(parent); 238 239 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_DRAM_CONTROL); 240 switch(reg & 0x0000e000) { 241 case SM502_MEM_2M: 242 sc->sc_fbsize = 2 * 1024 * 1024; 243 break; 244 case SM502_MEM_4M: 245 sc->sc_fbsize = 4 * 1024 * 1024; 246 break; 247 case SM502_MEM_8M: 248 sc->sc_fbsize = 8 * 1024 * 1024; 249 break; 250 case SM502_MEM_16M: 251 sc->sc_fbsize = 16 * 1024 * 1024; 252 break; 253 case SM502_MEM_32M: 254 sc->sc_fbsize = 32 * 1024 * 1024; 255 break; 256 case SM502_MEM_64M: 257 sc->sc_fbsize = 64 * 1024 * 1024; 258 break; 259 } 260 261 sc->sc_width = (bus_space_read_4(sc->sc_memt, sc->sc_regh, 262 SM502_PANEL_FB_WIDTH) & SM502_FBW_WIN_WIDTH_MASK) >> 16; 263 sc->sc_height = (bus_space_read_4(sc->sc_memt, sc->sc_regh, 264 SM502_PANEL_FB_HEIGHT) & SM502_FBH_WIN_HEIGHT_MASK) >> 16; 265 266 #ifdef VOYAGERFB_DEPTH_32 267 sc->sc_depth = 32; 268 #else 269 sc->sc_depth = 8; 270 #endif 271 272 /* 273 * XXX yeah, casting the fb address to uint32_t is formally wrong 274 * but as far as I know there are no SM502 with 64bit BARs 275 */ 276 aprint_normal_dev(self, "%d MB video memory at 0x%08x\n", 277 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb); 278 279 /* init engine here */ 280 voyagerfb_init(sc); 281 282 aprint_normal_dev(self, "%d x %d, %d bit, stride %d\n", 283 sc->sc_width, sc->sc_height, sc->sc_depth, sc->sc_stride); 284 285 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 286 "default", 287 0, 0, 288 NULL, 289 8, 16, 290 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 291 WSSCREEN_RESIZE, 292 NULL 293 }; 294 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 295 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 296 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 297 sc->sc_locked = 0; 298 299 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 300 &voyagerfb_accessops); 301 sc->vd.init_screen = voyagerfb_init_screen; 302 sc->vd.show_screen_cookie = &sc->sc_gc; 303 sc->vd.show_screen_cb = glyphcache_adapt; 304 305 /* backlight control */ 306 voyagerfb_setup_backlight(sc); 307 308 ri = &sc->sc_console_screen.scr_ri; 309 310 sc->sc_gc.gc_bitblt = voyagerfb_bitblt; 311 sc->sc_gc.gc_blitcookie = sc; 312 sc->sc_gc.gc_rop = ROP_COPY; 313 if (is_console) { 314 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 315 &defattr); 316 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 317 318 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 319 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 320 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 321 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 322 } else { 323 if (sc->sc_console_screen.scr_ri.ri_rows == 0) { 324 /* do some minimal setup to avoid weirdness later */ 325 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 326 &defattr); 327 } else 328 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 329 } 330 glyphcache_init(&sc->sc_gc, sc->sc_height, 331 ((sc->sc_fbsize - 16 * 64) / sc->sc_stride) - 332 sc->sc_height, 333 sc->sc_width, 334 ri->ri_font->fontwidth, 335 ri->ri_font->fontheight, 336 defattr); 337 if (is_console) 338 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 339 defattr); 340 341 rasops_get_cmap(ri, cmap, sizeof(cmap)); 342 j = 0; 343 if (sc->sc_depth <= 8) { 344 for (i = 0; i < 256; i++) { 345 346 sc->sc_cmap_red[i] = cmap[j]; 347 sc->sc_cmap_green[i] = cmap[j + 1]; 348 sc->sc_cmap_blue[i] = cmap[j + 2]; 349 voyagerfb_putpalreg(sc, i, cmap[j], cmap[j + 1], 350 cmap[j + 2]); 351 j += 3; 352 } 353 } 354 355 voyagerfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 356 ri->ri_devcmap[(defattr >> 16) & 0xff]); 357 358 if (is_console) 359 vcons_replay_msgbuf(&sc->sc_console_screen); 360 361 aa.console = is_console; 362 aa.scrdata = &sc->sc_screenlist; 363 aa.accessops = &voyagerfb_accessops; 364 aa.accesscookie = &sc->vd; 365 366 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, 367 CFARGS(.iattr = "wsemuldisplaydev")); 368 } 369 370 static int 371 voyagerfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 372 struct lwp *l) 373 { 374 struct vcons_data *vd = v; 375 struct voyagerfb_softc *sc = vd->cookie; 376 struct wsdisplay_fbinfo *wdf; 377 struct vcons_screen *ms = vd->active; 378 struct wsdisplay_param *param; 379 380 switch (cmd) { 381 case WSDISPLAYIO_GTYPE: 382 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 383 return 0; 384 385 /* PCI config read/write pass through. */ 386 case PCI_IOC_CFGREAD: 387 case PCI_IOC_CFGWRITE: 388 return pci_devioctl(sc->sc_pc, sc->sc_pcitag, 389 cmd, data, flag, l); 390 391 case WSDISPLAYIO_GET_BUSID: 392 return wsdisplayio_busid_pci(device_parent(sc->sc_dev), 393 sc->sc_pc, sc->sc_pcitag, data); 394 395 case WSDISPLAYIO_GINFO: 396 if (ms == NULL) 397 return ENODEV; 398 wdf = (void *)data; 399 wdf->height = ms->scr_ri.ri_height; 400 wdf->width = ms->scr_ri.ri_width; 401 wdf->depth = 32; 402 wdf->cmsize = 256; 403 return 0; 404 405 case WSDISPLAYIO_GETCMAP: 406 return voyagerfb_getcmap(sc, 407 (struct wsdisplay_cmap *)data); 408 409 case WSDISPLAYIO_PUTCMAP: 410 return voyagerfb_putcmap(sc, 411 (struct wsdisplay_cmap *)data); 412 413 case WSDISPLAYIO_LINEBYTES: 414 *(u_int *)data = sc->sc_stride; 415 return 0; 416 417 case WSDISPLAYIO_SMODE: { 418 int new_mode = *(int*)data; 419 if (new_mode != sc->sc_mode) { 420 sc->sc_mode = new_mode; 421 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 422 #ifdef VOYAGERFB_DEPTH_32 423 sc->sc_depth = 32; 424 #else 425 sc->sc_depth = 8; 426 #endif 427 glyphcache_wipe(&sc->sc_gc); 428 voyagerfb_init(sc); 429 voyagerfb_restore_palette(sc); 430 vcons_redraw_screen(ms); 431 } else { 432 sc->sc_depth = 32; 433 voyagerfb_init(sc); 434 } 435 } 436 } 437 return 0; 438 439 case WSDISPLAYIO_GVIDEO: 440 *(int *)data = sc->sc_bl_on ? WSDISPLAYIO_VIDEO_ON : 441 WSDISPLAYIO_VIDEO_OFF; 442 return 0; 443 444 case WSDISPLAYIO_SVIDEO: { 445 int new_bl = *(int *)data; 446 447 voyagerfb_switch_backlight(sc, new_bl); 448 } 449 return 0; 450 451 case WSDISPLAYIO_GETPARAM: 452 param = (struct wsdisplay_param *)data; 453 switch (param->param) { 454 case WSDISPLAYIO_PARAM_BRIGHTNESS: 455 param->min = 0; 456 param->max = 255; 457 param->curval = sc->sc_bl_level; 458 return 0; 459 case WSDISPLAYIO_PARAM_BACKLIGHT: 460 param->min = 0; 461 param->max = 1; 462 param->curval = sc->sc_bl_on; 463 return 0; 464 } 465 return EPASSTHROUGH; 466 467 case WSDISPLAYIO_SETPARAM: 468 param = (struct wsdisplay_param *)data; 469 switch (param->param) { 470 case WSDISPLAYIO_PARAM_BRIGHTNESS: 471 voyagerfb_set_backlight(sc, param->curval); 472 return 0; 473 case WSDISPLAYIO_PARAM_BACKLIGHT: 474 voyagerfb_switch_backlight(sc, param->curval); 475 return 0; 476 } 477 return EPASSTHROUGH; 478 479 case WSDISPLAYIO_GCURPOS: 480 { 481 struct wsdisplay_curpos *pos; 482 483 pos = (struct wsdisplay_curpos *)data; 484 pos->x = sc->sc_cur_x; 485 pos->y = sc->sc_cur_y; 486 } 487 return 0; 488 489 case WSDISPLAYIO_SCURPOS: 490 { 491 struct wsdisplay_curpos *pos; 492 493 pos = (struct wsdisplay_curpos *)data; 494 voyagerfb_set_curpos(sc, pos->x, pos->y); 495 } 496 return 0; 497 498 case WSDISPLAYIO_GCURMAX: 499 { 500 struct wsdisplay_curpos *pos; 501 502 pos = (struct wsdisplay_curpos *)data; 503 pos->x = 64; 504 pos->y = 64; 505 } 506 return 0; 507 508 case WSDISPLAYIO_GCURSOR: 509 { 510 struct wsdisplay_cursor *cu; 511 512 cu = (struct wsdisplay_cursor *)data; 513 return voyagerfb_gcursor(sc, cu); 514 } 515 516 case WSDISPLAYIO_SCURSOR: 517 { 518 struct wsdisplay_cursor *cu; 519 520 cu = (struct wsdisplay_cursor *)data; 521 return voyagerfb_scursor(sc, cu); 522 } 523 524 case WSDISPLAYIO_GET_FBINFO: 525 { 526 struct wsdisplayio_fbinfo *fbi = data; 527 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 528 } 529 } 530 return EPASSTHROUGH; 531 } 532 533 static paddr_t 534 voyagerfb_mmap(void *v, void *vs, off_t offset, int prot) 535 { 536 struct vcons_data *vd = v; 537 struct voyagerfb_softc *sc = vd->cookie; 538 paddr_t pa; 539 540 /* 'regular' framebuffer mmap()ing */ 541 if (offset < sc->sc_fbsize) { 542 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset, 0, prot, 543 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 544 return pa; 545 } 546 547 /* 548 * restrict all other mappings to processes with privileges 549 */ 550 if (kauth_authorize_machdep(kauth_cred_get(), 551 KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) != 0) { 552 aprint_normal("%s: mmap() rejected.\n", 553 device_xname(sc->sc_dev)); 554 return -1; 555 } 556 557 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) { 558 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 559 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 560 return pa; 561 } 562 563 if ((offset >= sc->sc_reg) && 564 (offset < (sc->sc_reg + sc->sc_regsize))) { 565 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 0); 566 return pa; 567 } 568 569 return -1; 570 } 571 572 static void 573 voyagerfb_init_screen(void *cookie, struct vcons_screen *scr, 574 int existing, long *defattr) 575 { 576 struct voyagerfb_softc *sc = cookie; 577 struct rasops_info *ri = &scr->scr_ri; 578 579 ri->ri_depth = sc->sc_depth; 580 ri->ri_width = sc->sc_width; 581 ri->ri_height = sc->sc_height; 582 ri->ri_stride = sc->sc_stride; 583 ri->ri_flg = RI_CENTER | RI_FULLCLEAR; 584 585 ri->ri_bits = (char *)sc->sc_fbaddr; 586 587 if (existing) { 588 ri->ri_flg |= RI_CLEAR; 589 } 590 591 if (sc->sc_depth == 8) { 592 ri->ri_flg |= RI_8BIT_IS_RGB; 593 #ifdef VOYAGERFB_ANTIALIAS 594 ri->ri_flg |= RI_ENABLE_ALPHA | RI_PREFER_ALPHA; 595 #endif 596 } 597 if (sc->sc_depth == 32) { 598 #ifdef VOYAGERFB_ANTIALIAS 599 ri->ri_flg |= RI_ENABLE_ALPHA; 600 #endif 601 /* we always run in RGB */ 602 ri->ri_rnum = 8; 603 ri->ri_gnum = 8; 604 ri->ri_bnum = 8; 605 ri->ri_rpos = 16; 606 ri->ri_gpos = 8; 607 ri->ri_bpos = 0; 608 } 609 610 scr->scr_flags |= VCONS_LOADFONT; 611 612 rasops_init(ri, 0, 0); 613 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 614 WSSCREEN_RESIZE; 615 616 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 617 sc->sc_width / ri->ri_font->fontwidth); 618 619 ri->ri_hw = scr; 620 ri->ri_ops.copyrows = voyagerfb_copyrows; 621 ri->ri_ops.copycols = voyagerfb_copycols; 622 ri->ri_ops.eraserows = voyagerfb_eraserows; 623 ri->ri_ops.erasecols = voyagerfb_erasecols; 624 ri->ri_ops.cursor = voyagerfb_cursor; 625 if (FONT_IS_ALPHA(ri->ri_font)) { 626 switch (sc->sc_depth) { 627 case 32: 628 ri->ri_ops.putchar = voyagerfb_putchar_aa32; 629 break; 630 case 8: 631 ri->ri_ops.putchar = voyagerfb_putchar_aa8; 632 break; 633 default: 634 printf("alpha font at %d!?\n", sc->sc_depth); 635 } 636 } else 637 ri->ri_ops.putchar = voyagerfb_putchar_mono; 638 } 639 640 static int 641 voyagerfb_putcmap(struct voyagerfb_softc *sc, struct wsdisplay_cmap *cm) 642 { 643 u_char *r, *g, *b; 644 u_int index = cm->index; 645 u_int count = cm->count; 646 int i, error; 647 u_char rbuf[256], gbuf[256], bbuf[256]; 648 649 #ifdef VOYAGERFB_DEBUG 650 aprint_debug("putcmap: %d %d\n",index, count); 651 #endif 652 if (cm->index >= 256 || cm->count > 256 || 653 (cm->index + cm->count) > 256) 654 return EINVAL; 655 error = copyin(cm->red, &rbuf[index], count); 656 if (error) 657 return error; 658 error = copyin(cm->green, &gbuf[index], count); 659 if (error) 660 return error; 661 error = copyin(cm->blue, &bbuf[index], count); 662 if (error) 663 return error; 664 665 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 666 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 667 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 668 669 r = &sc->sc_cmap_red[index]; 670 g = &sc->sc_cmap_green[index]; 671 b = &sc->sc_cmap_blue[index]; 672 673 for (i = 0; i < count; i++) { 674 voyagerfb_putpalreg(sc, index, *r, *g, *b); 675 index++; 676 r++, g++, b++; 677 } 678 return 0; 679 } 680 681 static int 682 voyagerfb_getcmap(struct voyagerfb_softc *sc, struct wsdisplay_cmap *cm) 683 { 684 u_int index = cm->index; 685 u_int count = cm->count; 686 int error; 687 688 if (index >= 255 || count > 256 || index + count > 256) 689 return EINVAL; 690 691 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 692 if (error) 693 return error; 694 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 695 if (error) 696 return error; 697 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 698 if (error) 699 return error; 700 701 return 0; 702 } 703 704 static void 705 voyagerfb_restore_palette(struct voyagerfb_softc *sc) 706 { 707 int i; 708 709 for (i = 0; i < 256; i++) { 710 voyagerfb_putpalreg(sc, i, sc->sc_cmap_red[i], 711 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]); 712 } 713 } 714 715 static int 716 voyagerfb_putpalreg(struct voyagerfb_softc *sc, int idx, uint8_t r, 717 uint8_t g, uint8_t b) 718 { 719 uint32_t reg; 720 721 reg = (r << 16) | (g << 8) | b; 722 /* XXX we should probably write the CRT palette too */ 723 bus_space_write_4(sc->sc_memt, sc->sc_regh, 724 SM502_PALETTE_PANEL + (idx << 2), reg); 725 return 0; 726 } 727 728 static void 729 voyagerfb_init(struct voyagerfb_softc *sc) 730 { 731 int reg; 732 733 voyagerfb_wait(sc); 734 /* disable colour compare */ 735 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_COLOR_COMP_MASK, 0); 736 /* allow writes to all planes */ 737 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PLANEMASK, 738 0xffffffff); 739 /* disable clipping */ 740 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CLIP_TOP_LEFT, 0); 741 /* source and destination in local memory, no offset */ 742 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC_BASE, 0); 743 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST_BASE, 0); 744 /* pitch is screen stride */ 745 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PITCH, 746 sc->sc_width | (sc->sc_width << 16)); 747 /* window is screen width */ 748 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_WINDOW_WIDTH, 749 sc->sc_width | (sc->sc_width << 16)); 750 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_DISP_CTRL); 751 reg &= ~SM502_PDC_DEPTH_MASK; 752 753 switch (sc->sc_depth) { 754 case 8: 755 bus_space_write_4(sc->sc_memt, sc->sc_regh, 756 SM502_STRETCH, SM502_STRETCH_8BIT); 757 sc->sc_stride = sc->sc_width; 758 reg |= SM502_PDC_8BIT; 759 break; 760 case 16: 761 bus_space_write_4(sc->sc_memt, sc->sc_regh, 762 SM502_STRETCH, SM502_STRETCH_16BIT); 763 sc->sc_stride = sc->sc_width << 1; 764 reg |= SM502_PDC_16BIT; 765 break; 766 case 24: 767 case 32: 768 bus_space_write_4(sc->sc_memt, sc->sc_regh, 769 SM502_STRETCH, SM502_STRETCH_32BIT); 770 sc->sc_stride = sc->sc_width << 2; 771 reg |= SM502_PDC_32BIT; 772 break; 773 } 774 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_FB_OFFSET, 775 (sc->sc_stride << 16) | sc->sc_stride); 776 777 /* clear the screen... */ 778 voyagerfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 0); 779 780 /* ...and then switch colour depth. For aesthetic reasons. */ 781 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_DISP_CTRL, 782 reg); 783 784 /* put the cursor at the end of video memory */ 785 sc->sc_cursor_addr = sc->sc_fbsize - 16 * 64; /* XXX */ 786 DPRINTF("%s: %08x\n", __func__, sc->sc_cursor_addr); 787 sc->sc_cursor = (uint32_t *)((uint8_t *)bus_space_vaddr(sc->sc_memt, 788 sc->sc_fbh) + sc->sc_cursor_addr); 789 #ifdef VOYAGERFB_DEBUG 790 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_XY, 791 0x00100010); 792 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_COL12, 793 0x0000ffff); 794 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_COL3, 795 0x0000f800); 796 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_ADDR, 797 SM502_CRSR_ENABLE | sc->sc_cursor_addr); 798 sc->sc_cursor[0] = 0x00000000; 799 sc->sc_cursor[1] = 0x00000000; 800 sc->sc_cursor[2] = 0xffffffff; 801 sc->sc_cursor[3] = 0xffffffff; 802 sc->sc_cursor[4] = 0xaaaaaaaa; 803 sc->sc_cursor[5] = 0xaaaaaaaa; 804 sc->sc_cursor[6] = 0xffffffff; 805 sc->sc_cursor[7] = 0x00000000; 806 #else 807 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_ADDR, 808 sc->sc_cursor_addr); 809 #endif 810 } 811 812 static void 813 voyagerfb_rectfill(struct voyagerfb_softc *sc, int x, int y, int wi, int he, 814 uint32_t colour) 815 { 816 817 voyagerfb_ready(sc); 818 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, 819 ROP_COPY | 820 SM502_CTRL_USE_ROP2 | 821 SM502_CTRL_CMD_RECTFILL | 822 SM502_CTRL_QUICKSTART_E); 823 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_FOREGROUND, 824 colour); 825 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST, 826 (x << 16) | y); 827 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION, 828 (wi << 16) | he); 829 } 830 831 static void 832 voyagerfb_bitblt(void *cookie, int xs, int ys, int xd, int yd, 833 int wi, int he, int rop) 834 { 835 struct voyagerfb_softc *sc = cookie; 836 uint32_t cmd; 837 838 cmd = (rop & 0xf) | SM502_CTRL_USE_ROP2 | SM502_CTRL_CMD_BITBLT | 839 SM502_CTRL_QUICKSTART_E; 840 841 voyagerfb_ready(sc); 842 843 if (xd <= xs) { 844 /* left to right */ 845 } else { 846 /* 847 * According to the manual this flag reverses only the blitter's 848 * X direction. At least on my Gdium it also reverses the Y 849 * direction 850 */ 851 cmd |= SM502_CTRL_R_TO_L; 852 xs += wi - 1; 853 xd += wi - 1; 854 ys += he - 1; 855 yd += he - 1; 856 } 857 858 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd); 859 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC, 860 (xs << 16) | ys); 861 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST, 862 (xd << 16) | yd); 863 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION, 864 (wi << 16) | he); 865 } 866 867 static void 868 voyagerfb_cursor(void *cookie, int on, int row, int col) 869 { 870 struct rasops_info *ri = cookie; 871 struct vcons_screen *scr = ri->ri_hw; 872 struct voyagerfb_softc *sc = scr->scr_cookie; 873 int x, y, wi, he; 874 875 wi = ri->ri_font->fontwidth; 876 he = ri->ri_font->fontheight; 877 878 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 879 x = ri->ri_ccol * wi + ri->ri_xorigin; 880 y = ri->ri_crow * he + ri->ri_yorigin; 881 if (ri->ri_flg & RI_CURSOR) { 882 voyagerfb_bitblt(sc, x, y, x, y, wi, he, ROP_INVERT); 883 ri->ri_flg &= ~RI_CURSOR; 884 } 885 ri->ri_crow = row; 886 ri->ri_ccol = col; 887 if (on) { 888 x = ri->ri_ccol * wi + ri->ri_xorigin; 889 y = ri->ri_crow * he + ri->ri_yorigin; 890 voyagerfb_bitblt(sc, x, y, x, y, wi, he, ROP_INVERT); 891 ri->ri_flg |= RI_CURSOR; 892 } 893 } else { 894 scr->scr_ri.ri_crow = row; 895 scr->scr_ri.ri_ccol = col; 896 scr->scr_ri.ri_flg &= ~RI_CURSOR; 897 } 898 899 } 900 901 static inline void 902 voyagerfb_feed8(struct voyagerfb_softc *sc, uint8_t *data, int len) 903 { 904 uint32_t *port = (uint32_t *)sc->sc_dataport; 905 int i; 906 907 for (i = 0; i < ((len + 3) & 0xfffc); i++) { 908 *port = *data; 909 data++; 910 } 911 } 912 913 static inline void 914 voyagerfb_feed16(struct voyagerfb_softc *sc, uint16_t *data, int len) 915 { 916 uint32_t *port = (uint32_t *)sc->sc_dataport; 917 int i; 918 919 len = len << 1; 920 for (i = 0; i < ((len + 1) & 0xfffe); i++) { 921 *port = *data; 922 data++; 923 } 924 } 925 926 static void 927 voyagerfb_putchar_mono(void *cookie, int row, int col, u_int c, long attr) 928 { 929 struct rasops_info *ri = cookie; 930 struct wsdisplay_font *font = PICK_FONT(ri, c); 931 struct vcons_screen *scr = ri->ri_hw; 932 struct voyagerfb_softc *sc = scr->scr_cookie; 933 uint32_t cmd; 934 int fg, bg; 935 uint8_t *data; 936 int x, y, wi, he; 937 938 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 939 return; 940 941 if (!CHAR_IN_FONT(c, font)) 942 return; 943 944 wi = font->fontwidth; 945 he = font->fontheight; 946 947 bg = ri->ri_devcmap[(attr >> 16) & 0x0f]; 948 fg = ri->ri_devcmap[(attr >> 24) & 0x0f]; 949 x = ri->ri_xorigin + col * wi; 950 y = ri->ri_yorigin + row * he; 951 if (c == 0x20) { 952 voyagerfb_rectfill(sc, x, y, wi, he, bg); 953 return; 954 } 955 956 data = WSFONT_GLYPH(c, font); 957 958 cmd = ROP_COPY | 959 SM502_CTRL_USE_ROP2 | 960 SM502_CTRL_CMD_HOSTWRT | 961 SM502_CTRL_HOSTBLT_MONO | 962 SM502_CTRL_QUICKSTART_E | 963 SM502_CTRL_MONO_PACK_32BIT; 964 voyagerfb_ready(sc); 965 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd); 966 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_FOREGROUND, fg); 967 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_BACKGROUND, bg); 968 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC, 0); 969 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST, (x << 16) | y); 970 bus_space_write_4(sc->sc_memt, sc->sc_regh, 971 SM502_DIMENSION, (wi << 16) | he); 972 /* now feed the data, padded to 32bit */ 973 switch (ri->ri_font->stride) { 974 case 1: 975 voyagerfb_feed8(sc, data, ri->ri_fontscale); 976 break; 977 case 2: 978 voyagerfb_feed16(sc, (uint16_t *)data, 979 ri->ri_fontscale); 980 break; 981 } 982 } 983 984 static void 985 voyagerfb_putchar_aa32(void *cookie, int row, int col, u_int c, long attr) 986 { 987 struct rasops_info *ri = cookie; 988 struct wsdisplay_font *font = PICK_FONT(ri, c); 989 struct vcons_screen *scr = ri->ri_hw; 990 struct voyagerfb_softc *sc = scr->scr_cookie; 991 uint32_t cmd; 992 int fg, bg; 993 uint8_t *data; 994 int x, y, wi, he; 995 int i, j, r, g, b, aval, pad; 996 int rf, gf, bf, rb, gb, bb; 997 uint32_t pixel; 998 int rv; 999 1000 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1001 return; 1002 1003 if (!CHAR_IN_FONT(c, font)) 1004 return; 1005 1006 wi = font->fontwidth; 1007 he = font->fontheight; 1008 1009 bg = ri->ri_devcmap[(attr >> 16) & 0x0f]; 1010 fg = ri->ri_devcmap[(attr >> 24) & 0x0f]; 1011 x = ri->ri_xorigin + col * wi; 1012 y = ri->ri_yorigin + row * he; 1013 if (c == 0x20) { 1014 voyagerfb_rectfill(sc, x, y, wi, he, bg); 1015 return; 1016 } 1017 1018 data = WSFONT_GLYPH(c, font); 1019 /* 1020 * we can't accelerate the actual alpha blending but 1021 * we can at least use a host blit to go through the 1022 * pipeline instead of having to sync the engine 1023 */ 1024 1025 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1026 if (rv == GC_OK) 1027 return; 1028 1029 cmd = ROP_COPY | 1030 SM502_CTRL_USE_ROP2 | 1031 SM502_CTRL_CMD_HOSTWRT | 1032 SM502_CTRL_QUICKSTART_E; 1033 voyagerfb_ready(sc); 1034 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd); 1035 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC, 0); 1036 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST, (x << 16) | y); 1037 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION, 1038 (wi << 16) | he); 1039 rf = (fg >> 16) & 0xff; 1040 rb = (bg >> 16) & 0xff; 1041 gf = (fg >> 8) & 0xff; 1042 gb = (bg >> 8) & 0xff; 1043 bf = fg & 0xff; 1044 bb = bg & 0xff; 1045 pad = wi & 1; 1046 for (i = 0; i < he; i++) { 1047 for (j = 0; j < wi; j++) { 1048 aval = *data; 1049 data++; 1050 if (aval == 0) { 1051 pixel = bg; 1052 } else if (aval == 255) { 1053 pixel = fg; 1054 } else { 1055 r = aval * rf + (255 - aval) * rb; 1056 g = aval * gf + (255 - aval) * gb; 1057 b = aval * bf + (255 - aval) * bb; 1058 pixel = (r & 0xff00) << 8 | 1059 (g & 0xff00) | 1060 (b & 0xff00) >> 8; 1061 } 1062 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1063 SM502_DATAPORT, pixel); 1064 } 1065 if (pad) 1066 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1067 SM502_DATAPORT, 0); 1068 } 1069 if (rv == GC_ADD) { 1070 glyphcache_add(&sc->sc_gc, c, x, y); 1071 } 1072 } 1073 1074 static void 1075 voyagerfb_putchar_aa8(void *cookie, int row, int col, u_int c, long attr) 1076 { 1077 struct rasops_info *ri = cookie; 1078 struct wsdisplay_font *font = PICK_FONT(ri, c); 1079 struct vcons_screen *scr = ri->ri_hw; 1080 struct voyagerfb_softc *sc = scr->scr_cookie; 1081 uint32_t cmd; 1082 int bg; 1083 uint8_t *data; 1084 int x, y, wi, he; 1085 int i, j, r, g, b, aval, pad; 1086 int r1, g1, b1, r0, g0, b0, fgo, bgo; 1087 uint32_t pixel = 0, latch = 0, bg8, fg8; 1088 int rv; 1089 1090 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1091 return; 1092 1093 if (!CHAR_IN_FONT(c, font)) 1094 return; 1095 1096 wi = font->fontwidth; 1097 he = font->fontheight; 1098 1099 bg = ri->ri_devcmap[(attr >> 16) & 0x0f]; 1100 x = ri->ri_xorigin + col * wi; 1101 y = ri->ri_yorigin + row * he; 1102 if (c == 0x20) { 1103 voyagerfb_rectfill(sc, x, y, wi, he, bg); 1104 return; 1105 } 1106 1107 data = WSFONT_GLYPH(c, font); 1108 /* 1109 * we can't accelerate the actual alpha blending but 1110 * we can at least use a host blit to go through the 1111 * pipeline instead of having to sync the engine 1112 */ 1113 1114 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1115 if (rv == GC_OK) 1116 return; 1117 1118 cmd = ROP_COPY | 1119 SM502_CTRL_USE_ROP2 | 1120 SM502_CTRL_CMD_HOSTWRT | 1121 SM502_CTRL_QUICKSTART_E; 1122 voyagerfb_ready(sc); 1123 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd); 1124 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC, 0); 1125 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST, (x << 16) | y); 1126 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION, 1127 (wi << 16) | he); 1128 1129 /* 1130 * we need the RGB colours here, so get offsets into rasops_cmap 1131 */ 1132 fgo = ((attr >> 24) & 0xf) * 3; 1133 bgo = ((attr >> 16) & 0xf) * 3; 1134 1135 r0 = rasops_cmap[bgo]; 1136 r1 = rasops_cmap[fgo]; 1137 g0 = rasops_cmap[bgo + 1]; 1138 g1 = rasops_cmap[fgo + 1]; 1139 b0 = rasops_cmap[bgo + 2]; 1140 b1 = rasops_cmap[fgo + 2]; 1141 #define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)) 1142 bg8 = R3G3B2(r0, g0, b0); 1143 fg8 = R3G3B2(r1, g1, b1); 1144 1145 pad = wi & 4; 1146 for (i = 0; i < he; i++) { 1147 for (j = 0; j < wi; j++) { 1148 aval = *data; 1149 data++; 1150 if (aval == 0) { 1151 pixel = bg8; 1152 } else if (aval == 255) { 1153 pixel = fg8; 1154 } else { 1155 r = aval * r1 + (255 - aval) * r0; 1156 g = aval * g1 + (255 - aval) * g0; 1157 b = aval * b1 + (255 - aval) * b0; 1158 pixel = ((r & 0xe000) >> 8) | 1159 ((g & 0xe000) >> 11) | 1160 ((b & 0xc000) >> 14); 1161 } 1162 latch = (latch << 8) | pixel; 1163 /* write in 32bit chunks */ 1164 if ((j & 3) == 3) { 1165 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1166 SM502_DATAPORT, be32toh(latch)); 1167 latch = 0; 1168 } 1169 } 1170 /* if we have pixels left in latch write them out */ 1171 if ((j & 3) != 0) { 1172 latch = latch << ((4 - (i & 3)) << 3); 1173 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1174 SM502_DATAPORT, be32toh(latch)); 1175 } 1176 if (pad) 1177 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1178 SM502_DATAPORT, 0); 1179 } 1180 if (rv == GC_ADD) { 1181 glyphcache_add(&sc->sc_gc, c, x, y); 1182 } 1183 } 1184 1185 static void 1186 voyagerfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1187 { 1188 struct rasops_info *ri = cookie; 1189 struct vcons_screen *scr = ri->ri_hw; 1190 struct voyagerfb_softc *sc = scr->scr_cookie; 1191 int32_t xs, xd, y, width, height; 1192 1193 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1194 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1195 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1196 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1197 width = ri->ri_font->fontwidth * ncols; 1198 height = ri->ri_font->fontheight; 1199 voyagerfb_bitblt(sc, xs, y, xd, y, width, height, ROP_COPY); 1200 } 1201 } 1202 1203 static void 1204 voyagerfb_erasecols(void *cookie, int row, int startcol, int ncols, 1205 long fillattr) 1206 { 1207 struct rasops_info *ri = cookie; 1208 struct vcons_screen *scr = ri->ri_hw; 1209 struct voyagerfb_softc *sc = scr->scr_cookie; 1210 int32_t x, y, width, height, fg, bg, ul; 1211 1212 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1213 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1214 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1215 width = ri->ri_font->fontwidth * ncols; 1216 height = ri->ri_font->fontheight; 1217 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1218 1219 voyagerfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1220 } 1221 } 1222 1223 static void 1224 voyagerfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1225 { 1226 struct rasops_info *ri = cookie; 1227 struct vcons_screen *scr = ri->ri_hw; 1228 struct voyagerfb_softc *sc = scr->scr_cookie; 1229 int32_t x, ys, yd, width, height; 1230 int i; 1231 1232 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1233 x = ri->ri_xorigin; 1234 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1235 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1236 width = ri->ri_emuwidth; 1237 height = ri->ri_font->fontheight * nrows; 1238 if ((nrows > 1) && (dstrow > srcrow)) { 1239 /* 1240 * the blitter can't do bottom-up copies so we have 1241 * to copy line by line here 1242 * should probably use a command sequence 1243 */ 1244 ys += (height - ri->ri_font->fontheight); 1245 yd += (height - ri->ri_font->fontheight); 1246 for (i = 0; i < nrows; i++) { 1247 voyagerfb_bitblt(sc, x, ys, x, yd, width, 1248 ri->ri_font->fontheight, ROP_COPY); 1249 ys -= ri->ri_font->fontheight; 1250 yd -= ri->ri_font->fontheight; 1251 } 1252 } else 1253 voyagerfb_bitblt(sc, x, ys, x, yd, width, height, 1254 ROP_COPY); 1255 } 1256 } 1257 1258 static void 1259 voyagerfb_eraserows(void *cookie, int row, int nrows, long fillattr) 1260 { 1261 struct rasops_info *ri = cookie; 1262 struct vcons_screen *scr = ri->ri_hw; 1263 struct voyagerfb_softc *sc = scr->scr_cookie; 1264 int32_t x, y, width, height, fg, bg, ul; 1265 1266 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1267 x = ri->ri_xorigin; 1268 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1269 width = ri->ri_emuwidth; 1270 height = ri->ri_font->fontheight * nrows; 1271 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1272 1273 voyagerfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1274 } 1275 } 1276 1277 /* backlight control */ 1278 static void 1279 voyagerfb_setup_backlight(struct voyagerfb_softc *sc) 1280 { 1281 /* switch the pin to gpio mode if it isn't already */ 1282 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0); 1283 /* turn it on */ 1284 voyager_write_gpio(sc->sc_gpio_cookie, 0xffffffff, GPIO_BACKLIGHT); 1285 sc->sc_bl_on = 1; 1286 sc->sc_bl_level = 255; 1287 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_UP, 1288 voyagerfb_brightness_up, TRUE); 1289 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_DOWN, 1290 voyagerfb_brightness_down, TRUE); 1291 } 1292 1293 static void 1294 voyagerfb_set_backlight(struct voyagerfb_softc *sc, int level) 1295 { 1296 1297 /* 1298 * should we do nothing when backlight is off, should we just store the 1299 * level and use it when turning back on or should we just flip sc_bl_on 1300 * and turn the backlight on? 1301 * For now turn it on so a crashed screensaver can't get the user stuck 1302 * with a dark screen as long as hotkeys work 1303 */ 1304 if (level > 255) level = 255; 1305 if (level < 0) level = 0; 1306 if (level == sc->sc_bl_level) 1307 return; 1308 sc->sc_bl_level = level; 1309 if (sc->sc_bl_on == 0) 1310 sc->sc_bl_on = 1; 1311 /* and here we would actually muck with the hardware */ 1312 if ((level == 0) || (level == 255)) { 1313 /* in these cases bypass the PWM and use the gpio */ 1314 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0); 1315 if (level == 0) { 1316 voyager_write_gpio(sc->sc_gpio_cookie, 1317 ~GPIO_BACKLIGHT, 0); 1318 } else { 1319 voyager_write_gpio(sc->sc_gpio_cookie, 1320 0xffffffff, GPIO_BACKLIGHT); 1321 } 1322 } else { 1323 uint32_t pwm; 1324 1325 pwm = voyager_set_pwm(20000, level * 1000 / 256); 1326 pwm |= SM502_PWM_ENABLE; 1327 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PWM0, pwm); 1328 1329 /* let the PWM take over */ 1330 voyager_control_gpio(sc->sc_gpio_cookie, 1331 0xffffffff, GPIO_BACKLIGHT); 1332 } 1333 } 1334 1335 static void 1336 voyagerfb_switch_backlight(struct voyagerfb_softc *sc, int on) 1337 { 1338 1339 if (on == sc->sc_bl_on) 1340 return; 1341 sc->sc_bl_on = on; 1342 if (on) { 1343 int level = sc->sc_bl_level; 1344 1345 sc->sc_bl_level = -1; 1346 voyagerfb_set_backlight(sc, level); 1347 } else { 1348 voyager_control_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0); 1349 voyager_write_gpio(sc->sc_gpio_cookie, ~GPIO_BACKLIGHT, 0); 1350 } 1351 } 1352 1353 1354 static void 1355 voyagerfb_brightness_up(device_t dev) 1356 { 1357 struct voyagerfb_softc *sc = device_private(dev); 1358 1359 voyagerfb_set_backlight(sc, sc->sc_bl_level + 8); 1360 } 1361 1362 static void 1363 voyagerfb_brightness_down(device_t dev) 1364 { 1365 struct voyagerfb_softc *sc = device_private(dev); 1366 1367 voyagerfb_set_backlight(sc, sc->sc_bl_level - 8); 1368 } 1369 1370 static int 1371 voyagerfb_set_curpos(struct voyagerfb_softc *sc, int x, int y) 1372 { 1373 uint32_t val; 1374 int xx, yy; 1375 1376 sc->sc_cur_x = x; 1377 sc->sc_cur_y = y; 1378 1379 xx = x - sc->sc_hot_x; 1380 yy = y - sc->sc_hot_y; 1381 1382 if (xx < 0) xx = abs(xx) | 0x800; 1383 if (yy < 0) yy = abs(yy) | 0x800; 1384 1385 val = (xx & 0xffff) | (yy << 16); 1386 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_CRSR_XY, val); 1387 1388 return 0; 1389 } 1390 1391 static int 1392 voyagerfb_gcursor(struct voyagerfb_softc *sc, struct wsdisplay_cursor *cur) 1393 { 1394 /* do nothing for now */ 1395 return 0; 1396 } 1397 1398 static int 1399 voyagerfb_scursor(struct voyagerfb_softc *sc, struct wsdisplay_cursor *cur) 1400 { 1401 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 1402 1403 bus_space_write_4(sc->sc_memt, sc->sc_regh, 1404 SM502_PANEL_CRSR_ADDR, 1405 sc->sc_cursor_addr | (cur->enable ? SM502_CRSR_ENABLE : 0)); 1406 DPRINTF("%s: %08x\n", __func__, sc->sc_cursor_addr); 1407 } 1408 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 1409 1410 sc->sc_hot_x = cur->hot.x; 1411 sc->sc_hot_y = cur->hot.y; 1412 } 1413 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 1414 1415 voyagerfb_set_curpos(sc, cur->pos.x, cur->pos.y); 1416 } 1417 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 1418 int i, idx; 1419 uint32_t val; 1420 1421 for (i = 0; i < cur->cmap.count; i++) { 1422 val = ((cur->cmap.red[i] & 0xf8) << 8) | 1423 ((cur->cmap.green[i] & 0xfc) << 3) | 1424 ((cur->cmap.blue[i] & 0xf8) >> 3); 1425 idx = i + cur->cmap.index; 1426 bus_space_write_2(sc->sc_memt, sc->sc_regh, 1427 SM502_PANEL_CRSR_COL12 + (idx << 1), 1428 val); 1429 /* 1430 * if userland doesn't try to set the 3rd colour we 1431 * assume it expects an X11-style 2 colour cursor 1432 * X should be our main user anyway 1433 */ 1434 if ((idx == 1) && 1435 ((cur->cmap.count + cur->cmap.index) < 3)) { 1436 bus_space_write_2(sc->sc_memt, sc->sc_regh, 1437 SM502_PANEL_CRSR_COL3, 1438 val); 1439 } 1440 DPRINTF("%s: %d %04x\n", __func__, i + cur->cmap.index, 1441 val); 1442 } 1443 } 1444 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 1445 1446 int i, j, cnt = 0; 1447 uint32_t latch = 0, omask; 1448 uint8_t imask; 1449 DPRINTF("%s: %d %d\n", __func__, cur->size.x, cur->size.y); 1450 for (i = 0; i < 256; i++) { 1451 omask = 0x00000001; 1452 imask = 0x01; 1453 cur->image[cnt] &= cur->mask[cnt]; 1454 for (j = 0; j < 8; j++) { 1455 if (cur->mask[cnt] & imask) 1456 latch |= omask; 1457 omask <<= 1; 1458 if (cur->image[cnt] & imask) 1459 latch |= omask; 1460 omask <<= 1; 1461 imask <<= 1; 1462 } 1463 cnt++; 1464 imask = 0x01; 1465 cur->image[cnt] &= cur->mask[cnt]; 1466 for (j = 0; j < 8; j++) { 1467 if (cur->mask[cnt] & imask) 1468 latch |= omask; 1469 omask <<= 1; 1470 if (cur->image[cnt] & imask) 1471 latch |= omask; 1472 omask <<= 1; 1473 imask <<= 1; 1474 } 1475 cnt++; 1476 sc->sc_cursor[i] = latch; 1477 latch = 0; 1478 } 1479 } 1480 return 0; 1481 } 1482