aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStepan Moskovchenko <stepanm@codeaurora.org>2011-02-28 19:03:02 -0500
committerDavid Brown <davidb@codeaurora.org>2011-03-08 17:40:58 -0500
commitb61401adf38f56dbfdac91f31425edf60595ed30 (patch)
treeeabe4fdc88d83a4df5afba29d1b899f227a3d901
parent41f3f5138a5ea71ee603f3d556953fce9aba3074 (diff)
msm: iommu: Rework clock logic and add IOMMU bus clock control
Clean up the clock control code in the probe calls, and add support for controlling the clock for the IOMMU bus interconnect. With the (proper) clock driver in place, the clock control logic in the probe function can be made much cleaner since it does not have to deal with the placeholder driver anymore. Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org> Reviewed-by: Trilok Soni <tsoni@codeaurora.org> Signed-off-by: David Brown <davidb@codeaurora.org>
-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);