Home | History | Annotate | Line # | Download | only in dev
zlcd.c revision 1.16
      1 /*	$NetBSD: zlcd.c,v 1.16 2012/01/25 16:51:17 tsutsui Exp $	*/
      2 /*	$OpenBSD: zaurus_lcd.c,v 1.20 2006/06/02 20:50:14 miod Exp $	*/
      3 /* NetBSD: lubbock_lcd.c,v 1.1 2003/08/09 19:38:53 bsh Exp */
      4 
      5 /*
      6  * Copyright (c) 2002, 2003  Genetec Corporation.  All rights reserved.
      7  * Written by Hiroyuki Bessho for Genetec Corporation.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. The name of Genetec Corporation may not be used to endorse or
     18  *    promote products derived from this software without specific prior
     19  *    written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
     25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 /*
     35  * LCD driver for Sharp Zaurus (based on the Intel Lubbock driver).
     36  *
     37  * Controlling LCD is almost completely done through PXA2X0's
     38  * integrated LCD controller.  Codes for it is arm/xscale/pxa2x0_lcd.c.
     39  *
     40  * Codes in this file provide platform specific things including:
     41  *   LCD on/off switch and backlight brightness
     42  *   LCD panel geometry
     43  */
     44 
     45 #include <sys/cdefs.h>
     46 __KERNEL_RCSID(0, "$NetBSD: zlcd.c,v 1.16 2012/01/25 16:51:17 tsutsui Exp $");
     47 
     48 #include "lcdctl.h"
     49 
     50 #include <sys/param.h>
     51 #include <sys/systm.h>
     52 #include <sys/device.h>
     53 
     54 #include <dev/cons.h>
     55 #include <dev/wscons/wsconsio.h>
     56 #include <dev/wscons/wsdisplayvar.h>
     57 
     58 #include <dev/hpc/hpcfbio.h>
     59 
     60 #include <arm/xscale/pxa2x0var.h>
     61 #include <arm/xscale/pxa2x0_lcd.h>
     62 
     63 #include <zaurus/zaurus/zaurus_var.h>
     64 #include <zaurus/dev/zlcdvar.h>
     65 #if NLCDCTL > 0
     66 #include <zaurus/dev/lcdctlvar.h>
     67 #endif
     68 
     69 /*
     70  * wsdisplay glue
     71  */
     72 static struct pxa2x0_wsscreen_descr lcd_std_screen = {
     73 	.c = {
     74 		.name = "std",
     75 		.textops = &pxa2x0_lcd_emulops,
     76 		.fontwidth = 8,
     77 		.fontheight = 16,
     78 		.capabilities = WSSCREEN_WSCOLORS,
     79 	},
     80 	.depth = 16,			/* bits per pixel */
     81 	.flags = RI_ROTATE_CW,		/* quarter clockwise rotation */
     82 };
     83 
     84 static const struct wsscreen_descr *lcd_scr_descr[] = {
     85 	&lcd_std_screen.c
     86 };
     87 
     88 static const struct wsscreen_list lcd_screen_list = {
     89 	.nscreens = __arraycount(lcd_scr_descr),
     90 	.screens = lcd_scr_descr,
     91 };
     92 
     93 static int	lcd_ioctl(void *, void *, u_long, void *, int, struct lwp *);
     94 static int	lcd_show_screen(void *, void *, int,
     95 		    void (*)(void *, int, int), void *);
     96 
     97 struct wsdisplay_accessops lcd_accessops = {
     98 	lcd_ioctl,
     99 	pxa2x0_lcd_mmap,
    100 	pxa2x0_lcd_alloc_screen,
    101 	pxa2x0_lcd_free_screen,
    102 	lcd_show_screen,
    103 	NULL,
    104 	NULL,
    105 	NULL,
    106 };
    107 
    108 const struct lcd_panel_geometry lcd_panel_geometry_c3000 =
    109 {
    110 	480,			/* Width */
    111 	640,			/* Height */
    112 	0,			/* No extra lines */
    113 
    114 	LCDPANEL_ACTIVE | LCDPANEL_VSP | LCDPANEL_HSP,
    115 	1,			/* clock divider */
    116 	0,			/* AC bias pin freq */
    117 
    118 	0x28,			/* horizontal sync pulse width */
    119 	0x2e,			/* BLW */
    120 	0x7d,			/* ELW */
    121 
    122 	2,			/* vertical sync pulse width */
    123 	1,			/* BFW */
    124 	0,			/* EFW */
    125 };
    126 
    127 static int	lcd_match(device_t, cfdata_t, void *);
    128 static void	lcd_attach(device_t, device_t, void *);
    129 
    130 CFATTACH_DECL_NEW(zlcd, sizeof(struct pxa2x0_lcd_softc),
    131 	lcd_match, lcd_attach, NULL, NULL);
    132 
    133 static bool	lcd_suspend(device_t, const pmf_qual_t *);
    134 static bool	lcd_resume(device_t, const pmf_qual_t *);
    135 
    136 static int
    137 lcd_match(device_t parent, cfdata_t cf, void *aux)
    138 {
    139 
    140 	if (ZAURUS_ISC1000 || ZAURUS_ISC3000)
    141 		return 1;
    142 	return 0;
    143 }
    144 
    145 static void
    146 lcd_attach(device_t parent, device_t self, void *aux)
    147 {
    148 	struct pxa2x0_lcd_softc *sc = device_private(self);
    149 	struct wsemuldisplaydev_attach_args aa;
    150 
    151 	sc->dev = self;
    152 
    153 	pxa2x0_lcd_attach_sub(sc, aux, &lcd_panel_geometry_c3000);
    154 
    155 	aa.console = glass_console;
    156 	aa.scrdata = &lcd_screen_list;
    157 	aa.accessops = &lcd_accessops;
    158 	aa.accesscookie = sc;
    159 
    160 	(void) config_found(self, &aa, wsemuldisplaydevprint);
    161 
    162 	if (!pmf_device_register(self, lcd_suspend, lcd_resume))
    163 		aprint_error_dev(self, "couldn't establish power handler\n");
    164 }
    165 
    166 void
    167 lcd_cnattach(void)
    168 {
    169 
    170 	pxa2x0_lcd_cnattach(&lcd_std_screen, &lcd_panel_geometry_c3000);
    171 }
    172 
    173 /*
    174  * power management
    175  */
    176 static bool
    177 lcd_suspend(device_t dv, const pmf_qual_t *qual)
    178 {
    179 	struct pxa2x0_lcd_softc *sc = device_private(dv);
    180 
    181 #if NLCDCTL > 0
    182 	lcdctl_onoff(false);
    183 #endif
    184 	pxa2x0_lcd_suspend(sc);
    185 
    186 	return true;
    187 }
    188 
    189 static bool
    190 lcd_resume(device_t dv, const pmf_qual_t *qual)
    191 {
    192 	struct pxa2x0_lcd_softc *sc = device_private(dv);
    193 
    194 	pxa2x0_lcd_resume(sc);
    195 #if NLCDCTL > 0
    196 	lcdctl_onoff(true);
    197 #endif
    198 
    199 	return true;
    200 }
    201 
    202 /*
    203  * wsdisplay accessops overrides
    204  */
    205 static int
    206 lcd_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
    207 {
    208 	struct pxa2x0_lcd_softc *sc = (struct pxa2x0_lcd_softc *)v;
    209 	struct hpcfb_fbconf *fbconf;
    210 	struct hpcfb_dspconf *dspconf;
    211 	int res = EINVAL;
    212 
    213 	switch (cmd) {
    214 #if NLCDCTL > 0
    215 	case WSDISPLAYIO_GETPARAM:
    216 	case WSDISPLAYIO_SETPARAM:
    217 		res = lcdctl_param(cmd, (struct wsdisplay_param *)data);
    218 		break;
    219 #endif
    220 
    221 	case HPCFBIO_GCONF:
    222 		fbconf = (struct hpcfb_fbconf *)data;
    223 		if (fbconf->hf_conf_index != 0 &&
    224 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
    225 			break;
    226 		}
    227 
    228 		fbconf->hf_conf_index = 0;
    229 		fbconf->hf_nconfs = 1;
    230 		fbconf->hf_class = HPCFB_CLASS_RGBCOLOR;
    231 		strlcpy(fbconf->hf_name, "Sharp Zaurus frame buffer",
    232 		    sizeof(fbconf->hf_name));
    233 		strlcpy(fbconf->hf_conf_name, "default",
    234 		    sizeof(fbconf->hf_conf_name));
    235 		fbconf->hf_width = sc->geometry->panel_width;
    236 		fbconf->hf_height = sc->geometry->panel_height;
    237 		fbconf->hf_baseaddr = (u_long)sc->active->buf_va;
    238 		fbconf->hf_offset = 0;
    239 		fbconf->hf_bytes_per_line = sc->geometry->panel_width *
    240 		    sc->active->depth / 8;
    241 		fbconf->hf_nplanes = 1;
    242 		fbconf->hf_bytes_per_plane = sc->geometry->panel_width *
    243 		    sc->geometry->panel_height * sc->active->depth / 8;
    244 		fbconf->hf_pack_width = sc->active->depth;
    245 		fbconf->hf_pixels_per_pack = 1;
    246 		fbconf->hf_pixel_width = sc->active->depth;
    247 		fbconf->hf_access_flags = (0
    248 					   | HPCFB_ACCESS_BYTE
    249 					   | HPCFB_ACCESS_WORD
    250 					   | HPCFB_ACCESS_DWORD);
    251 		fbconf->hf_order_flags = 0;
    252 		fbconf->hf_reg_offset = 0;
    253 
    254 		fbconf->hf_class_data_length = sizeof(struct hf_rgb_tag);
    255 		fbconf->hf_u.hf_rgb.hf_flags = 0;
    256 		fbconf->hf_u.hf_rgb.hf_red_width = 5;
    257 		fbconf->hf_u.hf_rgb.hf_red_shift = 11;
    258 		fbconf->hf_u.hf_rgb.hf_green_width = 6;
    259 		fbconf->hf_u.hf_rgb.hf_green_shift = 5;
    260 		fbconf->hf_u.hf_rgb.hf_blue_width = 5;
    261 		fbconf->hf_u.hf_rgb.hf_blue_shift = 0;
    262 		fbconf->hf_u.hf_rgb.hf_alpha_width = 0;
    263 		fbconf->hf_u.hf_rgb.hf_alpha_shift = 0;
    264 
    265 		fbconf->hf_ext_size = 0;
    266 		fbconf->hf_ext_data = NULL;
    267 
    268 		res = 0;
    269 		break;
    270 
    271 	case HPCFBIO_SCONF:
    272 		fbconf = (struct hpcfb_fbconf *)data;
    273 		if (fbconf->hf_conf_index != 0 &&
    274 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
    275 			break;
    276 		}
    277 		/* nothing to do because we have only one configuration */
    278 		res = 0;
    279 		break;
    280 
    281 	case HPCFBIO_GDSPCONF:
    282 		dspconf = (struct hpcfb_dspconf *)data;
    283 		if ((dspconf->hd_unit_index != 0 &&
    284 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
    285 		    (dspconf->hd_conf_index != 0 &&
    286 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
    287 			break;
    288 		}
    289 
    290 		dspconf->hd_unit_index = 0;
    291 		dspconf->hd_nunits = 1;
    292 		dspconf->hd_class = HPCFB_DSP_CLASS_COLORLCD;
    293 		strlcpy(dspconf->hd_name, "Sharp Zaurus LCD",
    294 		    sizeof(dspconf->hd_name));
    295 		dspconf->hd_op_flags = 0;
    296 		dspconf->hd_conf_index = 0;
    297 		dspconf->hd_nconfs = 1;
    298 		strlcpy(dspconf->hd_conf_name, "default",
    299 		    sizeof(dspconf->hd_conf_name));
    300 		dspconf->hd_width = sc->geometry->panel_width;
    301 		dspconf->hd_height = sc->geometry->panel_height;
    302 		dspconf->hd_xdpi = HPCFB_DSP_DPI_UNKNOWN;
    303 		dspconf->hd_ydpi = HPCFB_DSP_DPI_UNKNOWN;
    304 
    305 		res = 0;
    306 		break;
    307 
    308 	case HPCFBIO_SDSPCONF:
    309 		dspconf = (struct hpcfb_dspconf *)data;
    310 		if ((dspconf->hd_unit_index != 0 &&
    311 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
    312 		    (dspconf->hd_conf_index != 0 &&
    313 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
    314 			break;
    315 		}
    316 		/*
    317 		 * nothing to do
    318 		 * because we have only one unit and one configuration
    319 		 */
    320 		res = 0;
    321 		break;
    322 
    323 	case HPCFBIO_GOP:
    324 	case HPCFBIO_SOP:
    325 		/* curently not implemented...  */
    326 		break;
    327 	}
    328 
    329 	if (res == EINVAL)
    330 		res = pxa2x0_lcd_ioctl(v, vs, cmd, data, flag, l);
    331 	return res;
    332 }
    333 
    334 static int
    335 lcd_show_screen(void *v, void *cookie, int waitok,
    336     void (*cb_func)(void *, int, int), void *cb_arg)
    337 {
    338 	int error;
    339 
    340 	error = pxa2x0_lcd_show_screen(v, cookie, waitok, cb_func, cb_arg);
    341 	if (error)
    342 		return (error);
    343 
    344 #if NLCDCTL > 0
    345 	/* Turn on LCD */
    346 	lcdctl_onoff(true);
    347 #endif
    348 
    349 	return 0;
    350 }
    351