diff options
Diffstat (limited to 'drivers/iommu/sandbox_iommu.c')
-rw-r--r-- | drivers/iommu/sandbox_iommu.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/drivers/iommu/sandbox_iommu.c b/drivers/iommu/sandbox_iommu.c index c8161a40aef..6ceb7fd5ec3 100644 --- a/drivers/iommu/sandbox_iommu.c +++ b/drivers/iommu/sandbox_iommu.c @@ -5,6 +5,61 @@ #include <common.h> #include <dm.h> +#include <iommu.h> +#include <lmb.h> +#include <asm/io.h> +#include <linux/sizes.h> + +#define IOMMU_PAGE_SIZE SZ_4K + +struct sandbox_iommu_priv { + struct lmb lmb; +}; + +static dma_addr_t sandbox_iommu_map(struct udevice *dev, void *addr, + size_t size) +{ + struct sandbox_iommu_priv *priv = dev_get_priv(dev); + phys_addr_t paddr, dva; + phys_size_t psize, off; + + paddr = ALIGN_DOWN(virt_to_phys(addr), IOMMU_PAGE_SIZE); + off = virt_to_phys(addr) - paddr; + psize = ALIGN(size + off, IOMMU_PAGE_SIZE); + + dva = lmb_alloc(&priv->lmb, psize, IOMMU_PAGE_SIZE); + + return dva + off; +} + +static void sandbox_iommu_unmap(struct udevice *dev, dma_addr_t addr, + size_t size) +{ + struct sandbox_iommu_priv *priv = dev_get_priv(dev); + phys_addr_t dva; + phys_size_t psize; + + dva = ALIGN_DOWN(addr, IOMMU_PAGE_SIZE); + psize = size + (addr - dva); + psize = ALIGN(psize, IOMMU_PAGE_SIZE); + + lmb_free(&priv->lmb, dva, psize); +} + +static struct iommu_ops sandbox_iommu_ops = { + .map = sandbox_iommu_map, + .unmap = sandbox_iommu_unmap, +}; + +static int sandbox_iommu_probe(struct udevice *dev) +{ + struct sandbox_iommu_priv *priv = dev_get_priv(dev); + + lmb_init(&priv->lmb); + lmb_add(&priv->lmb, 0x89abc000, SZ_16K); + + return 0; +} static const struct udevice_id sandbox_iommu_ids[] = { { .compatible = "sandbox,iommu" }, @@ -15,4 +70,7 @@ U_BOOT_DRIVER(sandbox_iommu) = { .name = "sandbox_iommu", .id = UCLASS_IOMMU, .of_match = sandbox_iommu_ids, + .priv_auto = sizeof(struct sandbox_iommu_priv), + .ops = &sandbox_iommu_ops, + .probe = sandbox_iommu_probe, }; |