b4051604f188a8a6f166687924e89a6e75150f6d
[linux-2.6.git] / drivers / video / tegra / host / dev.c
1 /*
2  * drivers/video/tegra/host/dev.c
3  *
4  * Tegra Graphics Host Driver Entrypoint
5  *
6  * Copyright (c) 2010-2012, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <linux/slab.h>
22 #include <linux/string.h>
23 #include <linux/spinlock.h>
24 #include <linux/fs.h>
25 #include <linux/cdev.h>
26 #include <linux/uaccess.h>
27 #include <linux/file.h>
28 #include <linux/module.h>
29 #include <linux/clk.h>
30 #include <linux/hrtimer.h>
31
32 #include "dev.h"
33 #define CREATE_TRACE_POINTS
34 #include <trace/events/nvhost.h>
35
36 #include <linux/io.h>
37
38 #include <linux/nvhost.h>
39 #include <linux/nvhost_ioctl.h>
40 #include <mach/gpufuse.h>
41 #include <mach/hardware.h>
42 #include <mach/iomap.h>
43
44 #include "debug.h"
45 #include "t20/t20.h"
46 #include "t30/t30.h"
47 #include "bus_client.h"
48 #include "nvhost_acm.h"
49 #include "nvhost_channel.h"
50 #include "nvhost_job.h"
51 #include "t20/t20.h"
52 #include "t30/t30.h"
53 #include "t114/t114.h"
54 #include "nvhost_memmgr.h"
55 #include "chip_support.h"
56
57 #define DRIVER_NAME             "host1x"
58 #define HOST_DEFAULT_RATE       108000000
59
60 static unsigned int register_sets;
61
62 struct nvhost_ctrl_userctx {
63         struct nvhost_master *dev;
64         u32 *mod_locks;
65 };
66
67 static int nvhost_ctrlrelease(struct inode *inode, struct file *filp)
68 {
69         struct nvhost_ctrl_userctx *priv = filp->private_data;
70         int i;
71
72         trace_nvhost_ctrlrelease(priv->dev->dev->name);
73
74         filp->private_data = NULL;
75         if (priv->mod_locks[0])
76                 nvhost_module_idle(priv->dev->dev);
77         for (i = 1; i < priv->dev->syncpt.nb_mlocks; i++)
78                 if (priv->mod_locks[i])
79                         nvhost_mutex_unlock(&priv->dev->syncpt, i);
80         kfree(priv->mod_locks);
81         kfree(priv);
82         return 0;
83 }
84
85 static int nvhost_ctrlopen(struct inode *inode, struct file *filp)
86 {
87         struct nvhost_master *host =
88                 container_of(inode->i_cdev, struct nvhost_master, cdev);
89         struct nvhost_ctrl_userctx *priv;
90         u32 *mod_locks;
91
92         trace_nvhost_ctrlopen(host->dev->name);
93
94         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
95         mod_locks = kzalloc(sizeof(u32) * host->syncpt.nb_mlocks, GFP_KERNEL);
96
97         if (!(priv && mod_locks)) {
98                 kfree(priv);
99                 kfree(mod_locks);
100                 return -ENOMEM;
101         }
102
103         priv->dev = host;
104         priv->mod_locks = mod_locks;
105         filp->private_data = priv;
106         return 0;
107 }
108
109 static int nvhost_ioctl_ctrl_syncpt_read(struct nvhost_ctrl_userctx *ctx,
110         struct nvhost_ctrl_syncpt_read_args *args)
111 {
112         if (args->id >= ctx->dev->syncpt.nb_pts)
113                 return -EINVAL;
114         args->value = nvhost_syncpt_read(&ctx->dev->syncpt, args->id);
115         trace_nvhost_ioctl_ctrl_syncpt_read(args->id, args->value);
116         return 0;
117 }
118
119 static int nvhost_ioctl_ctrl_syncpt_incr(struct nvhost_ctrl_userctx *ctx,
120         struct nvhost_ctrl_syncpt_incr_args *args)
121 {
122         if (args->id >= ctx->dev->syncpt.nb_pts)
123                 return -EINVAL;
124         trace_nvhost_ioctl_ctrl_syncpt_incr(args->id);
125         nvhost_syncpt_incr(&ctx->dev->syncpt, args->id);
126         return 0;
127 }
128
129 static int nvhost_ioctl_ctrl_syncpt_waitex(struct nvhost_ctrl_userctx *ctx,
130         struct nvhost_ctrl_syncpt_waitex_args *args)
131 {
132         u32 timeout;
133         int err;
134         if (args->id >= ctx->dev->syncpt.nb_pts)
135                 return -EINVAL;
136         if (args->timeout == NVHOST_NO_TIMEOUT)
137                 timeout = MAX_SCHEDULE_TIMEOUT;
138         else
139                 timeout = (u32)msecs_to_jiffies(args->timeout);
140
141         err = nvhost_syncpt_wait_timeout(&ctx->dev->syncpt, args->id,
142                                         args->thresh, timeout, &args->value);
143         trace_nvhost_ioctl_ctrl_syncpt_wait(args->id, args->thresh,
144           args->timeout, args->value, err);
145
146         return err;
147 }
148
149 static int nvhost_ioctl_ctrl_module_mutex(struct nvhost_ctrl_userctx *ctx,
150         struct nvhost_ctrl_module_mutex_args *args)
151 {
152         int err = 0;
153         if (args->id >= ctx->dev->syncpt.nb_mlocks ||
154             args->lock > 1)
155                 return -EINVAL;
156
157         trace_nvhost_ioctl_ctrl_module_mutex(args->lock, args->id);
158         if (args->lock && !ctx->mod_locks[args->id]) {
159                 if (args->id == 0)
160                         nvhost_module_busy(ctx->dev->dev);
161                 else
162                         err = nvhost_mutex_try_lock(&ctx->dev->syncpt,
163                                         args->id);
164                 if (!err)
165                         ctx->mod_locks[args->id] = 1;
166         } else if (!args->lock && ctx->mod_locks[args->id]) {
167                 if (args->id == 0)
168                         nvhost_module_idle(ctx->dev->dev);
169                 else
170                         nvhost_mutex_unlock(&ctx->dev->syncpt, args->id);
171                 ctx->mod_locks[args->id] = 0;
172         }
173         return err;
174 }
175
176 static int match_by_moduleid(struct device *dev, void *data)
177 {
178         struct nvhost_device *ndev = to_nvhost_device(dev);
179         u32 id = (u32)data;
180
181         return id == ndev->moduleid;
182 }
183
184 static struct nvhost_device *get_ndev_by_moduleid(struct nvhost_master *host,
185                 u32 id)
186 {
187         struct device *dev = bus_find_device(&nvhost_bus_inst->nvhost_bus_type, NULL, (void *)id,
188                         match_by_moduleid);
189
190         return dev ? to_nvhost_device(dev) : NULL;
191 }
192
193 static int nvhost_ioctl_ctrl_module_regrdwr(struct nvhost_ctrl_userctx *ctx,
194         struct nvhost_ctrl_module_regrdwr_args *args)
195 {
196         u32 num_offsets = args->num_offsets;
197         u32 *offsets = args->offsets;
198         u32 *values = args->values;
199         u32 vals[64];
200         struct nvhost_device *ndev;
201
202         trace_nvhost_ioctl_ctrl_module_regrdwr(args->id,
203                         args->num_offsets, args->write);
204         /* Check that there is something to read and that block size is
205          * u32 aligned */
206         if (num_offsets == 0 || args->block_size & 3)
207                 return -EINVAL;
208
209         ndev = get_ndev_by_moduleid(ctx->dev, args->id);
210         if (!ndev)
211                 return -EINVAL;
212
213         while (num_offsets--) {
214                 int err;
215                 int remaining = args->block_size >> 2;
216                 u32 offs;
217                 if (get_user(offs, offsets))
218                         return -EFAULT;
219                 offsets++;
220                 while (remaining) {
221                         int batch = min(remaining, 64);
222                         if (args->write) {
223                                 if (copy_from_user(vals, values,
224                                                         batch*sizeof(u32)))
225                                         return -EFAULT;
226                                 err = nvhost_write_module_regs(ndev,
227                                                 offs, batch, vals);
228                                 if (err)
229                                         return err;
230                         } else {
231                                 err = nvhost_read_module_regs(ndev,
232                                                 offs, batch, vals);
233                                 if (err)
234                                         return err;
235                                 if (copy_to_user(values, vals,
236                                                         batch*sizeof(u32)))
237                                         return -EFAULT;
238                         }
239                         remaining -= batch;
240                         offs += batch*sizeof(u32);
241                         values += batch;
242                 }
243         }
244
245         return 0;
246 }
247
248 static int nvhost_ioctl_ctrl_get_version(struct nvhost_ctrl_userctx *ctx,
249         struct nvhost_get_param_args *args)
250 {
251         args->value = NVHOST_SUBMIT_VERSION_MAX_SUPPORTED;
252         return 0;
253 }
254
255 static long nvhost_ctrlctl(struct file *filp,
256         unsigned int cmd, unsigned long arg)
257 {
258         struct nvhost_ctrl_userctx *priv = filp->private_data;
259         u8 buf[NVHOST_IOCTL_CTRL_MAX_ARG_SIZE];
260         int err = 0;
261
262         if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) ||
263                 (_IOC_NR(cmd) == 0) ||
264                 (_IOC_NR(cmd) > NVHOST_IOCTL_CTRL_LAST) ||
265                 (_IOC_SIZE(cmd) > NVHOST_IOCTL_CTRL_MAX_ARG_SIZE))
266                 return -EFAULT;
267
268         if (_IOC_DIR(cmd) & _IOC_WRITE) {
269                 if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
270                         return -EFAULT;
271         }
272
273         switch (cmd) {
274         case NVHOST_IOCTL_CTRL_SYNCPT_READ:
275                 err = nvhost_ioctl_ctrl_syncpt_read(priv, (void *)buf);
276                 break;
277         case NVHOST_IOCTL_CTRL_SYNCPT_INCR:
278                 err = nvhost_ioctl_ctrl_syncpt_incr(priv, (void *)buf);
279                 break;
280         case NVHOST_IOCTL_CTRL_SYNCPT_WAIT:
281                 err = nvhost_ioctl_ctrl_syncpt_waitex(priv, (void *)buf);
282                 break;
283         case NVHOST_IOCTL_CTRL_MODULE_MUTEX:
284                 err = nvhost_ioctl_ctrl_module_mutex(priv, (void *)buf);
285                 break;
286         case NVHOST_IOCTL_CTRL_MODULE_REGRDWR:
287                 err = nvhost_ioctl_ctrl_module_regrdwr(priv, (void *)buf);
288                 break;
289         case NVHOST_IOCTL_CTRL_SYNCPT_WAITEX:
290                 err = nvhost_ioctl_ctrl_syncpt_waitex(priv, (void *)buf);
291                 break;
292         case NVHOST_IOCTL_CTRL_GET_VERSION:
293                 err = nvhost_ioctl_ctrl_get_version(priv, (void *)buf);
294                 break;
295         default:
296                 err = -ENOTTY;
297                 break;
298         }
299
300         if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ))
301                 err = copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd));
302
303         return err;
304 }
305
306 static const struct file_operations nvhost_ctrlops = {
307         .owner = THIS_MODULE,
308         .release = nvhost_ctrlrelease,
309         .open = nvhost_ctrlopen,
310         .unlocked_ioctl = nvhost_ctrlctl
311 };
312
313 static void power_on_host(struct nvhost_device *dev)
314 {
315         struct nvhost_master *host = nvhost_get_drvdata(dev);
316         nvhost_syncpt_reset(&host->syncpt);
317         nvhost_intr_start(&host->intr, clk_get_rate(dev->clk[0]));
318 }
319
320 static int power_off_host(struct nvhost_device *dev)
321 {
322         struct nvhost_master *host = nvhost_get_drvdata(dev);
323         nvhost_syncpt_save(&host->syncpt);
324         nvhost_intr_stop(&host->intr);
325         return 0;
326 }
327
328 static int __devinit nvhost_user_init(struct nvhost_master *host)
329 {
330         int err, devno;
331
332         host->nvhost_class = class_create(THIS_MODULE, IFACE_NAME);
333         if (IS_ERR(host->nvhost_class)) {
334                 err = PTR_ERR(host->nvhost_class);
335                 dev_err(&host->dev->dev, "failed to create class\n");
336                 goto fail;
337         }
338
339         err = alloc_chrdev_region(&devno, 0, 1, IFACE_NAME);
340         if (err < 0) {
341                 dev_err(&host->dev->dev, "failed to reserve chrdev region\n");
342                 goto fail;
343         }
344
345         cdev_init(&host->cdev, &nvhost_ctrlops);
346         host->cdev.owner = THIS_MODULE;
347         err = cdev_add(&host->cdev, devno, 1);
348         if (err < 0)
349                 goto fail;
350         host->ctrl = device_create(host->nvhost_class, NULL, devno, NULL,
351                         IFACE_NAME "-ctrl");
352         if (IS_ERR(host->ctrl)) {
353                 err = PTR_ERR(host->ctrl);
354                 dev_err(&host->dev->dev, "failed to create ctrl device\n");
355                 goto fail;
356         }
357
358         return 0;
359 fail:
360         return err;
361 }
362
363 struct nvhost_device *nvhost_get_device(char *name)
364 {
365         if (host_device_op().get_nvhost_device)
366                 return host_device_op().get_nvhost_device(name);
367         pr_warn("%s: nvhost device %s does not exist\n", __func__, name);
368         return NULL;
369 }
370
371 struct nvhost_channel *nvhost_alloc_channel(int index)
372 {
373         BUG_ON(!host_device_op().alloc_nvhost_channel);
374         return host_device_op().alloc_nvhost_channel(index);
375 }
376
377 void nvhost_free_channel(struct nvhost_channel *ch)
378 {
379         BUG_ON(!host_device_op().free_nvhost_channel);
380         host_device_op().free_nvhost_channel(ch);
381 }
382
383 static void nvhost_free_resources(struct nvhost_master *host)
384 {
385         kfree(host->intr.syncpt);
386         host->intr.syncpt = 0;
387 }
388
389 static int __devinit nvhost_alloc_resources(struct nvhost_master *host)
390 {
391         int err;
392
393         err = nvhost_init_chip_support(host);
394         if (err)
395                 return err;
396
397         host->intr.syncpt = kzalloc(sizeof(struct nvhost_intr_syncpt) *
398                                     host->syncpt.nb_pts, GFP_KERNEL);
399
400         if (!host->intr.syncpt) {
401                 /* frees happen in the support removal phase */
402                 return -ENOMEM;
403         }
404
405         return 0;
406 }
407
408 static struct resource nvhost_resources[] = {
409         {
410                 .start = TEGRA_HOST1X_BASE,
411                 .end = TEGRA_HOST1X_BASE + TEGRA_HOST1X_SIZE - 1,
412                 .flags = IORESOURCE_MEM,
413         },
414         {
415                 .start = TEGRA_DISPLAY_BASE,
416                 .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE - 1,
417                 .flags = IORESOURCE_MEM,
418         },
419         {
420                 .start = TEGRA_DISPLAY2_BASE,
421                 .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1,
422                 .flags = IORESOURCE_MEM,
423         },
424         {
425                 .start = TEGRA_VI_BASE,
426                 .end = TEGRA_VI_BASE + TEGRA_VI_SIZE - 1,
427                 .flags = IORESOURCE_MEM,
428         },
429         {
430                 .start = TEGRA_ISP_BASE,
431                 .end = TEGRA_ISP_BASE + TEGRA_ISP_SIZE - 1,
432                 .flags = IORESOURCE_MEM,
433         },
434         {
435                 .start = TEGRA_MPE_BASE,
436                 .end = TEGRA_MPE_BASE + TEGRA_MPE_SIZE - 1,
437                 .flags = IORESOURCE_MEM,
438         },
439         {
440                 .start = TEGRA_MSENC_BASE,
441                 .end = TEGRA_MSENC_BASE + TEGRA_MSENC_SIZE - 1,
442                 .flags = IORESOURCE_MEM,
443         },
444         {
445                 .start = TEGRA_TSEC_BASE,
446                 .end = TEGRA_TSEC_BASE + TEGRA_TSEC_SIZE - 1,
447                 .flags = IORESOURCE_MEM,
448         },
449         {
450                 .start = INT_SYNCPT_THRESH_BASE,
451                 .end = INT_SYNCPT_THRESH_BASE + INT_SYNCPT_THRESH_NR - 1,
452                 .flags = IORESOURCE_IRQ,
453         },
454         {
455                 .start = INT_HOST1X_MPCORE_GENERAL,
456                 .end = INT_HOST1X_MPCORE_GENERAL,
457                 .flags = IORESOURCE_IRQ,
458         },
459 };
460
461 struct nvhost_device tegra_grhost_device = {
462         .name = DRIVER_NAME,
463         .id = -1,
464         .resource = nvhost_resources,
465         .num_resources = ARRAY_SIZE(nvhost_resources),
466         .clocks = {{"host1x", HOST_DEFAULT_RATE}, {} },
467         NVHOST_MODULE_NO_POWERGATE_IDS,
468 };
469
470 static int __devinit nvhost_probe(struct nvhost_device *dev,
471         struct nvhost_device_id *id_table)
472 {
473         struct nvhost_master *host;
474         struct resource *regs, *intr0, *intr1;
475         int i, err;
476
477         regs = nvhost_get_resource(dev, IORESOURCE_MEM, 0);
478         intr0 = nvhost_get_resource(dev, IORESOURCE_IRQ, 0);
479         intr1 = nvhost_get_resource(dev, IORESOURCE_IRQ, 1);
480
481         if (!regs || !intr0 || !intr1) {
482                 dev_err(&dev->dev, "missing required platform resources\n");
483                 return -ENXIO;
484         }
485
486         host = kzalloc(sizeof(*host), GFP_KERNEL);
487         if (!host)
488                 return -ENOMEM;
489
490         host->reg_mem = request_mem_region(regs->start,
491                                         resource_size(regs), dev->name);
492         if (!host->reg_mem) {
493                 dev_err(&dev->dev, "failed to get host register memory\n");
494                 err = -ENXIO;
495                 goto fail;
496         }
497
498         host->aperture = ioremap(regs->start, resource_size(regs));
499         if (!host->aperture) {
500                 dev_err(&dev->dev, "failed to remap host registers\n");
501                 err = -ENXIO;
502                 goto fail;
503         }
504
505         err = nvhost_alloc_resources(host);
506         if (err) {
507                 dev_err(&dev->dev, "failed to init chip support\n");
508                 goto fail;
509         }
510
511         host->memmgr = mem_op().alloc_mgr();
512         if (!host->memmgr) {
513                 dev_err(&dev->dev, "unable to create nvmap client\n");
514                 err = -EIO;
515                 goto fail;
516         }
517
518         /*  Register host1x device as bus master */
519         host->dev = dev;
520
521         /*  Give pointer to host1x via driver */
522         nvhost_set_drvdata(dev, host);
523
524         nvhost_bus_add_host(host);
525
526         err = nvhost_syncpt_init(&tegra_grhost_device, &host->syncpt);
527         if (err)
528                 goto fail;
529
530         err = nvhost_intr_init(&host->intr, intr1->start, intr0->start);
531         if (err)
532                 goto fail;
533
534         err = nvhost_user_init(host);
535         if (err)
536                 goto fail;
537
538         err = nvhost_module_init(&tegra_grhost_device);
539         if (err)
540                 goto fail;
541
542         for (i = 0; i < host->dev->num_clks; i++)
543                 clk_enable(host->dev->clk[i]);
544         nvhost_syncpt_reset(&host->syncpt);
545         for (i = 0; i < host->dev->num_clks; i++)
546                 clk_disable(host->dev->clk[0]);
547
548         nvhost_debug_init(host);
549
550         dev_info(&dev->dev, "initialized\n");
551         return 0;
552
553 fail:
554         nvhost_free_resources(host);
555         if (host->memmgr)
556                 mem_op().put_mgr(host->memmgr);
557         kfree(host);
558         return err;
559 }
560
561 static int __exit nvhost_remove(struct nvhost_device *dev)
562 {
563         struct nvhost_master *host = nvhost_get_drvdata(dev);
564         nvhost_intr_deinit(&host->intr);
565         nvhost_syncpt_deinit(&host->syncpt);
566         nvhost_free_resources(host);
567         return 0;
568 }
569
570 static int nvhost_suspend(struct nvhost_device *dev, pm_message_t state)
571 {
572         struct nvhost_master *host = nvhost_get_drvdata(dev);
573         int ret = 0;
574
575         ret = nvhost_module_suspend(host->dev);
576         dev_info(&dev->dev, "suspend status: %d\n", ret);
577
578         return ret;
579 }
580
581 static int nvhost_resume(struct nvhost_device *dev)
582 {
583         dev_info(&dev->dev, "resuming\n");
584         return 0;
585 }
586
587 static struct nvhost_driver nvhost_driver = {
588         .probe = nvhost_probe,
589         .remove = __exit_p(nvhost_remove),
590         .suspend = nvhost_suspend,
591         .resume = nvhost_resume,
592         .driver = {
593                 .owner = THIS_MODULE,
594                 .name = DRIVER_NAME
595         },
596         .finalize_poweron = power_on_host,
597         .prepare_poweroff = power_off_host,
598 };
599
600 static int __init nvhost_mod_init(void)
601 {
602         register_sets = tegra_gpu_register_sets();
603         return nvhost_driver_register(&nvhost_driver);
604 }
605
606 static void __exit nvhost_mod_exit(void)
607 {
608         nvhost_driver_unregister(&nvhost_driver);
609 }
610
611 /* host1x master device needs nvmap to be instantiated first.
612  * nvmap is instantiated via fs_initcall.
613  * Hence instantiate host1x master device using rootfs_initcall
614  * which is one level after fs_initcall. */
615 rootfs_initcall(nvhost_mod_init);
616 module_exit(nvhost_mod_exit);
617
618 module_param_call(register_sets, NULL, param_get_uint, &register_sets, 0444);
619 MODULE_PARM_DESC(register_sets, "Number of register sets");
620
621 MODULE_AUTHOR("NVIDIA");
622 MODULE_DESCRIPTION("Graphics host driver for Tegra products");
623 MODULE_VERSION("1.0");
624 MODULE_LICENSE("GPL");
625 MODULE_ALIAS("platform-nvhost");