aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra/host/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/host/dev.c')
-rw-r--r--drivers/video/tegra/host/dev.c635
1 files changed, 635 insertions, 0 deletions
diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c
new file mode 100644
index 00000000000..8f0c0393401
--- /dev/null
+++ b/drivers/video/tegra/host/dev.c
@@ -0,0 +1,635 @@
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/clk.h>
29#include <linux/hrtimer.h>
30
31#include "dev.h"
32#define CREATE_TRACE_POINTS
33#include <trace/events/nvhost.h>
34
35#include <linux/io.h>
36
37#include <linux/nvhost.h>
38#include <linux/nvhost_ioctl.h>
39#include <mach/nvmap.h>
40#include <mach/gpufuse.h>
41#include <mach/hardware.h>
42#include <mach/iomap.h>
43
44#include "debug.h"
45#include "nvhost_job.h"
46#include "t20/t20.h"
47#include "t30/t30.h"
48#include "bus_client.h"
49
50#define DRIVER_NAME "host1x"
51
52int nvhost_major;
53int nvhost_minor;
54
55static unsigned int register_sets;
56
57struct nvhost_ctrl_userctx {
58 struct nvhost_master *dev;
59 u32 *mod_locks;
60};
61
62static int nvhost_ctrlrelease(struct inode *inode, struct file *filp)
63{
64 struct nvhost_ctrl_userctx *priv = filp->private_data;
65 int i;
66
67 trace_nvhost_ctrlrelease(priv->dev->dev->name);
68
69 filp->private_data = NULL;
70 if (priv->mod_locks[0])
71 nvhost_module_idle(priv->dev->dev);
72 for (i = 1; i < priv->dev->syncpt.nb_mlocks; i++)
73 if (priv->mod_locks[i])
74 nvhost_mutex_unlock(&priv->dev->syncpt, i);
75 kfree(priv->mod_locks);
76 kfree(priv);
77 return 0;
78}
79
80static int nvhost_ctrlopen(struct inode *inode, struct file *filp)
81{
82 struct nvhost_master *host = container_of(inode->i_cdev, struct nvhost_master, cdev);
83 struct nvhost_ctrl_userctx *priv;
84 u32 *mod_locks;
85
86 trace_nvhost_ctrlopen(host->dev->name);
87
88 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
89 mod_locks = kzalloc(sizeof(u32) * host->syncpt.nb_mlocks, GFP_KERNEL);
90
91 if (!(priv && mod_locks)) {
92 kfree(priv);
93 kfree(mod_locks);
94 return -ENOMEM;
95 }
96
97 priv->dev = host;
98 priv->mod_locks = mod_locks;
99 filp->private_data = priv;
100 return 0;
101}
102
103static int nvhost_ioctl_ctrl_syncpt_read(struct nvhost_ctrl_userctx *ctx,
104 struct nvhost_ctrl_syncpt_read_args *args)
105{
106 if (args->id >= ctx->dev->syncpt.nb_pts)
107 return -EINVAL;
108 args->value = nvhost_syncpt_read(&ctx->dev->syncpt, args->id);
109 trace_nvhost_ioctl_ctrl_syncpt_read(args->id, args->value);
110 return 0;
111}
112
113static int nvhost_ioctl_ctrl_syncpt_incr(struct nvhost_ctrl_userctx *ctx,
114 struct nvhost_ctrl_syncpt_incr_args *args)
115{
116 if (args->id >= ctx->dev->syncpt.nb_pts)
117 return -EINVAL;
118 trace_nvhost_ioctl_ctrl_syncpt_incr(args->id);
119 nvhost_syncpt_incr(&ctx->dev->syncpt, args->id);
120 return 0;
121}
122
123static int nvhost_ioctl_ctrl_syncpt_waitex(struct nvhost_ctrl_userctx *ctx,
124 struct nvhost_ctrl_syncpt_waitex_args *args)
125{
126 u32 timeout;
127 int err;
128 if (args->id >= ctx->dev->syncpt.nb_pts)
129 return -EINVAL;
130 if (args->timeout == NVHOST_NO_TIMEOUT)
131 timeout = MAX_SCHEDULE_TIMEOUT;
132 else
133 timeout = (u32)msecs_to_jiffies(args->timeout);
134
135 err = nvhost_syncpt_wait_timeout(&ctx->dev->syncpt, args->id,
136 args->thresh, timeout, &args->value);
137 trace_nvhost_ioctl_ctrl_syncpt_wait(args->id, args->thresh,
138 args->timeout, args->value, err);
139
140 return err;
141}
142
143static int nvhost_ioctl_ctrl_module_mutex(struct nvhost_ctrl_userctx *ctx,
144 struct nvhost_ctrl_module_mutex_args *args)
145{
146 int err = 0;
147 if (args->id >= ctx->dev->syncpt.nb_mlocks ||
148 args->lock > 1)
149 return -EINVAL;
150
151 trace_nvhost_ioctl_ctrl_module_mutex(args->lock, args->id);
152 if (args->lock && !ctx->mod_locks[args->id]) {
153 if (args->id == 0)
154 nvhost_module_busy(ctx->dev->dev);
155 else
156 err = nvhost_mutex_try_lock(&ctx->dev->syncpt,
157 args->id);
158 if (!err)
159 ctx->mod_locks[args->id] = 1;
160 } else if (!args->lock && ctx->mod_locks[args->id]) {
161 if (args->id == 0)
162 nvhost_module_idle(ctx->dev->dev);
163 else
164 nvhost_mutex_unlock(&ctx->dev->syncpt, args->id);
165 ctx->mod_locks[args->id] = 0;
166 }
167 return err;
168}
169
170static struct nvhost_device *get_ndev_by_moduleid(struct nvhost_master *host,
171 u32 id)
172{
173 int i;
174
175 for (i = 0; i < host->nb_channels; i++) {
176 struct nvhost_device *ndev = host->channels[i].dev;
177
178 /* display and dsi do not use channel for register programming.
179 * so their channels do not have device instance.
180 * hence skip such channels from here. */
181 if (ndev == NULL)
182 continue;
183
184 if (id == ndev->moduleid)
185 return ndev;
186 }
187 return NULL;
188}
189
190static int nvhost_ioctl_ctrl_module_regrdwr(struct nvhost_ctrl_userctx *ctx,
191 struct nvhost_ctrl_module_regrdwr_args *args)
192{
193 u32 num_offsets = args->num_offsets;
194 u32 *offsets = args->offsets;
195 u32 *values = args->values;
196 u32 vals[64];
197 struct nvhost_device *ndev;
198
199 trace_nvhost_ioctl_ctrl_module_regrdwr(args->id,
200 args->num_offsets, args->write);
201 /* Check that there is something to read and that block size is
202 * u32 aligned */
203 if (num_offsets == 0 || args->block_size & 3)
204 return -EINVAL;
205
206 ndev = get_ndev_by_moduleid(ctx->dev, args->id);
207 if (!ndev)
208 return -EINVAL;
209
210 while (num_offsets--) {
211 int remaining = args->block_size >> 2;
212 u32 offs;
213 if (get_user(offs, offsets))
214 return -EFAULT;
215 offsets++;
216 while (remaining) {
217 i