1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2021 Mark Kettenis <kettenis@openbsd.org> 4 */ 5 6#include <dm.h> 7#include <iommu.h> 8#include <lmb.h> 9#include <asm/io.h> 10#include <linux/sizes.h> 11 12#define IOMMU_PAGE_SIZE SZ_4K 13 14struct sandbox_iommu_priv { 15 struct lmb lmb; 16}; 17 18static dma_addr_t sandbox_iommu_map(struct udevice *dev, void *addr, 19 size_t size) 20{ 21 struct sandbox_iommu_priv *priv = dev_get_priv(dev); 22 phys_addr_t paddr, dva; 23 phys_size_t psize, off; 24 25 paddr = ALIGN_DOWN(virt_to_phys(addr), IOMMU_PAGE_SIZE); 26 off = virt_to_phys(addr) - paddr; 27 psize = ALIGN(size + off, IOMMU_PAGE_SIZE); 28 29 dva = lmb_alloc(&priv->lmb, psize, IOMMU_PAGE_SIZE); 30 31 return dva + off; 32} 33 34static void sandbox_iommu_unmap(struct udevice *dev, dma_addr_t addr, 35 size_t size) 36{ 37 struct sandbox_iommu_priv *priv = dev_get_priv(dev); 38 phys_addr_t dva; 39 phys_size_t psize; 40 41 dva = ALIGN_DOWN(addr, IOMMU_PAGE_SIZE); 42 psize = size + (addr - dva); 43 psize = ALIGN(psize, IOMMU_PAGE_SIZE); 44 45 lmb_free(&priv->lmb, dva, psize); 46} 47 48static struct iommu_ops sandbox_iommu_ops = { 49 .map = sandbox_iommu_map, 50 .unmap = sandbox_iommu_unmap, 51}; 52 53static int sandbox_iommu_probe(struct udevice *dev) 54{ 55 struct sandbox_iommu_priv *priv = dev_get_priv(dev); 56 57 lmb_init(&priv->lmb); 58 lmb_add(&priv->lmb, 0x89abc000, SZ_16K); 59 60 return 0; 61} 62 63static const struct udevice_id sandbox_iommu_ids[] = { 64 { .compatible = "sandbox,iommu" }, 65 { /* sentinel */ } 66}; 67 68U_BOOT_DRIVER(sandbox_iommu) = { 69 .name = "sandbox_iommu", 70 .id = UCLASS_IOMMU, 71 .of_match = sandbox_iommu_ids, 72 .priv_auto = sizeof(struct sandbox_iommu_priv), 73 .ops = &sandbox_iommu_ops, 74 .probe = sandbox_iommu_probe, 75}; 76