diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2020-01-15 07:58:30 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2020-01-15 07:58:30 +0100 |
commit | 56c313fe1751756ba978824798f61b4abe6ac49c (patch) | |
tree | 9e98f6bee10468f8b58667e41d2f3dc3e842477a /drivers/of | |
parent | 38188906dce22189462cea0b23e67fd122e22dea (diff) | |
parent | 184050d9972b37557cdff40805ee04582c8e54e6 (diff) | |
download | barebox-56c313fe1751756ba978824798f61b4abe6ac49c.tar.gz barebox-56c313fe1751756ba978824798f61b4abe6ac49c.tar.xz |
Merge branch 'for-next/rpi'
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/address.c | 109 | ||||
-rw-r--r-- | drivers/of/base.c | 46 | ||||
-rw-r--r-- | drivers/of/platform.c | 18 |
3 files changed, 155 insertions, 18 deletions
diff --git a/drivers/of/address.c b/drivers/of/address.c index 007c5fd9d0..f0a74ec37c 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/base.c b/drivers/of/base.c index 80ceeab13b..9ede052274 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -78,36 +78,46 @@ static struct device_node *of_aliases; #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 -int of_n_addr_cells(struct device_node *np) +int of_bus_n_addr_cells(struct device_node *np) { - const __be32 *ip; + u32 cells; + + for (; np; np = np->parent) + if (!of_property_read_u32(np, "#address-cells", &cells)) + return cells; - do { - if (np->parent) - np = np->parent; - ip = of_get_property(np, "#address-cells", NULL); - if (ip) - return be32_to_cpup(ip); - } while (np->parent); /* No #address-cells property for the root node */ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; } + +int of_n_addr_cells(struct device_node *np) +{ + if (np->parent) + np = np->parent; + + return of_bus_n_addr_cells(np); +} EXPORT_SYMBOL(of_n_addr_cells); -int of_n_size_cells(struct device_node *np) +int of_bus_n_size_cells(struct device_node *np) { - const __be32 *ip; + u32 cells; + + for (; np; np = np->parent) + if (!of_property_read_u32(np, "#size-cells", &cells)) + return cells; - do { - if (np->parent) - np = np->parent; - ip = of_get_property(np, "#size-cells", NULL); - if (ip) - return be32_to_cpup(ip); - } while (np->parent); /* No #size-cells property for the root node */ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; } + +int of_n_size_cells(struct device_node *np) +{ + if (np->parent) + np = np->parent; + + return of_bus_n_size_cells(np); +} EXPORT_SYMBOL(of_n_size_cells); struct property *of_find_property(const struct device_node *np, diff --git a/drivers/of/platform.c b/drivers/of/platform.c index d3795d799a..b1a7eb6730 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", |