1 /* $NetBSD: mq200.c,v 1.18 2001/09/16 05:32:18 uch Exp $ */ 2 3 /*- 4 * Copyright (c) 2000, 2001 TAKEMURA Shin 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 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32 #include <sys/param.h> 33 #include <sys/kernel.h> 34 #include <sys/device.h> 35 #include <sys/systm.h> 36 #include <sys/reboot.h> 37 38 #include <uvm/uvm_extern.h> 39 40 #include <dev/wscons/wsconsio.h> 41 42 #include <machine/bootinfo.h> 43 #include <machine/bus.h> 44 #include <machine/autoconf.h> 45 #include <machine/config_hook.h> 46 #include <machine/platid.h> 47 #include <machine/platid_mask.h> 48 49 #include "opt_mq200.h" 50 #include <hpcmips/dev/mq200reg.h> 51 #include <hpcmips/dev/mq200var.h> 52 #include <hpcmips/dev/mq200priv.h> 53 54 #include "bivideo.h" 55 #if NBIVIDEO > 0 56 #include <dev/hpc/bivideovar.h> 57 #endif 58 59 /* 60 * function prototypes 61 */ 62 static void mq200_power(int, void *); 63 static int mq200_hardpower(void *, int, long, void *); 64 static int mq200_fbinit(struct hpcfb_fbconf *); 65 static int mq200_ioctl(void *, u_long, caddr_t, int, struct proc *); 66 static paddr_t mq200_mmap(void *, off_t offset, int); 67 static void mq200_update_powerstate(struct mq200_softc *, int); 68 void mq200_init_backlight(struct mq200_softc *, int); 69 void mq200_init_brightness(struct mq200_softc *, int); 70 void mq200_init_contrast(struct mq200_softc *, int); 71 void mq200_set_brightness(struct mq200_softc *, int); 72 void mq200_set_contrast(struct mq200_softc *, int); 73 74 /* 75 * static variables 76 */ 77 struct hpcfb_accessops mq200_ha = { 78 mq200_ioctl, mq200_mmap 79 }; 80 81 #ifdef MQ200_DEBUG 82 int mq200_debug = MQ200DEBUG_CONF; 83 #endif 84 85 int 86 mq200_probe(bus_space_tag_t iot, bus_space_handle_t ioh) 87 { 88 unsigned long regval; 89 90 #if NBIVIDEO > 0 91 if (bivideo_dont_attach) /* some video driver already attached */ 92 return (0); 93 #endif /* NBIVIDEO > 0 */ 94 95 regval = bus_space_read_4(iot, ioh, MQ200_PC00R); 96 VPRINTF("probe: vendor id=%04lx product id=%04lx\n", 97 regval & 0xffff, (regval >> 16) & 0xffff); 98 if (regval != ((MQ200_PRODUCT_ID << 16) | MQ200_VENDOR_ID)) 99 return (0); 100 101 return (1); 102 } 103 104 void 105 mq200_attach(struct mq200_softc *sc) 106 { 107 unsigned long regval; 108 struct hpcfb_attach_args ha; 109 int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1; 110 111 printf(": "); 112 if (mq200_fbinit(&sc->sc_fbconf) != 0) { 113 /* just return so that hpcfb will not be attached */ 114 return; 115 } 116 117 sc->sc_fbconf.hf_baseaddr = (u_long)bootinfo->fb_addr; 118 sc->sc_fbconf.hf_offset = (u_long)sc->sc_fbconf.hf_baseaddr - 119 MIPS_PHYS_TO_KSEG1(mips_ptob(mips_btop(sc->sc_baseaddr))); 120 DPRINTF("hf_baseaddr=%lx\n", sc->sc_fbconf.hf_baseaddr); 121 DPRINTF("hf_offset=%lx\n", sc->sc_fbconf.hf_offset); 122 123 regval = mq200_read(sc, MQ200_PC08R); 124 printf("MQ200 Rev.%02lx video controller", regval & 0xff); 125 if (console) { 126 printf(", console"); 127 } 128 printf("\n"); 129 printf("%s: framebuffer address: 0x%08lx\n", 130 sc->sc_dev.dv_xname, (u_long)bootinfo->fb_addr); 131 132 /* 133 * setup registers 134 */ 135 sc->sc_flags = 0; 136 sc->sc_baseclock = 12288; /* 12.288 MHz */ 137 #ifdef MQ200_DEBUG 138 if (bootverbose) { 139 /* dump current setting */ 140 mq200_dump_all(sc); 141 mq200_dump_pll(sc); 142 } 143 #endif 144 mq200_setup_regctx(sc); 145 mq200_mdsetup(sc); 146 if (sc->sc_md) { 147 if (sc->sc_md->md_flags & MQ200_MD_HAVEFP) { 148 sc->sc_flags |= MQ200_SC_GC2_ENABLE; /* FP */ 149 } 150 #if MQ200_USECRT 151 if (sc->sc_md->md_flags & MQ200_MD_HAVECRT) { 152 int i; 153 sc->sc_flags |= MQ200_SC_GC1_ENABLE; /* CRT */ 154 for (i = 0; i < mq200_crt_nparams; i++) { 155 sc->sc_crt = &mq200_crt_params[i]; 156 if (sc->sc_md->md_fp_width <= 157 mq200_crt_params[i].width && 158 sc->sc_md->md_fp_height <= 159 mq200_crt_params[i].height) 160 break; 161 } 162 } 163 #endif 164 mq200_setup(sc); 165 166 if (sc->sc_flags & MQ200_SC_GC2_ENABLE) /* FP */ 167 mq200_win_enable(sc, MQ200_GC2, MQ200_GCC_16BPP_DIRECT, 168 0x00080100, 169 sc->sc_md->md_fp_width, sc->sc_md->md_fp_height, 170 1280); 171 if (sc->sc_flags & MQ200_SC_GC1_ENABLE) /* CRT */ 172 mq200_win_enable(sc, MQ200_GC1, MQ200_GCC_16BPP_DIRECT, 173 0x00080100, 174 sc->sc_md->md_fp_width, sc->sc_md->md_fp_height, 175 1280); 176 } 177 #ifdef MQ200_DEBUG 178 if (sc->sc_md == NULL || bootverbose) { 179 mq200_dump_pll(sc); 180 } 181 #endif 182 183 /* Add a power hook to power saving */ 184 sc->sc_mq200pwstate = MQ200_POWERSTATE_D0; 185 sc->sc_powerhook = powerhook_establish(mq200_power, sc); 186 if (sc->sc_powerhook == NULL) 187 printf("%s: WARNING: unable to establish power hook\n", 188 sc->sc_dev.dv_xname); 189 190 /* Add a hard power hook to power saving */ 191 sc->sc_hardpowerhook = config_hook(CONFIG_HOOK_PMEVENT, 192 CONFIG_HOOK_PMEVENT_HARDPOWER, 193 CONFIG_HOOK_SHARE, 194 mq200_hardpower, sc); 195 if (sc->sc_hardpowerhook == NULL) 196 printf("%s: WARNING: unable to establish hard power hook\n", 197 sc->sc_dev.dv_xname); 198 199 /* initialize backlight brightness and lcd contrast */ 200 sc->sc_lcd_inited = 0; 201 mq200_init_brightness(sc, 1); 202 mq200_init_contrast(sc, 1); 203 mq200_init_backlight(sc, 1); 204 205 if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0) { 206 panic("mq200_attach: can't init fb console"); 207 } 208 209 ha.ha_console = console; 210 ha.ha_accessops = &mq200_ha; 211 ha.ha_accessctx = sc; 212 ha.ha_curfbconf = 0; 213 ha.ha_nfbconf = 1; 214 ha.ha_fbconflist = &sc->sc_fbconf; 215 ha.ha_curdspconf = 0; 216 ha.ha_ndspconf = 1; 217 ha.ha_dspconflist = &sc->sc_dspconf; 218 219 config_found(&sc->sc_dev, &ha, hpcfbprint); 220 221 #if NBIVIDEO > 0 222 /* 223 * bivideo is no longer need 224 */ 225 bivideo_dont_attach = 1; 226 #endif /* NBIVIDEO > 0 */ 227 } 228 229 static void 230 mq200_update_powerstate(struct mq200_softc *sc, int updates) 231 { 232 233 if (updates & PWRSTAT_LCD) 234 config_hook_call(CONFIG_HOOK_POWERCONTROL, 235 CONFIG_HOOK_POWERCONTROL_LCD, 236 (void*)!(sc->sc_powerstate & 237 (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND))); 238 239 if (updates & PWRSTAT_BACKLIGHT) 240 config_hook_call(CONFIG_HOOK_POWERCONTROL, 241 CONFIG_HOOK_POWERCONTROL_LCDLIGHT, 242 (void*)(!(sc->sc_powerstate & 243 (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)) && 244 (sc->sc_powerstate & PWRSTAT_BACKLIGHT))); 245 } 246 247 static void 248 mq200_power(int why, void *arg) 249 { 250 struct mq200_softc *sc = arg; 251 252 switch (why) { 253 case PWR_SUSPEND: 254 sc->sc_powerstate |= PWRSTAT_SUSPEND; 255 mq200_update_powerstate(sc, PWRSTAT_ALL); 256 break; 257 case PWR_STANDBY: 258 sc->sc_powerstate |= PWRSTAT_SUSPEND; 259 mq200_update_powerstate(sc, PWRSTAT_ALL); 260 break; 261 case PWR_RESUME: 262 sc->sc_powerstate &= ~PWRSTAT_SUSPEND; 263 mq200_update_powerstate(sc, PWRSTAT_ALL); 264 break; 265 } 266 } 267 268 static int 269 mq200_hardpower(void *ctx, int type, long id, void *msg) 270 { 271 struct mq200_softc *sc = ctx; 272 int why = (int)msg; 273 274 switch (why) { 275 case PWR_SUSPEND: 276 sc->sc_mq200pwstate = MQ200_POWERSTATE_D2; 277 break; 278 case PWR_STANDBY: 279 sc->sc_mq200pwstate = MQ200_POWERSTATE_D3; 280 break; 281 case PWR_RESUME: 282 sc->sc_mq200pwstate = MQ200_POWERSTATE_D0; 283 break; 284 } 285 286 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 287 MQ200_PMCSR, sc->sc_mq200pwstate); 288 289 /* 290 * you should wait until the 291 * power state transit sequence will end. 292 */ 293 { 294 unsigned long tmp; 295 do { 296 tmp = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 297 MQ200_PMCSR); 298 } while ((tmp & 0x3) != (sc->sc_mq200pwstate & 0x3)); 299 delay(100000); /* XXX */ 300 } 301 302 return (0); 303 } 304 305 306 static int 307 mq200_fbinit(struct hpcfb_fbconf *fb) 308 { 309 310 /* 311 * get fb settings from bootinfo 312 */ 313 if (bootinfo == NULL || 314 bootinfo->fb_addr == 0 || 315 bootinfo->fb_line_bytes == 0 || 316 bootinfo->fb_width == 0 || 317 bootinfo->fb_height == 0) { 318 printf("no frame buffer information.\n"); 319 return (-1); 320 } 321 322 /* zero fill */ 323 bzero(fb, sizeof(*fb)); 324 325 fb->hf_conf_index = 0; /* configuration index */ 326 fb->hf_nconfs = 1; /* how many configurations */ 327 strcpy(fb->hf_name, "built-in video"); 328 /* frame buffer name */ 329 strcpy(fb->hf_conf_name, "default"); 330 /* configuration name */ 331 fb->hf_height = bootinfo->fb_height; 332 fb->hf_width = bootinfo->fb_width; 333 fb->hf_baseaddr = mips_ptob(mips_btop(bootinfo->fb_addr)); 334 fb->hf_offset = (u_long)bootinfo->fb_addr - fb->hf_baseaddr; 335 /* frame buffer start offset */ 336 fb->hf_bytes_per_line = bootinfo->fb_line_bytes; 337 fb->hf_nplanes = 1; 338 fb->hf_bytes_per_plane = bootinfo->fb_height * 339 bootinfo->fb_line_bytes; 340 341 fb->hf_access_flags |= HPCFB_ACCESS_BYTE; 342 fb->hf_access_flags |= HPCFB_ACCESS_WORD; 343 fb->hf_access_flags |= HPCFB_ACCESS_DWORD; 344 345 switch (bootinfo->fb_type) { 346 /* 347 * gray scale 348 */ 349 case BIFB_D2_M2L_3: 350 case BIFB_D2_M2L_3x2: 351 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 352 /* fall through */ 353 case BIFB_D2_M2L_0: 354 case BIFB_D2_M2L_0x2: 355 fb->hf_class = HPCFB_CLASS_GRAYSCALE; 356 fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 357 fb->hf_pack_width = 8; 358 fb->hf_pixels_per_pack = 4; 359 fb->hf_pixel_width = 2; 360 fb->hf_class_data_length = sizeof(struct hf_gray_tag); 361 fb->hf_u.hf_gray.hf_flags = 0; /* reserved for future use */ 362 break; 363 364 case BIFB_D4_M2L_F: 365 case BIFB_D4_M2L_Fx2: 366 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 367 /* fall through */ 368 case BIFB_D4_M2L_0: 369 case BIFB_D4_M2L_0x2: 370 fb->hf_class = HPCFB_CLASS_GRAYSCALE; 371 fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 372 fb->hf_pack_width = 8; 373 fb->hf_pixels_per_pack = 2; 374 fb->hf_pixel_width = 4; 375 fb->hf_class_data_length = sizeof(struct hf_gray_tag); 376 fb->hf_u.hf_gray.hf_flags = 0; /* reserved for future use */ 377 break; 378 379 /* 380 * indexed color 381 */ 382 case BIFB_D8_FF: 383 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 384 /* fall through */ 385 case BIFB_D8_00: 386 fb->hf_class = HPCFB_CLASS_INDEXCOLOR; 387 fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 388 fb->hf_pack_width = 8; 389 fb->hf_pixels_per_pack = 1; 390 fb->hf_pixel_width = 8; 391 fb->hf_class_data_length = sizeof(struct hf_indexed_tag); 392 fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */ 393 break; 394 395 /* 396 * RGB color 397 */ 398 case BIFB_D16_FFFF: 399 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 400 /* fall through */ 401 case BIFB_D16_0000: 402 fb->hf_class = HPCFB_CLASS_RGBCOLOR; 403 fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 404 fb->hf_order_flags = HPCFB_REVORDER_BYTE; 405 fb->hf_pack_width = 16; 406 fb->hf_pixels_per_pack = 1; 407 fb->hf_pixel_width = 16; 408 409 fb->hf_class_data_length = sizeof(struct hf_rgb_tag); 410 fb->hf_u.hf_rgb.hf_flags = 0; /* reserved for future use */ 411 412 fb->hf_u.hf_rgb.hf_red_width = 5; 413 fb->hf_u.hf_rgb.hf_red_shift = 11; 414 fb->hf_u.hf_rgb.hf_green_width = 6; 415 fb->hf_u.hf_rgb.hf_green_shift = 5; 416 fb->hf_u.hf_rgb.hf_blue_width = 5; 417 fb->hf_u.hf_rgb.hf_blue_shift = 0; 418 fb->hf_u.hf_rgb.hf_alpha_width = 0; 419 fb->hf_u.hf_rgb.hf_alpha_shift = 0; 420 break; 421 422 default: 423 printf("unknown type (=%d).\n", bootinfo->fb_type); 424 return (-1); 425 break; 426 } 427 428 return (0); /* no error */ 429 } 430 431 int 432 mq200_ioctl(v, cmd, data, flag, p) 433 void *v; 434 u_long cmd; 435 caddr_t data; 436 int flag; 437 struct proc *p; 438 { 439 struct mq200_softc *sc = (struct mq200_softc *)v; 440 struct hpcfb_fbconf *fbconf; 441 struct hpcfb_dspconf *dspconf; 442 struct wsdisplay_cmap *cmap; 443 struct wsdisplay_param *dispparam; 444 445 switch (cmd) { 446 case WSDISPLAYIO_GETCMAP: 447 cmap = (struct wsdisplay_cmap*)data; 448 449 if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR || 450 sc->sc_fbconf.hf_pack_width != 8 || 451 256 <= cmap->index || 452 256 < (cmap->index + cmap->count)) 453 return (EINVAL); 454 455 #if 0 456 if (!uvm_useracc(cmap->red, cmap->count, B_WRITE) || 457 !uvm_useracc(cmap->green, cmap->count, B_WRITE) || 458 !uvm_useracc(cmap->blue, cmap->count, B_WRITE)) 459 return (EFAULT); 460 461 copyout(&bivideo_cmap_r[cmap->index], cmap->red, cmap->count); 462 copyout(&bivideo_cmap_g[cmap->index], cmap->green,cmap->count); 463 copyout(&bivideo_cmap_b[cmap->index], cmap->blue, cmap->count); 464 #endif 465 466 return (0); 467 468 case WSDISPLAYIO_PUTCMAP: 469 /* 470 * This driver can't set color map. 471 */ 472 return (EINVAL); 473 474 case WSDISPLAYIO_SVIDEO: 475 if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) 476 sc->sc_powerstate |= PWRSTAT_VIDEOOFF; 477 else 478 sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF; 479 mq200_update_powerstate(sc, PWRSTAT_ALL); 480 return 0; 481 482 case WSDISPLAYIO_GVIDEO: 483 *(int *)data = (sc->sc_powerstate&PWRSTAT_VIDEOOFF) ? 484 WSDISPLAYIO_VIDEO_OFF:WSDISPLAYIO_VIDEO_ON; 485 return 0; 486 487 case WSDISPLAYIO_GETPARAM: 488 dispparam = (struct wsdisplay_param*)data; 489 switch (dispparam->param) { 490 case WSDISPLAYIO_PARAM_BACKLIGHT: 491 VPRINTF("ioctl: GET:BACKLIGHT\n"); 492 mq200_init_brightness(sc, 0); 493 mq200_init_backlight(sc, 0); 494 VPRINTF("ioctl: GET:(real)BACKLIGHT %d\n", 495 (sc->sc_powerstate&PWRSTAT_BACKLIGHT)? 1: 0); 496 dispparam->min = 0; 497 dispparam->max = 1; 498 if (sc->sc_max_brightness > 0) 499 dispparam->curval = sc->sc_brightness > 0 500 ? 1: 0; 501 else 502 dispparam->curval = 503 (sc->sc_powerstate&PWRSTAT_BACKLIGHT) 504 ? 1: 0; 505 VPRINTF("ioctl: GET:BACKLIGHT:%d(%s)\n", 506 dispparam->curval, 507 sc->sc_max_brightness > 0? "brightness": "light"); 508 return 0; 509 break; 510 case WSDISPLAYIO_PARAM_CONTRAST: 511 VPRINTF("ioctl: GET:CONTRAST\n"); 512 mq200_init_contrast(sc, 0); 513 if (sc->sc_max_contrast > 0) { 514 dispparam->min = 0; 515 dispparam->max = sc->sc_max_contrast; 516 dispparam->curval = sc->sc_contrast; 517 VPRINTF("ioctl: GET:CONTRAST" 518 " max=%d, current=%d\n", 519 sc->sc_max_contrast, sc->sc_contrast); 520 return 0; 521 } else { 522 VPRINTF("ioctl: GET:CONTRAST EINVAL\n"); 523 return (EINVAL); 524 } 525 break; 526 case WSDISPLAYIO_PARAM_BRIGHTNESS: 527 VPRINTF("ioctl: GET:BRIGHTNESS\n"); 528 mq200_init_brightness(sc, 0); 529 if (sc->sc_max_brightness > 0) { 530 dispparam->min = 0; 531 dispparam->max = sc->sc_max_brightness; 532 dispparam->curval = sc->sc_brightness; 533 VPRINTF("ioctl: GET:BRIGHTNESS" 534 " max=%d, current=%d\n", 535 sc->sc_max_brightness, sc->sc_brightness); 536 return 0; 537 } else { 538 VPRINTF("ioctl: GET:BRIGHTNESS EINVAL\n"); 539 return (EINVAL); 540 } 541 return (EINVAL); 542 default: 543 return (EINVAL); 544 } 545 return (0); 546 547 case WSDISPLAYIO_SETPARAM: 548 dispparam = (struct wsdisplay_param*)data; 549 switch (dispparam->param) { 550 case WSDISPLAYIO_PARAM_BACKLIGHT: 551 VPRINTF("ioctl: SET:BACKLIGHT\n"); 552 if (dispparam->curval < 0 || 553 1 < dispparam->curval) 554 return (EINVAL); 555 mq200_init_brightness(sc, 0); 556 VPRINTF("ioctl: SET:max brightness=%d\n", 557 sc->sc_max_brightness); 558 if (sc->sc_max_brightness > 0) { /* dimmer */ 559 if (dispparam->curval == 0){ 560 sc->sc_brightness_save = 561 sc->sc_brightness; 562 mq200_set_brightness(sc, 0); /* min */ 563 } else { 564 if (sc->sc_brightness_save == 0) 565 sc->sc_brightness_save = 566 sc->sc_max_brightness; 567 mq200_set_brightness(sc, 568 sc->sc_brightness_save); 569 } 570 VPRINTF("ioctl: SET:BACKLIGHT:" 571 " brightness=%d\n", sc->sc_brightness); 572 } else { /* off */ 573 if (dispparam->curval == 0) 574 sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT; 575 else 576 sc->sc_powerstate |= PWRSTAT_BACKLIGHT; 577 VPRINTF("ioctl: SET:BACKLIGHT:" 578 " powerstate %d\n", 579 (sc->sc_powerstate & PWRSTAT_BACKLIGHT) 580 ? 1 : 0); 581 mq200_update_powerstate(sc, PWRSTAT_BACKLIGHT); 582 VPRINTF("ioctl: SET:BACKLIGHT:%d\n", 583 (sc->sc_powerstate & PWRSTAT_BACKLIGHT) 584 ? 1 : 0); 585 } 586 return 0; 587 break; 588 case WSDISPLAYIO_PARAM_CONTRAST: 589 VPRINTF("ioctl: SET:CONTRAST\n"); 590 mq200_init_contrast(sc, 0); 591 if (dispparam->curval < 0 || 592 sc->sc_max_contrast < dispparam->curval) 593 return (EINVAL); 594 if (sc->sc_max_contrast > 0) { 595 int org = sc->sc_contrast; 596 mq200_set_contrast(sc, dispparam->curval); 597 VPRINTF("ioctl: SET:CONTRAST" 598 " org=%d, current=%d\n", org, 599 sc->sc_contrast); 600 VPRINTF("ioctl: SETPARAM:" 601 " CONTRAST org=%d, current=%d\n", org, 602 sc->sc_contrast); 603 return 0; 604 } else { 605 VPRINTF("ioctl: SET:CONTRAST EINVAL\n"); 606 return (EINVAL); 607 } 608 break; 609 case WSDISPLAYIO_PARAM_BRIGHTNESS: 610 VPRINTF("ioctl: SET:BRIGHTNESS\n"); 611 mq200_init_brightness(sc, 0); 612 if (dispparam->curval < 0 || 613 sc->sc_max_brightness < dispparam->curval) 614 return (EINVAL); 615 if (sc->sc_max_brightness > 0) { 616 int org = sc->sc_brightness; 617 mq200_set_brightness(sc, dispparam->curval); 618 VPRINTF("ioctl: SET:BRIGHTNESS" 619 " org=%d, current=%d\n", org, 620 sc->sc_brightness); 621 return 0; 622 } else { 623 VPRINTF("ioctl: SET:BRIGHTNESS EINVAL\n"); 624 return (EINVAL); 625 } 626 break; 627 default: 628 return (EINVAL); 629 } 630 return (0); 631 632 case HPCFBIO_GCONF: 633 fbconf = (struct hpcfb_fbconf *)data; 634 if (fbconf->hf_conf_index != 0 && 635 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) { 636 return (EINVAL); 637 } 638 *fbconf = sc->sc_fbconf; /* structure assignment */ 639 return (0); 640 case HPCFBIO_SCONF: 641 fbconf = (struct hpcfb_fbconf *)data; 642 if (fbconf->hf_conf_index != 0 && 643 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) { 644 return (EINVAL); 645 } 646 /* 647 * nothing to do because we have only one configration 648 */ 649 return (0); 650 case HPCFBIO_GDSPCONF: 651 dspconf = (struct hpcfb_dspconf *)data; 652 if ((dspconf->hd_unit_index != 0 && 653 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) || 654 (dspconf->hd_conf_index != 0 && 655 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) { 656 return (EINVAL); 657 } 658 *dspconf = sc->sc_dspconf; /* structure assignment */ 659 return (0); 660 case HPCFBIO_SDSPCONF: 661 dspconf = (struct hpcfb_dspconf *)data; 662 if ((dspconf->hd_unit_index != 0 && 663 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) || 664 (dspconf->hd_conf_index != 0 && 665 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) { 666 return (EINVAL); 667 } 668 /* 669 * nothing to do 670 * because we have only one unit and one configration 671 */ 672 return (0); 673 case HPCFBIO_GOP: 674 case HPCFBIO_SOP: 675 /* 676 * curently not implemented... 677 */ 678 return (EINVAL); 679 } 680 681 return (ENOTTY); 682 } 683 684 paddr_t 685 mq200_mmap(void *ctx, off_t offset, int prot) 686 { 687 struct mq200_softc *sc = (struct mq200_softc *)ctx; 688 689 if (offset < 0 || MQ200_MAPSIZE <= offset) 690 return -1; 691 692 return mips_btop(sc->sc_baseaddr + offset); 693 } 694 695 696 void 697 mq200_init_backlight(struct mq200_softc *sc, int inattach) 698 { 699 int val = -1; 700 701 if (sc->sc_lcd_inited&BACKLIGHT_INITED) 702 return; 703 704 if (config_hook_call(CONFIG_HOOK_GET, 705 CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) { 706 /* we can get real light state */ 707 VPRINTF("init_backlight: real backlight=%d\n", val); 708 if (val == 0) 709 sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT; 710 else 711 sc->sc_powerstate |= PWRSTAT_BACKLIGHT; 712 sc->sc_lcd_inited |= BACKLIGHT_INITED; 713 } else if (inattach) { 714 /* 715 we cannot get real light state in attach time 716 because light device not yet attached. 717 we will retry in !inattach. 718 temporary assume light is on. 719 */ 720 sc->sc_powerstate |= PWRSTAT_BACKLIGHT; 721 } else { 722 /* we cannot get real light state, so work by myself state */ 723 sc->sc_lcd_inited |= BACKLIGHT_INITED; 724 } 725 } 726 727 void 728 mq200_init_brightness(struct mq200_softc *sc, int inattach) 729 { 730 int val = -1; 731 732 if (sc->sc_lcd_inited&BRIGHTNESS_INITED) 733 return; 734 735 VPRINTF("init_brightness\n"); 736 if (config_hook_call(CONFIG_HOOK_GET, 737 CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) { 738 /* we can get real brightness max */ 739 VPRINTF("init_brightness: real brightness max=%d\n", val); 740 sc->sc_max_brightness = val; 741 val = -1; 742 if (config_hook_call(CONFIG_HOOK_GET, 743 CONFIG_HOOK_BRIGHTNESS, &val) != -1) { 744 /* we can get real brightness */ 745 VPRINTF("init_brightness: real brightness=%d\n", val); 746 sc->sc_brightness_save = sc->sc_brightness = val; 747 } else { 748 sc->sc_brightness_save = 749 sc->sc_brightness = sc->sc_max_brightness; 750 } 751 sc->sc_lcd_inited |= BRIGHTNESS_INITED; 752 } else if (inattach) { 753 /* 754 we cannot get real brightness in attach time 755 because brightness device not yet attached. 756 we will retry in !inattach. 757 */ 758 sc->sc_max_brightness = -1; 759 sc->sc_brightness = -1; 760 sc->sc_brightness_save = -1; 761 } else { 762 /* we cannot get real brightness */ 763 sc->sc_lcd_inited |= BRIGHTNESS_INITED; 764 } 765 766 return; 767 } 768 769 770 void 771 mq200_init_contrast(struct mq200_softc *sc, int inattach) 772 { 773 int val = -1; 774 775 if (sc->sc_lcd_inited&CONTRAST_INITED) 776 return; 777 778 VPRINTF("init_contrast\n"); 779 if (config_hook_call(CONFIG_HOOK_GET, 780 CONFIG_HOOK_CONTRAST_MAX, &val) != -1) { 781 /* we can get real contrast max */ 782 VPRINTF("init_contrast: real contrast max=%d\n", val); 783 sc->sc_max_contrast = val; 784 val = -1; 785 if (config_hook_call(CONFIG_HOOK_GET, 786 CONFIG_HOOK_CONTRAST, &val) != -1) { 787 /* we can get real contrast */ 788 VPRINTF("init_contrast: real contrast=%d\n", val); 789 sc->sc_contrast = val; 790 } else { 791 sc->sc_contrast = sc->sc_max_contrast; 792 } 793 sc->sc_lcd_inited |= CONTRAST_INITED; 794 } else if (inattach) { 795 /* 796 we cannot get real contrast in attach time 797 because contrast device not yet attached. 798 we will retry in !inattach. 799 */ 800 sc->sc_max_contrast = -1; 801 sc->sc_contrast = -1; 802 } else { 803 /* we cannot get real contrast */ 804 sc->sc_lcd_inited |= CONTRAST_INITED; 805 } 806 807 return; 808 } 809 810 811 void 812 mq200_set_brightness(struct mq200_softc *sc, int val) 813 { 814 sc->sc_brightness = val; 815 816 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val); 817 if (config_hook_call(CONFIG_HOOK_GET, 818 CONFIG_HOOK_BRIGHTNESS, &val) != -1) { 819 sc->sc_brightness = val; 820 } 821 } 822 823 void 824 mq200_set_contrast(struct mq200_softc *sc, int val) 825 { 826 sc->sc_contrast = val; 827 828 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val); 829 if (config_hook_call(CONFIG_HOOK_GET, 830 CONFIG_HOOK_CONTRAST, &val) != -1) { 831 sc->sc_contrast = val; 832 } 833 } 834