[PATCH 4/8] dm: Introduce xxx_get_dma_range()

Nicolas Saenz Julienne nsaenzjulienne at suse.de
Thu Nov 19 18:48:18 CET 2020


Add the follwing functions to get a specific device's DMA ranges:
 - dev_get_dma_range()
 - ofnode_get_dma_range()
 - of_get_dma_range()
 - fdt_get_dma_range()
They are specially useful in oder to be able validate a physical address
space range into a bus's and to convert addresses from and to address
spaces.

Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne at suse.de>
---
 common/fdt_support.c   | 72 ++++++++++++++++++++++++++++++++++++++++++
 drivers/core/of_addr.c | 68 +++++++++++++++++++++++++++++++++++++++
 drivers/core/ofnode.c  |  9 ++++++
 drivers/core/read.c    |  5 +++
 include/dm/of_addr.h   | 17 ++++++++++
 include/dm/ofnode.h    | 16 ++++++++++
 include/dm/read.h      |  6 ++++
 include/fdt_support.h  | 14 ++++++++
 8 files changed, 207 insertions(+)

diff --git a/common/fdt_support.c b/common/fdt_support.c
index 5ae75df3c6..78dc7906bd 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -1342,6 +1342,78 @@ u64 fdt_translate_dma_address(const void *blob, int node_offset,
 	return __of_translate_address(blob, node_offset, in_addr, "dma-ranges");
 }
 
+int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu,
+		      dma_addr_t *bus, u64 *size)
+{
+	bool found_dma_ranges = false;
+	const fdt32_t *ranges;
+	int na, ns, pna, pns;
+	int parent = node;
+	u64 cpu_addr;
+	int ret = 0;
+	int len;
+
+	/* Find the closest dma-ranges property */
+	while (parent >= 0) {
+		ranges = fdt_getprop(blob, parent, "dma-ranges", &len);
+
+		/* Ignore empty ranges, they imply no translation required */
+		if (ranges && len > 0)
+			break;
+
+		/* Once we find 'dma-ranges', then a missing one is an error */
+		if (found_dma_ranges && !ranges) {
+			ret = -ENODEV;
+			goto out;
+		}
+
+		if (ranges)
+			found_dma_ranges = true;
+
+		parent = fdt_parent_offset(blob, parent);
+	}
+
+	if (!ranges || parent < 0) {
+		debug("no dma-ranges found for node %s\n",
+		      fdt_get_name(blob, node, NULL));
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* switch to that node */
+	node = parent;
+	parent = fdt_parent_offset(blob, node);
+	if (parent < 0) {
+		printf("Found dma-ranges in root node, shoudln't happen\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Get the address sizes both for the bus and its parent */
+	of_match_bus(blob, node)->count_cells(blob, node, &na, &ns);
+	if (!OF_CHECK_COUNTS(na, ns)) {
+		printf("%s: Bad cell count for %s\n", __FUNCTION__,
+		       fdt_get_name(blob, node, NULL));
+		return -EINVAL;
+		goto out;
+	}
+
+	of_match_bus(blob, parent)->count_cells(blob, parent, &pna, &pns);
+	if (!OF_CHECK_COUNTS(pna, pns)) {
+		printf("%s: Bad cell count for %s\n", __FUNCTION__,
+		       fdt_get_name(blob, parent, NULL));
+		return -EINVAL;
+		goto out;
+	}
+
+	*bus = fdt_read_number(ranges, na);
+	cpu_addr = fdt_read_number(ranges + na, pna);
+	*cpu = fdt_translate_dma_address(blob, node, (const fdt32_t*)&cpu_addr);
+	*size = fdt_read_number(ranges + na + pna, ns);
+out:
+	return ret;
+}
+
 /**
  * fdt_node_offset_by_compat_reg: Find a node that matches compatiable and
  * who's reg property matches a physical cpu address
diff --git a/drivers/core/of_addr.c b/drivers/core/of_addr.c
index ca34d84922..8457e04a25 100644
--- a/drivers/core/of_addr.c
+++ b/drivers/core/of_addr.c
@@ -325,6 +325,74 @@ u64 of_translate_dma_address(const struct device_node *dev, const __be32 *in_add
 	return __of_translate_address(dev, in_addr, "dma-ranges");
 }
 
+int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
+		     dma_addr_t *bus, u64 *size)
+{
+	bool found_dma_ranges = false;
+	struct device_node parent;
+	int na, ns, pna, pns;
+	const __be32 *ranges;
+	int ret = 0;
+	int len;
+
+	/* Find the closest dma-ranges property */
+	while (dev) {
+		ranges = of_get_property(dev, "dma-ranges", &len);
+
+		/* Ignore empty ranges, they imply no translation required */
+		if (ranges && len > 0)
+			break;
+
+		/* Once we find 'dma-ranges', then a missing one is an error */
+		if (found_dma_ranges && !ranges) {
+			ret = -ENODEV;
+			goto out;
+		}
+
+		if (ranges)
+			found_dma_ranges = true;
+
+		dev = of_get_parent(dev);
+	}
+
+	if (!dev || !ranges) {
+		debug("no dma-ranges found for node %s\n",
+		      of_node_full_name(dev));
+		ret = -ENODEV
+		goto out;
+	}
+
+	/* switch to that node */
+	parent = of_get_parent(dev);
+	if (!parent) {
+		printf("Found dma-ranges in root node, shoudln't happen\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Get the address sizes both for the bus and its parent */
+	of_match_bus(dev)->count_cells(dev, &na, &ns);
+	if (!OF_CHECK_COUNTS(na, ns)) {
+		printf("Bad cell count for %s\n", of_node_full_name(dev));
+		return -EINVAL;
+		goto out;
+	}
+
+	of_match_bus(parent)->count_cells(parent, &pna, &pns);
+	if (!OF_CHECK_COUNTS(pna, pns)) {
+		printf("Bad cell count for %s\n", of_node_full_name(parent));
+		return -EINVAL;
+		goto out;
+	}
+
+	*bus = of_read_number(ranges, na);
+	*cpu = of_translate_dma_address(dev, of_read_number(ranges + na, pna));
+	*size = of_read_number(ranges + na + pna, ns);
+out:
+	return ret;
+}
+
+
 static int __of_address_to_resource(const struct device_node *dev,
 		const __be32 *addrp, u64 size, unsigned int flags,
 		const char *name, struct resource *r)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index a68076bf35..15470d4875 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -911,6 +911,15 @@ u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
 		return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
 }
 
+int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
+{
+	if (ofnode_is_np(node))
+		return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
+	else
+		return fdt_get_dma_range(gd->fdt_blob, ofnode_to_offset(node),
+					 cpu, bus, size);
+}
+
 int ofnode_device_is_compatible(ofnode node, const char *compat)
 {
 	if (ofnode_is_np(node))
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 076125824c..b835e82be9 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -338,6 +338,11 @@ u64 dev_translate_dma_address(const struct udevice *dev, const fdt32_t *in_addr)
 	return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
 }
 
+u64 dev_translate_cpu_address(const struct udevice *dev, const fdt32_t *in_addr)
+{
+	return ofnode_translate_cpu_address(dev_ofnode(dev), in_addr);
+}
+
 int dev_read_alias_highest_id(const char *stem)
 {
 	if (of_live_active())
diff --git a/include/dm/of_addr.h b/include/dm/of_addr.h
index 3fa1ffce81..ee21d5cf4f 100644
--- a/include/dm/of_addr.h
+++ b/include/dm/of_addr.h
@@ -44,6 +44,23 @@ u64 of_translate_address(const struct device_node *no, const __be32 *in_addr);
  */
 u64 of_translate_dma_address(const struct device_node *no, const __be32 *in_addr);
 
+
+/**
+ * of_get_dma_range() - get dma-ranges for a specific DT node
+ *
+ * Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
+ * cpu->bus address translations
+ *
+ * @param blob		Pointer to device tree blob
+ * @param node_offset	Node DT offset
+ * @param cpu		Pointer to variable storing the range's cpu address
+ * @param bus		Pointer to variable storing the range's bus address
+ * @param size		Pointer to variable storing the range's size
+ * @return translated DMA address or OF_BAD_ADDR on error
+ */
+int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
+		     dma_addr_t *bus, u64 *size);
+
 /**
  * of_get_address() - obtain an address from a node
  *
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index ced7f6ffb2..dc3dd84d9f 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -939,6 +939,22 @@ u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr);
  */
 u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr);
 
+/**
+ * ofnode_get_dma_range() - get dma-ranges for a specific DT node
+ *
+ * Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
+ * cpu->bus address translations
+ *
+ * @param blob		Pointer to device tree blob
+ * @param node_offset	Node DT offset
+ * @param cpu		Pointer to variable storing the range's cpu address
+ * @param bus		Pointer to variable storing the range's bus address
+ * @param size		Pointer to variable storing the range's size
+ * @return translated DMA address or OF_BAD_ADDR on error
+ */
+int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus,
+			 u64 *size);
+
 /**
  * ofnode_device_is_compatible() - check if the node is compatible with compat
  *
diff --git a/include/dm/read.h b/include/dm/read.h
index 0585eb1228..9e1f3f5f12 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -1004,6 +1004,12 @@ static inline u64 dev_translate_dma_address(const struct udevice *dev,
 	return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
 }
 
+static inline u64 dev_get_dma_range(const struct udevice *dev, phys_addr_t *cpu,
+				    dma_addr_t *bus, u64 *size)
+{
+	return ofnode_get_dma_range(dev_ofnode(dev), cpu, bus, size);
+}
+
 static inline int dev_read_alias_highest_id(const char *stem)
 {
 	if (!CONFIG_IS_ENABLED(OF_LIBFDT))
diff --git a/include/fdt_support.h b/include/fdt_support.h
index dbbac0fb6a..46eb1dbbb2 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -260,6 +260,20 @@ u64 fdt_translate_address(const void *blob, int node_offset,
 u64 fdt_translate_dma_address(const void *blob, int node_offset,
 			      const __be32 *in_addr);
 
+/**
+ * Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
+ * cpu->bus address translations
+ *
+ * @param blob		Pointer to device tree blob
+ * @param node_offset	Node DT offset
+ * @param cpu		Pointer to variable storing the range's cpu address
+ * @param bus		Pointer to variable storing the range's bus address
+ * @param size		Pointer to variable storing the range's size
+ * @return translated DMA address or OF_BAD_ADDR on error
+ */
+int fdt_get_dma_range(const void *blob, int node_offset, phys_addr_t *cpu,
+		      dma_addr_t *bus, u64 *size);
+
 int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
 					phys_addr_t compat_off);
 int fdt_alloc_phandle(void *blob);
-- 
2.29.2



More information about the U-Boot mailing list