diff options
Diffstat (limited to 'kernel/drivers/iommu/omap-iommu.c')
-rw-r--r-- | kernel/drivers/iommu/omap-iommu.c | 256 |
1 files changed, 75 insertions, 181 deletions
diff --git a/kernel/drivers/iommu/omap-iommu.c b/kernel/drivers/iommu/omap-iommu.c index a22c33d6a..3dc5b65f3 100644 --- a/kernel/drivers/iommu/omap-iommu.c +++ b/kernel/drivers/iommu/omap-iommu.c @@ -12,7 +12,6 @@ */ #include <linux/err.h> -#include <linux/module.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/ioport.h> @@ -27,6 +26,8 @@ #include <linux/of_iommu.h> #include <linux/of_irq.h> #include <linux/of_platform.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> #include <asm/cacheflush.h> @@ -38,11 +39,6 @@ #define to_iommu(dev) \ ((struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))) -#define for_each_iotlb_cr(obj, n, __i, cr) \ - for (__i = 0; \ - (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true); \ - __i++) - /* bitmap of the page sizes currently supported */ #define OMAP_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M) @@ -72,11 +68,6 @@ struct omap_iommu_domain { #define MMU_LOCK_VICT(x) \ ((x & MMU_LOCK_VICT_MASK) >> MMU_LOCK_VICT_SHIFT) -struct iotlb_lock { - short base; - short vict; -}; - static struct platform_driver omap_iommu_driver; static struct kmem_cache *iopte_cachep; @@ -123,6 +114,18 @@ void omap_iommu_restore_ctx(struct device *dev) } EXPORT_SYMBOL_GPL(omap_iommu_restore_ctx); +static void dra7_cfg_dspsys_mmu(struct omap_iommu *obj, bool enable) +{ + u32 val, mask; + + if (!obj->syscfg) + return; + + mask = (1 << (obj->id * DSP_SYS_MMU_CONFIG_EN_SHIFT)); + val = enable ? mask : 0; + regmap_update_bits(obj->syscfg, DSP_SYS_MMU_CONFIG, mask, val); +} + static void __iommu_set_twl(struct omap_iommu *obj, bool on) { u32 l = iommu_read_reg(obj, MMU_CNTL); @@ -158,6 +161,8 @@ static int omap2_iommu_enable(struct omap_iommu *obj) iommu_write_reg(obj, pa, MMU_TTB); + dra7_cfg_dspsys_mmu(obj, true); + if (obj->has_bus_err_back) iommu_write_reg(obj, MMU_GP_REG_BUS_ERR_BACK_EN, MMU_GP_REG); @@ -172,6 +177,7 @@ static void omap2_iommu_disable(struct omap_iommu *obj) l &= ~MMU_CNTL_MASK; iommu_write_reg(obj, l, MMU_CNTL); + dra7_cfg_dspsys_mmu(obj, false); dev_dbg(obj->dev, "%s is shutting down\n", obj->name); } @@ -213,14 +219,6 @@ static void iommu_disable(struct omap_iommu *obj) /* * TLB operations */ -static inline int iotlb_cr_valid(struct cr_regs *cr) -{ - if (!cr) - return -EINVAL; - - return cr->cam & MMU_CAM_V; -} - static u32 iotlb_cr_to_virt(struct cr_regs *cr) { u32 page_size = cr->cam & MMU_CAM_PGSZ_MASK; @@ -260,7 +258,7 @@ static u32 iommu_report_fault(struct omap_iommu *obj, u32 *da) return status; } -static void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l) +void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l) { u32 val; @@ -268,10 +266,9 @@ static void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l) l->base = MMU_LOCK_BASE(val); l->vict = MMU_LOCK_VICT(val); - } -static void iotlb_lock_set(struct omap_iommu *obj, struct iotlb_lock *l) +void iotlb_lock_set(struct omap_iommu *obj, struct iotlb_lock *l) { u32 val; @@ -297,7 +294,7 @@ static void iotlb_load_cr(struct omap_iommu *obj, struct cr_regs *cr) } /* only used in iotlb iteration for-loop */ -static struct cr_regs __iotlb_read_cr(struct omap_iommu *obj, int n) +struct cr_regs __iotlb_read_cr(struct omap_iommu *obj, int n) { struct cr_regs cr; struct iotlb_lock l; @@ -468,129 +465,6 @@ static void flush_iotlb_all(struct omap_iommu *obj) pm_runtime_put_sync(obj->dev); } -#ifdef CONFIG_OMAP_IOMMU_DEBUG - -#define pr_reg(name) \ - do { \ - ssize_t bytes; \ - const char *str = "%20s: %08x\n"; \ - const int maxcol = 32; \ - bytes = snprintf(p, maxcol, str, __stringify(name), \ - iommu_read_reg(obj, MMU_##name)); \ - p += bytes; \ - len -= bytes; \ - if (len < maxcol) \ - goto out; \ - } while (0) - -static ssize_t -omap2_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len) -{ - char *p = buf; - - pr_reg(REVISION); - pr_reg(IRQSTATUS); - pr_reg(IRQENABLE); - pr_reg(WALKING_ST); - pr_reg(CNTL); - pr_reg(FAULT_AD); - pr_reg(TTB); - pr_reg(LOCK); - pr_reg(LD_TLB); - pr_reg(CAM); - pr_reg(RAM); - pr_reg(GFLUSH); - pr_reg(FLUSH_ENTRY); - pr_reg(READ_CAM); - pr_reg(READ_RAM); - pr_reg(EMU_FAULT_AD); -out: - return p - buf; -} - -ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t bytes) -{ - if (!obj || !buf) - return -EINVAL; - - pm_runtime_get_sync(obj->dev); - - bytes = omap2_iommu_dump_ctx(obj, buf, bytes); - - pm_runtime_put_sync(obj->dev); - - return bytes; -} - -static int -__dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num) -{ - int i; - struct iotlb_lock saved; - struct cr_regs tmp; - struct cr_regs *p = crs; - - pm_runtime_get_sync(obj->dev); - iotlb_lock_get(obj, &saved); - - for_each_iotlb_cr(obj, num, i, tmp) { - if (!iotlb_cr_valid(&tmp)) - continue; - *p++ = tmp; - } - - iotlb_lock_set(obj, &saved); - pm_runtime_put_sync(obj->dev); - - return p - crs; -} - -/** - * iotlb_dump_cr - Dump an iommu tlb entry into buf - * @obj: target iommu - * @cr: contents of cam and ram register - * @buf: output buffer - **/ -static ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr, - char *buf) -{ - char *p = buf; - - /* FIXME: Need more detail analysis of cam/ram */ - p += sprintf(p, "%08x %08x %01x\n", cr->cam, cr->ram, - (cr->cam & MMU_CAM_P) ? 1 : 0); - - return p - buf; -} - -/** - * omap_dump_tlb_entries - dump cr arrays to given buffer - * @obj: target iommu - * @buf: output buffer - **/ -size_t omap_dump_tlb_entries(struct omap_iommu *obj, char *buf, ssize_t bytes) -{ - int i, num; - struct cr_regs *cr; - char *p = buf; - - num = bytes / sizeof(*cr); - num = min(obj->nr_tlb_entries, num); - - cr = kcalloc(num, sizeof(*cr), GFP_KERNEL); - if (!cr) - return 0; - - num = __dump_tlb_entries(obj, cr, num); - for (i = 0; i < num; i++) - p += iotlb_dump_cr(obj, cr + i, p); - kfree(cr); - - return p - buf; -} - -#endif /* CONFIG_OMAP_IOMMU_DEBUG */ - /* * H/W pagetable operations */ @@ -930,14 +804,14 @@ static irqreturn_t iommu_fault_handler(int irq, void *data) if (!iopgd_is_table(*iopgd)) { dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:px%08x\n", - obj->name, errs, da, iopgd, *iopgd); + obj->name, errs, da, iopgd, *iopgd); return IRQ_NONE; } iopte = iopte_offset(iopgd, da); dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x pte:0x%p *pte:0x%08x\n", - obj->name, errs, da, iopgd, *iopgd, iopte, *iopte); + obj->name, errs, da, iopgd, *iopgd, iopte, *iopte); return IRQ_NONE; } @@ -963,9 +837,8 @@ static struct omap_iommu *omap_iommu_attach(const char *name, u32 *iopgd) struct device *dev; struct omap_iommu *obj; - dev = driver_find_device(&omap_iommu_driver.driver, NULL, - (void *)name, - device_match_by_alias); + dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name, + device_match_by_alias); if (!dev) return ERR_PTR(-ENODEV); @@ -1008,6 +881,42 @@ static void omap_iommu_detach(struct omap_iommu *obj) dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name); } +static int omap_iommu_dra7_get_dsp_system_cfg(struct platform_device *pdev, + struct omap_iommu *obj) +{ + struct device_node *np = pdev->dev.of_node; + int ret; + + if (!of_device_is_compatible(np, "ti,dra7-dsp-iommu")) + return 0; + + if (!of_property_read_bool(np, "ti,syscon-mmuconfig")) { + dev_err(&pdev->dev, "ti,syscon-mmuconfig property is missing\n"); + return -EINVAL; + } + + obj->syscfg = + syscon_regmap_lookup_by_phandle(np, "ti,syscon-mmuconfig"); + if (IS_ERR(obj->syscfg)) { + /* can fail with -EPROBE_DEFER */ + ret = PTR_ERR(obj->syscfg); + return ret; + } + + if (of_property_read_u32_index(np, "ti,syscon-mmuconfig", 1, + &obj->id)) { + dev_err(&pdev->dev, "couldn't get the IOMMU instance id within subsystem\n"); + return -EINVAL; + } + + if (obj->id != 0 && obj->id != 1) { + dev_err(&pdev->dev, "invalid IOMMU instance id\n"); + return -EINVAL; + } + + return 0; +} + /* * OMAP Device MMU(IOMMU) detection */ @@ -1051,6 +960,10 @@ static int omap_iommu_probe(struct platform_device *pdev) if (IS_ERR(obj->regbase)) return PTR_ERR(obj->regbase); + err = omap_iommu_dra7_get_dsp_system_cfg(pdev, obj); + if (err) + return err; + irq = platform_get_irq(pdev, 0); if (irq < 0) return -ENODEV; @@ -1087,9 +1000,9 @@ static const struct of_device_id omap_iommu_of_match[] = { { .compatible = "ti,omap2-iommu" }, { .compatible = "ti,omap4-iommu" }, { .compatible = "ti,dra7-iommu" }, + { .compatible = "ti,dra7-dsp-iommu" }, {}, }; -MODULE_DEVICE_TABLE(of, omap_iommu_of_match); static struct platform_driver omap_iommu_driver = { .probe = omap_iommu_probe, @@ -1121,7 +1034,7 @@ static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, int pgsz) } static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, - phys_addr_t pa, size_t bytes, int prot) + phys_addr_t pa, size_t bytes, int prot) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); struct omap_iommu *oiommu = omap_domain->iommu_dev; @@ -1148,7 +1061,7 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, } static size_t omap_iommu_unmap(struct iommu_domain *domain, unsigned long da, - size_t size) + size_t size) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); struct omap_iommu *oiommu = omap_domain->iommu_dev; @@ -1199,7 +1112,7 @@ out: } static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain, - struct device *dev) + struct device *dev) { struct omap_iommu *oiommu = dev_to_omap_iommu(dev); struct omap_iommu_arch_data *arch_data = dev->archdata.iommu; @@ -1220,7 +1133,7 @@ static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain, } static void omap_iommu_detach_dev(struct iommu_domain *domain, - struct device *dev) + struct device *dev) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); @@ -1237,16 +1150,12 @@ static struct iommu_domain *omap_iommu_domain_alloc(unsigned type) return NULL; omap_domain = kzalloc(sizeof(*omap_domain), GFP_KERNEL); - if (!omap_domain) { - pr_err("kzalloc failed\n"); + if (!omap_domain) goto out; - } omap_domain->pgtable = kzalloc(IOPGD_TABLE_SIZE, GFP_KERNEL); - if (!omap_domain->pgtable) { - pr_err("kzalloc failed\n"); + if (!omap_domain->pgtable) goto fail_nomem; - } /* * should never fail, but please keep this around to ensure @@ -1285,7 +1194,7 @@ static void omap_iommu_domain_free(struct iommu_domain *domain) } static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain, - dma_addr_t da) + dma_addr_t da) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); struct omap_iommu *oiommu = omap_domain->iommu_dev; @@ -1302,7 +1211,7 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain, ret = omap_iommu_translate(*pte, da, IOLARGE_MASK); else dev_err(dev, "bogus pte 0x%x, da 0x%llx", *pte, - (unsigned long long)da); + (unsigned long long)da); } else { if (iopgd_is_section(*pgd)) ret = omap_iommu_translate(*pgd, da, IOSECTION_MASK); @@ -1310,7 +1219,7 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain, ret = omap_iommu_translate(*pgd, da, IOSUPER_MASK); else dev_err(dev, "bogus pgd 0x%x, da 0x%llx", *pgd, - (unsigned long long)da); + (unsigned long long)da); } return ret; @@ -1405,20 +1314,5 @@ static int __init omap_iommu_init(void) return platform_driver_register(&omap_iommu_driver); } -/* must be ready before omap3isp is probed */ subsys_initcall(omap_iommu_init); - -static void __exit omap_iommu_exit(void) -{ - kmem_cache_destroy(iopte_cachep); - - platform_driver_unregister(&omap_iommu_driver); - - omap_iommu_debugfs_exit(); -} -module_exit(omap_iommu_exit); - -MODULE_DESCRIPTION("omap iommu: tlb and pagetable primitives"); -MODULE_ALIAS("platform:omap-iommu"); -MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi"); -MODULE_LICENSE("GPL v2"); +/* must be ready before omap3isp is probed */ |