Module Name: src
Committed By: bouyer
Date: Tue Apr 3 12:40:20 UTC 2018
Modified Files:
src/sys/dev/fdt: files.fdt
Added Files:
src/sys/dev/fdt: connector_fdt.c connector_fdt.h fdt_port.c fdt_port.h
panel_fdt.c panel_fdt.h
Log Message:
Add connector and panel drivers (panel supports only panel-lvds and
panel-dual-lvds at this time, but can easily be extended to other types
of panels).
Add an API for ports/endpoints.
Proposed on tech-kern@ a few days ago, ok jmcneill@
To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/sys/dev/fdt/connector_fdt.c \
src/sys/dev/fdt/connector_fdt.h src/sys/dev/fdt/fdt_port.c \
src/sys/dev/fdt/fdt_port.h src/sys/dev/fdt/panel_fdt.c \
src/sys/dev/fdt/panel_fdt.h
cvs rdiff -u -r1.22 -r1.23 src/sys/dev/fdt/files.fdt
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/fdt/files.fdt
diff -u src/sys/dev/fdt/files.fdt:1.22 src/sys/dev/fdt/files.fdt:1.23
--- src/sys/dev/fdt/files.fdt:1.22 Sun Oct 22 13:56:49 2017
+++ src/sys/dev/fdt/files.fdt Tue Apr 3 12:40:20 2018
@@ -1,4 +1,4 @@
-# $NetBSD: files.fdt,v 1.22 2017/10/22 13:56:49 jmcneill Exp $
+# $NetBSD: files.fdt,v 1.23 2018/04/03 12:40:20 bouyer Exp $
include "external/bsd/libfdt/conf/files.libfdt"
@@ -34,6 +34,16 @@ device gpioleds: leds
attach gpioleds at fdt
file dev/fdt/gpioleds.c gpioleds
+file dev/fdt/fdt_port.c fdt_port
+
+device connector: fdt_port
+attach connector at fdt with fdt_connector
+file dev/fdt/connector_fdt.c fdt_connector
+
+device panel: fdt_port
+attach panel at fdt with fdt_panel
+file dev/fdt/panel_fdt.c fdt_panel
+
file dev/fdt/fdt_openfirm.c fdtbus
file dev/fdt/fdt_subr.c fdtbus
file dev/fdt/fdt_clock.c fdtbus
Added files:
Index: src/sys/dev/fdt/connector_fdt.c
diff -u /dev/null src/sys/dev/fdt/connector_fdt.c:1.1
--- /dev/null Tue Apr 3 12:40:20 2018
+++ src/sys/dev/fdt/connector_fdt.c Tue Apr 3 12:40:20 2018
@@ -0,0 +1,129 @@
+/* $NetBSD: connector_fdt.c,v 1.1 2018/04/03 12:40:20 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * connector driver.
+ * specified in linux/Documentation/devicetree/bindings/display/connector/
+ * basically it only register its endpoint.
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(1, "$NetBSD: connector_fdt.c,v 1.1 2018/04/03 12:40:20 bouyer Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/bus.h>
+#include <sys/kmem.h>
+
+#include <dev/fdt/fdtvar.h>
+#include <dev/fdt/fdt_port.h>
+#include <dev/fdt/connector_fdt.h>
+
+static int fdt_connector_match(device_t, cfdata_t, void *);
+static void fdt_connector_attach(device_t, device_t, void *);
+static void *fdt_connector_get_data(device_t, struct fdt_endpoint *);
+
+SLIST_HEAD(, fdt_connector_softc) fdt_connectors =
+ SLIST_HEAD_INITIALIZER(&fdt_connectors);
+
+struct fdt_connector_softc {
+ device_t sc_dev;
+ int sc_phandle;
+ struct fdt_connector sc_con;
+ SLIST_ENTRY(fdt_connector_softc) sc_list;
+ struct fdt_device_ports sc_ports;
+};
+
+#define sc_type sc_con.con_type
+
+CFATTACH_DECL_NEW(fdt_connector, sizeof(struct fdt_connector_softc),
+ fdt_connector_match, fdt_connector_attach, NULL, NULL);
+
+static const struct of_compat_data compat_data[] = {
+ {"composite-video-connector", CON_TV},
+ {"dvi-connector", CON_DVI},
+ {"hdmi-connector", CON_HDMI},
+ {"vga-connector", CON_VGA},
+ { NULL }
+};
+
+static int
+fdt_connector_match(device_t parent, cfdata_t cf, void *aux)
+{
+ const struct fdt_attach_args *faa = aux;
+
+ return of_match_compat_data(faa->faa_phandle, compat_data);
+}
+
+static void
+fdt_connector_attach(device_t parent, device_t self, void *aux)
+{
+ struct fdt_connector_softc *sc = device_private(self);
+ const struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+
+ sc->sc_dev = self;
+ sc->sc_phandle = phandle;
+ sc->sc_type = of_search_compatible(phandle, compat_data)->data;
+
+ SLIST_INSERT_HEAD(&fdt_connectors, sc, sc_list);
+
+ aprint_naive("\n");
+ switch(sc->sc_type) {
+ case CON_VGA:
+ aprint_normal(": VGA");
+ break;
+ case CON_DVI:
+ aprint_normal(": DVI");
+ break;
+ case CON_HDMI:
+ aprint_normal(": HDMI");
+ break;
+ case CON_TV:
+ aprint_normal(": composite");
+ break;
+ default:
+ panic("unknown connector type %d\n", sc->sc_type);
+ }
+ aprint_normal(" connector\n");
+ sc->sc_ports.dp_ep_get_data = fdt_connector_get_data;
+ fdt_ports_register(&sc->sc_ports, self, phandle, EP_CONNECTOR);
+}
+
+static void *
+fdt_connector_get_data(device_t dev, struct fdt_endpoint *ep)
+{
+ struct fdt_connector_softc *sc = device_private(dev);
+
+ return &sc->sc_con;
+}
Index: src/sys/dev/fdt/connector_fdt.h
diff -u /dev/null src/sys/dev/fdt/connector_fdt.h:1.1
--- /dev/null Tue Apr 3 12:40:20 2018
+++ src/sys/dev/fdt/connector_fdt.h Tue Apr 3 12:40:20 2018
@@ -0,0 +1,41 @@
+/* $NetBSD: connector_fdt.h,v 1.1 2018/04/03 12:40:20 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+enum connector_type {
+ CON_VGA,
+ CON_DVI,
+ CON_HDMI,
+ CON_TV,
+};
+
+struct fdt_connector {
+ enum connector_type con_type;
+};
Index: src/sys/dev/fdt/fdt_port.c
diff -u /dev/null src/sys/dev/fdt/fdt_port.c:1.1
--- /dev/null Tue Apr 3 12:40:20 2018
+++ src/sys/dev/fdt/fdt_port.c Tue Apr 3 12:40:20 2018
@@ -0,0 +1,370 @@
+/* $NetBSD: fdt_port.c,v 1.1 2018/04/03 12:40:20 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * ports and endpoints management. from
+ * linux/Documentation/devicetree/bindings/graph.txt
+ * Given a device and its node, it enumerates all ports and endpoints for this
+ * device, and register connections with the remote endpoints.
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(1, "$NetBSD: fdt_port.c,v 1.1 2018/04/03 12:40:20 bouyer Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/bus.h>
+#include <sys/kmem.h>
+
+#include <dev/fdt/fdtvar.h>
+#include <dev/fdt/fdt_port.h>
+
+struct fdt_endpoint;
+
+struct fdt_port {
+ int port_id;
+ int port_phandle; /* port's node */
+ struct fdt_endpoint *port_ep; /* this port's endpoints */
+ int port_nep; /* number of endpoints for this port */
+ struct fdt_device_ports *port_dp; /* this port's device */
+};
+
+struct fdt_endpoint {
+ int ep_id;
+ enum endpoint_type ep_type;
+ int ep_phandle;
+ struct fdt_port *ep_port; /* parent of this endpoint */
+ int ep_rphandle; /* report endpoint */
+ struct fdt_endpoint *ep_rep;
+ bool ep_active;
+ bool ep_enabled;
+};
+
+SLIST_HEAD(, fdt_device_ports) fdt_port_devices =
+ SLIST_HEAD_INITIALIZER(&fdt_port_devices);
+
+static void fdt_endpoints_register(int, struct fdt_port *, enum endpoint_type);
+static const char *ep_name(struct fdt_endpoint *, char *, int);
+
+struct fdt_endpoint *
+fdt_endpoint_get_from_phandle(int rphandle)
+{
+ struct fdt_device_ports *ports;
+ int p, e;
+
+ if (rphandle < 0)
+ return NULL;
+
+ SLIST_FOREACH(ports, &fdt_port_devices, dp_list) {
+ for (p = 0; p < ports->dp_nports; p++) {
+ struct fdt_port *port = &ports->dp_port[p];
+ for (e = 0; e < port->port_nep; e++) {
+ struct fdt_endpoint *ep = &port->port_ep[e];
+ if (ep->ep_phandle == rphandle)
+ return ep;
+ }
+ }
+ }
+ return NULL;
+
+}
+
+struct fdt_endpoint *
+fdt_endpoint_get_from_index(struct fdt_device_ports *device_ports,
+ int port_index, int ep_index)
+{
+ int p, e;
+ for (p = 0; p < device_ports->dp_nports; p++) {
+ struct fdt_port *port = &device_ports->dp_port[p];
+ if (port->port_id != port_index)
+ continue;
+ for (e = 0; e < port->port_nep; e++) {
+ struct fdt_endpoint *ep = &port->port_ep[e];
+ if (ep->ep_id == ep_index) {
+ return ep;
+ }
+ }
+ }
+ return NULL;
+}
+
+struct fdt_endpoint *
+fdt_endpoint_remote(struct fdt_endpoint *ep)
+{
+ return ep->ep_rep;
+}
+
+int
+fdt_endpoint_port_index(struct fdt_endpoint *ep)
+{
+ return ep->ep_port->port_id;
+}
+
+int
+fdt_endpoint_index(struct fdt_endpoint *ep)
+{
+ return ep->ep_id;
+}
+
+device_t
+fdt_endpoint_device(struct fdt_endpoint *ep)
+{
+ return ep->ep_port->port_dp->dp_dev;
+}
+
+bool
+fdt_endpoint_is_active(struct fdt_endpoint *ep)
+{
+ return ep->ep_active;
+}
+
+bool
+fdt_endpoint_is_enabled(struct fdt_endpoint *ep)
+{
+ return ep->ep_enabled;
+}
+
+int
+fdt_endpoint_activate(struct fdt_endpoint *ep, bool activate)
+{
+ struct fdt_endpoint *rep = fdt_endpoint_remote(ep);
+ struct fdt_device_ports *rdp;
+ int error = 0;
+
+ if (rep == NULL)
+ return ENODEV;
+
+ KASSERT(ep->ep_active == rep->ep_active);
+ KASSERT(ep->ep_enabled == rep->ep_enabled);
+ if (!activate && ep->ep_enabled)
+ return EBUSY;
+
+ rdp = rep->ep_port->port_dp;
+ if (rdp->dp_ep_activate)
+ error = rdp->dp_ep_activate(rdp->dp_dev, rep, activate);
+
+ if (error == 0)
+ rep->ep_active = ep->ep_active = activate;
+ return error;
+}
+
+int
+fdt_endpoint_enable(struct fdt_endpoint *ep, bool enable)
+{
+ struct fdt_endpoint *rep = fdt_endpoint_remote(ep);
+ struct fdt_device_ports *rdp;
+ int error = 0;
+
+ if (rep == NULL)
+ return EINVAL;
+
+ KASSERT(ep->ep_active == rep->ep_active);
+ KASSERT(ep->ep_enabled == rep->ep_enabled);
+ if (ep->ep_active == false)
+ return EINVAL;
+
+ rdp = rep->ep_port->port_dp;
+ if (rdp->dp_ep_enable)
+ error = rdp->dp_ep_enable(rdp->dp_dev, rep, enable);
+
+ if (error == 0)
+ rep->ep_enabled = ep->ep_enabled = enable;
+ return error;
+}
+
+void *
+fdt_endpoint_get_data(struct fdt_endpoint *ep)
+{
+ struct fdt_device_ports *dp = ep->ep_port->port_dp;
+
+ if (dp->dp_ep_get_data)
+ return dp->dp_ep_get_data(dp->dp_dev, ep);
+
+ return NULL;
+}
+
+int
+fdt_ports_register(struct fdt_device_ports *ports, device_t self,
+ int phandle, enum endpoint_type type)
+{
+ int port_phandle, child;
+ int i;
+ char buf[20];
+ uint64_t id;
+
+ ports->dp_dev = self;
+ SLIST_INSERT_HEAD(&fdt_port_devices, ports, dp_list);
+
+ /*
+ * walk the childs looking for ports. ports may be grouped under
+ * an optional ports node
+ */
+ port_phandle = phandle;
+again:
+ ports->dp_nports = 0;
+ for (child = OF_child(port_phandle); child; child = OF_peer(child)) {
+ if (OF_getprop(child, "name", buf, sizeof(buf)) <= 0)
+ continue;
+ if (strcmp(buf, "ports") == 0) {
+ port_phandle = child;
+ goto again;
+ }
+ if (strcmp(buf, "port") != 0)
+ continue;
+ ports->dp_nports++;
+ }
+ if (ports->dp_nports == 0)
+ return 0;
+
+ ports->dp_port =
+ kmem_zalloc(sizeof(struct fdt_port) * ports->dp_nports, KM_SLEEP);
+ KASSERT(ports->dp_port != NULL);
+ /* now scan again ports, looking for endpoints */
+ for (child = OF_child(port_phandle), i = 0; child;
+ child = OF_peer(child)) {
+ if (OF_getprop(child, "name", buf, sizeof(buf)) <= 0)
+ continue;
+ if (strcmp(buf, "ports") == 0) {
+ panic("fdt_ports_register: undetected ports");
+ }
+ if (strcmp(buf, "port") != 0)
+ continue;
+ if (fdtbus_get_reg64(child, 0, &id, NULL) != 0) {
+ if (ports->dp_nports > 1)
+ aprint_error_dev(self,
+ "%s: missing reg property",
+ fdtbus_get_string(child, "name"));
+ id = i;
+ }
+ ports->dp_port[i].port_id = id;
+ ports->dp_port[i].port_phandle = child;
+ ports->dp_port[i].port_dp = ports;
+ fdt_endpoints_register(child, &ports->dp_port[i], type);
+ i++;
+ }
+ KASSERT(i == ports->dp_nports);
+ return 0;
+}
+
+
+static void
+fdt_endpoints_register(int phandle, struct fdt_port *port,
+ enum endpoint_type type)
+{
+ int child;
+ int i;
+ char buf[128];
+ uint64_t id;
+ struct fdt_endpoint *ep, *rep;
+ struct fdt_device_ports *dp;
+
+ port->port_nep = 0;
+ for (child = OF_child(phandle); child; child = OF_peer(child)) {
+ if (OF_getprop(child, "name", buf, sizeof(buf)) <= 0)
+ continue;
+ if (strcmp(buf, "endpoint") != 0)
+ continue;
+ port->port_nep++;
+ }
+ if (port->port_nep == 0) {
+ port->port_ep = NULL;
+ return;
+ }
+
+ port->port_ep =
+ kmem_zalloc(sizeof(struct fdt_endpoint) * port->port_nep, KM_SLEEP);
+ KASSERT(port->port_ep != NULL);
+ /* now scan again ports, looking for endpoints */
+ for (child = OF_child(phandle), i = 0; child; child = OF_peer(child)) {
+ if (OF_getprop(child, "name", buf, sizeof(buf)) <= 0)
+ continue;
+ if (strcmp(buf, "endpoint") != 0)
+ continue;
+ if (fdtbus_get_reg64(child, 0, &id, NULL) != 0) {
+ if (port->port_nep > 1)
+ aprint_error_dev(port->port_dp->dp_dev,
+ "%s: missing reg property",
+ fdtbus_get_string(child, "name"));
+ id = i;
+ }
+ ep = &port->port_ep[i];
+ ep->ep_id = id;
+ ep->ep_type = type;
+ ep->ep_phandle = child;
+ ep->ep_port = port;
+ ep->ep_rphandle = fdtbus_get_phandle(child, "remote-endpoint");
+ ep->ep_rep = fdt_endpoint_get_from_phandle(
+ port->port_ep[i].ep_rphandle);
+ rep = ep->ep_rep;
+ if (rep != NULL && rep->ep_rep != NULL) {
+ aprint_error("%s: ", ep_name(ep, buf, sizeof(buf)));
+ aprint_error("remote endpoint %s ",
+ ep_name(rep, buf, sizeof(buf)));
+ aprint_error("already connected to %s\n",
+ ep_name(rep->ep_rep, buf, sizeof(buf)));
+ } else if (rep != NULL) {
+ rep->ep_rep = ep;
+ rep->ep_rphandle = child;
+ aprint_verbose("%s ", ep_name(ep, buf, sizeof(buf)));
+ aprint_verbose("connected to %s\n",
+ ep_name(rep, buf, sizeof(buf)));
+ if (rep->ep_type == EP_OTHER)
+ rep->ep_type = ep->ep_type;
+ else if (ep->ep_type == EP_OTHER)
+ ep->ep_type = rep->ep_type;
+ dp = port->port_dp;
+ if (dp->dp_ep_connect)
+ dp->dp_ep_connect(dp->dp_dev, ep, true);
+ dp = rep->ep_port->port_dp;
+ if (dp->dp_ep_connect)
+ dp->dp_ep_connect(dp->dp_dev, rep, true);
+ }
+ i++;
+ }
+ KASSERT(i == port->port_nep);
+}
+
+static const char *
+ep_name(struct fdt_endpoint *ep, char *buf, int size)
+{
+ int a;
+
+ a = snprintf(&buf[0], size, "%s",
+ device_xname(ep->ep_port->port_dp->dp_dev));
+ if (ep->ep_port->port_id >= 0 && a < size)
+ a += snprintf(&buf[a], size - a, " port %d",
+ ep->ep_port->port_id);
+ if (ep->ep_id >= 0 && a < size)
+ snprintf(&buf[a], size - a, " endpoint %d", ep->ep_id);
+ return buf;
+}
Index: src/sys/dev/fdt/fdt_port.h
diff -u /dev/null src/sys/dev/fdt/fdt_port.h:1.1
--- /dev/null Tue Apr 3 12:40:20 2018
+++ src/sys/dev/fdt/fdt_port.h Tue Apr 3 12:40:20 2018
@@ -0,0 +1,108 @@
+/* $NetBSD: fdt_port.h,v 1.1 2018/04/03 12:40:20 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * ports and endpoints management. from
+ * linux/Documentation/devicetree/bindings/graph.txt
+ * 2 endpoints can be connected together in the device tree. In this case
+ * an endpoint will have a remote endpoint.
+ * A pair of connected endpoints can be activated by a driver; when it choose
+ * to use this path.
+ * A pair of active endpoints can be enabled; when a driver starts to send
+ * a signal. Disabling a pair of endpoints can cause appropriate actions
+ * to save power (stop clocks, disable output buffers, turn on/off power, ...)
+ */
+
+#ifndef _DEV_FDT_FDT_PORT_H_
+#define _DEV_FDT_FDT_PORT_H_
+
+struct fdt_port;
+struct fdt_endpoint;
+
+struct fdt_device_ports {
+ struct fdt_port *dp_port; /* this device's ports */
+ int dp_nports; /* number of ports for this device */
+ device_t dp_dev;
+ /* callbacks to device drivers owning endpoints */
+ void (*dp_ep_connect)(device_t, struct fdt_endpoint *, bool);
+ int (*dp_ep_activate)(device_t, struct fdt_endpoint *, bool);
+ int (*dp_ep_enable)(device_t, struct fdt_endpoint *, bool);
+ void * (*dp_ep_get_data)(device_t, struct fdt_endpoint *);
+ SLIST_ENTRY(fdt_device_ports) dp_list;
+};
+
+enum endpoint_type {
+ EP_OTHER = 0,
+ EP_CONNECTOR,
+ EP_PANEL,
+};
+
+
+/*
+ * register a device's ports and enpoints into the provided fdt_device_ports.
+ * when and endpoint is connected to a remote endpoint, dp_ep_connect
+ * is called for the devices associated to both endpoints
+ */
+int fdt_ports_register(struct fdt_device_ports *, device_t,
+ int, enum endpoint_type);
+
+/* various methods to retrive an enpoint descriptor */
+struct fdt_endpoint *fdt_endpoint_get_from_phandle(int);
+struct fdt_endpoint *fdt_endpoint_get_from_index(struct fdt_device_ports *,
+ int, int);
+struct fdt_endpoint *fdt_endpoint_remote(struct fdt_endpoint *);
+
+/*
+ * get informations/data for a given endpoint
+ */
+int fdt_endpoint_port_index(struct fdt_endpoint *);
+int fdt_endpoint_index(struct fdt_endpoint *);
+device_t fdt_endpoint_device(struct fdt_endpoint *);
+bool fdt_endpoint_is_active(struct fdt_endpoint *);
+bool fdt_endpoint_is_enabled(struct fdt_endpoint *);
+/*
+ * call dp_ep_get_data() for the endpoint. The returned pointer is
+ * type of driver-specific.
+ */
+void * fdt_endpoint_get_data(struct fdt_endpoint *);
+
+/*
+ * Activate/deactivate an endpoint. This causes dp_ep_activate() to be
+ * called for the remote endpoint
+ */
+int fdt_endpoint_activate(struct fdt_endpoint *, bool);
+/*
+ * Enable/disable an endpoint. This causes dp_ep_enable() to be called for
+ * the remote endpoint
+ */
+int fdt_endpoint_enable(struct fdt_endpoint *, bool);
+
+#endif /* _DEV_FDT_FDT_PORT_H_ */
Index: src/sys/dev/fdt/panel_fdt.c
diff -u /dev/null src/sys/dev/fdt/panel_fdt.c:1.1
--- /dev/null Tue Apr 3 12:40:20 2018
+++ src/sys/dev/fdt/panel_fdt.c Tue Apr 3 12:40:20 2018
@@ -0,0 +1,192 @@
+/* $NetBSD: panel_fdt.c,v 1.1 2018/04/03 12:40:20 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * lvds panel driver.
+ * specified in linux/Documentation/devicetree/bindings/display/panel/
+ * Simple RGB panels could be added as well
+ * registers an endpoint for use by graphic controller drivers
+ *
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(1, "$NetBSD: panel_fdt.c,v 1.1 2018/04/03 12:40:20 bouyer Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/bus.h>
+#include <sys/gpio.h>
+
+#include <dev/fdt/fdtvar.h>
+#include <dev/fdt/panel_fdt.h>
+
+static int fdt_panel_match(device_t, cfdata_t, void *);
+static void fdt_panel_attach(device_t, device_t, void *);
+static void *fdt_panel_get_data(device_t, struct fdt_endpoint *);
+static int fdt_panel_enable(device_t, struct fdt_endpoint *, bool);
+
+struct fdt_panel_softc {
+ device_t sc_dev;
+ int sc_phandle;
+ struct fdt_panel sc_panel;
+ struct fdt_device_ports sc_ports;
+#define MAX_GPIO_ENABLES 8
+ struct fdtbus_gpio_pin *sc_gpios_enable[MAX_GPIO_ENABLES];
+};
+
+
+CFATTACH_DECL_NEW(fdt_panel, sizeof(struct fdt_panel_softc),
+ fdt_panel_match, fdt_panel_attach, NULL, NULL);
+
+static const struct of_compat_data compat_data[] = {
+ {"panel-lvds", PANEL_LVDS},
+ {"panel-dual-lvds", PANEL_DUAL_LVDS},
+ { NULL }
+};
+
+static int
+fdt_panel_match(device_t parent, cfdata_t cf, void *aux)
+{
+ const struct fdt_attach_args *faa = aux;
+
+ return of_match_compat_data(faa->faa_phandle, compat_data);
+}
+
+static void
+fdt_panel_attach(device_t parent, device_t self, void *aux)
+{
+ struct fdt_panel_softc *sc = device_private(self);
+ const struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ const struct display_timing * const timing =
+ &sc->sc_panel.panel_timing;
+ int child;
+ char buf[16];
+ const char *val;
+ int i;
+
+ sc->sc_dev = self;
+ sc->sc_phandle = phandle;
+ sc->sc_panel.panel_type =
+ of_search_compatible(phandle, compat_data)->data;
+
+ if (of_getprop_uint32(phandle, "width-mm", &sc->sc_panel.panel_width) ||
+ of_getprop_uint32(phandle, "height-mm", &sc->sc_panel.panel_height)){
+ aprint_error(": missing width-mm or height-mm properties\n");
+ return;
+ }
+ for (child = OF_child(phandle); child; child = OF_peer(child)) {
+ if (OF_getprop(child, "name", buf, sizeof(buf)) <= 0)
+ continue;
+ if (strcmp(buf, "panel-timing") != 0)
+ continue;
+
+ if (display_timing_parse(child,
+ &sc->sc_panel.panel_timing) != 0) {
+ aprint_error(": failed to parse panel-timing\n");
+ return;
+ }
+ }
+ if (sc->sc_panel.panel_timing.clock_freq == 0) {
+ aprint_error(": missing panel-timing\n");
+ return;
+ }
+ switch(sc->sc_panel.panel_type) {
+ case PANEL_LVDS:
+ case PANEL_DUAL_LVDS:
+ val = fdtbus_get_string(phandle, "data-mapping");
+ if (val == NULL) {
+ aprint_error(": missing data-mapping\n");
+ return;
+ }
+ if (strcmp(val, "jeida-18") == 0)
+ sc->sc_panel.panel_lvds_format = LVDS_JEIDA_18;
+ else if (strcmp(val, "jeida-24") == 0)
+ sc->sc_panel.panel_lvds_format = LVDS_JEIDA_24;
+ else if (strcmp(val, "vesa-24") == 0)
+ sc->sc_panel.panel_lvds_format = LVDS_VESA_24;
+ else {
+ aprint_error(": unkown data-mapping \"%s\"\n", val);
+ return;
+ }
+ break;
+ default:
+ panic("unknown panel type %d", sc->sc_panel.panel_type);
+ }
+
+ aprint_naive("\n");
+ aprint_normal(": %dx%d", timing->hactive, timing->vactive);
+ switch(sc->sc_panel.panel_type) {
+ case PANEL_LVDS:
+ aprint_normal(" LVDS");
+ break;
+ case PANEL_DUAL_LVDS:
+ aprint_normal(" dual-link LVDS");
+ break;
+ default:
+ panic(" unknown panel type %d", sc->sc_panel.panel_type);
+ }
+ aprint_normal(" panel\n");
+
+ for (i = 0; i < MAX_GPIO_ENABLES ; i++) {
+ sc->sc_gpios_enable[i] = fdtbus_gpio_acquire_index(phandle,
+ "enable-gpios", i, GPIO_PIN_OUTPUT);
+ if (sc->sc_gpios_enable[i] == NULL)
+ break;
+ }
+
+ aprint_verbose_dev(self, "%d enable GPIO%c\n", i, i > 1 ? 's' : ' ');
+
+ sc->sc_ports.dp_ep_get_data = fdt_panel_get_data;
+ sc->sc_ports.dp_ep_enable = fdt_panel_enable;
+ fdt_ports_register(&sc->sc_ports, self, phandle, EP_PANEL);
+}
+
+static void *
+fdt_panel_get_data(device_t dev, struct fdt_endpoint *ep)
+{
+ struct fdt_panel_softc *sc = device_private(dev);
+ return &sc->sc_panel;
+}
+
+static int
+fdt_panel_enable(device_t dev, struct fdt_endpoint *ep, bool enable)
+{
+ struct fdt_panel_softc *sc = device_private(dev);
+ for (int i = 0; i < MAX_GPIO_ENABLES ; i++) {
+ if (sc->sc_gpios_enable[i] == NULL)
+ break;
+ fdtbus_gpio_write(sc->sc_gpios_enable[i], enable);
+ }
+ return 0;
+}
Index: src/sys/dev/fdt/panel_fdt.h
diff -u /dev/null src/sys/dev/fdt/panel_fdt.h:1.1
--- /dev/null Tue Apr 3 12:40:20 2018
+++ src/sys/dev/fdt/panel_fdt.h Tue Apr 3 12:40:20 2018
@@ -0,0 +1,62 @@
+/* $NetBSD: panel_fdt.h,v 1.1 2018/04/03 12:40:20 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * lvds panels driver. From
+ * linux/Documentation/devicetree/bindings/display/panel/
+ * Simple RGB panels could be added as well
+ */
+
+#include <dev/fdt/fdt_port.h>
+#include <dev/fdt/display_timing.h>
+
+enum panel_type {
+ PANEL_LVDS = 1,
+ PANEL_DUAL_LVDS,
+};
+
+enum lvds_format {
+ LVDS_JEIDA_18,
+ LVDS_JEIDA_24,
+ LVDS_VESA_24
+};
+
+
+struct fdt_panel {
+ enum panel_type panel_type;
+ int panel_width;
+ int panel_height;
+ union {
+ enum lvds_format panel_lvds_format;
+ } format_u;
+#define panel_lvds_format format_u.panel_lvds_format
+ struct display_timing panel_timing;
+};