[PATCH v2] iommu: Add RISC-V IOMMU driver

Anirudh Srinivasan <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
Adds a basic driver for IOMMUs that conform to the RISC-V IOMMU
specification. This driver sets up the IOMMU in bare mode so that
peripherals requiring DMA in U-Boot can function.

Signed-off-by: Anirudh Srinivasan <[email protected]>
---
Changes in v2:
- Changed DDTP read timeout to 3s from 10s
- Link to v1: https://patch.msgid.link/[email protected]
---
Hi,

This is a pre-requisite for U-Boot on Tenstorrent Atlantis. On this
platform, the IOMMU comes up in Off mode at boot, so this is needed for
SD and NVME boot to work in U-Boot.
---
 MAINTAINERS                 |  1 +
 drivers/iommu/Kconfig       |  8 +++++
 drivers/iommu/Makefile      |  1 +
 drivers/iommu/riscv_iommu.c | 82 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 92 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 289a45f47bb..a7b9e78cd79 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1583,6 +1583,7 @@ F:	arch/riscv/
 F:	cmd/riscv/
 F:	doc/arch/riscv.rst
 F:	doc/usage/sbi.rst
+F:	drivers/iommu/riscv_iommu.c
 F:	drivers/sysreset/sysreset_sbi.c
 F:	drivers/timer/andes_plmt_timer.c
 F:	drivers/timer/riscv_aclint_timer.c
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 2ba6d9c1362..24cfd823c0a 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -40,4 +40,12 @@ config QCOM_HYP_SMMU
 	  Say Y here to enable support for non-boot peripherals like USB by
 	  configuring identity mapped streams for them.
 
+config RISCV_IOMMU
+	bool "RISC-V IOMMU support"
+	depends on IOMMU && RISCV && 64BIT
+	help
+	  Enable support for the RISC-V IOMMU. This driver configures the IOMMU
+	  in Bare mode so that devices requiring DMA in U-Boot can work
+	  without additional configuration.
+
 endmenu
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 438cab8a7c4..caad566694a 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_IOMMU) += iommu-uclass.o
 obj-$(CONFIG_APPLE_DART) += apple_dart.o
 obj-$(CONFIG_SANDBOX) += sandbox_iommu.o
 obj-$(CONFIG_QCOM_HYP_SMMU) += qcom-hyp-smmu.o
+obj-$(CONFIG_RISCV_IOMMU) += riscv_iommu.o
diff --git a/drivers/iommu/riscv_iommu.c b/drivers/iommu/riscv_iommu.c
new file mode 100644
index 00000000000..ad5ee7c5088
--- /dev/null
+++ b/drivers/iommu/riscv_iommu.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 Tenstorrent
+ */
+
+#include <dm.h>
+#include <iommu.h>
+
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/iopoll.h>
+
+#define RISCV_IOMMU_REG_DDTP              0x10
+#define RISCV_IOMMU_DDTP_BUSY             BIT_ULL(4)
+#define RISCV_IOMMU_DDTP_TIMEOUT          30000000
+#define RISCV_IOMMU_DDTP_IOMMU_MODE_MASK  GENMASK_ULL(3, 0)
+#define RISCV_IOMMU_DDTP_IOMMU_MODE_OFF   0
+#define RISCV_IOMMU_DDTP_IOMMU_MODE_BARE  1
+
+static int riscv_iommu_probe(struct udevice *dev)
+{
+	void *base;
+	int ret;
+	u64 val;
+
+	base = dev_read_addr_ptr(dev);
+	if (!base)
+		return -EINVAL;
+
+	/* Read DDTP and check if busy bit is cleared */
+	ret = readq_poll_timeout(base + RISCV_IOMMU_REG_DDTP, val,
+				 !(val & RISCV_IOMMU_DDTP_BUSY),
+				 RISCV_IOMMU_DDTP_TIMEOUT);
+	if (ret)
+		return ret;
+
+	/*
+	 * Transitions to Bare mode from any mode other
+	 * than Off are undefined. Skip writing the register
+	 * when already in Bare mode.
+	 */
+	switch (val & RISCV_IOMMU_DDTP_IOMMU_MODE_MASK) {
+	case RISCV_IOMMU_DDTP_IOMMU_MODE_OFF:
+		break;
+	case RISCV_IOMMU_DDTP_IOMMU_MODE_BARE:
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	/* Enable Bare Mode */
+	val &= ~RISCV_IOMMU_DDTP_IOMMU_MODE_MASK;
+	val |= RISCV_IOMMU_DDTP_IOMMU_MODE_BARE;
+	writeq(val, base + RISCV_IOMMU_REG_DDTP);
+
+	/* Read DDTP to check if write was accepted */
+	ret = readq_poll_timeout(base + RISCV_IOMMU_REG_DDTP, val,
+				 !(val & RISCV_IOMMU_DDTP_BUSY),
+				 RISCV_IOMMU_DDTP_TIMEOUT);
+	if (ret)
+		return ret;
+
+	/* Check if DDTP value is Bare */
+	if ((val & RISCV_IOMMU_DDTP_IOMMU_MODE_MASK) !=
+	    RISCV_IOMMU_DDTP_IOMMU_MODE_BARE)
+		return -EIO;
+
+	return 0;
+}
+
+static const struct udevice_id riscv_iommu_ids[] = {
+	{ .compatible = "riscv,iommu" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(riscv_iommu) = {
+	.name = "riscv_iommu",
+	.id = UCLASS_IOMMU,
+	.of_match = riscv_iommu_ids,
+	.probe = riscv_iommu_probe,
+	.flags	= DM_FLAG_VITAL,
+};

---
base-commit: 5c215cb75c3723cbf77c36cbac3e60b001721c79
change-id: 20260803-riscv_iommu-697ed4fefd31

Best regards,
--  
Anirudh Srinivasan <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.