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