1 /* $NetBSD: plumvideo.c,v 1.46 2025/02/26 04:49:46 andvar Exp $ */ 2 3 /*- 4 * Copyright (c) 1999-2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: plumvideo.c,v 1.46 2025/02/26 04:49:46 andvar Exp $"); 34 35 #include "plumohci.h" /* Plum2 OHCI shared memory allocated on V-RAM */ 36 #include "bivideo.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 42 #include <sys/ioctl.h> 43 #include <sys/buf.h> 44 #include <uvm/uvm_extern.h> 45 46 #include <dev/cons.h> /* consdev */ 47 48 #include <mips/cache.h> 49 50 #include <machine/bus.h> 51 #include <machine/intr.h> 52 #include <machine/config_hook.h> 53 54 #include <hpcmips/tx/tx39var.h> 55 #include <hpcmips/dev/plumvar.h> 56 #include <hpcmips/dev/plumicuvar.h> 57 #include <hpcmips/dev/plumpowervar.h> 58 #include <hpcmips/dev/plumvideoreg.h> 59 60 #include <machine/bootinfo.h> 61 62 #include <dev/wscons/wsdisplayvar.h> 63 #include <dev/rasops/rasops.h> 64 #include <dev/hpc/video_subr.h> 65 66 #include <dev/wscons/wsconsio.h> 67 #include <dev/hpc/hpcfbvar.h> 68 #include <dev/hpc/hpcfbio.h> 69 #if NBIVIDEO > 0 70 #include <dev/hpc/bivideovar.h> 71 #endif 72 73 #ifdef PLUMVIDEODEBUG 74 #define DPRINTF_ENABLE 75 #define DPRINTF_DEBUG plumvideo_debug 76 #endif 77 #include <machine/debug.h> 78 79 struct plumvideo_softc { 80 device_t sc_dev; 81 tx_chipset_tag_t sc_tc; 82 plum_chipset_tag_t sc_pc; 83 84 void *sc_powerhook; /* power management hook */ 85 int sc_console; 86 87 int sc_backlight; 88 int sc_brightness; 89 int sc_max_brightness; 90 91 /* control register */ 92 bus_space_tag_t sc_regt; 93 bus_space_handle_t sc_regh; 94 /* frame buffer */ 95 bus_space_tag_t sc_fbiot; 96 bus_space_handle_t sc_fbioh; 97 /* clut buffer (8bpp only) */ 98 bus_space_tag_t sc_clutiot; 99 bus_space_handle_t sc_clutioh; 100 /* bitblt */ 101 bus_space_tag_t sc_bitbltt; 102 bus_space_handle_t sc_bitblth; 103 104 struct video_chip sc_chip; 105 struct hpcfb_fbconf sc_fbconf; 106 struct hpcfb_dspconf sc_dspconf; 107 }; 108 109 int plumvideo_match(device_t, cfdata_t, void *); 110 void plumvideo_attach(device_t, device_t, void *); 111 112 int plumvideo_ioctl(void *, u_long, void *, int, struct lwp *); 113 paddr_t plumvideo_mmap(void *, off_t, int); 114 115 CFATTACH_DECL_NEW(plumvideo, sizeof(struct plumvideo_softc), 116 plumvideo_match, plumvideo_attach, NULL, NULL); 117 118 struct hpcfb_accessops plumvideo_ha = { 119 plumvideo_ioctl, plumvideo_mmap 120 }; 121 122 int plumvideo_power(void *, int, long, void *); 123 124 int plumvideo_init(struct plumvideo_softc *, int *); 125 void plumvideo_hpcfbinit(struct plumvideo_softc *, int); 126 127 void plumvideo_clut_default(struct plumvideo_softc *); 128 void plumvideo_clut_set(struct plumvideo_softc *, u_int32_t *, int, int); 129 void plumvideo_clut_get(struct plumvideo_softc *, u_int32_t *, int, int); 130 void __plumvideo_clut_access(struct plumvideo_softc *, u_int32_t *, int, int, 131 void (*)(bus_space_tag_t, bus_space_handle_t, u_int32_t *, int, int)); 132 static void _flush_cache(void) __attribute__((__unused__)); /* !!! */ 133 static void plumvideo_init_backlight(struct plumvideo_softc *); 134 static void plumvideo_backlight(struct plumvideo_softc *, int); 135 static void plumvideo_brightness(struct plumvideo_softc *, int); 136 137 #ifdef PLUMVIDEODEBUG 138 void plumvideo_dump(struct plumvideo_softc*); 139 #endif 140 141 #define ON 1 142 #define OFF 0 143 144 int 145 plumvideo_match(device_t parent, cfdata_t cf, void *aux) 146 { 147 /* 148 * VRAM area also uses as UHOSTC shared RAM. 149 */ 150 return (2); /* 1st attach group */ 151 } 152 153 void 154 plumvideo_attach(device_t parent, device_t self, void *aux) 155 { 156 struct plum_attach_args *pa = aux; 157 struct plumvideo_softc *sc = device_private(self); 158 struct hpcfb_attach_args ha; 159 int console, reverse_flag; 160 161 sc->sc_dev = self; 162 sc->sc_console = console = cn_tab ? 0 : 1; 163 sc->sc_pc = pa->pa_pc; 164 sc->sc_regt = pa->pa_regt; 165 sc->sc_fbiot = sc->sc_clutiot = sc->sc_bitbltt = pa->pa_iot; 166 167 printf(": "); 168 169 /* map register area */ 170 if (bus_space_map(sc->sc_regt, PLUM_VIDEO_REGBASE, 171 PLUM_VIDEO_REGSIZE, 0, &sc->sc_regh)) { 172 printf("register map failed\n"); 173 return; 174 } 175 176 /* initialize backlight and brightness values */ 177 plumvideo_init_backlight(sc); 178 179 /* power control */ 180 plumvideo_power(sc, 0, 0, 181 (void *)(console ? PWR_RESUME : PWR_SUSPEND)); 182 /* Add a hard power hook to power saving */ 183 sc->sc_powerhook = config_hook(CONFIG_HOOK_PMEVENT, 184 CONFIG_HOOK_PMEVENT_HARDPOWER, 185 CONFIG_HOOK_SHARE, 186 plumvideo_power, sc); 187 if (sc->sc_powerhook == 0) 188 printf("WARNING unable to establish hard power hook"); 189 190 /* 191 * Initialize LCD controller 192 * map V-RAM area. 193 * reinstall bootinfo structure. 194 * some OHCI shared-buffer hack. XXX 195 */ 196 if (plumvideo_init(sc, &reverse_flag) != 0) 197 return; 198 199 printf("\n"); 200 201 /* Attach frame buffer device */ 202 plumvideo_hpcfbinit(sc, reverse_flag); 203 204 #ifdef PLUMVIDEODEBUG 205 if (plumvideo_debug > 0) 206 plumvideo_dump(sc); 207 /* attach debug draw routine (debugging use) */ 208 video_attach_drawfunc(&sc->sc_chip); 209 tx_conf_register_video(sc->sc_pc->pc_tc, &sc->sc_chip); 210 #endif /* PLUMVIDEODEBUG */ 211 212 if(console && hpcfb_cnattach(&sc->sc_fbconf) != 0) { 213 panic("plumvideo_attach: can't init fb console"); 214 } 215 216 ha.ha_console = console; 217 ha.ha_accessops = &plumvideo_ha; 218 ha.ha_accessctx = sc; 219 ha.ha_curfbconf = 0; 220 ha.ha_nfbconf = 1; 221 ha.ha_fbconflist = &sc->sc_fbconf; 222 ha.ha_curdspconf = 0; 223 ha.ha_ndspconf = 1; 224 ha.ha_dspconflist = &sc->sc_dspconf; 225 226 config_found(self, &ha, hpcfbprint, CFARGS_NONE); 227 #if NBIVIDEO > 0 228 /* bivideo is no longer need */ 229 bivideo_dont_attach = 1; 230 #endif /* NBIVIDEO > 0 */ 231 } 232 233 void 234 plumvideo_hpcfbinit(struct plumvideo_softc *sc, int reverse_flag) 235 { 236 struct hpcfb_fbconf *fb = &sc->sc_fbconf; 237 struct video_chip *chip = &sc->sc_chip; 238 vaddr_t fbvaddr = (vaddr_t)sc->sc_fbioh; 239 int height = chip->vc_fbheight; 240 int width = chip->vc_fbwidth; 241 int depth = chip->vc_fbdepth; 242 243 memset(fb, 0, sizeof(struct hpcfb_fbconf)); 244 245 fb->hf_conf_index = 0; /* configuration index */ 246 fb->hf_nconfs = 1; /* how many configurations */ 247 strncpy(fb->hf_name, "PLUM built-in video", HPCFB_MAXNAMELEN); 248 /* frame buffer name */ 249 strncpy(fb->hf_conf_name, "LCD", HPCFB_MAXNAMELEN); 250 /* configuration name */ 251 fb->hf_height = height; 252 fb->hf_width = width; 253 fb->hf_baseaddr = (u_long)fbvaddr; 254 fb->hf_offset = (u_long)fbvaddr - mips_ptob(mips_btop(fbvaddr)); 255 /* frame buffer start offset */ 256 fb->hf_bytes_per_line = (width * depth) / NBBY; 257 fb->hf_nplanes = 1; 258 fb->hf_bytes_per_plane = height * fb->hf_bytes_per_line; 259 260 fb->hf_access_flags |= HPCFB_ACCESS_BYTE; 261 fb->hf_access_flags |= HPCFB_ACCESS_WORD; 262 fb->hf_access_flags |= HPCFB_ACCESS_DWORD; 263 if (reverse_flag) 264 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 265 266 switch (depth) { 267 default: 268 panic("plumvideo_hpcfbinit: not supported color depth"); 269 /* NOTREACHED */ 270 case 16: 271 fb->hf_class = HPCFB_CLASS_RGBCOLOR; 272 fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 273 fb->hf_pack_width = 16; 274 fb->hf_pixels_per_pack = 1; 275 fb->hf_pixel_width = 16; 276 277 fb->hf_class_data_length = sizeof(struct hf_rgb_tag); 278 /* reserved for future use */ 279 fb->hf_u.hf_rgb.hf_flags = 0; 280 281 fb->hf_u.hf_rgb.hf_red_width = 5; 282 fb->hf_u.hf_rgb.hf_red_shift = 11; 283 fb->hf_u.hf_rgb.hf_green_width = 6; 284 fb->hf_u.hf_rgb.hf_green_shift = 5; 285 fb->hf_u.hf_rgb.hf_blue_width = 5; 286 fb->hf_u.hf_rgb.hf_blue_shift = 0; 287 fb->hf_u.hf_rgb.hf_alpha_width = 0; 288 fb->hf_u.hf_rgb.hf_alpha_shift = 0; 289 break; 290 291 case 8: 292 fb->hf_class = HPCFB_CLASS_INDEXCOLOR; 293 fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 294 fb->hf_pack_width = 8; 295 fb->hf_pixels_per_pack = 1; 296 fb->hf_pixel_width = 8; 297 fb->hf_class_data_length = sizeof(struct hf_indexed_tag); 298 /* reserved for future use */ 299 fb->hf_u.hf_indexed.hf_flags = 0; 300 break; 301 } 302 } 303 304 int 305 plumvideo_init(struct plumvideo_softc *sc, int *reverse) 306 { 307 struct video_chip *chip = &sc->sc_chip; 308 bus_space_tag_t regt = sc->sc_regt; 309 bus_space_handle_t regh = sc->sc_regh; 310 plumreg_t reg; 311 size_t vram_size; 312 int bpp, width, height, vram_pitch; 313 314 *reverse = video_reverse_color(); 315 chip->vc_v = sc->sc_pc->pc_tc; 316 #if notyet 317 /* map BitBlt area */ 318 if (bus_space_map(sc->sc_bitbltt, 319 PLUM_VIDEO_BITBLT_IOBASE, 320 PLUM_VIDEO_BITBLT_IOSIZE, 0, 321 &sc->sc_bitblth)) { 322 printf(": BitBlt map failed\n"); 323 return (1); 324 } 325 #endif 326 reg = plum_conf_read(regt, regh, PLUM_VIDEO_PLGMD_REG); 327 328 switch (reg & PLUM_VIDEO_PLGMD_GMODE_MASK) { 329 case PLUM_VIDEO_PLGMD_16BPP: 330 #if NPLUMOHCI > 0 /* reserve V-RAM area for USB OHCI */ 331 /* FALLTHROUGH */ 332 #else 333 bpp = 16; 334 break; 335 #endif 336 default: 337 bootinfo->fb_type = *reverse ? BIFB_D8_FF : BIFB_D8_00; 338 reg &= ~PLUM_VIDEO_PLGMD_GMODE_MASK; 339 plum_conf_write(regt, regh, PLUM_VIDEO_PLGMD_REG, reg); 340 reg |= PLUM_VIDEO_PLGMD_8BPP; 341 plum_conf_write(regt, regh, PLUM_VIDEO_PLGMD_REG, reg); 342 #if notyet 343 /* change BitBlt color depth */ 344 plum_conf_write(sc->sc_bitbltt, sc->sc_bitblth, 0x8, 0); 345 #endif 346 /* FALLTHROUGH */ 347 case PLUM_VIDEO_PLGMD_8BPP: 348 bpp = 8; 349 break; 350 } 351 chip->vc_fbdepth = bpp; 352 353 /* 354 * Get display size from WindowsCE set. 355 */ 356 chip->vc_fbwidth = width = bootinfo->fb_width = 357 plum_conf_read(regt, regh, PLUM_VIDEO_PLHPX_REG) + 1; 358 chip->vc_fbheight = height = bootinfo->fb_height = 359 plum_conf_read(regt, regh, PLUM_VIDEO_PLVT_REG) - 360 plum_conf_read(regt, regh, PLUM_VIDEO_PLVDS_REG); 361 362 /* 363 * set line byte length to bootinfo and LCD controller. 364 */ 365 vram_pitch = bootinfo->fb_line_bytes = (width * bpp) / NBBY; 366 plum_conf_write(regt, regh, PLUM_VIDEO_PLPIT1_REG, vram_pitch); 367 plum_conf_write(regt, regh, PLUM_VIDEO_PLPIT2_REG, 368 vram_pitch & PLUM_VIDEO_PLPIT2_MASK); 369 plum_conf_write(regt, regh, PLUM_VIDEO_PLOFS_REG, vram_pitch); 370 371 /* 372 * boot messages and map CLUT(if any). 373 */ 374 printf("display mode: "); 375 switch (bpp) { 376 default: 377 printf("disabled "); 378 break; 379 case 8: 380 printf("8bpp "); 381 /* map CLUT area */ 382 if (bus_space_map(sc->sc_clutiot, 383 PLUM_VIDEO_CLUT_LCD_IOBASE, 384 PLUM_VIDEO_CLUT_LCD_IOSIZE, 0, 385 &sc->sc_clutioh)) { 386 printf(": CLUT map failed\n"); 387 return (1); 388 } 389 /* install default CLUT */ 390 plumvideo_clut_default(sc); 391 break; 392 case 16: 393 printf("16bpp "); 394 break; 395 } 396 397 /* 398 * calculate frame buffer size. 399 */ 400 reg = plum_conf_read(regt, regh, PLUM_VIDEO_PLGMD_REG); 401 vram_size = (width * height * bpp) / NBBY; 402 vram_size = mips_round_page(vram_size); 403 chip->vc_fbsize = vram_size; 404 405 /* 406 * map V-RAM area. 407 */ 408 if (bus_space_map(sc->sc_fbiot, PLUM_VIDEO_VRAM_IOBASE, 409 vram_size, 0, &sc->sc_fbioh)) { 410 printf(": V-RAM map failed\n"); 411 return (1); 412 } 413 414 bootinfo->fb_addr = (unsigned char *)sc->sc_fbioh; 415 chip->vc_fbvaddr = (vaddr_t)sc->sc_fbioh; 416 chip->vc_fbpaddr = PLUM_VIDEO_VRAM_IOBASE_PHYSICAL; 417 418 return (0); 419 } 420 421 int 422 plumvideo_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 423 { 424 struct plumvideo_softc *sc = v; 425 struct hpcfb_fbconf *fbconf; 426 struct hpcfb_dspconf *dspconf; 427 struct wsdisplay_cmap *cmap; 428 struct wsdisplay_param *dispparam; 429 u_int8_t *r, *g, *b; 430 u_int32_t *rgb; 431 int idx, error; 432 size_t cnt; 433 434 switch (cmd) { 435 case WSDISPLAYIO_GETCMAP: 436 cmap = (struct wsdisplay_cmap *)data; 437 cnt = cmap->count; 438 idx = cmap->index; 439 440 if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR || 441 sc->sc_fbconf.hf_pack_width != 8 || 442 !LEGAL_CLUT_INDEX(idx) || 443 !LEGAL_CLUT_INDEX(idx + cnt - 1)) { 444 return (EINVAL); 445 } 446 447 error = cmap_work_alloc(&r, &g, &b, &rgb, cnt); 448 if (error) 449 goto out; 450 plumvideo_clut_get(sc, rgb, idx, cnt); 451 rgb24_decompose(rgb, r, g, b, cnt); 452 453 error = copyout(r, cmap->red, cnt); 454 if (error) 455 goto out; 456 error = copyout(g, cmap->green, cnt); 457 if (error) 458 goto out; 459 error = copyout(b, cmap->blue, cnt); 460 461 out: 462 cmap_work_free(r, g, b, rgb); 463 return error; 464 465 case WSDISPLAYIO_PUTCMAP: 466 cmap = (struct wsdisplay_cmap *)data; 467 cnt = cmap->count; 468 idx = cmap->index; 469 470 if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR || 471 sc->sc_fbconf.hf_pack_width != 8 || 472 !LEGAL_CLUT_INDEX(idx) || 473 !LEGAL_CLUT_INDEX(idx + cnt - 1)) { 474 return (EINVAL); 475 } 476 477 error = cmap_work_alloc(&r, &g, &b, &rgb, cnt); 478 if (error) 479 goto out; 480 error = copyin(cmap->red, r, cnt); 481 if (error) 482 goto out; 483 error = copyin(cmap->green, g, cnt); 484 if (error) 485 goto out; 486 error = copyin(cmap->blue, b, cnt); 487 if (error) 488 goto out; 489 rgb24_compose(rgb, r, g, b, cnt); 490 plumvideo_clut_set(sc, rgb, idx, cnt); 491 goto out; 492 493 case WSDISPLAYIO_SVIDEO: 494 if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) 495 plumvideo_backlight(sc, 0); 496 else 497 plumvideo_backlight(sc, 1); 498 return 0; 499 500 case WSDISPLAYIO_GVIDEO: 501 *(int *)data = sc->sc_backlight ? 502 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF; 503 return 0; 504 505 case WSDISPLAYIO_GETPARAM: 506 dispparam = (struct wsdisplay_param *)data; 507 switch (dispparam->param) { 508 case WSDISPLAYIO_PARAM_BACKLIGHT: 509 dispparam->min = 0; 510 dispparam->max = 1; 511 dispparam->curval = sc->sc_backlight; 512 break; 513 case WSDISPLAYIO_PARAM_BRIGHTNESS: 514 if (sc->sc_max_brightness <= 0) 515 return EINVAL; 516 dispparam->min = 0; 517 dispparam->max = sc->sc_max_brightness; 518 dispparam->curval = sc->sc_brightness; 519 break; 520 default: 521 return EINVAL; 522 } 523 return 0; 524 525 case WSDISPLAYIO_SETPARAM: 526 dispparam = (struct wsdisplay_param * )data; 527 switch (dispparam->param) { 528 case WSDISPLAYIO_PARAM_BACKLIGHT: 529 if (dispparam->curval < 0 || 1 < dispparam->curval) 530 return EINVAL; 531 plumvideo_backlight(sc, dispparam->curval); 532 break; 533 case WSDISPLAYIO_PARAM_BRIGHTNESS: 534 if (sc->sc_max_brightness <= 0) 535 return EINVAL; 536 if (dispparam->curval < 0 || 537 sc->sc_max_brightness < dispparam->curval) 538 return EINVAL; 539 plumvideo_brightness(sc, dispparam->curval); 540 break; 541 default: 542 return EINVAL; 543 } 544 return 0; 545 546 case HPCFBIO_GCONF: 547 fbconf = (struct hpcfb_fbconf *)data; 548 if (fbconf->hf_conf_index != 0 && 549 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) { 550 return (EINVAL); 551 } 552 *fbconf = sc->sc_fbconf; /* structure assignment */ 553 return (0); 554 555 case HPCFBIO_SCONF: 556 fbconf = (struct hpcfb_fbconf *)data; 557 if (fbconf->hf_conf_index != 0 && 558 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) { 559 return (EINVAL); 560 } 561 /* 562 * nothing to do because we have only one configuration 563 */ 564 return (0); 565 566 case HPCFBIO_GDSPCONF: 567 dspconf = (struct hpcfb_dspconf *)data; 568 if ((dspconf->hd_unit_index != 0 && 569 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) || 570 (dspconf->hd_conf_index != 0 && 571 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) { 572 return (EINVAL); 573 } 574 *dspconf = sc->sc_dspconf; /* structure assignment */ 575 return (0); 576 577 case HPCFBIO_SDSPCONF: 578 dspconf = (struct hpcfb_dspconf *)data; 579 if ((dspconf->hd_unit_index != 0 && 580 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) || 581 (dspconf->hd_conf_index != 0 && 582 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) { 583 return (EINVAL); 584 } 585 /* 586 * nothing to do 587 * because we have only one unit and one configuration 588 */ 589 return (0); 590 591 case HPCFBIO_GOP: 592 case HPCFBIO_SOP: 593 /* XXX not implemented yet */ 594 return (EINVAL); 595 } 596 597 return (EPASSTHROUGH); 598 } 599 600 paddr_t 601 plumvideo_mmap(void *ctx, off_t offset, int prot) 602 { 603 struct plumvideo_softc *sc = ctx; 604 605 if (offset < 0 || (sc->sc_fbconf.hf_bytes_per_plane + 606 sc->sc_fbconf.hf_offset) < offset) { 607 return (-1); 608 } 609 610 return (mips_btop(PLUM_VIDEO_VRAM_IOBASE_PHYSICAL + offset)); 611 } 612 613 static void __plumvideo_clut_get(bus_space_tag_t, bus_space_handle_t, 614 u_int32_t *, int, int); 615 static void __plumvideo_clut_get(bus_space_tag_t iot, bus_space_handle_t ioh, 616 u_int32_t *rgb, int beg, int cnt) 617 { 618 int i; 619 620 for (i = 0, beg *= 4; i < cnt; i++, beg += 4) { 621 *rgb++ = bus_space_read_4(iot, ioh, beg) & 622 0x00ffffff; 623 } 624 } 625 626 void 627 plumvideo_clut_get(struct plumvideo_softc *sc, u_int32_t *rgb, int beg, 628 int cnt) 629 { 630 KASSERT(rgb); 631 KASSERT(LEGAL_CLUT_INDEX(beg)); 632 KASSERT(LEGAL_CLUT_INDEX(beg + cnt - 1)); 633 __plumvideo_clut_access(sc, rgb, beg, cnt, __plumvideo_clut_get); 634 } 635 636 static void __plumvideo_clut_set(bus_space_tag_t, bus_space_handle_t, 637 u_int32_t *, int, int); 638 static void __plumvideo_clut_set(bus_space_tag_t iot, bus_space_handle_t ioh, 639 u_int32_t *rgb, int beg, int cnt) 640 { 641 int i; 642 643 for (i = 0, beg *= 4; i < cnt; i++, beg +=4) { 644 bus_space_write_4(iot, ioh, beg, 645 *rgb++ & 0x00ffffff); 646 } 647 } 648 649 void 650 plumvideo_clut_set(struct plumvideo_softc *sc, u_int32_t *rgb, int beg, 651 int cnt) 652 { 653 KASSERT(rgb); 654 KASSERT(LEGAL_CLUT_INDEX(beg)); 655 KASSERT(LEGAL_CLUT_INDEX(beg + cnt - 1)); 656 __plumvideo_clut_access(sc, rgb, beg, cnt, __plumvideo_clut_set); 657 } 658 659 static void __plumvideo_clut_default(bus_space_tag_t, bus_space_handle_t, 660 u_int32_t *, int, int); 661 static void __plumvideo_clut_default(bus_space_tag_t iot, bus_space_handle_t ioh, 662 u_int32_t *rgb, int beg, int cnt) 663 { 664 static const u_int8_t compo6[6] = { 0, 51, 102, 153, 204, 255 }; 665 static const u_int32_t ansi_color[16] = { 666 0x000000, 0xff0000, 0x00ff00, 0xffff00, 667 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff, 668 0x000000, 0x800000, 0x008000, 0x808000, 669 0x000080, 0x800080, 0x008080, 0x808080, 670 }; 671 int i, r, g, b; 672 673 /* ANSI escape sequence */ 674 for (i = 0; i < 16; i++) { 675 bus_space_write_4(iot, ioh, i << 2, ansi_color[i]); 676 } 677 /* 16 - 31, gray scale */ 678 for ( ; i < 32; i++) { 679 int j = (i - 16) * 17; 680 bus_space_write_4(iot, ioh, i << 2, RGB24(j, j, j)); 681 } 682 /* 32 - 247, RGB color */ 683 for (r = 0; r < 6; r++) { 684 for (g = 0; g < 6; g++) { 685 for (b = 0; b < 6; b++) { 686 bus_space_write_4(iot, ioh, i << 2, 687 RGB24(compo6[r], 688 compo6[g], 689 compo6[b])); 690 i++; 691 } 692 } 693 } 694 /* 248 - 245, just white */ 695 for ( ; i < 256; i++) { 696 bus_space_write_4(iot, ioh, i << 2, 0xffffff); 697 } 698 } 699 700 void 701 plumvideo_clut_default(struct plumvideo_softc *sc) 702 { 703 __plumvideo_clut_access(sc, NULL, 0, 256, __plumvideo_clut_default); 704 } 705 706 void 707 __plumvideo_clut_access(struct plumvideo_softc *sc, u_int32_t *rgb, int beg, 708 int cnt, void (*palette_func)(bus_space_tag_t, bus_space_handle_t, 709 u_int32_t *, int, int)) 710 { 711 bus_space_tag_t regt = sc->sc_regt; 712 bus_space_handle_t regh = sc->sc_regh; 713 plumreg_t val, gmode; 714 715 /* display off */ 716 val = bus_space_read_4(regt, regh, PLUM_VIDEO_PLGMD_REG); 717 gmode = val & PLUM_VIDEO_PLGMD_GMODE_MASK; 718 val &= ~PLUM_VIDEO_PLGMD_GMODE_MASK; 719 bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val); 720 721 /* palette access disable */ 722 val &= ~PLUM_VIDEO_PLGMD_PALETTE_ENABLE; 723 bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val); 724 725 /* change palette mode to CPU */ 726 val &= ~PLUM_VIDEO_PLGMD_MODE_DISPLAY; 727 bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val); 728 729 /* palette access */ 730 (*palette_func) (sc->sc_clutiot, sc->sc_clutioh, rgb, beg, cnt); 731 732 /* change palette mode to Display */ 733 val |= PLUM_VIDEO_PLGMD_MODE_DISPLAY; 734 bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val); 735 736 /* palette access enable */ 737 val |= PLUM_VIDEO_PLGMD_PALETTE_ENABLE; 738 bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val); 739 740 /* display on */ 741 val |= gmode; 742 bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val); 743 } 744 745 /* !!! */ 746 static void 747 _flush_cache(void) 748 { 749 mips_dcache_wbinv_all(); 750 mips_icache_sync_all(); 751 } 752 753 int 754 plumvideo_power(void *ctx, int type, long id, void *msg) 755 { 756 struct plumvideo_softc *sc = ctx; 757 int why = (int)msg; 758 759 switch (why) { 760 case PWR_RESUME: 761 if (!sc->sc_console) 762 return (0); /* serial console */ 763 764 DPRINTF("%s: ON\n", device_xname(sc->sc_dev)); 765 /* power on */ 766 plumvideo_backlight(sc, 1); 767 break; 768 case PWR_SUSPEND: 769 /* FALLTHROUGH */ 770 case PWR_STANDBY: 771 DPRINTF("%s: OFF\n", device_xname(sc->sc_dev)); 772 /* power off */ 773 plumvideo_backlight(sc, 0); 774 break; 775 } 776 777 return (0); 778 } 779 780 static void 781 plumvideo_init_backlight(struct plumvideo_softc *sc) 782 { 783 int val; 784 785 val = -1; 786 if (config_hook_call(CONFIG_HOOK_GET, 787 CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) { 788 /* we can get real backlight state */ 789 sc->sc_backlight = val; 790 } 791 792 val = -1; 793 if (config_hook_call(CONFIG_HOOK_GET, 794 CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) { 795 /* we can get real brightness max */ 796 sc->sc_max_brightness = val; 797 798 val = -1; 799 if (config_hook_call(CONFIG_HOOK_GET, 800 CONFIG_HOOK_BRIGHTNESS, &val) != -1) { 801 /* we can get real brightness */ 802 sc->sc_brightness = val; 803 } else { 804 sc->sc_brightness = sc->sc_max_brightness; 805 } 806 } 807 } 808 809 static void 810 plumvideo_backlight(struct plumvideo_softc *sc, int on) 811 { 812 plum_chipset_tag_t pc = sc->sc_pc; 813 bus_space_tag_t regt = sc->sc_regt; 814 bus_space_handle_t regh = sc->sc_regh; 815 816 sc->sc_backlight = on; 817 if (on) { 818 /* LCD on */ 819 plum_power_establish(pc, PLUM_PWR_LCD); 820 /* backlight on */ 821 plum_power_establish(pc, PLUM_PWR_BKL); 822 plum_conf_write(regt, regh, PLUM_VIDEO_PLLUM_REG, 823 PLUM_VIDEO_PLLUM_MAX); 824 } else { 825 /* backlight off */ 826 plum_conf_write(regt, regh, PLUM_VIDEO_PLLUM_REG, 827 PLUM_VIDEO_PLLUM_MIN); 828 plum_power_disestablish(pc, PLUM_PWR_BKL); 829 /* LCD off */ 830 plum_power_disestablish(pc, PLUM_PWR_LCD); 831 } 832 /* call machine dependent backlight control */ 833 config_hook_call(CONFIG_HOOK_SET, 834 CONFIG_HOOK_POWER_LCDLIGHT, (void *)on); 835 } 836 837 static void 838 plumvideo_brightness(struct plumvideo_softc *sc, int val) 839 { 840 841 sc->sc_brightness = val; 842 /* call machine dependent brightness control */ 843 if (sc->sc_backlight) 844 config_hook_call(CONFIG_HOOK_SET, 845 CONFIG_HOOK_BRIGHTNESS, &val); 846 } 847 848 #ifdef PLUMVIDEODEBUG 849 void 850 plumvideo_dump(struct plumvideo_softc *sc) 851 { 852 bus_space_tag_t regt = sc->sc_regt; 853 bus_space_handle_t regh = sc->sc_regh; 854 855 plumreg_t reg; 856 int i; 857 858 for (i = 0; i < 0x160; i += 4) { 859 reg = plum_conf_read(regt, regh, i); 860 printf("0x%03x %08x", i, reg); 861 dbg_bit_print(reg); 862 } 863 } 864 #endif /* PLUMVIDEODEBUG */ 865