[PATCH] iommu: Add RISC-V IOMMU driver
Anirudh Srinivasan via U-Boot <[email protected]> Mon, 03 Aug 2026 15:06:12 -0500
| Newsgroups | gmane.comp.boot-loaders.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]> --- 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..9e41a397250 --- /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 10000000 +#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]>