xref: /netbsd/sys/dev/fdt/fdt_panel.c (revision 67b4eb14)
1*67b4eb14Sriastradh /* $NetBSD: fdt_panel.c,v 1.6 2021/12/19 11:01:10 riastradh Exp $ */
234cf509cSjakllsch 
334cf509cSjakllsch /*-
434cf509cSjakllsch  * Copyright (c) 2019 Jonathan A. Kollasch <jakllsch@kollasch.net>
534cf509cSjakllsch  * All rights reserved.
634cf509cSjakllsch  *
734cf509cSjakllsch  * Redistribution and use in source and binary forms, with or without
834cf509cSjakllsch  * modification, are permitted provided that the following conditions
934cf509cSjakllsch  * are met:
1034cf509cSjakllsch  * 1. Redistributions of source code must retain the above copyright
1134cf509cSjakllsch  *    notice, this list of conditions and the following disclaimer.
1234cf509cSjakllsch  * 2. Redistributions in binary form must reproduce the above copyright
1334cf509cSjakllsch  *    notice, this list of conditions and the following disclaimer in the
1434cf509cSjakllsch  *    documentation and/or other materials provided with the distribution.
1534cf509cSjakllsch  *
1634cf509cSjakllsch  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1734cf509cSjakllsch  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1834cf509cSjakllsch  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1934cf509cSjakllsch  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2034cf509cSjakllsch  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2134cf509cSjakllsch  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2234cf509cSjakllsch  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2334cf509cSjakllsch  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2434cf509cSjakllsch  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2534cf509cSjakllsch  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2634cf509cSjakllsch  * SUCH DAMAGE.
2734cf509cSjakllsch  */
2834cf509cSjakllsch 
2934cf509cSjakllsch #include <sys/cdefs.h>
30*67b4eb14Sriastradh __KERNEL_RCSID(0, "$NetBSD: fdt_panel.c,v 1.6 2021/12/19 11:01:10 riastradh Exp $");
3134cf509cSjakllsch 
3234cf509cSjakllsch #include <sys/param.h>
3334cf509cSjakllsch #include <sys/bus.h>
3434cf509cSjakllsch #include <sys/device.h>
3534cf509cSjakllsch #include <sys/gpio.h>
36*67b4eb14Sriastradh #include <sys/systm.h>
3734cf509cSjakllsch 
3834cf509cSjakllsch #include <dev/fdt/fdt_port.h>
39*67b4eb14Sriastradh #include <dev/fdt/fdtvar.h>
4034cf509cSjakllsch 
4134cf509cSjakllsch #include <dev/i2c/ddcvar.h>
4234cf509cSjakllsch 
43c7fa00edSriastradh #include <drm/drm_drv.h>
4434cf509cSjakllsch #include <drm/drm_edid.h>
45*67b4eb14Sriastradh #include <drm/drm_panel.h>
4634cf509cSjakllsch 
478e90f9edSthorpej static const struct device_compatible_entry compat_data[] = {
488e90f9edSthorpej 	{ .compat = "simple-panel" },
49f0643dbdSjmcneill 	{ .compat = "boe,nv140fhmn49" },
508e90f9edSthorpej 	DEVICE_COMPAT_EOL
5134cf509cSjakllsch };
5234cf509cSjakllsch 
5334cf509cSjakllsch struct panel_fdt_softc {
5434cf509cSjakllsch 	device_t			sc_dev;
5534cf509cSjakllsch 	struct fdt_device_ports		sc_ports;
5634cf509cSjakllsch 	struct drm_panel		sc_panel;
5734cf509cSjakllsch 	struct fdtbus_gpio_pin *	sc_enable;
5834cf509cSjakllsch 	struct fdtbus_regulator *	sc_regulator;
5934cf509cSjakllsch };
6034cf509cSjakllsch 
6134cf509cSjakllsch #define	to_panel_fdt(x)	container_of(x, struct panel_fdt_softc, sc_panel)
6234cf509cSjakllsch 
6334cf509cSjakllsch static int
panel_fdt_enable(struct drm_panel * panel)6434cf509cSjakllsch panel_fdt_enable(struct drm_panel * panel)
6534cf509cSjakllsch {
6634cf509cSjakllsch 	struct panel_fdt_softc * const sc = to_panel_fdt(panel);
6734cf509cSjakllsch 
6834cf509cSjakllsch         if (sc->sc_enable) {
6934cf509cSjakllsch 		fdtbus_gpio_write(sc->sc_enable, true);
7034cf509cSjakllsch         }
7134cf509cSjakllsch 
7234cf509cSjakllsch 	if (!cold)
7334cf509cSjakllsch 		kpause("panele", false, mstohz(200), NULL);
7434cf509cSjakllsch 
7534cf509cSjakllsch 	return 0;
7634cf509cSjakllsch }
7734cf509cSjakllsch 
7834cf509cSjakllsch static int
panel_fdt_prepare(struct drm_panel * panel)7934cf509cSjakllsch panel_fdt_prepare(struct drm_panel * panel)
8034cf509cSjakllsch {
8134cf509cSjakllsch 	struct panel_fdt_softc * const sc = to_panel_fdt(panel);
8234cf509cSjakllsch 
8334cf509cSjakllsch         if (sc->sc_regulator) {
8434cf509cSjakllsch                 fdtbus_regulator_enable(sc->sc_regulator);
8534cf509cSjakllsch         }
8634cf509cSjakllsch 
8734cf509cSjakllsch 	if (cold)
8834cf509cSjakllsch 		delay(210000);
8934cf509cSjakllsch 	else
9034cf509cSjakllsch 		kpause("panelp", false, mstohz(210), NULL);
9134cf509cSjakllsch 
9234cf509cSjakllsch 	return 0;
9334cf509cSjakllsch }
9434cf509cSjakllsch 
9534cf509cSjakllsch static const struct drm_panel_funcs panel_fdt_funcs = {
9634cf509cSjakllsch 	.disable = NULL,
9734cf509cSjakllsch 	.enable = panel_fdt_enable,
9834cf509cSjakllsch 	.get_modes = NULL,
9934cf509cSjakllsch 	.get_timings = NULL,
10034cf509cSjakllsch 	.prepare = panel_fdt_prepare,
10134cf509cSjakllsch 	.unprepare = NULL,
10234cf509cSjakllsch };
10334cf509cSjakllsch 
10434cf509cSjakllsch static int
panel_fdt_ep_activate(device_t dev,struct fdt_endpoint * ep,bool activate)10534cf509cSjakllsch panel_fdt_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate)
10634cf509cSjakllsch {
10734cf509cSjakllsch 	struct fdt_endpoint *rep = fdt_endpoint_remote(ep);
10834cf509cSjakllsch 
10934cf509cSjakllsch 	if (fdt_endpoint_port_index(ep) != 0)
11034cf509cSjakllsch 		return EINVAL;
11134cf509cSjakllsch 
11234cf509cSjakllsch 	if (fdt_endpoint_type(rep) != EP_DRM_ENCODER)
11334cf509cSjakllsch 		return EINVAL;
11434cf509cSjakllsch 
11534cf509cSjakllsch 	return 0;
11634cf509cSjakllsch }
11734cf509cSjakllsch 
11834cf509cSjakllsch static void *
panel_fdt_ep_get_data(device_t dev,struct fdt_endpoint * ep)11934cf509cSjakllsch panel_fdt_ep_get_data(device_t dev, struct fdt_endpoint *ep)
12034cf509cSjakllsch {
12134cf509cSjakllsch 	struct panel_fdt_softc * const sc = device_private(dev);
12234cf509cSjakllsch 
12334cf509cSjakllsch 	return &sc->sc_panel;
12434cf509cSjakllsch }
12534cf509cSjakllsch 
12634cf509cSjakllsch static int
panel_fdt_match(device_t parent,cfdata_t cf,void * aux)12734cf509cSjakllsch panel_fdt_match(device_t parent, cfdata_t cf, void *aux)
12834cf509cSjakllsch {
12934cf509cSjakllsch 	struct fdt_attach_args * const faa = aux;
13034cf509cSjakllsch 
1318e90f9edSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
13234cf509cSjakllsch }
13334cf509cSjakllsch 
13434cf509cSjakllsch static void
panel_fdt_attach(device_t parent,device_t self,void * aux)13534cf509cSjakllsch panel_fdt_attach(device_t parent, device_t self, void *aux)
13634cf509cSjakllsch {
13734cf509cSjakllsch 	struct panel_fdt_softc * const sc = device_private(self);
13834cf509cSjakllsch 	struct fdt_attach_args * const faa = aux;
13934cf509cSjakllsch 	const int phandle = faa->faa_phandle;
14034cf509cSjakllsch 
14134cf509cSjakllsch 	aprint_naive("\n");
14234cf509cSjakllsch 	aprint_normal(": panel\n");
14334cf509cSjakllsch 
14434cf509cSjakllsch 	sc->sc_dev = self;
14534cf509cSjakllsch 
14634cf509cSjakllsch 	/* required for "simple-panel" */
14734cf509cSjakllsch         sc->sc_regulator = fdtbus_regulator_acquire(phandle, "power-supply");
1489b97e576Sjakllsch         if (sc->sc_regulator == NULL) {
1499b97e576Sjakllsch 		aprint_error_dev(self, "regulator not found\n");
1509b97e576Sjakllsch 		return;
1519b97e576Sjakllsch 	}
15234cf509cSjakllsch 
15334cf509cSjakllsch 	/* optional for "simple-panel" */
15434cf509cSjakllsch 	sc->sc_enable = fdtbus_gpio_acquire_index(phandle,
15534cf509cSjakllsch 	    "enable-gpios", 0, GPIO_PIN_OUTPUT);
15634cf509cSjakllsch 
15734cf509cSjakllsch 	sc->sc_ports.dp_ep_activate = panel_fdt_ep_activate;
15834cf509cSjakllsch 	sc->sc_ports.dp_ep_get_data = panel_fdt_ep_get_data;
15934cf509cSjakllsch 	fdt_ports_register(&sc->sc_ports, self, phandle, EP_DRM_PANEL);
16034cf509cSjakllsch 
161c7fa00edSriastradh 	drm_panel_init(&sc->sc_panel, self, &panel_fdt_funcs, DRM_MODE_CONNECTOR_DPI);
16234cf509cSjakllsch 	sc->sc_panel.funcs = &panel_fdt_funcs;
16334cf509cSjakllsch 
16434cf509cSjakllsch 	drm_panel_add(&sc->sc_panel);
16534cf509cSjakllsch }
16634cf509cSjakllsch 
16734cf509cSjakllsch CFATTACH_DECL_NEW(panel_fdt, sizeof(struct panel_fdt_softc),
16834cf509cSjakllsch 	panel_fdt_match, panel_fdt_attach, NULL, NULL);
169