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