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