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