aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-msm/iommu_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-msm/iommu_dev.c')
-rw-r--r--arch/arm/mach-msm/iommu_dev.c230
1 files changed, 137 insertions, 93 deletions
diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
index b83c73b41fd1..8e8fb079852d 100644
--- a/arch/arm/mach-msm/iommu_dev.c
+++ b/arch/arm/mach-msm/iommu_dev.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
@@ -29,6 +29,7 @@
29 29
30#include <mach/iommu_hw-8xxx.h> 30#include <mach/iommu_hw-8xxx.h>
31#include <mach/iommu.h> 31#include <mach/iommu.h>
32#include <mach/clk.h>
32 33
33struct iommu_ctx_iter_data { 34struct iommu_ctx_iter_data {
34 /* input */ 35 /* input */
@@ -84,9 +85,9 @@ fail:
84} 85}
85EXPORT_SYMBOL(msm_iommu_get_ctx); 86EXPORT_SYMBOL(msm_iommu_get_ctx);
86 87
87static void msm_iommu_reset(void __iomem *base) 88static void msm_iommu_reset(void __iomem *base, int ncb)
88{ 89{
89 int ctx, ncb; 90 int ctx;
90 91
91 SET_RPUE(base, 0); 92 SET_RPUE(base, 0);
92 SET_RPUEIE(base, 0); 93 SET_RPUEIE(base, 0);
@@ -99,7 +100,6 @@ static void msm_iommu_reset(void __iomem *base)
99 SET_GLOBAL_TLBIALL(base, 0); 100 SET_GLOBAL_TLBIALL(base, 0);
100 SET_RPU_ACR(base, 0); 101 SET_RPU_ACR(base, 0);
101 SET_TLBLKCRWE(base, 1); 102 SET_TLBLKCRWE(base, 1);
102 ncb = GET_NCB(base)+1;
103 103
104 for (ctx = 0; ctx < ncb; ctx++) { 104 for (ctx = 0; ctx < ncb; ctx++) {
105 SET_BPRCOSH(base, ctx, 0); 105 SET_BPRCOSH(base, ctx, 0);
@@ -130,117 +130,140 @@ static int msm_iommu_probe(struct platform_device *pdev)
130{ 130{
131 struct resource *r, *r2; 131 struct resource *r, *r2;
132 struct clk *iommu_clk; 132 struct clk *iommu_clk;
133 struct clk *iommu_pclk;
133 struct msm_iommu_drvdata *drvdata; 134 struct msm_iommu_drvdata *drvdata;
134 struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data; 135 struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
135 void __iomem *regs_base; 136 void __iomem *regs_base;
136 resource_size_t len; 137 resource_size_t len;
137 int ret = 0, ncb, nm2v, irq; 138 int ret, irq, par;
138 139
139 if (pdev->id != -1) { 140 if (pdev->id == -1) {
140 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); 141 msm_iommu_root_dev = pdev;
142 return 0;
143 }
141 144
142 if (!drvdata) { 145 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
143 ret = -ENOMEM;
144 goto fail;
145 }
146 146
147 if (!iommu_dev) { 147 if (!drvdata) {
148 ret = -ENODEV; 148 ret = -ENOMEM;
149 goto fail; 149 goto fail;
150 } 150 }
151 151
152 if (iommu_dev->clk_rate != 0) { 152 if (!iommu_dev) {
153 iommu_clk = clk_get(&pdev->dev, "iommu_clk"); 153 ret = -ENODEV;
154 154 goto fail;
155 if (IS_ERR(iommu_clk)) { 155 }
156 ret = -ENODEV; 156
157 goto fail; 157 iommu_pclk = clk_get(NULL, "smmu_pclk");
158 } 158 if (IS_ERR(iommu_pclk)) {
159 159 ret = -ENODEV;
160 if (iommu_dev->clk_rate > 0) { 160 goto fail;
161 ret = clk_set_rate(iommu_clk, 161 }
162 iommu_dev->clk_rate); 162
163 if (ret) { 163 ret = clk_enable(iommu_pclk);
164 clk_put(iommu_clk); 164 if (ret)
165 goto fail; 165 goto fail_enable;
166 } 166
167 } 167 iommu_clk = clk_get(&pdev->dev, "iommu_clk");
168 168
169 ret = clk_enable(iommu_clk); 169 if (!IS_ERR(iommu_clk)) {
170 if (ret) { 170 if (clk_get_rate(iommu_clk) == 0)
171 clk_put(iommu_clk); 171 clk_set_min_rate(iommu_clk, 1);
172 goto fail; 172
173 } 173 ret = clk_enable(iommu_clk);
174 if (ret) {
174 clk_put(iommu_clk); 175 clk_put(iommu_clk);
176 goto fail_pclk;
175 } 177 }
178 } else
179 iommu_clk = NULL;
176 180
177 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, 181 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "physbase");
178 "physbase");
179 if (!r) {
180 ret = -ENODEV;
181 goto fail;
182 }
183 182
184 len = r->end - r->start + 1; 183 if (!r) {
184 ret = -ENODEV;
185 goto fail_clk;
186 }
185 187
186 r2 = request_mem_region(r->start, len, r->name); 188 len = resource_size(r);
187 if (!r2) {
188 pr_err("Could not request memory region: "
189 "start=%p, len=%d\n", (void *) r->start, len);
190 ret = -EBUSY;
191 goto fail;
192 }
193 189
194 regs_base = ioremap(r2->start, len); 190 r2 = request_mem_region(r->start, len, r->name);
191 if (!r2) {
192 pr_err("Could not request memory region: start=%p, len=%d\n",
193 (void *) r->start, len);
194 ret = -EBUSY;
195 goto fail_clk;
196 }
195 197
196 if (!regs_base) { 198 regs_base = ioremap(r2->start, len);
197 pr_err("Could not ioremap: start=%p, len=%d\n",
198 (void *) r2->start, len);
199 ret = -EBUSY;
200 goto fail_mem;
201 }
202 199
203 irq = platform_get_irq_byname(pdev, "secure_irq"); 200 if (!regs_base) {
204 if (irq < 0) { 201 pr_err("Could not ioremap: start=%p, len=%d\n",
205 ret = -ENODEV; 202 (void *) r2->start, len);
206 goto fail_io; 203 ret = -EBUSY;
207 } 204 goto fail_mem;
205 }
208 206
209 mb(); 207 irq = platform_get_irq_byname(pdev, "secure_irq");
208 if (irq < 0) {
209 ret = -ENODEV;
210 goto fail_io;
211 }
210 212
211 if (GET_IDR(regs_base) == 0) { 213 msm_iommu_reset(regs_base, iommu_dev->ncb);
212 pr_err("Invalid IDR value detected\n");
213 ret = -ENODEV;
214 goto fail_io;
215 }
216 214
217 ret = request_irq(irq, msm_iommu_fault_handler, 0, 215 SET_M(regs_base, 0, 1);
218 "msm_iommu_secure_irpt_handler", drvdata); 216 SET_PAR(regs_base, 0, 0);
219 if (ret) { 217 SET_V2PCFG(regs_base, 0, 1);
220 pr_err("Request IRQ %d failed with ret=%d\n", irq, ret); 218 SET_V2PPR(regs_base, 0, 0);
221 goto fail_io; 219 par = GET_PAR(regs_base, 0);
222 } 220 SET_V2PCFG(regs_base, 0, 0);
221 SET_M(regs_base, 0, 0);
223 222
224 msm_iommu_reset(regs_base); 223 if (!par) {
225 drvdata->base = regs_base; 224 pr_err("%s: Invalid PAR value detected\n", iommu_dev->name);
226 drvdata->irq = irq; 225 ret = -ENODEV;
226 goto fail_io;
227 }
227 228
228 nm2v = GET_NM2VCBMT((unsigned long) regs_base); 229 ret = request_irq(irq, msm_iommu_fault_handler, 0,
229 ncb = GET_NCB((unsigned long) regs_base); 230 "msm_iommu_secure_irpt_handler", drvdata);
231 if (ret) {
232 pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
233 goto fail_io;
234 }
230 235
231 pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
232 iommu_dev->name, regs_base, irq, ncb+1);
233 236
234 platform_set_drvdata(pdev, drvdata); 237 drvdata->pclk = iommu_pclk;
235 } else 238 drvdata->clk = iommu_clk;
236 msm_iommu_root_dev = pdev; 239 drvdata->base = regs_base;
240 drvdata->irq = irq;
241 drvdata->ncb = iommu_dev->ncb;
237 242
238 return 0; 243 pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
244 iommu_dev->name, regs_base, irq, iommu_dev->ncb);
245
246 platform_set_drvdata(pdev, drvdata);
247
248 if (iommu_clk)
249 clk_disable(iommu_clk);
250
251 clk_disable(iommu_pclk);
239 252
253 return 0;
240fail_io: 254fail_io:
241 iounmap(regs_base); 255 iounmap(regs_base);
242fail_mem: 256fail_mem:
243 release_mem_region(r->start, len); 257 release_mem_region(r->start, len);
258fail_clk:
259 if (iommu_clk) {
260 clk_disable(iommu_clk);
261 clk_put(iommu_clk);
262 }
263fail_pclk:
264 clk_disable(iommu_pclk);
265fail_enable:
266 clk_put(iommu_pclk);
244fail: 267fail:
245 kfree(drvdata); 268 kfree(drvdata);
246 return ret; 269 return ret;
@@ -252,7 +275,10 @@ static int msm_iommu_remove(struct platform_device *pdev)
252 275
253 drv = platform_get_drvdata(pdev); 276 drv = platform_get_drvdata(pdev);
254 if (drv) { 277 if (drv) {
255 memset(drv, 0, sizeof(struct msm_iommu_drvdata)); 278 if (drv->clk)
279 clk_put(drv->clk);
280 clk_put(drv->pclk);
281 memset(drv, 0, sizeof(*drv));
256 kfree(drv); 282 kfree(drv);
257 platform_set_drvdata(pdev, NULL); 283 platform_set_drvdata(pdev, NULL);
258 } 284 }
@@ -264,7 +290,7 @@ static int msm_iommu_ctx_probe(struct platform_device *pdev)
264 struct msm_iommu_ctx_dev *c = pdev->dev.platform_data; 290 struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
265 struct msm_iommu_drvdata *drvdata; 291 struct msm_iommu_drvdata *drvdata;
266 struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL; 292 struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
267 int i, ret = 0; 293 int i, ret;
268 if (!c || !pdev->dev.parent) { 294 if (!c || !pdev->dev.parent) {
269 ret = -EINVAL; 295 ret = -EINVAL;
270 goto fail; 296 goto fail;
@@ -288,6 +314,18 @@ static int msm_iommu_ctx_probe(struct platform_device *pdev)
288 INIT_LIST_HEAD(&ctx_drvdata->attached_elm); 314 INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
289 platform_set_drvdata(pdev, ctx_drvdata); 315 platform_set_drvdata(pdev, ctx_drvdata);
290 316
317 ret = clk_enable(drvdata->pclk);
318 if (ret)
319 goto fail;
320
321 if (drvdata->clk) {
322 ret = clk_enable(drvdata->clk);
323 if (ret) {
324 clk_disable(drvdata->pclk);
325 goto fail;
326 }
327 }
328
291 /* Program the M2V tables for this context */ 329 /* Program the M2V tables for this context */
292 for (i = 0; i < MAX_NUM_MIDS; i++) { 330 for (i = 0; i < MAX_NUM_MIDS; i++) {
293 int mid = c->mids[i]; 331 int mid = c->mids[i];
@@ -297,21 +335,27 @@ static int msm_iommu_ctx_probe(struct platform_device *pdev)
297 SET_M2VCBR_N(drvdata->base, mid, 0); 335 SET_M2VCBR_N(drvdata->base, mid, 0);
298 SET_CBACR_N(drvdata->base, c->num, 0); 336 SET_CBACR_N(drvdata->base, c->num, 0);
299 337
300 /* Set VMID = MID */ 338 /* Set VMID = 0 */
301 SET_VMID(drvdata->base, mid, mid); 339 SET_VMID(drvdata->base, mid, 0);
302 340
303 /* Set the context number for that MID to this context */ 341 /* Set the context number for that MID to this context */
304 SET_CBNDX(drvdata->base, mid, c->num); 342 SET_CBNDX(drvdata->base, mid, c->num);
305 343
306 /* Set MID associated with this context bank */ 344 /* Set MID associated with this context bank to 0*/
307 SET_CBVMID(drvdata->base, c->num, mid); 345 SET_CBVMID(drvdata->base, c->num, 0);
346
347 /* Set the ASID for TLB tagging for this context */
348 SET_CONTEXTIDR_ASID(drvdata->base, c->num, c->num);
308 349
309 /* Set security bit override to be Non-secure */ 350 /* Set security bit override to be Non-secure */
310 SET_NSCFG(drvdata->base, mid, 3); 351 SET_NSCFG(drvdata->base, mid, 3);
311 } 352 }
312 353
313 pr_info("context device %s with bank index %d\n", c->name, c->num); 354 if (drvdata->clk)
355 clk_disable(drvdata->clk);
356 clk_disable(drvdata->pclk);
314 357
358 dev_info(&pdev->dev, "context %s using bank %d\n", c->name, c->num);
315 return 0; 359 return 0;
316fail: 360fail:
317 kfree(ctx_drvdata); 361 kfree(ctx_drvdata);