aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-msm
diff options
context:
space:
mode:
authorStepan Moskovchenko <stepanm@codeaurora.org>2011-02-24 21:00:39 -0500
committerDavid Brown <davidb@codeaurora.org>2011-03-08 17:40:58 -0500
commit41f3f5138a5ea71ee603f3d556953fce9aba3074 (patch)
tree7fe712ddf9b29098b527dbdf9766d4d155dc00d8 /arch/arm/mach-msm
parent8bec99b586e2aa285076c2057e72b70ab5c43175 (diff)
msm: iommu: Clock control for the IOMMU driver
Add clock control to the IOMMU driver. The IOMMU bus clock (and potentially an AXI clock) need to be on to gain access to IOMMU registers. Actively control these clocks when needed instead of leaving them on. Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org> Signed-off-by: David Brown <davidb@codeaurora.org>
Diffstat (limited to 'arch/arm/mach-msm')
-rw-r--r--arch/arm/mach-msm/include/mach/iommu.h9
-rw-r--r--arch/arm/mach-msm/iommu.c58
2 files changed, 62 insertions, 5 deletions
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 296c0f10f230..8738a4455588 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -1,4 +1,4 @@
1/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. 1/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 * 2 *
3 * This program is free software; you can redistribute it and/or modify 3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and 4 * it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
19#define MSM_IOMMU_H 19#define MSM_IOMMU_H
20 20
21#include <linux/interrupt.h> 21#include <linux/interrupt.h>
22#include <linux/clk.h>
22 23
23/* Sharability attributes of MSM IOMMU mappings */ 24/* Sharability attributes of MSM IOMMU mappings */
24#define MSM_IOMMU_ATTR_NON_SH 0x0 25#define MSM_IOMMU_ATTR_NON_SH 0x0
@@ -74,13 +75,17 @@ struct msm_iommu_ctx_dev {
74 * struct msm_iommu_drvdata - A single IOMMU hardware instance 75 * struct msm_iommu_drvdata - A single IOMMU hardware instance
75 * @base: IOMMU config port base address (VA) 76 * @base: IOMMU config port base address (VA)
76 * @irq: Interrupt number 77 * @irq: Interrupt number
77 * 78 * @clk: The bus clock for this IOMMU hardware instance
79 * @pclk: The clock for the IOMMU bus interconnect
80 *
78 * A msm_iommu_drvdata holds the global driver data about a single piece 81 * A msm_iommu_drvdata holds the global driver data about a single piece
79 * of an IOMMU hardware instance. 82 * of an IOMMU hardware instance.
80 */ 83 */
81struct msm_iommu_drvdata { 84struct msm_iommu_drvdata {
82 void __iomem *base; 85 void __iomem *base;
83 int irq; 86 int irq;
87 struct clk *clk;
88 struct clk *pclk;
84}; 89};
85 90
86/** 91/**
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index e2d58e4cb0d7..cde3cd0f8c0c 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -1,4 +1,4 @@
1/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. 1/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 * 2 *
3 * This program is free software; you can redistribute it and/or modify 3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and 4 * it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,7 @@
26#include <linux/spinlock.h> 26#include <linux/spinlock.h>
27#include <linux/slab.h> 27#include <linux/slab.h>
28#include <linux/iommu.h> 28#include <linux/iommu.h>
29#include <linux/clk.h>
29 30
30#include <asm/cacheflush.h> 31#include <asm/cacheflush.h>
31#include <asm/sizes.h> 32#include <asm/sizes.h>
@@ -50,6 +51,30 @@ struct msm_priv {
50 struct list_head list_attached; 51 struct list_head list_attached;
51}; 52};
52 53
54static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
55{
56 int ret;
57
58 ret = clk_enable(drvdata->pclk);
59 if (ret)
60 goto fail;
61
62 if (drvdata->clk) {
63 ret = clk_enable(drvdata->clk);
64 if (ret)
65 clk_disable(drvdata->pclk);
66 }
67fail:
68 return ret;
69}
70
71static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
72{
73 if (drvdata->clk)
74 clk_disable(drvdata->clk);
75 clk_disable(drvdata->pclk);
76}
77
53static int __flush_iotlb(struct iommu_domain *domain) 78static int __flush_iotlb(struct iommu_domain *domain)
54{ 79{
55 struct msm_priv *priv = domain->priv; 80 struct msm_priv *priv = domain->priv;
@@ -77,9 +102,16 @@ static int __flush_iotlb(struct iommu_domain *domain)
77 BUG(); 102 BUG();
78 103
79 iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent); 104 iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
105 BUG_ON(!iommu_drvdata);
106
107 ret = __enable_clocks(iommu_drvdata);
108 if (ret)
109 goto fail;
110
80 SET_CTX_TLBIALL(iommu_drvdata->base, ctx_drvdata->num, 0); 111 SET_CTX_TLBIALL(iommu_drvdata->base, ctx_drvdata->num, 0);
112 __disable_clocks(iommu_drvdata);
81 } 113 }
82 114fail:
83 return ret; 115 return ret;
84} 116}
85 117
@@ -265,9 +297,14 @@ static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
265 goto fail; 297 goto fail;
266 } 298 }
267 299
300 ret = __enable_clocks(iommu_drvdata);
301 if (ret)
302 goto fail;
303
268 __program_context(iommu_drvdata->base, ctx_dev->num, 304 __program_context(iommu_drvdata->base, ctx_dev->num,
269 __pa(priv->pgtable)); 305 __pa(priv->pgtable));
270 306
307 __disable_clocks(iommu_drvdata);
271 list_add(&(ctx_drvdata->attached_elm), &priv->list_attached); 308 list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
272 ret = __flush_iotlb(domain); 309 ret = __flush_iotlb(domain);
273 310
@@ -303,7 +340,12 @@ static void msm_iommu_detach_dev(struct iommu_domain *domain,
303 if (ret) 340 if (ret)
304 goto fail; 341 goto fail;
305 342
343 ret = __enable_clocks(iommu_drvdata);
344 if (ret)
345 goto fail;
346
306 __reset_context(iommu_drvdata->base, ctx_dev->num); 347 __reset_context(iommu_drvdata->base, ctx_dev->num);
348 __disable_clocks(iommu_drvdata);
307 list_del_init(&ctx_drvdata->attached_elm); 349 list_del_init(&ctx_drvdata->attached_elm);
308 350
309fail: 351fail:
@@ -532,6 +574,10 @@ static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
532 base = iommu_drvdata->base; 574 base = iommu_drvdata->base;
533 ctx = ctx_drvdata->num; 575 ctx = ctx_drvdata->num;
534 576
577 ret = __enable_clocks(iommu_drvdata);
578 if (ret)
579 goto fail;
580
535 /* Invalidate context TLB */ 581 /* Invalidate context TLB */
536 SET_CTX_TLBIALL(base, ctx, 0); 582 SET_CTX_TLBIALL(base, ctx, 0);
537 SET_V2PPR_VA(base, ctx, va >> V2Pxx_VA_SHIFT); 583 SET_V2PPR_VA(base, ctx, va >> V2Pxx_VA_SHIFT);
@@ -547,6 +593,7 @@ static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
547 if (GET_FAULT(base, ctx)) 593 if (GET_FAULT(base, ctx))
548 ret = 0; 594 ret = 0;
549 595
596 __disable_clocks(iommu_drvdata);
550fail: 597fail:
551 spin_unlock_irqrestore(&msm_iommu_lock, flags); 598 spin_unlock_irqrestore(&msm_iommu_lock, flags);
552 return ret; 599 return ret;
@@ -590,7 +637,7 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
590 struct msm_iommu_drvdata *drvdata = dev_id; 637 struct msm_iommu_drvdata *drvdata = dev_id;
591 void __iomem *base; 638 void __iomem *base;
592 unsigned int fsr; 639 unsigned int fsr;
593 int ncb, i; 640 int ncb, i, ret;
594 641
595 spin_lock(&msm_iommu_lock); 642 spin_lock(&msm_iommu_lock);
596 643
@@ -604,6 +651,10 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
604 pr_err("Unexpected IOMMU page fault!\n"); 651 pr_err("Unexpected IOMMU page fault!\n");
605 pr_err("base = %08x\n", (unsigned int) base); 652 pr_err("base = %08x\n", (unsigned int) base);
606 653
654 ret = __enable_clocks(drvdata);
655 if (ret)
656 goto fail;
657
607 ncb = GET_NCB(base)+1; 658 ncb = GET_NCB(base)+1;
608 for (i = 0; i < ncb; i++) { 659 for (i = 0; i < ncb; i++) {
609 fsr = GET_FSR(base, i); 660 fsr = GET_FSR(base, i);
@@ -614,6 +665,7 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
614 SET_FSR(base, i, 0x4000000F); 665 SET_FSR(base, i, 0x4000000F);
615 } 666 }
616 } 667 }
668 __disable_clocks(drvdata);
617fail: 669fail:
618 spin_unlock(&msm_iommu_lock); 670 spin_unlock(&msm_iommu_lock);
619 return 0; 671 return 0;