aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/tegra-smmu.c
diff options
context:
space:
mode:
authorHiroshi Doyu <hdoyu@nvidia.com>2013-01-31 03:14:10 -0500
committerJoerg Roedel <joro@8bytes.org>2013-02-05 08:18:01 -0500
commita6870e928d1b2a97d95e7bf1aaefd3da34b83a85 (patch)
treeedb13665e5cbfe256fd5dc52bdfc55d15ec26839 /drivers/iommu/tegra-smmu.c
parent0fde671b81d406a59ae21f35f121851509c3b138 (diff)
iommu/tegra: smmu: Support variable MMIO ranges/blocks
Presently SMMU registers are located in discontiguous 3 blocks. They are interleaved by MC registers. Ideally SMMU register blocks should be in an independent one block, but it is too late to change this H/W design. In the future Tegra chips over some generations, it is expected that some of register block "size" can be extended towards the end and also more new register blocks will be added at most a few blocks. The starting address of each existing block won't change. This patch allocates multiple number of register blocks dynamically based on the info passed from DT. Those ranges are verified in the accessors{read,write}. This may sacrifice some performance because a new accessors prevents compiler optimization of a fixed size register offset calculation. Since SMMU register accesses are not so frequent, this would be acceptable. This patch is necessary to unify "tegra-smmu.ko" over some Tegra SoC generations. Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com> Reviewed-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Joerg Roedel <joro@8bytes.org>
Diffstat (limited to 'drivers/iommu/tegra-smmu.c')
-rw-r--r--drivers/iommu/tegra-smmu.c61
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 {
293 * Per SMMU device - IOMMU device 293 * Per SMMU device - IOMMU device
294 */ 294 */
295struct smmu_device { 295struct smmu_device {
296 void __iomem *regs[NUM_SMMU_REG_BANKS]; 296 void __iomem *regbase; /* register offset base */
297 void __iomem **regs; /* register block start address array */
298 void __iomem **rege; /* register block end address array */
299 int nregs; /* number of register blocks */
300
297 unsigned long iovmm_base; /* remappable base address */ 301 unsigned long iovmm_base; /* remappable base address */
298 unsigned long page_count; /* total remappable size */ 302 unsigned long page_count; /* total remappable size */
299 spinlock_t lock; 303 spinlock_t lock;
@@ -325,35 +329,33 @@ static struct smmu_device *smmu_handle; /* unique for a system */
325 */ 329 */
326static inline u32 smmu_read(struct smmu_device *smmu, size_t offs) 330static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
327{ 331{
328 BUG_ON(offs < 0x10); 332 int i;
329 if (offs < 0x3c) 333
330 return readl(smmu->regs[0] + offs - 0x10); 334 for (i = 0; i < smmu->nregs; i++) {
331 BUG_ON(offs < 0x1f0); 335 void __iomem *addr = smmu->regbase + offs;
332 if (offs < 0x200) 336
333 return readl(smmu->regs[1] + offs - 0x1f0); 337 BUG_ON(addr < smmu->regs[i]);
334 BUG_ON(offs < 0x228); 338 if (addr <= smmu->rege[i])
335 if (offs < 0x284) 339 return readl(addr);
336 return readl(smmu->regs[2] + offs - 0x228); 340 }
341
337 BUG(); 342 BUG();
338} 343}
339 344
340static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs) 345static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
341{ 346{
342 BUG_ON(offs < 0x10); 347 int i;
343 if (offs < 0x3c) { 348
344 writel(val, smmu->regs[0] + offs - 0x10); 349 for (i = 0; i < smmu->nregs; i++) {
345 return; 350 void __iomem *addr = smmu->regbase + offs;
346 } 351
347 BUG_ON(offs < 0x1f0); 352 BUG_ON(addr < smmu->regs[i]);
348 if (offs < 0x200) { 353 if (addr <= smmu->rege[i]) {
349 writel(val, smmu->regs[1] + offs - 0x1f0); 354 writel(val, addr);
350 return; 355 return;
351 } 356 }
352 BUG_ON(offs < 0x228);
353 if (offs < 0x284) {
354 writel(val, smmu->regs[2] + offs - 0x228);
355 return;
356 } 357 }
358
357 BUG(); 359 BUG();
358} 360}
359 361
@@ -1170,7 +1172,13 @@ static int tegra_smmu_probe(struct platform_device *pdev)
1170 return -ENOMEM; 1172 return -ENOMEM;
1171 } 1173 }
1172 1174
1173 for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) { 1175 smmu->nregs = pdev->num_resources;
1176 smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
1177 GFP_KERNEL);
1178 smmu->rege = smmu->regs + smmu->nregs;
1179 if (!smmu->regs)
1180 return -ENOMEM;
1181 for (i = 0; i < smmu->nregs; i++) {
1174 struct resource *res; 1182 struct resource *res;
1175 1183
1176 res = platform_get_resource(pdev, IORESOURCE_MEM, i); 1184 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
@@ -1179,7 +1187,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
1179 smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res); 1187 smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
1180 if (!smmu->regs[i]) 1188 if (!smmu->regs[i])
1181 return -EBUSY; 1189 return -EBUSY;
1190 smmu->rege[i] = smmu->regs[i] + resource_size(res) - 1;
1182 } 1191 }
1192 /* Same as "mc" 1st regiter block start address */
1193 smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
1183 1194
1184 err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size); 1195 err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
1185 if (err) 1196 if (err)