diff options
-rw-r--r-- | arch/arm/mach-msm/devices-iommu.c | 5 | ||||
-rw-r--r-- | arch/arm/mach-msm/include/mach/iommu.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-msm/iommu_dev.c | 206 |
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 | ||
281 | static struct msm_iommu_dev jpegd_iommu = { | 281 | static struct msm_iommu_dev jpegd_iommu = { |
282 | .name = "jpegd", | 282 | .name = "jpegd", |
283 | .clk_rate = -1 | ||
284 | }; | 283 | }; |
285 | 284 | ||
286 | static struct msm_iommu_dev vpe_iommu = { | 285 | static struct msm_iommu_dev vpe_iommu = { |
@@ -305,7 +304,6 @@ static struct msm_iommu_dev ijpeg_iommu = { | |||
305 | 304 | ||
306 | static struct msm_iommu_dev vfe_iommu = { | 305 | static struct msm_iommu_dev vfe_iommu = { |
307 | .name = "vfe", | 306 | .name = "vfe", |
308 | .clk_rate = -1 | ||
309 | }; | 307 | }; |
310 | 308 | ||
311 | static struct msm_iommu_dev vcodec_a_iommu = { | 309 | static struct msm_iommu_dev vcodec_a_iommu = { |
@@ -318,17 +316,14 @@ static struct msm_iommu_dev vcodec_b_iommu = { | |||
318 | 316 | ||
319 | static struct msm_iommu_dev gfx3d_iommu = { | 317 | static struct msm_iommu_dev gfx3d_iommu = { |
320 | .name = "gfx3d", | 318 | .name = "gfx3d", |
321 | .clk_rate = 27000000 | ||
322 | }; | 319 | }; |
323 | 320 | ||
324 | static struct msm_iommu_dev gfx2d0_iommu = { | 321 | static struct msm_iommu_dev gfx2d0_iommu = { |
325 | .name = "gfx2d0", | 322 | .name = "gfx2d0", |
326 | .clk_rate = 27000000 | ||
327 | }; | 323 | }; |
328 | 324 | ||
329 | static struct msm_iommu_dev gfx2d1_iommu = { | 325 | static struct msm_iommu_dev gfx2d1_iommu = { |
330 | .name = "gfx2d1", | 326 | .name = "gfx2d1", |
331 | .clk_rate = 27000000 | ||
332 | }; | 327 | }; |
333 | 328 | ||
334 | static struct platform_device msm_device_iommu_jpegd = { | 329 | static 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 | */ |
53 | struct msm_iommu_dev { | 49 | struct 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 | ||
33 | struct iommu_ctx_iter_data { | 34 | struct 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; | ||
240 | fail_io: | 249 | fail_io: |
241 | iounmap(regs_base); | 250 | iounmap(regs_base); |
242 | fail_mem: | 251 | fail_mem: |
243 | release_mem_region(r->start, len); | 252 | release_mem_region(r->start, len); |
253 | fail_clk: | ||
254 | if (iommu_clk) { | ||
255 | clk_disable(iommu_clk); | ||
256 | clk_put(iommu_clk); | ||
257 | } | ||
258 | fail_pclk: | ||
259 | clk_disable(iommu_pclk); | ||
260 | fail_enable: | ||
261 | clk_put(iommu_pclk); | ||
244 | fail: | 262 | fail: |
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; |
316 | fail: | 352 | fail: |
317 | kfree(ctx_drvdata); | 353 | kfree(ctx_drvdata); |