summaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2020-01-15 07:58:30 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2020-01-15 07:58:30 +0100
commit56c313fe1751756ba978824798f61b4abe6ac49c (patch)
tree9e98f6bee10468f8b58667e41d2f3dc3e842477a /drivers/of
parent38188906dce22189462cea0b23e67fd122e22dea (diff)
parent184050d9972b37557cdff40805ee04582c8e54e6 (diff)
downloadbarebox-56c313fe1751756ba978824798f61b4abe6ac49c.tar.gz
barebox-56c313fe1751756ba978824798f61b4abe6ac49c.tar.xz
Merge branch 'for-next/rpi'
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/address.c109
-rw-r--r--drivers/of/base.c46
-rw-r--r--drivers/of/platform.c18
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",