1 /* $NetBSD: ite8181.c,v 1.20 2003/11/13 03:09:28 chs Exp $ */ 2 3 /*- 4 * Copyright (c) 2000,2001 SATO Kazumi 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: ite8181.c,v 1.20 2003/11/13 03:09:28 chs Exp $"); 32 33 #include <sys/param.h> 34 #include <sys/kernel.h> 35 #include <sys/device.h> 36 #include <sys/systm.h> 37 #include <sys/boot_flag.h> 38 #include <sys/buf.h> 39 40 #include <uvm/uvm_extern.h> 41 42 #include <dev/wscons/wsconsio.h> 43 44 #include <machine/bootinfo.h> 45 #include <machine/bus.h> 46 #include <machine/autoconf.h> 47 #include <machine/config_hook.h> 48 #include <machine/platid.h> 49 #include <machine/platid_mask.h> 50 51 #include <hpcmips/dev/ite8181reg.h> 52 #include <hpcmips/dev/ite8181var.h> 53 #include "bivideo.h" 54 #if NBIVIDEO > 0 55 #include <dev/hpc/bivideovar.h> 56 #endif 57 #include <dev/hpc/hpccmapvar.h> 58 59 #define ITE8181DEBUG 60 #ifdef ITE8181DEBUG 61 #ifndef ITE8181DEBUG_CONF 62 #define ITE8181DEBUG_CONF 0 63 #endif 64 int ite8181_debug = ITE8181DEBUG_CONF; 65 #define DPRINTF(arg) if (ite8181_debug) printf arg 66 #define DPRINTFN(n, arg) if (ite8181_debug > (n)) printf arg 67 #define VPRINTF(arg) if (bootverbose || ite8181_debug) printf arg 68 #define VPRINTFN(n, arg) if (bootverbose || ite8181_debug > (n)) printf arg 69 #else 70 #define DPRINTF(arg) 71 #define DPRINTFN(n, arg) 72 #define VPRINTF(arg) if (bootverbose) printf arg 73 #define VPRINTFN(n, arg) if (bootverbose) printf arg 74 #endif 75 76 #ifndef ITE8181_LCD_CONTROL_ENABLE 77 int ite8181_lcd_control_disable = 1; 78 #else /* ITE8181_LCD_CONTROL_ENABLE */ 79 int ite8181_lcd_control_disable = 0; 80 #endif /* ITE8181_LCD_CONTROL_ENABLE */ 81 82 #define ITE8181_WINCE_CMAP 83 84 /* 85 * XXX: 86 * IBM WorkPad z50 power unit has too weak power. 87 * So we must wait too many times to access some device 88 * after LCD panel and BackLight on. 89 * Currently delay is not enough ??? FIXME 90 */ 91 #ifndef ITE8181_LCD_ON_SELF_DELAY 92 #define ITE8181_LCD_ON_SELF_DELAY 1000 93 #endif /* ITE8181_LCD_ON__SELF_DELAY */ 94 #ifndef ITE8181_LCD_ON_DELAY 95 #define ITE8181_LCD_ON_DELAY 2000 96 #endif /* ITE8181_LCD_ON_DELAY */ 97 int ite8181_lcd_on_self_delay = ITE8181_LCD_ON_SELF_DELAY; /* msec */ 98 int ite8181_lcd_on_delay = ITE8181_LCD_ON_DELAY; /* msec */ 99 100 #define MSEC 1000 101 /* 102 * function prototypes 103 */ 104 static void ite8181_config_write_4(bus_space_tag_t, bus_space_handle_t, 105 int, int); 106 static int ite8181_config_read_4(bus_space_tag_t, bus_space_handle_t, 107 int); 108 static void ite8181_gui_write_4(struct ite8181_softc *, int, int); 109 static int ite8181_gui_read_4(struct ite8181_softc *, int); 110 111 static void ite8181_gui_write_1(struct ite8181_softc *, int, int); 112 static int ite8181_gui_read_1(struct ite8181_softc *, int); 113 114 static void ite8181_graphics_write_1(struct ite8181_softc *, int, int); 115 static int ite8181_graphics_read_1(struct ite8181_softc *, int); 116 117 static void ite8181_ema_write_1(struct ite8181_softc *, int, int); 118 static int ite8181_ema_read_1(struct ite8181_softc *, int); 119 120 static void ite8181_power(int, void *); 121 static int ite8181_hardpower(void *, int, long, void *); 122 static int ite8181_fbinit(struct hpcfb_fbconf *); 123 static int ite8181_ioctl(void *, u_long, caddr_t, int, struct proc *); 124 static paddr_t ite8181_mmap(void *, off_t offset, int); 125 static void ite8181_erase_cursor(struct ite8181_softc *); 126 static int ite8181_lcd_power(struct ite8181_softc *, int); 127 128 static void ite8181_update_powerstate(struct ite8181_softc *, int); 129 void ite8181_init_backlight(struct ite8181_softc *, int); 130 void ite8181_init_brightness(struct ite8181_softc *, int); 131 void ite8181_init_contrast(struct ite8181_softc *, int); 132 void ite8181_set_brightness(struct ite8181_softc *, int); 133 void ite8181_set_contrast(struct ite8181_softc *, int); 134 135 /* 136 * static variables 137 */ 138 struct hpcfb_accessops ite8181_ha = { 139 ite8181_ioctl, ite8181_mmap 140 }; 141 142 inline int 143 ite8181_config_read_4(bus_space_tag_t iot, bus_space_handle_t ioh, 144 int byteoffset) 145 { 146 147 return (bus_space_read_4(iot, ioh, ITE8181_CONF_OFFSET + byteoffset)); 148 } 149 150 inline void 151 ite8181_config_write_4(bus_space_tag_t iot, bus_space_handle_t ioh, 152 int byteoffset, int data) 153 { 154 155 bus_space_write_4(iot, ioh, ITE8181_CONF_OFFSET + byteoffset, data); 156 } 157 158 inline int 159 ite8181_gui_read_4(struct ite8181_softc *sc, int byteoffset) 160 { 161 162 return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, 163 sc->sc_gba + byteoffset)); 164 } 165 166 inline void 167 ite8181_gui_write_4(struct ite8181_softc *sc, int byteoffset, int data) 168 { 169 170 bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_gba + byteoffset, 171 data); 172 } 173 174 inline int 175 ite8181_gui_read_1(struct ite8181_softc *sc, int byteoffset) 176 { 177 178 return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, 179 sc->sc_gba + byteoffset)); 180 } 181 182 inline void 183 ite8181_gui_write_1(struct ite8181_softc *sc, int byteoffset, int data) 184 { 185 186 bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_gba + byteoffset, 187 data); 188 } 189 190 inline int 191 ite8181_graphics_read_1(struct ite8181_softc *sc, int byteoffset) 192 { 193 194 return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, 195 sc->sc_sba + byteoffset)); 196 } 197 198 inline void 199 ite8181_graphics_write_1(struct ite8181_softc *sc, int byteoffset, int data) 200 { 201 202 bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_sba + byteoffset, 203 data); 204 } 205 206 inline int 207 ite8181_ema_read_1(struct ite8181_softc *sc, int byteoffset) 208 { 209 210 ite8181_graphics_write_1(sc, ITE8181_EMA_EXAX, byteoffset); 211 return (ite8181_graphics_read_1(sc, ITE8181_EMA_EXADATA)); 212 } 213 214 inline void 215 ite8181_ema_write_1(struct ite8181_softc *sc, int byteoffset, int data) 216 { 217 218 ite8181_graphics_write_1(sc, ITE8181_EMA_EXAX, byteoffset); 219 ite8181_graphics_write_1(sc, ITE8181_EMA_EXADATA, data); 220 } 221 222 int 223 ite8181_probe(bus_space_tag_t iot, bus_space_handle_t ioh) 224 { 225 unsigned long regval; 226 227 #if NBIVIDEO > 0 228 if (bivideo_dont_attach) /* some video driver already attached */ 229 return (0); 230 #endif /* NBIVIDEO > 0 */ 231 232 regval = ite8181_config_read_4(iot, ioh, ITE8181_ID); 233 VPRINTF(("ite8181_probe: vendor id=%04lx product id=%04lx\n", 234 regval & 0xffff, (regval >> 16) & 0xffff)); 235 if (regval != ((ITE8181_PRODUCT_ID << 16) | ITE8181_VENDER_ID)) 236 return (0); 237 238 return (1); 239 } 240 241 void 242 ite8181_attach(struct ite8181_softc *sc) 243 { 244 unsigned long regval; 245 struct hpcfb_attach_args ha; 246 int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1; 247 248 printf(": "); 249 if (ite8181_fbinit(&sc->sc_fbconf) != 0) { 250 /* just return so that hpcfb will not be attached */ 251 return; 252 } 253 254 regval = ite8181_config_read_4(sc->sc_iot, sc->sc_ioh, ITE8181_CLASS); 255 printf("ITE8181 Rev.%02lx", regval & ITE8181_REV_MASK); 256 if (console) { 257 printf(", console"); 258 } 259 printf("\n"); 260 printf("%s: framebuffer address: 0x%08lx\n", 261 sc->sc_dev.dv_xname, (u_long)bootinfo->fb_addr); 262 if (ite8181_lcd_control_disable) 263 printf("%s: ite8181 lcd control is DISABLED.\n", 264 sc->sc_dev.dv_xname); 265 266 /* set base offsets */ 267 sc->sc_mba = ite8181_config_read_4(sc->sc_iot, sc->sc_ioh, ITE8181_MBA); 268 DPRINTFN(1, ("ite8181: Memory base offset %08x\n", sc->sc_mba)); 269 sc->sc_gba = ite8181_config_read_4(sc->sc_iot, sc->sc_ioh, ITE8181_GBA); 270 DPRINTFN(1, ("ite8181: GUI base offset %08x\n", sc->sc_gba)); 271 sc->sc_sba = ite8181_config_read_4(sc->sc_iot, sc->sc_ioh, ITE8181_SBA); 272 DPRINTFN(1, ("ite8181: Graphics base offset %08x\n", sc->sc_sba)); 273 274 /* assume lcd is on */ 275 sc->sc_lcd = 1; 276 /* erase wince cursor */ 277 ite8181_erase_cursor(sc); 278 279 /* Add a power hook to power saving */ 280 sc->sc_powerhook = powerhook_establish(ite8181_power, sc); 281 if (sc->sc_powerhook == NULL) 282 printf("%s: WARNING: unable to establish power hook\n", 283 sc->sc_dev.dv_xname); 284 285 /* Add a hard power hook to power saving */ 286 sc->sc_hardpowerhook = config_hook(CONFIG_HOOK_PMEVENT, 287 CONFIG_HOOK_PMEVENT_HARDPOWER, 288 CONFIG_HOOK_SHARE, 289 ite8181_hardpower, sc); 290 if (sc->sc_hardpowerhook == NULL) 291 printf("%s: WARNING: unable to establish hard power hook\n", 292 sc->sc_dev.dv_xname); 293 294 /* initialize backlight brightness and lcd contrast */ 295 sc->sc_lcd_inited = 0; 296 ite8181_init_brightness(sc, 1); 297 ite8181_init_contrast(sc, 1); 298 ite8181_init_backlight(sc, 1); 299 300 if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0) { 301 panic("ite8181_attach: can't init fb console"); 302 } 303 304 ha.ha_console = console; 305 ha.ha_accessops = &ite8181_ha; 306 ha.ha_accessctx = sc; 307 ha.ha_curfbconf = 0; 308 ha.ha_nfbconf = 1; 309 ha.ha_fbconflist = &sc->sc_fbconf; 310 ha.ha_curdspconf = 0; 311 ha.ha_ndspconf = 1; 312 ha.ha_dspconflist = &sc->sc_dspconf; 313 314 config_found(&sc->sc_dev, &ha, hpcfbprint); 315 316 #if NBIVIDEO > 0 317 /* 318 * bivideo is no longer need 319 */ 320 bivideo_dont_attach = 1; 321 #endif /* NBIVIDEO > 0 */ 322 } 323 324 int 325 ite8181_lcd_power(struct ite8181_softc *sc, int on) 326 { 327 int lcd_p; 328 int lcd_s; 329 int lcd_seq; 330 int loop = 10; 331 332 if (ite8181_lcd_control_disable) { 333 VPRINTF(("ite8171_lcd_control_disable!: %s\n", on?"on":"off")); 334 return 0; 335 } 336 337 if (sc->sc_lcd != on) { 338 ite8181_ema_write_1(sc, ITE8181_EMA_ENABLEEMA, 339 ITE8181_EMA_ENABLEPASS); 340 lcd_p = ite8181_ema_read_1(sc, ITE8181_EMA_LCDPOWER); 341 lcd_s = ite8181_ema_read_1(sc, ITE8181_EMA_LCDPOWERSTAT); 342 lcd_seq = ite8181_ema_read_1(sc, ITE8181_EMA_LCDPOWERSEQ); 343 DPRINTFN(1,("ite8181_lcd_power(%d)< p=%x, s=%x, seq=%x\n", 344 on, 345 lcd_p, lcd_s, lcd_seq)); 346 if (on) { 347 sc->sc_lcd = 1; 348 lcd_seq |= (ITE8181_PUP0|ITE8181_PUP1|ITE8181_PUP2); 349 ite8181_ema_write_1(sc, ITE8181_EMA_LCDPOWERSEQ, 350 lcd_seq); 351 lcd_p &= ~ITE8181_LCDSTANDBY; 352 ite8181_ema_write_1(sc, ITE8181_EMA_LCDPOWER, lcd_p); 353 /* 354 * XXX: 355 * IBM WorkPad z50 power unit has too weak power. 356 * So we must wait too many times to access self device 357 * after LCD panel and BackLight on. 358 * Currently delay is not enough ??? FIXME 359 */ 360 delay(ite8181_lcd_on_self_delay*MSEC); 361 while (loop--) { 362 lcd_p = ite8181_ema_read_1(sc, 363 ITE8181_EMA_LCDPOWER); 364 lcd_s = ite8181_ema_read_1(sc, 365 ITE8181_EMA_LCDPOWERSTAT); 366 lcd_seq = ite8181_ema_read_1(sc, 367 ITE8181_EMA_LCDPOWERSEQ); 368 DPRINTFN(1,("ite8181_lcd_power(%d)%d| p=%x," 369 " s=%x, seq=%x\n", on, loop, lcd_p, lcd_s, 370 lcd_seq)); 371 /* 372 * XXX the states which are not described 373 * XXX in manual. 374 */ 375 if (!(lcd_s&ITE8181_LCDPSTANDBY) && 376 !(lcd_s&ITE8181_LCDPUP) && 377 (lcd_s&ITE8181_LCDPON)) 378 break; 379 delay(100); 380 } 381 lcd_s |= ITE8181_PPTOBEON; 382 ite8181_ema_write_1(sc, ITE8181_EMA_LCDPOWERSTAT, 383 lcd_s); 384 } else { 385 sc->sc_lcd = 0; 386 lcd_p |= ITE8181_LCDSTANDBY; 387 ite8181_ema_write_1(sc, ITE8181_EMA_LCDPOWER, lcd_p); 388 while (loop--) { 389 lcd_p = ite8181_ema_read_1(sc, 390 ITE8181_EMA_LCDPOWER); 391 lcd_s = ite8181_ema_read_1(sc, 392 ITE8181_EMA_LCDPOWERSTAT); 393 lcd_seq = ite8181_ema_read_1(sc, 394 ITE8181_EMA_LCDPOWERSEQ); 395 DPRINTFN(1,("ite8181_lcd_power(%d)%d| p=%x," 396 " s=%x, seq=%x\n", on, loop, lcd_p, lcd_s, 397 lcd_seq)); 398 /* 399 * XXX the states which are not described 400 * XXX in manual. 401 */ 402 if ((lcd_s&ITE8181_LCDPSTANDBY) && 403 !(lcd_s&ITE8181_LCDPDOWN) && 404 !(lcd_s&ITE8181_LCDPON)) 405 break; 406 delay(100); 407 } 408 lcd_s &= ~ITE8181_PPTOBEON; 409 ite8181_ema_write_1(sc, ITE8181_EMA_LCDPOWERSTAT, 410 lcd_s); 411 } 412 DPRINTFN(1,("ite8181_lcd_power(%d)> p=%x, s=%x, seq=%x\n", 413 on, 414 ite8181_ema_read_1(sc, ITE8181_EMA_LCDPOWER), 415 ite8181_ema_read_1(sc, ITE8181_EMA_LCDPOWERSTAT), 416 ite8181_ema_read_1(sc, ITE8181_EMA_LCDPOWERSEQ))); 417 ite8181_ema_write_1(sc, ITE8181_EMA_ENABLEEMA, 418 ITE8181_EMA_DISABLEPASS); 419 } 420 return 0; 421 } 422 423 static void 424 ite8181_erase_cursor(struct ite8181_softc *sc) 425 { 426 ite8181_gui_write_1(sc, ITE8181_GUI_C1C, 0); /* Cursor 1 Control Reg. */ 427 /* other ? */ 428 } 429 430 static void 431 ite8181_update_powerstate(struct ite8181_softc *sc, int updates) 432 { 433 if (updates & PWRSTAT_LCD) 434 config_hook_call(CONFIG_HOOK_POWERCONTROL, 435 CONFIG_HOOK_POWERCONTROL_LCD, 436 (void*)!(sc->sc_powerstate & 437 (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND))); 438 439 if (updates & PWRSTAT_BACKLIGHT) 440 config_hook_call(CONFIG_HOOK_POWERCONTROL, 441 CONFIG_HOOK_POWERCONTROL_LCDLIGHT, 442 (void*)(!(sc->sc_powerstate & 443 (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)) && 444 (sc->sc_powerstate & PWRSTAT_BACKLIGHT))); 445 } 446 447 static void 448 ite8181_power(int why, void *arg) 449 { 450 struct ite8181_softc *sc = arg; 451 452 switch (why) { 453 case PWR_STANDBY: 454 sc->sc_powerstate |= PWRSTAT_SUSPEND; 455 ite8181_update_powerstate(sc, PWRSTAT_ALL); 456 break; 457 case PWR_SUSPEND: 458 sc->sc_powerstate |= PWRSTAT_SUSPEND; 459 ite8181_update_powerstate(sc, PWRSTAT_ALL); 460 break; 461 case PWR_RESUME: 462 sc->sc_powerstate &= ~PWRSTAT_SUSPEND; 463 ite8181_update_powerstate(sc, PWRSTAT_ALL); 464 break; 465 } 466 } 467 468 static int 469 ite8181_hardpower(void *ctx, int type, long id, void *msg) 470 { 471 struct ite8181_softc *sc = ctx; 472 int why = (int)msg; 473 474 switch (why) { 475 case PWR_STANDBY: 476 /* ite8181_lcd_power(sc, 0); */ 477 delay(MSEC); 478 break; 479 case PWR_SUSPEND: 480 ite8181_lcd_power(sc, 0); 481 delay(MSEC); 482 break; 483 case PWR_RESUME: 484 delay(MSEC); 485 ite8181_lcd_power(sc, 1); 486 /* 487 * XXX: 488 * IBM WorkPad z50 power unit has too weak power. 489 * So we must wait too many times to access other devices 490 * after LCD panel and BackLight on. 491 */ 492 delay(ite8181_lcd_on_delay*MSEC); 493 break; 494 } 495 496 /* 497 * you should wait until the 498 * power state transit sequence will end. 499 */ 500 501 return (0); 502 } 503 504 static int 505 ite8181_fbinit(struct hpcfb_fbconf *fb) 506 { 507 508 /* 509 * get fb settings from bootinfo 510 */ 511 if (bootinfo == NULL || 512 bootinfo->fb_addr == 0 || 513 bootinfo->fb_line_bytes == 0 || 514 bootinfo->fb_width == 0 || 515 bootinfo->fb_height == 0) { 516 printf("no frame buffer information.\n"); 517 return (-1); 518 } 519 520 /* zero fill */ 521 bzero(fb, sizeof(*fb)); 522 523 fb->hf_conf_index = 0; /* configuration index */ 524 fb->hf_nconfs = 1; /* how many configurations */ 525 strcpy(fb->hf_name, "built-in video"); 526 /* frame buffer name */ 527 strcpy(fb->hf_conf_name, "default"); 528 /* configuration name */ 529 fb->hf_height = bootinfo->fb_height; 530 fb->hf_width = bootinfo->fb_width; 531 fb->hf_baseaddr = (u_long)bootinfo->fb_addr; 532 fb->hf_offset = (u_long)bootinfo->fb_addr - 533 mips_ptob(mips_btop(bootinfo->fb_addr)); 534 /* frame buffer start offset */ 535 fb->hf_bytes_per_line = bootinfo->fb_line_bytes; 536 fb->hf_nplanes = 1; 537 fb->hf_bytes_per_plane = bootinfo->fb_height * 538 bootinfo->fb_line_bytes; 539 540 fb->hf_access_flags |= HPCFB_ACCESS_BYTE; 541 fb->hf_access_flags |= HPCFB_ACCESS_WORD; 542 fb->hf_access_flags |= HPCFB_ACCESS_DWORD; 543 544 switch (bootinfo->fb_type) { 545 /* 546 * gray scale 547 */ 548 case BIFB_D2_M2L_3: 549 case BIFB_D2_M2L_3x2: 550 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 551 /* fall through */ 552 case BIFB_D2_M2L_0: 553 case BIFB_D2_M2L_0x2: 554 fb->hf_class = HPCFB_CLASS_GRAYSCALE; 555 fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 556 fb->hf_pack_width = 8; 557 fb->hf_pixels_per_pack = 4; 558 fb->hf_pixel_width = 2; 559 fb->hf_class_data_length = sizeof(struct hf_gray_tag); 560 fb->hf_u.hf_gray.hf_flags = 0; /* reserved for future use */ 561 break; 562 563 case BIFB_D4_M2L_F: 564 case BIFB_D4_M2L_Fx2: 565 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 566 /* fall through */ 567 case BIFB_D4_M2L_0: 568 case BIFB_D4_M2L_0x2: 569 fb->hf_class = HPCFB_CLASS_GRAYSCALE; 570 fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 571 fb->hf_pack_width = 8; 572 fb->hf_pixels_per_pack = 2; 573 fb->hf_pixel_width = 4; 574 fb->hf_class_data_length = sizeof(struct hf_gray_tag); 575 fb->hf_u.hf_gray.hf_flags = 0; /* reserved for future use */ 576 break; 577 578 /* 579 * indexed color 580 */ 581 case BIFB_D8_FF: 582 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 583 /* fall through */ 584 case BIFB_D8_00: 585 fb->hf_class = HPCFB_CLASS_INDEXCOLOR; 586 fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 587 fb->hf_pack_width = 8; 588 fb->hf_pixels_per_pack = 1; 589 fb->hf_pixel_width = 8; 590 fb->hf_class_data_length = sizeof(struct hf_indexed_tag); 591 fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */ 592 break; 593 594 /* 595 * RGB color 596 */ 597 case BIFB_D16_FFFF: 598 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 599 /* fall through */ 600 case BIFB_D16_0000: 601 fb->hf_class = HPCFB_CLASS_RGBCOLOR; 602 fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 603 fb->hf_order_flags = HPCFB_REVORDER_BYTE; 604 fb->hf_pack_width = 16; 605 fb->hf_pixels_per_pack = 1; 606 fb->hf_pixel_width = 16; 607 608 fb->hf_class_data_length = sizeof(struct hf_rgb_tag); 609 fb->hf_u.hf_rgb.hf_flags = 0; /* reserved for future use */ 610 611 fb->hf_u.hf_rgb.hf_red_width = 5; 612 fb->hf_u.hf_rgb.hf_red_shift = 11; 613 fb->hf_u.hf_rgb.hf_green_width = 6; 614 fb->hf_u.hf_rgb.hf_green_shift = 5; 615 fb->hf_u.hf_rgb.hf_blue_width = 5; 616 fb->hf_u.hf_rgb.hf_blue_shift = 0; 617 fb->hf_u.hf_rgb.hf_alpha_width = 0; 618 fb->hf_u.hf_rgb.hf_alpha_shift = 0; 619 break; 620 621 default: 622 printf("unknown type (=%d).\n", bootinfo->fb_type); 623 return (-1); 624 break; 625 } 626 627 return (0); /* no error */ 628 } 629 630 int 631 ite8181_ioctl(v, cmd, data, flag, p) 632 void *v; 633 u_long cmd; 634 caddr_t data; 635 int flag; 636 struct proc *p; 637 { 638 struct ite8181_softc *sc = (struct ite8181_softc *)v; 639 struct hpcfb_fbconf *fbconf; 640 struct hpcfb_dspconf *dspconf; 641 struct wsdisplay_cmap *cmap; 642 struct wsdisplay_param *dispparam; 643 int error; 644 645 switch (cmd) { 646 case WSDISPLAYIO_GETCMAP: 647 cmap = (struct wsdisplay_cmap *)data; 648 649 if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR || 650 sc->sc_fbconf.hf_pack_width != 8 || 651 256 <= cmap->index || 652 256 - cmap->index < cmap->count) 653 return (EINVAL); 654 655 #ifdef ITE8181_WINCE_CMAP 656 error = copyout(&bivideo_cmap_r[cmap->index], cmap->red, 657 cmap->count); 658 if (error) 659 return error; 660 error = copyout(&bivideo_cmap_g[cmap->index], cmap->green, 661 cmap->count); 662 if (error) 663 return error; 664 error = copyout(&bivideo_cmap_b[cmap->index], cmap->blue, 665 cmap->count); 666 return error; 667 #else /* ITE8181_WINCE_CMAP */ 668 return EINVAL; 669 #endif /* ITE8181_WINCE_CMAP */ 670 671 case WSDISPLAYIO_PUTCMAP: 672 /* 673 * This driver can't set color map. 674 */ 675 return (EINVAL); 676 677 case WSDISPLAYIO_SVIDEO: 678 if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) 679 sc->sc_powerstate |= PWRSTAT_VIDEOOFF; 680 else 681 sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF; 682 ite8181_update_powerstate(sc, PWRSTAT_ALL); 683 return 0; 684 685 case WSDISPLAYIO_GVIDEO: 686 *(int *)data = (sc->sc_powerstate&PWRSTAT_VIDEOOFF) ? 687 WSDISPLAYIO_VIDEO_OFF:WSDISPLAYIO_VIDEO_ON; 688 return 0; 689 690 691 case WSDISPLAYIO_GETPARAM: 692 dispparam = (struct wsdisplay_param*)data; 693 switch (dispparam->param) { 694 case WSDISPLAYIO_PARAM_BACKLIGHT: 695 VPRINTF(("ite8181_ioctl: GET:BACKLIGHT\n")); 696 ite8181_init_brightness(sc, 0); 697 ite8181_init_backlight(sc, 0); 698 VPRINTF(("ite8181_ioctl: GET:(real)BACKLIGHT %d\n", 699 (sc->sc_powerstate&PWRSTAT_BACKLIGHT)? 1: 0)); 700 dispparam->min = 0; 701 dispparam->max = 1; 702 if (sc->sc_max_brightness > 0) 703 dispparam->curval = 704 sc->sc_brightness > 0 ? 1: 0; 705 else 706 dispparam->curval = 707 (sc->sc_powerstate & PWRSTAT_BACKLIGHT) 708 ? 1: 0; 709 VPRINTF(("ite8181_ioctl: GET:BACKLIGHT:%d(%s)\n", 710 dispparam->curval, 711 sc->sc_max_brightness > 0? "brightness": "light")); 712 return 0; 713 break; 714 case WSDISPLAYIO_PARAM_CONTRAST: 715 VPRINTF(("ite8181_ioctl: GET:CONTRAST\n")); 716 ite8181_init_contrast(sc, 0); 717 if (sc->sc_max_contrast > 0) { 718 dispparam->min = 0; 719 dispparam->max = sc->sc_max_contrast; 720 dispparam->curval = sc->sc_contrast; 721 VPRINTF(("ite8181_ioctl: GET:CONTRAST max=%d," 722 " current=%d\n", sc->sc_max_contrast, 723 sc->sc_contrast)); 724 return 0; 725 } else { 726 VPRINTF(("ite8181_ioctl: " 727 "GET:CONTRAST EINVAL\n")); 728 return (EINVAL); 729 } 730 break; 731 case WSDISPLAYIO_PARAM_BRIGHTNESS: 732 VPRINTF(("ite8181_ioctl: GET:BRIGHTNESS\n")); 733 ite8181_init_brightness(sc, 0); 734 if (sc->sc_max_brightness > 0) { 735 dispparam->min = 0; 736 dispparam->max = sc->sc_max_brightness; 737 dispparam->curval = sc->sc_brightness; 738 VPRINTF(("ite8181_ioctl: GET:BRIGHTNESS" 739 " max=%d, current=%d\n", 740 sc->sc_max_brightness, sc->sc_brightness)); 741 return 0; 742 } else { 743 VPRINTF(("ite8181_ioctl: GET:BRIGHTNESS" 744 " EINVAL\n")); 745 return (EINVAL); 746 } 747 return (EINVAL); 748 default: 749 return (EINVAL); 750 } 751 return (0); 752 753 case WSDISPLAYIO_SETPARAM: 754 dispparam = (struct wsdisplay_param*)data; 755 switch (dispparam->param) { 756 case WSDISPLAYIO_PARAM_BACKLIGHT: 757 VPRINTF(("ite8181_ioctl: SET:BACKLIGHT\n")); 758 if (dispparam->curval < 0 || 759 1 < dispparam->curval) 760 return (EINVAL); 761 ite8181_init_brightness(sc, 0); 762 VPRINTF(("ite8181_ioctl: SET:max brightness=%d\n", 763 sc->sc_max_brightness)); 764 if (sc->sc_max_brightness > 0) { /* dimmer */ 765 if (dispparam->curval == 0){ 766 sc->sc_brightness_save = 767 sc->sc_brightness; 768 ite8181_set_brightness(sc, 0);/* min */ 769 } else { 770 if (sc->sc_brightness_save == 0) 771 sc->sc_brightness_save = 772 sc->sc_max_brightness; 773 ite8181_set_brightness(sc, 774 sc->sc_brightness_save); 775 } 776 VPRINTF(("ite8181_ioctl: SET:BACKLIGHT:" 777 "brightness=%d\n", sc->sc_brightness)); 778 } else { /* off */ 779 if (dispparam->curval == 0) 780 sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT; 781 else 782 sc->sc_powerstate |= PWRSTAT_BACKLIGHT; 783 VPRINTF(("ite8181_ioctl: SET:BACKLIGHT:" 784 "powerstate %d\n", 785 (sc->sc_powerstate & PWRSTAT_BACKLIGHT) 786 ? 1 : 0)); 787 ite8181_update_powerstate(sc, 788 PWRSTAT_BACKLIGHT); 789 VPRINTF(("ite8181_ioctl: SET:BACKLIGHT:%d\n", 790 (sc->sc_powerstate & PWRSTAT_BACKLIGHT) 791 ? 1 : 0)); 792 } 793 return 0; 794 break; 795 case WSDISPLAYIO_PARAM_CONTRAST: 796 VPRINTF(("ite8181_ioctl: SET:CONTRAST\n")); 797 ite8181_init_contrast(sc, 0); 798 if (dispparam->curval < 0 || 799 sc->sc_max_contrast < dispparam->curval) 800 return (EINVAL); 801 if (sc->sc_max_contrast > 0) { 802 int org = sc->sc_contrast; 803 ite8181_set_contrast(sc, dispparam->curval); 804 VPRINTF(("ite8181_ioctl: SET:CONTRAST" 805 " org=%d, current=%d\n", org, 806 sc->sc_contrast)); 807 return 0; 808 } else { 809 VPRINTF(("ite8181_ioctl: SET:CONTRAST" 810 " EINVAL\n")); 811 return (EINVAL); 812 } 813 break; 814 case WSDISPLAYIO_PARAM_BRIGHTNESS: 815 VPRINTF(("ite8181_ioctl: SET:BRIGHTNESS\n")); 816 ite8181_init_brightness(sc, 0); 817 if (dispparam->curval < 0 || 818 sc->sc_max_brightness < dispparam->curval) 819 return (EINVAL); 820 if (sc->sc_max_brightness > 0) { 821 int org = sc->sc_brightness; 822 ite8181_set_brightness(sc, dispparam->curval); 823 VPRINTF(("ite8181_ioctl: SET:BRIGHTNESS" 824 " org=%d, current=%d\n", org, 825 sc->sc_brightness)); 826 return 0; 827 } else { 828 VPRINTF(("ite8181_ioctl: SET:BRIGHTNESS" 829 " EINVAL\n")); 830 return (EINVAL); 831 } 832 break; 833 default: 834 return (EINVAL); 835 } 836 return (0); 837 838 case HPCFBIO_GCONF: 839 fbconf = (struct hpcfb_fbconf *)data; 840 if (fbconf->hf_conf_index != 0 && 841 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) { 842 return (EINVAL); 843 } 844 *fbconf = sc->sc_fbconf; /* structure assignment */ 845 return (0); 846 case HPCFBIO_SCONF: 847 fbconf = (struct hpcfb_fbconf *)data; 848 if (fbconf->hf_conf_index != 0 && 849 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) { 850 return (EINVAL); 851 } 852 /* 853 * nothing to do because we have only one configration 854 */ 855 return (0); 856 case HPCFBIO_GDSPCONF: 857 dspconf = (struct hpcfb_dspconf *)data; 858 if ((dspconf->hd_unit_index != 0 && 859 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) || 860 (dspconf->hd_conf_index != 0 && 861 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) { 862 return (EINVAL); 863 } 864 *dspconf = sc->sc_dspconf; /* structure assignment */ 865 return (0); 866 case HPCFBIO_SDSPCONF: 867 dspconf = (struct hpcfb_dspconf *)data; 868 if ((dspconf->hd_unit_index != 0 && 869 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) || 870 (dspconf->hd_conf_index != 0 && 871 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) { 872 return (EINVAL); 873 } 874 /* 875 * nothing to do 876 * because we have only one unit and one configration 877 */ 878 return (0); 879 case HPCFBIO_GOP: 880 case HPCFBIO_SOP: 881 /* 882 * curently not implemented... 883 */ 884 return (EINVAL); 885 } 886 887 return (EPASSTHROUGH); 888 } 889 890 paddr_t 891 ite8181_mmap(void *ctx, off_t offset, int prot) 892 { 893 struct ite8181_softc *sc = (struct ite8181_softc *)ctx; 894 895 if (offset < 0 || 896 (sc->sc_fbconf.hf_bytes_per_plane + 897 sc->sc_fbconf.hf_offset) < offset) 898 return -1; 899 900 return mips_btop((u_long)bootinfo->fb_addr + offset); 901 } 902 903 904 void 905 ite8181_init_backlight(struct ite8181_softc *sc, int inattach) 906 { 907 int val = -1; 908 909 if (sc->sc_lcd_inited&BACKLIGHT_INITED) 910 return; 911 912 if (config_hook_call(CONFIG_HOOK_GET, 913 CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) { 914 /* we can get real light state */ 915 VPRINTF(("ite8181_init_backlight: real backlight=%d\n", val)); 916 if (val == 0) 917 sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT; 918 else 919 sc->sc_powerstate |= PWRSTAT_BACKLIGHT; 920 sc->sc_lcd_inited |= BACKLIGHT_INITED; 921 } else if (inattach) { 922 /* 923 we cannot get real light state in attach time 924 because light device not yet attached. 925 we will retry in !inattach. 926 temporary assume light is on. 927 */ 928 sc->sc_powerstate |= PWRSTAT_BACKLIGHT; 929 } else { 930 /* we cannot get real light state, so work by myself state */ 931 sc->sc_lcd_inited |= BACKLIGHT_INITED; 932 } 933 } 934 935 void 936 ite8181_init_brightness(struct ite8181_softc *sc, int inattach) 937 { 938 int val = -1; 939 940 if (sc->sc_lcd_inited&BRIGHTNESS_INITED) 941 return; 942 943 VPRINTF(("ite8181_init_brightness\n")); 944 if (config_hook_call(CONFIG_HOOK_GET, 945 CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) { 946 /* we can get real brightness max */ 947 VPRINTF(("ite8181_init_brightness: real brightness max=%d\n", 948 val)); 949 sc->sc_max_brightness = val; 950 val = -1; 951 if (config_hook_call(CONFIG_HOOK_GET, 952 CONFIG_HOOK_BRIGHTNESS, &val) != -1) { 953 /* we can get real brightness */ 954 VPRINTF(("ite8181_init_brightness:" 955 " real brightness=%d\n", val)); 956 sc->sc_brightness_save = sc->sc_brightness = val; 957 } else { 958 sc->sc_brightness_save = 959 sc->sc_brightness = sc->sc_max_brightness; 960 } 961 sc->sc_lcd_inited |= BRIGHTNESS_INITED; 962 } else if (inattach) { 963 /* 964 we cannot get real brightness in attach time 965 because brightness device not yet attached. 966 we will retry in !inattach. 967 */ 968 sc->sc_max_brightness = -1; 969 sc->sc_brightness = -1; 970 sc->sc_brightness_save = -1; 971 } else { 972 /* we cannot get real brightness */ 973 sc->sc_lcd_inited |= BRIGHTNESS_INITED; 974 } 975 976 return; 977 } 978 979 void 980 ite8181_init_contrast(struct ite8181_softc *sc, int inattach) 981 { 982 int val = -1; 983 984 if (sc->sc_lcd_inited&CONTRAST_INITED) 985 return; 986 987 VPRINTF(("ite8181_init_contrast\n")); 988 if (config_hook_call(CONFIG_HOOK_GET, 989 CONFIG_HOOK_CONTRAST_MAX, &val) != -1) { 990 /* we can get real contrast max */ 991 VPRINTF(("ite8181_init_contrast: real contrast max=%d\n", val)); 992 sc->sc_max_contrast = val; 993 val = -1; 994 if (config_hook_call(CONFIG_HOOK_GET, 995 CONFIG_HOOK_CONTRAST, &val) != -1) { 996 /* we can get real contrast */ 997 VPRINTF(("ite8181_init_contrast: real contrast=%d\n", 998 val)); 999 sc->sc_contrast = val; 1000 } else { 1001 sc->sc_contrast = sc->sc_max_contrast; 1002 } 1003 sc->sc_lcd_inited |= CONTRAST_INITED; 1004 } else if (inattach) { 1005 /* 1006 we cannot get real contrast in attach time 1007 because contrast device not yet attached. 1008 we will retry in !inattach. 1009 */ 1010 sc->sc_max_contrast = -1; 1011 sc->sc_contrast = -1; 1012 } else { 1013 /* we cannot get real contrast */ 1014 sc->sc_lcd_inited |= CONTRAST_INITED; 1015 } 1016 1017 return; 1018 } 1019 1020 1021 void 1022 ite8181_set_brightness(struct ite8181_softc *sc, int val) 1023 { 1024 1025 sc->sc_brightness = val; 1026 1027 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val); 1028 if (config_hook_call(CONFIG_HOOK_GET, 1029 CONFIG_HOOK_BRIGHTNESS, &val) != -1) { 1030 sc->sc_brightness = val; 1031 } 1032 } 1033 1034 void 1035 ite8181_set_contrast(struct ite8181_softc *sc, int val) 1036 { 1037 1038 sc->sc_contrast = val; 1039 1040 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val); 1041 if (config_hook_call(CONFIG_HOOK_GET, 1042 CONFIG_HOOK_CONTRAST, &val) != -1) { 1043 sc->sc_contrast = val; 1044 } 1045 } 1046