xref: /netbsd-src/sys/arch/hpcarm/dev/sed_saip.c (revision 86c307248f84cb113ddd7597e82b97bcf315b5bb)
1*86c30724Sandvar /*	$NetBSD: sed_saip.c,v 1.29 2022/05/28 10:36:22 andvar Exp $	*/
276b3b49bStoshii 
376b3b49bStoshii /*-
476b3b49bStoshii  * Copyright (c) 1999-2001
576b3b49bStoshii  *         Shin Takemura and PocketBSD Project. All rights reserved.
676b3b49bStoshii  *
776b3b49bStoshii  * Redistribution and use in source and binary forms, with or without
876b3b49bStoshii  * modification, are permitted provided that the following conditions
976b3b49bStoshii  * are met:
1076b3b49bStoshii  * 1. Redistributions of source code must retain the above copyright
1176b3b49bStoshii  *    notice, this list of conditions and the following disclaimer.
1276b3b49bStoshii  * 2. Redistributions in binary form must reproduce the above copyright
1376b3b49bStoshii  *    notice, this list of conditions and the following disclaimer in the
1476b3b49bStoshii  *    documentation and/or other materials provided with the distribution.
1576b3b49bStoshii  * 3. All advertising materials mentioning features or use of this software
1676b3b49bStoshii  *    must display the following acknowledgement:
1776b3b49bStoshii  *	This product includes software developed by the PocketBSD project
1876b3b49bStoshii  *	and its contributors.
1976b3b49bStoshii  * 4. Neither the name of the project nor the names of its contributors
2076b3b49bStoshii  *    may be used to endorse or promote products derived from this software
2176b3b49bStoshii  *    without specific prior written permission.
2276b3b49bStoshii  *
23d6a89fc1Speter  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2476b3b49bStoshii  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2576b3b49bStoshii  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26d6a89fc1Speter  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2776b3b49bStoshii  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2876b3b49bStoshii  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2976b3b49bStoshii  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3076b3b49bStoshii  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3176b3b49bStoshii  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3276b3b49bStoshii  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3376b3b49bStoshii  * SUCH DAMAGE.
3476b3b49bStoshii  */
3576b3b49bStoshii 
3608716eaeSlukem #include <sys/cdefs.h>
37*86c30724Sandvar __KERNEL_RCSID(0, "$NetBSD: sed_saip.c,v 1.29 2022/05/28 10:36:22 andvar Exp $");
3808716eaeSlukem 
3976b3b49bStoshii #include <sys/param.h>
4076b3b49bStoshii #include <sys/systm.h>
4176b3b49bStoshii #include <sys/device.h>
4276b3b49bStoshii #include <sys/buf.h>
4376b3b49bStoshii #include <sys/ioctl.h>
4476b3b49bStoshii #include <sys/reboot.h>
459edf49b0Sdyoung #include <sys/bus.h>
4676b3b49bStoshii 
4776b3b49bStoshii #include <machine/bootinfo.h>
4876b3b49bStoshii #include <machine/config_hook.h>
49e671a13dStoshii #include <machine/platid.h>
50e671a13dStoshii #include <machine/platid_mask.h>
5176b3b49bStoshii 
5276b3b49bStoshii #include <dev/wscons/wsconsio.h>
5376b3b49bStoshii #include <dev/wscons/wsdisplayvar.h>
5476b3b49bStoshii 
5576b3b49bStoshii #include <dev/rasops/rasops.h>
5676b3b49bStoshii 
5776b3b49bStoshii #include <dev/hpc/hpcfbvar.h>
5876b3b49bStoshii #include <dev/hpc/hpcfbio.h>
5976b3b49bStoshii #include <dev/hpc/hpccmapvar.h>
6076b3b49bStoshii 
61724da0fdSpeter #include <hpcarm/dev/sed1356var.h>
62e671a13dStoshii 
63103776feSpeter #ifdef SED_DEBUG
644c494f76Srjs #define VPRINTF(arg)	do { if (bootverbose) aprint_normal arg; } while (0)
65103776feSpeter #else
66103776feSpeter #define VPRINTF(arg)	/* nothing */
67103776feSpeter #endif
6876b3b49bStoshii 
6976b3b49bStoshii /*
70724da0fdSpeter  * Function prototypes.
7176b3b49bStoshii  */
724c494f76Srjs static int	sed1356_match(device_t, cfdata_t, void *);
734c494f76Srjs static void	sed1356_attach(device_t, device_t, void *);
7453524e44Schristos static int	sed1356_ioctl(void *, u_long, void *, int, struct lwp *);
75724da0fdSpeter static paddr_t	sed1356_mmap(void *, off_t, int);
7676b3b49bStoshii 
7776b3b49bStoshii static int	sed1356_init(struct hpcfb_fbconf *);
7876b3b49bStoshii static void	sed1356_power(int, void *);
7976b3b49bStoshii static void	sed1356_update_powerstate(struct sed1356_softc *, int);
80724da0fdSpeter static void	sed1356_init_backlight(struct sed1356_softc *, int);
81724da0fdSpeter static void	sed1356_set_brightness(struct sed1356_softc *, int);
82724da0fdSpeter static void	sed1356_set_contrast(struct sed1356_softc *, int);
8376b3b49bStoshii 
8476b3b49bStoshii #if defined __mips__ || defined __sh__ || defined __arm__
8576b3b49bStoshii #define __BTOP(x)		((paddr_t)(x) >> PGSHIFT)
8676b3b49bStoshii #define __PTOB(x)		((paddr_t)(x) << PGSHIFT)
8776b3b49bStoshii #else
8876b3b49bStoshii #error "define btop, ptob."
8976b3b49bStoshii #endif
9076b3b49bStoshii 
9176b3b49bStoshii /*
92724da0fdSpeter  * External functions/variables.
93724da0fdSpeter  */
94724da0fdSpeter extern struct cfdriver sed_cd;
95724da0fdSpeter extern struct bus_space sa11x0_bs_tag;
96724da0fdSpeter extern int j720lcd_power(void *, int, long, void *);   /* XXX */
97724da0fdSpeter 
98724da0fdSpeter /*
99724da0fdSpeter  * Static variables.
10076b3b49bStoshii  */
1014c494f76Srjs CFATTACH_DECL_NEW(sed, sizeof(struct sed1356_softc),
102724da0fdSpeter     sed1356_match, sed1356_attach, NULL, NULL);
10376b3b49bStoshii struct hpcfb_accessops sed1356_ha = {
10476b3b49bStoshii 	sed1356_ioctl, sed1356_mmap
10576b3b49bStoshii };
10676b3b49bStoshii 
10776b3b49bStoshii static int attach_flag = 0;
10876b3b49bStoshii 
10976b3b49bStoshii /*
110724da0fdSpeter  * Function bodies.
11176b3b49bStoshii  */
112724da0fdSpeter static int
sed1356_match(device_t parent,cfdata_t match,void * aux)1134c494f76Srjs sed1356_match(device_t parent, cfdata_t match, void *aux)
11476b3b49bStoshii {
11576b3b49bStoshii 
11676b3b49bStoshii 	/* XXX check version register */
11776b3b49bStoshii 	return 1;
11876b3b49bStoshii }
11976b3b49bStoshii 
120724da0fdSpeter static void
sed1356_attach(device_t parent,device_t self,void * aux)1214c494f76Srjs sed1356_attach(device_t parent, device_t self, void *aux)
12276b3b49bStoshii {
1234c494f76Srjs 	struct sed1356_softc *sc = device_private(self);
12476b3b49bStoshii 	struct hpcfb_attach_args ha;
125f8c1bea1Stoshii 	int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1;
12676b3b49bStoshii 
12776b3b49bStoshii 	if (attach_flag) {
12876b3b49bStoshii 		panic("%s(%d): sed1356 attached twice", __FILE__, __LINE__);
12976b3b49bStoshii 	}
13076b3b49bStoshii 	attach_flag = 1;
13176b3b49bStoshii 
13276b3b49bStoshii 	if (sed1356_init(&sc->sc_fbconf) != 0) {
13376b3b49bStoshii 		/* just return so that hpcfb will not be attached */
13476b3b49bStoshii 		return;
13576b3b49bStoshii 	}
1364c494f76Srjs 	aprint_normal("\n");
13776b3b49bStoshii 
1384c494f76Srjs 	sc->sc_dev = self;
139e671a13dStoshii 	sc->sc_iot = &sa11x0_bs_tag;
1404c494f76Srjs 	sc->sc_parent = device_private(parent);
141e671a13dStoshii 	if (bus_space_map(sc->sc_iot, (bus_addr_t)bootinfo->fb_addr & ~0x3fffff,
142e671a13dStoshii 	    0x200, 0, &sc->sc_regh)) {
1434c494f76Srjs 		aprint_normal_dev(self, "unable to map register\n");
144e671a13dStoshii 		return;
145e671a13dStoshii 	}
146e671a13dStoshii 
1474c494f76Srjs 	aprint_normal_dev(self, "Epson SED1356");
148f8c1bea1Stoshii 	if (console) {
1494c494f76Srjs 		aprint_normal(", console");
15076b3b49bStoshii 	}
1514c494f76Srjs 	aprint_normal("\n");
1524c494f76Srjs 	aprint_normal_dev(self, "framebuffer address: 0x%08lx\n",
1534c494f76Srjs 			  (u_long)bootinfo->fb_addr);
15476b3b49bStoshii 
15576b3b49bStoshii 	/* Add a suspend hook to power saving */
15676b3b49bStoshii 	sc->sc_powerstate = 0;
157cbab9cadSchs 	sc->sc_powerhook = powerhook_establish(device_xname(self),
158f135e0d6Sjmcneill 	    sed1356_power, sc);
15976b3b49bStoshii 	if (sc->sc_powerhook == NULL)
1604c494f76Srjs 		aprint_normal_dev(self, "WARNING: unable to establish power hook\n");
16176b3b49bStoshii 
162724da0fdSpeter 	/* Initialize backlight brightness and lcd contrast */
16376b3b49bStoshii 	sc->sc_lcd_inited = 0;
16476b3b49bStoshii 	sed1356_init_brightness(sc, 1);
16576b3b49bStoshii 	sed1356_init_contrast(sc, 1);
16676b3b49bStoshii 	sed1356_init_backlight(sc, 1);
16776b3b49bStoshii 
168f8c1bea1Stoshii 	if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0)
169724da0fdSpeter 		panic("sed1356_attach: cannot init fb console");
170f8c1bea1Stoshii 
171f8c1bea1Stoshii 	ha.ha_console = console;
17276b3b49bStoshii 	ha.ha_accessops = &sed1356_ha;
17376b3b49bStoshii 	ha.ha_accessctx = sc;
17476b3b49bStoshii 	ha.ha_curfbconf = 0;
17576b3b49bStoshii 	ha.ha_nfbconf = 1;
17676b3b49bStoshii 	ha.ha_fbconflist = &sc->sc_fbconf;
17776b3b49bStoshii 	ha.ha_curdspconf = 0;
17876b3b49bStoshii 	ha.ha_ndspconf = 1;
17976b3b49bStoshii 	ha.ha_dspconflist = &sc->sc_dspconf;
18076b3b49bStoshii 
181e671a13dStoshii 	/* XXX */
182e671a13dStoshii 	if (platid_match(&platid, &platid_mask_MACH_HP_JORNADA_7XX)) {
183e671a13dStoshii 		config_hook(CONFIG_HOOK_POWERCONTROL,
184e671a13dStoshii 			    CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
185547e1f66Speter 			    CONFIG_HOOK_SHARE, j720lcd_power, sc);
186e671a13dStoshii 	}
187e671a13dStoshii 
188c7fb772bSthorpej 	config_found(self, &ha, hpcfbprint, CFARGS_NONE);
18976b3b49bStoshii }
19076b3b49bStoshii 
19176b3b49bStoshii static int
sed1356_init(struct hpcfb_fbconf * fb)19276b3b49bStoshii sed1356_init(struct hpcfb_fbconf *fb)
19376b3b49bStoshii {
19476b3b49bStoshii 	/*
19576b3b49bStoshii 	 * get fb settings from bootinfo
19676b3b49bStoshii 	 */
19776b3b49bStoshii 	if (bootinfo == NULL ||
19876b3b49bStoshii 	    bootinfo->fb_addr == 0 ||
19976b3b49bStoshii 	    bootinfo->fb_line_bytes == 0 ||
20076b3b49bStoshii 	    bootinfo->fb_width == 0 ||
20176b3b49bStoshii 	    bootinfo->fb_height == 0) {
2024c494f76Srjs 		aprint_normal("no frame buffer information.\n");
203724da0fdSpeter 		return -1;
20476b3b49bStoshii 	}
20576b3b49bStoshii 
20676b3b49bStoshii 	/* zero fill */
207cd3fb67fSichiro 	memset(fb, 0, sizeof(*fb));
20876b3b49bStoshii 
20976b3b49bStoshii 	fb->hf_conf_index	= 0;	/* configuration index		*/
21076b3b49bStoshii 	fb->hf_nconfs		= 1;   	/* how many configurations	*/
21176b3b49bStoshii 	strcpy(fb->hf_name, "built-in video");
21276b3b49bStoshii 					/* frame buffer name		*/
21376b3b49bStoshii 	strcpy(fb->hf_conf_name, "default");
21476b3b49bStoshii 					/* configuration name		*/
21576b3b49bStoshii 	fb->hf_height		= bootinfo->fb_height;
21676b3b49bStoshii 	fb->hf_width		= bootinfo->fb_width;
217e671a13dStoshii 
21876b3b49bStoshii 	if (bus_space_map(&sa11x0_bs_tag, (bus_addr_t)bootinfo->fb_addr,
21976b3b49bStoshii 			   bootinfo->fb_height * bootinfo->fb_line_bytes,
22076b3b49bStoshii 			   0, &fb->hf_baseaddr)) {
2214c494f76Srjs 		aprint_normal("unable to map framebuffer\n");
222724da0fdSpeter 		return -1;
22376b3b49bStoshii 	}
22476b3b49bStoshii 	fb->hf_offset		= (u_long)bootinfo->fb_addr -
22576b3b49bStoshii 				      __PTOB(__BTOP(bootinfo->fb_addr));
22676b3b49bStoshii 					/* frame buffer start offset   	*/
22776b3b49bStoshii 	fb->hf_bytes_per_line	= bootinfo->fb_line_bytes;
22876b3b49bStoshii 	fb->hf_nplanes		= 1;
22976b3b49bStoshii 	fb->hf_bytes_per_plane	= bootinfo->fb_height *
23076b3b49bStoshii 					bootinfo->fb_line_bytes;
23176b3b49bStoshii 
23276b3b49bStoshii 	fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
23376b3b49bStoshii 	fb->hf_access_flags |= HPCFB_ACCESS_WORD;
23476b3b49bStoshii 	fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
23576b3b49bStoshii 
23676b3b49bStoshii 	switch (bootinfo->fb_type) {
23776b3b49bStoshii 		/*
23876b3b49bStoshii 		 * gray scale
23976b3b49bStoshii 		 */
24076b3b49bStoshii 	case BIFB_D4_M2L_F:
24176b3b49bStoshii 	case BIFB_D4_M2L_Fx2:
24276b3b49bStoshii 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
24376b3b49bStoshii 		/* fall through */
24476b3b49bStoshii 	case BIFB_D4_M2L_0:
24576b3b49bStoshii 	case BIFB_D4_M2L_0x2:
24676b3b49bStoshii 		fb->hf_class = HPCFB_CLASS_GRAYSCALE;
24776b3b49bStoshii 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
24876b3b49bStoshii 		fb->hf_pack_width = 8;
24976b3b49bStoshii 		fb->hf_pixels_per_pack = 2;
25076b3b49bStoshii 		fb->hf_pixel_width = 4;
25176b3b49bStoshii 		fb->hf_class_data_length = sizeof(struct hf_gray_tag);
25276b3b49bStoshii 		fb->hf_u.hf_gray.hf_flags = 0;	/* reserved for future use */
25376b3b49bStoshii 		break;
25476b3b49bStoshii 
25576b3b49bStoshii 		/*
25676b3b49bStoshii 		 * indexed color
25776b3b49bStoshii 		 */
25876b3b49bStoshii 	case BIFB_D8_FF:
25976b3b49bStoshii 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
26076b3b49bStoshii 		/* fall through */
26176b3b49bStoshii 	case BIFB_D8_00:
26276b3b49bStoshii 		fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
26376b3b49bStoshii 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
26476b3b49bStoshii 		fb->hf_pack_width = 8;
26576b3b49bStoshii 		fb->hf_pixels_per_pack = 1;
26676b3b49bStoshii 		fb->hf_pixel_width = 8;
26776b3b49bStoshii 		fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
26876b3b49bStoshii 		fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */
26976b3b49bStoshii 		break;
27076b3b49bStoshii 
27176b3b49bStoshii 		/*
27276b3b49bStoshii 		 * RGB color
27376b3b49bStoshii 		 */
27476b3b49bStoshii 	case BIFB_D16_FFFF:
27576b3b49bStoshii 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
27676b3b49bStoshii 		/* fall through */
27776b3b49bStoshii 	case BIFB_D16_0000:
27876b3b49bStoshii 		fb->hf_class = HPCFB_CLASS_RGBCOLOR;
27976b3b49bStoshii 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
28064b6b76aStakemura 		fb->hf_order_flags = HPCFB_REVORDER_BYTE;
28176b3b49bStoshii 		fb->hf_pack_width = 16;
28276b3b49bStoshii 		fb->hf_pixels_per_pack = 1;
28376b3b49bStoshii 		fb->hf_pixel_width = 16;
28476b3b49bStoshii 
28576b3b49bStoshii 		fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
28676b3b49bStoshii 		fb->hf_u.hf_rgb.hf_flags = 0;	/* reserved for future use */
28776b3b49bStoshii 
28876b3b49bStoshii 		fb->hf_u.hf_rgb.hf_red_width = 5;
28976b3b49bStoshii 		fb->hf_u.hf_rgb.hf_red_shift = 11;
29076b3b49bStoshii 		fb->hf_u.hf_rgb.hf_green_width = 6;
29176b3b49bStoshii 		fb->hf_u.hf_rgb.hf_green_shift = 5;
29276b3b49bStoshii 		fb->hf_u.hf_rgb.hf_blue_width = 5;
29376b3b49bStoshii 		fb->hf_u.hf_rgb.hf_blue_shift = 0;
29476b3b49bStoshii 		fb->hf_u.hf_rgb.hf_alpha_width = 0;
29576b3b49bStoshii 		fb->hf_u.hf_rgb.hf_alpha_shift = 0;
29676b3b49bStoshii 		break;
29776b3b49bStoshii 
29876b3b49bStoshii 	default:
2994c494f76Srjs 		aprint_normal("unsupported type %d.\n", bootinfo->fb_type);
300724da0fdSpeter 		return -1;
30176b3b49bStoshii 	}
30276b3b49bStoshii 
303724da0fdSpeter 	return 0; /* no error */
30476b3b49bStoshii }
30576b3b49bStoshii 
30676b3b49bStoshii static void
sed1356_power(int why,void * arg)30776b3b49bStoshii sed1356_power(int why, void *arg)
30876b3b49bStoshii {
30976b3b49bStoshii 	struct sed1356_softc *sc = arg;
31076b3b49bStoshii 
31176b3b49bStoshii 	switch (why) {
31276b3b49bStoshii 	case PWR_SUSPEND:
31376b3b49bStoshii 	case PWR_STANDBY:
31476b3b49bStoshii 		sc->sc_powerstate |= PWRSTAT_SUSPEND;
31576b3b49bStoshii 		sed1356_update_powerstate(sc, PWRSTAT_ALL);
31676b3b49bStoshii 		break;
31776b3b49bStoshii 	case PWR_RESUME:
31876b3b49bStoshii 		sc->sc_powerstate &= ~PWRSTAT_SUSPEND;
31976b3b49bStoshii 		sed1356_update_powerstate(sc, PWRSTAT_ALL);
32076b3b49bStoshii 		break;
32176b3b49bStoshii 	}
32276b3b49bStoshii }
32376b3b49bStoshii 
32476b3b49bStoshii static void
sed1356_update_powerstate(struct sed1356_softc * sc,int updates)32576b3b49bStoshii sed1356_update_powerstate(struct sed1356_softc *sc, int updates)
32676b3b49bStoshii {
32776b3b49bStoshii 	if (updates & PWRSTAT_LCD)
32876b3b49bStoshii 		config_hook_call(CONFIG_HOOK_POWERCONTROL,
32976b3b49bStoshii 		    CONFIG_HOOK_POWERCONTROL_LCD,
33076b3b49bStoshii 		    (void *)!(sc->sc_powerstate &
33176b3b49bStoshii 				(PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)));
33276b3b49bStoshii 
33376b3b49bStoshii 	if (updates & PWRSTAT_BACKLIGHT)
33476b3b49bStoshii 		config_hook_call(CONFIG_HOOK_POWERCONTROL,
33576b3b49bStoshii 		    CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
33676b3b49bStoshii 		    (void *)(!(sc->sc_powerstate &
33776b3b49bStoshii 				(PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)) &&
33876b3b49bStoshii 			     (sc->sc_powerstate & PWRSTAT_BACKLIGHT)));
33976b3b49bStoshii }
34076b3b49bStoshii 
341724da0fdSpeter static int
sed1356_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)34253524e44Schristos sed1356_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
34376b3b49bStoshii {
34476b3b49bStoshii 	struct sed1356_softc *sc = (struct sed1356_softc *)v;
34576b3b49bStoshii 	struct hpcfb_fbconf *fbconf;
34676b3b49bStoshii 	struct hpcfb_dspconf *dspconf;
34776b3b49bStoshii 	struct wsdisplay_param *dispparam;
34876b3b49bStoshii 
34976b3b49bStoshii 	switch (cmd) {
35076b3b49bStoshii 	case WSDISPLAYIO_GETCMAP:
35176b3b49bStoshii 	case WSDISPLAYIO_PUTCMAP:
35276b3b49bStoshii 		/*
35376b3b49bStoshii 		 * XXX should be able to handle color map in 4/8 bpp mode.
35476b3b49bStoshii 		 */
355724da0fdSpeter 		return EINVAL;
35676b3b49bStoshii 
35776b3b49bStoshii 	case WSDISPLAYIO_SVIDEO:
35876b3b49bStoshii 		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
35976b3b49bStoshii 			sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
36076b3b49bStoshii 		else
36176b3b49bStoshii 			sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
36276b3b49bStoshii 		sed1356_update_powerstate(sc, PWRSTAT_ALL);
36376b3b49bStoshii 		return 0;
36476b3b49bStoshii 
36576b3b49bStoshii 	case WSDISPLAYIO_GVIDEO:
36676b3b49bStoshii 		*(int *)data = (sc->sc_powerstate & PWRSTAT_VIDEOOFF) ?
36776b3b49bStoshii 				WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
36876b3b49bStoshii 		return 0;
36976b3b49bStoshii 
37076b3b49bStoshii 	case WSDISPLAYIO_GETPARAM:
37176b3b49bStoshii 		dispparam = (struct wsdisplay_param *)data;
37276b3b49bStoshii 		switch (dispparam->param) {
37376b3b49bStoshii 		case WSDISPLAYIO_PARAM_BACKLIGHT:
37476b3b49bStoshii 			VPRINTF(("sed1356_ioctl: GET:BACKLIGHT\n"));
37576b3b49bStoshii 			sed1356_init_brightness(sc, 0);
37676b3b49bStoshii 			sed1356_init_backlight(sc, 0);
37776b3b49bStoshii 			VPRINTF(("sed1356_ioctl: GET:(real)BACKLIGHT %d\n",
37876b3b49bStoshii 			    (sc->sc_powerstate & PWRSTAT_BACKLIGHT) ? 1: 0));
37976b3b49bStoshii 			dispparam->min = 0;
38076b3b49bStoshii 			dispparam->max = 1;
38176b3b49bStoshii 			if (sc->sc_max_brightness > 0)
382724da0fdSpeter 				dispparam->curval = (sc->sc_brightness > 0) ?
383724da0fdSpeter 				    1 : 0;
38476b3b49bStoshii 			else
38576b3b49bStoshii 				dispparam->curval =
386724da0fdSpeter 				    (sc->sc_powerstate & PWRSTAT_BACKLIGHT) ?
387724da0fdSpeter 				    1 : 0;
38876b3b49bStoshii 			VPRINTF(("sed1356_ioctl: GET:BACKLIGHT:%d(%s)\n",
389724da0fdSpeter 			    dispparam->curval, (sc->sc_max_brightness > 0) ?
390724da0fdSpeter 			    "brightness": "light"));
39176b3b49bStoshii 			return 0;
392724da0fdSpeter 
39376b3b49bStoshii 		case WSDISPLAYIO_PARAM_CONTRAST:
39476b3b49bStoshii 			VPRINTF(("sed1356_ioctl: GET:CONTRAST\n"));
39576b3b49bStoshii 			sed1356_init_contrast(sc, 0);
39676b3b49bStoshii 			if (sc->sc_max_contrast > 0) {
39776b3b49bStoshii 				dispparam->min = 0;
39876b3b49bStoshii 				dispparam->max = sc->sc_max_contrast;
39976b3b49bStoshii 				dispparam->curval = sc->sc_contrast;
400724da0fdSpeter 				VPRINTF(("sed1356_ioctl: GET:CONTRAST max=%d,"
401724da0fdSpeter 				    " current=%d\n", sc->sc_max_contrast,
402724da0fdSpeter 				    sc->sc_contrast));
40376b3b49bStoshii 				return 0;
40476b3b49bStoshii 			}
405724da0fdSpeter 			VPRINTF(("sed1356_ioctl: GET:CONTRAST EINVAL\n"));
406724da0fdSpeter 			return EINVAL;
407724da0fdSpeter 
40876b3b49bStoshii 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
40976b3b49bStoshii 			VPRINTF(("sed1356_ioctl: GET:BRIGHTNESS\n"));
41076b3b49bStoshii 			sed1356_init_brightness(sc, 0);
41176b3b49bStoshii 			if (sc->sc_max_brightness > 0) {
41276b3b49bStoshii 				dispparam->min = 0;
41376b3b49bStoshii 				dispparam->max = sc->sc_max_brightness;
41476b3b49bStoshii 				dispparam->curval = sc->sc_brightness;
415724da0fdSpeter 				VPRINTF(("sed1356_ioctl: GET:BRIGHTNESS max=%d,"
416724da0fdSpeter 				    " current=%d\n", sc->sc_max_brightness,
417724da0fdSpeter 				    sc->sc_brightness));
41876b3b49bStoshii 				return 0;
419724da0fdSpeter 			}
42076b3b49bStoshii 			VPRINTF(("sed1356_ioctl: GET:BRIGHTNESS EINVAL\n"));
421724da0fdSpeter 			return EINVAL;
422724da0fdSpeter 
42376b3b49bStoshii 		default:
424724da0fdSpeter 			return EINVAL;
42576b3b49bStoshii 		}
426724da0fdSpeter 		break;
42776b3b49bStoshii 
42876b3b49bStoshii 	case WSDISPLAYIO_SETPARAM:
42976b3b49bStoshii 		dispparam = (struct wsdisplay_param*)data;
43076b3b49bStoshii 		switch (dispparam->param) {
43176b3b49bStoshii 		case WSDISPLAYIO_PARAM_BACKLIGHT:
43276b3b49bStoshii 			VPRINTF(("sed1356_ioctl: SET:BACKLIGHT\n"));
433724da0fdSpeter 			if (dispparam->curval < 0 || 1 < dispparam->curval)
434724da0fdSpeter 				return EINVAL;
43576b3b49bStoshii 			sed1356_init_brightness(sc, 0);
436724da0fdSpeter 			VPRINTF(("sed1356_ioctl: SET:max brightness=%d\n",
437724da0fdSpeter 			    sc->sc_max_brightness));
43876b3b49bStoshii 			if (sc->sc_max_brightness > 0) { /* dimmer */
43976b3b49bStoshii 				if (dispparam->curval == 0){
440724da0fdSpeter 					sc->sc_brightness_save =
441724da0fdSpeter 					    sc->sc_brightness;
44276b3b49bStoshii 					sed1356_set_brightness(sc, 0); /* min */
44376b3b49bStoshii 				} else {
44476b3b49bStoshii 					if (sc->sc_brightness_save == 0)
445724da0fdSpeter 						sc->sc_brightness_save =
446724da0fdSpeter 						    sc->sc_max_brightness;
447724da0fdSpeter 					sed1356_set_brightness(sc,
448724da0fdSpeter 					    sc->sc_brightness_save);
44976b3b49bStoshii 				}
450724da0fdSpeter 				VPRINTF(("sed1356_ioctl: SET:BACKLIGHT:"
451724da0fdSpeter 				    "brightness=%d\n", sc->sc_brightness));
45276b3b49bStoshii 			} else { /* off */
45376b3b49bStoshii 				if (dispparam->curval == 0)
45476b3b49bStoshii 					sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
45576b3b49bStoshii 				else
45676b3b49bStoshii 					sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
457724da0fdSpeter 				VPRINTF(("sed1356_ioctl: SET:BACKLIGHT:"
458724da0fdSpeter 				    "powerstate %d\n", (sc->sc_powerstate &
459724da0fdSpeter 				    PWRSTAT_BACKLIGHT) ? 1 : 0));
46076b3b49bStoshii 				sed1356_update_powerstate(sc, PWRSTAT_BACKLIGHT);
46176b3b49bStoshii 				VPRINTF(("sed1356_ioctl: SET:BACKLIGHT:%d\n",
462724da0fdSpeter 				    (sc->sc_powerstate & PWRSTAT_BACKLIGHT) ?
463724da0fdSpeter 				    1 : 0));
46476b3b49bStoshii 			}
46576b3b49bStoshii 			return 0;
466724da0fdSpeter 
46776b3b49bStoshii 		case WSDISPLAYIO_PARAM_CONTRAST:
46876b3b49bStoshii 			VPRINTF(("sed1356_ioctl: SET:CONTRAST\n"));
46976b3b49bStoshii 			sed1356_init_contrast(sc, 0);
47076b3b49bStoshii 			if (dispparam->curval < 0 ||
47176b3b49bStoshii 			    sc->sc_max_contrast < dispparam->curval)
472724da0fdSpeter 				return EINVAL;
47376b3b49bStoshii 			if (sc->sc_max_contrast > 0) {
474d6a89fc1Speter 				VPRINTF(("sed1356_ioctl: SET:CONTRAST org=%d",
475d6a89fc1Speter 				    sc->sc_contrast));
47676b3b49bStoshii 				sed1356_set_contrast(sc, dispparam->curval);
477d6a89fc1Speter 				VPRINTF((", current=%d\n", sc->sc_contrast));
47876b3b49bStoshii 				return 0;
47976b3b49bStoshii 			}
480724da0fdSpeter 			VPRINTF(("sed1356_ioctl: SET:CONTRAST EINVAL\n"));
481724da0fdSpeter 			return EINVAL;
482724da0fdSpeter 
48376b3b49bStoshii 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
48476b3b49bStoshii 			VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS\n"));
48576b3b49bStoshii 			sed1356_init_brightness(sc, 0);
48676b3b49bStoshii 			if (dispparam->curval < 0 ||
48776b3b49bStoshii 			    sc->sc_max_brightness < dispparam->curval)
488724da0fdSpeter 				return EINVAL;
48976b3b49bStoshii 			if (sc->sc_max_brightness > 0) {
490d6a89fc1Speter 				VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS org=%d",
491d6a89fc1Speter 				    sc->sc_brightness));
49276b3b49bStoshii 				sed1356_set_brightness(sc, dispparam->curval);
493d6a89fc1Speter 				VPRINTF((", current=%d\n", sc->sc_brightness));
49476b3b49bStoshii 				return 0;
495724da0fdSpeter 			}
49676b3b49bStoshii 			VPRINTF(("sed1356_ioctl: SET:BRIGHTNESS EINVAL\n"));
497724da0fdSpeter 			return EINVAL;
498724da0fdSpeter 
49976b3b49bStoshii 		default:
500724da0fdSpeter 			return EINVAL;
50176b3b49bStoshii 		}
502724da0fdSpeter 		return 0;
50376b3b49bStoshii 
50476b3b49bStoshii 	case HPCFBIO_GCONF:
50576b3b49bStoshii 		fbconf = (struct hpcfb_fbconf *)data;
50676b3b49bStoshii 		if (fbconf->hf_conf_index != 0 &&
50776b3b49bStoshii 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
508724da0fdSpeter 			return EINVAL;
50976b3b49bStoshii 		}
51076b3b49bStoshii 		*fbconf = sc->sc_fbconf;	/* structure assignment */
511724da0fdSpeter 		return 0;
51276b3b49bStoshii 	case HPCFBIO_SCONF:
51376b3b49bStoshii 		fbconf = (struct hpcfb_fbconf *)data;
51476b3b49bStoshii 		if (fbconf->hf_conf_index != 0 &&
51576b3b49bStoshii 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
516724da0fdSpeter 			return EINVAL;
51776b3b49bStoshii 		}
51876b3b49bStoshii 		/*
519964859d8Sabs 		 * nothing to do because we have only one configuration
52076b3b49bStoshii 		 */
521724da0fdSpeter 		return 0;
52276b3b49bStoshii 	case HPCFBIO_GDSPCONF:
52376b3b49bStoshii 		dspconf = (struct hpcfb_dspconf *)data;
52476b3b49bStoshii 		if ((dspconf->hd_unit_index != 0 &&
52576b3b49bStoshii 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
52676b3b49bStoshii 		    (dspconf->hd_conf_index != 0 &&
52776b3b49bStoshii 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
528724da0fdSpeter 			return EINVAL;
52976b3b49bStoshii 		}
53076b3b49bStoshii 		*dspconf = sc->sc_dspconf;	/* structure assignment */
531724da0fdSpeter 		return 0;
53276b3b49bStoshii 	case HPCFBIO_SDSPCONF:
53376b3b49bStoshii 		dspconf = (struct hpcfb_dspconf *)data;
53476b3b49bStoshii 		if ((dspconf->hd_unit_index != 0 &&
53576b3b49bStoshii 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
53676b3b49bStoshii 		    (dspconf->hd_conf_index != 0 &&
53776b3b49bStoshii 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
538724da0fdSpeter 			return EINVAL;
53976b3b49bStoshii 		}
54076b3b49bStoshii 		/*
54176b3b49bStoshii 		 * nothing to do
542964859d8Sabs 		 * because we have only one unit and one configuration
54376b3b49bStoshii 		 */
544724da0fdSpeter 		return 0;
54576b3b49bStoshii 	case HPCFBIO_GOP:
54676b3b49bStoshii 	case HPCFBIO_SOP:
54776b3b49bStoshii 		/*
548*86c30724Sandvar 		 * currently not implemented...
54976b3b49bStoshii 		 */
550724da0fdSpeter 		return EINVAL;
55176b3b49bStoshii 	}
55276b3b49bStoshii 
553724da0fdSpeter 	return EPASSTHROUGH;
55476b3b49bStoshii }
55576b3b49bStoshii 
556724da0fdSpeter static paddr_t
sed1356_mmap(void * ctx,off_t offset,int prot)55776b3b49bStoshii sed1356_mmap(void *ctx, off_t offset, int prot)
55876b3b49bStoshii {
55976b3b49bStoshii 	struct sed1356_softc *sc = (struct sed1356_softc *)ctx;
56076b3b49bStoshii 
56176b3b49bStoshii 	if (offset < 0 ||
56276b3b49bStoshii 	    (sc->sc_fbconf.hf_bytes_per_plane +
56376b3b49bStoshii 	     sc->sc_fbconf.hf_offset) < offset)
56476b3b49bStoshii 		return -1;
56576b3b49bStoshii 
56676b3b49bStoshii 	return __BTOP((u_long)bootinfo->fb_addr + offset);
56776b3b49bStoshii }
56876b3b49bStoshii 
569724da0fdSpeter static void
sed1356_init_backlight(struct sed1356_softc * sc,int inattach)57076b3b49bStoshii sed1356_init_backlight(struct sed1356_softc *sc, int inattach)
57176b3b49bStoshii {
57276b3b49bStoshii 	int val = -1;
57376b3b49bStoshii 
57476b3b49bStoshii 	if (sc->sc_lcd_inited & BACKLIGHT_INITED)
57576b3b49bStoshii 		return;
57676b3b49bStoshii 
57776b3b49bStoshii 	if (config_hook_call(CONFIG_HOOK_GET,
57876b3b49bStoshii 	    CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) {
57976b3b49bStoshii 		/* we can get real light state */
58076b3b49bStoshii 		VPRINTF(("sed1356_init_backlight: real backlight=%d\n", val));
58176b3b49bStoshii 		if (val == 0)
58276b3b49bStoshii 			sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
58376b3b49bStoshii 		else
58476b3b49bStoshii 			sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
58576b3b49bStoshii 		sc->sc_lcd_inited |= BACKLIGHT_INITED;
58676b3b49bStoshii 	} else if (inattach) {
58776b3b49bStoshii 		/*
58876b3b49bStoshii 		   we cannot get real light state in attach time
58976b3b49bStoshii 		   because light device not yet attached.
59076b3b49bStoshii 		   we will retry in !inattach.
59176b3b49bStoshii 		   temporary assume light is on.
59276b3b49bStoshii 		 */
59376b3b49bStoshii 		sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
59476b3b49bStoshii 	} else {
59576b3b49bStoshii 		/* we cannot get real light state, so work by myself state */
59676b3b49bStoshii 		sc->sc_lcd_inited |= BACKLIGHT_INITED;
59776b3b49bStoshii 	}
59876b3b49bStoshii }
59976b3b49bStoshii 
60076b3b49bStoshii void
sed1356_init_brightness(struct sed1356_softc * sc,int inattach)60176b3b49bStoshii sed1356_init_brightness(struct sed1356_softc *sc, int inattach)
60276b3b49bStoshii {
60376b3b49bStoshii 	int val = -1;
60476b3b49bStoshii 
60576b3b49bStoshii 	if (sc->sc_lcd_inited & BRIGHTNESS_INITED)
60676b3b49bStoshii 		return;
60776b3b49bStoshii 
60876b3b49bStoshii 	VPRINTF(("sed1356_init_brightness\n"));
60976b3b49bStoshii 	if (config_hook_call(CONFIG_HOOK_GET,
61076b3b49bStoshii 	    CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) {
61176b3b49bStoshii 		/* we can get real brightness max */
612724da0fdSpeter 		VPRINTF(("sed1356_init_brightness: "
613724da0fdSpeter 		    "real brightness max=%d\n", val));
61476b3b49bStoshii 		sc->sc_max_brightness = val;
61576b3b49bStoshii 		val = -1;
61676b3b49bStoshii 		if (config_hook_call(CONFIG_HOOK_GET,
61776b3b49bStoshii 		    CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
61876b3b49bStoshii 			/* we can get real brightness */
619724da0fdSpeter 			VPRINTF(("sed1356_init_brightness: "
620724da0fdSpeter 			    "real brightness=%d\n", val));
62176b3b49bStoshii 			sc->sc_brightness_save = sc->sc_brightness = val;
62276b3b49bStoshii 		} else {
62376b3b49bStoshii 			sc->sc_brightness_save =
62476b3b49bStoshii 			sc->sc_brightness = sc->sc_max_brightness;
62576b3b49bStoshii 		}
62676b3b49bStoshii 		sc->sc_lcd_inited |= BRIGHTNESS_INITED;
62776b3b49bStoshii 	} else if (inattach) {
62876b3b49bStoshii 		/*
629724da0fdSpeter 		 * we cannot get real brightness in attach time
630724da0fdSpeter 		 * because brightness device not yet attached.
631724da0fdSpeter 		 * we will retry in !inattach.
63276b3b49bStoshii 		 */
63376b3b49bStoshii 		sc->sc_max_brightness = -1;
63476b3b49bStoshii 		sc->sc_brightness = -1;
63576b3b49bStoshii 		sc->sc_brightness_save = -1;
63676b3b49bStoshii 	} else {
63776b3b49bStoshii 		/* we cannot get real brightness */
63876b3b49bStoshii 		sc->sc_lcd_inited |= BRIGHTNESS_INITED;
63976b3b49bStoshii 	}
64076b3b49bStoshii }
64176b3b49bStoshii 
64276b3b49bStoshii void
sed1356_init_contrast(struct sed1356_softc * sc,int inattach)64376b3b49bStoshii sed1356_init_contrast(struct sed1356_softc *sc, int inattach)
64476b3b49bStoshii {
64576b3b49bStoshii 	int val = -1;
64676b3b49bStoshii 
64776b3b49bStoshii 	if (sc->sc_lcd_inited & CONTRAST_INITED)
64876b3b49bStoshii 		return;
64976b3b49bStoshii 
65076b3b49bStoshii 	VPRINTF(("sed1356_init_contrast\n"));
65176b3b49bStoshii 	if (config_hook_call(CONFIG_HOOK_GET,
65276b3b49bStoshii 	    CONFIG_HOOK_CONTRAST_MAX, &val) != -1) {
65376b3b49bStoshii 		/* we can get real contrast max */
654724da0fdSpeter 		VPRINTF(("sed1356_init_contrast: "
655724da0fdSpeter 		    "real contrast max=%d\n", val));
65676b3b49bStoshii 		sc->sc_max_contrast = val;
65776b3b49bStoshii 		val = -1;
65876b3b49bStoshii 		if (config_hook_call(CONFIG_HOOK_GET,
65976b3b49bStoshii 		    CONFIG_HOOK_CONTRAST, &val) != -1) {
66076b3b49bStoshii 			/* we can get real contrast */
661724da0fdSpeter 			VPRINTF(("sed1356_init_contrast: "
662724da0fdSpeter 			    "real contrast=%d\n", val));
66376b3b49bStoshii 			sc->sc_contrast = val;
66476b3b49bStoshii 		} else {
66576b3b49bStoshii 			sc->sc_contrast = sc->sc_max_contrast;
66676b3b49bStoshii 		}
66776b3b49bStoshii 		sc->sc_lcd_inited |= CONTRAST_INITED;
66876b3b49bStoshii 	} else if (inattach) {
66976b3b49bStoshii 		/*
670724da0fdSpeter 		 * we cannot get real contrast in attach time
671724da0fdSpeter 		 * because contrast device not yet attached.
672724da0fdSpeter 		 * we will retry in !inattach.
67376b3b49bStoshii 		 */
67476b3b49bStoshii 		sc->sc_max_contrast = -1;
67576b3b49bStoshii 		sc->sc_contrast = -1;
67676b3b49bStoshii 	} else {
67776b3b49bStoshii 		/* we cannot get real contrast */
67876b3b49bStoshii 		sc->sc_lcd_inited |= CONTRAST_INITED;
67976b3b49bStoshii 	}
68076b3b49bStoshii }
68176b3b49bStoshii 
682724da0fdSpeter static void
sed1356_set_brightness(struct sed1356_softc * sc,int val)68376b3b49bStoshii sed1356_set_brightness(struct sed1356_softc *sc, int val)
68476b3b49bStoshii {
68576b3b49bStoshii 	sc->sc_brightness = val;
68676b3b49bStoshii 
68776b3b49bStoshii 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
68876b3b49bStoshii 	if (config_hook_call(CONFIG_HOOK_GET,
68976b3b49bStoshii 	    CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
69076b3b49bStoshii 		sc->sc_brightness = val;
69176b3b49bStoshii 	}
69276b3b49bStoshii }
69376b3b49bStoshii 
694724da0fdSpeter static void
sed1356_set_contrast(struct sed1356_softc * sc,int val)69576b3b49bStoshii sed1356_set_contrast(struct sed1356_softc *sc, int val)
69676b3b49bStoshii {
69776b3b49bStoshii 	sc->sc_contrast = val;
69876b3b49bStoshii 
69976b3b49bStoshii 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
70076b3b49bStoshii 	if (config_hook_call(CONFIG_HOOK_GET,
70176b3b49bStoshii 	    CONFIG_HOOK_CONTRAST, &val) != -1) {
70276b3b49bStoshii 		sc->sc_contrast = val;
70376b3b49bStoshii 	}
70476b3b49bStoshii }
705547e1f66Speter 
706547e1f66Speter void
sed1356_toggle_lcdlight(void)707547e1f66Speter sed1356_toggle_lcdlight(void)
708547e1f66Speter {
709cf990769Srafal 	struct sed1356_softc *sc = device_lookup_private(&sed_cd, 0);
710547e1f66Speter 
711547e1f66Speter 	if (sc->sc_powerstate & PWRSTAT_VIDEOOFF)
712547e1f66Speter 		sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
713547e1f66Speter 	else
714547e1f66Speter 		sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
715547e1f66Speter 
716547e1f66Speter 	sed1356_update_powerstate(sc, PWRSTAT_ALL);
717547e1f66Speter }
718