+/*
+ * The 'dma-ranges' device tree property for shared dma memory does not seem
+ * to be fully supported for coherent memory. Therefor we apply the DMA range
+ * offset ourselves.
+ */
+static dma_addr_t ethosu_buffer_dma_ranges(struct device *dev,
+ dma_addr_t dma_addr,
+ size_t dma_buf_size)
+{
+ struct device_node *node = dev->of_node;
+ const __be32 *ranges;
+ int len;
+ int naddr;
+ int nsize;
+ int inc;
+ int i;
+
+ if (!node)
+ return dma_addr;
+
+ /* Get the #address-cells and #size-cells properties */
+ naddr = of_n_addr_cells(node);
+ nsize = of_n_size_cells(node);
+
+ /* Read the 'dma-ranges' property */
+ ranges = of_get_property(node, "dma-ranges", &len);
+ if (!ranges || len <= 0)
+ return dma_addr;
+
+ dev_dbg(dev, "ranges=%p, len=%d, naddr=%d, nsize=%d\n",
+ ranges, len, naddr, nsize);
+
+ len /= sizeof(*ranges);
+ inc = naddr + naddr + nsize;
+
+ for (i = 0; (i + inc) <= len; i += inc) {
+ dma_addr_t daddr;
+ dma_addr_t paddr;
+ dma_addr_t size;
+
+ daddr = of_read_number(&ranges[i], naddr);
+ paddr = of_read_number(&ranges[i + naddr], naddr);
+ size = of_read_number(&ranges[i + naddr + naddr], nsize);
+
+ dev_dbg(dev, "daddr=0x%llx, paddr=0x%llx, size=0x%llx\n",
+ daddr, paddr, size);
+
+ if (dma_addr >= paddr &&
+ (dma_addr + dma_buf_size) < (paddr + size))
+ return dma_addr + daddr - paddr;
+ }
+
+ return dma_addr;
+}