No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / hpcmips / dev / mq200.c
blob27b8e02a077b49bb72b4afd4a10f8a964aef2ddd
1 /* $NetBSD: mq200.c,v 1.29 2009/03/14 21:04:09 dsl Exp $ */
3 /*-
4 * Copyright (c) 2000, 2001 TAKEMURA Shin
5 * All rights reserved.
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.
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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mq200.c,v 1.29 2009/03/14 21:04:09 dsl Exp $");
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>
41 #include <uvm/uvm_extern.h>
43 #include <dev/wscons/wsconsio.h>
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>
52 #include "opt_mq200.h"
53 #include <hpcmips/dev/mq200reg.h>
54 #include <hpcmips/dev/mq200var.h>
55 #include <hpcmips/dev/mq200priv.h>
57 #include "bivideo.h"
58 #if NBIVIDEO > 0
59 #include <dev/hpc/bivideovar.h>
60 #endif
63 * function prototypes
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, void *, int, struct lwp *);
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);
78 * static variables
80 struct hpcfb_accessops mq200_ha = {
81 mq200_ioctl, mq200_mmap
84 #ifdef MQ200_DEBUG
85 int mq200_debug = MQ200DEBUG_CONF;
86 #endif
88 int
89 mq200_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
91 unsigned long regval;
93 #if NBIVIDEO > 0
94 if (bivideo_dont_attach) /* some video driver already attached */
95 return (0);
96 #endif /* NBIVIDEO > 0 */
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);
104 return (1);
107 void
108 mq200_attach(struct mq200_softc *sc)
110 unsigned long regval;
111 struct hpcfb_attach_args ha;
112 int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1;
114 printf(": ");
115 if (mq200_fbinit(&sc->sc_fbconf) != 0) {
116 /* just return so that hpcfb will not be attached */
117 return;
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);
126 regval = mq200_read(sc, MQ200_PC08R);
127 printf("MQ200 Rev.%02lx video controller", regval & 0xff);
128 if (console) {
129 printf(", console");
131 printf("\n");
132 printf("%s: framebuffer address: 0x%08lx\n",
133 sc->sc_dev.dv_xname, (u_long)bootinfo->fb_addr);
136 * setup registers
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);
146 #endif
147 mq200_setup_regctx(sc);
148 mq200_mdsetup(sc);
149 if (sc->sc_md) {
150 int mode;
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;
164 if (sc->sc_md->md_flags & MQ200_MD_HAVEFP) {
165 sc->sc_flags |= MQ200_SC_GC2_ENABLE; /* FP */
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;
180 #endif
181 mq200_setup(sc);
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);
194 #ifdef MQ200_DEBUG
195 if (sc->sc_md == NULL || bootverbose) {
196 mq200_dump_pll(sc);
198 #endif
200 /* Add a power hook to power saving */
201 sc->sc_mq200pwstate = MQ200_POWERSTATE_D0;
202 sc->sc_powerhook = powerhook_establish(sc->sc_dev.dv_xname,
203 mq200_power, sc);
204 if (sc->sc_powerhook == NULL)
205 printf("%s: WARNING: unable to establish power hook\n",
206 sc->sc_dev.dv_xname);
208 /* Add a hard power hook to power saving */
209 sc->sc_hardpowerhook = config_hook(CONFIG_HOOK_PMEVENT,
210 CONFIG_HOOK_PMEVENT_HARDPOWER,
211 CONFIG_HOOK_SHARE,
212 mq200_hardpower, sc);
213 if (sc->sc_hardpowerhook == NULL)
214 printf("%s: WARNING: unable to establish hard power hook\n",
215 sc->sc_dev.dv_xname);
217 /* initialize backlight brightness and lcd contrast */
218 sc->sc_lcd_inited = 0;
219 mq200_init_brightness(sc, 1);
220 mq200_init_contrast(sc, 1);
221 mq200_init_backlight(sc, 1);
223 if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0) {
224 panic("mq200_attach: can't init fb console");
227 ha.ha_console = console;
228 ha.ha_accessops = &mq200_ha;
229 ha.ha_accessctx = sc;
230 ha.ha_curfbconf = 0;
231 ha.ha_nfbconf = 1;
232 ha.ha_fbconflist = &sc->sc_fbconf;
233 ha.ha_curdspconf = 0;
234 ha.ha_ndspconf = 1;
235 ha.ha_dspconflist = &sc->sc_dspconf;
237 config_found(&sc->sc_dev, &ha, hpcfbprint);
239 #if NBIVIDEO > 0
241 * bivideo is no longer need
243 bivideo_dont_attach = 1;
244 #endif /* NBIVIDEO > 0 */
247 static void
248 mq200_update_powerstate(struct mq200_softc *sc, int updates)
251 if (updates & PWRSTAT_LCD)
252 config_hook_call(CONFIG_HOOK_POWERCONTROL,
253 CONFIG_HOOK_POWERCONTROL_LCD,
254 (void*)!(sc->sc_powerstate &
255 (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)));
257 if (updates & PWRSTAT_BACKLIGHT)
258 config_hook_call(CONFIG_HOOK_POWERCONTROL,
259 CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
260 (void*)(!(sc->sc_powerstate &
261 (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)) &&
262 (sc->sc_powerstate & PWRSTAT_BACKLIGHT)));
265 static void
266 mq200_power(int why, void *arg)
268 struct mq200_softc *sc = arg;
270 switch (why) {
271 case PWR_SUSPEND:
272 sc->sc_powerstate |= PWRSTAT_SUSPEND;
273 mq200_update_powerstate(sc, PWRSTAT_ALL);
274 break;
275 case PWR_STANDBY:
276 sc->sc_powerstate |= PWRSTAT_SUSPEND;
277 mq200_update_powerstate(sc, PWRSTAT_ALL);
278 break;
279 case PWR_RESUME:
280 sc->sc_powerstate &= ~PWRSTAT_SUSPEND;
281 mq200_update_powerstate(sc, PWRSTAT_ALL);
282 break;
286 static int
287 mq200_hardpower(void *ctx, int type, long id, void *msg)
289 struct mq200_softc *sc = ctx;
290 int why = (int)msg;
292 switch (why) {
293 case PWR_SUSPEND:
294 sc->sc_mq200pwstate = MQ200_POWERSTATE_D2;
295 break;
296 case PWR_STANDBY:
297 sc->sc_mq200pwstate = MQ200_POWERSTATE_D3;
298 break;
299 case PWR_RESUME:
300 sc->sc_mq200pwstate = MQ200_POWERSTATE_D0;
301 break;
304 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
305 MQ200_PMCSR, sc->sc_mq200pwstate);
308 * you should wait until the
309 * power state transit sequence will end.
312 unsigned long tmp;
313 do {
314 tmp = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
315 MQ200_PMCSR);
316 } while ((tmp & 0x3) != (sc->sc_mq200pwstate & 0x3));
317 delay(100000); /* XXX */
320 return (0);
324 static int
325 mq200_fbinit(struct hpcfb_fbconf *fb)
329 * get fb settings from bootinfo
331 if (bootinfo == NULL ||
332 bootinfo->fb_addr == 0 ||
333 bootinfo->fb_line_bytes == 0 ||
334 bootinfo->fb_width == 0 ||
335 bootinfo->fb_height == 0) {
336 printf("no frame buffer information.\n");
337 return (-1);
340 /* zero fill */
341 memset(fb, 0, sizeof(*fb));
343 fb->hf_conf_index = 0; /* configuration index */
344 fb->hf_nconfs = 1; /* how many configurations */
345 strcpy(fb->hf_name, "built-in video");
346 /* frame buffer name */
347 strcpy(fb->hf_conf_name, "default");
348 /* configuration name */
349 fb->hf_height = bootinfo->fb_height;
350 fb->hf_width = bootinfo->fb_width;
351 fb->hf_baseaddr = mips_ptob(mips_btop(bootinfo->fb_addr));
352 fb->hf_offset = (u_long)bootinfo->fb_addr - fb->hf_baseaddr;
353 /* frame buffer start offset */
354 fb->hf_bytes_per_line = bootinfo->fb_line_bytes;
355 fb->hf_nplanes = 1;
356 fb->hf_bytes_per_plane = bootinfo->fb_height *
357 bootinfo->fb_line_bytes;
359 fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
360 fb->hf_access_flags |= HPCFB_ACCESS_WORD;
361 fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
363 switch (bootinfo->fb_type) {
365 * monochrome
367 case BIFB_D1_M2L_1:
368 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
369 /* fall through */
370 case BIFB_D1_M2L_0:
371 fb->hf_class = HPCFB_CLASS_GRAYSCALE;
372 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
373 fb->hf_pack_width = 8;
374 fb->hf_pixels_per_pack = 8;
375 fb->hf_pixel_width = 1;
376 fb->hf_class_data_length = sizeof(struct hf_gray_tag);
377 fb->hf_u.hf_gray.hf_flags = 0; /* reserved for future use */
378 break;
381 * gray scale
383 case BIFB_D2_M2L_3:
384 case BIFB_D2_M2L_3x2:
385 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
386 /* fall through */
387 case BIFB_D2_M2L_0:
388 case BIFB_D2_M2L_0x2:
389 fb->hf_class = HPCFB_CLASS_GRAYSCALE;
390 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
391 fb->hf_pack_width = 8;
392 fb->hf_pixels_per_pack = 4;
393 fb->hf_pixel_width = 2;
394 fb->hf_class_data_length = sizeof(struct hf_gray_tag);
395 fb->hf_u.hf_gray.hf_flags = 0; /* reserved for future use */
396 break;
398 case BIFB_D4_M2L_F:
399 case BIFB_D4_M2L_Fx2:
400 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
401 /* fall through */
402 case BIFB_D4_M2L_0:
403 case BIFB_D4_M2L_0x2:
404 fb->hf_class = HPCFB_CLASS_GRAYSCALE;
405 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
406 fb->hf_pack_width = 8;
407 fb->hf_pixels_per_pack = 2;
408 fb->hf_pixel_width = 4;
409 fb->hf_class_data_length = sizeof(struct hf_gray_tag);
410 fb->hf_u.hf_gray.hf_flags = 0; /* reserved for future use */
411 break;
414 * indexed color
416 case BIFB_D8_FF:
417 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
418 /* fall through */
419 case BIFB_D8_00:
420 fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
421 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
422 fb->hf_pack_width = 8;
423 fb->hf_pixels_per_pack = 1;
424 fb->hf_pixel_width = 8;
425 fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
426 fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */
427 break;
430 * RGB color
432 case BIFB_D16_FFFF:
433 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
434 /* fall through */
435 case BIFB_D16_0000:
436 fb->hf_class = HPCFB_CLASS_RGBCOLOR;
437 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
438 fb->hf_order_flags = HPCFB_REVORDER_BYTE;
439 fb->hf_pack_width = 16;
440 fb->hf_pixels_per_pack = 1;
441 fb->hf_pixel_width = 16;
443 fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
444 fb->hf_u.hf_rgb.hf_flags = 0; /* reserved for future use */
446 fb->hf_u.hf_rgb.hf_red_width = 5;
447 fb->hf_u.hf_rgb.hf_red_shift = 11;
448 fb->hf_u.hf_rgb.hf_green_width = 6;
449 fb->hf_u.hf_rgb.hf_green_shift = 5;
450 fb->hf_u.hf_rgb.hf_blue_width = 5;
451 fb->hf_u.hf_rgb.hf_blue_shift = 0;
452 fb->hf_u.hf_rgb.hf_alpha_width = 0;
453 fb->hf_u.hf_rgb.hf_alpha_shift = 0;
454 break;
456 default:
457 printf("unknown type (=%d).\n", bootinfo->fb_type);
458 return (-1);
459 break;
462 return (0); /* no error */
466 mq200_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
468 struct mq200_softc *sc = (struct mq200_softc *)v;
469 struct hpcfb_fbconf *fbconf;
470 struct hpcfb_dspconf *dspconf;
471 struct wsdisplay_cmap *cmap;
472 struct wsdisplay_param *dispparam;
474 switch (cmd) {
475 case WSDISPLAYIO_GETCMAP:
476 cmap = (struct wsdisplay_cmap *)data;
478 if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
479 sc->sc_fbconf.hf_pack_width != 8 ||
480 256 <= cmap->index ||
481 256 - cmap->index < cmap->count)
482 return (EINVAL);
485 * This driver can't get color map.
487 return (EINVAL);
489 case WSDISPLAYIO_PUTCMAP:
491 * This driver can't set color map.
493 return (EINVAL);
495 case WSDISPLAYIO_SVIDEO:
496 if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
497 sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
498 else
499 sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
500 mq200_update_powerstate(sc, PWRSTAT_ALL);
501 return 0;
503 case WSDISPLAYIO_GVIDEO:
504 *(int *)data = (sc->sc_powerstate&PWRSTAT_VIDEOOFF) ?
505 WSDISPLAYIO_VIDEO_OFF:WSDISPLAYIO_VIDEO_ON;
506 return 0;
508 case WSDISPLAYIO_GETPARAM:
509 dispparam = (struct wsdisplay_param*)data;
510 switch (dispparam->param) {
511 case WSDISPLAYIO_PARAM_BACKLIGHT:
512 VPRINTF("ioctl: GET:BACKLIGHT\n");
513 mq200_init_brightness(sc, 0);
514 mq200_init_backlight(sc, 0);
515 VPRINTF("ioctl: GET:(real)BACKLIGHT %d\n",
516 (sc->sc_powerstate&PWRSTAT_BACKLIGHT)? 1: 0);
517 dispparam->min = 0;
518 dispparam->max = 1;
519 if (sc->sc_max_brightness > 0)
520 dispparam->curval = sc->sc_brightness > 0
521 ? 1: 0;
522 else
523 dispparam->curval =
524 (sc->sc_powerstate&PWRSTAT_BACKLIGHT)
525 ? 1: 0;
526 VPRINTF("ioctl: GET:BACKLIGHT:%d(%s)\n",
527 dispparam->curval,
528 sc->sc_max_brightness > 0? "brightness": "light");
529 return 0;
530 break;
531 case WSDISPLAYIO_PARAM_CONTRAST:
532 VPRINTF("ioctl: GET:CONTRAST\n");
533 mq200_init_contrast(sc, 0);
534 if (sc->sc_max_contrast > 0) {
535 dispparam->min = 0;
536 dispparam->max = sc->sc_max_contrast;
537 dispparam->curval = sc->sc_contrast;
538 VPRINTF("ioctl: GET:CONTRAST"
539 " max=%d, current=%d\n",
540 sc->sc_max_contrast, sc->sc_contrast);
541 return 0;
542 } else {
543 VPRINTF("ioctl: GET:CONTRAST EINVAL\n");
544 return (EINVAL);
546 break;
547 case WSDISPLAYIO_PARAM_BRIGHTNESS:
548 VPRINTF("ioctl: GET:BRIGHTNESS\n");
549 mq200_init_brightness(sc, 0);
550 if (sc->sc_max_brightness > 0) {
551 dispparam->min = 0;
552 dispparam->max = sc->sc_max_brightness;
553 dispparam->curval = sc->sc_brightness;
554 VPRINTF("ioctl: GET:BRIGHTNESS"
555 " max=%d, current=%d\n",
556 sc->sc_max_brightness, sc->sc_brightness);
557 return 0;
558 } else {
559 VPRINTF("ioctl: GET:BRIGHTNESS EINVAL\n");
560 return (EINVAL);
562 return (EINVAL);
563 default:
564 return (EINVAL);
566 return (0);
568 case WSDISPLAYIO_SETPARAM:
569 dispparam = (struct wsdisplay_param*)data;
570 switch (dispparam->param) {
571 case WSDISPLAYIO_PARAM_BACKLIGHT:
572 VPRINTF("ioctl: SET:BACKLIGHT\n");
573 if (dispparam->curval < 0 ||
574 1 < dispparam->curval)
575 return (EINVAL);
576 mq200_init_brightness(sc, 0);
577 VPRINTF("ioctl: SET:max brightness=%d\n",
578 sc->sc_max_brightness);
579 if (sc->sc_max_brightness > 0) { /* dimmer */
580 if (dispparam->curval == 0){
581 sc->sc_brightness_save =
582 sc->sc_brightness;
583 mq200_set_brightness(sc, 0); /* min */
584 } else {
585 if (sc->sc_brightness_save == 0)
586 sc->sc_brightness_save =
587 sc->sc_max_brightness;
588 mq200_set_brightness(sc,
589 sc->sc_brightness_save);
591 VPRINTF("ioctl: SET:BACKLIGHT:"
592 " brightness=%d\n", sc->sc_brightness);
593 } else { /* off */
594 if (dispparam->curval == 0)
595 sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
596 else
597 sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
598 VPRINTF("ioctl: SET:BACKLIGHT:"
599 " powerstate %d\n",
600 (sc->sc_powerstate & PWRSTAT_BACKLIGHT)
601 ? 1 : 0);
602 mq200_update_powerstate(sc, PWRSTAT_BACKLIGHT);
603 VPRINTF("ioctl: SET:BACKLIGHT:%d\n",
604 (sc->sc_powerstate & PWRSTAT_BACKLIGHT)
605 ? 1 : 0);
607 return 0;
608 break;
609 case WSDISPLAYIO_PARAM_CONTRAST:
610 VPRINTF("ioctl: SET:CONTRAST\n");
611 mq200_init_contrast(sc, 0);
612 if (dispparam->curval < 0 ||
613 sc->sc_max_contrast < dispparam->curval)
614 return (EINVAL);
615 if (sc->sc_max_contrast > 0) {
616 int org = sc->sc_contrast;
617 mq200_set_contrast(sc, dispparam->curval);
618 VPRINTF("ioctl: SET:CONTRAST"
619 " org=%d, current=%d\n", org,
620 sc->sc_contrast);
621 VPRINTF("ioctl: SETPARAM:"
622 " CONTRAST org=%d, current=%d\n", org,
623 sc->sc_contrast);
624 return 0;
625 } else {
626 VPRINTF("ioctl: SET:CONTRAST EINVAL\n");
627 return (EINVAL);
629 break;
630 case WSDISPLAYIO_PARAM_BRIGHTNESS:
631 VPRINTF("ioctl: SET:BRIGHTNESS\n");
632 mq200_init_brightness(sc, 0);
633 if (dispparam->curval < 0 ||
634 sc->sc_max_brightness < dispparam->curval)
635 return (EINVAL);
636 if (sc->sc_max_brightness > 0) {
637 int org = sc->sc_brightness;
638 mq200_set_brightness(sc, dispparam->curval);
639 VPRINTF("ioctl: SET:BRIGHTNESS"
640 " org=%d, current=%d\n", org,
641 sc->sc_brightness);
642 return 0;
643 } else {
644 VPRINTF("ioctl: SET:BRIGHTNESS EINVAL\n");
645 return (EINVAL);
647 break;
648 default:
649 return (EINVAL);
651 return (0);
653 case HPCFBIO_GCONF:
654 fbconf = (struct hpcfb_fbconf *)data;
655 if (fbconf->hf_conf_index != 0 &&
656 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
657 return (EINVAL);
659 *fbconf = sc->sc_fbconf; /* structure assignment */
660 return (0);
661 case HPCFBIO_SCONF:
662 fbconf = (struct hpcfb_fbconf *)data;
663 if (fbconf->hf_conf_index != 0 &&
664 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
665 return (EINVAL);
668 * nothing to do because we have only one configuration
670 return (0);
671 case HPCFBIO_GDSPCONF:
672 dspconf = (struct hpcfb_dspconf *)data;
673 if ((dspconf->hd_unit_index != 0 &&
674 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
675 (dspconf->hd_conf_index != 0 &&
676 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
677 return (EINVAL);
679 *dspconf = sc->sc_dspconf; /* structure assignment */
680 return (0);
681 case HPCFBIO_SDSPCONF:
682 dspconf = (struct hpcfb_dspconf *)data;
683 if ((dspconf->hd_unit_index != 0 &&
684 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
685 (dspconf->hd_conf_index != 0 &&
686 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
687 return (EINVAL);
690 * nothing to do
691 * because we have only one unit and one configuration
693 return (0);
694 case HPCFBIO_GOP:
695 case HPCFBIO_SOP:
697 * curently not implemented...
699 return (EINVAL);
702 return (EPASSTHROUGH);
705 paddr_t
706 mq200_mmap(void *ctx, off_t offset, int prot)
708 struct mq200_softc *sc = (struct mq200_softc *)ctx;
710 if (offset < 0 || MQ200_MAPSIZE <= offset)
711 return -1;
713 return mips_btop(sc->sc_baseaddr + offset);
717 void
718 mq200_init_backlight(struct mq200_softc *sc, int inattach)
720 int val = -1;
722 if (sc->sc_lcd_inited&BACKLIGHT_INITED)
723 return;
725 if (config_hook_call(CONFIG_HOOK_GET,
726 CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) {
727 /* we can get real light state */
728 VPRINTF("init_backlight: real backlight=%d\n", val);
729 if (val == 0)
730 sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
731 else
732 sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
733 sc->sc_lcd_inited |= BACKLIGHT_INITED;
734 } else if (inattach) {
736 we cannot get real light state in attach time
737 because light device not yet attached.
738 we will retry in !inattach.
739 temporary assume light is on.
741 sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
742 } else {
743 /* we cannot get real light state, so work by myself state */
744 sc->sc_lcd_inited |= BACKLIGHT_INITED;
748 void
749 mq200_init_brightness(struct mq200_softc *sc, int inattach)
751 int val = -1;
753 if (sc->sc_lcd_inited&BRIGHTNESS_INITED)
754 return;
756 VPRINTF("init_brightness\n");
757 if (config_hook_call(CONFIG_HOOK_GET,
758 CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) {
759 /* we can get real brightness max */
760 VPRINTF("init_brightness: real brightness max=%d\n", val);
761 sc->sc_max_brightness = val;
762 val = -1;
763 if (config_hook_call(CONFIG_HOOK_GET,
764 CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
765 /* we can get real brightness */
766 VPRINTF("init_brightness: real brightness=%d\n", val);
767 sc->sc_brightness_save = sc->sc_brightness = val;
768 } else {
769 sc->sc_brightness_save =
770 sc->sc_brightness = sc->sc_max_brightness;
772 sc->sc_lcd_inited |= BRIGHTNESS_INITED;
773 } else if (inattach) {
775 we cannot get real brightness in attach time
776 because brightness device not yet attached.
777 we will retry in !inattach.
779 sc->sc_max_brightness = -1;
780 sc->sc_brightness = -1;
781 sc->sc_brightness_save = -1;
782 } else {
783 /* we cannot get real brightness */
784 sc->sc_lcd_inited |= BRIGHTNESS_INITED;
787 return;
791 void
792 mq200_init_contrast(struct mq200_softc *sc, int inattach)
794 int val = -1;
796 if (sc->sc_lcd_inited&CONTRAST_INITED)
797 return;
799 VPRINTF("init_contrast\n");
800 if (config_hook_call(CONFIG_HOOK_GET,
801 CONFIG_HOOK_CONTRAST_MAX, &val) != -1) {
802 /* we can get real contrast max */
803 VPRINTF("init_contrast: real contrast max=%d\n", val);
804 sc->sc_max_contrast = val;
805 val = -1;
806 if (config_hook_call(CONFIG_HOOK_GET,
807 CONFIG_HOOK_CONTRAST, &val) != -1) {
808 /* we can get real contrast */
809 VPRINTF("init_contrast: real contrast=%d\n", val);
810 sc->sc_contrast = val;
811 } else {
812 sc->sc_contrast = sc->sc_max_contrast;
814 sc->sc_lcd_inited |= CONTRAST_INITED;
815 } else if (inattach) {
817 we cannot get real contrast in attach time
818 because contrast device not yet attached.
819 we will retry in !inattach.
821 sc->sc_max_contrast = -1;
822 sc->sc_contrast = -1;
823 } else {
824 /* we cannot get real contrast */
825 sc->sc_lcd_inited |= CONTRAST_INITED;
828 return;
832 void
833 mq200_set_brightness(struct mq200_softc *sc, int val)
835 sc->sc_brightness = val;
837 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
838 if (config_hook_call(CONFIG_HOOK_GET,
839 CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
840 sc->sc_brightness = val;
844 void
845 mq200_set_contrast(struct mq200_softc *sc, int val)
847 sc->sc_contrast = val;
849 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
850 if (config_hook_call(CONFIG_HOOK_GET,
851 CONFIG_HOOK_CONTRAST, &val) != -1) {
852 sc->sc_contrast = val;