Home | History | Annotate | Line # | Download | only in dev
wzero3_lcd.c revision 1.3
      1 /*	$NetBSD: wzero3_lcd.c,v 1.3 2011/07/19 15:37:39 dyoung Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2008,2009 NONAKA Kimihiro <nonaka (at) netbsd.org>
      5  * 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  *
     16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: wzero3_lcd.c,v 1.3 2011/07/19 15:37:39 dyoung Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/systm.h>
     34 #include <sys/device.h>
     35 #include <sys/pmf.h>
     36 #include <sys/bus.h>
     37 
     38 #include <dev/cons.h>
     39 #include <dev/wscons/wsconsio.h>
     40 #include <dev/wscons/wsdisplayvar.h>
     41 #include <dev/wscons/wscons_callbacks.h>
     42 
     43 #include <dev/hpc/hpcfbio.h>
     44 
     45 #include <arm/xscale/pxa2x0cpu.h>
     46 #include <arm/xscale/pxa2x0var.h>
     47 #include <arm/xscale/pxa2x0_lcd.h>
     48 
     49 #include <machine/bootinfo.h>
     50 #include <machine/platid.h>
     51 #include <machine/platid_mask.h>
     52 
     53 #ifdef DEBUG
     54 #define DPRINTF(arg)	printf arg
     55 #else
     56 #define DPRINTF(arg)	/* nothing */
     57 #endif
     58 
     59 /*
     60  * wsdisplay glue
     61  */
     62 static struct pxa2x0_wsscreen_descr wzero3lcd_std_screen = {
     63 	.c = {
     64 		.name = "std",
     65 		.textops = &pxa2x0_lcd_emulops,
     66 		.fontwidth = 8,
     67 		.fontheight = 16,
     68 		.capabilities = WSSCREEN_WSCOLORS,
     69 	},
     70 	.depth = 16,			/* bits per pixel */
     71 	.flags = 0,
     72 };
     73 
     74 static const struct wsscreen_descr *wzero3lcd_scr_descr[] = {
     75 	&wzero3lcd_std_screen.c
     76 };
     77 
     78 static const struct wsscreen_list wzero3lcd_screen_list = {
     79 	.nscreens = __arraycount(wzero3lcd_scr_descr),
     80 	.screens = wzero3lcd_scr_descr,
     81 };
     82 
     83 static int wzero3lcd_ioctl(void *, void *, u_long, void *, int, struct lwp *);
     84 static int wzero3lcd_param(struct pxa2x0_lcd_softc *, u_long, struct wsdisplay_param *);
     85 static int wzero3lcd_show_screen(void *, void *, int, void (*)(void *, int, int), void *);
     86 
     87 static struct wsdisplay_accessops wzero3lcd_accessops = {
     88 	wzero3lcd_ioctl,
     89 	pxa2x0_lcd_mmap,
     90 	pxa2x0_lcd_alloc_screen,
     91 	pxa2x0_lcd_free_screen,
     92 	wzero3lcd_show_screen,
     93 	NULL,
     94 	NULL,
     95 	NULL,
     96 };
     97 
     98 /* WS003SH or WS004SH */
     99 static const struct lcd_panel_geometry sharp_ws003sh = {
    100 	480,			/* Width */
    101 	640,			/* Height */
    102 	0,			/* No extra lines */
    103 
    104 	LCDPANEL_ACTIVE | LCDPANEL_VSP | LCDPANEL_HSP,
    105 	1,			/* clock divider */
    106 	0,			/* AC bias pin freq */
    107 
    108 	0x14,			/* horizontal sync pulse width */
    109 	0x4e,			/* BLW */
    110 	0x46,			/* ELW */
    111 
    112 	0,			/* vertical sync pulse width */
    113 	2,			/* BFW */
    114 	5,			/* EFW */
    115 
    116 	0,			/* PCDDIV */
    117 };
    118 
    119 /* WS007SH */
    120 static const struct lcd_panel_geometry sharp_ws007sh = {
    121 	480,			/* Width */
    122 	640,			/* Height */
    123 	0,			/* No extra lines */
    124 
    125 	LCDPANEL_ACTIVE | LCDPANEL_VSP | LCDPANEL_HSP | LCDPANEL_PCP | LCDPANEL_OEP,
    126 	3,			/* clock divider */
    127 	0,			/* AC bias pin freq */
    128 
    129 	0x27,			/* horizontal sync pulse width */
    130 	0x68,			/* BLW */
    131 	0x5b,			/* ELW */
    132 
    133 	0,			/* vertical sync pulse width */
    134 	2,			/* BFW */
    135 	5,			/* EFW */
    136 
    137 	1,			/* PCDDIV */
    138 };
    139 
    140 /* WS011SH */
    141 static const struct lcd_panel_geometry sharp_ws011sh = {
    142 	480,			/* Width */
    143 	800,			/* Height */
    144 	0,			/* No extra lines */
    145 
    146 	LCDPANEL_ACTIVE | LCDPANEL_VSP | LCDPANEL_HSP | LCDPANEL_PCP,
    147 	1,			/* clock divider */
    148 	0,			/* AC bias pin freq */
    149 
    150 	0x0a,			/* horizontal sync pulse width */
    151 	0x0c,			/* BLW */
    152 	0x5e,			/* ELW */
    153 
    154 	0,			/* vertical sync pulse width */
    155 	2,			/* BFW */
    156 	1,			/* EFW */
    157 
    158 	0,			/* PCDDIV */
    159 };
    160 
    161 /* WS020SH */
    162 static const struct lcd_panel_geometry sharp_ws020sh = {
    163 	480,			/* Width */
    164 	800,			/* Height */
    165 	0,			/* No extra lines */
    166 
    167 	LCDPANEL_ACTIVE | LCDPANEL_VSP | LCDPANEL_HSP | LCDPANEL_PCP,
    168 	1,			/* clock divider */
    169 	0,			/* AC bias pin freq */
    170 
    171 	0x0a,			/* horizontal sync pulse width */
    172 	0x0c,			/* BLW */
    173 	0x5e,			/* ELW */
    174 
    175 	0,			/* vertical sync pulse width */
    176 	2,			/* BFW */
    177 	1,			/* EFW */
    178 
    179 	0,			/* PCDDIV */
    180 };
    181 
    182 static int	wzero3lcd_match(struct device *, struct cfdata *, void *);
    183 static void	wzero3lcd_attach(struct device *, struct device *, void *);
    184 
    185 CFATTACH_DECL_NEW(wzero3lcd, sizeof(struct pxa2x0_lcd_softc),
    186 	wzero3lcd_match, wzero3lcd_attach, NULL, NULL);
    187 
    188 static const struct lcd_panel_geometry *wzero3lcd_lookup(void);
    189 void wzero3lcd_cnattach(void);
    190 static bool wzero3lcd_suspend(device_t dv, const pmf_qual_t *);
    191 static bool wzero3lcd_resume(device_t dv, const pmf_qual_t *);
    192 
    193 /* default: quarter counter clockwise rotation */
    194 int screen_rotate = 270;
    195 
    196 static const struct lcd_panel_geometry *
    197 wzero3lcd_lookup(void)
    198 {
    199 
    200 	if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS003SH)
    201 	 || platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS004SH))
    202 		return &sharp_ws003sh;
    203 	if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS007SH))
    204 		return &sharp_ws007sh;
    205 	if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS011SH))
    206 		return &sharp_ws011sh;
    207 	if (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS020SH))
    208 		return &sharp_ws020sh;
    209 	return NULL;
    210 }
    211 
    212 static int
    213 wzero3lcd_match(struct device *parent, struct cfdata *cf, void *aux)
    214 {
    215 
    216 	if (strcmp(cf->cf_name, "lcd") != 0)
    217 		return 0;
    218 	if (wzero3lcd_lookup() == NULL)
    219 		return 0;
    220 	return 1;
    221 }
    222 
    223 static void
    224 wzero3lcd_attach(struct device *parent, struct device *self, void *aux)
    225 {
    226 	struct pxa2x0_lcd_softc *sc = device_private(self);
    227 	struct wsemuldisplaydev_attach_args aa;
    228 	const struct lcd_panel_geometry *panel;
    229 
    230 	sc->dev = self;
    231 
    232 	panel = wzero3lcd_lookup();
    233 	if (panel == NULL) {
    234 		aprint_error(": unknown model\n");
    235 		return;
    236 	}
    237 
    238 	if ((platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS007SH))
    239 	 || (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS011SH))
    240 	 || (platid_match(&platid, &platid_mask_MACH_SHARP_WZERO3_WS020SH)))
    241 		sc->flags |= FLAG_NOUSE_ACBIAS;
    242 
    243 	wzero3lcd_std_screen.flags &= ~(RI_ROTATE_MASK);
    244 	switch (screen_rotate) {
    245 	default:
    246 		break;
    247 
    248 	case 270:	/* quarter counter clockwise rotation */
    249 		wzero3lcd_std_screen.flags |= RI_ROTATE_CCW;
    250 		break;
    251 	}
    252 	pxa2x0_lcd_attach_sub(sc, aux, panel);
    253 
    254 	aa.console = (bootinfo->bi_cnuse != BI_CNUSE_SERIAL);
    255 	aa.scrdata = &wzero3lcd_screen_list;
    256 	aa.accessops = &wzero3lcd_accessops;
    257 	aa.accesscookie = sc;
    258 
    259 	(void) config_found(self, &aa, wsemuldisplaydevprint);
    260 
    261 	if (!pmf_device_register(sc->dev, wzero3lcd_suspend, wzero3lcd_resume))
    262 		aprint_error_dev(sc->dev, "couldn't establish power handler\n");
    263 }
    264 
    265 void
    266 wzero3lcd_cnattach(void)
    267 {
    268 	const struct lcd_panel_geometry *panel;
    269 
    270 	panel = wzero3lcd_lookup();
    271 	if (panel == NULL)
    272 		return;
    273 
    274 	pxa2x0_lcd_cnattach(&wzero3lcd_std_screen, panel);
    275 }
    276 
    277 /*
    278  * Power management
    279  */
    280 static bool
    281 wzero3lcd_suspend(device_t dv, const pmf_qual_t *qual)
    282 {
    283 	struct pxa2x0_lcd_softc *sc = device_private(dv);
    284 
    285 	pxa2x0_lcd_suspend(sc);
    286 
    287 	return true;
    288 }
    289 
    290 static bool
    291 wzero3lcd_resume(device_t dv, const pmf_qual_t *qual)
    292 {
    293 	struct pxa2x0_lcd_softc *sc = device_private(dv);
    294 
    295 	pxa2x0_lcd_resume(sc);
    296 
    297 	return true;
    298 }
    299 
    300 /*
    301  * wsdisplay accessops overrides
    302  */
    303 static int
    304 wzero3lcd_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
    305 {
    306 	struct pxa2x0_lcd_softc *sc = (struct pxa2x0_lcd_softc *)v;
    307 	struct hpcfb_fbconf *fbconf;
    308 	struct hpcfb_dspconf *dspconf;
    309 	int res = EINVAL;
    310 
    311 	switch (cmd) {
    312 	case WSDISPLAYIO_GETPARAM:
    313 	case WSDISPLAYIO_SETPARAM:
    314 		res = wzero3lcd_param(sc, cmd, (struct wsdisplay_param *)data);
    315 		break;
    316 
    317 	case HPCFBIO_GCONF:
    318 		fbconf = (struct hpcfb_fbconf *)data;
    319 		if (fbconf->hf_conf_index != 0 &&
    320 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
    321 			break;
    322 		}
    323 
    324 		fbconf->hf_conf_index = 0;
    325 		fbconf->hf_nconfs = 1;
    326 		fbconf->hf_class = HPCFB_CLASS_RGBCOLOR;
    327 		strlcpy(fbconf->hf_name, "Sharp W-ZERO3 frame buffer",
    328 		    sizeof(fbconf->hf_name));
    329 		strlcpy(fbconf->hf_conf_name, "LCD",
    330 		    sizeof(fbconf->hf_conf_name));
    331 		fbconf->hf_baseaddr = (u_long)sc->active->buf_va;
    332 		fbconf->hf_width = sc->geometry->panel_width;
    333 		fbconf->hf_height = sc->geometry->panel_height;
    334 		fbconf->hf_offset = 0;
    335 		fbconf->hf_bytes_per_line = fbconf->hf_width *
    336 		    sc->active->depth / 8;
    337 		fbconf->hf_nplanes = 1;
    338 		fbconf->hf_bytes_per_plane = fbconf->hf_width *
    339 		    fbconf->hf_height * sc->active->depth / 8;
    340 		fbconf->hf_pack_width = sc->active->depth;
    341 		fbconf->hf_pixels_per_pack = 1;
    342 		fbconf->hf_pixel_width = sc->active->depth;
    343 		fbconf->hf_access_flags = (HPCFB_ACCESS_STATIC
    344 					   | HPCFB_ACCESS_BYTE
    345 					   | HPCFB_ACCESS_WORD
    346 					   | HPCFB_ACCESS_DWORD);
    347 		fbconf->hf_order_flags = 0;
    348 		fbconf->hf_reg_offset = 0;
    349 
    350 		fbconf->hf_class_data_length = sizeof(struct hf_rgb_tag);
    351 		fbconf->hf_u.hf_rgb.hf_flags = 0;
    352 		fbconf->hf_u.hf_rgb.hf_red_width = 5;
    353 		fbconf->hf_u.hf_rgb.hf_red_shift = 11;
    354 		fbconf->hf_u.hf_rgb.hf_green_width = 6;
    355 		fbconf->hf_u.hf_rgb.hf_green_shift = 5;
    356 		fbconf->hf_u.hf_rgb.hf_blue_width = 5;
    357 		fbconf->hf_u.hf_rgb.hf_blue_shift = 0;
    358 		fbconf->hf_u.hf_rgb.hf_alpha_width = 0;
    359 		fbconf->hf_u.hf_rgb.hf_alpha_shift = 0;
    360 
    361 		fbconf->hf_ext_size = 0;
    362 		fbconf->hf_ext_data = NULL;
    363 
    364 		res = 0;
    365 		break;
    366 
    367 	case HPCFBIO_SCONF:
    368 		fbconf = (struct hpcfb_fbconf *)data;
    369 		if (fbconf->hf_conf_index != 0 &&
    370 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
    371 			break;
    372 		}
    373 		/* nothing to do because we have only one configuration */
    374 		res = 0;
    375 		break;
    376 
    377 	case HPCFBIO_GDSPCONF:
    378 		dspconf = (struct hpcfb_dspconf *)data;
    379 		if ((dspconf->hd_unit_index != 0 &&
    380 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
    381 		    (dspconf->hd_conf_index != 0 &&
    382 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
    383 			break;
    384 		}
    385 
    386 		dspconf->hd_unit_index = 0;
    387 		dspconf->hd_nunits = 1;
    388 		dspconf->hd_class = HPCFB_DSP_CLASS_COLORLCD;
    389 		strlcpy(dspconf->hd_name, "PXA2x0 Internal LCD controller",
    390 		    sizeof(dspconf->hd_name));
    391 		dspconf->hd_op_flags = 0;
    392 		dspconf->hd_conf_index = 0;
    393 		dspconf->hd_nconfs = 1;
    394 		strlcpy(dspconf->hd_conf_name, "LCD",
    395 		    sizeof(dspconf->hd_conf_name));
    396 		dspconf->hd_width = sc->geometry->panel_width;
    397 		dspconf->hd_height = sc->geometry->panel_height;
    398 		dspconf->hd_xdpi = HPCFB_DSP_DPI_UNKNOWN;
    399 		dspconf->hd_ydpi = HPCFB_DSP_DPI_UNKNOWN;
    400 
    401 		res = 0;
    402 		break;
    403 
    404 	case HPCFBIO_SDSPCONF:
    405 		dspconf = (struct hpcfb_dspconf *)data;
    406 		if ((dspconf->hd_unit_index != 0 &&
    407 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
    408 		    (dspconf->hd_conf_index != 0 &&
    409 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
    410 			break;
    411 		}
    412 		/*
    413 		 * nothing to do
    414 		 * because we have only one unit and one configuration
    415 		 */
    416 		res = 0;
    417 		break;
    418 
    419 	case HPCFBIO_GOP:
    420 	case HPCFBIO_SOP:
    421 		/* curently not implemented...  */
    422 		break;
    423 	}
    424 
    425 	if (res == EINVAL)
    426 		res = pxa2x0_lcd_ioctl(v, vs, cmd, data, flag, l);
    427 	return res;
    428 }
    429 
    430 static int
    431 wzero3lcd_show_screen(void *v, void *cookie, int waitok, void (*cb_func)(void *, int, int), void *cb_arg)
    432 {
    433 	int error;
    434 
    435 	error = pxa2x0_lcd_show_screen(v, cookie, waitok, cb_func, cb_arg);
    436 	if (error)
    437 		return (error);
    438 
    439 	return 0;
    440 }
    441 
    442 /*
    443  * wsdisplay I/O controls
    444  */
    445 static int
    446 wzero3lcd_param(struct pxa2x0_lcd_softc *sc, u_long cmd, struct wsdisplay_param *dp)
    447 {
    448 	int res = EINVAL;
    449 
    450 	switch (dp->param) {
    451 	case WSDISPLAYIO_PARAM_BACKLIGHT:
    452 		/* unsupported */
    453 		DPRINTF(("%s: ioctl(WSDISPLAYIO_PARAM_BACKLIGHT) isn't supported\n", device_xname(sc->dev)));
    454 		res = ENOTTY;
    455 		break;
    456 
    457 	case WSDISPLAYIO_PARAM_CONTRAST:
    458 		DPRINTF(("%s: ioctl(WSDISPLAYIO_PARAM_CONTRAST) isn't supported\n", device_xname(sc->dev)));
    459 		/* unsupported */
    460 		res = ENOTTY;
    461 		break;
    462 
    463 	case WSDISPLAYIO_PARAM_BRIGHTNESS:
    464 		DPRINTF(("%s: ioctl(WSDISPLAYIO_PARAM_BRIGHTNESS) isn't supported\n", device_xname(sc->dev)));
    465 		/* unsupported */
    466 		res = ENOTTY;
    467 	}
    468 
    469 	return res;
    470 }
    471