mq200.c revision 1.20 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