1 /* $NetBSD: r128fb.c,v 1.42 2020/05/21 22:55:48 macallan Exp $ */ 2 3 /* 4 * Copyright (c) 2007, 2012 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 ATI Rage 128 graphics controllers 30 * tested on macppc only so far 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: r128fb.c,v 1.42 2020/05/21 22:55:48 macallan 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/pci/pcivar.h> 45 #include <dev/pci/pcireg.h> 46 #include <dev/pci/pcidevs.h> 47 #include <dev/pci/pciio.h> 48 #include <dev/pci/r128fbreg.h> 49 50 #include <dev/wscons/wsdisplayvar.h> 51 #include <dev/wscons/wsconsio.h> 52 #include <dev/wsfont/wsfont.h> 53 #include <dev/rasops/rasops.h> 54 #include <dev/wscons/wsdisplay_vconsvar.h> 55 #include <dev/pci/wsdisplay_pci.h> 56 #include <dev/wscons/wsdisplay_glyphcachevar.h> 57 58 #include "opt_r128fb.h" 59 #include "opt_vcons.h" 60 61 #ifdef R128FB_DEBUG 62 #define DPRINTF printf 63 #else 64 #define DPRINTF while(0) printf 65 #endif 66 67 struct r128fb_softc { 68 device_t sc_dev; 69 70 pci_chipset_tag_t sc_pc; 71 pcitag_t sc_pcitag; 72 73 bus_space_tag_t sc_memt; 74 bus_space_tag_t sc_iot; 75 76 bus_space_handle_t sc_regh; 77 bus_addr_t sc_fb, sc_reg; 78 bus_size_t sc_fbsize, sc_regsize; 79 80 int sc_width, sc_height, sc_depth, sc_stride; 81 int sc_locked, sc_have_backlight, sc_bl_level, sc_bl_on; 82 struct vcons_screen sc_console_screen; 83 struct wsscreen_descr sc_defaultscreen_descr; 84 const struct wsscreen_descr *sc_screens[1]; 85 struct wsscreen_list sc_screenlist; 86 struct vcons_data vd; 87 int sc_mode; 88 u_char sc_cmap_red[256]; 89 u_char sc_cmap_green[256]; 90 u_char sc_cmap_blue[256]; 91 /* engine stuff */ 92 uint32_t sc_master_cntl; 93 glyphcache sc_gc; 94 }; 95 96 static int r128fb_match(device_t, cfdata_t, void *); 97 static void r128fb_attach(device_t, device_t, void *); 98 99 CFATTACH_DECL_NEW(r128fb, sizeof(struct r128fb_softc), 100 r128fb_match, r128fb_attach, NULL, NULL); 101 102 static int r128fb_ioctl(void *, void *, u_long, void *, int, 103 struct lwp *); 104 static paddr_t r128fb_mmap(void *, void *, off_t, int); 105 static void r128fb_init_screen(void *, struct vcons_screen *, int, long *); 106 107 static int r128fb_putcmap(struct r128fb_softc *, struct wsdisplay_cmap *); 108 static int r128fb_getcmap(struct r128fb_softc *, struct wsdisplay_cmap *); 109 static void r128fb_restore_palette(struct r128fb_softc *); 110 static int r128fb_putpalreg(struct r128fb_softc *, uint8_t, uint8_t, 111 uint8_t, uint8_t); 112 113 static void r128fb_init(struct r128fb_softc *); 114 static void r128fb_flush_engine(struct r128fb_softc *); 115 static void r128fb_rectfill(struct r128fb_softc *, int, int, int, int, 116 uint32_t); 117 static void r128fb_bitblt(void *, int, int, int, int, int, 118 int, int); 119 120 static void r128fb_cursor(void *, int, int, int); 121 static void r128fb_putchar(void *, int, int, u_int, long); 122 static void r128fb_putchar_aa(void *, int, int, u_int, long); 123 static void r128fb_copycols(void *, int, int, int, int); 124 static void r128fb_erasecols(void *, int, int, int, long); 125 static void r128fb_copyrows(void *, int, int, int); 126 static void r128fb_eraserows(void *, int, int, long); 127 128 static void r128fb_brightness_up(device_t); 129 static void r128fb_brightness_down(device_t); 130 /* set backlight level */ 131 static void r128fb_set_backlight(struct r128fb_softc *, int); 132 /* turn backlight on and off without messing with the level */ 133 static void r128fb_switch_backlight(struct r128fb_softc *, int); 134 135 struct wsdisplay_accessops r128fb_accessops = { 136 r128fb_ioctl, 137 r128fb_mmap, 138 NULL, /* alloc_screen */ 139 NULL, /* free_screen */ 140 NULL, /* show_screen */ 141 NULL, /* load_font */ 142 NULL, /* pollc */ 143 NULL /* scroll */ 144 }; 145 146 static inline void 147 r128fb_wait(struct r128fb_softc *sc, int slots) 148 { 149 uint32_t reg; 150 151 do { 152 reg = (bus_space_read_4(sc->sc_memt, sc->sc_regh, 153 R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK); 154 } while (reg <= slots); 155 } 156 157 static void 158 r128fb_flush_engine(struct r128fb_softc *sc) 159 { 160 uint32_t reg; 161 162 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, R128_PC_NGUI_CTLSTAT); 163 reg |= R128_PC_FLUSH_ALL; 164 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_PC_NGUI_CTLSTAT, reg); 165 do { 166 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, 167 R128_PC_NGUI_CTLSTAT); 168 } while (reg & R128_PC_BUSY); 169 } 170 171 static int 172 r128fb_match(device_t parent, cfdata_t match, void *aux) 173 { 174 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 175 176 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY) 177 return 0; 178 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_ATI) 179 return 0; 180 181 /* only cards tested on so far - likely need a list */ 182 if ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_RAGE1AGP4XT) || 183 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_RAGE3AGP4XT) || 184 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_RAGEGLPCI) || 185 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_RAGE_MOB_M3_AGP)) 186 return 100; 187 return (0); 188 } 189 190 static void 191 r128fb_attach(device_t parent, device_t self, void *aux) 192 { 193 struct r128fb_softc *sc = device_private(self); 194 struct pci_attach_args *pa = aux; 195 struct rasops_info *ri; 196 bus_space_tag_t tag; 197 struct wsemuldisplaydev_attach_args aa; 198 prop_dictionary_t dict; 199 unsigned long defattr; 200 bool is_console = FALSE; 201 int i, j; 202 uint32_t reg, flags; 203 uint8_t cmap[768]; 204 205 sc->sc_pc = pa->pa_pc; 206 sc->sc_pcitag = pa->pa_tag; 207 sc->sc_memt = pa->pa_memt; 208 sc->sc_iot = pa->pa_iot; 209 sc->sc_dev = self; 210 211 pci_aprint_devinfo(pa, NULL); 212 213 /* fill in parameters from properties */ 214 dict = device_properties(self); 215 if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) { 216 aprint_error("%s: no width property\n", device_xname(self)); 217 return; 218 } 219 if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) { 220 aprint_error("%s: no height property\n", device_xname(self)); 221 return; 222 } 223 224 #ifdef GLYPHCACHE_DEBUG 225 /* leave some visible VRAM unused so we can see the glyph cache */ 226 sc->sc_height -= 200; 227 #endif 228 229 if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) { 230 aprint_error("%s: no depth property\n", device_xname(self)); 231 return; 232 } 233 if (!prop_dictionary_get_uint32(dict, "linebytes", &sc->sc_stride)) { 234 aprint_error("%s: no linebytes property\n", 235 device_xname(self)); 236 return; 237 } 238 239 prop_dictionary_get_bool(dict, "is_console", &is_console); 240 241 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, 0x10, PCI_MAPREG_TYPE_MEM, 242 &sc->sc_fb, &sc->sc_fbsize, &flags)) { 243 aprint_error("%s: failed to map the frame buffer.\n", 244 device_xname(sc->sc_dev)); 245 } 246 247 if (pci_mapreg_map(pa, 0x18, PCI_MAPREG_TYPE_MEM, 0, 248 &tag, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) { 249 aprint_error("%s: failed to map registers.\n", 250 device_xname(sc->sc_dev)); 251 } 252 253 aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self), 254 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb); 255 256 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 257 "default", 258 0, 0, 259 NULL, 260 8, 16, 261 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 262 WSSCREEN_RESIZE, 263 NULL 264 }; 265 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 266 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 267 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 268 sc->sc_locked = 0; 269 270 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 271 &r128fb_accessops); 272 sc->vd.init_screen = r128fb_init_screen; 273 sc->vd.show_screen_cookie = &sc->sc_gc; 274 sc->vd.show_screen_cb = glyphcache_adapt; 275 276 /* init engine here */ 277 r128fb_init(sc); 278 279 ri = &sc->sc_console_screen.scr_ri; 280 281 sc->sc_gc.gc_bitblt = r128fb_bitblt; 282 sc->sc_gc.gc_blitcookie = sc; 283 sc->sc_gc.gc_rop = R128_ROP3_S; 284 if (is_console) { 285 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 286 &defattr); 287 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 288 289 r128fb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 290 ri->ri_devcmap[(defattr >> 16) & 0xff]); 291 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 292 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 293 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 294 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 295 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 296 (0x800000 / sc->sc_stride) - sc->sc_height - 5, 297 sc->sc_width, 298 ri->ri_font->fontwidth, 299 ri->ri_font->fontheight, 300 defattr); 301 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 302 defattr); 303 vcons_replay_msgbuf(&sc->sc_console_screen); 304 } else { 305 /* 306 * since we're not the console we can postpone the rest 307 * until someone actually allocates a screen for us 308 */ 309 if (sc->sc_console_screen.scr_ri.ri_rows == 0) { 310 /* do some minimal setup to avoid weirdnesses later */ 311 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 312 &defattr); 313 } else 314 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 315 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 316 (0x800000 / sc->sc_stride) - sc->sc_height - 5, 317 sc->sc_width, 318 ri->ri_font->fontwidth, 319 ri->ri_font->fontheight, 320 defattr); 321 } 322 323 j = 0; 324 rasops_get_cmap(ri, cmap, sizeof(cmap)); 325 for (i = 0; i < 256; i++) { 326 sc->sc_cmap_red[i] = cmap[j]; 327 sc->sc_cmap_green[i] = cmap[j + 1]; 328 sc->sc_cmap_blue[i] = cmap[j + 2]; 329 r128fb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]); 330 j += 3; 331 } 332 333 /* no suspend/resume support yet */ 334 if (!pmf_device_register(sc->sc_dev, NULL, NULL)) 335 aprint_error_dev(sc->sc_dev, 336 "couldn't establish power handler\n"); 337 338 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, R128_LVDS_GEN_CNTL); 339 DPRINTF("R128_LVDS_GEN_CNTL: %08x\n", reg); 340 if (reg & R128_LVDS_ON) { 341 sc->sc_have_backlight = 1; 342 sc->sc_bl_on = 1; 343 sc->sc_bl_level = 255 - 344 ((reg & R128_LEVEL_MASK) >> R128_LEVEL_SHIFT); 345 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_UP, 346 r128fb_brightness_up, TRUE); 347 pmf_event_register(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_DOWN, 348 r128fb_brightness_down, TRUE); 349 aprint_verbose("%s: LVDS output is active, enabling backlight" 350 " control\n", device_xname(self)); 351 } else 352 sc->sc_have_backlight = 0; 353 354 aa.console = is_console; 355 aa.scrdata = &sc->sc_screenlist; 356 aa.accessops = &r128fb_accessops; 357 aa.accesscookie = &sc->vd; 358 359 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint); 360 } 361 362 static int 363 r128fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 364 struct lwp *l) 365 { 366 struct vcons_data *vd = v; 367 struct r128fb_softc *sc = vd->cookie; 368 struct wsdisplay_fbinfo *wdf; 369 struct vcons_screen *ms = vd->active; 370 struct wsdisplay_param *param; 371 372 switch (cmd) { 373 case WSDISPLAYIO_GTYPE: 374 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 375 return 0; 376 377 /* PCI config read/write passthrough. */ 378 case PCI_IOC_CFGREAD: 379 case PCI_IOC_CFGWRITE: 380 return pci_devioctl(sc->sc_pc, sc->sc_pcitag, 381 cmd, data, flag, l); 382 383 case WSDISPLAYIO_GET_BUSID: 384 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, 385 sc->sc_pcitag, data); 386 387 case WSDISPLAYIO_GINFO: 388 if (ms == NULL) 389 return ENODEV; 390 wdf = (void *)data; 391 wdf->height = ms->scr_ri.ri_height; 392 wdf->width = ms->scr_ri.ri_width; 393 wdf->depth = ms->scr_ri.ri_depth; 394 wdf->cmsize = 256; 395 return 0; 396 397 case WSDISPLAYIO_GETCMAP: 398 return r128fb_getcmap(sc, 399 (struct wsdisplay_cmap *)data); 400 401 case WSDISPLAYIO_PUTCMAP: 402 return r128fb_putcmap(sc, 403 (struct wsdisplay_cmap *)data); 404 405 case WSDISPLAYIO_LINEBYTES: 406 *(u_int *)data = sc->sc_stride; 407 return 0; 408 409 case WSDISPLAYIO_SMODE: { 410 int new_mode = *(int*)data; 411 if (new_mode != sc->sc_mode) { 412 sc->sc_mode = new_mode; 413 if(new_mode == WSDISPLAYIO_MODE_EMUL) { 414 r128fb_init(sc); 415 r128fb_restore_palette(sc); 416 glyphcache_wipe(&sc->sc_gc); 417 r128fb_rectfill(sc, 0, 0, sc->sc_width, 418 sc->sc_height, ms->scr_ri.ri_devcmap[ 419 (ms->scr_defattr >> 16) & 0xff]); 420 vcons_redraw_screen(ms); 421 } 422 } 423 } 424 return 0; 425 426 case WSDISPLAYIO_GETPARAM: 427 param = (struct wsdisplay_param *)data; 428 if (sc->sc_have_backlight == 0) 429 return EPASSTHROUGH; 430 switch (param->param) { 431 case WSDISPLAYIO_PARAM_BRIGHTNESS: 432 param->min = 0; 433 param->max = 255; 434 param->curval = sc->sc_bl_level; 435 return 0; 436 case WSDISPLAYIO_PARAM_BACKLIGHT: 437 param->min = 0; 438 param->max = 1; 439 param->curval = sc->sc_bl_on; 440 return 0; 441 } 442 return EPASSTHROUGH; 443 444 case WSDISPLAYIO_SETPARAM: 445 param = (struct wsdisplay_param *)data; 446 if (sc->sc_have_backlight == 0) 447 return EPASSTHROUGH; 448 switch (param->param) { 449 case WSDISPLAYIO_PARAM_BRIGHTNESS: 450 r128fb_set_backlight(sc, param->curval); 451 return 0; 452 case WSDISPLAYIO_PARAM_BACKLIGHT: 453 r128fb_switch_backlight(sc, param->curval); 454 return 0; 455 } 456 return EPASSTHROUGH; 457 458 case WSDISPLAYIO_GET_EDID: { 459 struct wsdisplayio_edid_info *d = data; 460 return wsdisplayio_get_edid(sc->sc_dev, d); 461 } 462 463 case WSDISPLAYIO_GET_FBINFO: 464 { 465 struct wsdisplayio_fbinfo *fbi = data; 466 467 return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 468 } 469 } 470 return EPASSTHROUGH; 471 } 472 473 static paddr_t 474 r128fb_mmap(void *v, void *vs, off_t offset, int prot) 475 { 476 struct vcons_data *vd = v; 477 struct r128fb_softc *sc = vd->cookie; 478 paddr_t pa; 479 480 /* 'regular' framebuffer mmap()ing */ 481 if (offset < sc->sc_fbsize) { 482 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset, 0, prot, 483 BUS_SPACE_MAP_LINEAR); 484 return pa; 485 } 486 487 /* 488 * restrict all other mappings to processes with superuser privileges 489 * or the kernel itself 490 */ 491 if (kauth_authorize_machdep(kauth_cred_get(), KAUTH_MACHDEP_UNMANAGEDMEM, 492 NULL, NULL, NULL, NULL) != 0) { 493 aprint_normal("%s: mmap() rejected.\n", 494 device_xname(sc->sc_dev)); 495 return -1; 496 } 497 498 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) { 499 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 500 BUS_SPACE_MAP_LINEAR); 501 return pa; 502 } 503 504 if ((offset >= sc->sc_reg) && 505 (offset < (sc->sc_reg + sc->sc_regsize))) { 506 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 507 BUS_SPACE_MAP_LINEAR); 508 return pa; 509 } 510 511 #ifdef PCI_MAGIC_IO_RANGE 512 /* allow mapping of IO space */ 513 if ((offset >= PCI_MAGIC_IO_RANGE) && 514 (offset < PCI_MAGIC_IO_RANGE + 0x10000)) { 515 pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE, 516 0, prot, BUS_SPACE_MAP_LINEAR); 517 return pa; 518 } 519 #endif 520 521 #ifdef OFB_ALLOW_OTHERS 522 if (offset >= 0x80000000) { 523 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot, 524 BUS_SPACE_MAP_LINEAR); 525 return pa; 526 } 527 #endif 528 return -1; 529 } 530 531 static void 532 r128fb_init_screen(void *cookie, struct vcons_screen *scr, 533 int existing, long *defattr) 534 { 535 struct r128fb_softc *sc = cookie; 536 struct rasops_info *ri = &scr->scr_ri; 537 538 ri->ri_depth = sc->sc_depth; 539 ri->ri_width = sc->sc_width; 540 ri->ri_height = sc->sc_height; 541 ri->ri_stride = sc->sc_stride; 542 ri->ri_flg = RI_CENTER; 543 if (sc->sc_depth == 8) 544 ri->ri_flg |= RI_8BIT_IS_RGB | RI_ENABLE_ALPHA | 545 RI_PREFER_ALPHA; 546 547 rasops_init(ri, 0, 0); 548 ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE | 549 WSSCREEN_RESIZE; 550 #ifdef VCONS_DRAW_INTR 551 scr->scr_flags |= VCONS_DONT_READ; 552 #endif 553 scr->scr_flags |= VCONS_LOADFONT; 554 555 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 556 sc->sc_width / ri->ri_font->fontwidth); 557 558 ri->ri_hw = scr; 559 ri->ri_ops.copyrows = r128fb_copyrows; 560 ri->ri_ops.copycols = r128fb_copycols; 561 ri->ri_ops.eraserows = r128fb_eraserows; 562 ri->ri_ops.erasecols = r128fb_erasecols; 563 ri->ri_ops.cursor = r128fb_cursor; 564 if (FONT_IS_ALPHA(ri->ri_font)) { 565 ri->ri_ops.putchar = r128fb_putchar_aa; 566 } else 567 ri->ri_ops.putchar = r128fb_putchar; 568 } 569 570 static int 571 r128fb_putcmap(struct r128fb_softc *sc, struct wsdisplay_cmap *cm) 572 { 573 u_char *r, *g, *b; 574 u_int index = cm->index; 575 u_int count = cm->count; 576 int i, error; 577 u_char rbuf[256], gbuf[256], bbuf[256]; 578 579 #ifdef R128FB_DEBUG 580 aprint_debug("putcmap: %d %d\n",index, count); 581 #endif 582 if (cm->index >= 256 || cm->count > 256 || 583 (cm->index + cm->count) > 256) 584 return EINVAL; 585 error = copyin(cm->red, &rbuf[index], count); 586 if (error) 587 return error; 588 error = copyin(cm->green, &gbuf[index], count); 589 if (error) 590 return error; 591 error = copyin(cm->blue, &bbuf[index], count); 592 if (error) 593 return error; 594 595 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); 596 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); 597 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); 598 599 r = &sc->sc_cmap_red[index]; 600 g = &sc->sc_cmap_green[index]; 601 b = &sc->sc_cmap_blue[index]; 602 603 for (i = 0; i < count; i++) { 604 r128fb_putpalreg(sc, index, *r, *g, *b); 605 index++; 606 r++, g++, b++; 607 } 608 return 0; 609 } 610 611 static int 612 r128fb_getcmap(struct r128fb_softc *sc, struct wsdisplay_cmap *cm) 613 { 614 u_int index = cm->index; 615 u_int count = cm->count; 616 int error; 617 618 if (index >= 255 || count > 256 || index + count > 256) 619 return EINVAL; 620 621 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 622 if (error) 623 return error; 624 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 625 if (error) 626 return error; 627 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 628 if (error) 629 return error; 630 631 return 0; 632 } 633 634 static void 635 r128fb_restore_palette(struct r128fb_softc *sc) 636 { 637 int i; 638 639 for (i = 0; i < (1 << sc->sc_depth); i++) { 640 r128fb_putpalreg(sc, i, sc->sc_cmap_red[i], 641 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]); 642 } 643 } 644 645 static int 646 r128fb_putpalreg(struct r128fb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, 647 uint8_t b) 648 { 649 uint32_t reg; 650 651 /* whack the DAC */ 652 reg = (r << 16) | (g << 8) | b; 653 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_PALETTE_INDEX, idx); 654 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_PALETTE_DATA, reg); 655 return 0; 656 } 657 658 static void 659 r128fb_init(struct r128fb_softc *sc) 660 { 661 uint32_t datatype, d, reg; 662 663 r128fb_flush_engine(sc); 664 665 r128fb_wait(sc, 9); 666 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_CRTC_OFFSET, 0); 667 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DEFAULT_OFFSET, 0); 668 /* pitch is in units of 8 pixels */ 669 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DEFAULT_PITCH, 670 sc->sc_width >> 3); 671 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_AUX_SC_CNTL, 0); 672 bus_space_write_4(sc->sc_memt, sc->sc_regh, 673 R128_DEFAULT_SC_BOTTOM_RIGHT, 674 R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX); 675 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SC_TOP_LEFT, 0); 676 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SC_BOTTOM_RIGHT, 677 R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX); 678 bus_space_write_4(sc->sc_memt, sc->sc_regh, 679 R128_DEFAULT_SC_BOTTOM_RIGHT, 680 R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX); 681 682 #if 0 683 #if BYTE_ORDER == BIG_ENDIAN 684 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_DATATYPE, 685 R128_HOST_BIG_ENDIAN_EN); 686 #else 687 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_DATATYPE, 0); 688 #endif 689 #endif 690 r128fb_wait(sc, 7); 691 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SRC_PITCH, 692 sc->sc_width >> 3); 693 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_PITCH, 694 sc->sc_width >> 3); 695 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SRC_OFFSET, 0); 696 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_OFFSET, 0); 697 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_WRITE_MASK, 698 0xffffffff); 699 700 switch (sc->sc_depth) { 701 case 8: 702 datatype = R128_GMC_DST_8BPP_CI; 703 d = R128_CRTC_COLOR_8BIT; 704 break; 705 case 15: 706 datatype = R128_GMC_DST_15BPP; 707 d = R128_CRTC_COLOR_15BIT; 708 break; 709 case 16: 710 datatype = R128_GMC_DST_16BPP; 711 d = R128_CRTC_COLOR_16BIT; 712 break; 713 case 24: 714 datatype = R128_GMC_DST_24BPP; 715 d = R128_CRTC_COLOR_24BIT; 716 break; 717 case 32: 718 datatype = R128_GMC_DST_32BPP; 719 d = R128_CRTC_COLOR_32BIT; 720 break; 721 default: 722 aprint_error("%s: unsupported depth %d\n", 723 device_xname(sc->sc_dev), sc->sc_depth); 724 return; 725 } 726 sc->sc_master_cntl = R128_GMC_CLR_CMP_CNTL_DIS | 727 R128_GMC_AUX_CLIP_DIS | datatype; 728 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, R128_CRTC_GEN_CNTL); 729 DPRINTF("depth: %d\n", reg & R128_CRTC_PIX_WIDTH); 730 reg &= ~R128_CRTC_PIX_WIDTH; 731 reg |= d; 732 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_CRTC_GEN_CNTL, reg); 733 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_CRTC_PITCH, sc->sc_width >> 3); 734 r128fb_flush_engine(sc); 735 } 736 737 static void 738 r128fb_rectfill(struct r128fb_softc *sc, int x, int y, int wi, int he, 739 uint32_t colour) 740 { 741 742 r128fb_wait(sc, 5); 743 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_GUI_MASTER_CNTL, 744 R128_GMC_BRUSH_SOLID_COLOR | 745 R128_GMC_SRC_DATATYPE_COLOR | 746 R128_ROP3_P | 747 sc->sc_master_cntl); 748 749 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_BRUSH_FRGD_CLR, 750 colour); 751 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_CNTL, 752 R128_DST_X_LEFT_TO_RIGHT | R128_DST_Y_TOP_TO_BOTTOM); 753 /* now feed it coordinates */ 754 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_X_Y, 755 (x << 16) | y); 756 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_WIDTH_HEIGHT, 757 (wi << 16) | he); 758 } 759 760 static void 761 r128fb_bitblt(void *cookie, int xs, int ys, int xd, int yd, 762 int wi, int he, int rop) 763 { 764 struct r128fb_softc *sc = cookie; 765 uint32_t dp_cntl = 0; 766 767 r128fb_wait(sc, 5); 768 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_GUI_MASTER_CNTL, 769 R128_GMC_BRUSH_SOLID_COLOR | 770 R128_GMC_SRC_DATATYPE_COLOR | 771 rop | 772 R128_DP_SRC_SOURCE_MEMORY | 773 sc->sc_master_cntl); 774 775 if (yd <= ys) { 776 dp_cntl = R128_DST_Y_TOP_TO_BOTTOM; 777 } else { 778 ys += he - 1; 779 yd += he - 1; 780 } 781 if (xd <= xs) { 782 dp_cntl |= R128_DST_X_LEFT_TO_RIGHT; 783 } else { 784 xs += wi - 1; 785 xd += wi - 1; 786 } 787 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DP_CNTL, dp_cntl); 788 789 /* now feed it coordinates */ 790 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SRC_X_Y, 791 (xs << 16) | ys); 792 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_X_Y, 793 (xd << 16) | yd); 794 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_WIDTH_HEIGHT, 795 (wi << 16) | he); 796 } 797 798 static void 799 r128fb_cursor(void *cookie, int on, int row, int col) 800 { 801 struct rasops_info *ri = cookie; 802 struct vcons_screen *scr = ri->ri_hw; 803 struct r128fb_softc *sc = scr->scr_cookie; 804 int x, y, wi, he; 805 806 wi = ri->ri_font->fontwidth; 807 he = ri->ri_font->fontheight; 808 809 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 810 if (ri->ri_flg & RI_CURSOR) { 811 x = ri->ri_ccol * wi + ri->ri_xorigin; 812 y = ri->ri_crow * he + ri->ri_yorigin; 813 r128fb_bitblt(sc, x, y, x, y, wi, he, R128_ROP3_Dn); 814 ri->ri_flg &= ~RI_CURSOR; 815 } 816 ri->ri_crow = row; 817 ri->ri_ccol = col; 818 if (on) { 819 x = ri->ri_ccol * wi + ri->ri_xorigin; 820 y = ri->ri_crow * he + ri->ri_yorigin; 821 r128fb_bitblt(sc, x, y, x, y, wi, he, R128_ROP3_Dn); 822 ri->ri_flg |= RI_CURSOR; 823 } 824 } else { 825 scr->scr_ri.ri_crow = row; 826 scr->scr_ri.ri_ccol = col; 827 scr->scr_ri.ri_flg &= ~RI_CURSOR; 828 } 829 830 } 831 832 static void 833 r128fb_putchar(void *cookie, int row, int col, u_int c, long attr) 834 { 835 struct rasops_info *ri = cookie; 836 struct wsdisplay_font *font = PICK_FONT(ri, c); 837 struct vcons_screen *scr = ri->ri_hw; 838 struct r128fb_softc *sc = scr->scr_cookie; 839 void *data; 840 uint32_t fg, bg; 841 int i, x, y, wi, he, offset; 842 843 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 844 return; 845 846 if (!CHAR_IN_FONT(c, font)) 847 return; 848 849 wi = font->fontwidth; 850 he = font->fontheight; 851 852 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 853 fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 854 x = ri->ri_xorigin + col * wi; 855 y = ri->ri_yorigin + row * he; 856 857 if (c == 0x20) { 858 r128fb_rectfill(sc, x, y, wi, he, bg); 859 return; 860 } 861 862 data = WSFONT_GLYPH(c, font); 863 864 r128fb_wait(sc, 8); 865 866 bus_space_write_4(sc->sc_memt, sc->sc_regh, 867 R128_DP_GUI_MASTER_CNTL, 868 R128_GMC_BRUSH_SOLID_COLOR | 869 R128_GMC_SRC_DATATYPE_MONO_FG_BG | 870 R128_ROP3_S | 871 R128_DP_SRC_SOURCE_HOST_DATA | 872 R128_GMC_DST_CLIPPING | 873 sc->sc_master_cntl); 874 875 bus_space_write_4(sc->sc_memt, sc->sc_regh, 876 R128_DP_CNTL, 877 R128_DST_Y_TOP_TO_BOTTOM | 878 R128_DST_X_LEFT_TO_RIGHT); 879 880 bus_space_write_4(sc->sc_memt, sc->sc_regh, 881 R128_DP_SRC_FRGD_CLR, fg); 882 bus_space_write_4(sc->sc_memt, sc->sc_regh, 883 R128_DP_SRC_BKGD_CLR, bg); 884 885 /* 886 * The Rage 128 doesn't have anything to skip pixels 887 * when colour expanding but all coordinates 888 * are signed so we just clip the leading bytes and 889 * trailing bits away 890 */ 891 bus_space_write_4(sc->sc_memt, sc->sc_regh, 892 R128_SC_RIGHT, x + wi - 1); 893 bus_space_write_4(sc->sc_memt, sc->sc_regh, 894 R128_SC_LEFT, x); 895 896 /* needed? */ 897 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SRC_X_Y, 0); 898 899 offset = 32 - (font->stride << 3); 900 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_X_Y, 901 ((x - offset) << 16) | y); 902 bus_space_write_4(sc->sc_memt, sc->sc_regh, 903 R128_DST_WIDTH_HEIGHT, (32 << 16) | he); 904 905 r128fb_wait(sc, he); 906 switch (font->stride) { 907 case 1: { 908 uint8_t *data8 = data; 909 uint32_t reg; 910 for (i = 0; i < he; i++) { 911 reg = *data8; 912 bus_space_write_stream_4(sc->sc_memt, 913 sc->sc_regh, R128_HOST_DATA0, reg); 914 data8++; 915 } 916 break; 917 } 918 case 2: { 919 uint16_t *data16 = data; 920 uint32_t reg; 921 for (i = 0; i < he; i++) { 922 reg = *data16; 923 bus_space_write_stream_4(sc->sc_memt, 924 sc->sc_regh, R128_HOST_DATA0, reg); 925 data16++; 926 } 927 break; 928 } 929 } 930 } 931 932 static void 933 r128fb_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 934 { 935 struct rasops_info *ri = cookie; 936 struct wsdisplay_font *font = PICK_FONT(ri, c); 937 struct vcons_screen *scr = ri->ri_hw; 938 struct r128fb_softc *sc = scr->scr_cookie; 939 uint32_t bg, latch = 0, bg8, fg8, pixel; 940 int i, x, y, wi, he, r, g, b, aval; 941 int r1, g1, b1, r0, g0, b0, fgo, bgo; 942 uint8_t *data8; 943 int rv, cnt = 0; 944 945 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 946 return; 947 948 if (!CHAR_IN_FONT(c, font)) 949 return; 950 951 wi = font->fontwidth; 952 he = font->fontheight; 953 954 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 955 x = ri->ri_xorigin + col * wi; 956 y = ri->ri_yorigin + row * he; 957 if (c == 0x20) { 958 r128fb_rectfill(sc, x, y, wi, he, bg); 959 return; 960 } 961 962 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 963 if (rv == GC_OK) 964 return; 965 966 data8 = WSFONT_GLYPH(c, font); 967 968 r128fb_wait(sc, 5); 969 bus_space_write_4(sc->sc_memt, sc->sc_regh, 970 R128_DP_GUI_MASTER_CNTL, 971 R128_GMC_BRUSH_SOLID_COLOR | 972 R128_GMC_SRC_DATATYPE_COLOR | 973 R128_ROP3_S | 974 R128_DP_SRC_SOURCE_HOST_DATA | 975 sc->sc_master_cntl); 976 977 bus_space_write_4(sc->sc_memt, sc->sc_regh, 978 R128_DP_CNTL, 979 R128_DST_Y_TOP_TO_BOTTOM | 980 R128_DST_X_LEFT_TO_RIGHT); 981 982 /* needed? */ 983 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_SRC_X_Y, 0); 984 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_X_Y, 985 (x << 16) | y); 986 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_DST_WIDTH_HEIGHT, 987 (wi << 16) | he); 988 989 /* 990 * we need the RGB colours here, so get offsets into rasops_cmap 991 */ 992 fgo = ((attr >> 24) & 0xf) * 3; 993 bgo = ((attr >> 16) & 0xf) * 3; 994 995 r0 = rasops_cmap[bgo]; 996 r1 = rasops_cmap[fgo]; 997 g0 = rasops_cmap[bgo + 1]; 998 g1 = rasops_cmap[fgo + 1]; 999 b0 = rasops_cmap[bgo + 2]; 1000 b1 = rasops_cmap[fgo + 2]; 1001 #define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)) 1002 bg8 = R3G3B2(r0, g0, b0); 1003 fg8 = R3G3B2(r1, g1, b1); 1004 1005 r128fb_wait(sc, 16); 1006 1007 for (i = 0; i < ri->ri_fontscale; i++) { 1008 aval = *data8; 1009 if (aval == 0) { 1010 pixel = bg8; 1011 } else if (aval == 255) { 1012 pixel = fg8; 1013 } else { 1014 r = aval * r1 + (255 - aval) * r0; 1015 g = aval * g1 + (255 - aval) * g0; 1016 b = aval * b1 + (255 - aval) * b0; 1017 pixel = ((r & 0xe000) >> 8) | 1018 ((g & 0xe000) >> 11) | 1019 ((b & 0xc000) >> 14); 1020 } 1021 latch = (latch << 8) | pixel; 1022 /* write in 32bit chunks */ 1023 if ((i & 3) == 3) { 1024 bus_space_write_stream_4(sc->sc_memt, sc->sc_regh, 1025 R128_HOST_DATA0, latch); 1026 /* 1027 * not strictly necessary, old data should be shifted 1028 * out 1029 */ 1030 latch = 0; 1031 cnt++; 1032 if (cnt > 15) { 1033 r128fb_wait(sc, 16); 1034 cnt = 0; 1035 } 1036 } 1037 data8++; 1038 } 1039 /* if we have pixels left in latch write them out */ 1040 if ((i & 3) != 0) { 1041 latch = latch << ((4 - (i & 3)) << 3); 1042 bus_space_write_stream_4(sc->sc_memt, sc->sc_regh, 1043 R128_HOST_DATA0, latch); 1044 } 1045 if (rv == GC_ADD) { 1046 glyphcache_add(&sc->sc_gc, c, x, y); 1047 } 1048 } 1049 1050 static void 1051 r128fb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1052 { 1053 struct rasops_info *ri = cookie; 1054 struct vcons_screen *scr = ri->ri_hw; 1055 struct r128fb_softc *sc = scr->scr_cookie; 1056 int32_t xs, xd, y, width, height; 1057 1058 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1059 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1060 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1061 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1062 width = ri->ri_font->fontwidth * ncols; 1063 height = ri->ri_font->fontheight; 1064 r128fb_bitblt(sc, xs, y, xd, y, width, height, R128_ROP3_S); 1065 } 1066 } 1067 1068 static void 1069 r128fb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1070 { 1071 struct rasops_info *ri = cookie; 1072 struct vcons_screen *scr = ri->ri_hw; 1073 struct r128fb_softc *sc = scr->scr_cookie; 1074 int32_t x, y, width, height, fg, bg, ul; 1075 1076 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1077 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1078 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1079 width = ri->ri_font->fontwidth * ncols; 1080 height = ri->ri_font->fontheight; 1081 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1082 1083 r128fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1084 } 1085 } 1086 1087 static void 1088 r128fb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1089 { 1090 struct rasops_info *ri = cookie; 1091 struct vcons_screen *scr = ri->ri_hw; 1092 struct r128fb_softc *sc = scr->scr_cookie; 1093 int32_t x, ys, yd, width, height; 1094 1095 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1096 x = ri->ri_xorigin; 1097 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1098 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1099 width = ri->ri_emuwidth; 1100 height = ri->ri_font->fontheight * nrows; 1101 r128fb_bitblt(sc, x, ys, x, yd, width, height, R128_ROP3_S); 1102 } 1103 } 1104 1105 static void 1106 r128fb_eraserows(void *cookie, int row, int nrows, long fillattr) 1107 { 1108 struct rasops_info *ri = cookie; 1109 struct vcons_screen *scr = ri->ri_hw; 1110 struct r128fb_softc *sc = scr->scr_cookie; 1111 int32_t x, y, width, height, fg, bg, ul; 1112 1113 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { 1114 x = ri->ri_xorigin; 1115 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1116 width = ri->ri_emuwidth; 1117 height = ri->ri_font->fontheight * nrows; 1118 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 1119 1120 r128fb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); 1121 } 1122 } 1123 1124 static void 1125 r128fb_set_backlight(struct r128fb_softc *sc, int level) 1126 { 1127 uint32_t reg; 1128 1129 /* 1130 * should we do nothing when backlight is off, should we just store the 1131 * level and use it when turning back on or should we just flip sc_bl_on 1132 * and turn the backlight on? 1133 * For now turn it on so a crashed screensaver can't get the user stuck 1134 * with a dark screen as long as hotkeys work 1135 */ 1136 if (level > 255) level = 255; 1137 if (level < 0) level = 0; 1138 if (level == sc->sc_bl_level) 1139 return; 1140 sc->sc_bl_level = level; 1141 if (sc->sc_bl_on == 0) 1142 sc->sc_bl_on = 1; 1143 level = 255 - level; 1144 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, R128_LVDS_GEN_CNTL); 1145 reg &= ~R128_LEVEL_MASK; 1146 reg |= (level << R128_LEVEL_SHIFT); 1147 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_LVDS_GEN_CNTL, reg); 1148 DPRINTF("backlight level: %d reg %08x\n", level, reg); 1149 } 1150 1151 static void 1152 r128fb_switch_backlight(struct r128fb_softc *sc, int on) 1153 { 1154 uint32_t reg; 1155 int level; 1156 1157 if (on == sc->sc_bl_on) 1158 return; 1159 sc->sc_bl_on = on; 1160 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, R128_LVDS_GEN_CNTL); 1161 reg &= ~R128_LEVEL_MASK; 1162 level = on ? 255 - sc->sc_bl_level : 255; 1163 reg |= level << R128_LEVEL_SHIFT; 1164 bus_space_write_4(sc->sc_memt, sc->sc_regh, R128_LVDS_GEN_CNTL, reg); 1165 DPRINTF("backlight state: %d reg %08x\n", on, reg); 1166 } 1167 1168 1169 static void 1170 r128fb_brightness_up(device_t dev) 1171 { 1172 struct r128fb_softc *sc = device_private(dev); 1173 1174 r128fb_set_backlight(sc, sc->sc_bl_level + 8); 1175 } 1176 1177 static void 1178 r128fb_brightness_down(device_t dev) 1179 { 1180 struct r128fb_softc *sc = device_private(dev); 1181 1182 r128fb_set_backlight(sc, sc->sc_bl_level - 8); 1183 } 1184