xref: /netbsd-src/sys/arch/zaurus/dev/zlcd.c (revision 86c307248f84cb113ddd7597e82b97bcf315b5bb)
1*86c30724Sandvar /*	$NetBSD: zlcd.c,v 1.21 2022/05/28 10:36:23 andvar Exp $	*/
2953d3b5bSober /*	$OpenBSD: zaurus_lcd.c,v 1.20 2006/06/02 20:50:14 miod Exp $	*/
3953d3b5bSober /* NetBSD: lubbock_lcd.c,v 1.1 2003/08/09 19:38:53 bsh Exp */
4953d3b5bSober 
5953d3b5bSober /*
6953d3b5bSober  * Copyright (c) 2002, 2003  Genetec Corporation.  All rights reserved.
7953d3b5bSober  * Written by Hiroyuki Bessho for Genetec Corporation.
8953d3b5bSober  *
9953d3b5bSober  * Redistribution and use in source and binary forms, with or without
10953d3b5bSober  * modification, are permitted provided that the following conditions
11953d3b5bSober  * are met:
12953d3b5bSober  * 1. Redistributions of source code must retain the above copyright
13953d3b5bSober  *    notice, this list of conditions and the following disclaimer.
14953d3b5bSober  * 2. Redistributions in binary form must reproduce the above copyright
15953d3b5bSober  *    notice, this list of conditions and the following disclaimer in the
16953d3b5bSober  *    documentation and/or other materials provided with the distribution.
17953d3b5bSober  * 3. The name of Genetec Corporation may not be used to endorse or
18953d3b5bSober  *    promote products derived from this software without specific prior
19953d3b5bSober  *    written permission.
20953d3b5bSober  *
21953d3b5bSober  * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
22953d3b5bSober  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23953d3b5bSober  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24953d3b5bSober  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
25953d3b5bSober  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26953d3b5bSober  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27953d3b5bSober  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28953d3b5bSober  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29953d3b5bSober  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30953d3b5bSober  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31953d3b5bSober  * POSSIBILITY OF SUCH DAMAGE.
32953d3b5bSober  */
33953d3b5bSober 
34953d3b5bSober /*
35953d3b5bSober  * LCD driver for Sharp Zaurus (based on the Intel Lubbock driver).
36953d3b5bSober  *
37953d3b5bSober  * Controlling LCD is almost completely done through PXA2X0's
38953d3b5bSober  * integrated LCD controller.  Codes for it is arm/xscale/pxa2x0_lcd.c.
39953d3b5bSober  *
40953d3b5bSober  * Codes in this file provide platform specific things including:
41953d3b5bSober  *   LCD panel geometry
42b41763f4Stsutsui  *
43b41763f4Stsutsui  * LCD on/off switch and backlight brightness are done in lcdctl.c.
44953d3b5bSober  */
45953d3b5bSober 
46953d3b5bSober #include <sys/cdefs.h>
47*86c30724Sandvar __KERNEL_RCSID(0, "$NetBSD: zlcd.c,v 1.21 2022/05/28 10:36:23 andvar Exp $");
486145ba81Stsutsui 
496145ba81Stsutsui #include "lcdctl.h"
50953d3b5bSober 
51953d3b5bSober #include <sys/param.h>
52953d3b5bSober #include <sys/systm.h>
536145ba81Stsutsui #include <sys/device.h>
54953d3b5bSober 
55953d3b5bSober #include <dev/cons.h>
56953d3b5bSober #include <dev/wscons/wsconsio.h>
57953d3b5bSober #include <dev/wscons/wsdisplayvar.h>
58953d3b5bSober 
5974c51d31Snonaka #include <dev/hpc/hpcfbio.h>
6074c51d31Snonaka 
61953d3b5bSober #include <arm/xscale/pxa2x0var.h>
62953d3b5bSober #include <arm/xscale/pxa2x0_lcd.h>
63953d3b5bSober 
64953d3b5bSober #include <zaurus/zaurus/zaurus_var.h>
65003bdf4cSnonaka #include <zaurus/dev/zlcdvar.h>
666145ba81Stsutsui #if NLCDCTL > 0
676145ba81Stsutsui #include <zaurus/dev/lcdctlvar.h>
686145ba81Stsutsui #endif
69953d3b5bSober 
70953d3b5bSober /*
71953d3b5bSober  * wsdisplay glue
72953d3b5bSober  */
73f19ed1a8Speter static struct pxa2x0_wsscreen_descr lcd_std_screen = {
74f19ed1a8Speter 	.c = {
75f19ed1a8Speter 		.name = "std",
76f19ed1a8Speter 		.textops = &pxa2x0_lcd_emulops,
77f19ed1a8Speter 		.fontwidth = 8,
78f19ed1a8Speter 		.fontheight = 16,
79f19ed1a8Speter 		.capabilities = WSSCREEN_WSCOLORS,
80953d3b5bSober 	},
81f19ed1a8Speter 	.depth = 16,			/* bits per pixel */
825c470843Sober 	.flags = RI_ROTATE_CW,		/* quarter clockwise rotation */
83953d3b5bSober };
84953d3b5bSober 
85953d3b5bSober static const struct wsscreen_descr *lcd_scr_descr[] = {
86f19ed1a8Speter 	&lcd_std_screen.c
87953d3b5bSober };
88953d3b5bSober 
89f19ed1a8Speter static const struct wsscreen_list lcd_screen_list = {
90f19ed1a8Speter 	.nscreens = __arraycount(lcd_scr_descr),
91f19ed1a8Speter 	.screens = lcd_scr_descr,
92953d3b5bSober };
93953d3b5bSober 
9453524e44Schristos static int	lcd_ioctl(void *, void *, u_long, void *, int, struct lwp *);
95f19ed1a8Speter static int	lcd_show_screen(void *, void *, int,
96953d3b5bSober 		    void (*)(void *, int, int), void *);
97953d3b5bSober 
98f19ed1a8Speter struct wsdisplay_accessops lcd_accessops = {
99953d3b5bSober 	lcd_ioctl,
100953d3b5bSober 	pxa2x0_lcd_mmap,
101953d3b5bSober 	pxa2x0_lcd_alloc_screen,
102953d3b5bSober 	pxa2x0_lcd_free_screen,
103953d3b5bSober 	lcd_show_screen,
104f19ed1a8Speter 	NULL,
105f19ed1a8Speter 	NULL,
106f19ed1a8Speter 	NULL,
107953d3b5bSober };
108953d3b5bSober 
1096145ba81Stsutsui const struct lcd_panel_geometry lcd_panel_geometry_c3000 =
110953d3b5bSober {
111953d3b5bSober 	480,			/* Width */
112953d3b5bSober 	640,			/* Height */
113953d3b5bSober 	0,			/* No extra lines */
114953d3b5bSober 
115953d3b5bSober 	LCDPANEL_ACTIVE | LCDPANEL_VSP | LCDPANEL_HSP,
116953d3b5bSober 	1,			/* clock divider */
117953d3b5bSober 	0,			/* AC bias pin freq */
118953d3b5bSober 
119953d3b5bSober 	0x28,			/* horizontal sync pulse width */
120953d3b5bSober 	0x2e,			/* BLW */
121953d3b5bSober 	0x7d,			/* ELW */
122953d3b5bSober 
123953d3b5bSober 	2,			/* vertical sync pulse width */
124953d3b5bSober 	1,			/* BFW */
125953d3b5bSober 	0,			/* EFW */
126953d3b5bSober };
127953d3b5bSober 
1281a686006Snonaka static int	lcd_match(device_t, cfdata_t, void *);
1291a686006Snonaka static void	lcd_attach(device_t, device_t, void *);
130953d3b5bSober 
1311a686006Snonaka CFATTACH_DECL_NEW(zlcd, sizeof(struct pxa2x0_lcd_softc),
132953d3b5bSober 	lcd_match, lcd_attach, NULL, NULL);
133953d3b5bSober 
134003bdf4cSnonaka static bool	lcd_suspend(device_t, const pmf_qual_t *);
135003bdf4cSnonaka static bool	lcd_resume(device_t, const pmf_qual_t *);
136953d3b5bSober 
137953d3b5bSober static int
lcd_match(device_t parent,cfdata_t cf,void * aux)1381a686006Snonaka lcd_match(device_t parent, cfdata_t cf, void *aux)
139953d3b5bSober {
140953d3b5bSober 
141003bdf4cSnonaka 	if (ZAURUS_ISC1000 || ZAURUS_ISC3000)
142953d3b5bSober 		return 1;
143003bdf4cSnonaka 	return 0;
144953d3b5bSober }
145953d3b5bSober 
146953d3b5bSober static void
lcd_attach(device_t parent,device_t self,void * aux)1471a686006Snonaka lcd_attach(device_t parent, device_t self, void *aux)
148953d3b5bSober {
1491a686006Snonaka 	struct pxa2x0_lcd_softc *sc = device_private(self);
150953d3b5bSober 	struct wsemuldisplaydev_attach_args aa;
151953d3b5bSober 
1521a686006Snonaka 	sc->dev = self;
1531a686006Snonaka 
1546145ba81Stsutsui 	pxa2x0_lcd_attach_sub(sc, aux, &lcd_panel_geometry_c3000);
155953d3b5bSober 
156953d3b5bSober 	aa.console = glass_console;
157953d3b5bSober 	aa.scrdata = &lcd_screen_list;
158953d3b5bSober 	aa.accessops = &lcd_accessops;
159953d3b5bSober 	aa.accesscookie = sc;
160953d3b5bSober 
161c7fb772bSthorpej 	(void) config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE);
162953d3b5bSober 
163003bdf4cSnonaka 	if (!pmf_device_register(self, lcd_suspend, lcd_resume))
164003bdf4cSnonaka 		aprint_error_dev(self, "couldn't establish power handler\n");
165953d3b5bSober }
166953d3b5bSober 
167405a97b6Snonaka void
lcd_cnattach(void)168405a97b6Snonaka lcd_cnattach(void)
169405a97b6Snonaka {
170405a97b6Snonaka 
171533071c4Stsutsui 	if (ZAURUS_ISC1000 || ZAURUS_ISC3000)
1726145ba81Stsutsui 		pxa2x0_lcd_cnattach(&lcd_std_screen, &lcd_panel_geometry_c3000);
173405a97b6Snonaka }
174405a97b6Snonaka 
175953d3b5bSober /*
176664df27bSnonaka  * power management
177664df27bSnonaka  */
178664df27bSnonaka static bool
lcd_suspend(device_t dv,const pmf_qual_t * qual)179c1b390d4Sdyoung lcd_suspend(device_t dv, const pmf_qual_t *qual)
180664df27bSnonaka {
181664df27bSnonaka 	struct pxa2x0_lcd_softc *sc = device_private(dv);
182664df27bSnonaka 
1836145ba81Stsutsui #if NLCDCTL > 0
1846145ba81Stsutsui 	lcdctl_onoff(false);
1856145ba81Stsutsui #endif
186664df27bSnonaka 	pxa2x0_lcd_suspend(sc);
187664df27bSnonaka 
188664df27bSnonaka 	return true;
189664df27bSnonaka }
190664df27bSnonaka 
191664df27bSnonaka static bool
lcd_resume(device_t dv,const pmf_qual_t * qual)192c1b390d4Sdyoung lcd_resume(device_t dv, const pmf_qual_t *qual)
193664df27bSnonaka {
194664df27bSnonaka 	struct pxa2x0_lcd_softc *sc = device_private(dv);
195664df27bSnonaka 
196664df27bSnonaka 	pxa2x0_lcd_resume(sc);
1976145ba81Stsutsui #if NLCDCTL > 0
1986145ba81Stsutsui 	lcdctl_onoff(true);
1996145ba81Stsutsui #endif
200664df27bSnonaka 
201664df27bSnonaka 	return true;
202664df27bSnonaka }
203664df27bSnonaka 
204664df27bSnonaka /*
205953d3b5bSober  * wsdisplay accessops overrides
206953d3b5bSober  */
207f19ed1a8Speter static int
lcd_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)20853524e44Schristos lcd_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
209953d3b5bSober {
210953d3b5bSober 	struct pxa2x0_lcd_softc *sc = (struct pxa2x0_lcd_softc *)v;
21174c51d31Snonaka 	struct hpcfb_fbconf *fbconf;
21274c51d31Snonaka 	struct hpcfb_dspconf *dspconf;
213953d3b5bSober 	int res = EINVAL;
214953d3b5bSober 
215953d3b5bSober 	switch (cmd) {
2166145ba81Stsutsui #if NLCDCTL > 0
217953d3b5bSober 	case WSDISPLAYIO_GETPARAM:
218953d3b5bSober 	case WSDISPLAYIO_SETPARAM:
2196145ba81Stsutsui 		res = lcdctl_param(cmd, (struct wsdisplay_param *)data);
220953d3b5bSober 		break;
2216145ba81Stsutsui #endif
22274c51d31Snonaka 
22374c51d31Snonaka 	case HPCFBIO_GCONF:
22474c51d31Snonaka 		fbconf = (struct hpcfb_fbconf *)data;
22574c51d31Snonaka 		if (fbconf->hf_conf_index != 0 &&
22674c51d31Snonaka 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
22774c51d31Snonaka 			break;
22874c51d31Snonaka 		}
22974c51d31Snonaka 
23074c51d31Snonaka 		fbconf->hf_conf_index = 0;
23174c51d31Snonaka 		fbconf->hf_nconfs = 1;
23274c51d31Snonaka 		fbconf->hf_class = HPCFB_CLASS_RGBCOLOR;
23374c51d31Snonaka 		strlcpy(fbconf->hf_name, "Sharp Zaurus frame buffer",
23474c51d31Snonaka 		    sizeof(fbconf->hf_name));
23574c51d31Snonaka 		strlcpy(fbconf->hf_conf_name, "default",
23674c51d31Snonaka 		    sizeof(fbconf->hf_conf_name));
23774c51d31Snonaka 		fbconf->hf_width = sc->geometry->panel_width;
23874c51d31Snonaka 		fbconf->hf_height = sc->geometry->panel_height;
23974c51d31Snonaka 		fbconf->hf_baseaddr = (u_long)sc->active->buf_va;
24074c51d31Snonaka 		fbconf->hf_offset = 0;
24174c51d31Snonaka 		fbconf->hf_bytes_per_line = sc->geometry->panel_width *
24274c51d31Snonaka 		    sc->active->depth / 8;
24374c51d31Snonaka 		fbconf->hf_nplanes = 1;
24474c51d31Snonaka 		fbconf->hf_bytes_per_plane = sc->geometry->panel_width *
24574c51d31Snonaka 		    sc->geometry->panel_height * sc->active->depth / 8;
24674c51d31Snonaka 		fbconf->hf_pack_width = sc->active->depth;
24774c51d31Snonaka 		fbconf->hf_pixels_per_pack = 1;
24874c51d31Snonaka 		fbconf->hf_pixel_width = sc->active->depth;
24974c51d31Snonaka 		fbconf->hf_access_flags = (0
25074c51d31Snonaka 					   | HPCFB_ACCESS_BYTE
25174c51d31Snonaka 					   | HPCFB_ACCESS_WORD
25274c51d31Snonaka 					   | HPCFB_ACCESS_DWORD);
25374c51d31Snonaka 		fbconf->hf_order_flags = 0;
25474c51d31Snonaka 		fbconf->hf_reg_offset = 0;
25574c51d31Snonaka 
25674c51d31Snonaka 		fbconf->hf_class_data_length = sizeof(struct hf_rgb_tag);
25774c51d31Snonaka 		fbconf->hf_u.hf_rgb.hf_flags = 0;
25874c51d31Snonaka 		fbconf->hf_u.hf_rgb.hf_red_width = 5;
25974c51d31Snonaka 		fbconf->hf_u.hf_rgb.hf_red_shift = 11;
26074c51d31Snonaka 		fbconf->hf_u.hf_rgb.hf_green_width = 6;
26174c51d31Snonaka 		fbconf->hf_u.hf_rgb.hf_green_shift = 5;
26274c51d31Snonaka 		fbconf->hf_u.hf_rgb.hf_blue_width = 5;
26374c51d31Snonaka 		fbconf->hf_u.hf_rgb.hf_blue_shift = 0;
26474c51d31Snonaka 		fbconf->hf_u.hf_rgb.hf_alpha_width = 0;
26574c51d31Snonaka 		fbconf->hf_u.hf_rgb.hf_alpha_shift = 0;
26674c51d31Snonaka 
26774c51d31Snonaka 		fbconf->hf_ext_size = 0;
26874c51d31Snonaka 		fbconf->hf_ext_data = NULL;
26974c51d31Snonaka 
27074c51d31Snonaka 		res = 0;
27174c51d31Snonaka 		break;
27274c51d31Snonaka 
27374c51d31Snonaka 	case HPCFBIO_SCONF:
27474c51d31Snonaka 		fbconf = (struct hpcfb_fbconf *)data;
27574c51d31Snonaka 		if (fbconf->hf_conf_index != 0 &&
27674c51d31Snonaka 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
27774c51d31Snonaka 			break;
27874c51d31Snonaka 		}
27974c51d31Snonaka 		/* nothing to do because we have only one configuration */
28074c51d31Snonaka 		res = 0;
28174c51d31Snonaka 		break;
28274c51d31Snonaka 
28374c51d31Snonaka 	case HPCFBIO_GDSPCONF:
28474c51d31Snonaka 		dspconf = (struct hpcfb_dspconf *)data;
28574c51d31Snonaka 		if ((dspconf->hd_unit_index != 0 &&
28674c51d31Snonaka 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
28774c51d31Snonaka 		    (dspconf->hd_conf_index != 0 &&
28874c51d31Snonaka 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
28974c51d31Snonaka 			break;
29074c51d31Snonaka 		}
29174c51d31Snonaka 
29274c51d31Snonaka 		dspconf->hd_unit_index = 0;
29374c51d31Snonaka 		dspconf->hd_nunits = 1;
29474c51d31Snonaka 		dspconf->hd_class = HPCFB_DSP_CLASS_COLORLCD;
29574c51d31Snonaka 		strlcpy(dspconf->hd_name, "Sharp Zaurus LCD",
29674c51d31Snonaka 		    sizeof(dspconf->hd_name));
29774c51d31Snonaka 		dspconf->hd_op_flags = 0;
29874c51d31Snonaka 		dspconf->hd_conf_index = 0;
29974c51d31Snonaka 		dspconf->hd_nconfs = 1;
30074c51d31Snonaka 		strlcpy(dspconf->hd_conf_name, "default",
30174c51d31Snonaka 		    sizeof(dspconf->hd_conf_name));
30274c51d31Snonaka 		dspconf->hd_width = sc->geometry->panel_width;
30374c51d31Snonaka 		dspconf->hd_height = sc->geometry->panel_height;
30474c51d31Snonaka 		dspconf->hd_xdpi = HPCFB_DSP_DPI_UNKNOWN;
30574c51d31Snonaka 		dspconf->hd_ydpi = HPCFB_DSP_DPI_UNKNOWN;
30674c51d31Snonaka 
30774c51d31Snonaka 		res = 0;
30874c51d31Snonaka 		break;
30974c51d31Snonaka 
31074c51d31Snonaka 	case HPCFBIO_SDSPCONF:
31174c51d31Snonaka 		dspconf = (struct hpcfb_dspconf *)data;
31274c51d31Snonaka 		if ((dspconf->hd_unit_index != 0 &&
31374c51d31Snonaka 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
31474c51d31Snonaka 		    (dspconf->hd_conf_index != 0 &&
31574c51d31Snonaka 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
31674c51d31Snonaka 			break;
31774c51d31Snonaka 		}
31874c51d31Snonaka 		/*
31974c51d31Snonaka 		 * nothing to do
32074c51d31Snonaka 		 * because we have only one unit and one configuration
32174c51d31Snonaka 		 */
32274c51d31Snonaka 		res = 0;
32374c51d31Snonaka 		break;
32474c51d31Snonaka 
32574c51d31Snonaka 	case HPCFBIO_GOP:
32674c51d31Snonaka 	case HPCFBIO_SOP:
327*86c30724Sandvar 		/* currently not implemented...  */
32874c51d31Snonaka 		break;
329953d3b5bSober 	}
330953d3b5bSober 
331953d3b5bSober 	if (res == EINVAL)
332953d3b5bSober 		res = pxa2x0_lcd_ioctl(v, vs, cmd, data, flag, l);
333953d3b5bSober 	return res;
334953d3b5bSober }
335953d3b5bSober 
336f19ed1a8Speter static int
lcd_show_screen(void * v,void * cookie,int waitok,void (* cb_func)(void *,int,int),void * cb_arg)337953d3b5bSober lcd_show_screen(void *v, void *cookie, int waitok,
338f19ed1a8Speter     void (*cb_func)(void *, int, int), void *cb_arg)
339953d3b5bSober {
340953d3b5bSober 	int error;
341953d3b5bSober 
342f19ed1a8Speter 	error = pxa2x0_lcd_show_screen(v, cookie, waitok, cb_func, cb_arg);
343953d3b5bSober 	if (error)
344953d3b5bSober 		return (error);
345953d3b5bSober 
3466145ba81Stsutsui #if NLCDCTL > 0
347953d3b5bSober 	/* Turn on LCD */
3486145ba81Stsutsui 	lcdctl_onoff(true);
3496145ba81Stsutsui #endif
350953d3b5bSober 
351953d3b5bSober 	return 0;
352953d3b5bSober }
353