diff options
| author | GuEe-GUI <[email protected]> | 2024-09-10 13:38:24 +0800 |
|---|---|---|
| committer | Meco Man <[email protected]> | 2024-09-13 17:33:29 -0400 |
| commit | 2d026a316aa39b13897959d3fc851e39aaa0d054 (patch) | |
| tree | 4982127c0ae1159fccee1cf12b661bbdab68c010 | |
| parent | 117e6ed347ee67699238170e76633d70703c2b55 (diff) | |
[FEATURE/OFW] add address reverse/translate for DMA/CPU's address
DMA and CPU address view is different, we need to convert them:
+--------+ +--------+ +---------+ +--------+
| | | | | | | |
| CPUs | | DEV0 | | IOMMU <----+ | DEV1 |
| | | | | | | | |
+----+---+ +----+---+ +----+----+ | +----+---+
| | | | |
0x200000 | 0x1000 | 0x1000 | | 0x8000 |
| | | | |
+-------------+-----------+ +----------+
|
|
+--------v----------------------------------------------------+
| |
| Address BUS |
| |
+-------------------------------------------------------------+
Signed-off-by: GuEe-GUI <[email protected]>
| -rwxr-xr-x | components/drivers/include/drivers/ofw_io.h | 21 | ||||
| -rwxr-xr-x | components/drivers/ofw/io.c | 69 |
2 files changed, 90 insertions, 0 deletions
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 |
