
On 10/12/2020 10:42, Nicolas Saenz Julienne wrote:
Add the following 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@suse.de
Changes since v1:
- Fix wrong arguments in of_get_dma_range()'s call to of_translate_dma_address()
- Fix build in SPL/TPL and no LIBFDT supprt
- Add missing declaration in 'core/read.c'
- Address Matthias' comments
common/fdt_support.c | 73 ++++++++++++++++++++++++++++++++++++++++++ drivers/core/of_addr.c | 71 ++++++++++++++++++++++++++++++++++++++++ drivers/core/ofnode.c | 9 ++++++ drivers/core/read.c | 9 ++++++ include/dm/of_addr.h | 17 ++++++++++ include/dm/ofnode.h | 16 +++++++++ include/dm/read.h | 21 ++++++++++++ include/fdt_support.h | 14 ++++++++ 8 files changed, 230 insertions(+)
diff --git a/common/fdt_support.c b/common/fdt_support.c index 5ae75df3c6..4bcd6720d2 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -1342,6 +1342,79 @@ 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;
- struct of_bus *bus_node;
- const fdt32_t *ranges;
- int na, ns, pna, pns;
- int parent = node;
- 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 */
- bus_node = of_match_bus(blob, node);
- bus_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;
- }
- bus_node = of_match_bus(blob, parent);
- bus_node->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 = fdt_translate_dma_address(blob, node, ranges + na);
- *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..b1d6165b0a 100644 --- a/drivers/core/of_addr.c +++ b/drivers/core/of_addr.c @@ -325,6 +325,77 @@ 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;
- struct of_bus *bus_node;
- 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;
- }
Although the function is a dummy, we should put of_node_put() here, to be in sync with the rest of the code.
Regards, Matthias