aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra/host/bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/host/bus.c')
-rw-r--r--drivers/video/tegra/host/bus.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/drivers/video/tegra/host/bus.c b/drivers/video/tegra/host/bus.c
new file mode 100644
index 00000000000..774aac7bd43
--- /dev/null
+++ b/drivers/video/tegra/host/bus.c
@@ -0,0 +1,569 @@
1/*
2 * drivers/video/tegra/host/bus.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@google.com>
6 *
7 * Copyright (C) 2010-2012 NVIDIA Corporation
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/pm_runtime.h>
21#include <linux/nvhost.h>
22
23#include "dev.h"
24
25struct nvhost_master *nvhost;
26
27struct resource *nvhost_get_resource(struct nvhost_device *dev,
28 unsigned int type, unsigned int num)
29{
30 int i;
31
32 for (i = 0; i < dev->num_resources; i++) {
33 struct resource *r = &dev->resource[i];
34
35 if (type == resource_type(r) && num-- == 0)
36 return r;
37 }
38 return NULL;
39}
40EXPORT_SYMBOL_GPL(nvhost_get_resource);
41
42int nvhost_get_irq(struct nvhost_device *dev, unsigned int num)
43{
44 struct resource *r = nvhost_get_resource(dev, IORESOURCE_IRQ, num);
45
46 return r ? r->start : -ENXIO;
47}
48EXPORT_SYMBOL_GPL(nvhost_get_irq);
49
50struct resource *nvhost_get_resource_byname(struct nvhost_device *dev,
51 unsigned int type,
52 const char *name)
53{
54 int i;
55
56 for (i = 0; i < dev->num_resources; i++) {
57 struct resource *r = &dev->resource[i];
58
59 if (type == resource_type(r) && !strcmp(r->name, name))
60 return r;
61 }
62 return NULL;
63}
64EXPORT_SYMBOL_GPL(nvhost_get_resource_byname);
65
66int nvhost_get_irq_byname(struct nvhost_device *dev, const char *name)
67{
68 struct resource *r = nvhost_get_resource_byname(dev, IORESOURCE_IRQ,
69 name);
70
71 return r ? r->start : -ENXIO;
72}
73EXPORT_SYMBOL_GPL(nvhost_get_irq_byname);
74
75static int nvhost_drv_probe(struct device *_dev)
76{
77 struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
78 struct nvhost_device *dev = to_nvhost_device(_dev);
79
80 return drv->probe(dev);
81}
82
83static int nvhost_drv_remove(struct device *_dev)
84{
85 struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
86 struct nvhost_device *dev = to_nvhost_device(_dev);
87
88 return drv->remove(dev);
89}
90
91static void nvhost_drv_shutdown(struct device *_dev)
92{
93 struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
94 struct nvhost_device *dev = to_nvhost_device(_dev);
95
96 drv->shutdown(dev);
97}
98
99int nvhost_driver_register(struct nvhost_driver *drv)
100{
101 drv->driver.bus = &nvhost_bus_type;
102 if (drv->probe)
103 drv->driver.probe = nvhost_drv_probe;
104 if (drv->remove)
105 drv->driver.remove = nvhost_drv_remove;
106 if (drv->shutdown)
107 drv->driver.shutdown = nvhost_drv_shutdown;
108
109 return driver_register(&drv->driver);
110}
111EXPORT_SYMBOL(nvhost_driver_register);
112
113void nvhost_driver_unregister(struct nvhost_driver *drv)
114{
115 driver_unregister(&drv->driver);
116}
117EXPORT_SYMBOL_GPL(nvhost_driver_unregister);
118
119int nvhost_device_register(struct nvhost_device *dev)
120{
121 int i, ret = 0;
122
123 if (!dev)
124 return -EINVAL;
125
126 device_initialize(&dev->dev);
127
128 /* If the dev does not have a parent, assign host1x as parent */
129 if (!dev->dev.parent && nvhost && nvhost->dev != dev)
130 dev->dev.parent = &nvhost->dev->dev;
131
132 dev->dev.bus = &nvhost_bus_type;
133
134 if (dev->id != -1)
135 dev_set_name(&dev->dev, "%s.%d", dev->name, dev->id);
136 else
137 dev_set_name(&dev->dev, "%s", dev->name);
138
139 for (i = 0; i < dev->num_resources; i++) {
140 struct resource *p, *r = &dev->resource[i];
141
142 if (r->name == NULL)
143 r->name = dev_name(&dev->dev);
144
145 p = r->parent;
146 if (!p) {
147 if (resource_type(r) == IORESOURCE_MEM)
148 p = &iomem_resource;
149 else if (resource_type(r) == IORESOURCE_IO)
150 p = &ioport_resource;
151 }
152
153 if (p && insert_resource(p, r)) {
154 pr_err("%s: failed to claim resource %d\n",
155 dev_name(&dev->dev), i);
156 ret = -EBUSY;
157 goto failed;
158 }
159 }
160
161 ret = device_add(&dev->dev);
162 if (ret == 0)
163 return ret;
164
165failed:
166 while (--i >= 0) {
167 struct resource *r = &dev->resource[i];
168 unsigned long type = resource_type(r);
169
170 if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
171 release_resource(r);
172 }
173
174 return ret;
175}
176EXPORT_SYMBOL_GPL(nvhost_device_register);
177
178void nvhost_device_unregister(struct nvhost_device *dev)
179{
180 int i;
181 if (dev) {
182 device_del(&dev->dev);
183
184 for (i = 0; i < dev->num_resources; i++) {
185 struct resource *r = &dev->resource[i];
186 unsigned long type = resource_type(r);
187
188 if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
189 release_resource(r);
190 }
191
192 put_device(&dev->dev);
193 }
194}
195EXPORT_SYMBOL_GPL(nvhost_device_unregister);
196
197static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
198{
199 struct nvhost_device *dev = to_nvhost_device(_dev);
200
201 return !strncmp(dev->name, drv->name, strlen(drv->name));
202}
203
204#ifdef CONFIG_PM_SLEEP
205
206static int nvhost_legacy_suspend(struct device *dev, pm_message_t mesg)
207{
208 struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver);
209 struct nvhost_device *pdev = to_nvhost_device(dev);
210 int ret = 0;
211
212 if (dev->driver && pdrv->suspend)
213 ret = pdrv->suspend(pdev, mesg);
214
215 return ret;
216}
217
218static int nvhost_legacy_resume(struct device *dev)
219{
220 struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver);
221 struct nvhost_device *pdev = to_nvhost_device(dev);
222 int ret = 0;
223
224 if (dev->driver && pdrv->resume)
225 ret = pdrv->resume(pdev);
226
227 return ret;
228}
229
230static int nvhost_pm_prepare(struct device *dev)
231{
232 struct device_driver *drv = dev->driver;
233 int ret = 0;
234
235 if (drv && drv->pm && drv->pm->prepare)
236 ret = drv->pm->prepare(dev);
237
238 return ret;
239}
240
241static void nvhost_pm_complete(struct device *dev)
242{
243 struct device_driver *drv = dev->driver;
244
245 if (drv && drv->pm && drv->pm->complete)
246 drv->pm->complete(dev);
247}
248
249#else /* !CONFIG_PM_SLEEP */
250
251#define nvhost_pm_prepare NULL
252#define nvhost_pm_complete NULL
253
254#endif /* !CONFIG_PM_SLEEP */
255
256#ifdef CONFIG_SUSPEND
257
258int __weak nvhost_pm_suspend(struct device *dev)
259{
260 struct device_driver *drv = dev->driver;
261 int ret = 0;
262
263 if (!drv)
264 return 0;
265
266 if (drv->pm) {
267 if (drv->pm->suspend)
268 ret = drv->pm->suspend(dev);
269 } else {
270 ret = nvhost_legacy_suspend(dev, PMSG_SUSPEND);
271 }
272
273 return ret;
274}
275
276int __weak nvhost_pm_suspend_noirq(struct device *dev)
277{
278 struct device_driver *drv = dev->driver;
279 int ret = 0;
280
281 if (!drv)
282 return 0;
283
284 if (drv->pm) {
285 if (drv->pm->suspend_noirq)
286 ret = drv->pm->suspend_noirq(dev);
287 }
288
289 return ret;
290}
291
292int __weak nvhost_pm_resume(struct device *dev)
293{
294 struct device_driver *drv = dev->driver;
295 int ret = 0;
296
297 if (!drv)
298 return 0;
299
300 if (drv->pm) {
301 if (drv->pm->resume)
302 ret = drv->pm->resume(dev);
303 } else {
304 ret = nvhost_legacy_resume(dev);
305 }
306
307 return ret;
308}
309
310int __weak nvhost_pm_resume_noirq(struct device *dev)
311{
312 struct device_driver *drv = dev->driver;
313 int ret = 0;
314
315 if (!drv)
316 return 0;
317
318 if (drv->pm) {
319 if (drv->pm->resume_noirq)
320 ret = drv->pm->resume_noirq(dev);
321 }
322
323 return ret;
324}
325
326#else /* !CONFIG_SUSPEND */
327
328#define nvhost_pm_suspend NULL
329#define nvhost_pm_resume NULL
330#define nvhost_pm_suspend_noirq NULL
331#define nvhost_pm_resume_noirq NULL
332
333#endif /* !CONFIG_SUSPEND */
334
335#ifdef CONFIG_HIBERNATION
336
337static int nvhost_pm_freeze(struct device *dev)
338{
339 struct device_driver *drv = dev->driver;
340 int ret = 0;
341
342 if (!drv)
343 return 0;
344
345 if (drv->pm) {
346 if (drv->pm->freeze)
347 ret = drv->pm->freeze(dev);
348 } else {
349 ret = nvhost_legacy_suspend(dev, PMSG_FREEZE);
350 }
351
352 return ret;
353}
354
355static int nvhost_pm_freeze_noirq(struct device *dev)
356{
357 struct device_driver *drv = dev->driver;
358 int ret = 0;
359
360 if (!drv)
361 return 0;
362
363 if (drv->pm) {
364 if (drv->pm->freeze_noirq)
365 ret = drv->pm->freeze_noirq(dev);
366 }
367
368 return ret;
369}
370
371static int nvhost_pm_thaw(struct device *dev)
372{
373 struct device_driver *drv = dev->driver;
374 int ret = 0;
375
376 if (!drv)
377 return 0;
378
379 if (drv->pm) {
380 if (drv->pm->thaw)
381 ret = drv->pm->thaw(dev);
382 } else {
383 ret = nvhost_legacy_resume(dev);
384 }
385
386 return ret;
387}
388
389static int nvhost_pm_thaw_noirq(struct device *dev)
390{
391 struct device_driver *drv = dev->driver;
392 int ret = 0;
393
394 if (!drv)
395 return 0;
396
397 if (drv->pm) {
398 if (drv->pm->thaw_noirq)
399 ret = drv->pm->thaw_noirq(dev);
400 }
401
402 return ret;
403}
404
405static int nvhost_pm_poweroff(struct device *dev)
406{
407 struct device_driver *drv = dev->driver;
408 int ret = 0;
409
410 if (!drv)
411 return 0;
412
413 if (drv->pm) {
414 if (drv->pm->poweroff)
415 ret = drv->pm->poweroff(dev);
416 } else {
417 ret = nvhost_legacy_suspend(dev, PMSG_HIBERNATE);
418 }
419
420 return ret;
421}
422
423static int nvhost_pm_poweroff_noirq(struct device *dev)
424{
425 struct device_driver *drv = dev->driver;
426 int ret = 0;
427
428 if (!drv)
429 return 0;
430
431 if (drv->pm) {
432 if (drv->pm->poweroff_noirq)
433 ret = drv->pm->poweroff_noirq(dev);
434 }
435
436 return ret;
437}
438
439static int nvhost_pm_restore(struct device *dev)
440{
441 struct device_driver *drv = dev->driver;
442 int ret = 0;
443
444 if (!drv)
445 return 0;
446
447 if (drv->pm) {
448 if (drv->pm->restore)
449 ret = drv->pm->restore(dev);
450 } else {
451 ret = nvhost_legacy_resume(dev);
452 }
453
454 return ret;
455}
456
457static int nvhost_pm_restore_noirq(struct device *dev)
458{
459 struct device_driver *drv = dev->driver;
460 int ret = 0;
461
462 if (!drv)
463 return 0;
464
465 if (drv->pm) {
466 if (drv->pm->restore_noirq)
467 ret = drv->pm->restore_noirq(dev);
468 }
469
470 return ret;
471}
472
473#else /* !CONFIG_HIBERNATION */
474
475#define nvhost_pm_freeze NULL
476#define nvhost_pm_thaw NULL
477#define nvhost_pm_poweroff NULL
478#define nvhost_pm_restore NULL
479#define nvhost_pm_freeze_noirq NULL
480#define nvhost_pm_thaw_noirq NULL
481#define nvhost_pm_poweroff_noirq NULL
482#define nvhost_pm_restore_noirq NULL
483
484#endif /* !CONFIG_HIBERNATION */
485
486#ifdef CONFIG_PM_RUNTIME
487
488int __weak nvhost_pm_runtime_suspend(struct device *dev)
489{
490 return pm_generic_runtime_suspend(dev);
491};
492
493int __weak nvhost_pm_runtime_resume(struct device *dev)
494{
495 return pm_generic_runtime_resume(dev);
496};
497
498int __weak nvhost_pm_runtime_idle(struct device *dev)
499{
500 return pm_generic_runtime_idle(dev);
501};
502
503#else /* !CONFIG_PM_RUNTIME */
504
505#define nvhost_pm_runtime_suspend NULL
506#define nvhost_pm_runtime_resume NULL
507#define nvhost_pm_runtime_idle NULL
508
509#endif /* !CONFIG_PM_RUNTIME */
510
511static const struct dev_pm_ops nvhost_dev_pm_ops = {
512 .prepare = nvhost_pm_prepare,
513 .complete = nvhost_pm_complete,
514 .suspend = nvhost_pm_suspend,
515 .resume = nvhost_pm_resume,
516 .freeze = nvhost_pm_freeze,
517 .thaw = nvhost_pm_thaw,
518 .poweroff = nvhost_pm_poweroff,
519 .restore = nvhost_pm_restore,
520 .suspend_noirq = nvhost_pm_suspend_noirq,
521 .resume_noirq = nvhost_pm_resume_noirq,
522 .freeze_noirq = nvhost_pm_freeze_noirq,
523 .thaw_noirq = nvhost_pm_thaw_noirq,
524 .poweroff_noirq = nvhost_pm_poweroff_noirq,
525 .restore_noirq = nvhost_pm_restore_noirq,
526 .runtime_suspend = nvhost_pm_runtime_suspend,
527 .runtime_resume = nvhost_pm_runtime_resume,
528 .runtime_idle = nvhost_pm_runtime_idle,
529};
530
531struct bus_type nvhost_bus_type = {
532 .name = "nvhost",
533 .match = nvhost_bus_match,
534 .pm = &nvhost_dev_pm_ops,
535};
536EXPORT_SYMBOL(nvhost_bus_type);
537
538static int set_parent(struct device *dev, void *data)
539{
540 struct nvhost_device *ndev = to_nvhost_device(dev);
541 struct nvhost_master *host = data;
542 if (!dev->parent && ndev != host->dev)
543 dev->parent = &host->dev->dev;
544 return 0;
545}
546
547int nvhost_bus_add_host(struct nvhost_master *host)
548{
549 nvhost = host;
550
551 /* Assign host1x as parent to all devices in nvhost bus */
552 bus_for_each_dev(&nvhost_bus_type, NULL, host, set_parent);
553
554 return 0;
555}
556
557
558int nvhost_bus_init(void)
559{
560 int err;
561
562 pr_info("host1x bus init\n");
563
564 err = bus_register(&nvhost_bus_type);
565
566 return err;
567}
568postcore_initcall(nvhost_bus_init);
569