11.6Sriastrad/* $NetBSD: fdt_panel.c,v 1.6 2021/12/19 11:01:10 riastradh Exp $ */ 21.1Sjakllsch 31.1Sjakllsch/*- 41.1Sjakllsch * Copyright (c) 2019 Jonathan A. Kollasch <jakllsch@kollasch.net> 51.1Sjakllsch * All rights reserved. 61.1Sjakllsch * 71.1Sjakllsch * Redistribution and use in source and binary forms, with or without 81.1Sjakllsch * modification, are permitted provided that the following conditions 91.1Sjakllsch * are met: 101.1Sjakllsch * 1. Redistributions of source code must retain the above copyright 111.1Sjakllsch * notice, this list of conditions and the following disclaimer. 121.1Sjakllsch * 2. Redistributions in binary form must reproduce the above copyright 131.1Sjakllsch * notice, this list of conditions and the following disclaimer in the 141.1Sjakllsch * documentation and/or other materials provided with the distribution. 151.1Sjakllsch * 161.1Sjakllsch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 171.1Sjakllsch * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181.1Sjakllsch * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191.1Sjakllsch * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 201.1Sjakllsch * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211.1Sjakllsch * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 221.1Sjakllsch * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231.1Sjakllsch * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241.1Sjakllsch * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251.1Sjakllsch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261.1Sjakllsch * SUCH DAMAGE. 271.1Sjakllsch */ 281.1Sjakllsch 291.1Sjakllsch#include <sys/cdefs.h> 301.6Sriastrad__KERNEL_RCSID(0, "$NetBSD: fdt_panel.c,v 1.6 2021/12/19 11:01:10 riastradh Exp $"); 311.1Sjakllsch 321.1Sjakllsch#include <sys/param.h> 331.1Sjakllsch#include <sys/bus.h> 341.1Sjakllsch#include <sys/device.h> 351.6Sriastrad#include <sys/gpio.h> 361.1Sjakllsch#include <sys/systm.h> 371.1Sjakllsch 381.6Sriastrad#include <dev/fdt/fdt_port.h> 391.1Sjakllsch#include <dev/fdt/fdtvar.h> 401.1Sjakllsch 411.1Sjakllsch#include <dev/i2c/ddcvar.h> 421.1Sjakllsch 431.5Sriastrad#include <drm/drm_drv.h> 441.6Sriastrad#include <drm/drm_edid.h> 451.1Sjakllsch#include <drm/drm_panel.h> 461.1Sjakllsch 471.3Sthorpejstatic const struct device_compatible_entry compat_data[] = { 481.3Sthorpej { .compat = "simple-panel" }, 491.4Sjmcneill { .compat = "boe,nv140fhmn49" }, 501.3Sthorpej DEVICE_COMPAT_EOL 511.1Sjakllsch}; 521.1Sjakllsch 531.1Sjakllschstruct panel_fdt_softc { 541.1Sjakllsch device_t sc_dev; 551.1Sjakllsch struct fdt_device_ports sc_ports; 561.1Sjakllsch struct drm_panel sc_panel; 571.1Sjakllsch struct fdtbus_gpio_pin * sc_enable; 581.1Sjakllsch struct fdtbus_regulator * sc_regulator; 591.1Sjakllsch}; 601.1Sjakllsch 611.1Sjakllsch#define to_panel_fdt(x) container_of(x, struct panel_fdt_softc, sc_panel) 621.1Sjakllsch 631.1Sjakllschstatic int 641.1Sjakllschpanel_fdt_enable(struct drm_panel * panel) 651.1Sjakllsch{ 661.1Sjakllsch struct panel_fdt_softc * const sc = to_panel_fdt(panel); 671.1Sjakllsch 681.1Sjakllsch if (sc->sc_enable) { 691.1Sjakllsch fdtbus_gpio_write(sc->sc_enable, true); 701.1Sjakllsch } 711.1Sjakllsch 721.1Sjakllsch if (!cold) 731.1Sjakllsch kpause("panele", false, mstohz(200), NULL); 741.1Sjakllsch 751.1Sjakllsch return 0; 761.1Sjakllsch} 771.1Sjakllsch 781.1Sjakllschstatic int 791.1Sjakllschpanel_fdt_prepare(struct drm_panel * panel) 801.1Sjakllsch{ 811.1Sjakllsch struct panel_fdt_softc * const sc = to_panel_fdt(panel); 821.1Sjakllsch 831.1Sjakllsch if (sc->sc_regulator) { 841.1Sjakllsch fdtbus_regulator_enable(sc->sc_regulator); 851.1Sjakllsch } 861.1Sjakllsch 871.1Sjakllsch if (cold) 881.1Sjakllsch delay(210000); 891.1Sjakllsch else 901.1Sjakllsch kpause("panelp", false, mstohz(210), NULL); 911.1Sjakllsch 921.1Sjakllsch return 0; 931.1Sjakllsch} 941.1Sjakllsch 951.1Sjakllschstatic const struct drm_panel_funcs panel_fdt_funcs = { 961.1Sjakllsch .disable = NULL, 971.1Sjakllsch .enable = panel_fdt_enable, 981.1Sjakllsch .get_modes = NULL, 991.1Sjakllsch .get_timings = NULL, 1001.1Sjakllsch .prepare = panel_fdt_prepare, 1011.1Sjakllsch .unprepare = NULL, 1021.1Sjakllsch}; 1031.1Sjakllsch 1041.1Sjakllschstatic int 1051.1Sjakllschpanel_fdt_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate) 1061.1Sjakllsch{ 1071.1Sjakllsch struct fdt_endpoint *rep = fdt_endpoint_remote(ep); 1081.1Sjakllsch 1091.1Sjakllsch if (fdt_endpoint_port_index(ep) != 0) 1101.1Sjakllsch return EINVAL; 1111.1Sjakllsch 1121.1Sjakllsch if (fdt_endpoint_type(rep) != EP_DRM_ENCODER) 1131.1Sjakllsch return EINVAL; 1141.1Sjakllsch 1151.1Sjakllsch return 0; 1161.1Sjakllsch} 1171.1Sjakllsch 1181.1Sjakllschstatic void * 1191.1Sjakllschpanel_fdt_ep_get_data(device_t dev, struct fdt_endpoint *ep) 1201.1Sjakllsch{ 1211.1Sjakllsch struct panel_fdt_softc * const sc = device_private(dev); 1221.1Sjakllsch 1231.1Sjakllsch return &sc->sc_panel; 1241.1Sjakllsch} 1251.1Sjakllsch 1261.1Sjakllschstatic int 1271.1Sjakllschpanel_fdt_match(device_t parent, cfdata_t cf, void *aux) 1281.1Sjakllsch{ 1291.1Sjakllsch struct fdt_attach_args * const faa = aux; 1301.1Sjakllsch 1311.3Sthorpej return of_compatible_match(faa->faa_phandle, compat_data); 1321.1Sjakllsch} 1331.1Sjakllsch 1341.1Sjakllschstatic void 1351.1Sjakllschpanel_fdt_attach(device_t parent, device_t self, void *aux) 1361.1Sjakllsch{ 1371.1Sjakllsch struct panel_fdt_softc * const sc = device_private(self); 1381.1Sjakllsch struct fdt_attach_args * const faa = aux; 1391.1Sjakllsch const int phandle = faa->faa_phandle; 1401.1Sjakllsch 1411.1Sjakllsch aprint_naive("\n"); 1421.1Sjakllsch aprint_normal(": panel\n"); 1431.1Sjakllsch 1441.1Sjakllsch sc->sc_dev = self; 1451.1Sjakllsch 1461.1Sjakllsch /* required for "simple-panel" */ 1471.1Sjakllsch sc->sc_regulator = fdtbus_regulator_acquire(phandle, "power-supply"); 1481.2Sjakllsch if (sc->sc_regulator == NULL) { 1491.2Sjakllsch aprint_error_dev(self, "regulator not found\n"); 1501.2Sjakllsch return; 1511.2Sjakllsch } 1521.1Sjakllsch 1531.1Sjakllsch /* optional for "simple-panel" */ 1541.1Sjakllsch sc->sc_enable = fdtbus_gpio_acquire_index(phandle, 1551.1Sjakllsch "enable-gpios", 0, GPIO_PIN_OUTPUT); 1561.1Sjakllsch 1571.1Sjakllsch sc->sc_ports.dp_ep_activate = panel_fdt_ep_activate; 1581.1Sjakllsch sc->sc_ports.dp_ep_get_data = panel_fdt_ep_get_data; 1591.1Sjakllsch fdt_ports_register(&sc->sc_ports, self, phandle, EP_DRM_PANEL); 1601.1Sjakllsch 1611.5Sriastrad drm_panel_init(&sc->sc_panel, self, &panel_fdt_funcs, DRM_MODE_CONNECTOR_DPI); 1621.1Sjakllsch sc->sc_panel.funcs = &panel_fdt_funcs; 1631.1Sjakllsch 1641.1Sjakllsch drm_panel_add(&sc->sc_panel); 1651.1Sjakllsch} 1661.1Sjakllsch 1671.1SjakllschCFATTACH_DECL_NEW(panel_fdt, sizeof(struct panel_fdt_softc), 1681.1Sjakllsch panel_fdt_match, panel_fdt_attach, NULL, NULL); 169