linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: frowand.list@gmail.com
To: robh+dt@kernel.org, david@gibson.dropbear.id.au,
	pantelis.antoniou@konsulko.com, stephen.boyd@linaro.org,
	broonie@kernel.org, grant.likely@secretlab.ca,
	mark.rutland@arm.com
Cc: mporter@konsulko.com, koen@dominion.thruhere.net,
	linux@roeck-us.net, marex@denx.de, wsa@the-dreams.de,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-i2c@vger.kernel.org, panto@antoniou-consulting.com
Subject: [RFC PATCH 1/1] device tree connectors, using plugs and sockets.
Date: Sat,  2 Jul 2016 16:55:50 -0700	[thread overview]
Message-ID: <1467503750-31703-2-git-send-email-frowand.list@gmail.com> (raw)
In-Reply-To: <1467503750-31703-1-git-send-email-frowand.list@gmail.com>

From: Frank Rowand <frank.rowand@am.sony.com>

This patch has been compiled but has not been booted.  It is likely
to contain bugs.

Problem: mother boards may contain multiple connectors that daughter
boards may be attached to.  If two of the daughter boards can be
described by the same .dtsi file, then it should be possible to
apply the same .dtbo overlay file for each of the boards, specifying
a different target connector for each board.

This patch provides the foundation to allow that to occur, by
creating the two halves of a connector, the socket on the mother
board and the plug on the daughter board.

The one remaining piece that this patch does not provide is how
the overlay manager (which does not yet exist in the mainline
tree) can apply an overlay to two different targets.  That
final step should be a trivial change to of_overlay_create(),
adding a parameter that is a mapping of the target (or maybe
even targets) in the overlay to different targets in the
active device tree.

Signed-off-by: Frank Rowand <frank.rowand@am.sony.com>
---
 drivers/of/overlay.c | 141 ++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 118 insertions(+), 23 deletions(-)

diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 82250815e9a5..df9b0097a1e1 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -25,8 +25,9 @@
 
 /**
  * struct of_overlay_info - Holds a single overlay info
- * @target:	target of the overlay operation
- * @overlay:	pointer to the overlay contents node
+ * @target:		target of the overlay operation
+ * @overlay:		pointer to the overlay contents node
+ * @plug_targets:	pointer to array of plug target pointers
  *
  * Holds a single overlay state, including all the overlay logs &
  * records.
@@ -34,6 +35,7 @@
 struct of_overlay_info {
 	struct device_node *target;
 	struct device_node *overlay;
+	struct device_node **plug_targets;
 };
 
 /**
@@ -54,7 +56,8 @@ struct of_overlay {
 };
 
 static int of_overlay_apply_one(struct of_overlay *ov,
-		struct device_node *target, const struct device_node *overlay);
+		struct device_node *target, const struct device_node *overlay,
+		bool plug_node, struct of_overlay_info *ovinfo);
 
 static int of_overlay_apply_single_property(struct of_overlay *ov,
 		struct device_node *target, struct property *prop)
@@ -97,7 +100,7 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
 	tchild = of_get_child_by_name(target, cname);
 	if (tchild != NULL) {
 		/* apply overlay recursively */
-		ret = of_overlay_apply_one(ov, tchild, child);
+		ret = of_overlay_apply_one(ov, tchild, child, false, NULL);
 		of_node_put(tchild);
 	} else {
 		/* create empty tree as a target */
@@ -112,7 +115,7 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
 		if (ret)
 			return ret;
 
-		ret = of_overlay_apply_one(ov, tchild, child);
+		ret = of_overlay_apply_one(ov, tchild, child, false, NULL);
 		if (ret)
 			return ret;
 	}
@@ -128,33 +131,108 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
  * by using the changeset.
  */
 static int of_overlay_apply_one(struct of_overlay *ov,
-		struct device_node *target, const struct device_node *overlay)
+		struct device_node *target, const struct device_node *overlay,
+		bool plug_node, struct of_overlay_info *ovinfo)
 {
-	struct device_node *child;
+	struct device_node *overlay_child;
+	struct device_node *plug_target;
 	struct property *prop;
 	int ret;
+	u32 val;
 
-	for_each_property_of_node(overlay, prop) {
-		ret = of_overlay_apply_single_property(ov, target, prop);
-		if (ret) {
-			pr_err("%s: Failed to apply prop @%s/%s\n",
-				__func__, target->full_name, prop->name);
-			return ret;
+	if (!plug_node) {
+		for_each_property_of_node(overlay, prop) {
+			ret = of_overlay_apply_single_property(ov, target, prop);
+			if (ret) {
+				pr_err("%s: Failed to apply prop @%s/%s\n",
+					__func__, target->full_name, prop->name);
+				return ret;
+			}
 		}
 	}
 
-	for_each_child_of_node(overlay, child) {
-		ret = of_overlay_apply_single_device_node(ov, target, child);
-		if (ret != 0) {
-			pr_err("%s: Failed to apply single node @%s/%s\n",
-					__func__, target->full_name,
-					child->name);
-			of_node_put(child);
-			return ret;
+	if (plug_node) {
+		struct device_node *socket_child;
+		int child_cnt = 0;
+
+		if (WARN_ON(!ovinfo))
+			return -EINVAL;
+
+		for_each_child_of_node(overlay->child, overlay_child) {
+			child_cnt++;
+		}
+		/* plug_targets[] is NULL terminated */
+		child_cnt++;
+		ovinfo->plug_targets = kcalloc(child_cnt,
+					       sizeof(*ovinfo->plug_targets),
+					       GFP_KERNEL);
+
+		child_cnt = 0;
+		for_each_child_of_node(overlay->child, overlay_child) {
+
+			socket_child = of_get_child_by_name(target,
+							    overlay_child->name);
+			ret = of_property_read_u32(socket_child,
+						   "target_phandle", &val);
+			of_node_put(socket_child);
+			if (ret != 0)
+				goto overlay_child;
+			plug_target = of_find_node_by_phandle(val);
+			if (!plug_target)
+				goto overlay_child;
+			/* save for of_node_put() in of_free_overlay_info() */
+			ovinfo->plug_targets[child_cnt++] = plug_target;
+
+			ret = of_overlay_apply_single_device_node(ov, plug_target,
+								  overlay_child);
+			if (ret != 0)
+				goto plug_target;
+		}
+
+	} else {
+		for_each_child_of_node(overlay, overlay_child) {
+			ret = of_overlay_apply_single_device_node(ov, target,
+								  overlay_child);
+			if (ret != 0)
+				goto overlay_child;
 		}
 	}
 
 	return 0;
+
+plug_target:
+	of_node_put(plug_target);
+overlay_child:
+	of_node_put(overlay_child);
+	return ret;
+}
+
+static bool plug_compatible(struct device_node *overlay,
+			    struct device_node *target)
+{
+	struct property *prop_plug;
+	struct property *prop_socket;
+	const char *c_plug;
+	const char *c_socket;
+	bool socket_node;
+
+	socket_node = of_property_read_bool(target, "connector-socket");
+	if (!socket_node)
+		return false;
+
+	prop_plug = of_find_property(overlay, "compatible", NULL);
+	prop_socket = of_find_property(target, "compatible", NULL);
+
+	for (c_socket = of_prop_next_string(prop_plug, NULL); c_socket;
+	     c_socket = of_prop_next_string(prop_plug, c_socket)) {
+		for (c_plug = of_prop_next_string(prop_plug, NULL); c_plug;
+		     c_plug = of_prop_next_string(prop_plug, c_plug)) {
+			if (!of_compat_cmp(c_plug, c_socket, strlen(c_plug)))
+				return true;
+		}
+	}
+
+	return false;
 }
 
 /**
@@ -168,13 +246,24 @@ static int of_overlay_apply_one(struct of_overlay *ov,
  */
 static int of_overlay_apply(struct of_overlay *ov)
 {
-	int i, err;
+	int i, err = 0;
+	bool plug_node = false;
 
 	/* first we apply the overlays atomically */
 	for (i = 0; i < ov->count; i++) {
 		struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i];
 
-		err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay);
+		plug_node = of_property_read_bool(ovinfo->overlay,
+						  "connector-plug");
+		if (plug_node) {
+			if (!plug_compatible(ovinfo->target, ovinfo->overlay))
+				err = -ENODEV;
+		}
+
+		if (err == 0)
+			err = of_overlay_apply_one(ov, ovinfo->target,
+						   ovinfo->overlay, plug_node,
+						   ovinfo);
 		if (err != 0) {
 			pr_err("%s: overlay failed '%s'\n",
 				__func__, ovinfo->target->full_name);
@@ -309,6 +398,7 @@ static int of_build_overlay_info(struct of_overlay *ov,
 static int of_free_overlay_info(struct of_overlay *ov)
 {
 	struct of_overlay_info *ovinfo;
+	struct device_node **plug_targets;
 	int i;
 
 	/* do it in reverse */
@@ -317,6 +407,11 @@ static int of_free_overlay_info(struct of_overlay *ov)
 
 		of_node_put(ovinfo->target);
 		of_node_put(ovinfo->overlay);
+		plug_targets = ovinfo->plug_targets;
+		while (*plug_targets != NULL) {
+			of_node_put(*plug_targets);
+			plug_targets++;
+		}
 	}
 	kfree(ov->ovinfo_tab);
 
-- 
1.9.1

  reply	other threads:[~2016-07-02 23:56 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-02 23:55 [RFC PATCH 0/1] Portable Device Tree Connector -- conceptual frowand.list
2016-07-02 23:55 ` frowand.list [this message]
2016-07-03  6:06 ` Frank Rowand
2016-07-04 15:22 ` Mark Brown
2016-07-04 18:15   ` Frank Rowand
2016-07-05 18:01 ` Pantelis Antoniou
2016-07-06 17:40   ` Frank Rowand
2016-07-07  7:15 ` David Gibson
2016-07-08  7:26   ` Pantelis Antoniou
2016-07-08  7:43     ` David Gibson
2016-07-08 19:20     ` Frank Rowand
2016-07-08 19:25       ` Frank Rowand
2016-07-08 19:22   ` Frank Rowand

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1467503750-31703-2-git-send-email-frowand.list@gmail.com \
    --to=frowand.list@gmail.com \
    --cc=broonie@kernel.org \
    --cc=david@gibson.dropbear.id.au \
    --cc=devicetree@vger.kernel.org \
    --cc=grant.likely@secretlab.ca \
    --cc=koen@dominion.thruhere.net \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=marex@denx.de \
    --cc=mark.rutland@arm.com \
    --cc=mporter@konsulko.com \
    --cc=pantelis.antoniou@konsulko.com \
    --cc=panto@antoniou-consulting.com \
    --cc=robh+dt@kernel.org \
    --cc=stephen.boyd@linaro.org \
    --cc=wsa@the-dreams.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).