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