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