aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra/host/nvhost_channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/host/nvhost_channel.c')
-rw-r--r--drivers/video/tegra/host/nvhost_channel.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/drivers/video/tegra/host/nvhost_channel.c b/drivers/video/tegra/host/nvhost_channel.c
new file mode 100644
index 00000000000..a7c03308134
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_channel.c
@@ -0,0 +1,158 @@
1/*
2 * drivers/video/tegra/host/nvhost_channel.c
3 *
4 * Tegra Graphics Host Channel
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 "nvhost_channel.h"
22#include "dev.h"
23#include "nvhost_job.h"
24#include <trace/events/nvhost.h>
25#include <linux/nvhost_ioctl.h>
26#include <linux/slab.h>
27
28#include <linux/platform_device.h>
29
30#define NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT 50
31
32int nvhost_channel_init(struct nvhost_channel *ch,
33 struct nvhost_master *dev, int index)
34{
35 int err;
36 struct nvhost_device *ndev;
37 struct resource *r = NULL;
38 void __iomem *regs = NULL;
39 struct resource *reg_mem = NULL;
40
41 /* Link nvhost_device to nvhost_channel */
42 err = host_channel_op(dev).init(ch, dev, index);
43 if (err < 0) {
44 dev_err(&dev->dev->dev, "failed to init channel %d\n",
45 index);
46 return err;
47 }
48 ndev = ch->dev;
49 ndev->channel = ch;
50
51 /* Map IO memory related to nvhost_device */
52 if (ndev->moduleid != NVHOST_MODULE_NONE) {
53 /* First one is host1x - skip that */
54 r = nvhost_get_resource(dev->dev,
55 IORESOURCE_MEM, ndev->moduleid + 1);
56 if (!r)
57 goto fail;
58
59 reg_mem = request_mem_region(r->start,
60 resource_size(r), ndev->name);
61 if (!reg_mem)
62 goto fail;
63
64 regs = ioremap(r->start, resource_size(r));
65 if (!regs)
66 goto fail;
67
68 ndev->reg_mem = reg_mem;
69 ndev->aperture = regs;
70 }
71 return 0;
72
73fail:
74 if (reg_mem)
75 release_mem_region(r->start, resource_size(r));
76 if (regs)
77 iounmap(regs);
78 dev_err(&ndev->dev, "failed to get register memory\n");
79 return -ENXIO;
80
81}
82
83int nvhost_channel_submit(struct nvhost_job *job)
84{
85 /* Low priority submits wait until sync queue is empty. Ignores result
86 * from nvhost_cdma_flush, as we submit either when push buffer is
87 * empty or when we reach the timeout. */
88 if (job->priority < NVHOST_PRIORITY_MEDIUM)
89 (void)nvhost_cdma_flush(&job->ch->cdma,
90 NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT);
91
92 return channel_op(job->ch).submit(job);
93}
94
95struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch)
96{
97 int err = 0;
98 mutex_lock(&ch->reflock);
99 if (ch->refcount == 0) {
100 if (ch->dev->init)
101 ch->dev->init(ch->dev);
102 err = nvhost_cdma_init(&ch->cdma);
103 } else if (ch->dev->exclusive) {
104 err = -EBUSY;
105 }
106 if (!err)
107 ch->refcount++;
108
109 mutex_unlock(&ch->reflock);
110
111 /* Keep alive modules that needs to be when a channel is open */
112 if (!err && ch->dev->keepalive)
113 nvhost_module_busy(ch->dev);
114
115 return err ? NULL : ch;
116}
117
118void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx)
119{
120 BUG_ON(!channel_cdma_op(ch).stop);
121
122 if (ctx) {
123 mutex_lock(&ch->submitlock);
124 if (ch->cur_ctx == ctx)
125 ch->cur_ctx = NULL;
126 mutex_unlock(&ch->submitlock);
127 }
128
129 /* Allow keep-alive'd module to be turned off */
130 if (ch->dev->keepalive)
131 nvhost_module_idle(ch->dev);
132
133 mutex_lock(&ch->reflock);
134 if (ch->refcount == 1) {
135 channel_cdma_op(ch).stop(&ch->cdma);
136 nvhost_cdma_deinit(&ch->cdma);
137 nvhost_module_suspend(ch->dev, false);
138 }
139 ch->refcount--;
140 mutex_unlock(&ch->reflock);
141}
142
143int nvhost_channel_suspend(struct nvhost_channel *ch)
144{
145 int ret = 0;
146
147 mutex_lock(&ch->reflock);
148 BUG_ON(!channel_cdma_op(ch).stop);
149
150 if (ch->refcount) {
151 ret = nvhost_module_suspend(ch->dev, false);
152 if (!ret)
153 channel_cdma_op(ch).stop(&ch->cdma);
154 }
155 mutex_unlock(&ch->reflock);
156
157 return ret;
158}