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