xref: /netbsd-src/sys/arch/hpcarm/dev/sed_saip.c (revision 86c307248f84cb113ddd7597e82b97bcf315b5bb)
1 /*	$NetBSD: sed_saip.c,v 1.29 2022/05/28 10:36:22 andvar 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 AUTHOR 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 AUTHOR 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 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: sed_saip.c,v 1.29 2022/05/28 10:36:22 andvar Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <sys/reboot.h>
45 #include <sys/bus.h>
46 
47 #include <machine/bootinfo.h>
48 #include <machine/config_hook.h>
49 #include <machine/platid.h>
50 #include <machine/platid_mask.h>
51 
52 #include <dev/wscons/wsconsio.h>
53 #include <dev/wscons/wsdisplayvar.h>
54 
55 #include <dev/rasops/rasops.h>
56 
57 #include <dev/hpc/hpcfbvar.h>
58 #include <dev/hpc/hpcfbio.h>
59 #include <dev/hpc/hpccmapvar.h>
60 
61 #include <hpcarm/dev/sed1356var.h>
62 
63 #ifdef SED_DEBUG
64 #define VPRINTF(arg)	do { if (bootverbose) aprint_normal arg; } while (0)
65 #else
66 #define VPRINTF(arg)	/* nothing */
67 #endif
68 
69 /*
70  * Function prototypes.
71  */
72 static int	sed1356_match(device_t, cfdata_t, void *);
73 static void	sed1356_attach(device_t, device_t, void *);
74 static int	sed1356_ioctl(void *, u_long, void *, int, struct lwp *);
75 static paddr_t	sed1356_mmap(void *, off_t, int);
76 
77 static int	sed1356_init(struct hpcfb_fbconf *);
78 static void	sed1356_power(int, void *);
79 static void	sed1356_update_powerstate(struct sed1356_softc *, int);
80 static void	sed1356_init_backlight(struct sed1356_softc *, int);
81 static void	sed1356_set_brightness(struct sed1356_softc *, int);
82 static void	sed1356_set_contrast(struct sed1356_softc *, int);
83 
84 #if defined __mips__ || defined __sh__ || defined __arm__
85 #define __BTOP(x)		((paddr_t)(x) >> PGSHIFT)
86 #define __PTOB(x)		((paddr_t)(x) << PGSHIFT)
87 #else
88 #error "define btop, ptob."
89 #endif
90 
91 /*
92  * External functions/variables.
93  */
94 extern struct cfdriver sed_cd;
95 extern struct bus_space sa11x0_bs_tag;
96 extern int j720lcd_power(void *, int, long, void *);   /* XXX */
97 
98 /*
99  * Static variables.
100  */
101 CFATTACH_DECL_NEW(sed, sizeof(struct sed1356_softc),
102     sed1356_match, sed1356_attach, NULL, NULL);
103 struct hpcfb_accessops sed1356_ha = {
104 	sed1356_ioctl, sed1356_mmap
105 };
106 
107 static int attach_flag = 0;
108 
109 /*
110  * Function bodies.
111  */
112 static int
sed1356_match(device_t parent,cfdata_t match,void * aux)113 sed1356_match(device_t parent, cfdata_t match, void *aux)
114 {
115 
116 	/* XXX check version register */
117 	return 1;
118 }
119 
120 static void
sed1356_attach(device_t parent,device_t self,void * aux)121 sed1356_attach(device_t parent, device_t self, void *aux)
122 {
123 	struct sed1356_softc *sc = device_private(self);
124 	struct hpcfb_attach_args ha;
125 	int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1;
126 
127 	if (attach_flag) {
128 		panic("%s(%d): sed1356 attached twice", __FILE__, __LINE__);
129 	}
130 	attach_flag = 1;
131 
132 	if (sed1356_init(&sc->sc_fbconf) != 0) {
133 		/* just return so that hpcfb will not be attached */
134 		return;
135 	}
136 	aprint_normal("\n");
137 
138 	sc->sc_dev = self;
139 	sc->sc_iot = &sa11x0_bs_tag;
140 	sc->sc_parent = device_private(parent);
141 	if (bus_space_map(sc->sc_iot, (bus_addr_t)bootinfo->fb_addr & ~0x3fffff,
142 	    0x200, 0, &sc->sc_regh)) {
143 		aprint_normal_dev(self, "unable to map register\n");
144 		return;
145 	}
146 
147 	aprint_normal_dev(self, "Epson SED1356");
148 	if (console) {
149 		aprint_normal(", console");
150 	}
151 	aprint_normal("\n");
152 	aprint_normal_dev(self, "framebuffer address: 0x%08lx\n",
153 			  (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(device_xname(self),
158 	    sed1356_power, sc);
159 	if (sc->sc_powerhook == NULL)
160 		aprint_normal_dev(self, "WARNING: unable to establish power hook\n");
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, CFARGS_NONE);
189 }
190 
191 static int
sed1356_init(struct hpcfb_fbconf * fb)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 		aprint_normal("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 		aprint_normal("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 		aprint_normal("unsupported type %d.\n", bootinfo->fb_type);
300 		return -1;
301 	}
302 
303 	return 0; /* no error */
304 }
305 
306 static void
sed1356_power(int why,void * arg)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
sed1356_update_powerstate(struct sed1356_softc * sc,int updates)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
sed1356_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)342 sed1356_ioctl(void *v, u_long cmd, void *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 				VPRINTF(("sed1356_ioctl: SET:CONTRAST org=%d",
475 				    sc->sc_contrast));
476 				sed1356_set_contrast(sc, dispparam->curval);
477 				VPRINTF((", current=%d\n", sc->sc_contrast));
478 				return 0;
479 			}
480 			VPRINTF(("sed1356_ioctl: SET:CONTRAST EINVAL\n"));
481 			return EINVAL;
482 
483 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
484 			VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS\n"));
485 			sed1356_init_brightness(sc, 0);
486 			if (dispparam->curval < 0 ||
487 			    sc->sc_max_brightness < dispparam->curval)
488 				return EINVAL;
489 			if (sc->sc_max_brightness > 0) {
490 				VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS org=%d",
491 				    sc->sc_brightness));
492 				sed1356_set_brightness(sc, dispparam->curval);
493 				VPRINTF((", current=%d\n", sc->sc_brightness));
494 				return 0;
495 			}
496 			VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS EINVAL\n"));
497 			return EINVAL;
498 
499 		default:
500 			return EINVAL;
501 		}
502 		return 0;
503 
504 	case HPCFBIO_GCONF:
505 		fbconf = (struct hpcfb_fbconf *)data;
506 		if (fbconf->hf_conf_index != 0 &&
507 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
508 			return EINVAL;
509 		}
510 		*fbconf = sc->sc_fbconf;	/* structure assignment */
511 		return 0;
512 	case HPCFBIO_SCONF:
513 		fbconf = (struct hpcfb_fbconf *)data;
514 		if (fbconf->hf_conf_index != 0 &&
515 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
516 			return EINVAL;
517 		}
518 		/*
519 		 * nothing to do because we have only one configuration
520 		 */
521 		return 0;
522 	case HPCFBIO_GDSPCONF:
523 		dspconf = (struct hpcfb_dspconf *)data;
524 		if ((dspconf->hd_unit_index != 0 &&
525 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
526 		    (dspconf->hd_conf_index != 0 &&
527 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
528 			return EINVAL;
529 		}
530 		*dspconf = sc->sc_dspconf;	/* structure assignment */
531 		return 0;
532 	case HPCFBIO_SDSPCONF:
533 		dspconf = (struct hpcfb_dspconf *)data;
534 		if ((dspconf->hd_unit_index != 0 &&
535 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
536 		    (dspconf->hd_conf_index != 0 &&
537 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
538 			return EINVAL;
539 		}
540 		/*
541 		 * nothing to do
542 		 * because we have only one unit and one configuration
543 		 */
544 		return 0;
545 	case HPCFBIO_GOP:
546 	case HPCFBIO_SOP:
547 		/*
548 		 * currently not implemented...
549 		 */
550 		return EINVAL;
551 	}
552 
553 	return EPASSTHROUGH;
554 }
555 
556 static paddr_t
sed1356_mmap(void * ctx,off_t offset,int prot)557 sed1356_mmap(void *ctx, off_t offset, int prot)
558 {
559 	struct sed1356_softc *sc = (struct sed1356_softc *)ctx;
560 
561 	if (offset < 0 ||
562 	    (sc->sc_fbconf.hf_bytes_per_plane +
563 	     sc->sc_fbconf.hf_offset) < offset)
564 		return -1;
565 
566 	return __BTOP((u_long)bootinfo->fb_addr + offset);
567 }
568 
569 static void
sed1356_init_backlight(struct sed1356_softc * sc,int inattach)570 sed1356_init_backlight(struct sed1356_softc *sc, int inattach)
571 {
572 	int val = -1;
573 
574 	if (sc->sc_lcd_inited & BACKLIGHT_INITED)
575 		return;
576 
577 	if (config_hook_call(CONFIG_HOOK_GET,
578 	    CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) {
579 		/* we can get real light state */
580 		VPRINTF(("sed1356_init_backlight: real backlight=%d\n", val));
581 		if (val == 0)
582 			sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
583 		else
584 			sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
585 		sc->sc_lcd_inited |= BACKLIGHT_INITED;
586 	} else if (inattach) {
587 		/*
588 		   we cannot get real light state in attach time
589 		   because light device not yet attached.
590 		   we will retry in !inattach.
591 		   temporary assume light is on.
592 		 */
593 		sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
594 	} else {
595 		/* we cannot get real light state, so work by myself state */
596 		sc->sc_lcd_inited |= BACKLIGHT_INITED;
597 	}
598 }
599 
600 void
sed1356_init_brightness(struct sed1356_softc * sc,int inattach)601 sed1356_init_brightness(struct sed1356_softc *sc, int inattach)
602 {
603 	int val = -1;
604 
605 	if (sc->sc_lcd_inited & BRIGHTNESS_INITED)
606 		return;
607 
608 	VPRINTF(("sed1356_init_brightness\n"));
609 	if (config_hook_call(CONFIG_HOOK_GET,
610 	    CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) {
611 		/* we can get real brightness max */
612 		VPRINTF(("sed1356_init_brightness: "
613 		    "real brightness max=%d\n", val));
614 		sc->sc_max_brightness = val;
615 		val = -1;
616 		if (config_hook_call(CONFIG_HOOK_GET,
617 		    CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
618 			/* we can get real brightness */
619 			VPRINTF(("sed1356_init_brightness: "
620 			    "real brightness=%d\n", val));
621 			sc->sc_brightness_save = sc->sc_brightness = val;
622 		} else {
623 			sc->sc_brightness_save =
624 			sc->sc_brightness = sc->sc_max_brightness;
625 		}
626 		sc->sc_lcd_inited |= BRIGHTNESS_INITED;
627 	} else if (inattach) {
628 		/*
629 		 * we cannot get real brightness in attach time
630 		 * because brightness device not yet attached.
631 		 * we will retry in !inattach.
632 		 */
633 		sc->sc_max_brightness = -1;
634 		sc->sc_brightness = -1;
635 		sc->sc_brightness_save = -1;
636 	} else {
637 		/* we cannot get real brightness */
638 		sc->sc_lcd_inited |= BRIGHTNESS_INITED;
639 	}
640 }
641 
642 void
sed1356_init_contrast(struct sed1356_softc * sc,int inattach)643 sed1356_init_contrast(struct sed1356_softc *sc, int inattach)
644 {
645 	int val = -1;
646 
647 	if (sc->sc_lcd_inited & CONTRAST_INITED)
648 		return;
649 
650 	VPRINTF(("sed1356_init_contrast\n"));
651 	if (config_hook_call(CONFIG_HOOK_GET,
652 	    CONFIG_HOOK_CONTRAST_MAX, &val) != -1) {
653 		/* we can get real contrast max */
654 		VPRINTF(("sed1356_init_contrast: "
655 		    "real contrast max=%d\n", val));
656 		sc->sc_max_contrast = val;
657 		val = -1;
658 		if (config_hook_call(CONFIG_HOOK_GET,
659 		    CONFIG_HOOK_CONTRAST, &val) != -1) {
660 			/* we can get real contrast */
661 			VPRINTF(("sed1356_init_contrast: "
662 			    "real contrast=%d\n", val));
663 			sc->sc_contrast = val;
664 		} else {
665 			sc->sc_contrast = sc->sc_max_contrast;
666 		}
667 		sc->sc_lcd_inited |= CONTRAST_INITED;
668 	} else if (inattach) {
669 		/*
670 		 * we cannot get real contrast in attach time
671 		 * because contrast device not yet attached.
672 		 * we will retry in !inattach.
673 		 */
674 		sc->sc_max_contrast = -1;
675 		sc->sc_contrast = -1;
676 	} else {
677 		/* we cannot get real contrast */
678 		sc->sc_lcd_inited |= CONTRAST_INITED;
679 	}
680 }
681 
682 static void
sed1356_set_brightness(struct sed1356_softc * sc,int val)683 sed1356_set_brightness(struct sed1356_softc *sc, int val)
684 {
685 	sc->sc_brightness = val;
686 
687 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
688 	if (config_hook_call(CONFIG_HOOK_GET,
689 	    CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
690 		sc->sc_brightness = val;
691 	}
692 }
693 
694 static void
sed1356_set_contrast(struct sed1356_softc * sc,int val)695 sed1356_set_contrast(struct sed1356_softc *sc, int val)
696 {
697 	sc->sc_contrast = val;
698 
699 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
700 	if (config_hook_call(CONFIG_HOOK_GET,
701 	    CONFIG_HOOK_CONTRAST, &val) != -1) {
702 		sc->sc_contrast = val;
703 	}
704 }
705 
706 void
sed1356_toggle_lcdlight(void)707 sed1356_toggle_lcdlight(void)
708 {
709 	struct sed1356_softc *sc = device_lookup_private(&sed_cd, 0);
710 
711 	if (sc->sc_powerstate & PWRSTAT_VIDEOOFF)
712 		sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
713 	else
714 		sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
715 
716 	sed1356_update_powerstate(sc, PWRSTAT_ALL);
717 }
718