25960b9fd9290604e3887b5157dcd6445ee2fe6d
[linux-2.6.git] / drivers / video / tegra / host / bus.c
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/slab.h>
21 #include <linux/pm_runtime.h>
22 #include <linux/export.h>
23 #include <linux/nvhost.h>
24 #include <linux/io.h>
25
26 #include "bus.h"
27 #include "dev.h"
28
29 struct nvhost_bus *nvhost_bus_inst;
30 struct nvhost_master *nvhost;
31
32 struct resource *nvhost_get_resource(struct nvhost_device *dev,
33                                        unsigned int type, unsigned int num)
34 {
35         int i;
36
37         for (i = 0; i < dev->num_resources; i++) {
38                 struct resource *r = &dev->resource[i];
39
40                 if (type == resource_type(r) && num-- == 0)
41                         return r;
42         }
43         return NULL;
44 }
45 EXPORT_SYMBOL_GPL(nvhost_get_resource);
46
47 int nvhost_get_irq(struct nvhost_device *dev, unsigned int num)
48 {
49         struct resource *r = nvhost_get_resource(dev, IORESOURCE_IRQ, num);
50
51         return r ? r->start : -ENXIO;
52 }
53 EXPORT_SYMBOL_GPL(nvhost_get_irq);
54
55 struct resource *nvhost_get_resource_byname(struct nvhost_device *dev,
56                                               unsigned int type,
57                                               const char *name)
58 {
59         int i;
60
61         for (i = 0; i < dev->num_resources; i++) {
62                 struct resource *r = &dev->resource[i];
63
64                 if (type == resource_type(r) && !strcmp(r->name, name))
65                         return r;
66         }
67         return NULL;
68 }
69 EXPORT_SYMBOL_GPL(nvhost_get_resource_byname);
70
71 int nvhost_get_irq_byname(struct nvhost_device *dev, const char *name)
72 {
73         struct resource *r = nvhost_get_resource_byname(dev, IORESOURCE_IRQ,
74                                                           name);
75
76         return r ? r->start : -ENXIO;
77 }
78 EXPORT_SYMBOL_GPL(nvhost_get_irq_byname);
79
80 static struct nvhost_device_id *nvhost_bus_match_id(struct nvhost_device *dev,
81         struct nvhost_device_id *id_table)
82 {
83         while (id_table->name[0]) {
84                 if (strcmp(dev->name, id_table->name) == 0)
85                         return id_table;
86                 id_table++;
87         }
88         return NULL;
89 }
90
91 static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
92 {
93         struct nvhost_device *dev = to_nvhost_device(_dev);
94         struct nvhost_driver *ndrv = to_nvhost_driver(drv);
95
96         /* check if driver support multiple devices through id_table */
97         if (ndrv->id_table)
98                 return nvhost_bus_match_id(dev, ndrv->id_table) != NULL;
99         else /* driver does not support id_table */
100                 return !strncmp(dev->name, drv->name, strlen(drv->name));
101 }
102
103 static int nvhost_drv_probe(struct device *_dev)
104 {
105         struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
106         struct nvhost_device *dev = to_nvhost_device(_dev);
107
108         if (drv && drv->probe) {
109                 if (drv->id_table)
110                         return drv->probe(dev, nvhost_bus_match_id(dev, drv->id_table));
111                 else
112                         return drv->probe(dev, NULL);
113         }
114         else
115                 return -ENODEV;
116 }
117
118 static int nvhost_drv_remove(struct device *_dev)
119 {
120         struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
121         struct nvhost_device *dev = to_nvhost_device(_dev);
122
123         return drv->remove(dev);
124 }
125
126 static void nvhost_drv_shutdown(struct device *_dev)
127 {
128         struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
129         struct nvhost_device *dev = to_nvhost_device(_dev);
130
131         drv->shutdown(dev);
132 }
133
134 int nvhost_driver_register(struct nvhost_driver *drv)
135 {
136         drv->driver.bus = &nvhost_bus_inst->nvhost_bus_type;
137         if (drv->probe)
138                 drv->driver.probe = nvhost_drv_probe;
139         if (drv->remove)
140                 drv->driver.remove = nvhost_drv_remove;
141         if (drv->shutdown)
142                 drv->driver.shutdown = nvhost_drv_shutdown;
143
144         return driver_register(&drv->driver);
145 }
146 EXPORT_SYMBOL(nvhost_driver_register);
147
148 void nvhost_driver_unregister(struct nvhost_driver *drv)
149 {
150         driver_unregister(&drv->driver);
151 }
152 EXPORT_SYMBOL_GPL(nvhost_driver_unregister);
153
154 int nvhost_device_register(struct nvhost_device *dev)
155 {
156         int i, ret = 0;
157
158         if (!dev)
159                 return -EINVAL;
160
161         device_initialize(&dev->dev);
162
163         /*  If the dev does not have a parent, assign host1x as parent */
164         if (!dev->dev.parent && nvhost && nvhost->dev != dev)
165                 dev->dev.parent = &nvhost->dev->dev;
166
167         dev->dev.bus = &nvhost_bus_inst->nvhost_bus_type;
168
169         if (dev->id != -1)
170                 dev_set_name(&dev->dev, "%s.%d", dev->name,  dev->id);
171         else
172                 dev_set_name(&dev->dev, "%s", dev->name);
173
174         for (i = 0; i < dev->num_resources; i++) {
175                 struct resource *p, *r = &dev->resource[i];
176
177                 if (r->name == NULL)
178                         r->name = dev_name(&dev->dev);
179
180                 p = r->parent;
181                 if (!p) {
182                         if (resource_type(r) == IORESOURCE_MEM)
183                                 p = &iomem_resource;
184                         else if (resource_type(r) == IORESOURCE_IO)
185                                 p = &ioport_resource;
186                 }
187
188                 if (p && insert_resource(p, r)) {
189                         pr_err("%s: failed to claim resource %d\n",
190                                dev_name(&dev->dev), i);
191                         ret = -EBUSY;
192                         goto failed;
193                 }
194         }
195
196         ret = device_add(&dev->dev);
197         if (ret == 0)
198                 return ret;
199
200 failed:
201         while (--i >= 0) {
202                 struct resource *r = &dev->resource[i];
203                 unsigned long type = resource_type(r);
204
205                 if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
206                         release_resource(r);
207         }
208
209         return ret;
210 }
211 EXPORT_SYMBOL_GPL(nvhost_device_register);
212
213 void nvhost_device_unregister(struct nvhost_device *dev)
214 {
215         int i;
216         if (dev) {
217                 device_del(&dev->dev);
218
219                 for (i = 0; i < dev->num_resources; i++) {
220                         struct resource *r = &dev->resource[i];
221                         unsigned long type = resource_type(r);
222
223                         if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
224                                 release_resource(r);
225                 }
226
227                 put_device(&dev->dev);
228         }
229 }
230 EXPORT_SYMBOL_GPL(nvhost_device_unregister);
231
232 void nvhost_device_writel(struct nvhost_device *dev, u32 r, u32 v)
233 {
234         writel(v, dev->aperture + r);
235 }
236 EXPORT_SYMBOL_GPL(nvhost_device_writel);
237
238 u32 nvhost_device_readl(struct nvhost_device *dev, u32 r)
239 {
240         return readl(dev->aperture + r);
241 }
242 EXPORT_SYMBOL_GPL(nvhost_device_readl);
243
244 #ifdef CONFIG_PM_SLEEP
245
246 static int nvhost_legacy_suspend(struct device *dev, pm_message_t mesg)
247 {
248         struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver);
249         struct nvhost_device *pdev = to_nvhost_device(dev);
250         int ret = 0;
251
252         if (dev->driver && pdrv->suspend)
253                 ret = pdrv->suspend(pdev, mesg);
254
255         return ret;
256 }
257
258 static int nvhost_legacy_resume(struct device *dev)
259 {
260         struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver);
261         struct nvhost_device *pdev = to_nvhost_device(dev);
262         int ret = 0;
263
264         if (dev->driver && pdrv->resume)
265                 ret = pdrv->resume(pdev);
266
267         return ret;
268 }
269
270 static int nvhost_pm_prepare(struct device *dev)
271 {
272         struct device_driver *drv = dev->driver;
273         int ret = 0;
274
275         if (drv && drv->pm && drv->pm->prepare)
276                 ret = drv->pm->prepare(dev);
277
278         return ret;
279 }
280
281 static void nvhost_pm_complete(struct device *dev)
282 {
283         struct device_driver *drv = dev->driver;
284
285         if (drv && drv->pm && drv->pm->complete)
286                 drv->pm->complete(dev);
287 }
288
289 #else /* !CONFIG_PM_SLEEP */
290
291 #define nvhost_pm_prepare               NULL
292 #define nvhost_pm_complete              NULL
293
294 #endif /* !CONFIG_PM_SLEEP */
295
296 #ifdef CONFIG_SUSPEND
297
298 int __weak nvhost_pm_suspend(struct device *dev)
299 {
300         struct device_driver *drv = dev->driver;
301         int ret = 0;
302
303         if (!drv)
304                 return 0;
305
306         if (drv->pm) {
307                 if (drv->pm->suspend)
308                         ret = drv->pm->suspend(dev);
309         } else {
310                 ret = nvhost_legacy_suspend(dev, PMSG_SUSPEND);
311         }
312
313         return ret;
314 }
315
316 int __weak nvhost_pm_suspend_noirq(struct device *dev)
317 {
318         struct device_driver *drv = dev->driver;
319         int ret = 0;
320
321         if (!drv)
322                 return 0;
323
324         if (drv->pm) {
325                 if (drv->pm->suspend_noirq)
326                         ret = drv->pm->suspend_noirq(dev);
327         }
328
329         return ret;
330 }
331
332 int __weak nvhost_pm_resume(struct device *dev)
333 {
334         struct device_driver *drv = dev->driver;
335         int ret = 0;
336
337         if (!drv)
338                 return 0;
339
340         if (drv->pm) {
341                 if (drv->pm->resume)
342                         ret = drv->pm->resume(dev);
343         } else {
344                 ret = nvhost_legacy_resume(dev);
345         }
346
347         return ret;
348 }
349
350 int __weak nvhost_pm_resume_noirq(struct device *dev)
351 {
352         struct device_driver *drv = dev->driver;
353         int ret = 0;
354
355         if (!drv)
356                 return 0;
357
358         if (drv->pm) {
359                 if (drv->pm->resume_noirq)
360                         ret = drv->pm->resume_noirq(dev);
361         }
362
363         return ret;
364 }
365
366 #else /* !CONFIG_SUSPEND */
367
368 #define nvhost_pm_suspend               NULL
369 #define nvhost_pm_resume                NULL
370 #define nvhost_pm_suspend_noirq NULL
371 #define nvhost_pm_resume_noirq  NULL
372
373 #endif /* !CONFIG_SUSPEND */
374
375 #ifdef CONFIG_HIBERNATION
376
377 static int nvhost_pm_freeze(struct device *dev)
378 {
379         struct device_driver *drv = dev->driver;
380         int ret = 0;
381
382         if (!drv)
383                 return 0;
384
385         if (drv->pm) {
386                 if (drv->pm->freeze)
387                         ret = drv->pm->freeze(dev);
388         } else {
389                 ret = nvhost_legacy_suspend(dev, PMSG_FREEZE);
390         }
391
392         return ret;
393 }
394
395 static int nvhost_pm_freeze_noirq(struct device *dev)
396 {
397         struct device_driver *drv = dev->driver;
398         int ret = 0;
399
400         if (!drv)
401                 return 0;
402
403         if (drv->pm) {
404                 if (drv->pm->freeze_noirq)
405                         ret = drv->pm->freeze_noirq(dev);
406         }
407
408         return ret;
409 }
410
411 static int nvhost_pm_thaw(struct device *dev)
412 {
413         struct device_driver *drv = dev->driver;
414         int ret = 0;
415
416         if (!drv)
417                 return 0;
418
419         if (drv->pm) {
420                 if (drv->pm->thaw)
421                         ret = drv->pm->thaw(dev);
422         } else {
423                 ret = nvhost_legacy_resume(dev);
424         }
425
426         return ret;
427 }
428
429 static int nvhost_pm_thaw_noirq(struct device *dev)
430 {
431         struct device_driver *drv = dev->driver;
432         int ret = 0;
433
434         if (!drv)
435                 return 0;
436
437         if (drv->pm) {
438                 if (drv->pm->thaw_noirq)
439                         ret = drv->pm->thaw_noirq(dev);
440         }
441
442         return ret;
443 }
444
445 static int nvhost_pm_poweroff(struct device *dev)
446 {
447         struct device_driver *drv = dev->driver;
448         int ret = 0;
449
450         if (!drv)
451                 return 0;
452
453         if (drv->pm) {
454                 if (drv->pm->poweroff)
455                         ret = drv->pm->poweroff(dev);
456         } else {
457                 ret = nvhost_legacy_suspend(dev, PMSG_HIBERNATE);
458         }
459
460         return ret;
461 }
462
463 static int nvhost_pm_poweroff_noirq(struct device *dev)
464 {
465         struct device_driver *drv = dev->driver;
466         int ret = 0;
467
468         if (!drv)
469                 return 0;
470
471         if (drv->pm) {
472                 if (drv->pm->poweroff_noirq)
473                         ret = drv->pm->poweroff_noirq(dev);
474         }
475
476         return ret;
477 }
478
479 static int nvhost_pm_restore(struct device *dev)
480 {
481         struct device_driver *drv = dev->driver;
482         int ret = 0;
483
484         if (!drv)
485                 return 0;
486
487         if (drv->pm) {
488                 if (drv->pm->restore)
489                         ret = drv->pm->restore(dev);
490         } else {
491                 ret = nvhost_legacy_resume(dev);
492         }
493
494         return ret;
495 }
496
497 static int nvhost_pm_restore_noirq(struct device *dev)
498 {
499         struct device_driver *drv = dev->driver;
500         int ret = 0;
501
502         if (!drv)
503                 return 0;
504
505         if (drv->pm) {
506                 if (drv->pm->restore_noirq)
507                         ret = drv->pm->restore_noirq(dev);
508         }
509
510         return ret;
511 }
512
513 #else /* !CONFIG_HIBERNATION */
514
515 #define nvhost_pm_freeze                NULL
516 #define nvhost_pm_thaw          NULL
517 #define nvhost_pm_poweroff              NULL
518 #define nvhost_pm_restore               NULL
519 #define nvhost_pm_freeze_noirq  NULL
520 #define nvhost_pm_thaw_noirq            NULL
521 #define nvhost_pm_poweroff_noirq        NULL
522 #define nvhost_pm_restore_noirq NULL
523
524 #endif /* !CONFIG_HIBERNATION */
525
526 #ifdef CONFIG_PM_RUNTIME
527
528 int __weak nvhost_pm_runtime_suspend(struct device *dev)
529 {
530         return pm_generic_runtime_suspend(dev);
531 };
532
533 int __weak nvhost_pm_runtime_resume(struct device *dev)
534 {
535         return pm_generic_runtime_resume(dev);
536 };
537
538 int __weak nvhost_pm_runtime_idle(struct device *dev)
539 {
540         return pm_generic_runtime_idle(dev);
541 };
542
543 #else /* !CONFIG_PM_RUNTIME */
544
545 #define nvhost_pm_runtime_suspend NULL
546 #define nvhost_pm_runtime_resume NULL
547 #define nvhost_pm_runtime_idle NULL
548
549 #endif /* !CONFIG_PM_RUNTIME */
550
551 static const struct dev_pm_ops nvhost_dev_pm_ops = {
552         .prepare = nvhost_pm_prepare,
553         .complete = nvhost_pm_complete,
554         .suspend = nvhost_pm_suspend,
555         .resume = nvhost_pm_resume,
556         .freeze = nvhost_pm_freeze,
557         .thaw = nvhost_pm_thaw,
558         .poweroff = nvhost_pm_poweroff,
559         .restore = nvhost_pm_restore,
560         .suspend_noirq = nvhost_pm_suspend_noirq,
561         .resume_noirq = nvhost_pm_resume_noirq,
562         .freeze_noirq = nvhost_pm_freeze_noirq,
563         .thaw_noirq = nvhost_pm_thaw_noirq,
564         .poweroff_noirq = nvhost_pm_poweroff_noirq,
565         .restore_noirq = nvhost_pm_restore_noirq,
566         .runtime_suspend = nvhost_pm_runtime_suspend,
567         .runtime_resume = nvhost_pm_runtime_resume,
568         .runtime_idle = nvhost_pm_runtime_idle,
569 };
570
571 static int set_parent(struct device *dev, void *data)
572 {
573         struct nvhost_device *ndev = to_nvhost_device(dev);
574         struct nvhost_master *host = data;
575         if (!dev->parent && ndev != host->dev)
576                 dev->parent = &host->dev->dev;
577         return 0;
578 }
579
580 int nvhost_bus_add_host(struct nvhost_master *host)
581 {
582         nvhost = host;
583
584         /*  Assign host1x as parent to all devices in nvhost bus */
585         bus_for_each_dev(&nvhost_bus_inst->nvhost_bus_type, NULL, host, set_parent);
586
587         return 0;
588 }
589
590 struct nvhost_bus *nvhost_bus_get(void)
591 {
592         return nvhost_bus_inst;
593 }
594
595 int nvhost_bus_init(void)
596 {
597         int err;
598         struct nvhost_chip_support *chip_ops;
599
600         pr_info("host1x bus init\n");
601
602         nvhost_bus_inst = kzalloc(sizeof(*nvhost_bus_inst), GFP_KERNEL);
603         if (nvhost_bus_inst == NULL) {
604                 pr_err("%s: Cannot allocate nvhost_bus\n", __func__);
605                 return -ENOMEM;
606         }
607
608         chip_ops = kzalloc(sizeof(*chip_ops), GFP_KERNEL);
609         if (chip_ops == NULL) {
610                 pr_err("%s: Cannot allocate nvhost_chip_support\n", __func__);
611                 kfree(nvhost_bus_inst);
612                 nvhost_bus_inst = NULL;
613                 return -ENOMEM;
614         }
615
616         nvhost_bus_inst->nvhost_bus_type.name = "nvhost";
617         nvhost_bus_inst->nvhost_bus_type.match = nvhost_bus_match;
618         nvhost_bus_inst->nvhost_bus_type.pm = &nvhost_dev_pm_ops;
619         nvhost_bus_inst->nvhost_chip_ops = chip_ops;
620
621         err = bus_register(&nvhost_bus_inst->nvhost_bus_type);
622
623         return err;
624 }
625 postcore_initcall(nvhost_bus_init);