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