xref: /netbsd-src/sys/arch/hpcarm/dev/sed_saip.c (revision 724da0fd92a003abf4aedc1d6dea5b5fb2c0c06a)
1 /*	$NetBSD: sed_saip.c,v 1.18 2006/03/04 16:51:56 peter Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999-2001
5  *         Shin Takemura and PocketBSD Project. 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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the PocketBSD project
18  *	and its contributors.
19  * 4. Neither the name of the project nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  */
36 
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: sed_saip.c,v 1.18 2006/03/04 16:51:56 peter Exp $");
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/device.h>
43 #include <sys/buf.h>
44 #include <sys/ioctl.h>
45 #include <sys/reboot.h>
46 
47 #include <machine/bus.h>
48 #include <machine/bootinfo.h>
49 #include <machine/config_hook.h>
50 #include <machine/platid.h>
51 #include <machine/platid_mask.h>
52 
53 #include <dev/wscons/wsconsio.h>
54 #include <dev/wscons/wsdisplayvar.h>
55 
56 #include <dev/rasops/rasops.h>
57 
58 #include <dev/hpc/hpcfbvar.h>
59 #include <dev/hpc/hpcfbio.h>
60 #include <dev/hpc/hpccmapvar.h>
61 
62 #include <hpcarm/dev/sed1356var.h>
63 
64 #ifdef SED_DEBUG
65 #define VPRINTF(arg)	do { if (bootverbose) printf arg; } while (0);
66 #else
67 #define VPRINTF(arg)	/* nothing */
68 #endif
69 
70 /*
71  * Function prototypes.
72  */
73 static int	sed1356_match(struct device *, struct cfdata *, void *);
74 static void	sed1356_attach(struct device *, struct device *, void *);
75 static int	sed1356_ioctl(void *, u_long, caddr_t, int, struct lwp *);
76 static paddr_t	sed1356_mmap(void *, off_t, int);
77 
78 static int	sed1356_init(struct hpcfb_fbconf *);
79 static void	sed1356_power(int, void *);
80 static void	sed1356_update_powerstate(struct sed1356_softc *, int);
81 static void	sed1356_init_backlight(struct sed1356_softc *, int);
82 static void	sed1356_set_brightness(struct sed1356_softc *, int);
83 static void	sed1356_set_contrast(struct sed1356_softc *, int);
84 
85 #if defined __mips__ || defined __sh__ || defined __arm__
86 #define __BTOP(x)		((paddr_t)(x) >> PGSHIFT)
87 #define __PTOB(x)		((paddr_t)(x) << PGSHIFT)
88 #else
89 #error "define btop, ptob."
90 #endif
91 
92 /*
93  * External functions/variables.
94  */
95 extern struct cfdriver sed_cd;
96 extern struct bus_space sa11x0_bs_tag;
97 extern int j720lcd_power(void *, int, long, void *);   /* XXX */
98 
99 /*
100  * Static variables.
101  */
102 CFATTACH_DECL(sed, sizeof(struct sed1356_softc),
103     sed1356_match, sed1356_attach, NULL, NULL);
104 struct hpcfb_accessops sed1356_ha = {
105 	sed1356_ioctl, sed1356_mmap
106 };
107 
108 static int attach_flag = 0;
109 
110 /*
111  * Function bodies.
112  */
113 static int
114 sed1356_match(struct device *parent, struct cfdata *match, void *aux)
115 {
116 
117 	/* XXX check version register */
118 	return 1;
119 }
120 
121 static void
122 sed1356_attach(struct device *parent, struct device *self, void *aux)
123 {
124 	struct sed1356_softc *sc = (struct sed1356_softc *)self;
125 	struct hpcfb_attach_args ha;
126 	int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1;
127 
128 	if (attach_flag) {
129 		panic("%s(%d): sed1356 attached twice", __FILE__, __LINE__);
130 	}
131 	attach_flag = 1;
132 
133 	if (sed1356_init(&sc->sc_fbconf) != 0) {
134 		/* just return so that hpcfb will not be attached */
135 		return;
136 	}
137 	printf("\n");
138 
139 	sc->sc_iot = &sa11x0_bs_tag;
140 	sc->sc_parent = (struct sa11x0_softc *)parent;
141 	if (bus_space_map(sc->sc_iot, (bus_addr_t)bootinfo->fb_addr & ~0x3fffff,
142 	    0x200, 0, &sc->sc_regh)) {
143 		printf("%s: unable to map register\n", sc->sc_dev.dv_xname);
144 		return;
145 	}
146 
147 	printf("%s: Epson SED1356", sc->sc_dev.dv_xname);
148 	if (console) {
149 		printf(", console");
150 	}
151 	printf("\n");
152 	printf("%s: framebuffer address: 0x%08lx\n",
153 	    sc->sc_dev.dv_xname, (u_long)bootinfo->fb_addr);
154 
155 	/* Add a suspend hook to power saving */
156 	sc->sc_powerstate = 0;
157 	sc->sc_powerhook = powerhook_establish(sed1356_power, sc);
158 	if (sc->sc_powerhook == NULL)
159 		printf("%s: WARNING: unable to establish power hook\n",
160 		    sc->sc_dev.dv_xname);
161 
162 	/* Initialize backlight brightness and lcd contrast */
163 	sc->sc_lcd_inited = 0;
164 	sed1356_init_brightness(sc, 1);
165 	sed1356_init_contrast(sc, 1);
166 	sed1356_init_backlight(sc, 1);
167 
168 	if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0)
169 		panic("sed1356_attach: cannot init fb console");
170 
171 	ha.ha_console = console;
172 	ha.ha_accessops = &sed1356_ha;
173 	ha.ha_accessctx = sc;
174 	ha.ha_curfbconf = 0;
175 	ha.ha_nfbconf = 1;
176 	ha.ha_fbconflist = &sc->sc_fbconf;
177 	ha.ha_curdspconf = 0;
178 	ha.ha_ndspconf = 1;
179 	ha.ha_dspconflist = &sc->sc_dspconf;
180 
181 	/* XXX */
182 	if (platid_match(&platid, &platid_mask_MACH_HP_JORNADA_7XX)) {
183 		config_hook(CONFIG_HOOK_POWERCONTROL,
184 			    CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
185 			    CONFIG_HOOK_SHARE, j720lcd_power, sc);
186 	}
187 
188 	config_found(self, &ha, hpcfbprint);
189 }
190 
191 static int
192 sed1356_init(struct hpcfb_fbconf *fb)
193 {
194 	/*
195 	 * get fb settings from bootinfo
196 	 */
197 	if (bootinfo == NULL ||
198 	    bootinfo->fb_addr == 0 ||
199 	    bootinfo->fb_line_bytes == 0 ||
200 	    bootinfo->fb_width == 0 ||
201 	    bootinfo->fb_height == 0) {
202 		printf("no frame buffer information.\n");
203 		return -1;
204 	}
205 
206 	/* zero fill */
207 	memset(fb, 0, sizeof(*fb));
208 
209 	fb->hf_conf_index	= 0;	/* configuration index		*/
210 	fb->hf_nconfs		= 1;   	/* how many configurations	*/
211 	strcpy(fb->hf_name, "built-in video");
212 					/* frame buffer name		*/
213 	strcpy(fb->hf_conf_name, "default");
214 					/* configuration name		*/
215 	fb->hf_height		= bootinfo->fb_height;
216 	fb->hf_width		= bootinfo->fb_width;
217 
218 	if (bus_space_map(&sa11x0_bs_tag, (bus_addr_t)bootinfo->fb_addr,
219 			   bootinfo->fb_height * bootinfo->fb_line_bytes,
220 			   0, &fb->hf_baseaddr)) {
221 		printf("unable to map framebuffer\n");
222 		return -1;
223 	}
224 	fb->hf_offset		= (u_long)bootinfo->fb_addr -
225 				      __PTOB(__BTOP(bootinfo->fb_addr));
226 					/* frame buffer start offset   	*/
227 	fb->hf_bytes_per_line	= bootinfo->fb_line_bytes;
228 	fb->hf_nplanes		= 1;
229 	fb->hf_bytes_per_plane	= bootinfo->fb_height *
230 					bootinfo->fb_line_bytes;
231 
232 	fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
233 	fb->hf_access_flags |= HPCFB_ACCESS_WORD;
234 	fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
235 
236 	switch (bootinfo->fb_type) {
237 		/*
238 		 * gray scale
239 		 */
240 	case BIFB_D4_M2L_F:
241 	case BIFB_D4_M2L_Fx2:
242 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
243 		/* fall through */
244 	case BIFB_D4_M2L_0:
245 	case BIFB_D4_M2L_0x2:
246 		fb->hf_class = HPCFB_CLASS_GRAYSCALE;
247 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
248 		fb->hf_pack_width = 8;
249 		fb->hf_pixels_per_pack = 2;
250 		fb->hf_pixel_width = 4;
251 		fb->hf_class_data_length = sizeof(struct hf_gray_tag);
252 		fb->hf_u.hf_gray.hf_flags = 0;	/* reserved for future use */
253 		break;
254 
255 		/*
256 		 * indexed color
257 		 */
258 	case BIFB_D8_FF:
259 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
260 		/* fall through */
261 	case BIFB_D8_00:
262 		fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
263 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
264 		fb->hf_pack_width = 8;
265 		fb->hf_pixels_per_pack = 1;
266 		fb->hf_pixel_width = 8;
267 		fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
268 		fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */
269 		break;
270 
271 		/*
272 		 * RGB color
273 		 */
274 	case BIFB_D16_FFFF:
275 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
276 		/* fall through */
277 	case BIFB_D16_0000:
278 		fb->hf_class = HPCFB_CLASS_RGBCOLOR;
279 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
280 		fb->hf_order_flags = HPCFB_REVORDER_BYTE;
281 		fb->hf_pack_width = 16;
282 		fb->hf_pixels_per_pack = 1;
283 		fb->hf_pixel_width = 16;
284 
285 		fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
286 		fb->hf_u.hf_rgb.hf_flags = 0;	/* reserved for future use */
287 
288 		fb->hf_u.hf_rgb.hf_red_width = 5;
289 		fb->hf_u.hf_rgb.hf_red_shift = 11;
290 		fb->hf_u.hf_rgb.hf_green_width = 6;
291 		fb->hf_u.hf_rgb.hf_green_shift = 5;
292 		fb->hf_u.hf_rgb.hf_blue_width = 5;
293 		fb->hf_u.hf_rgb.hf_blue_shift = 0;
294 		fb->hf_u.hf_rgb.hf_alpha_width = 0;
295 		fb->hf_u.hf_rgb.hf_alpha_shift = 0;
296 		break;
297 
298 	default:
299 		printf("unsupported type %d.\n", bootinfo->fb_type);
300 		return -1;
301 	}
302 
303 	return 0; /* no error */
304 }
305 
306 static void
307 sed1356_power(int why, void *arg)
308 {
309 	struct sed1356_softc *sc = arg;
310 
311 	switch (why) {
312 	case PWR_SUSPEND:
313 	case PWR_STANDBY:
314 		sc->sc_powerstate |= PWRSTAT_SUSPEND;
315 		sed1356_update_powerstate(sc, PWRSTAT_ALL);
316 		break;
317 	case PWR_RESUME:
318 		sc->sc_powerstate &= ~PWRSTAT_SUSPEND;
319 		sed1356_update_powerstate(sc, PWRSTAT_ALL);
320 		break;
321 	}
322 }
323 
324 static void
325 sed1356_update_powerstate(struct sed1356_softc *sc, int updates)
326 {
327 	if (updates & PWRSTAT_LCD)
328 		config_hook_call(CONFIG_HOOK_POWERCONTROL,
329 		    CONFIG_HOOK_POWERCONTROL_LCD,
330 		    (void *)!(sc->sc_powerstate &
331 				(PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)));
332 
333 	if (updates & PWRSTAT_BACKLIGHT)
334 		config_hook_call(CONFIG_HOOK_POWERCONTROL,
335 		    CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
336 		    (void *)(!(sc->sc_powerstate &
337 				(PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)) &&
338 			     (sc->sc_powerstate & PWRSTAT_BACKLIGHT)));
339 }
340 
341 static int
342 sed1356_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct lwp *l)
343 {
344 	struct sed1356_softc *sc = (struct sed1356_softc *)v;
345 	struct hpcfb_fbconf *fbconf;
346 	struct hpcfb_dspconf *dspconf;
347 	struct wsdisplay_param *dispparam;
348 
349 	switch (cmd) {
350 	case WSDISPLAYIO_GETCMAP:
351 	case WSDISPLAYIO_PUTCMAP:
352 		/*
353 		 * XXX should be able to handle color map in 4/8 bpp mode.
354 		 */
355 		return EINVAL;
356 
357 	case WSDISPLAYIO_SVIDEO:
358 		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
359 			sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
360 		else
361 			sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
362 		sed1356_update_powerstate(sc, PWRSTAT_ALL);
363 		return 0;
364 
365 	case WSDISPLAYIO_GVIDEO:
366 		*(int *)data = (sc->sc_powerstate & PWRSTAT_VIDEOOFF) ?
367 				WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
368 		return 0;
369 
370 	case WSDISPLAYIO_GETPARAM:
371 		dispparam = (struct wsdisplay_param *)data;
372 		switch (dispparam->param) {
373 		case WSDISPLAYIO_PARAM_BACKLIGHT:
374 			VPRINTF(("sed1356_ioctl: GET:BACKLIGHT\n"));
375 			sed1356_init_brightness(sc, 0);
376 			sed1356_init_backlight(sc, 0);
377 			VPRINTF(("sed1356_ioctl: GET:(real)BACKLIGHT %d\n",
378 			    (sc->sc_powerstate & PWRSTAT_BACKLIGHT) ? 1: 0));
379 			dispparam->min = 0;
380 			dispparam->max = 1;
381 			if (sc->sc_max_brightness > 0)
382 				dispparam->curval = (sc->sc_brightness > 0) ?
383 				    1 : 0;
384 			else
385 				dispparam->curval =
386 				    (sc->sc_powerstate & PWRSTAT_BACKLIGHT) ?
387 				    1 : 0;
388 			VPRINTF(("sed1356_ioctl: GET:BACKLIGHT:%d(%s)\n",
389 			    dispparam->curval, (sc->sc_max_brightness > 0) ?
390 			    "brightness": "light"));
391 			return 0;
392 
393 		case WSDISPLAYIO_PARAM_CONTRAST:
394 			VPRINTF(("sed1356_ioctl: GET:CONTRAST\n"));
395 			sed1356_init_contrast(sc, 0);
396 			if (sc->sc_max_contrast > 0) {
397 				dispparam->min = 0;
398 				dispparam->max = sc->sc_max_contrast;
399 				dispparam->curval = sc->sc_contrast;
400 				VPRINTF(("sed1356_ioctl: GET:CONTRAST max=%d,"
401 				    " current=%d\n", sc->sc_max_contrast,
402 				    sc->sc_contrast));
403 				return 0;
404 			}
405 			VPRINTF(("sed1356_ioctl: GET:CONTRAST EINVAL\n"));
406 			return EINVAL;
407 
408 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
409 			VPRINTF(("sed1356_ioctl: GET:BRIGHTNESS\n"));
410 			sed1356_init_brightness(sc, 0);
411 			if (sc->sc_max_brightness > 0) {
412 				dispparam->min = 0;
413 				dispparam->max = sc->sc_max_brightness;
414 				dispparam->curval = sc->sc_brightness;
415 				VPRINTF(("sed1356_ioctl: GET:BRIGHTNESS max=%d,"
416 				    " current=%d\n", sc->sc_max_brightness,
417 				    sc->sc_brightness));
418 				return 0;
419 			}
420 			VPRINTF(("sed1356_ioctl: GET:BRIGHTNESS EINVAL\n"));
421 			return EINVAL;
422 
423 		default:
424 			return EINVAL;
425 		}
426 		break;
427 
428 	case WSDISPLAYIO_SETPARAM:
429 		dispparam = (struct wsdisplay_param*)data;
430 		switch (dispparam->param) {
431 		case WSDISPLAYIO_PARAM_BACKLIGHT:
432 			VPRINTF(("sed1356_ioctl: SET:BACKLIGHT\n"));
433 			if (dispparam->curval < 0 || 1 < dispparam->curval)
434 				return EINVAL;
435 			sed1356_init_brightness(sc, 0);
436 			VPRINTF(("sed1356_ioctl: SET:max brightness=%d\n",
437 			    sc->sc_max_brightness));
438 			if (sc->sc_max_brightness > 0) { /* dimmer */
439 				if (dispparam->curval == 0){
440 					sc->sc_brightness_save =
441 					    sc->sc_brightness;
442 					sed1356_set_brightness(sc, 0); /* min */
443 				} else {
444 					if (sc->sc_brightness_save == 0)
445 						sc->sc_brightness_save =
446 						    sc->sc_max_brightness;
447 					sed1356_set_brightness(sc,
448 					    sc->sc_brightness_save);
449 				}
450 				VPRINTF(("sed1356_ioctl: SET:BACKLIGHT:"
451 				    "brightness=%d\n", sc->sc_brightness));
452 			} else { /* off */
453 				if (dispparam->curval == 0)
454 					sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
455 				else
456 					sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
457 				VPRINTF(("sed1356_ioctl: SET:BACKLIGHT:"
458 				    "powerstate %d\n", (sc->sc_powerstate &
459 				    PWRSTAT_BACKLIGHT) ? 1 : 0));
460 				sed1356_update_powerstate(sc, PWRSTAT_BACKLIGHT);
461 				VPRINTF(("sed1356_ioctl: SET:BACKLIGHT:%d\n",
462 				    (sc->sc_powerstate & PWRSTAT_BACKLIGHT) ?
463 				    1 : 0));
464 			}
465 			return 0;
466 
467 		case WSDISPLAYIO_PARAM_CONTRAST:
468 			VPRINTF(("sed1356_ioctl: SET:CONTRAST\n"));
469 			sed1356_init_contrast(sc, 0);
470 			if (dispparam->curval < 0 ||
471 			    sc->sc_max_contrast < dispparam->curval)
472 				return EINVAL;
473 			if (sc->sc_max_contrast > 0) {
474 #ifdef SED_DEBUG
475 				int org = sc->sc_contrast;
476 #endif
477 				sed1356_set_contrast(sc, dispparam->curval);
478 				VPRINTF(("sed1356_ioctl: SET:CONTRAST org=%d,"
479 				    " current=%d\n", org, sc->sc_contrast));
480 				return 0;
481 			}
482 			VPRINTF(("sed1356_ioctl: SET:CONTRAST EINVAL\n"));
483 			return EINVAL;
484 
485 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
486 			VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS\n"));
487 			sed1356_init_brightness(sc, 0);
488 			if (dispparam->curval < 0 ||
489 			    sc->sc_max_brightness < dispparam->curval)
490 				return EINVAL;
491 			if (sc->sc_max_brightness > 0) {
492 #ifdef SED_DEBUG
493 				int org = sc->sc_brightness;
494 #endif
495 				sed1356_set_brightness(sc, dispparam->curval);
496 				VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS org=%d,"
497 				    " current=%d\n", org, sc->sc_brightness));
498 				return 0;
499 			}
500 			VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS EINVAL\n"));
501 			return EINVAL;
502 
503 		default:
504 			return EINVAL;
505 		}
506 		return 0;
507 
508 	case HPCFBIO_GCONF:
509 		fbconf = (struct hpcfb_fbconf *)data;
510 		if (fbconf->hf_conf_index != 0 &&
511 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
512 			return EINVAL;
513 		}
514 		*fbconf = sc->sc_fbconf;	/* structure assignment */
515 		return 0;
516 	case HPCFBIO_SCONF:
517 		fbconf = (struct hpcfb_fbconf *)data;
518 		if (fbconf->hf_conf_index != 0 &&
519 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
520 			return EINVAL;
521 		}
522 		/*
523 		 * nothing to do because we have only one configuration
524 		 */
525 		return 0;
526 	case HPCFBIO_GDSPCONF:
527 		dspconf = (struct hpcfb_dspconf *)data;
528 		if ((dspconf->hd_unit_index != 0 &&
529 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
530 		    (dspconf->hd_conf_index != 0 &&
531 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
532 			return EINVAL;
533 		}
534 		*dspconf = sc->sc_dspconf;	/* structure assignment */
535 		return 0;
536 	case HPCFBIO_SDSPCONF:
537 		dspconf = (struct hpcfb_dspconf *)data;
538 		if ((dspconf->hd_unit_index != 0 &&
539 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
540 		    (dspconf->hd_conf_index != 0 &&
541 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
542 			return EINVAL;
543 		}
544 		/*
545 		 * nothing to do
546 		 * because we have only one unit and one configuration
547 		 */
548 		return 0;
549 	case HPCFBIO_GOP:
550 	case HPCFBIO_SOP:
551 		/*
552 		 * curently not implemented...
553 		 */
554 		return EINVAL;
555 	}
556 
557 	return EPASSTHROUGH;
558 }
559 
560 static paddr_t
561 sed1356_mmap(void *ctx, off_t offset, int prot)
562 {
563 	struct sed1356_softc *sc = (struct sed1356_softc *)ctx;
564 
565 	if (offset < 0 ||
566 	    (sc->sc_fbconf.hf_bytes_per_plane +
567 	     sc->sc_fbconf.hf_offset) < offset)
568 		return -1;
569 
570 	return __BTOP((u_long)bootinfo->fb_addr + offset);
571 }
572 
573 static void
574 sed1356_init_backlight(struct sed1356_softc *sc, int inattach)
575 {
576 	int val = -1;
577 
578 	if (sc->sc_lcd_inited & BACKLIGHT_INITED)
579 		return;
580 
581 	if (config_hook_call(CONFIG_HOOK_GET,
582 	    CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) {
583 		/* we can get real light state */
584 		VPRINTF(("sed1356_init_backlight: real backlight=%d\n", val));
585 		if (val == 0)
586 			sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
587 		else
588 			sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
589 		sc->sc_lcd_inited |= BACKLIGHT_INITED;
590 	} else if (inattach) {
591 		/*
592 		   we cannot get real light state in attach time
593 		   because light device not yet attached.
594 		   we will retry in !inattach.
595 		   temporary assume light is on.
596 		 */
597 		sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
598 	} else {
599 		/* we cannot get real light state, so work by myself state */
600 		sc->sc_lcd_inited |= BACKLIGHT_INITED;
601 	}
602 }
603 
604 void
605 sed1356_init_brightness(struct sed1356_softc *sc, int inattach)
606 {
607 	int val = -1;
608 
609 	if (sc->sc_lcd_inited & BRIGHTNESS_INITED)
610 		return;
611 
612 	VPRINTF(("sed1356_init_brightness\n"));
613 	if (config_hook_call(CONFIG_HOOK_GET,
614 	    CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) {
615 		/* we can get real brightness max */
616 		VPRINTF(("sed1356_init_brightness: "
617 		    "real brightness max=%d\n", val));
618 		sc->sc_max_brightness = val;
619 		val = -1;
620 		if (config_hook_call(CONFIG_HOOK_GET,
621 		    CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
622 			/* we can get real brightness */
623 			VPRINTF(("sed1356_init_brightness: "
624 			    "real brightness=%d\n", val));
625 			sc->sc_brightness_save = sc->sc_brightness = val;
626 		} else {
627 			sc->sc_brightness_save =
628 			sc->sc_brightness = sc->sc_max_brightness;
629 		}
630 		sc->sc_lcd_inited |= BRIGHTNESS_INITED;
631 	} else if (inattach) {
632 		/*
633 		 * we cannot get real brightness in attach time
634 		 * because brightness device not yet attached.
635 		 * we will retry in !inattach.
636 		 */
637 		sc->sc_max_brightness = -1;
638 		sc->sc_brightness = -1;
639 		sc->sc_brightness_save = -1;
640 	} else {
641 		/* we cannot get real brightness */
642 		sc->sc_lcd_inited |= BRIGHTNESS_INITED;
643 	}
644 }
645 
646 void
647 sed1356_init_contrast(struct sed1356_softc *sc, int inattach)
648 {
649 	int val = -1;
650 
651 	if (sc->sc_lcd_inited & CONTRAST_INITED)
652 		return;
653 
654 	VPRINTF(("sed1356_init_contrast\n"));
655 	if (config_hook_call(CONFIG_HOOK_GET,
656 	    CONFIG_HOOK_CONTRAST_MAX, &val) != -1) {
657 		/* we can get real contrast max */
658 		VPRINTF(("sed1356_init_contrast: "
659 		    "real contrast max=%d\n", val));
660 		sc->sc_max_contrast = val;
661 		val = -1;
662 		if (config_hook_call(CONFIG_HOOK_GET,
663 		    CONFIG_HOOK_CONTRAST, &val) != -1) {
664 			/* we can get real contrast */
665 			VPRINTF(("sed1356_init_contrast: "
666 			    "real contrast=%d\n", val));
667 			sc->sc_contrast = val;
668 		} else {
669 			sc->sc_contrast = sc->sc_max_contrast;
670 		}
671 		sc->sc_lcd_inited |= CONTRAST_INITED;
672 	} else if (inattach) {
673 		/*
674 		 * we cannot get real contrast in attach time
675 		 * because contrast device not yet attached.
676 		 * we will retry in !inattach.
677 		 */
678 		sc->sc_max_contrast = -1;
679 		sc->sc_contrast = -1;
680 	} else {
681 		/* we cannot get real contrast */
682 		sc->sc_lcd_inited |= CONTRAST_INITED;
683 	}
684 }
685 
686 static void
687 sed1356_set_brightness(struct sed1356_softc *sc, int val)
688 {
689 	sc->sc_brightness = val;
690 
691 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
692 	if (config_hook_call(CONFIG_HOOK_GET,
693 	    CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
694 		sc->sc_brightness = val;
695 	}
696 }
697 
698 static void
699 sed1356_set_contrast(struct sed1356_softc *sc, int val)
700 {
701 	sc->sc_contrast = val;
702 
703 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
704 	if (config_hook_call(CONFIG_HOOK_GET,
705 	    CONFIG_HOOK_CONTRAST, &val) != -1) {
706 		sc->sc_contrast = val;
707 	}
708 }
709 
710 void
711 sed1356_toggle_lcdlight(void)
712 {
713 	struct sed1356_softc *sc = sed_cd.cd_devs[0];
714 
715 	if (sc->sc_powerstate & PWRSTAT_VIDEOOFF)
716 		sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
717 	else
718 		sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
719 
720 	sed1356_update_powerstate(sc, PWRSTAT_ALL);
721 }
722