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