xref: /netbsd-src/sys/dev/fdt/fdt_panel.c (revision dd47db3e83a68b8e7f55e1a33bd6e94970c2de7e)
1*dd47db3eSriastradh /* $NetBSD: fdt_panel.c,v 1.6 2021/12/19 11:01:10 riastradh Exp $ */
218f2cadaSjakllsch 
318f2cadaSjakllsch /*-
418f2cadaSjakllsch  * Copyright (c) 2019 Jonathan A. Kollasch <jakllsch@kollasch.net>
518f2cadaSjakllsch  * All rights reserved.
618f2cadaSjakllsch  *
718f2cadaSjakllsch  * Redistribution and use in source and binary forms, with or without
818f2cadaSjakllsch  * modification, are permitted provided that the following conditions
918f2cadaSjakllsch  * are met:
1018f2cadaSjakllsch  * 1. Redistributions of source code must retain the above copyright
1118f2cadaSjakllsch  *    notice, this list of conditions and the following disclaimer.
1218f2cadaSjakllsch  * 2. Redistributions in binary form must reproduce the above copyright
1318f2cadaSjakllsch  *    notice, this list of conditions and the following disclaimer in the
1418f2cadaSjakllsch  *    documentation and/or other materials provided with the distribution.
1518f2cadaSjakllsch  *
1618f2cadaSjakllsch  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1718f2cadaSjakllsch  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1818f2cadaSjakllsch  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1918f2cadaSjakllsch  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2018f2cadaSjakllsch  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2118f2cadaSjakllsch  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2218f2cadaSjakllsch  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2318f2cadaSjakllsch  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2418f2cadaSjakllsch  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2518f2cadaSjakllsch  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2618f2cadaSjakllsch  * SUCH DAMAGE.
2718f2cadaSjakllsch  */
2818f2cadaSjakllsch 
2918f2cadaSjakllsch #include <sys/cdefs.h>
30*dd47db3eSriastradh __KERNEL_RCSID(0, "$NetBSD: fdt_panel.c,v 1.6 2021/12/19 11:01:10 riastradh Exp $");
3118f2cadaSjakllsch 
3218f2cadaSjakllsch #include <sys/param.h>
3318f2cadaSjakllsch #include <sys/bus.h>
3418f2cadaSjakllsch #include <sys/device.h>
3518f2cadaSjakllsch #include <sys/gpio.h>
36*dd47db3eSriastradh #include <sys/systm.h>
3718f2cadaSjakllsch 
3818f2cadaSjakllsch #include <dev/fdt/fdt_port.h>
39*dd47db3eSriastradh #include <dev/fdt/fdtvar.h>
4018f2cadaSjakllsch 
4118f2cadaSjakllsch #include <dev/i2c/ddcvar.h>
4218f2cadaSjakllsch 
433973e774Sriastradh #include <drm/drm_drv.h>
4418f2cadaSjakllsch #include <drm/drm_edid.h>
45*dd47db3eSriastradh #include <drm/drm_panel.h>
4618f2cadaSjakllsch 
476e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
486e54367aSthorpej 	{ .compat = "simple-panel" },
49c34066c2Sjmcneill 	{ .compat = "boe,nv140fhmn49" },
506e54367aSthorpej 	DEVICE_COMPAT_EOL
5118f2cadaSjakllsch };
5218f2cadaSjakllsch 
5318f2cadaSjakllsch struct panel_fdt_softc {
5418f2cadaSjakllsch 	device_t			sc_dev;
5518f2cadaSjakllsch 	struct fdt_device_ports		sc_ports;
5618f2cadaSjakllsch 	struct drm_panel		sc_panel;
5718f2cadaSjakllsch 	struct fdtbus_gpio_pin *	sc_enable;
5818f2cadaSjakllsch 	struct fdtbus_regulator *	sc_regulator;
5918f2cadaSjakllsch };
6018f2cadaSjakllsch 
6118f2cadaSjakllsch #define	to_panel_fdt(x)	container_of(x, struct panel_fdt_softc, sc_panel)
6218f2cadaSjakllsch 
6318f2cadaSjakllsch static int
panel_fdt_enable(struct drm_panel * panel)6418f2cadaSjakllsch panel_fdt_enable(struct drm_panel * panel)
6518f2cadaSjakllsch {
6618f2cadaSjakllsch 	struct panel_fdt_softc * const sc = to_panel_fdt(panel);
6718f2cadaSjakllsch 
6818f2cadaSjakllsch         if (sc->sc_enable) {
6918f2cadaSjakllsch 		fdtbus_gpio_write(sc->sc_enable, true);
7018f2cadaSjakllsch         }
7118f2cadaSjakllsch 
7218f2cadaSjakllsch 	if (!cold)
7318f2cadaSjakllsch 		kpause("panele", false, mstohz(200), NULL);
7418f2cadaSjakllsch 
7518f2cadaSjakllsch 	return 0;
7618f2cadaSjakllsch }
7718f2cadaSjakllsch 
7818f2cadaSjakllsch static int
panel_fdt_prepare(struct drm_panel * panel)7918f2cadaSjakllsch panel_fdt_prepare(struct drm_panel * panel)
8018f2cadaSjakllsch {
8118f2cadaSjakllsch 	struct panel_fdt_softc * const sc = to_panel_fdt(panel);
8218f2cadaSjakllsch 
8318f2cadaSjakllsch         if (sc->sc_regulator) {
8418f2cadaSjakllsch                 fdtbus_regulator_enable(sc->sc_regulator);
8518f2cadaSjakllsch         }
8618f2cadaSjakllsch 
8718f2cadaSjakllsch 	if (cold)
8818f2cadaSjakllsch 		delay(210000);
8918f2cadaSjakllsch 	else
9018f2cadaSjakllsch 		kpause("panelp", false, mstohz(210), NULL);
9118f2cadaSjakllsch 
9218f2cadaSjakllsch 	return 0;
9318f2cadaSjakllsch }
9418f2cadaSjakllsch 
9518f2cadaSjakllsch static const struct drm_panel_funcs panel_fdt_funcs = {
9618f2cadaSjakllsch 	.disable = NULL,
9718f2cadaSjakllsch 	.enable = panel_fdt_enable,
9818f2cadaSjakllsch 	.get_modes = NULL,
9918f2cadaSjakllsch 	.get_timings = NULL,
10018f2cadaSjakllsch 	.prepare = panel_fdt_prepare,
10118f2cadaSjakllsch 	.unprepare = NULL,
10218f2cadaSjakllsch };
10318f2cadaSjakllsch 
10418f2cadaSjakllsch static int
panel_fdt_ep_activate(device_t dev,struct fdt_endpoint * ep,bool activate)10518f2cadaSjakllsch panel_fdt_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate)
10618f2cadaSjakllsch {
10718f2cadaSjakllsch 	struct fdt_endpoint *rep = fdt_endpoint_remote(ep);
10818f2cadaSjakllsch 
10918f2cadaSjakllsch 	if (fdt_endpoint_port_index(ep) != 0)
11018f2cadaSjakllsch 		return EINVAL;
11118f2cadaSjakllsch 
11218f2cadaSjakllsch 	if (fdt_endpoint_type(rep) != EP_DRM_ENCODER)
11318f2cadaSjakllsch 		return EINVAL;
11418f2cadaSjakllsch 
11518f2cadaSjakllsch 	return 0;
11618f2cadaSjakllsch }
11718f2cadaSjakllsch 
11818f2cadaSjakllsch static void *
panel_fdt_ep_get_data(device_t dev,struct fdt_endpoint * ep)11918f2cadaSjakllsch panel_fdt_ep_get_data(device_t dev, struct fdt_endpoint *ep)
12018f2cadaSjakllsch {
12118f2cadaSjakllsch 	struct panel_fdt_softc * const sc = device_private(dev);
12218f2cadaSjakllsch 
12318f2cadaSjakllsch 	return &sc->sc_panel;
12418f2cadaSjakllsch }
12518f2cadaSjakllsch 
12618f2cadaSjakllsch static int
panel_fdt_match(device_t parent,cfdata_t cf,void * aux)12718f2cadaSjakllsch panel_fdt_match(device_t parent, cfdata_t cf, void *aux)
12818f2cadaSjakllsch {
12918f2cadaSjakllsch 	struct fdt_attach_args * const faa = aux;
13018f2cadaSjakllsch 
1316e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
13218f2cadaSjakllsch }
13318f2cadaSjakllsch 
13418f2cadaSjakllsch static void
panel_fdt_attach(device_t parent,device_t self,void * aux)13518f2cadaSjakllsch panel_fdt_attach(device_t parent, device_t self, void *aux)
13618f2cadaSjakllsch {
13718f2cadaSjakllsch 	struct panel_fdt_softc * const sc = device_private(self);
13818f2cadaSjakllsch 	struct fdt_attach_args * const faa = aux;
13918f2cadaSjakllsch 	const int phandle = faa->faa_phandle;
14018f2cadaSjakllsch 
14118f2cadaSjakllsch 	aprint_naive("\n");
14218f2cadaSjakllsch 	aprint_normal(": panel\n");
14318f2cadaSjakllsch 
14418f2cadaSjakllsch 	sc->sc_dev = self;
14518f2cadaSjakllsch 
14618f2cadaSjakllsch 	/* required for "simple-panel" */
14718f2cadaSjakllsch         sc->sc_regulator = fdtbus_regulator_acquire(phandle, "power-supply");
148b8c4c0c3Sjakllsch         if (sc->sc_regulator == NULL) {
149b8c4c0c3Sjakllsch 		aprint_error_dev(self, "regulator not found\n");
150b8c4c0c3Sjakllsch 		return;
151b8c4c0c3Sjakllsch 	}
15218f2cadaSjakllsch 
15318f2cadaSjakllsch 	/* optional for "simple-panel" */
15418f2cadaSjakllsch 	sc->sc_enable = fdtbus_gpio_acquire_index(phandle,
15518f2cadaSjakllsch 	    "enable-gpios", 0, GPIO_PIN_OUTPUT);
15618f2cadaSjakllsch 
15718f2cadaSjakllsch 	sc->sc_ports.dp_ep_activate = panel_fdt_ep_activate;
15818f2cadaSjakllsch 	sc->sc_ports.dp_ep_get_data = panel_fdt_ep_get_data;
15918f2cadaSjakllsch 	fdt_ports_register(&sc->sc_ports, self, phandle, EP_DRM_PANEL);
16018f2cadaSjakllsch 
1613973e774Sriastradh 	drm_panel_init(&sc->sc_panel, self, &panel_fdt_funcs, DRM_MODE_CONNECTOR_DPI);
16218f2cadaSjakllsch 	sc->sc_panel.funcs = &panel_fdt_funcs;
16318f2cadaSjakllsch 
16418f2cadaSjakllsch 	drm_panel_add(&sc->sc_panel);
16518f2cadaSjakllsch }
16618f2cadaSjakllsch 
16718f2cadaSjakllsch CFATTACH_DECL_NEW(panel_fdt, sizeof(struct panel_fdt_softc),
16818f2cadaSjakllsch 	panel_fdt_match, panel_fdt_attach, NULL, NULL);
169