diff --git a/components/drivers/include/drivers/ofw_io.h b/components/drivers/include/drivers/ofw_io.h index 4ebfbe2c82..f458435d09 100755 --- a/components/drivers/include/drivers/ofw_io.h +++ b/components/drivers/include/drivers/ofw_io.h @@ -26,6 +26,27 @@ rt_err_t rt_ofw_get_address_by_name(struct rt_ofw_node *np, const char *name, int rt_ofw_get_address_array(struct rt_ofw_node *np, int nr, rt_uint64_t *out_regs); rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address); +rt_uint64_t rt_ofw_reverse_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address); + +rt_inline rt_uint64_t rt_ofw_translate_dma2cpu(struct rt_ofw_node *np, rt_uint64_t address) +{ + rt_uint64_t bus_addr, cpu_addr; + + bus_addr = rt_ofw_reverse_address(np, "dma-ranges", address); + cpu_addr = rt_ofw_translate_address(np, "ranges", bus_addr); + + return cpu_addr != ~0ULL ? cpu_addr : address; +} + +rt_inline rt_uint64_t rt_ofw_translate_cpu2dma(struct rt_ofw_node *np, rt_uint64_t address) +{ + rt_uint64_t bus_addr, dma_addr; + + bus_addr = rt_ofw_reverse_address(np, "ranges", address); + dma_addr = rt_ofw_translate_address(np, "dma-ranges", bus_addr); + + return dma_addr != ~0ULL ? dma_addr : address; +} void *rt_ofw_iomap(struct rt_ofw_node *np, int index); void *rt_ofw_iomap_by_name(struct rt_ofw_node *np, const char *name); diff --git a/components/drivers/ofw/io.c b/components/drivers/ofw/io.c index d9065c07f4..b0a7526f5b 100755 --- a/components/drivers/ofw/io.c +++ b/components/drivers/ofw/io.c @@ -407,6 +407,75 @@ rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_t return cpu_addr; } +rt_uint64_t rt_ofw_reverse_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address) +{ + rt_uint64_t bus_addr = address; + + if (!range_type) + { + range_type = "ranges"; + } + + rt_ofw_foreach_parent_node(np) + { + rt_ssize_t len; + struct rt_ofw_prop *prop; + struct bus_ranges *ranges = RT_NULL; + + prop = rt_ofw_get_prop(np, range_type, &len); + + if (!prop || !len) + { + continue; + } + + for (int i = 0; i < RT_ARRAY_SIZE(_bus_ranges); ++i) + { + if (!_bus_ranges[i]) + { + break; + } + + if (_bus_ranges[i]->np == np) + { + ranges = _bus_ranges[i]; + break; + } + } + + if (!ranges) + { + ranges = ofw_bus_ranges(np, prop); + } + + if (ranges) + { + for (int i = 0; i < ranges->nr; ++i) + { + rt_uint64_t parent_addr = ranges->parent_addr[i]; + rt_uint64_t child_size = ranges->child_size[i]; + + if (address >= parent_addr && address < parent_addr + child_size) + { + bus_addr = ranges->child_addr[i] + (address - parent_addr); + + break; + } + } + } + else + { + bus_addr = ~0ULL; + } + + rt_ofw_node_put(np); + + break; + } + + return bus_addr; +} + #ifdef ARCH_CPU_64BIT #define ofw_address_cpu_cast(np, address) (void *)(address) #else