diff options
author | Cho KyongHo <pullip.cho@samsung.com> | 2014-05-12 02:14:55 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2014-05-13 13:12:55 -0400 |
commit | 7060587052e0370ea1b7a41c84d5ad364be16f51 (patch) | |
tree | e9cdb5f0764594786ccf9f83415fb0317c15aba0 /drivers/iommu | |
parent | 46c16d1e4c11ffa0481b1dd6841e0bcabcf278e7 (diff) |
iommu/exynos: Gating clocks of master H/W
This patch gates clocks of master H/W as well as clocks of System MMU
if master clocks are specified.
Some Exynos SoCs (i.e. GScalers in Exynos5250) have dependencies in
the gating clocks of master H/W and its System MMU. If a H/W is the
case, accessing control registers of System MMU is prohibited unless
both of the gating clocks of System MMU and its master H/W.
CC: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Cho KyongHo <pullip.cho@samsung.com>
Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/exynos-iommu.c | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index c86e3745e98f..5af5c5c16f49 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c | |||
@@ -172,6 +172,7 @@ struct sysmmu_drvdata { | |||
172 | struct device *dev; /* Owner of system MMU */ | 172 | struct device *dev; /* Owner of system MMU */ |
173 | void __iomem *sfrbase; | 173 | void __iomem *sfrbase; |
174 | struct clk *clk; | 174 | struct clk *clk; |
175 | struct clk *clk_master; | ||
175 | int activations; | 176 | int activations; |
176 | rwlock_t lock; | 177 | rwlock_t lock; |
177 | struct iommu_domain *domain; | 178 | struct iommu_domain *domain; |
@@ -300,6 +301,8 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) | |||
300 | 301 | ||
301 | WARN_ON(!is_sysmmu_active(data)); | 302 | WARN_ON(!is_sysmmu_active(data)); |
302 | 303 | ||
304 | if (!IS_ERR(data->clk_master)) | ||
305 | clk_enable(data->clk_master); | ||
303 | itype = (enum exynos_sysmmu_inttype) | 306 | itype = (enum exynos_sysmmu_inttype) |
304 | __ffs(__raw_readl(data->sfrbase + REG_INT_STATUS)); | 307 | __ffs(__raw_readl(data->sfrbase + REG_INT_STATUS)); |
305 | if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN)))) | 308 | if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN)))) |
@@ -326,6 +329,9 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) | |||
326 | if (itype != SYSMMU_FAULT_UNKNOWN) | 329 | if (itype != SYSMMU_FAULT_UNKNOWN) |
327 | sysmmu_unblock(data->sfrbase); | 330 | sysmmu_unblock(data->sfrbase); |
328 | 331 | ||
332 | if (!IS_ERR(data->clk_master)) | ||
333 | clk_disable(data->clk_master); | ||
334 | |||
329 | read_unlock(&data->lock); | 335 | read_unlock(&data->lock); |
330 | 336 | ||
331 | return IRQ_HANDLED; | 337 | return IRQ_HANDLED; |
@@ -341,9 +347,14 @@ static bool __exynos_sysmmu_disable(struct sysmmu_drvdata *data) | |||
341 | if (!set_sysmmu_inactive(data)) | 347 | if (!set_sysmmu_inactive(data)) |
342 | goto finish; | 348 | goto finish; |
343 | 349 | ||
350 | if (!IS_ERR(data->clk_master)) | ||
351 | clk_enable(data->clk_master); | ||
352 | |||
344 | __raw_writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL); | 353 | __raw_writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL); |
345 | 354 | ||
346 | clk_disable(data->clk); | 355 | clk_disable(data->clk); |
356 | if (!IS_ERR(data->clk_master)) | ||
357 | clk_disable(data->clk_master); | ||
347 | 358 | ||
348 | disabled = true; | 359 | disabled = true; |
349 | data->pgtable = 0; | 360 | data->pgtable = 0; |
@@ -386,14 +397,19 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata *data, | |||
386 | goto finish; | 397 | goto finish; |
387 | } | 398 | } |
388 | 399 | ||
389 | clk_enable(data->clk); | ||
390 | |||
391 | data->pgtable = pgtable; | 400 | data->pgtable = pgtable; |
392 | 401 | ||
402 | if (!IS_ERR(data->clk_master)) | ||
403 | clk_enable(data->clk_master); | ||
404 | clk_enable(data->clk); | ||
405 | |||
393 | __sysmmu_set_ptbase(data->sfrbase, pgtable); | 406 | __sysmmu_set_ptbase(data->sfrbase, pgtable); |
394 | 407 | ||
395 | __raw_writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL); | 408 | __raw_writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL); |
396 | 409 | ||
410 | if (!IS_ERR(data->clk_master)) | ||
411 | clk_disable(data->clk_master); | ||
412 | |||
397 | data->domain = domain; | 413 | data->domain = domain; |
398 | 414 | ||
399 | dev_dbg(data->sysmmu, "Enabled\n"); | 415 | dev_dbg(data->sysmmu, "Enabled\n"); |
@@ -450,6 +466,10 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova, | |||
450 | if (is_sysmmu_active(data)) { | 466 | if (is_sysmmu_active(data)) { |
451 | unsigned int maj; | 467 | unsigned int maj; |
452 | unsigned int num_inv = 1; | 468 | unsigned int num_inv = 1; |
469 | |||
470 | if (!IS_ERR(data->clk_master)) | ||
471 | clk_enable(data->clk_master); | ||
472 | |||
453 | maj = __raw_readl(data->sfrbase + REG_MMU_VERSION); | 473 | maj = __raw_readl(data->sfrbase + REG_MMU_VERSION); |
454 | /* | 474 | /* |
455 | * L2TLB invalidation required | 475 | * L2TLB invalidation required |
@@ -469,6 +489,8 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova, | |||
469 | data->sfrbase, iova, num_inv); | 489 | data->sfrbase, iova, num_inv); |
470 | sysmmu_unblock(data->sfrbase); | 490 | sysmmu_unblock(data->sfrbase); |
471 | } | 491 | } |
492 | if (!IS_ERR(data->clk_master)) | ||
493 | clk_disable(data->clk_master); | ||
472 | } else { | 494 | } else { |
473 | dev_dbg(data->sysmmu, "Disabled. Skipping invalidating TLB.\n"); | 495 | dev_dbg(data->sysmmu, "Disabled. Skipping invalidating TLB.\n"); |
474 | } | 496 | } |
@@ -484,10 +506,14 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev) | |||
484 | read_lock_irqsave(&data->lock, flags); | 506 | read_lock_irqsave(&data->lock, flags); |
485 | 507 | ||
486 | if (is_sysmmu_active(data)) { | 508 | if (is_sysmmu_active(data)) { |
509 | if (!IS_ERR(data->clk_master)) | ||
510 | clk_enable(data->clk_master); | ||
487 | if (sysmmu_block(data->sfrbase)) { | 511 | if (sysmmu_block(data->sfrbase)) { |
488 | __sysmmu_tlb_invalidate(data->sfrbase); | 512 | __sysmmu_tlb_invalidate(data->sfrbase); |
489 | sysmmu_unblock(data->sfrbase); | 513 | sysmmu_unblock(data->sfrbase); |
490 | } | 514 | } |
515 | if (!IS_ERR(data->clk_master)) | ||
516 | clk_disable(data->clk_master); | ||
491 | } else { | 517 | } else { |
492 | dev_dbg(data->sysmmu, "Disabled. Skipping invalidating TLB.\n"); | 518 | dev_dbg(data->sysmmu, "Disabled. Skipping invalidating TLB.\n"); |
493 | } | 519 | } |
@@ -536,6 +562,16 @@ static int exynos_sysmmu_probe(struct platform_device *pdev) | |||
536 | } | 562 | } |
537 | } | 563 | } |
538 | 564 | ||
565 | data->clk_master = devm_clk_get(dev, "master"); | ||
566 | if (!IS_ERR(data->clk_master)) { | ||
567 | ret = clk_prepare(data->clk_master); | ||
568 | if (ret) { | ||
569 | clk_unprepare(data->clk); | ||
570 | dev_err(dev, "Failed to prepare master's clk\n"); | ||
571 | return ret; | ||
572 | } | ||
573 | } | ||
574 | |||
539 | data->sysmmu = dev; | 575 | data->sysmmu = dev; |
540 | rwlock_init(&data->lock); | 576 | rwlock_init(&data->lock); |
541 | INIT_LIST_HEAD(&data->node); | 577 | INIT_LIST_HEAD(&data->node); |