diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/amba | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/amba')
-rw-r--r-- | drivers/amba/Makefile | 4 | ||||
-rw-r--r-- | drivers/amba/bus.c | 430 | ||||
-rw-r--r-- | drivers/amba/tegra-ahb.c | 290 |
3 files changed, 211 insertions, 513 deletions
diff --git a/drivers/amba/Makefile b/drivers/amba/Makefile index 66e81c2f1e3..40fe74097be 100644 --- a/drivers/amba/Makefile +++ b/drivers/amba/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | obj-$(CONFIG_ARM_AMBA) += bus.o | 1 | obj-y += bus.o |
2 | obj-$(CONFIG_TEGRA_AHB) += tegra-ahb.o | 2 | |
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index cdbad3a454a..d74926e0939 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c | |||
@@ -16,9 +16,9 @@ | |||
16 | #include <linux/pm.h> | 16 | #include <linux/pm.h> |
17 | #include <linux/pm_runtime.h> | 17 | #include <linux/pm_runtime.h> |
18 | #include <linux/amba/bus.h> | 18 | #include <linux/amba/bus.h> |
19 | #include <linux/sizes.h> | ||
20 | 19 | ||
21 | #include <asm/irq.h> | 20 | #include <asm/irq.h> |
21 | #include <asm/sizes.h> | ||
22 | 22 | ||
23 | #define to_amba_driver(d) container_of(d, struct amba_driver, drv) | 23 | #define to_amba_driver(d) container_of(d, struct amba_driver, drv) |
24 | 24 | ||
@@ -45,18 +45,18 @@ static int amba_match(struct device *dev, struct device_driver *drv) | |||
45 | return amba_lookup(pcdrv->id_table, pcdev) != NULL; | 45 | return amba_lookup(pcdrv->id_table, pcdev) != NULL; |
46 | } | 46 | } |
47 | 47 | ||
48 | #ifdef CONFIG_HOTPLUG | ||
48 | static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) | 49 | static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) |
49 | { | 50 | { |
50 | struct amba_device *pcdev = to_amba_device(dev); | 51 | struct amba_device *pcdev = to_amba_device(dev); |
51 | int retval = 0; | 52 | int retval = 0; |
52 | 53 | ||
53 | retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); | 54 | retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); |
54 | if (retval) | ||
55 | return retval; | ||
56 | |||
57 | retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid); | ||
58 | return retval; | 55 | return retval; |
59 | } | 56 | } |
57 | #else | ||
58 | #define amba_uevent NULL | ||
59 | #endif | ||
60 | 60 | ||
61 | #define amba_attr_func(name,fmt,arg...) \ | 61 | #define amba_attr_func(name,fmt,arg...) \ |
62 | static ssize_t name##_show(struct device *_dev, \ | 62 | static ssize_t name##_show(struct device *_dev, \ |
@@ -109,7 +109,31 @@ static int amba_legacy_resume(struct device *dev) | |||
109 | return ret; | 109 | return ret; |
110 | } | 110 | } |
111 | 111 | ||
112 | #endif /* CONFIG_PM_SLEEP */ | 112 | static int amba_pm_prepare(struct device *dev) |
113 | { | ||
114 | struct device_driver *drv = dev->driver; | ||
115 | int ret = 0; | ||
116 | |||
117 | if (drv && drv->pm && drv->pm->prepare) | ||
118 | ret = drv->pm->prepare(dev); | ||
119 | |||
120 | return ret; | ||
121 | } | ||
122 | |||
123 | static void amba_pm_complete(struct device *dev) | ||
124 | { | ||
125 | struct device_driver *drv = dev->driver; | ||
126 | |||
127 | if (drv && drv->pm && drv->pm->complete) | ||
128 | drv->pm->complete(dev); | ||
129 | } | ||
130 | |||
131 | #else /* !CONFIG_PM_SLEEP */ | ||
132 | |||
133 | #define amba_pm_prepare NULL | ||
134 | #define amba_pm_complete NULL | ||
135 | |||
136 | #endif /* !CONFIG_PM_SLEEP */ | ||
113 | 137 | ||
114 | #ifdef CONFIG_SUSPEND | 138 | #ifdef CONFIG_SUSPEND |
115 | 139 | ||
@@ -131,6 +155,22 @@ static int amba_pm_suspend(struct device *dev) | |||
131 | return ret; | 155 | return ret; |
132 | } | 156 | } |
133 | 157 | ||
158 | static int amba_pm_suspend_noirq(struct device *dev) | ||
159 | { | ||
160 | struct device_driver *drv = dev->driver; | ||
161 | int ret = 0; | ||
162 | |||
163 | if (!drv) | ||
164 | return 0; | ||
165 | |||
166 | if (drv->pm) { | ||
167 | if (drv->pm->suspend_noirq) | ||
168 | ret = drv->pm->suspend_noirq(dev); | ||
169 | } | ||
170 | |||
171 | return ret; | ||
172 | } | ||
173 | |||
134 | static int amba_pm_resume(struct device *dev) | 174 | static int amba_pm_resume(struct device *dev) |
135 | { | 175 | { |
136 | struct device_driver *drv = dev->driver; | 176 | struct device_driver *drv = dev->driver; |
@@ -149,10 +189,28 @@ static int amba_pm_resume(struct device *dev) | |||
149 | return ret; | 189 | return ret; |
150 | } | 190 | } |
151 | 191 | ||
192 | static int amba_pm_resume_noirq(struct device *dev) | ||
193 | { | ||
194 | struct device_driver *drv = dev->driver; | ||
195 | int ret = 0; | ||
196 | |||
197 | if (!drv) | ||
198 | return 0; | ||
199 | |||
200 | if (drv->pm) { | ||
201 | if (drv->pm->resume_noirq) | ||
202 | ret = drv->pm->resume_noirq(dev); | ||
203 | } | ||
204 | |||
205 | return ret; | ||
206 | } | ||
207 | |||
152 | #else /* !CONFIG_SUSPEND */ | 208 | #else /* !CONFIG_SUSPEND */ |
153 | 209 | ||
154 | #define amba_pm_suspend NULL | 210 | #define amba_pm_suspend NULL |
155 | #define amba_pm_resume NULL | 211 | #define amba_pm_resume NULL |
212 | #define amba_pm_suspend_noirq NULL | ||
213 | #define amba_pm_resume_noirq NULL | ||
156 | 214 | ||
157 | #endif /* !CONFIG_SUSPEND */ | 215 | #endif /* !CONFIG_SUSPEND */ |
158 | 216 | ||
@@ -176,6 +234,22 @@ static int amba_pm_freeze(struct device *dev) | |||
176 | return ret; | 234 | return ret; |
177 | } | 235 | } |
178 | 236 | ||
237 | static int amba_pm_freeze_noirq(struct device *dev) | ||
238 | { | ||
239 | struct device_driver *drv = dev->driver; | ||
240 | int ret = 0; | ||
241 | |||
242 | if (!drv) | ||
243 | return 0; | ||
244 | |||
245 | if (drv->pm) { | ||
246 | if (drv->pm->freeze_noirq) | ||
247 | ret = drv->pm->freeze_noirq(dev); | ||
248 | } | ||
249 | |||
250 | return ret; | ||
251 | } | ||
252 | |||
179 | static int amba_pm_thaw(struct device *dev) | 253 | static int amba_pm_thaw(struct device *dev) |
180 | { | 254 | { |
181 | struct device_driver *drv = dev->driver; | 255 | struct device_driver *drv = dev->driver; |
@@ -194,6 +268,22 @@ static int amba_pm_thaw(struct device *dev) | |||
194 | return ret; | 268 | return ret; |
195 | } | 269 | } |
196 | 270 | ||
271 | static int amba_pm_thaw_noirq(struct device *dev) | ||
272 | { | ||
273 | struct device_driver *drv = dev->driver; | ||
274 | int ret = 0; | ||
275 | |||
276 | if (!drv) | ||
277 | return 0; | ||
278 | |||
279 | if (drv->pm) { | ||
280 | if (drv->pm->thaw_noirq) | ||
281 | ret = drv->pm->thaw_noirq(dev); | ||
282 | } | ||
283 | |||
284 | return ret; | ||
285 | } | ||
286 | |||
197 | static int amba_pm_poweroff(struct device *dev) | 287 | static int amba_pm_poweroff(struct device *dev) |
198 | { | 288 | { |
199 | struct device_driver *drv = dev->driver; | 289 | struct device_driver *drv = dev->driver; |
@@ -212,6 +302,22 @@ static int amba_pm_poweroff(struct device *dev) | |||
212 | return ret; | 302 | return ret; |
213 | } | 303 | } |
214 | 304 | ||
305 | static int amba_pm_poweroff_noirq(struct device *dev) | ||
306 | { | ||
307 | struct device_driver *drv = dev->driver; | ||
308 | int ret = 0; | ||
309 | |||
310 | if (!drv) | ||
311 | return 0; | ||
312 | |||
313 | if (drv->pm) { | ||
314 | if (drv->pm->poweroff_noirq) | ||
315 | ret = drv->pm->poweroff_noirq(dev); | ||
316 | } | ||
317 | |||
318 | return ret; | ||
319 | } | ||
320 | |||
215 | static int amba_pm_restore(struct device *dev) | 321 | static int amba_pm_restore(struct device *dev) |
216 | { | 322 | { |
217 | struct device_driver *drv = dev->driver; | 323 | struct device_driver *drv = dev->driver; |
@@ -230,60 +336,55 @@ static int amba_pm_restore(struct device *dev) | |||
230 | return ret; | 336 | return ret; |
231 | } | 337 | } |
232 | 338 | ||
233 | #else /* !CONFIG_HIBERNATE_CALLBACKS */ | 339 | static int amba_pm_restore_noirq(struct device *dev) |
234 | |||
235 | #define amba_pm_freeze NULL | ||
236 | #define amba_pm_thaw NULL | ||
237 | #define amba_pm_poweroff NULL | ||
238 | #define amba_pm_restore NULL | ||
239 | |||
240 | #endif /* !CONFIG_HIBERNATE_CALLBACKS */ | ||
241 | |||
242 | #ifdef CONFIG_PM_RUNTIME | ||
243 | /* | ||
244 | * Hooks to provide runtime PM of the pclk (bus clock). It is safe to | ||
245 | * enable/disable the bus clock at runtime PM suspend/resume as this | ||
246 | * does not result in loss of context. | ||
247 | */ | ||
248 | static int amba_pm_runtime_suspend(struct device *dev) | ||
249 | { | 340 | { |
250 | struct amba_device *pcdev = to_amba_device(dev); | 341 | struct device_driver *drv = dev->driver; |
251 | int ret = pm_generic_runtime_suspend(dev); | 342 | int ret = 0; |
252 | 343 | ||
253 | if (ret == 0 && dev->driver) | 344 | if (!drv) |
254 | clk_disable(pcdev->pclk); | 345 | return 0; |
346 | |||
347 | if (drv->pm) { | ||
348 | if (drv->pm->restore_noirq) | ||
349 | ret = drv->pm->restore_noirq(dev); | ||
350 | } | ||
255 | 351 | ||
256 | return ret; | 352 | return ret; |
257 | } | 353 | } |
258 | 354 | ||
259 | static int amba_pm_runtime_resume(struct device *dev) | 355 | #else /* !CONFIG_HIBERNATE_CALLBACKS */ |
260 | { | ||
261 | struct amba_device *pcdev = to_amba_device(dev); | ||
262 | int ret; | ||
263 | 356 | ||
264 | if (dev->driver) { | 357 | #define amba_pm_freeze NULL |
265 | ret = clk_enable(pcdev->pclk); | 358 | #define amba_pm_thaw NULL |
266 | /* Failure is probably fatal to the system, but... */ | 359 | #define amba_pm_poweroff NULL |
267 | if (ret) | 360 | #define amba_pm_restore NULL |
268 | return ret; | 361 | #define amba_pm_freeze_noirq NULL |
269 | } | 362 | #define amba_pm_thaw_noirq NULL |
363 | #define amba_pm_poweroff_noirq NULL | ||
364 | #define amba_pm_restore_noirq NULL | ||
270 | 365 | ||
271 | return pm_generic_runtime_resume(dev); | 366 | #endif /* !CONFIG_HIBERNATE_CALLBACKS */ |
272 | } | ||
273 | #endif | ||
274 | 367 | ||
275 | #ifdef CONFIG_PM | 368 | #ifdef CONFIG_PM |
276 | 369 | ||
277 | static const struct dev_pm_ops amba_pm = { | 370 | static const struct dev_pm_ops amba_pm = { |
371 | .prepare = amba_pm_prepare, | ||
372 | .complete = amba_pm_complete, | ||
278 | .suspend = amba_pm_suspend, | 373 | .suspend = amba_pm_suspend, |
279 | .resume = amba_pm_resume, | 374 | .resume = amba_pm_resume, |
280 | .freeze = amba_pm_freeze, | 375 | .freeze = amba_pm_freeze, |
281 | .thaw = amba_pm_thaw, | 376 | .thaw = amba_pm_thaw, |
282 | .poweroff = amba_pm_poweroff, | 377 | .poweroff = amba_pm_poweroff, |
283 | .restore = amba_pm_restore, | 378 | .restore = amba_pm_restore, |
379 | .suspend_noirq = amba_pm_suspend_noirq, | ||
380 | .resume_noirq = amba_pm_resume_noirq, | ||
381 | .freeze_noirq = amba_pm_freeze_noirq, | ||
382 | .thaw_noirq = amba_pm_thaw_noirq, | ||
383 | .poweroff_noirq = amba_pm_poweroff_noirq, | ||
384 | .restore_noirq = amba_pm_restore_noirq, | ||
284 | SET_RUNTIME_PM_OPS( | 385 | SET_RUNTIME_PM_OPS( |
285 | amba_pm_runtime_suspend, | 386 | pm_generic_runtime_suspend, |
286 | amba_pm_runtime_resume, | 387 | pm_generic_runtime_resume, |
287 | pm_generic_runtime_idle | 388 | pm_generic_runtime_idle |
288 | ) | 389 | ) |
289 | }; | 390 | }; |
@@ -325,17 +426,9 @@ static int amba_get_enable_pclk(struct amba_device *pcdev) | |||
325 | if (IS_ERR(pclk)) | 426 | if (IS_ERR(pclk)) |
326 | return PTR_ERR(pclk); | 427 | return PTR_ERR(pclk); |
327 | 428 | ||
328 | ret = clk_prepare(pclk); | ||
329 | if (ret) { | ||
330 | clk_put(pclk); | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | ret = clk_enable(pclk); | 429 | ret = clk_enable(pclk); |
335 | if (ret) { | 430 | if (ret) |
336 | clk_unprepare(pclk); | ||
337 | clk_put(pclk); | 431 | clk_put(pclk); |
338 | } | ||
339 | 432 | ||
340 | return ret; | 433 | return ret; |
341 | } | 434 | } |
@@ -345,10 +438,42 @@ static void amba_put_disable_pclk(struct amba_device *pcdev) | |||
345 | struct clk *pclk = pcdev->pclk; | 438 | struct clk *pclk = pcdev->pclk; |
346 | 439 | ||
347 | clk_disable(pclk); | 440 | clk_disable(pclk); |
348 | clk_unprepare(pclk); | ||
349 | clk_put(pclk); | 441 | clk_put(pclk); |
350 | } | 442 | } |
351 | 443 | ||
444 | static int amba_get_enable_vcore(struct amba_device *pcdev) | ||
445 | { | ||
446 | struct regulator *vcore = regulator_get(&pcdev->dev, "vcore"); | ||
447 | int ret; | ||
448 | |||
449 | pcdev->vcore = vcore; | ||
450 | |||
451 | if (IS_ERR(vcore)) { | ||
452 | /* It is OK not to supply a vcore regulator */ | ||
453 | if (PTR_ERR(vcore) == -ENODEV) | ||
454 | return 0; | ||
455 | return PTR_ERR(vcore); | ||
456 | } | ||
457 | |||
458 | ret = regulator_enable(vcore); | ||
459 | if (ret) { | ||
460 | regulator_put(vcore); | ||
461 | pcdev->vcore = ERR_PTR(-ENODEV); | ||
462 | } | ||
463 | |||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | static void amba_put_disable_vcore(struct amba_device *pcdev) | ||
468 | { | ||
469 | struct regulator *vcore = pcdev->vcore; | ||
470 | |||
471 | if (!IS_ERR(vcore)) { | ||
472 | regulator_disable(vcore); | ||
473 | regulator_put(vcore); | ||
474 | } | ||
475 | } | ||
476 | |||
352 | /* | 477 | /* |
353 | * These are the device model conversion veneers; they convert the | 478 | * These are the device model conversion veneers; they convert the |
354 | * device model structures to our more specific structures. | 479 | * device model structures to our more specific structures. |
@@ -361,23 +486,20 @@ static int amba_probe(struct device *dev) | |||
361 | int ret; | 486 | int ret; |
362 | 487 | ||
363 | do { | 488 | do { |
364 | ret = amba_get_enable_pclk(pcdev); | 489 | ret = amba_get_enable_vcore(pcdev); |
365 | if (ret) | 490 | if (ret) |
366 | break; | 491 | break; |
367 | 492 | ||
368 | pm_runtime_get_noresume(dev); | 493 | ret = amba_get_enable_pclk(pcdev); |
369 | pm_runtime_set_active(dev); | 494 | if (ret) |
370 | pm_runtime_enable(dev); | 495 | break; |
371 | 496 | ||
372 | ret = pcdrv->probe(pcdev, id); | 497 | ret = pcdrv->probe(pcdev, id); |
373 | if (ret == 0) | 498 | if (ret == 0) |
374 | break; | 499 | break; |
375 | 500 | ||
376 | pm_runtime_disable(dev); | ||
377 | pm_runtime_set_suspended(dev); | ||
378 | pm_runtime_put_noidle(dev); | ||
379 | |||
380 | amba_put_disable_pclk(pcdev); | 501 | amba_put_disable_pclk(pcdev); |
502 | amba_put_disable_vcore(pcdev); | ||
381 | } while (0); | 503 | } while (0); |
382 | 504 | ||
383 | return ret; | 505 | return ret; |
@@ -387,18 +509,10 @@ static int amba_remove(struct device *dev) | |||
387 | { | 509 | { |
388 | struct amba_device *pcdev = to_amba_device(dev); | 510 | struct amba_device *pcdev = to_amba_device(dev); |
389 | struct amba_driver *drv = to_amba_driver(dev->driver); | 511 | struct amba_driver *drv = to_amba_driver(dev->driver); |
390 | int ret; | 512 | int ret = drv->remove(pcdev); |
391 | |||
392 | pm_runtime_get_sync(dev); | ||
393 | ret = drv->remove(pcdev); | ||
394 | pm_runtime_put_noidle(dev); | ||
395 | |||
396 | /* Undo the runtime PM settings in amba_probe() */ | ||
397 | pm_runtime_disable(dev); | ||
398 | pm_runtime_set_suspended(dev); | ||
399 | pm_runtime_put_noidle(dev); | ||
400 | 513 | ||
401 | amba_put_disable_pclk(pcdev); | 514 | amba_put_disable_pclk(pcdev); |
515 | amba_put_disable_vcore(pcdev); | ||
402 | 516 | ||
403 | return ret; | 517 | return ret; |
404 | } | 518 | } |
@@ -453,22 +567,37 @@ static void amba_device_release(struct device *dev) | |||
453 | } | 567 | } |
454 | 568 | ||
455 | /** | 569 | /** |
456 | * amba_device_add - add a previously allocated AMBA device structure | 570 | * amba_device_register - register an AMBA device |
457 | * @dev: AMBA device allocated by amba_device_alloc | 571 | * @dev: AMBA device to register |
458 | * @parent: resource parent for this devices resources | 572 | * @parent: parent memory resource |
459 | * | 573 | * |
460 | * Claim the resource, and read the device cell ID if not already | 574 | * Setup the AMBA device, reading the cell ID if present. |
461 | * initialized. Register the AMBA device with the Linux device | 575 | * Claim the resource, and register the AMBA device with |
462 | * manager. | 576 | * the Linux device manager. |
463 | */ | 577 | */ |
464 | int amba_device_add(struct amba_device *dev, struct resource *parent) | 578 | int amba_device_register(struct amba_device *dev, struct resource *parent) |
465 | { | 579 | { |
466 | u32 size; | 580 | u32 size; |
467 | void __iomem *tmp; | 581 | void __iomem *tmp; |
468 | int i, ret; | 582 | int i, ret; |
469 | 583 | ||
470 | WARN_ON(dev->irq[0] == (unsigned int)-1); | 584 | device_initialize(&dev->dev); |
471 | WARN_ON(dev->irq[1] == (unsigned int)-1); | 585 | |
586 | /* | ||
587 | * Copy from device_add | ||
588 | */ | ||
589 | if (dev->dev.init_name) { | ||
590 | dev_set_name(&dev->dev, "%s", dev->dev.init_name); | ||
591 | dev->dev.init_name = NULL; | ||
592 | } | ||
593 | |||
594 | dev->dev.release = amba_device_release; | ||
595 | dev->dev.bus = &amba_bustype; | ||
596 | dev->dev.dma_mask = &dev->dma_mask; | ||
597 | dev->res.name = dev_name(&dev->dev); | ||
598 | |||
599 | if (!dev->dev.coherent_dma_mask && dev->dma_mask) | ||
600 | dev_warn(&dev->dev, "coherent dma mask is unset\n"); | ||
472 | 601 | ||
473 | ret = request_resource(parent, &dev->res); | 602 | ret = request_resource(parent, &dev->res); |
474 | if (ret) | 603 | if (ret) |
@@ -523,9 +652,9 @@ int amba_device_add(struct amba_device *dev, struct resource *parent) | |||
523 | if (ret) | 652 | if (ret) |
524 | goto err_release; | 653 | goto err_release; |
525 | 654 | ||
526 | if (dev->irq[0]) | 655 | if (dev->irq[0] != NO_IRQ) |
527 | ret = device_create_file(&dev->dev, &dev_attr_irq0); | 656 | ret = device_create_file(&dev->dev, &dev_attr_irq0); |
528 | if (ret == 0 && dev->irq[1]) | 657 | if (ret == 0 && dev->irq[1] != NO_IRQ) |
529 | ret = device_create_file(&dev->dev, &dev_attr_irq1); | 658 | ret = device_create_file(&dev->dev, &dev_attr_irq1); |
530 | if (ret == 0) | 659 | if (ret == 0) |
531 | return ret; | 660 | return ret; |
@@ -537,147 +666,6 @@ int amba_device_add(struct amba_device *dev, struct resource *parent) | |||
537 | err_out: | 666 | err_out: |
538 | return ret; | 667 | return ret; |
539 | } | 668 | } |
540 | EXPORT_SYMBOL_GPL(amba_device_add); | ||
541 | |||
542 | static struct amba_device * | ||
543 | amba_aphb_device_add(struct device *parent, const char *name, | ||
544 | resource_size_t base, size_t size, int irq1, int irq2, | ||
545 | void *pdata, unsigned int periphid, u64 dma_mask, | ||
546 | struct resource *resbase) | ||
547 | { | ||
548 | struct amba_device *dev; | ||
549 | int ret; | ||
550 | |||
551 | dev = amba_device_alloc(name, base, size); | ||
552 | if (!dev) | ||
553 | return ERR_PTR(-ENOMEM); | ||
554 | |||
555 | dev->dma_mask = dma_mask; | ||
556 | dev->dev.coherent_dma_mask = dma_mask; | ||
557 | dev->irq[0] = irq1; | ||
558 | dev->irq[1] = irq2; | ||
559 | dev->periphid = periphid; | ||
560 | dev->dev.platform_data = pdata; | ||
561 | dev->dev.parent = parent; | ||
562 | |||
563 | ret = amba_device_add(dev, resbase); | ||
564 | if (ret) { | ||
565 | amba_device_put(dev); | ||
566 | return ERR_PTR(ret); | ||
567 | } | ||
568 | |||
569 | return dev; | ||
570 | } | ||
571 | |||
572 | struct amba_device * | ||
573 | amba_apb_device_add(struct device *parent, const char *name, | ||
574 | resource_size_t base, size_t size, int irq1, int irq2, | ||
575 | void *pdata, unsigned int periphid) | ||
576 | { | ||
577 | return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, | ||
578 | periphid, 0, &iomem_resource); | ||
579 | } | ||
580 | EXPORT_SYMBOL_GPL(amba_apb_device_add); | ||
581 | |||
582 | struct amba_device * | ||
583 | amba_ahb_device_add(struct device *parent, const char *name, | ||
584 | resource_size_t base, size_t size, int irq1, int irq2, | ||
585 | void *pdata, unsigned int periphid) | ||
586 | { | ||
587 | return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, | ||
588 | periphid, ~0ULL, &iomem_resource); | ||
589 | } | ||
590 | EXPORT_SYMBOL_GPL(amba_ahb_device_add); | ||
591 | |||
592 | struct amba_device * | ||
593 | amba_apb_device_add_res(struct device *parent, const char *name, | ||
594 | resource_size_t base, size_t size, int irq1, | ||
595 | int irq2, void *pdata, unsigned int periphid, | ||
596 | struct resource *resbase) | ||
597 | { | ||
598 | return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, | ||
599 | periphid, 0, resbase); | ||
600 | } | ||
601 | EXPORT_SYMBOL_GPL(amba_apb_device_add_res); | ||
602 | |||
603 | struct amba_device * | ||
604 | amba_ahb_device_add_res(struct device *parent, const char *name, | ||
605 | resource_size_t base, size_t size, int irq1, | ||
606 | int irq2, void *pdata, unsigned int periphid, | ||
607 | struct resource *resbase) | ||
608 | { | ||
609 | return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, | ||
610 | periphid, ~0ULL, resbase); | ||
611 | } | ||
612 | EXPORT_SYMBOL_GPL(amba_ahb_device_add_res); | ||
613 | |||
614 | |||
615 | static void amba_device_initialize(struct amba_device *dev, const char *name) | ||
616 | { | ||
617 | device_initialize(&dev->dev); | ||
618 | if (name) | ||
619 | dev_set_name(&dev->dev, "%s", name); | ||
620 | dev->dev.release = amba_device_release; | ||
621 | dev->dev.bus = &amba_bustype; | ||
622 | dev->dev.dma_mask = &dev->dma_mask; | ||
623 | dev->res.name = dev_name(&dev->dev); | ||
624 | } | ||
625 | |||
626 | /** | ||
627 | * amba_device_alloc - allocate an AMBA device | ||
628 | * @name: sysfs name of the AMBA device | ||
629 | * @base: base of AMBA device | ||
630 | * @size: size of AMBA device | ||
631 | * | ||
632 | * Allocate and initialize an AMBA device structure. Returns %NULL | ||
633 | * on failure. | ||
634 | */ | ||
635 | struct amba_device *amba_device_alloc(const char *name, resource_size_t base, | ||
636 | size_t size) | ||
637 | { | ||
638 | struct amba_device *dev; | ||
639 | |||
640 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
641 | if (dev) { | ||
642 | amba_device_initialize(dev, name); | ||
643 | dev->res.start = base; | ||
644 | dev->res.end = base + size - 1; | ||
645 | dev->res.flags = IORESOURCE_MEM; | ||
646 | } | ||
647 | |||
648 | return dev; | ||
649 | } | ||
650 | EXPORT_SYMBOL_GPL(amba_device_alloc); | ||
651 | |||
652 | /** | ||
653 | * amba_device_register - register an AMBA device | ||
654 | * @dev: AMBA device to register | ||
655 | * @parent: parent memory resource | ||
656 | * | ||
657 | * Setup the AMBA device, reading the cell ID if present. | ||
658 | * Claim the resource, and register the AMBA device with | ||
659 | * the Linux device manager. | ||
660 | */ | ||
661 | int amba_device_register(struct amba_device *dev, struct resource *parent) | ||
662 | { | ||
663 | amba_device_initialize(dev, dev->dev.init_name); | ||
664 | dev->dev.init_name = NULL; | ||
665 | |||
666 | if (!dev->dev.coherent_dma_mask && dev->dma_mask) | ||
667 | dev_warn(&dev->dev, "coherent dma mask is unset\n"); | ||
668 | |||
669 | return amba_device_add(dev, parent); | ||
670 | } | ||
671 | |||
672 | /** | ||
673 | * amba_device_put - put an AMBA device | ||
674 | * @dev: AMBA device to put | ||
675 | */ | ||
676 | void amba_device_put(struct amba_device *dev) | ||
677 | { | ||
678 | put_device(&dev->dev); | ||
679 | } | ||
680 | EXPORT_SYMBOL_GPL(amba_device_put); | ||
681 | 669 | ||
682 | /** | 670 | /** |
683 | * amba_device_unregister - unregister an AMBA device | 671 | * amba_device_unregister - unregister an AMBA device |
diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c deleted file mode 100644 index 536c166f425..00000000000 --- a/drivers/amba/tegra-ahb.c +++ /dev/null | |||
@@ -1,290 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * Copyright (C) 2011 Google, Inc. | ||
4 | * | ||
5 | * Author: | ||
6 | * Jay Cheng <jacheng@nvidia.com> | ||
7 | * James Wylder <james.wylder@motorola.com> | ||
8 | * Benoit Goby <benoit@android.com> | ||
9 | * Colin Cross <ccross@android.com> | ||
10 | * Hiroshi DOYU <hdoyu@nvidia.com> | ||
11 | * | ||
12 | * This software is licensed under the terms of the GNU General Public | ||
13 | * License version 2, as published by the Free Software Foundation, and | ||
14 | * may be copied, distributed, and modified under those terms. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/tegra-ahb.h> | ||
28 | |||
29 | #define DRV_NAME "tegra-ahb" | ||
30 | |||
31 | #define AHB_ARBITRATION_DISABLE 0x00 | ||
32 | #define AHB_ARBITRATION_PRIORITY_CTRL 0x04 | ||
33 | #define AHB_PRIORITY_WEIGHT(x) (((x) & 0x7) << 29) | ||
34 | #define PRIORITY_SELECT_USB BIT(6) | ||
35 | #define PRIORITY_SELECT_USB2 BIT(18) | ||
36 | #define PRIORITY_SELECT_USB3 BIT(17) | ||
37 | |||
38 | #define AHB_GIZMO_AHB_MEM 0x0c | ||
39 | #define ENB_FAST_REARBITRATE BIT(2) | ||
40 | #define DONT_SPLIT_AHB_WR BIT(7) | ||
41 | |||
42 | #define AHB_GIZMO_APB_DMA 0x10 | ||
43 | #define AHB_GIZMO_IDE 0x18 | ||
44 | #define AHB_GIZMO_USB 0x1c | ||
45 | #define AHB_GIZMO_AHB_XBAR_BRIDGE 0x20 | ||
46 | #define AHB_GIZMO_CPU_AHB_BRIDGE 0x24 | ||
47 | #define AHB_GIZMO_COP_AHB_BRIDGE 0x28 | ||
48 | #define AHB_GIZMO_XBAR_APB_CTLR 0x2c | ||
49 | #define AHB_GIZMO_VCP_AHB_BRIDGE 0x30 | ||
50 | #define AHB_GIZMO_NAND 0x3c | ||
51 | #define AHB_GIZMO_SDMMC4 0x44 | ||
52 | #define AHB_GIZMO_XIO 0x48 | ||
53 | #define AHB_GIZMO_BSEV 0x60 | ||
54 | #define AHB_GIZMO_BSEA 0x70 | ||
55 | #define AHB_GIZMO_NOR 0x74 | ||
56 | #define AHB_GIZMO_USB2 0x78 | ||
57 | #define AHB_GIZMO_USB3 0x7c | ||
58 | #define IMMEDIATE BIT(18) | ||
59 | |||
60 | #define AHB_GIZMO_SDMMC1 0x80 | ||
61 | #define AHB_GIZMO_SDMMC2 0x84 | ||
62 | #define AHB_GIZMO_SDMMC3 0x88 | ||
63 | #define AHB_MEM_PREFETCH_CFG_X 0xd8 | ||
64 | #define AHB_ARBITRATION_XBAR_CTRL 0xdc | ||
65 | #define AHB_MEM_PREFETCH_CFG3 0xe0 | ||
66 | #define AHB_MEM_PREFETCH_CFG4 0xe4 | ||
67 | #define AHB_MEM_PREFETCH_CFG1 0xec | ||
68 | #define AHB_MEM_PREFETCH_CFG2 0xf0 | ||
69 | #define PREFETCH_ENB BIT(31) | ||
70 | #define MST_ID(x) (((x) & 0x1f) << 26) | ||
71 | #define AHBDMA_MST_ID MST_ID(5) | ||
72 | #define USB_MST_ID MST_ID(6) | ||
73 | #define USB2_MST_ID MST_ID(18) | ||
74 | #define USB3_MST_ID MST_ID(17) | ||
75 | #define ADDR_BNDRY(x) (((x) & 0xf) << 21) | ||
76 | #define INACTIVITY_TIMEOUT(x) (((x) & 0xffff) << 0) | ||
77 | |||
78 | #define AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID 0xf8 | ||
79 | |||
80 | #define AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE BIT(17) | ||
81 | |||
82 | static struct platform_driver tegra_ahb_driver; | ||
83 | |||
84 | static const u32 tegra_ahb_gizmo[] = { | ||
85 | AHB_ARBITRATION_DISABLE, | ||
86 | AHB_ARBITRATION_PRIORITY_CTRL, | ||
87 | AHB_GIZMO_AHB_MEM, | ||
88 | AHB_GIZMO_APB_DMA, | ||
89 | AHB_GIZMO_IDE, | ||
90 | AHB_GIZMO_USB, | ||
91 | AHB_GIZMO_AHB_XBAR_BRIDGE, | ||
92 | AHB_GIZMO_CPU_AHB_BRIDGE, | ||
93 | AHB_GIZMO_COP_AHB_BRIDGE, | ||
94 | AHB_GIZMO_XBAR_APB_CTLR, | ||
95 | AHB_GIZMO_VCP_AHB_BRIDGE, | ||
96 | AHB_GIZMO_NAND, | ||
97 | AHB_GIZMO_SDMMC4, | ||
98 | AHB_GIZMO_XIO, | ||
99 | AHB_GIZMO_BSEV, | ||
100 | AHB_GIZMO_BSEA, | ||
101 | AHB_GIZMO_NOR, | ||
102 | AHB_GIZMO_USB2, | ||
103 | AHB_GIZMO_USB3, | ||
104 | AHB_GIZMO_SDMMC1, | ||
105 | AHB_GIZMO_SDMMC2, | ||
106 | AHB_GIZMO_SDMMC3, | ||
107 | AHB_MEM_PREFETCH_CFG_X, | ||
108 | AHB_ARBITRATION_XBAR_CTRL, | ||
109 | AHB_MEM_PREFETCH_CFG3, | ||
110 | AHB_MEM_PREFETCH_CFG4, | ||
111 | AHB_MEM_PREFETCH_CFG1, | ||
112 | AHB_MEM_PREFETCH_CFG2, | ||
113 | AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID, | ||
114 | }; | ||
115 | |||
116 | struct tegra_ahb { | ||
117 | void __iomem *regs; | ||
118 | struct device *dev; | ||
119 | u32 ctx[0]; | ||
120 | }; | ||
121 | |||
122 | static inline u32 gizmo_readl(struct tegra_ahb *ahb, u32 offset) | ||
123 | { | ||
124 | return readl(ahb->regs + offset); | ||
125 | } | ||
126 | |||
127 | static inline void gizmo_writel(struct tegra_ahb *ahb, u32 value, u32 offset) | ||
128 | { | ||
129 | writel(value, ahb->regs + offset); | ||
130 | } | ||
131 | |||
132 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
133 | static int tegra_ahb_match_by_smmu(struct device *dev, void *data) | ||
134 | { | ||
135 | struct tegra_ahb *ahb = dev_get_drvdata(dev); | ||
136 | struct device_node *dn = data; | ||
137 | |||
138 | return (ahb->dev->of_node == dn) ? 1 : 0; | ||
139 | } | ||
140 | |||
141 | int tegra_ahb_enable_smmu(struct device_node *dn) | ||
142 | { | ||
143 | struct device *dev; | ||
144 | u32 val; | ||
145 | struct tegra_ahb *ahb; | ||
146 | |||
147 | dev = driver_find_device(&tegra_ahb_driver.driver, NULL, dn, | ||
148 | tegra_ahb_match_by_smmu); | ||
149 | if (!dev) | ||
150 | return -EPROBE_DEFER; | ||
151 | ahb = dev_get_drvdata(dev); | ||
152 | val = gizmo_readl(ahb, AHB_ARBITRATION_XBAR_CTRL); | ||
153 | val |= AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE; | ||
154 | gizmo_writel(ahb, val, AHB_ARBITRATION_XBAR_CTRL); | ||
155 | return 0; | ||
156 | } | ||
157 | EXPORT_SYMBOL(tegra_ahb_enable_smmu); | ||
158 | #endif | ||
159 | |||
160 | #ifdef CONFIG_PM_SLEEP | ||
161 | static int tegra_ahb_suspend(struct device *dev) | ||
162 | { | ||
163 | int i; | ||
164 | struct tegra_ahb *ahb = dev_get_drvdata(dev); | ||
165 | |||
166 | for (i = 0; i < ARRAY_SIZE(tegra_ahb_gizmo); i++) | ||
167 | ahb->ctx[i] = gizmo_readl(ahb, tegra_ahb_gizmo[i]); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int tegra_ahb_resume(struct device *dev) | ||
172 | { | ||
173 | int i; | ||
174 | struct tegra_ahb *ahb = dev_get_drvdata(dev); | ||
175 | |||
176 | for (i = 0; i < ARRAY_SIZE(tegra_ahb_gizmo); i++) | ||
177 | gizmo_writel(ahb, ahb->ctx[i], tegra_ahb_gizmo[i]); | ||
178 | return 0; | ||
179 | } | ||
180 | #endif | ||
181 | |||
182 | static UNIVERSAL_DEV_PM_OPS(tegra_ahb_pm, | ||
183 | tegra_ahb_suspend, | ||
184 | tegra_ahb_resume, NULL); | ||
185 | |||
186 | static void tegra_ahb_gizmo_init(struct tegra_ahb *ahb) | ||
187 | { | ||
188 | u32 val; | ||
189 | |||
190 | val = gizmo_readl(ahb, AHB_GIZMO_AHB_MEM); | ||
191 | val |= ENB_FAST_REARBITRATE | IMMEDIATE | DONT_SPLIT_AHB_WR; | ||
192 | gizmo_writel(ahb, val, AHB_GIZMO_AHB_MEM); | ||
193 | |||
194 | val = gizmo_readl(ahb, AHB_GIZMO_USB); | ||
195 | val |= IMMEDIATE; | ||
196 | gizmo_writel(ahb, val, AHB_GIZMO_USB); | ||
197 | |||
198 | val = gizmo_readl(ahb, AHB_GIZMO_USB2); | ||
199 | val |= IMMEDIATE; | ||
200 | gizmo_writel(ahb, val, AHB_GIZMO_USB2); | ||
201 | |||
202 | val = gizmo_readl(ahb, AHB_GIZMO_USB3); | ||
203 | val |= IMMEDIATE; | ||
204 | gizmo_writel(ahb, val, AHB_GIZMO_USB3); | ||
205 | |||
206 | val = gizmo_readl(ahb, AHB_ARBITRATION_PRIORITY_CTRL); | ||
207 | val |= PRIORITY_SELECT_USB | | ||
208 | PRIORITY_SELECT_USB2 | | ||
209 | PRIORITY_SELECT_USB3 | | ||
210 | AHB_PRIORITY_WEIGHT(7); | ||
211 | gizmo_writel(ahb, val, AHB_ARBITRATION_PRIORITY_CTRL); | ||
212 | |||
213 | val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG1); | ||
214 | val &= ~MST_ID(~0); | ||
215 | val |= PREFETCH_ENB | | ||
216 | AHBDMA_MST_ID | | ||
217 | ADDR_BNDRY(0xc) | | ||
218 | INACTIVITY_TIMEOUT(0x1000); | ||
219 | gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG1); | ||
220 | |||
221 | val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG2); | ||
222 | val &= ~MST_ID(~0); | ||
223 | val |= PREFETCH_ENB | | ||
224 | USB_MST_ID | | ||
225 | ADDR_BNDRY(0xc) | | ||
226 | INACTIVITY_TIMEOUT(0x1000); | ||
227 | gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG2); | ||
228 | |||
229 | val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG3); | ||
230 | val &= ~MST_ID(~0); | ||
231 | val |= PREFETCH_ENB | | ||
232 | USB3_MST_ID | | ||
233 | ADDR_BNDRY(0xc) | | ||
234 | INACTIVITY_TIMEOUT(0x1000); | ||
235 | gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG3); | ||
236 | |||
237 | val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG4); | ||
238 | val &= ~MST_ID(~0); | ||
239 | val |= PREFETCH_ENB | | ||
240 | USB2_MST_ID | | ||
241 | ADDR_BNDRY(0xc) | | ||
242 | INACTIVITY_TIMEOUT(0x1000); | ||
243 | gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG4); | ||
244 | } | ||
245 | |||
246 | static int tegra_ahb_probe(struct platform_device *pdev) | ||
247 | { | ||
248 | struct resource *res; | ||
249 | struct tegra_ahb *ahb; | ||
250 | size_t bytes; | ||
251 | |||
252 | bytes = sizeof(*ahb) + sizeof(u32) * ARRAY_SIZE(tegra_ahb_gizmo); | ||
253 | ahb = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL); | ||
254 | if (!ahb) | ||
255 | return -ENOMEM; | ||
256 | |||
257 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
258 | if (!res) | ||
259 | return -ENODEV; | ||
260 | ahb->regs = devm_request_and_ioremap(&pdev->dev, res); | ||
261 | if (!ahb->regs) | ||
262 | return -EBUSY; | ||
263 | |||
264 | ahb->dev = &pdev->dev; | ||
265 | platform_set_drvdata(pdev, ahb); | ||
266 | tegra_ahb_gizmo_init(ahb); | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static const struct of_device_id tegra_ahb_of_match[] = { | ||
271 | { .compatible = "nvidia,tegra30-ahb", }, | ||
272 | { .compatible = "nvidia,tegra20-ahb", }, | ||
273 | {}, | ||
274 | }; | ||
275 | |||
276 | static struct platform_driver tegra_ahb_driver = { | ||
277 | .probe = tegra_ahb_probe, | ||
278 | .driver = { | ||
279 | .name = DRV_NAME, | ||
280 | .owner = THIS_MODULE, | ||
281 | .of_match_table = tegra_ahb_of_match, | ||
282 | .pm = &tegra_ahb_pm, | ||
283 | }, | ||
284 | }; | ||
285 | module_platform_driver(tegra_ahb_driver); | ||
286 | |||
287 | MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); | ||
288 | MODULE_DESCRIPTION("Tegra AHB driver"); | ||
289 | MODULE_LICENSE("GPL v2"); | ||
290 | MODULE_ALIAS("platform:" DRV_NAME); | ||