mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
To: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>,
	barebox@lists.infradead.org
Subject: [PATCH] of: add ranges address translation for default bus
Date: Mon, 13 May 2013 01:09:06 +0200	[thread overview]
Message-ID: <1368400146-30443-1-git-send-email-sebastian.hesselbarth@gmail.com> (raw)

This patch adds address translation for default bus types. It has been
shamelessly ported from Linux device tree address translation with the
following exceptions:
- only default bus map and translate are supported
- of_bus has not been ported
- check for #size-cells > 0 has been removed

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: barebox@lists.infradead.org
---
 drivers/of/base.c |  131 ++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 114 insertions(+), 17 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 8383549..cad7baa 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -28,6 +28,12 @@
 #include <linux/amba/bus.h>
 #include <linux/err.h>
 
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS	4
+#define OF_CHECK_ADDR_COUNT(na)	((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
+/* do not check for #size-cells > 0 as no size cells is perfectly valid */
+#define OF_CHECK_COUNTS(na, ns)	(OF_CHECK_ADDR_COUNT(na))
+
 /**
  * struct alias_prop - Alias property in 'aliases' node
  * @link:	List node to link the structure in aliases_lookup list
@@ -212,28 +218,119 @@ int of_alias_get_id(struct device_node *np, const char *stem)
 }
 EXPORT_SYMBOL_GPL(of_alias_get_id);
 
-u64 of_translate_address(struct device_node *node, const __be32 *in_addr)
+static u64 of_bus_default_map(__be32 *addr, const __be32 *range,
+			      int na, int ns, int pna)
 {
-	struct property *p;
-	u64 addr = be32_to_cpu(*in_addr);
+	u64 cp, s, da;
+
+	cp = of_read_number(range, na);
+	s = of_read_number(range + na + pna, ns);
+	da = of_read_number(addr, na);
+
+	/*
+	 * If #address-cells > 2 we assume the mapping does not specify a
+	 * physical address. Rather, the address specifies an identifier
+	 * that must match exactly.
+	 */
+	if (na > 2 && memcmp(range, addr, 4 * na) != 0)
+		return OF_BAD_ADDR;
+
+	/* check if address is outside mapping range */
+	if (da < cp || da >= (cp + s))
+		return OF_BAD_ADDR;
+	return da - cp;
+}
+
+static int of_bus_default_translate(__be32 *addr, u64 offset, int na)
+{
+	u64 a = of_read_number(addr, na);
+	memset(addr, 0, 4 * na);
+	a += offset;
+	if (na > 1)
+		addr[na - 2] = cpu_to_be32(a >> 32);
+	addr[na - 1] = cpu_to_be32(a & 0xffffffffu);
+	return 0;
+}
+
+static int of_translate_one(struct device_node *parent,
+			    __be32 *addr, int na, int ns, int pna,
+			    const char *rprop)
+{
+	const __be32 *ranges;
+	unsigned int rlen;
+	int rone;
+	u64 offset = OF_BAD_ADDR;
+
+	ranges = of_get_property(parent, rprop, &rlen);
+	if (!ranges)
+		return 1;
+
+	/* walk through ranges */
+	rlen /= 4;
+	rone = na + pna + ns;
+	for (; rlen >= rone; rlen -= rone, ranges += rone) {
+		offset = of_bus_default_map(addr, ranges, na, ns, pna);
+		if (offset != OF_BAD_ADDR)
+			break;
+	}
+	if (offset == OF_BAD_ADDR)
+		return 1;
+
+	memcpy(addr, ranges + na, 4 * pna);
+	/* translate into parent address space */
+	return of_bus_default_translate(addr, offset, pna);
+}
+
+u64 __of_translate_address(struct device_node *node,
+			   const __be32 *in_addr, const char *rprop)
+{
+	struct device_node *parent = node->parent;
+	__be32 addr[OF_MAX_ADDR_CELLS];
+	int na, ns, pna, pns;
+	u64 result = OF_BAD_ADDR;
+
+	/* count address cells & copy address locally */
+	of_bus_count_cells(node, &na, &ns);
+	if (!OF_CHECK_COUNTS(na, ns)) {
+		printk(KERN_ERR "of: bad cell count (%d, %d) for %s\n",
+		       na, ns, node->full_name);
+		return OF_BAD_ADDR;
+	}
+	memcpy(addr, in_addr, na * 4);
 
 	while (1) {
-		int na, nc;
-
-		if (!node->parent)
-			return addr;
-
-		node = node->parent;
-		p = of_find_property(node, "ranges");
-		if (!p && node->parent)
-			return OF_BAD_ADDR;
-		of_bus_count_cells(node, &na, &nc);
-		if (na != 1 || nc != 1) {
-			printk("%s: #size-cells != 1 or #address-cells != 1 "
-					"currently not supported\n", node->name);
-			return OF_BAD_ADDR;
+		node = parent;
+		parent = node->parent;
+
+		/* exit at root node */
+		if (!parent) {
+			result = of_read_number(addr, na);
+			break;
 		}
+
+		/* get new parent bus and counts */
+		of_bus_count_cells(node, &pna, &pns);
+		if (!OF_CHECK_COUNTS(pna, pns)) {
+			printk(KERN_ERR "of: bad cell count (%d, %d) for %s\n",
+			       pna, pns, node->full_name);
+			break;
+		}
+
+		/* apply bus translation */
+		if (of_translate_one(node, addr, na, ns, pna, rprop))
+			break;
+
+		/* ascend device tree */
+		na = pna;
+		ns = pns;
 	}
+
+	return result;
+}
+
+u64 of_translate_address(struct device_node *node, const __be32 *in_addr)
+{
+	return __of_translate_address(node, in_addr, "ranges");
 }
 EXPORT_SYMBOL(of_translate_address);
 
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

             reply	other threads:[~2013-05-12 23:09 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-05-12 23:09 Sebastian Hesselbarth [this message]
2013-05-19  7:34 ` Sascha Hauer
2013-05-19  8:07   ` Sebastian Hesselbarth
2013-05-19 10:39     ` Sascha Hauer
2013-05-19 10:49       ` Sebastian Hesselbarth
2013-05-19 15:20         ` Thomas Petazzoni
2013-06-11  9:33   ` Sebastian Hesselbarth
2013-06-13  9:25     ` Sascha Hauer
2013-06-13  9:38       ` Sebastian Hesselbarth
2013-06-13 12:48         ` Sascha Hauer
2013-06-13 18:50           ` Sebastian Hesselbarth
2013-06-17  7:47             ` Sascha Hauer
2013-06-17 10:23               ` Sebastian Hesselbarth
2013-06-17 10:40                 ` Sascha Hauer

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=1368400146-30443-1-git-send-email-sebastian.hesselbarth@gmail.com \
    --to=sebastian.hesselbarth@gmail.com \
    --cc=barebox@lists.infradead.org \
    --cc=thomas.petazzoni@free-electrons.com \
    /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