diff options
Diffstat (limited to 'drivers/video/tegra/host/nvhost_channel.c')
-rw-r--r-- | drivers/video/tegra/host/nvhost_channel.c | 158 |
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 | |||
32 | int 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 | |||
73 | fail: | ||
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 | |||
83 | int 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 | |||
95 | struct 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 | |||
118 | void 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 | |||
143 | int 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 | } | ||