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;
+};

Reply via email to