1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2021 Mark Kettenis <kettenis@openbsd.org>
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 
15 struct sandbox_iommu_priv {
16 	struct lmb lmb;
17 };
18 
sandbox_iommu_map(struct udevice * dev,void * addr,size_t size)19 static 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 
sandbox_iommu_unmap(struct udevice * dev,dma_addr_t addr,size_t size)35 static 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 
49 static struct iommu_ops sandbox_iommu_ops = {
50 	.map = sandbox_iommu_map,
51 	.unmap = sandbox_iommu_unmap,
52 };
53 
sandbox_iommu_probe(struct udevice * dev)54 static 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 
64 static const struct udevice_id sandbox_iommu_ids[] = {
65 	{ .compatible = "sandbox,iommu" },
66 	{ /* sentinel */ }
67 };
68 
69 U_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