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