xref: /netbsd-src/sys/arch/hpcmips/dev/mq200.c (revision 3cec974c61d7fac0a37c0377723a33214a458c8b)
1 /*	$NetBSD: mq200.c,v 1.11 2001/03/09 08:54:18 sato Exp $	*/
2 
3 /*-
4  * Copyright (c) 2000 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 <hpcmips/dev/mq200reg.h>
50 #include <hpcmips/dev/mq200var.h>
51 #include "bivideo.h"
52 #if NBIVIDEO > 0
53 #include <dev/hpc/bivideovar.h>
54 #endif
55 
56 #define MQ200DEBUG
57 #ifdef MQ200DEBUG
58 #ifndef MQ200DEBUG_CONF
59 #define MQ200DEBUG_CONF 0
60 #endif
61 int	mq200_debug = MQ200DEBUG_CONF;
62 #define	DPRINTF(arg)     do { if (mq200_debug) printf arg; } while(0);
63 #define	DPRINTFN(n, arg) do { if (mq200_debug > (n)) printf arg; } while (0);
64 #define	VPRINTF(arg)     do { if (bootverbose || mq200_debug) printf arg; } while(0);
65 #define	VPRINTFN(n, arg) do { if (bootverbose || mq200_debug > (n)) printf arg; } while (0);
66 #else
67 #define	DPRINTF(arg)     do { } while (0);
68 #define DPRINTFN(n, arg) do { } while (0);
69 #define	VPRINTF(arg)     do { if (bootverbose) printf arg; } while(0);
70 #define	VPRINTFN(n, arg) do { if (bootverbose) printf arg; } while (0);
71 #endif
72 
73 /*
74  * function prototypes
75  */
76 static void	mq200_power __P((int, void *));
77 static int	mq200_hardpower __P((void *, int, long, void *));
78 static int	mq200_fbinit __P((struct hpcfb_fbconf *));
79 static int	mq200_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
80 static paddr_t	mq200_mmap __P((void *, off_t offset, int));
81 static void	mq200_update_powerstate __P((struct mq200_softc *, int));
82 void	mq200_get_backlight __P((struct mq200_softc *));
83 void	mq200_init_brightness __P((struct mq200_softc *));
84 void	mq200_init_contrast __P((struct mq200_softc *));
85 void	mq200_set_brightness __P((struct mq200_softc *, int));
86 void	mq200_set_contrast __P((struct mq200_softc *, int));
87 
88 /*
89  * static variables
90  */
91 struct hpcfb_accessops mq200_ha = {
92 	mq200_ioctl, mq200_mmap
93 };
94 
95 int
96 mq200_probe(iot, ioh)
97 	bus_space_tag_t iot;
98 	bus_space_handle_t ioh;
99 {
100 	unsigned long regval;
101 
102 #if NBIVIDEO > 0
103 	if (bivideo_dont_attach) /* some video driver already attached */
104 		return (0);
105 #endif /* NBIVIDEO > 0 */
106 
107 	regval = bus_space_read_4(iot, ioh, MQ200_PC00R);
108 	VPRINTF(("mq200 probe: vendor id=%04lx product id=%04lx\n",
109 		 regval & 0xffff, (regval >> 16) & 0xffff));
110 	if (regval != ((MQ200_PRODUCT_ID << 16) | MQ200_VENDOR_ID))
111 		return (0);
112 
113 	return (1);
114 }
115 
116 void
117 mq200_attach(sc)
118 	struct mq200_softc *sc;
119 {
120 	unsigned long regval;
121 	struct hpcfb_attach_args ha;
122 	int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1;
123 
124 	printf(": ");
125 	if (mq200_fbinit(&sc->sc_fbconf) != 0) {
126 		/* just return so that hpcfb will not be attached */
127 		return;
128 	}
129 
130 	sc->sc_fbconf.hf_baseaddr = (u_long)bootinfo->fb_addr;
131 	sc->sc_fbconf.hf_offset	= (u_long)sc->sc_fbconf.hf_baseaddr -
132 	    MIPS_PHYS_TO_KSEG1(mips_ptob(mips_btop(sc->sc_baseaddr)));
133 	DPRINTF(("hf_baseaddr=%lx\n", sc->sc_fbconf.hf_baseaddr));
134 	DPRINTF(("hf_offset=%lx\n", sc->sc_fbconf.hf_offset));
135 
136 	regval = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MQ200_PC08R);
137 	printf("MQ200 Rev.%02lx video controller", regval & 0xff);
138 	if (console) {
139 		printf(", console");
140 	}
141 	printf("\n");
142         printf("%s: framebuffer address: 0x%08lx\n",
143 		sc->sc_dev.dv_xname, (u_long)bootinfo->fb_addr);
144 
145 	/* Add a power hook to power saving */
146 	sc->sc_mq200pwstate = MQ200_POWERSTATE_D0;
147 	sc->sc_powerhook = powerhook_establish(mq200_power, sc);
148 	if (sc->sc_powerhook == NULL)
149 		printf("%s: WARNING: unable to establish power hook\n",
150 			sc->sc_dev.dv_xname);
151 
152 	/* Add a hard power hook to power saving */
153 	sc->sc_hardpowerhook = config_hook(CONFIG_HOOK_PMEVENT,
154 					   CONFIG_HOOK_PMEVENT_HARDPOWER,
155 					   CONFIG_HOOK_SHARE,
156 					   mq200_hardpower, sc);
157 	if (sc->sc_hardpowerhook == NULL)
158 		printf("%s: WARNING: unable to establish hard power hook\n",
159 			sc->sc_dev.dv_xname);
160 
161 	/* initialize backlight brightness and lcd contrast */
162 	sc->sc_brightness = sc->sc_contrast =
163 	sc->sc_max_brightness = sc->sc_max_contrast = -1;
164 	mq200_init_brightness(sc);
165 	mq200_init_contrast(sc);
166 	mq200_get_backlight(sc);
167 
168 	if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0) {
169 		panic("mq200_attach: can't init fb console");
170 	}
171 
172 	ha.ha_console = console;
173 	ha.ha_accessops = &mq200_ha;
174 	ha.ha_accessctx = sc;
175 	ha.ha_curfbconf = 0;
176 	ha.ha_nfbconf = 1;
177 	ha.ha_fbconflist = &sc->sc_fbconf;
178 	ha.ha_curdspconf = 0;
179 	ha.ha_ndspconf = 1;
180 	ha.ha_dspconflist = &sc->sc_dspconf;
181 
182 	config_found(&sc->sc_dev, &ha, hpcfbprint);
183 
184 #if NBIVIDEO > 0
185 	/*
186 	 * bivideo is no longer need
187 	 */
188 	bivideo_dont_attach = 1;
189 #endif /* NBIVIDEO > 0 */
190 }
191 
192 static void
193 mq200_update_powerstate(sc, updates)
194 	struct mq200_softc *sc;
195 	int updates;
196 {
197 	if (updates & PWRSTAT_LCD)
198 		config_hook_call(CONFIG_HOOK_POWERCONTROL,
199 		    CONFIG_HOOK_POWERCONTROL_LCD,
200 		    (void*)!(sc->sc_powerstate &
201 				(PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)));
202 
203 	if (updates & PWRSTAT_BACKLIGHT)
204 		config_hook_call(CONFIG_HOOK_POWERCONTROL,
205 		    CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
206 		    (void*)(!(sc->sc_powerstate &
207 				(PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)) &&
208 			     (sc->sc_powerstate & PWRSTAT_BACKLIGHT)));
209 }
210 
211 static void
212 mq200_power(why, arg)
213 	int why;
214 	void *arg;
215 {
216 #if 0
217 	struct mq200_softc *sc = arg;
218 
219 	switch (why) {
220 	case PWR_SUSPEND:
221 		sc->sc_powerstate |= PWRSTAT_SUSPEND;
222 		mq200_update_powerstate(sc, PWRSTAT_ALL);
223 		sc->sc_mq200pwstate = MQ200_POWERSTATE_D2;
224 		break;
225 	case PWR_STANDBY:
226 		sc->sc_powerstate |= PWRSTAT_SUSPEND;
227 		mq200_update_powerstate(sc, PWRSTAT_ALL);
228 		sc->sc_mq200pwstate = MQ200_POWERSTATE_D3;
229 		break;
230 	case PWR_RESUME:
231 		sc->sc_powerstate &= ~PWRSTAT_SUSPEND;
232 		mq200_update_powerstate(sc, PWRSTAT_ALL);
233 		sc->sc_mq200pwstate = MQ200_POWERSTATE_D0;
234 		break;
235 	}
236 
237 	printf("MQ200_PMCSR=%08x\n", sc->sc_mq200pwstate);
238 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
239 			  MQ200_PMCSR, sc->sc_mq200pwstate);
240 #endif
241 }
242 
243 static int
244 mq200_hardpower(ctx, type, id, msg)
245 	void *ctx;
246 	int type;
247 	long id;
248 	void *msg;
249 {
250 	struct mq200_softc *sc = ctx;
251 	int why = (int)msg;
252 
253 	switch (why) {
254 	case PWR_SUSPEND:
255 		sc->sc_powerstate |= PWRSTAT_SUSPEND;
256 		mq200_update_powerstate(sc, PWRSTAT_ALL);
257 		sc->sc_mq200pwstate = MQ200_POWERSTATE_D2;
258 		break;
259 	case PWR_STANDBY:
260 		sc->sc_powerstate |= PWRSTAT_SUSPEND;
261 		mq200_update_powerstate(sc, PWRSTAT_ALL);
262 		sc->sc_mq200pwstate = MQ200_POWERSTATE_D3;
263 		break;
264 	case PWR_RESUME:
265 		sc->sc_powerstate &= ~PWRSTAT_SUSPEND;
266 		mq200_update_powerstate(sc, PWRSTAT_ALL);
267 		sc->sc_mq200pwstate = MQ200_POWERSTATE_D0;
268 		break;
269 	}
270 
271 	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
272 			  MQ200_PMCSR, sc->sc_mq200pwstate);
273 
274 	/*
275 	 * you should wait until the
276 	 * power state transit sequence will end.
277 	 */
278 	{
279 		unsigned long tmp;
280 		do {
281 			tmp = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
282 					       MQ200_PMCSR);
283 		} while ((tmp & 0x3) != (sc->sc_mq200pwstate & 0x3));
284 		delay(100000); /* XXX */
285 	}
286 
287 	return (0);
288 }
289 
290 
291 static int
292 mq200_fbinit(fb)
293 	struct hpcfb_fbconf *fb;
294 {
295 
296 	/*
297 	 * get fb settings from bootinfo
298 	 */
299 	if (bootinfo == NULL ||
300 	    bootinfo->fb_addr == 0 ||
301 	    bootinfo->fb_line_bytes == 0 ||
302 	    bootinfo->fb_width == 0 ||
303 	    bootinfo->fb_height == 0) {
304 		printf("no frame buffer infomation.\n");
305 		return (-1);
306 	}
307 
308 	/* zero fill */
309 	bzero(fb, sizeof(*fb));
310 
311 	fb->hf_conf_index	= 0;	/* configuration index		*/
312 	fb->hf_nconfs		= 1;   	/* how many configurations	*/
313 	strcpy(fb->hf_name, "built-in video");
314 					/* frame buffer name		*/
315 	strcpy(fb->hf_conf_name, "default");
316 					/* configuration name		*/
317 	fb->hf_height		= bootinfo->fb_height;
318 	fb->hf_width		= bootinfo->fb_width;
319 	fb->hf_baseaddr		= mips_ptob(mips_btop(bootinfo->fb_addr));
320 	fb->hf_offset		= (u_long)bootinfo->fb_addr - fb->hf_baseaddr;
321 					/* frame buffer start offset   	*/
322 	fb->hf_bytes_per_line	= bootinfo->fb_line_bytes;
323 	fb->hf_nplanes		= 1;
324 	fb->hf_bytes_per_plane	= bootinfo->fb_height *
325 					bootinfo->fb_line_bytes;
326 
327 	fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
328 	fb->hf_access_flags |= HPCFB_ACCESS_WORD;
329 	fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
330 
331 	switch (bootinfo->fb_type) {
332 		/*
333 		 * gray scale
334 		 */
335 	case BIFB_D2_M2L_3:
336 	case BIFB_D2_M2L_3x2:
337 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
338 		/* fall through */
339 	case BIFB_D2_M2L_0:
340 	case BIFB_D2_M2L_0x2:
341 		fb->hf_class = HPCFB_CLASS_GRAYSCALE;
342 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
343 		fb->hf_pack_width = 8;
344 		fb->hf_pixels_per_pack = 4;
345 		fb->hf_pixel_width = 2;
346 		fb->hf_class_data_length = sizeof(struct hf_gray_tag);
347 		fb->hf_u.hf_gray.hf_flags = 0;	/* reserved for future use */
348 		break;
349 
350 	case BIFB_D4_M2L_F:
351 	case BIFB_D4_M2L_Fx2:
352 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
353 		/* fall through */
354 	case BIFB_D4_M2L_0:
355 	case BIFB_D4_M2L_0x2:
356 		fb->hf_class = HPCFB_CLASS_GRAYSCALE;
357 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
358 		fb->hf_pack_width = 8;
359 		fb->hf_pixels_per_pack = 2;
360 		fb->hf_pixel_width = 4;
361 		fb->hf_class_data_length = sizeof(struct hf_gray_tag);
362 		fb->hf_u.hf_gray.hf_flags = 0;	/* reserved for future use */
363 		break;
364 
365 		/*
366 		 * indexed color
367 		 */
368 	case BIFB_D8_FF:
369 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
370 		/* fall through */
371 	case BIFB_D8_00:
372 		fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
373 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
374 		fb->hf_pack_width = 8;
375 		fb->hf_pixels_per_pack = 1;
376 		fb->hf_pixel_width = 8;
377 		fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
378 		fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */
379 		break;
380 
381 		/*
382 		 * RGB color
383 		 */
384 	case BIFB_D16_FFFF:
385 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
386 		/* fall through */
387 	case BIFB_D16_0000:
388 		fb->hf_class = HPCFB_CLASS_RGBCOLOR;
389 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
390 #if BYTE_ORDER == LITTLE_ENDIAN
391 		fb->hf_swap_flags = HPCFB_SWAP_BYTE;
392 #endif
393 		fb->hf_pack_width = 16;
394 		fb->hf_pixels_per_pack = 1;
395 		fb->hf_pixel_width = 16;
396 
397 		fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
398 		fb->hf_u.hf_rgb.hf_flags = 0;	/* reserved for future use */
399 
400 		fb->hf_u.hf_rgb.hf_red_width = 5;
401 		fb->hf_u.hf_rgb.hf_red_shift = 11;
402 		fb->hf_u.hf_rgb.hf_green_width = 6;
403 		fb->hf_u.hf_rgb.hf_green_shift = 5;
404 		fb->hf_u.hf_rgb.hf_blue_width = 5;
405 		fb->hf_u.hf_rgb.hf_blue_shift = 0;
406 		fb->hf_u.hf_rgb.hf_alpha_width = 0;
407 		fb->hf_u.hf_rgb.hf_alpha_shift = 0;
408 		break;
409 
410 	default:
411 		printf("unknown type (=%d).\n", bootinfo->fb_type);
412 		return (-1);
413 		break;
414 	}
415 
416 	return (0); /* no error */
417 }
418 
419 int
420 mq200_ioctl(v, cmd, data, flag, p)
421 	void *v;
422 	u_long cmd;
423 	caddr_t data;
424 	int flag;
425 	struct proc *p;
426 {
427 	struct mq200_softc *sc = (struct mq200_softc *)v;
428 	struct hpcfb_fbconf *fbconf;
429 	struct hpcfb_dspconf *dspconf;
430 	struct wsdisplay_cmap *cmap;
431 	struct wsdisplay_param *dispparam;
432 
433 	switch (cmd) {
434 	case WSDISPLAYIO_GETCMAP:
435 		cmap = (struct wsdisplay_cmap*)data;
436 
437 		if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
438 		    sc->sc_fbconf.hf_pack_width != 8 ||
439 		    256 <= cmap->index ||
440 		    256 < (cmap->index + cmap->count))
441 			return (EINVAL);
442 
443 #if 0
444 		if (!uvm_useracc(cmap->red, cmap->count, B_WRITE) ||
445 		    !uvm_useracc(cmap->green, cmap->count, B_WRITE) ||
446 		    !uvm_useracc(cmap->blue, cmap->count, B_WRITE))
447 			return (EFAULT);
448 
449 		copyout(&bivideo_cmap_r[cmap->index], cmap->red, cmap->count);
450 		copyout(&bivideo_cmap_g[cmap->index], cmap->green,cmap->count);
451 		copyout(&bivideo_cmap_b[cmap->index], cmap->blue, cmap->count);
452 #endif
453 
454 		return (0);
455 
456 	case WSDISPLAYIO_PUTCMAP:
457 		/*
458 		 * This driver can't set color map.
459 		 */
460 		return (EINVAL);
461 
462 	case WSDISPLAYIO_SVIDEO:
463 		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
464 			sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
465 		else
466 			sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
467 		mq200_update_powerstate(sc, PWRSTAT_ALL);
468 		return 0;
469 
470 	case WSDISPLAYIO_GVIDEO:
471 		*(int *)data = (sc->sc_powerstate&PWRSTAT_VIDEOOFF) ?
472 				WSDISPLAYIO_VIDEO_OFF:WSDISPLAYIO_VIDEO_ON;
473 		return 0;
474 
475 	case WSDISPLAYIO_GETPARAM:
476 		dispparam = (struct wsdisplay_param*)data;
477 		switch (dispparam->param) {
478 		case WSDISPLAYIO_PARAM_BACKLIGHT:
479 			VPRINTF(("mq200_ioctl: GETPARAM:BACKLIGHT call\n"));
480 			if (sc->sc_max_brightness == -1)
481 				mq200_init_brightness(sc);
482 			mq200_get_backlight(sc);
483 			dispparam->min = 0;
484 			dispparam->max = 1;
485 			if (sc->sc_max_brightness > 0)
486 				dispparam->curval = sc->sc_brightness > 0? 1: 0;
487 			else
488 				dispparam->curval =
489 				    (sc->sc_powerstate&PWRSTAT_BACKLIGHT) ? 1 : 0;
490 			VPRINTF(("mq200_ioctl: GETPARAM:BACKLIGHT:%d\n",
491 				dispparam->curval));
492 			return 0;
493 			break;
494 		case WSDISPLAYIO_PARAM_CONTRAST:
495 			VPRINTF(("mq200_ioctl: GETPARAM:CONTRAST call\n"));
496 			if (sc->sc_max_contrast == -1)
497 				mq200_init_contrast(sc);
498 			if (sc->sc_max_contrast > 0) {
499 				dispparam->min = 0;
500 				dispparam->max = sc->sc_max_contrast;
501 				dispparam->curval = sc->sc_contrast;
502 				VPRINTF(("mq200_ioctl: GETPARAM:CONTRAST max=%d, current=%d\n", sc->sc_max_contrast, sc->sc_contrast));
503 				return 0;
504 			} else {
505 				VPRINTF(("mq200_ioctl: GETPARAM:CONTRAST ret\n"));
506 				return (EINVAL);
507 			}
508 			break;
509 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
510 			VPRINTF(("mq200_ioctl: GETPARAM:BRIGHTNESS call\n"));
511 			if (sc->sc_max_brightness == -1)
512 				mq200_init_brightness(sc);
513 			if (sc->sc_max_brightness > 0) {
514 				dispparam->min = 0;
515 				dispparam->max = sc->sc_max_brightness;
516 				dispparam->curval = sc->sc_brightness;
517 				VPRINTF(("mq200_ioctl: GETPARAM:BRIGHTNESS max=%d, current=%d\n", sc->sc_max_brightness, sc->sc_brightness));
518 				return 0;
519 			} else {
520 				VPRINTF(("mq200_ioctl: GETPARAM:BRIGHTNESS ret\n"));
521 				return (EINVAL);
522 			}
523 			return (EINVAL);
524 		default:
525 			return (EINVAL);
526 		}
527 		return (0);
528 
529 	case WSDISPLAYIO_SETPARAM:
530 		dispparam = (struct wsdisplay_param*)data;
531 		switch (dispparam->param) {
532 		case WSDISPLAYIO_PARAM_BACKLIGHT:
533 			VPRINTF(("mq200_ioctl: SETPARAM:BACKLIGHT call\n"));
534 			if (dispparam->curval < 0 ||
535 			    1 < dispparam->curval)
536 				return (EINVAL);
537 			if (sc->sc_max_brightness == -1)
538 				mq200_init_brightness(sc);
539 			VPRINTF(("mq200_ioctl: SETPARAM:max brightness=%d\n", sc->sc_max_brightness));
540 			if (sc->sc_max_brightness > 0) { /* dimmer */
541 				if (dispparam->curval == 0){
542 					sc->sc_brightness_save = sc->sc_brightness;
543 					mq200_set_brightness(sc, 0);	/* min */
544 				} else {
545 					if (sc->sc_brightness_save == 0)
546 						sc->sc_brightness_save = sc->sc_max_brightness;
547 					mq200_set_brightness(sc, sc->sc_brightness_save);
548 				}
549 				VPRINTF(("mq200_ioctl: SETPARAM:BACKLIGHT: brightness=%d\n", sc->sc_brightness));
550 			} else { /* off */
551 				if (dispparam->curval == 0)
552 					sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
553 				else
554 					sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
555 				VPRINTF(("mq200_ioctl: SETPARAM:BACKLIGHT: powerstate %d\n",
556 						(sc->sc_powerstate & PWRSTAT_BACKLIGHT)?1:0));
557 				mq200_update_powerstate(sc, PWRSTAT_BACKLIGHT);
558 				VPRINTF(("mq200_ioctl: SETPARAM:BACKLIGHT:%d\n",
559 					(sc->sc_powerstate & PWRSTAT_BACKLIGHT)?1:0));
560 			}
561 			return 0;
562 			break;
563 		case WSDISPLAYIO_PARAM_CONTRAST:
564 			VPRINTF(("mq200_ioctl: SETPARAM:CONTRAST call\n"));
565 			if (sc->sc_max_contrast == -1)
566 				mq200_init_contrast(sc);
567 			if (dispparam->curval < 0 ||
568 			    sc->sc_max_contrast < dispparam->curval)
569 				return (EINVAL);
570 			if (sc->sc_max_contrast > 0) {
571 				int org = sc->sc_contrast;
572 				mq200_set_contrast(sc, dispparam->curval);
573 				VPRINTF(("mq200_ioctl: SETPARAM:CONTRAST org=%d, current=%d\n", org, sc->sc_contrast));
574 				return 0;
575 			} else {
576 				VPRINTF(("mq200_ioctl: SETPARAM:CONTRAST ret\n"));
577 				return (EINVAL);
578 			}
579 			break;
580 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
581 			VPRINTF(("mq200_ioctl: SETPARAM:BRIGHTNESS call\n"));
582 			if (sc->sc_max_brightness == -1)
583 				mq200_init_brightness(sc);
584 			if (dispparam->curval < 0 ||
585 			    sc->sc_max_brightness < dispparam->curval)
586 				return (EINVAL);
587 			if (sc->sc_max_brightness > 0) {
588 				int org = sc->sc_brightness;
589 				mq200_set_brightness(sc, dispparam->curval);
590 				VPRINTF(("mq200_ioctl: SETPARAM:BRIGHTNESS org=%d, current=%d\n", org, sc->sc_brightness));
591 				return 0;
592 			} else {
593 				VPRINTF(("mq200_ioctl: SETPARAM:BRIGHTNESS ret\n"));
594 				return (EINVAL);
595 			}
596 			break;
597 		default:
598 			return (EINVAL);
599 		}
600 		return (0);
601 
602 	case HPCFBIO_GCONF:
603 		fbconf = (struct hpcfb_fbconf *)data;
604 		if (fbconf->hf_conf_index != 0 &&
605 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
606 			return (EINVAL);
607 		}
608 		*fbconf = sc->sc_fbconf;	/* structure assignment */
609 		return (0);
610 	case HPCFBIO_SCONF:
611 		fbconf = (struct hpcfb_fbconf *)data;
612 		if (fbconf->hf_conf_index != 0 &&
613 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
614 			return (EINVAL);
615 		}
616 		/*
617 		 * nothing to do because we have only one configration
618 		 */
619 		return (0);
620 	case HPCFBIO_GDSPCONF:
621 		dspconf = (struct hpcfb_dspconf *)data;
622 		if ((dspconf->hd_unit_index != 0 &&
623 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
624 		    (dspconf->hd_conf_index != 0 &&
625 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
626 			return (EINVAL);
627 		}
628 		*dspconf = sc->sc_dspconf;	/* structure assignment */
629 		return (0);
630 	case HPCFBIO_SDSPCONF:
631 		dspconf = (struct hpcfb_dspconf *)data;
632 		if ((dspconf->hd_unit_index != 0 &&
633 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
634 		    (dspconf->hd_conf_index != 0 &&
635 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
636 			return (EINVAL);
637 		}
638 		/*
639 		 * nothing to do
640 		 * because we have only one unit and one configration
641 		 */
642 		return (0);
643 	case HPCFBIO_GOP:
644 	case HPCFBIO_SOP:
645 		/*
646 		 * curently not implemented...
647 		 */
648 		return (EINVAL);
649 	}
650 
651 	return (ENOTTY);
652 }
653 
654 paddr_t
655 mq200_mmap(ctx, offset, prot)
656 	void *ctx;
657 	off_t offset;
658 	int prot;
659 {
660 	struct mq200_softc *sc = (struct mq200_softc *)ctx;
661 
662 	if (offset < 0 || MQ200_MAPSIZE <= offset)
663 		return -1;
664 
665 	return mips_btop(sc->sc_baseaddr + offset);
666 }
667 
668 
669 void
670 mq200_get_backlight(sc)
671 	struct mq200_softc *sc;
672 {
673 	int val = -1;
674 
675 	if (sc->sc_max_brightness < 0) {
676 		if (config_hook_call(CONFIG_HOOK_GET,
677 		     CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) {
678 			if (val == 0)
679 				sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
680 			else
681 				sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
682 		}
683 	}
684 }
685 
686 void
687 mq200_init_brightness(sc)
688 	struct mq200_softc *sc;
689 {
690 	int val = -1;
691 
692 	VPRINTF(("mq200_init_brightness\n"));
693 	if (config_hook_call(CONFIG_HOOK_GET,
694 	     CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
695 		sc->sc_brightness_save = sc->sc_brightness = val;
696 	}
697 	val = -1;
698 	if (config_hook_call(CONFIG_HOOK_GET,
699 	     CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) {
700 		sc->sc_max_brightness = val;
701 	}
702 	return;
703 }
704 
705 
706 void
707 mq200_init_contrast(sc)
708 	struct mq200_softc *sc;
709 {
710 	int val = -1;
711 
712 	VPRINTF(("mq200_init_contrast\n"));
713 	if (config_hook_call(CONFIG_HOOK_GET,
714 	     CONFIG_HOOK_CONTRAST, &val) != -1) {
715 		sc->sc_contrast = val;
716 	}
717 	val = -1;
718 	if (config_hook_call(CONFIG_HOOK_GET,
719 	     CONFIG_HOOK_CONTRAST_MAX, &val) != -1) {
720 		sc->sc_max_contrast = val;
721 	}
722 	return;
723 }
724 
725 void
726 mq200_set_brightness(sc, val)
727 	struct mq200_softc *sc;
728 	int val;
729 {
730 	sc->sc_brightness = val;
731 
732 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
733 	if (config_hook_call(CONFIG_HOOK_GET,
734 	     CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
735 		sc->sc_brightness = val;
736 	}
737 }
738 
739 void
740 mq200_set_contrast(sc, val)
741 	struct mq200_softc *sc;
742 	int val;
743 {
744 	sc->sc_contrast = val;
745 
746 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
747 	if (config_hook_call(CONFIG_HOOK_GET,
748 	     CONFIG_HOOK_CONTRAST, &val) != -1) {
749 		sc->sc_contrast = val;
750 	}
751 }
752