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