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