diff options
Diffstat (limited to 'configs/platform-v7a/patches/barebox-2019.12.0/0005-of-Read-dma_offset-from-device-tree.patch')
-rw-r--r-- | configs/platform-v7a/patches/barebox-2019.12.0/0005-of-Read-dma_offset-from-device-tree.patch | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/configs/platform-v7a/patches/barebox-2019.12.0/0005-of-Read-dma_offset-from-device-tree.patch b/configs/platform-v7a/patches/barebox-2019.12.0/0005-of-Read-dma_offset-from-device-tree.patch new file mode 100644 index 0000000..d46d44b --- /dev/null +++ b/configs/platform-v7a/patches/barebox-2019.12.0/0005-of-Read-dma_offset-from-device-tree.patch @@ -0,0 +1,203 @@ +From: Sascha Hauer <s.hauer@pengutronix.de> +Date: Fri, 20 Dec 2019 12:32:23 +0100 +Subject: [PATCH] of: Read dma_offset from device tree + +This reads the dma-ranges property from the device tree and sets +dma_offset in the devices accordingly. The code is mostly taken +from the Kernel as of v5.5-rc1. of_dma_configure() is trimmed down +to the cases we want to support currently. + +Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> +--- + drivers/of/address.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/of/platform.c | 18 +++++++++ + include/of_address.h | 9 +++++ + 3 files changed, 136 insertions(+) + +diff --git a/drivers/of/address.c b/drivers/of/address.c +index 4e12522a0a75..2020f5b7b1ed 100644 +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -458,6 +458,33 @@ bool of_can_translate_address(struct device_node *dev) + } + EXPORT_SYMBOL(of_can_translate_address); + ++static struct device_node *__of_get_dma_parent(struct device_node *np) ++{ ++ struct of_phandle_args args; ++ int ret, index; ++ ++ index = of_property_match_string(np, "interconnect-names", "dma-mem"); ++ if (index < 0) ++ return of_get_parent(np); ++ ++ ret = of_parse_phandle_with_args(np, "interconnects", ++ "#interconnect-cells", ++ index, &args); ++ if (ret < 0) ++ return of_get_parent(np); ++ ++ return args.np; ++} ++ ++static struct device_node *of_get_next_dma_parent(struct device_node *np) ++{ ++ struct device_node *parent; ++ ++ parent = __of_get_dma_parent(np); ++ ++ return parent; ++} ++ + const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, + unsigned int *flags) + { +@@ -586,3 +613,85 @@ void __iomem *of_iomap(struct device_node *np, int index) + return IOMEM(res.start); + } + EXPORT_SYMBOL(of_iomap); ++ ++/** ++ * of_dma_get_range - Get DMA range info ++ * @np: device node to get DMA range info ++ * @dma_addr: pointer to store initial DMA address of DMA range ++ * @paddr: pointer to store initial CPU address of DMA range ++ * @size: pointer to store size of DMA range ++ * ++ * Look in bottom up direction for the first "dma-ranges" property ++ * and parse it. ++ * dma-ranges format: ++ * DMA addr (dma_addr) : naddr cells ++ * CPU addr (phys_addr_t) : pna cells ++ * size : nsize cells ++ * ++ * It returns -ENODEV if "dma-ranges" property was not found ++ * for this device in DT. ++ */ ++int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *size) ++{ ++ struct device_node *node = np; ++ const __be32 *ranges = NULL; ++ int len, naddr, nsize, pna; ++ int ret = 0; ++ bool found_dma_ranges = false; ++ u64 dmaaddr; ++ ++ while (node) { ++ ranges = of_get_property(node, "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; ++ } ++ found_dma_ranges = true; ++ ++ node = of_get_next_dma_parent(node); ++ } ++ ++ if (!node || !ranges) { ++ pr_debug("no dma-ranges found for node(%pOF)\n", np); ++ ret = -ENODEV; ++ goto out; ++ } ++ ++ naddr = of_bus_n_addr_cells(node); ++ nsize = of_bus_n_size_cells(node); ++ pna = of_n_addr_cells(node); ++ if ((len / sizeof(__be32)) % (pna + naddr + nsize)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* dma-ranges format: ++ * DMA addr : naddr cells ++ * CPU addr : pna cells ++ * size : nsize cells ++ */ ++ dmaaddr = of_read_number(ranges, naddr); ++ *paddr = of_translate_dma_address(node, ranges + naddr); ++ if (*paddr == OF_BAD_ADDR) { ++ pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n", ++ dmaaddr, np); ++ ret = -EINVAL; ++ goto out; ++ } ++ *dma_addr = dmaaddr; ++ ++ *size = of_read_number(ranges + naddr + pna, nsize); ++ ++ pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n", ++ *dma_addr, *paddr, *size); ++ ++out: ++ ++ return ret; ++} +diff --git a/drivers/of/platform.c b/drivers/of/platform.c +index d3795d799a13..b1a7eb673064 100644 +--- a/drivers/of/platform.c ++++ b/drivers/of/platform.c +@@ -74,6 +74,22 @@ static void of_device_make_bus_id(struct device_d *dev) + } + } + ++static void of_dma_configure(struct device_d *dev, struct device_node *np) ++{ ++ u64 dma_addr, paddr, size = 0; ++ unsigned long offset; ++ int ret; ++ ++ ret = of_dma_get_range(np, &dma_addr, &paddr, &size); ++ if (ret < 0) { ++ dma_addr = offset = 0; ++ } else { ++ offset = paddr - dma_addr; ++ } ++ ++ dev->dma_offset = offset; ++} ++ + /** + * of_platform_device_create - Alloc, initialize and register an of_device + * @np: pointer to node to create device for +@@ -148,6 +164,8 @@ struct device_d *of_platform_device_create(struct device_node *np, + dev->num_resources = num_reg; + of_device_make_bus_id(dev); + ++ of_dma_configure(dev, np); ++ + resinval = (-1); + + debug("%s: register device %s, io=%pa\n", +diff --git a/include/of_address.h b/include/of_address.h +index ebf3ec2a2423..350ecaec827a 100644 +--- a/include/of_address.h ++++ b/include/of_address.h +@@ -56,6 +56,9 @@ extern struct device_node *of_find_matching_node_by_address( + u64 base_address); + extern void __iomem *of_iomap(struct device_node *np, int index); + ++extern int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, ++ u64 *size); ++ + #else /* CONFIG_OFTREE */ + + static inline u64 of_translate_address(struct device_node *dev, +@@ -99,6 +102,12 @@ static inline void __iomem *of_iomap(struct device_node *np, int index) + return NULL; + } + ++static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr, ++ u64 *paddr, u64 *size) ++{ ++ return -ENOSYS; ++} ++ + #endif /* CONFIG_OFTREE */ + + #ifdef CONFIG_OF_PCI |