aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-msm/devices-iommu.c5
-rw-r--r--arch/arm/mach-msm/include/mach/iommu.h5
-rw-r--r--arch/arm/mach-msm/iommu_dev.c206
3 files changed, 121 insertions, 95 deletions
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index c0206b727502..af97afe0bfab 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -280,7 +280,6 @@ static struct platform_device msm_root_iommu_dev = {
280 280
281static struct msm_iommu_dev jpegd_iommu = { 281static struct msm_iommu_dev jpegd_iommu = {
282 .name = "jpegd", 282 .name = "jpegd",
283 .clk_rate = -1
284}; 283};
285 284
286static struct msm_iommu_dev vpe_iommu = { 285static struct msm_iommu_dev vpe_iommu = {
@@ -305,7 +304,6 @@ static struct msm_iommu_dev ijpeg_iommu = {
305 304
306static struct msm_iommu_dev vfe_iommu = { 305static struct msm_iommu_dev vfe_iommu = {
307 .name = "vfe", 306 .name = "vfe",
308 .clk_rate = -1
309}; 307};
310 308
311static struct msm_iommu_dev vcodec_a_iommu = { 309static struct msm_iommu_dev vcodec_a_iommu = {
@@ -318,17 +316,14 @@ static struct msm_iommu_dev vcodec_b_iommu = {
318 316
319static struct msm_iommu_dev gfx3d_iommu = { 317static struct msm_iommu_dev gfx3d_iommu = {
320 .name = "gfx3d", 318 .name = "gfx3d",
321 .clk_rate = 27000000
322}; 319};
323 320
324static struct msm_iommu_dev gfx2d0_iommu = { 321static struct msm_iommu_dev gfx2d0_iommu = {
325 .name = "gfx2d0", 322 .name = "gfx2d0",
326 .clk_rate = 27000000
327}; 323};
328 324
329static struct msm_iommu_dev gfx2d1_iommu = { 325static struct msm_iommu_dev gfx2d1_iommu = {
330 .name = "gfx2d1", 326 .name = "gfx2d1",
331 .clk_rate = 27000000
332}; 327};
333 328
334static struct platform_device msm_device_iommu_jpegd = { 329static struct platform_device msm_device_iommu_jpegd = {
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 8738a4455588..4dfe7efcf4ea 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -45,14 +45,9 @@
45/** 45/**
46 * struct msm_iommu_dev - a single IOMMU hardware instance 46 * struct msm_iommu_dev - a single IOMMU hardware instance
47 * name Human-readable name given to this IOMMU HW instance 47 * name Human-readable name given to this IOMMU HW instance
48 * clk_rate Rate to set for this IOMMU's clock, if applicable to this
49 * particular IOMMU. 0 means don't set a rate.
50 * -1 means it is an AXI clock with no valid rate
51 *
52 */ 48 */
53struct msm_iommu_dev { 49struct msm_iommu_dev {
54 const char *name; 50 const char *name;
55 int clk_rate;
56}; 51};
57 52
58/** 53/**
diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
index b83c73b41fd1..79ade0b3b326 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 */
@@ -130,117 +131,134 @@ static int msm_iommu_probe(struct platform_device *pdev)
130{ 131{
131 struct resource *r, *r2; 132 struct resource *r, *r2;
132 struct clk *iommu_clk; 133 struct clk *iommu_clk;
134 struct clk *iommu_pclk;
133 struct msm_iommu_drvdata *drvdata; 135 struct msm_iommu_drvdata *drvdata;
134 struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data; 136 struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
135 void __iomem *regs_base; 137 void __iomem *regs_base;
136 resource_size_t len; 138 resource_size_t len;
137 int ret = 0, ncb, nm2v, irq; 139 int ret, ncb, nm2v, irq;
138 140
139 if (pdev->id != -1) { 141 if (pdev->id == -1) {
140 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); 142 msm_iommu_root_dev = pdev;
143 return 0;
144 }
141 145
142 if (!drvdata) { 146 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
143 ret = -ENOMEM;
144 goto fail;
145 }
146 147
147 if (!iommu_dev) { 148 if (!drvdata) {
148 ret = -ENODEV; 149 ret = -ENOMEM;
149 goto fail; 150 goto fail;
150 } 151 }
152
153 if (!iommu_dev) {
154 ret = -ENODEV;
155 goto fail;
156 }
151 157
152 if (iommu_dev->clk_rate != 0) { 158 iommu_pclk = clk_get(NULL, "smmu_pclk");
153 iommu_clk = clk_get(&pdev->dev, "iommu_clk"); 159 if (IS_ERR(iommu_pclk)) {
154 160 ret = -ENODEV;
155 if (IS_ERR(iommu_clk)) { 161 goto fail;
156 ret = -ENODEV; 162 }
157 goto fail; 163
158 } 164 ret = clk_enable(iommu_pclk);
159 165 if (ret)
160 if (iommu_dev->clk_rate > 0) { 166 goto fail_enable;
161 ret = clk_set_rate(iommu_clk, 167
162 iommu_dev->clk_rate); 168 iommu_clk = clk_get(&pdev->dev, "iommu_clk");
163 if (ret) { 169
164 clk_put(iommu_clk); 170 if (!IS_ERR(iommu_clk)) {
165 goto fail; 171 if (clk_get_rate(iommu_clk) == 0)
166 } 172 clk_set_min_rate(iommu_clk, 1);
167 } 173
168 174 ret = clk_enable(iommu_clk);
169 ret = clk_enable(iommu_clk); 175 if (ret) {
170 if (ret) {
171 clk_put(iommu_clk);
172 goto fail;
173 }
174 clk_put(iommu_clk); 176 clk_put(iommu_clk);
177 goto fail_pclk;
175 } 178 }
179 } else
180 iommu_clk = NULL;
176 181
177 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, 182 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "physbase");
178 "physbase");
179 if (!r) {
180 ret = -ENODEV;
181 goto fail;
182 }
183 183
184 len = r->end - r->start + 1; 184 if (!r) {
185 ret = -ENODEV;
186 goto fail_clk;
187 }
185 188
186 r2 = request_mem_region(r->start, len, r->name); 189 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 190
194 regs_base = ioremap(r2->start, len); 191 r2 = request_mem_region(r->start, len, r->name);
192 if (!r2) {
193 pr_err("Could not request memory region: start=%p, len=%d\n",
194 (void *) r->start, len);
195 ret = -EBUSY;
196 goto fail_clk;
197 }
195 198
196 if (!regs_base) { 199 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 200
203 irq = platform_get_irq_byname(pdev, "secure_irq"); 201 if (!regs_base) {
204 if (irq < 0) { 202 pr_err("Could not ioremap: start=%p, len=%d\n",
205 ret = -ENODEV; 203 (void *) r2->start, len);
206 goto fail_io; 204 ret = -EBUSY;
207 } 205 goto fail_mem;
206 }
207
208 irq = platform_get_irq_byname(pdev, "secure_irq");
209 if (irq < 0) {
210 ret = -ENODEV;
211 goto fail_io;
212 }
208 213
209 mb(); 214 mb();
210 215
211 if (GET_IDR(regs_base) == 0) { 216 if (GET_IDR(regs_base) == 0) {
212 pr_err("Invalid IDR value detected\n"); 217 pr_err("Invalid IDR value detected\n");
213 ret = -ENODEV; 218 ret = -ENODEV;
214 goto fail_io; 219 goto fail_io;
215 } 220 }
216 221
217 ret = request_irq(irq, msm_iommu_fault_handler, 0, 222 ret = request_irq(irq, msm_iommu_fault_handler, 0,
218 "msm_iommu_secure_irpt_handler", drvdata); 223 "msm_iommu_secure_irpt_handler", drvdata);
219 if (ret) { 224 if (ret) {
220 pr_err("Request IRQ %d failed with ret=%d\n", irq, ret); 225 pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
221 goto fail_io; 226 goto fail_io;
222 } 227 }
223 228
224 msm_iommu_reset(regs_base); 229 msm_iommu_reset(regs_base);
225 drvdata->base = regs_base; 230 drvdata->pclk = iommu_pclk;
226 drvdata->irq = irq; 231 drvdata->clk = iommu_clk;
232 drvdata->base = regs_base;
233 drvdata->irq = irq;
227 234
228 nm2v = GET_NM2VCBMT((unsigned long) regs_base); 235 nm2v = GET_NM2VCBMT((unsigned long) regs_base);
229 ncb = GET_NCB((unsigned long) regs_base); 236 ncb = GET_NCB((unsigned long) regs_base);
230 237
231 pr_info("device %s mapped at %p, irq %d with %d ctx banks\n", 238 pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
232 iommu_dev->name, regs_base, irq, ncb+1); 239 iommu_dev->name, regs_base, irq, ncb+1);
233 240
234 platform_set_drvdata(pdev, drvdata); 241 platform_set_drvdata(pdev, drvdata);
235 } else
236 msm_iommu_root_dev = pdev;
237 242
238 return 0; 243 if (iommu_clk)
244 clk_disable(iommu_clk);
245
246 clk_disable(iommu_pclk);
239 247
248 return 0;
240fail_io: 249fail_io:
241 iounmap(regs_base); 250 iounmap(regs_base);
242fail_mem: 251fail_mem:
243 release_mem_region(r->start, len); 252 release_mem_region(r->start, len);
253fail_clk:
254 if (iommu_clk) {
255 clk_disable(iommu_clk);
256 clk_put(iommu_clk);
257 }
258fail_pclk:
259 clk_disable(iommu_pclk);
260fail_enable:
261 clk_put(iommu_pclk);
244fail: 262fail:
245 kfree(drvdata); 263 kfree(drvdata);
246 return ret; 264 return ret;
@@ -252,7 +270,10 @@ static int msm_iommu_remove(struct platform_device *pdev)
252 270
253 drv = platform_get_drvdata(pdev); 271 drv = platform_get_drvdata(pdev);
254 if (drv) { 272 if (drv) {
255 memset(drv, 0, sizeof(struct msm_iommu_drvdata)); 273 if (drv->clk)
274 clk_put(drv->clk);
275 clk_put(drv->pclk);
276 memset(drv, 0, sizeof(*drv));
256 kfree(drv); 277 kfree(drv);
257 platform_set_drvdata(pdev, NULL); 278 platform_set_drvdata(pdev, NULL);
258 } 279 }
@@ -264,7 +285,7 @@ static int msm_iommu_ctx_probe(struct platform_device *pdev)
264 struct msm_iommu_ctx_dev *c = pdev->dev.platform_data; 285 struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
265 struct msm_iommu_drvdata *drvdata; 286 struct msm_iommu_drvdata *drvdata;
266 struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL; 287 struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
267 int i, ret = 0; 288 int i, ret;
268 if (!c || !pdev->dev.parent) { 289 if (!c || !pdev->dev.parent) {
269 ret = -EINVAL; 290 ret = -EINVAL;
270 goto fail; 291 goto fail;
@@ -288,6 +309,18 @@ static int msm_iommu_ctx_probe(struct platform_device *pdev)
288 INIT_LIST_HEAD(&ctx_drvdata->attached_elm); 309 INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
289 platform_set_drvdata(pdev, ctx_drvdata); 310 platform_set_drvdata(pdev, ctx_drvdata);
290 311
312 ret = clk_enable(drvdata->pclk);
313 if (ret)
314 goto fail;
315
316 if (drvdata->clk) {
317 ret = clk_enable(drvdata->clk);
318 if (ret) {
319 clk_disable(drvdata->pclk);
320 goto fail;
321 }
322 }
323
291 /* Program the M2V tables for this context */ 324 /* Program the M2V tables for this context */
292 for (i = 0; i < MAX_NUM_MIDS; i++) { 325 for (i = 0; i < MAX_NUM_MIDS; i++) {
293 int mid = c->mids[i]; 326 int mid = c->mids[i];
@@ -310,8 +343,11 @@ static int msm_iommu_ctx_probe(struct platform_device *pdev)
310 SET_NSCFG(drvdata->base, mid, 3); 343 SET_NSCFG(drvdata->base, mid, 3);
311 } 344 }
312 345
313 pr_info("context device %s with bank index %d\n", c->name, c->num); 346 if (drvdata->clk)
347 clk_disable(drvdata->clk);
348 clk_disable(drvdata->pclk);
314 349
350 dev_info(&pdev->dev, "context %s using bank %d\n", c->name, c->num);
315 return 0; 351 return 0;
316fail: 352fail:
317 kfree(ctx_drvdata); 353 kfree(ctx_drvdata);