Lines Matching +full:iommu +full:- +full:base
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Unisoc IOMMU driver
11 #include <linux/dma-mapping.h>
13 #include <linux/iommu.h>
52 * struct sprd_iommu_device - high-level sprd IOMMU device representation,
55 * @ver: sprd IOMMU IP version
56 * @prot_page_va: protect page base virtual address
57 * @prot_page_pa: protect page base physical address, data would be
59 * @base: mapped base address for accessing registers
61 * @iommu: IOMMU core representation
62 * @group: IOMMU group
63 * @eb: gate clock which controls IOMMU access
70 void __iomem *base; member
72 struct iommu_device iommu; member
79 u32 *pgt_va; /* page table virtual address base */
80 dma_addr_t pgt_pa; /* page table physical address base */
94 writel_relaxed(val, sdev->base + reg); in sprd_iommu_write()
100 return readl_relaxed(sdev->base + reg); in sprd_iommu_read()
124 return -EINVAL; in sprd_iommu_get_version()
131 return ((domain->geometry.aperture_end - in sprd_iommu_pgt_size()
132 domain->geometry.aperture_start + 1) >> in sprd_iommu_pgt_size()
144 spin_lock_init(&dom->pgtlock); in sprd_iommu_domain_alloc_paging()
146 dom->domain.pgsize_bitmap = SPRD_IOMMU_PAGE_SIZE; in sprd_iommu_domain_alloc_paging()
148 dom->domain.geometry.aperture_start = 0; in sprd_iommu_domain_alloc_paging()
149 dom->domain.geometry.aperture_end = SZ_256M - 1; in sprd_iommu_domain_alloc_paging()
150 dom->domain.geometry.force_aperture = true; in sprd_iommu_domain_alloc_paging()
152 return &dom->domain; in sprd_iommu_domain_alloc_paging()
157 struct sprd_iommu_device *sdev = dom->sdev; in sprd_iommu_first_vpn()
161 if (sdev->ver == SPRD_IOMMU_EX) in sprd_iommu_first_vpn()
166 val = dom->domain.geometry.aperture_start >> SPRD_IOMMU_PAGE_SHIFT; in sprd_iommu_first_vpn()
172 struct sprd_iommu_device *sdev = dom->sdev; in sprd_iommu_vpn_range()
176 if (sdev->ver == SPRD_IOMMU_EX) in sprd_iommu_vpn_range()
181 val = (dom->domain.geometry.aperture_end - in sprd_iommu_vpn_range()
182 dom->domain.geometry.aperture_start) >> SPRD_IOMMU_PAGE_SHIFT; in sprd_iommu_vpn_range()
188 u32 val = dom->pgt_pa >> SPRD_IOMMU_PAGE_SHIFT; in sprd_iommu_first_ppn()
189 struct sprd_iommu_device *sdev = dom->sdev; in sprd_iommu_first_ppn()
192 if (sdev->ver == SPRD_IOMMU_EX) in sprd_iommu_first_ppn()
202 u32 val = sdev->prot_page_pa >> SPRD_IOMMU_PAGE_SHIFT; in sprd_iommu_default_ppn()
204 if (sdev->ver == SPRD_IOMMU_EX) { in sprd_iommu_default_ppn()
206 } else if (sdev->ver == SPRD_IOMMU_VAU) { in sprd_iommu_default_ppn()
217 if (sdev->ver == SPRD_IOMMU_EX) in sprd_iommu_hw_en()
232 if (!dom->sdev) in sprd_iommu_cleanup()
235 pgt_size = sprd_iommu_pgt_size(&dom->domain); in sprd_iommu_cleanup()
236 dma_free_coherent(dom->sdev->dev, pgt_size, dom->pgt_va, dom->pgt_pa); in sprd_iommu_cleanup()
237 sprd_iommu_hw_en(dom->sdev, false); in sprd_iommu_cleanup()
238 dom->sdev = NULL; in sprd_iommu_cleanup()
257 if (sdev->dom == dom) in sprd_iommu_attach_device()
261 if (!dom->pgt_va) { in sprd_iommu_attach_device()
262 dom->pgt_va = dma_alloc_coherent(sdev->dev, pgt_size, &dom->pgt_pa, GFP_KERNEL); in sprd_iommu_attach_device()
263 if (!dom->pgt_va) in sprd_iommu_attach_device()
264 return -ENOMEM; in sprd_iommu_attach_device()
266 dom->sdev = sdev; in sprd_iommu_attach_device()
269 sdev->dom = dom; in sprd_iommu_attach_device()
272 * One sprd IOMMU serves one client device only, disabled it before in sprd_iommu_attach_device()
296 unsigned long start = domain->geometry.aperture_start; in sprd_iommu_map()
297 unsigned long end = domain->geometry.aperture_end; in sprd_iommu_map()
299 if (!dom->sdev) { in sprd_iommu_map()
301 return -EINVAL; in sprd_iommu_map()
305 dev_err(dom->sdev->dev, "(iova(0x%lx) + size(%zx)) are not in the range!\n", in sprd_iommu_map()
307 return -EINVAL; in sprd_iommu_map()
310 pgt_base_iova = dom->pgt_va + ((iova - start) >> SPRD_IOMMU_PAGE_SHIFT); in sprd_iommu_map()
312 spin_lock_irqsave(&dom->pgtlock, flags); in sprd_iommu_map()
317 spin_unlock_irqrestore(&dom->pgtlock, flags); in sprd_iommu_map()
331 unsigned long start = domain->geometry.aperture_start; in sprd_iommu_unmap()
332 unsigned long end = domain->geometry.aperture_end; in sprd_iommu_unmap()
337 pgt_base_iova = dom->pgt_va + ((iova - start) >> SPRD_IOMMU_PAGE_SHIFT); in sprd_iommu_unmap()
339 spin_lock_irqsave(&dom->pgtlock, flags); in sprd_iommu_unmap()
341 spin_unlock_irqrestore(&dom->pgtlock, flags); in sprd_iommu_unmap()
352 if (dom->sdev->ver == SPRD_IOMMU_EX) in sprd_iommu_sync_map()
357 /* clear IOMMU TLB buffer after page table updated */ in sprd_iommu_sync_map()
358 sprd_iommu_write(dom->sdev, reg, 0xffffffff); in sprd_iommu_sync_map()
374 unsigned long start = domain->geometry.aperture_start; in sprd_iommu_iova_to_phys()
375 unsigned long end = domain->geometry.aperture_end; in sprd_iommu_iova_to_phys()
380 spin_lock_irqsave(&dom->pgtlock, flags); in sprd_iommu_iova_to_phys()
381 pa = *(dom->pgt_va + ((iova - start) >> SPRD_IOMMU_PAGE_SHIFT)); in sprd_iommu_iova_to_phys()
382 pa = (pa << SPRD_IOMMU_PAGE_SHIFT) + ((iova - start) & (SPRD_IOMMU_PAGE_SIZE - 1)); in sprd_iommu_iova_to_phys()
383 spin_unlock_irqrestore(&dom->pgtlock, flags); in sprd_iommu_iova_to_phys()
392 return &sdev->iommu; in sprd_iommu_probe_device()
401 pdev = of_find_device_by_node(args->np); in sprd_iommu_of_xlate()
428 { .compatible = "sprd,iommu-v1" },
442 eb = devm_clk_get_optional(sdev->dev, NULL); in sprd_iommu_clk_enable()
449 sdev->eb = eb; in sprd_iommu_clk_enable()
455 if (sdev->eb) in sprd_iommu_clk_disable()
456 clk_disable_unprepare(sdev->eb); in sprd_iommu_clk_disable()
462 struct device *dev = &pdev->dev; in sprd_iommu_probe()
463 void __iomem *base; in sprd_iommu_probe() local
468 return -ENOMEM; in sprd_iommu_probe()
470 base = devm_platform_ioremap_resource(pdev, 0); in sprd_iommu_probe()
471 if (IS_ERR(base)) { in sprd_iommu_probe()
473 return PTR_ERR(base); in sprd_iommu_probe()
475 sdev->base = base; in sprd_iommu_probe()
477 sdev->prot_page_va = dma_alloc_coherent(dev, SPRD_IOMMU_PAGE_SIZE, in sprd_iommu_probe()
478 &sdev->prot_page_pa, GFP_KERNEL); in sprd_iommu_probe()
479 if (!sdev->prot_page_va) in sprd_iommu_probe()
480 return -ENOMEM; in sprd_iommu_probe()
483 sdev->dev = dev; in sprd_iommu_probe()
485 ret = iommu_device_sysfs_add(&sdev->iommu, dev, NULL, dev_name(dev)); in sprd_iommu_probe()
489 ret = iommu_device_register(&sdev->iommu, &sprd_iommu_ops, dev); in sprd_iommu_probe()
499 dev_err(dev, "IOMMU version(%d) is invalid.\n", ret); in sprd_iommu_probe()
502 sdev->ver = ret; in sprd_iommu_probe()
509 iommu_device_unregister(&sdev->iommu); in sprd_iommu_probe()
511 iommu_device_sysfs_remove(&sdev->iommu); in sprd_iommu_probe()
513 dma_free_coherent(sdev->dev, SPRD_IOMMU_PAGE_SIZE, sdev->prot_page_va, sdev->prot_page_pa); in sprd_iommu_probe()
521 dma_free_coherent(sdev->dev, SPRD_IOMMU_PAGE_SIZE, sdev->prot_page_va, sdev->prot_page_pa); in sprd_iommu_remove()
524 iommu_device_sysfs_remove(&sdev->iommu); in sprd_iommu_remove()
525 iommu_device_unregister(&sdev->iommu); in sprd_iommu_remove()
530 .name = "sprd-iommu",
539 MODULE_DESCRIPTION("IOMMU driver for Unisoc SoCs");
540 MODULE_ALIAS("platform:sprd-iommu");