diff options
-rw-r--r-- | drivers/iommu/tegra-smmu.c | 61 |
1 files changed, 36 insertions, 25 deletions
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 87a719f4adfb..2fecbe7fd7fd 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -293,7 +293,11 @@ struct smmu_debugfs_info { * Per SMMU device - IOMMU device */ struct smmu_device { - void __iomem *regs[NUM_SMMU_REG_BANKS]; + void __iomem *regbase; /* register offset base */ + void __iomem **regs; /* register block start address array */ + void __iomem **rege; /* register block end address array */ + int nregs; /* number of register blocks */ + unsigned long iovmm_base; /* remappable base address */ unsigned long page_count; /* total remappable size */ spinlock_t lock; @@ -325,35 +329,33 @@ static struct smmu_device *smmu_handle; /* unique for a system */ */ static inline u32 smmu_read(struct smmu_device *smmu, size_t offs) { - BUG_ON(offs < 0x10); - if (offs < 0x3c) - return readl(smmu->regs[0] + offs - 0x10); - BUG_ON(offs < 0x1f0); - if (offs < 0x200) - return readl(smmu->regs[1] + offs - 0x1f0); - BUG_ON(offs < 0x228); - if (offs < 0x284) - return readl(smmu->regs[2] + offs - 0x228); + int i; + + for (i = 0; i < smmu->nregs; i++) { + void __iomem *addr = smmu->regbase + offs; + + BUG_ON(addr < smmu->regs[i]); + if (addr <= smmu->rege[i]) + return readl(addr); + } + BUG(); } static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs) { - BUG_ON(offs < 0x10); - if (offs < 0x3c) { - writel(val, smmu->regs[0] + offs - 0x10); - return; - } - BUG_ON(offs < 0x1f0); - if (offs < 0x200) { - writel(val, smmu->regs[1] + offs - 0x1f0); - return; - } - BUG_ON(offs < 0x228); - if (offs < 0x284) { - writel(val, smmu->regs[2] + offs - 0x228); - return; + int i; + + for (i = 0; i < smmu->nregs; i++) { + void __iomem *addr = smmu->regbase + offs; + + BUG_ON(addr < smmu->regs[i]); + if (addr <= smmu->rege[i]) { + writel(val, addr); + return; + } } + BUG(); } @@ -1170,7 +1172,13 @@ static int tegra_smmu_probe(struct platform_device *pdev) return -ENOMEM; } - for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) { + smmu->nregs = pdev->num_resources; + smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs), + GFP_KERNEL); + smmu->rege = smmu->regs + smmu->nregs; + if (!smmu->regs) + return -ENOMEM; + for (i = 0; i < smmu->nregs; i++) { struct resource *res; res = platform_get_resource(pdev, IORESOURCE_MEM, i); @@ -1179,7 +1187,10 @@ static int tegra_smmu_probe(struct platform_device *pdev) smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res); if (!smmu->regs[i]) return -EBUSY; + smmu->rege[i] = smmu->regs[i] + resource_size(res) - 1; } + /* Same as "mc" 1st regiter block start address */ + smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK); err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size); if (err) |