mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: Barebox List <barebox@lists.infradead.org>
Subject: [PATCH 04/10] of: Read dma_offset from device tree
Date: Fri, 20 Dec 2019 15:32:26 +0100	[thread overview]
Message-ID: <20191220143232.28354-5-s.hauer@pengutronix.de> (raw)
In-Reply-To: <20191220143232.28354-1-s.hauer@pengutronix.de>

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 4e12522a0a..2020f5b7b1 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 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",
diff --git a/include/of_address.h b/include/of_address.h
index ebf3ec2a24..350ecaec82 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
-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

  parent reply	other threads:[~2019-12-20 14:32 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
2019-12-20 14:32 ` [PATCH 01/10] usb: Make timeout unit clear Sascha Hauer
2019-12-20 14:32 ` [PATCH 02/10] of: Add of_bus_n_xxx_cells() Sascha Hauer
2019-12-20 14:32 ` [PATCH 03/10] device: Introduce dma_offset Sascha Hauer
2019-12-20 14:32 ` Sascha Hauer [this message]
2019-12-20 14:32 ` [PATCH 05/10] usb: Add usbroothubdes.h Sascha Hauer
2019-12-20 14:32 ` [PATCH 06/10] regulator: add function to get regulator by its name Sascha Hauer
2019-12-20 14:32 ` [PATCH 07/10] rpi: Enable USB Power domain during startup Sascha Hauer
2019-12-20 14:32 ` [PATCH 08/10] usb: Forward error code from usb_set_configuration Sascha Hauer
2019-12-20 14:32 ` [PATCH 09/10] usb: Add dwc2 host driver Sascha Hauer
2020-01-14 13:21   ` [RFC PATCH 0/7] usb: " Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 1/7] usb: dwc2: Add host controller driver Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 2/7] usb: dwc2: host: Handle dma mapping errors Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 3/7] usb: dwc2: Dynamic fifo size support from Linux Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 4/7] usb: dwc2: Rework roothub interface Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 5/7] HACK: usb: dwc2: Fix toggle reset Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 6/7] usb: dwc2: Rewrite dwc2_hc_init Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 7/7] usb: dwc2: Read dr_mode from device tree Jules Maselbas
2020-01-14 14:27     ` [RFC PATCH 0/7] usb: dwc2 host driver Sascha Hauer
2020-01-14 17:12       ` Jules Maselbas
2020-01-16  6:50         ` Sascha Hauer
2020-01-16 17:25           ` Jules Maselbas
2020-01-21 13:32             ` Michael Grzeschik
2019-12-20 14:32 ` [PATCH 10/10] ARM: rpi_defconfig: Enable networking support Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191220143232.28354-5-s.hauer@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox