diff options
Diffstat (limited to 'drivers/gpu/host1x/hw')
-rw-r--r-- | drivers/gpu/host1x/hw/Makefile | 6 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/cdma_hw.c | 326 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/channel_hw.c | 168 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/debug_hw.c | 322 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/host1x01.c | 42 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/host1x01.h | 25 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/host1x01_hardware.h | 143 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/hw_host1x01_channel.h | 120 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/hw_host1x01_sync.h | 243 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/hw_host1x01_uclass.h | 174 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/intr_hw.c | 143 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/syncpt_hw.c | 114 |
12 files changed, 1826 insertions, 0 deletions
diff --git a/drivers/gpu/host1x/hw/Makefile b/drivers/gpu/host1x/hw/Makefile new file mode 100644 index 000000000000..9b50863a2236 --- /dev/null +++ b/drivers/gpu/host1x/hw/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | ccflags-y = -Idrivers/gpu/host1x | ||
2 | |||
3 | host1x-hw-objs = \ | ||
4 | host1x01.o | ||
5 | |||
6 | obj-$(CONFIG_TEGRA_HOST1X) += host1x-hw.o | ||
diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c new file mode 100644 index 000000000000..590b69d91dab --- /dev/null +++ b/drivers/gpu/host1x/hw/cdma_hw.c | |||
@@ -0,0 +1,326 @@ | |||
1 | /* | ||
2 | * Tegra host1x Command DMA | ||
3 | * | ||
4 | * Copyright (c) 2010-2013, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/slab.h> | ||
20 | #include <linux/scatterlist.h> | ||
21 | #include <linux/dma-mapping.h> | ||
22 | |||
23 | #include "cdma.h" | ||
24 | #include "channel.h" | ||
25 | #include "dev.h" | ||
26 | #include "debug.h" | ||
27 | |||
28 | /* | ||
29 | * Put the restart at the end of pushbuffer memor | ||
30 | */ | ||
31 | static void push_buffer_init(struct push_buffer *pb) | ||
32 | { | ||
33 | *(pb->mapped + (pb->size_bytes >> 2)) = host1x_opcode_restart(0); | ||
34 | } | ||
35 | |||
36 | /* | ||
37 | * Increment timedout buffer's syncpt via CPU. | ||
38 | */ | ||
39 | static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr, | ||
40 | u32 syncpt_incrs, u32 syncval, u32 nr_slots) | ||
41 | { | ||
42 | struct host1x *host1x = cdma_to_host1x(cdma); | ||
43 | struct push_buffer *pb = &cdma->push_buffer; | ||
44 | u32 i; | ||
45 | |||
46 | for (i = 0; i < syncpt_incrs; i++) | ||
47 | host1x_syncpt_cpu_incr(cdma->timeout.syncpt); | ||
48 | |||
49 | /* after CPU incr, ensure shadow is up to date */ | ||
50 | host1x_syncpt_load(cdma->timeout.syncpt); | ||
51 | |||
52 | /* NOP all the PB slots */ | ||
53 | while (nr_slots--) { | ||
54 | u32 *p = (u32 *)((u32)pb->mapped + getptr); | ||
55 | *(p++) = HOST1X_OPCODE_NOP; | ||
56 | *(p++) = HOST1X_OPCODE_NOP; | ||
57 | dev_dbg(host1x->dev, "%s: NOP at 0x%x\n", __func__, | ||
58 | pb->phys + getptr); | ||
59 | getptr = (getptr + 8) & (pb->size_bytes - 1); | ||
60 | } | ||
61 | wmb(); | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * Start channel DMA | ||
66 | */ | ||
67 | static void cdma_start(struct host1x_cdma *cdma) | ||
68 | { | ||
69 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
70 | |||
71 | if (cdma->running) | ||
72 | return; | ||
73 | |||
74 | cdma->last_pos = cdma->push_buffer.pos; | ||
75 | |||
76 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
77 | HOST1X_CHANNEL_DMACTRL); | ||
78 | |||
79 | /* set base, put and end pointer */ | ||
80 | host1x_ch_writel(ch, cdma->push_buffer.phys, HOST1X_CHANNEL_DMASTART); | ||
81 | host1x_ch_writel(ch, cdma->push_buffer.pos, HOST1X_CHANNEL_DMAPUT); | ||
82 | host1x_ch_writel(ch, cdma->push_buffer.phys + | ||
83 | cdma->push_buffer.size_bytes + 4, | ||
84 | HOST1X_CHANNEL_DMAEND); | ||
85 | |||
86 | /* reset GET */ | ||
87 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP | | ||
88 | HOST1X_CHANNEL_DMACTRL_DMAGETRST | | ||
89 | HOST1X_CHANNEL_DMACTRL_DMAINITGET, | ||
90 | HOST1X_CHANNEL_DMACTRL); | ||
91 | |||
92 | /* start the command DMA */ | ||
93 | host1x_ch_writel(ch, 0, HOST1X_CHANNEL_DMACTRL); | ||
94 | |||
95 | cdma->running = true; | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * Similar to cdma_start(), but rather than starting from an idle | ||
100 | * state (where DMA GET is set to DMA PUT), on a timeout we restore | ||
101 | * DMA GET from an explicit value (so DMA may again be pending). | ||
102 | */ | ||
103 | static void cdma_timeout_restart(struct host1x_cdma *cdma, u32 getptr) | ||
104 | { | ||
105 | struct host1x *host1x = cdma_to_host1x(cdma); | ||
106 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
107 | |||
108 | if (cdma->running) | ||
109 | return; | ||
110 | |||
111 | cdma->last_pos = cdma->push_buffer.pos; | ||
112 | |||
113 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
114 | HOST1X_CHANNEL_DMACTRL); | ||
115 | |||
116 | /* set base, end pointer (all of memory) */ | ||
117 | host1x_ch_writel(ch, cdma->push_buffer.phys, HOST1X_CHANNEL_DMASTART); | ||
118 | host1x_ch_writel(ch, cdma->push_buffer.phys + | ||
119 | cdma->push_buffer.size_bytes, | ||
120 | HOST1X_CHANNEL_DMAEND); | ||
121 | |||
122 | /* set GET, by loading the value in PUT (then reset GET) */ | ||
123 | host1x_ch_writel(ch, getptr, HOST1X_CHANNEL_DMAPUT); | ||
124 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP | | ||
125 | HOST1X_CHANNEL_DMACTRL_DMAGETRST | | ||
126 | HOST1X_CHANNEL_DMACTRL_DMAINITGET, | ||
127 | HOST1X_CHANNEL_DMACTRL); | ||
128 | |||
129 | dev_dbg(host1x->dev, | ||
130 | "%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n", __func__, | ||
131 | host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET), | ||
132 | host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT), | ||
133 | cdma->last_pos); | ||
134 | |||
135 | /* deassert GET reset and set PUT */ | ||
136 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
137 | HOST1X_CHANNEL_DMACTRL); | ||
138 | host1x_ch_writel(ch, cdma->push_buffer.pos, HOST1X_CHANNEL_DMAPUT); | ||
139 | |||
140 | /* start the command DMA */ | ||
141 | host1x_ch_writel(ch, 0, HOST1X_CHANNEL_DMACTRL); | ||
142 | |||
143 | cdma->running = true; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * Kick channel DMA into action by writing its PUT offset (if it has changed) | ||
148 | */ | ||
149 | static void cdma_flush(struct host1x_cdma *cdma) | ||
150 | { | ||
151 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
152 | |||
153 | if (cdma->push_buffer.pos != cdma->last_pos) { | ||
154 | host1x_ch_writel(ch, cdma->push_buffer.pos, | ||
155 | HOST1X_CHANNEL_DMAPUT); | ||
156 | cdma->last_pos = cdma->push_buffer.pos; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static void cdma_stop(struct host1x_cdma *cdma) | ||
161 | { | ||
162 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
163 | |||
164 | mutex_lock(&cdma->lock); | ||
165 | if (cdma->running) { | ||
166 | host1x_cdma_wait_locked(cdma, CDMA_EVENT_SYNC_QUEUE_EMPTY); | ||
167 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
168 | HOST1X_CHANNEL_DMACTRL); | ||
169 | cdma->running = false; | ||
170 | } | ||
171 | mutex_unlock(&cdma->lock); | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * Stops both channel's command processor and CDMA immediately. | ||
176 | * Also, tears down the channel and resets corresponding module. | ||
177 | */ | ||
178 | static void cdma_freeze(struct host1x_cdma *cdma) | ||
179 | { | ||
180 | struct host1x *host = cdma_to_host1x(cdma); | ||
181 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
182 | u32 cmdproc_stop; | ||
183 | |||
184 | if (cdma->torndown && !cdma->running) { | ||
185 | dev_warn(host->dev, "Already torn down\n"); | ||
186 | return; | ||
187 | } | ||
188 | |||
189 | dev_dbg(host->dev, "freezing channel (id %d)\n", ch->id); | ||
190 | |||
191 | cmdproc_stop = host1x_sync_readl(host, HOST1X_SYNC_CMDPROC_STOP); | ||
192 | cmdproc_stop |= BIT(ch->id); | ||
193 | host1x_sync_writel(host, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP); | ||
194 | |||
195 | dev_dbg(host->dev, "%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n", | ||
196 | __func__, host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET), | ||
197 | host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT), | ||
198 | cdma->last_pos); | ||
199 | |||
200 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
201 | HOST1X_CHANNEL_DMACTRL); | ||
202 | |||
203 | host1x_sync_writel(host, BIT(ch->id), HOST1X_SYNC_CH_TEARDOWN); | ||
204 | |||
205 | cdma->running = false; | ||
206 | cdma->torndown = true; | ||
207 | } | ||
208 | |||
209 | static void cdma_resume(struct host1x_cdma *cdma, u32 getptr) | ||
210 | { | ||
211 | struct host1x *host1x = cdma_to_host1x(cdma); | ||
212 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
213 | u32 cmdproc_stop; | ||
214 | |||
215 | dev_dbg(host1x->dev, | ||
216 | "resuming channel (id %d, DMAGET restart = 0x%x)\n", | ||
217 | ch->id, getptr); | ||
218 | |||
219 | cmdproc_stop = host1x_sync_readl(host1x, HOST1X_SYNC_CMDPROC_STOP); | ||
220 | cmdproc_stop &= ~(BIT(ch->id)); | ||
221 | host1x_sync_writel(host1x, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP); | ||
222 | |||
223 | cdma->torndown = false; | ||
224 | cdma_timeout_restart(cdma, getptr); | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | * If this timeout fires, it indicates the current sync_queue entry has | ||
229 | * exceeded its TTL and the userctx should be timed out and remaining | ||
230 | * submits already issued cleaned up (future submits return an error). | ||
231 | */ | ||
232 | static void cdma_timeout_handler(struct work_struct *work) | ||
233 | { | ||
234 | struct host1x_cdma *cdma; | ||
235 | struct host1x *host1x; | ||
236 | struct host1x_channel *ch; | ||
237 | |||
238 | u32 syncpt_val; | ||
239 | |||
240 | u32 prev_cmdproc, cmdproc_stop; | ||
241 | |||
242 | cdma = container_of(to_delayed_work(work), struct host1x_cdma, | ||
243 | timeout.wq); | ||
244 | host1x = cdma_to_host1x(cdma); | ||
245 | ch = cdma_to_channel(cdma); | ||
246 | |||
247 | host1x_debug_dump(cdma_to_host1x(cdma)); | ||
248 | |||
249 | mutex_lock(&cdma->lock); | ||
250 | |||
251 | if (!cdma->timeout.client) { | ||
252 | dev_dbg(host1x->dev, | ||
253 | "cdma_timeout: expired, but has no clientid\n"); | ||
254 | mutex_unlock(&cdma->lock); | ||
255 | return; | ||
256 | } | ||
257 | |||
258 | /* stop processing to get a clean snapshot */ | ||
259 | prev_cmdproc = host1x_sync_readl(host1x, HOST1X_SYNC_CMDPROC_STOP); | ||
260 | cmdproc_stop = prev_cmdproc | BIT(ch->id); | ||
261 | host1x_sync_writel(host1x, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP); | ||
262 | |||
263 | dev_dbg(host1x->dev, "cdma_timeout: cmdproc was 0x%x is 0x%x\n", | ||
264 | prev_cmdproc, cmdproc_stop); | ||
265 | |||
266 | syncpt_val = host1x_syncpt_load(cdma->timeout.syncpt); | ||
267 | |||
268 | /* has buffer actually completed? */ | ||
269 | if ((s32)(syncpt_val - cdma->timeout.syncpt_val) >= 0) { | ||
270 | dev_dbg(host1x->dev, | ||
271 | "cdma_timeout: expired, but buffer had completed\n"); | ||
272 | /* restore */ | ||
273 | cmdproc_stop = prev_cmdproc & ~(BIT(ch->id)); | ||
274 | host1x_sync_writel(host1x, cmdproc_stop, | ||
275 | HOST1X_SYNC_CMDPROC_STOP); | ||
276 | mutex_unlock(&cdma->lock); | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | dev_warn(host1x->dev, "%s: timeout: %d (%s), HW thresh %d, done %d\n", | ||
281 | __func__, cdma->timeout.syncpt->id, cdma->timeout.syncpt->name, | ||
282 | syncpt_val, cdma->timeout.syncpt_val); | ||
283 | |||
284 | /* stop HW, resetting channel/module */ | ||
285 | host1x_hw_cdma_freeze(host1x, cdma); | ||
286 | |||
287 | host1x_cdma_update_sync_queue(cdma, ch->dev); | ||
288 | mutex_unlock(&cdma->lock); | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * Init timeout resources | ||
293 | */ | ||
294 | static int cdma_timeout_init(struct host1x_cdma *cdma, u32 syncpt_id) | ||
295 | { | ||
296 | INIT_DELAYED_WORK(&cdma->timeout.wq, cdma_timeout_handler); | ||
297 | cdma->timeout.initialized = true; | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * Clean up timeout resources | ||
304 | */ | ||
305 | static void cdma_timeout_destroy(struct host1x_cdma *cdma) | ||
306 | { | ||
307 | if (cdma->timeout.initialized) | ||
308 | cancel_delayed_work(&cdma->timeout.wq); | ||
309 | cdma->timeout.initialized = false; | ||
310 | } | ||
311 | |||
312 | static const struct host1x_cdma_ops host1x_cdma_ops = { | ||
313 | .start = cdma_start, | ||
314 | .stop = cdma_stop, | ||
315 | .flush = cdma_flush, | ||
316 | |||
317 | .timeout_init = cdma_timeout_init, | ||
318 | .timeout_destroy = cdma_timeout_destroy, | ||
319 | .freeze = cdma_freeze, | ||
320 | .resume = cdma_resume, | ||
321 | .timeout_cpu_incr = cdma_timeout_cpu_incr, | ||
322 | }; | ||
323 | |||
324 | static const struct host1x_pushbuffer_ops host1x_pushbuffer_ops = { | ||
325 | .init = push_buffer_init, | ||
326 | }; | ||
diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c new file mode 100644 index 000000000000..ee199623e365 --- /dev/null +++ b/drivers/gpu/host1x/hw/channel_hw.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * Tegra host1x Channel | ||
3 | * | ||
4 | * Copyright (c) 2010-2013, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/slab.h> | ||
20 | #include <trace/events/host1x.h> | ||
21 | |||
22 | #include "host1x.h" | ||
23 | #include "host1x_bo.h" | ||
24 | #include "channel.h" | ||
25 | #include "dev.h" | ||
26 | #include "intr.h" | ||
27 | #include "job.h" | ||
28 | |||
29 | #define HOST1X_CHANNEL_SIZE 16384 | ||
30 | #define TRACE_MAX_LENGTH 128U | ||
31 | |||
32 | static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo, | ||
33 | u32 offset, u32 words) | ||
34 | { | ||
35 | void *mem = NULL; | ||
36 | |||
37 | if (host1x_debug_trace_cmdbuf) | ||
38 | mem = host1x_bo_mmap(bo); | ||
39 | |||
40 | if (mem) { | ||
41 | u32 i; | ||
42 | /* | ||
43 | * Write in batches of 128 as there seems to be a limit | ||
44 | * of how much you can output to ftrace at once. | ||
45 | */ | ||
46 | for (i = 0; i < words; i += TRACE_MAX_LENGTH) { | ||
47 | trace_host1x_cdma_push_gather( | ||
48 | dev_name(cdma_to_channel(cdma)->dev), | ||
49 | (u32)bo, min(words - i, TRACE_MAX_LENGTH), | ||
50 | offset + i * sizeof(u32), mem); | ||
51 | } | ||
52 | host1x_bo_munmap(bo, mem); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | static void submit_gathers(struct host1x_job *job) | ||
57 | { | ||
58 | struct host1x_cdma *cdma = &job->channel->cdma; | ||
59 | unsigned int i; | ||
60 | |||
61 | for (i = 0; i < job->num_gathers; i++) { | ||
62 | struct host1x_job_gather *g = &job->gathers[i]; | ||
63 | u32 op1 = host1x_opcode_gather(g->words); | ||
64 | u32 op2 = g->base + g->offset; | ||
65 | trace_write_gather(cdma, g->bo, g->offset, op1 & 0xffff); | ||
66 | host1x_cdma_push(cdma, op1, op2); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static int channel_submit(struct host1x_job *job) | ||
71 | { | ||
72 | struct host1x_channel *ch = job->channel; | ||
73 | struct host1x_syncpt *sp; | ||
74 | u32 user_syncpt_incrs = job->syncpt_incrs; | ||
75 | u32 prev_max = 0; | ||
76 | u32 syncval; | ||
77 | int err; | ||
78 | struct host1x_waitlist *completed_waiter = NULL; | ||
79 | struct host1x *host = dev_get_drvdata(ch->dev->parent); | ||
80 | |||
81 | sp = host->syncpt + job->syncpt_id; | ||
82 | trace_host1x_channel_submit(dev_name(ch->dev), | ||
83 | job->num_gathers, job->num_relocs, | ||
84 | job->num_waitchk, job->syncpt_id, | ||
85 | job->syncpt_incrs); | ||
86 | |||
87 | /* before error checks, return current max */ | ||
88 | prev_max = job->syncpt_end = host1x_syncpt_read_max(sp); | ||
89 | |||
90 | /* get submit lock */ | ||
91 | err = mutex_lock_interruptible(&ch->submitlock); | ||
92 | if (err) | ||
93 | goto error; | ||
94 | |||
95 | completed_waiter = kzalloc(sizeof(*completed_waiter), GFP_KERNEL); | ||
96 | if (!completed_waiter) { | ||
97 | mutex_unlock(&ch->submitlock); | ||
98 | err = -ENOMEM; | ||
99 | goto error; | ||
100 | } | ||
101 | |||
102 | /* begin a CDMA submit */ | ||
103 | err = host1x_cdma_begin(&ch->cdma, job); | ||
104 | if (err) { | ||
105 | mutex_unlock(&ch->submitlock); | ||
106 | goto error; | ||
107 | } | ||
108 | |||
109 | if (job->serialize) { | ||
110 | /* | ||
111 | * Force serialization by inserting a host wait for the | ||
112 | * previous job to finish before this one can commence. | ||
113 | */ | ||
114 | host1x_cdma_push(&ch->cdma, | ||
115 | host1x_opcode_setclass(HOST1X_CLASS_HOST1X, | ||
116 | host1x_uclass_wait_syncpt_r(), 1), | ||
117 | host1x_class_host_wait_syncpt(job->syncpt_id, | ||
118 | host1x_syncpt_read_max(sp))); | ||
119 | } | ||
120 | |||
121 | syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs); | ||
122 | |||
123 | job->syncpt_end = syncval; | ||
124 | |||
125 | /* add a setclass for modules that require it */ | ||
126 | if (job->class) | ||
127 | host1x_cdma_push(&ch->cdma, | ||
128 | host1x_opcode_setclass(job->class, 0, 0), | ||
129 | HOST1X_OPCODE_NOP); | ||
130 | |||
131 | submit_gathers(job); | ||
132 | |||
133 | /* end CDMA submit & stash pinned hMems into sync queue */ | ||
134 | host1x_cdma_end(&ch->cdma, job); | ||
135 | |||
136 | trace_host1x_channel_submitted(dev_name(ch->dev), prev_max, syncval); | ||
137 | |||
138 | /* schedule a submit complete interrupt */ | ||
139 | err = host1x_intr_add_action(host, job->syncpt_id, syncval, | ||
140 | HOST1X_INTR_ACTION_SUBMIT_COMPLETE, ch, | ||
141 | completed_waiter, NULL); | ||
142 | completed_waiter = NULL; | ||
143 | WARN(err, "Failed to set submit complete interrupt"); | ||
144 | |||
145 | mutex_unlock(&ch->submitlock); | ||
146 | |||
147 | return 0; | ||
148 | |||
149 | error: | ||
150 | kfree(completed_waiter); | ||
151 | return err; | ||
152 | } | ||
153 | |||
154 | static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev, | ||
155 | unsigned int index) | ||
156 | { | ||
157 | ch->id = index; | ||
158 | mutex_init(&ch->reflock); | ||
159 | mutex_init(&ch->submitlock); | ||
160 | |||
161 | ch->regs = dev->regs + index * HOST1X_CHANNEL_SIZE; | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static const struct host1x_channel_ops host1x_channel_ops = { | ||
166 | .init = host1x_channel_init, | ||
167 | .submit = channel_submit, | ||
168 | }; | ||
diff --git a/drivers/gpu/host1x/hw/debug_hw.c b/drivers/gpu/host1x/hw/debug_hw.c new file mode 100644 index 000000000000..334c038052f5 --- /dev/null +++ b/drivers/gpu/host1x/hw/debug_hw.c | |||
@@ -0,0 +1,322 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Google, Inc. | ||
3 | * Author: Erik Gilling <konkers@android.com> | ||
4 | * | ||
5 | * Copyright (C) 2011-2013 NVIDIA Corporation | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/debugfs.h> | ||
19 | #include <linux/seq_file.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/scatterlist.h> | ||
22 | |||
23 | #include <linux/io.h> | ||
24 | |||
25 | #include "dev.h" | ||
26 | #include "debug.h" | ||
27 | #include "cdma.h" | ||
28 | #include "channel.h" | ||
29 | #include "host1x_bo.h" | ||
30 | |||
31 | #define HOST1X_DEBUG_MAX_PAGE_OFFSET 102400 | ||
32 | |||
33 | enum { | ||
34 | HOST1X_OPCODE_SETCLASS = 0x00, | ||
35 | HOST1X_OPCODE_INCR = 0x01, | ||
36 | HOST1X_OPCODE_NONINCR = 0x02, | ||
37 | HOST1X_OPCODE_MASK = 0x03, | ||
38 | HOST1X_OPCODE_IMM = 0x04, | ||
39 | HOST1X_OPCODE_RESTART = 0x05, | ||
40 | HOST1X_OPCODE_GATHER = 0x06, | ||
41 | HOST1X_OPCODE_EXTEND = 0x0e, | ||
42 | }; | ||
43 | |||
44 | enum { | ||
45 | HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK = 0x00, | ||
46 | HOST1X_OPCODE_EXTEND_RELEASE_MLOCK = 0x01, | ||
47 | }; | ||
48 | |||
49 | static unsigned int show_channel_command(struct output *o, u32 val) | ||
50 | { | ||
51 | unsigned mask; | ||
52 | unsigned subop; | ||
53 | |||
54 | switch (val >> 28) { | ||
55 | case HOST1X_OPCODE_SETCLASS: | ||
56 | mask = val & 0x3f; | ||
57 | if (mask) { | ||
58 | host1x_debug_output(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [", | ||
59 | val >> 6 & 0x3ff, | ||
60 | val >> 16 & 0xfff, mask); | ||
61 | return hweight8(mask); | ||
62 | } else { | ||
63 | host1x_debug_output(o, "SETCL(class=%03x)\n", | ||
64 | val >> 6 & 0x3ff); | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | case HOST1X_OPCODE_INCR: | ||
69 | host1x_debug_output(o, "INCR(offset=%03x, [", | ||
70 | val >> 16 & 0xfff); | ||
71 | return val & 0xffff; | ||
72 | |||
73 | case HOST1X_OPCODE_NONINCR: | ||
74 | host1x_debug_output(o, "NONINCR(offset=%03x, [", | ||
75 | val >> 16 & 0xfff); | ||
76 | return val & 0xffff; | ||
77 | |||
78 | case HOST1X_OPCODE_MASK: | ||
79 | mask = val & 0xffff; | ||
80 | host1x_debug_output(o, "MASK(offset=%03x, mask=%03x, [", | ||
81 | val >> 16 & 0xfff, mask); | ||
82 | return hweight16(mask); | ||
83 | |||
84 | case HOST1X_OPCODE_IMM: | ||
85 | host1x_debug_output(o, "IMM(offset=%03x, data=%03x)\n", | ||
86 | val >> 16 & 0xfff, val & 0xffff); | ||
87 | return 0; | ||
88 | |||
89 | case HOST1X_OPCODE_RESTART: | ||
90 | host1x_debug_output(o, "RESTART(offset=%08x)\n", val << 4); | ||
91 | return 0; | ||
92 | |||
93 | case HOST1X_OPCODE_GATHER: | ||
94 | host1x_debug_output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[", | ||
95 | val >> 16 & 0xfff, val >> 15 & 0x1, | ||
96 | val >> 14 & 0x1, val & 0x3fff); | ||
97 | return 1; | ||
98 | |||
99 | case HOST1X_OPCODE_EXTEND: | ||
100 | subop = val >> 24 & 0xf; | ||
101 | if (subop == HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK) | ||
102 | host1x_debug_output(o, "ACQUIRE_MLOCK(index=%d)\n", | ||
103 | val & 0xff); | ||
104 | else if (subop == HOST1X_OPCODE_EXTEND_RELEASE_MLOCK) | ||
105 | host1x_debug_output(o, "RELEASE_MLOCK(index=%d)\n", | ||
106 | val & 0xff); | ||
107 | else | ||
108 | host1x_debug_output(o, "EXTEND_UNKNOWN(%08x)\n", val); | ||
109 | return 0; | ||
110 | |||
111 | default: | ||
112 | return 0; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | static void show_gather(struct output *o, phys_addr_t phys_addr, | ||
117 | unsigned int words, struct host1x_cdma *cdma, | ||
118 | phys_addr_t pin_addr, u32 *map_addr) | ||
119 | { | ||
120 | /* Map dmaget cursor to corresponding mem handle */ | ||
121 | u32 offset = phys_addr - pin_addr; | ||
122 | unsigned int data_count = 0, i; | ||
123 | |||
124 | /* | ||
125 | * Sometimes we're given different hardware address to the same | ||
126 | * page - in these cases the offset will get an invalid number and | ||
127 | * we just have to bail out. | ||
128 | */ | ||
129 | if (offset > HOST1X_DEBUG_MAX_PAGE_OFFSET) { | ||
130 | host1x_debug_output(o, "[address mismatch]\n"); | ||
131 | return; | ||
132 | } | ||
133 | |||
134 | for (i = 0; i < words; i++) { | ||
135 | u32 addr = phys_addr + i * 4; | ||
136 | u32 val = *(map_addr + offset / 4 + i); | ||
137 | |||
138 | if (!data_count) { | ||
139 | host1x_debug_output(o, "%08x: %08x:", addr, val); | ||
140 | data_count = show_channel_command(o, val); | ||
141 | } else { | ||
142 | host1x_debug_output(o, "%08x%s", val, | ||
143 | data_count > 0 ? ", " : "])\n"); | ||
144 | data_count--; | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma) | ||
150 | { | ||
151 | struct host1x_job *job; | ||
152 | |||
153 | list_for_each_entry(job, &cdma->sync_queue, list) { | ||
154 | int i; | ||
155 | host1x_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d, first_get=%08x, timeout=%d num_slots=%d, num_handles=%d\n", | ||
156 | job, job->syncpt_id, job->syncpt_end, | ||
157 | job->first_get, job->timeout, | ||
158 | job->num_slots, job->num_unpins); | ||
159 | |||
160 | for (i = 0; i < job->num_gathers; i++) { | ||
161 | struct host1x_job_gather *g = &job->gathers[i]; | ||
162 | u32 *mapped; | ||
163 | |||
164 | if (job->gather_copy_mapped) | ||
165 | mapped = (u32 *)job->gather_copy_mapped; | ||
166 | else | ||
167 | mapped = host1x_bo_mmap(g->bo); | ||
168 | |||
169 | if (!mapped) { | ||
170 | host1x_debug_output(o, "[could not mmap]\n"); | ||
171 | continue; | ||
172 | } | ||
173 | |||
174 | host1x_debug_output(o, " GATHER at %08x+%04x, %d words\n", | ||
175 | g->base, g->offset, g->words); | ||
176 | |||
177 | show_gather(o, g->base + g->offset, g->words, cdma, | ||
178 | g->base, mapped); | ||
179 | |||
180 | if (!job->gather_copy_mapped) | ||
181 | host1x_bo_munmap(g->bo, mapped); | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | |||
186 | static void host1x_debug_show_channel_cdma(struct host1x *host, | ||
187 | struct host1x_channel *ch, | ||
188 | struct output *o) | ||
189 | { | ||
190 | struct host1x_cdma *cdma = &ch->cdma; | ||
191 | u32 dmaput, dmaget, dmactrl; | ||
192 | u32 cbstat, cbread; | ||
193 | u32 val, base, baseval; | ||
194 | |||
195 | dmaput = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT); | ||
196 | dmaget = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET); | ||
197 | dmactrl = host1x_ch_readl(ch, HOST1X_CHANNEL_DMACTRL); | ||
198 | cbread = host1x_sync_readl(host, HOST1X_SYNC_CBREAD(ch->id)); | ||
199 | cbstat = host1x_sync_readl(host, HOST1X_SYNC_CBSTAT(ch->id)); | ||
200 | |||
201 | host1x_debug_output(o, "%d-%s: ", ch->id, dev_name(ch->dev)); | ||
202 | |||
203 | if (HOST1X_CHANNEL_DMACTRL_DMASTOP_V(dmactrl) || | ||
204 | !ch->cdma.push_buffer.mapped) { | ||
205 | host1x_debug_output(o, "inactive\n\n"); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) == HOST1X_CLASS_HOST1X && | ||
210 | HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) == | ||
211 | HOST1X_UCLASS_WAIT_SYNCPT) | ||
212 | host1x_debug_output(o, "waiting on syncpt %d val %d\n", | ||
213 | cbread >> 24, cbread & 0xffffff); | ||
214 | else if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) == | ||
215 | HOST1X_CLASS_HOST1X && | ||
216 | HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) == | ||
217 | HOST1X_UCLASS_WAIT_SYNCPT_BASE) { | ||
218 | |||
219 | base = (cbread >> 16) & 0xff; | ||
220 | baseval = | ||
221 | host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(base)); | ||
222 | val = cbread & 0xffff; | ||
223 | host1x_debug_output(o, "waiting on syncpt %d val %d (base %d = %d; offset = %d)\n", | ||
224 | cbread >> 24, baseval + val, base, | ||
225 | baseval, val); | ||
226 | } else | ||
227 | host1x_debug_output(o, "active class %02x, offset %04x, val %08x\n", | ||
228 | HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat), | ||
229 | HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat), | ||
230 | cbread); | ||
231 | |||
232 | host1x_debug_output(o, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n", | ||
233 | dmaput, dmaget, dmactrl); | ||
234 | host1x_debug_output(o, "CBREAD %08x, CBSTAT %08x\n", cbread, cbstat); | ||
235 | |||
236 | show_channel_gathers(o, cdma); | ||
237 | host1x_debug_output(o, "\n"); | ||
238 | } | ||
239 | |||
240 | static void host1x_debug_show_channel_fifo(struct host1x *host, | ||
241 | struct host1x_channel *ch, | ||
242 | struct output *o) | ||
243 | { | ||
244 | u32 val, rd_ptr, wr_ptr, start, end; | ||
245 | unsigned int data_count = 0; | ||
246 | |||
247 | host1x_debug_output(o, "%d: fifo:\n", ch->id); | ||
248 | |||
249 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_FIFOSTAT); | ||
250 | host1x_debug_output(o, "FIFOSTAT %08x\n", val); | ||
251 | if (HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(val)) { | ||
252 | host1x_debug_output(o, "[empty]\n"); | ||
253 | return; | ||
254 | } | ||
255 | |||
256 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
257 | host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) | | ||
258 | HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id), | ||
259 | HOST1X_SYNC_CFPEEK_CTRL); | ||
260 | |||
261 | val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_PTRS); | ||
262 | rd_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(val); | ||
263 | wr_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(val); | ||
264 | |||
265 | val = host1x_sync_readl(host, HOST1X_SYNC_CF_SETUP(ch->id)); | ||
266 | start = HOST1X_SYNC_CF_SETUP_BASE_V(val); | ||
267 | end = HOST1X_SYNC_CF_SETUP_LIMIT_V(val); | ||
268 | |||
269 | do { | ||
270 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
271 | host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) | | ||
272 | HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id) | | ||
273 | HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(rd_ptr), | ||
274 | HOST1X_SYNC_CFPEEK_CTRL); | ||
275 | val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_READ); | ||
276 | |||
277 | if (!data_count) { | ||
278 | host1x_debug_output(o, "%08x:", val); | ||
279 | data_count = show_channel_command(o, val); | ||
280 | } else { | ||
281 | host1x_debug_output(o, "%08x%s", val, | ||
282 | data_count > 0 ? ", " : "])\n"); | ||
283 | data_count--; | ||
284 | } | ||
285 | |||
286 | if (rd_ptr == end) | ||
287 | rd_ptr = start; | ||
288 | else | ||
289 | rd_ptr++; | ||
290 | } while (rd_ptr != wr_ptr); | ||
291 | |||
292 | if (data_count) | ||
293 | host1x_debug_output(o, ", ...])\n"); | ||
294 | host1x_debug_output(o, "\n"); | ||
295 | |||
296 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
297 | } | ||
298 | |||
299 | static void host1x_debug_show_mlocks(struct host1x *host, struct output *o) | ||
300 | { | ||
301 | int i; | ||
302 | |||
303 | host1x_debug_output(o, "---- mlocks ----\n"); | ||
304 | for (i = 0; i < host1x_syncpt_nb_mlocks(host); i++) { | ||
305 | u32 owner = | ||
306 | host1x_sync_readl(host, HOST1X_SYNC_MLOCK_OWNER(i)); | ||
307 | if (HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(owner)) | ||
308 | host1x_debug_output(o, "%d: locked by channel %d\n", | ||
309 | i, HOST1X_SYNC_MLOCK_OWNER_CHID_F(owner)); | ||
310 | else if (HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(owner)) | ||
311 | host1x_debug_output(o, "%d: locked by cpu\n", i); | ||
312 | else | ||
313 | host1x_debug_output(o, "%d: unlocked\n", i); | ||
314 | } | ||
315 | host1x_debug_output(o, "\n"); | ||
316 | } | ||
317 | |||
318 | static const struct host1x_debug_ops host1x_debug_ops = { | ||
319 | .show_channel_cdma = host1x_debug_show_channel_cdma, | ||
320 | .show_channel_fifo = host1x_debug_show_channel_fifo, | ||
321 | .show_mlocks = host1x_debug_show_mlocks, | ||
322 | }; | ||
diff --git a/drivers/gpu/host1x/hw/host1x01.c b/drivers/gpu/host1x/hw/host1x01.c new file mode 100644 index 000000000000..a14e91cd1e58 --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x01.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Host1x init for T20 and T30 Architecture Chips | ||
3 | * | ||
4 | * Copyright (c) 2011-2013, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | /* include hw specification */ | ||
20 | #include "hw/host1x01.h" | ||
21 | #include "hw/host1x01_hardware.h" | ||
22 | |||
23 | /* include code */ | ||
24 | #include "hw/cdma_hw.c" | ||
25 | #include "hw/channel_hw.c" | ||
26 | #include "hw/debug_hw.c" | ||
27 | #include "hw/intr_hw.c" | ||
28 | #include "hw/syncpt_hw.c" | ||
29 | |||
30 | #include "dev.h" | ||
31 | |||
32 | int host1x01_init(struct host1x *host) | ||
33 | { | ||
34 | host->channel_op = &host1x_channel_ops; | ||
35 | host->cdma_op = &host1x_cdma_ops; | ||
36 | host->cdma_pb_op = &host1x_pushbuffer_ops; | ||
37 | host->syncpt_op = &host1x_syncpt_ops; | ||
38 | host->intr_op = &host1x_intr_ops; | ||
39 | host->debug_op = &host1x_debug_ops; | ||
40 | |||
41 | return 0; | ||
42 | } | ||
diff --git a/drivers/gpu/host1x/hw/host1x01.h b/drivers/gpu/host1x/hw/host1x01.h new file mode 100644 index 000000000000..2706b6743250 --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x01.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * Host1x init for T20 and T30 Architecture Chips | ||
3 | * | ||
4 | * Copyright (c) 2011-2013, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #ifndef HOST1X_HOST1X01_H | ||
19 | #define HOST1X_HOST1X01_H | ||
20 | |||
21 | struct host1x; | ||
22 | |||
23 | int host1x01_init(struct host1x *host); | ||
24 | |||
25 | #endif /* HOST1X_HOST1X01_H_ */ | ||
diff --git a/drivers/gpu/host1x/hw/host1x01_hardware.h b/drivers/gpu/host1x/hw/host1x01_hardware.h new file mode 100644 index 000000000000..5f0fb866efa8 --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x01_hardware.h | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * Tegra host1x Register Offsets for Tegra20 and Tegra30 | ||
3 | * | ||
4 | * Copyright (c) 2010-2013 NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifndef __HOST1X_HOST1X01_HARDWARE_H | ||
20 | #define __HOST1X_HOST1X01_HARDWARE_H | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | #include <linux/bitops.h> | ||
24 | |||
25 | #include "hw_host1x01_channel.h" | ||
26 | #include "hw_host1x01_sync.h" | ||
27 | #include "hw_host1x01_uclass.h" | ||
28 | |||
29 | static inline u32 host1x_class_host_wait_syncpt( | ||
30 | unsigned indx, unsigned threshold) | ||
31 | { | ||
32 | return host1x_uclass_wait_syncpt_indx_f(indx) | ||
33 | | host1x_uclass_wait_syncpt_thresh_f(threshold); | ||
34 | } | ||
35 | |||
36 | static inline u32 host1x_class_host_load_syncpt_base( | ||
37 | unsigned indx, unsigned threshold) | ||
38 | { | ||
39 | return host1x_uclass_load_syncpt_base_base_indx_f(indx) | ||
40 | | host1x_uclass_load_syncpt_base_value_f(threshold); | ||
41 | } | ||
42 | |||
43 | static inline u32 host1x_class_host_wait_syncpt_base( | ||
44 | unsigned indx, unsigned base_indx, unsigned offset) | ||
45 | { | ||
46 | return host1x_uclass_wait_syncpt_base_indx_f(indx) | ||
47 | | host1x_uclass_wait_syncpt_base_base_indx_f(base_indx) | ||
48 | | host1x_uclass_wait_syncpt_base_offset_f(offset); | ||
49 | } | ||
50 | |||
51 | static inline u32 host1x_class_host_incr_syncpt_base( | ||
52 | unsigned base_indx, unsigned offset) | ||
53 | { | ||
54 | return host1x_uclass_incr_syncpt_base_base_indx_f(base_indx) | ||
55 | | host1x_uclass_incr_syncpt_base_offset_f(offset); | ||
56 | } | ||
57 | |||
58 | static inline u32 host1x_class_host_incr_syncpt( | ||
59 | unsigned cond, unsigned indx) | ||
60 | { | ||
61 | return host1x_uclass_incr_syncpt_cond_f(cond) | ||
62 | | host1x_uclass_incr_syncpt_indx_f(indx); | ||
63 | } | ||
64 | |||
65 | static inline u32 host1x_class_host_indoff_reg_write( | ||
66 | unsigned mod_id, unsigned offset, bool auto_inc) | ||
67 | { | ||
68 | u32 v = host1x_uclass_indoff_indbe_f(0xf) | ||
69 | | host1x_uclass_indoff_indmodid_f(mod_id) | ||
70 | | host1x_uclass_indoff_indroffset_f(offset); | ||
71 | if (auto_inc) | ||
72 | v |= host1x_uclass_indoff_autoinc_f(1); | ||
73 | return v; | ||
74 | } | ||
75 | |||
76 | static inline u32 host1x_class_host_indoff_reg_read( | ||
77 | unsigned mod_id, unsigned offset, bool auto_inc) | ||
78 | { | ||
79 | u32 v = host1x_uclass_indoff_indmodid_f(mod_id) | ||
80 | | host1x_uclass_indoff_indroffset_f(offset) | ||
81 | | host1x_uclass_indoff_rwn_read_v(); | ||
82 | if (auto_inc) | ||
83 | v |= host1x_uclass_indoff_autoinc_f(1); | ||
84 | return v; | ||
85 | } | ||
86 | |||
87 | |||
88 | /* cdma opcodes */ | ||
89 | static inline u32 host1x_opcode_setclass( | ||
90 | unsigned class_id, unsigned offset, unsigned mask) | ||
91 | { | ||
92 | return (0 << 28) | (offset << 16) | (class_id << 6) | mask; | ||
93 | } | ||
94 | |||
95 | static inline u32 host1x_opcode_incr(unsigned offset, unsigned count) | ||
96 | { | ||
97 | return (1 << 28) | (offset << 16) | count; | ||
98 | } | ||
99 | |||
100 | static inline u32 host1x_opcode_nonincr(unsigned offset, unsigned count) | ||
101 | { | ||
102 | return (2 << 28) | (offset << 16) | count; | ||
103 | } | ||
104 | |||
105 | static inline u32 host1x_opcode_mask(unsigned offset, unsigned mask) | ||
106 | { | ||
107 | return (3 << 28) | (offset << 16) | mask; | ||
108 | } | ||
109 | |||
110 | static inline u32 host1x_opcode_imm(unsigned offset, unsigned value) | ||
111 | { | ||
112 | return (4 << 28) | (offset << 16) | value; | ||
113 | } | ||
114 | |||
115 | static inline u32 host1x_opcode_imm_incr_syncpt(unsigned cond, unsigned indx) | ||
116 | { | ||
117 | return host1x_opcode_imm(host1x_uclass_incr_syncpt_r(), | ||
118 | host1x_class_host_incr_syncpt(cond, indx)); | ||
119 | } | ||
120 | |||
121 | static inline u32 host1x_opcode_restart(unsigned address) | ||
122 | { | ||
123 | return (5 << 28) | (address >> 4); | ||
124 | } | ||
125 | |||
126 | static inline u32 host1x_opcode_gather(unsigned count) | ||
127 | { | ||
128 | return (6 << 28) | count; | ||
129 | } | ||
130 | |||
131 | static inline u32 host1x_opcode_gather_nonincr(unsigned offset, unsigned count) | ||
132 | { | ||
133 | return (6 << 28) | (offset << 16) | BIT(15) | count; | ||
134 | } | ||
135 | |||
136 | static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count) | ||
137 | { | ||
138 | return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count; | ||
139 | } | ||
140 | |||
141 | #define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0) | ||
142 | |||
143 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x01_channel.h b/drivers/gpu/host1x/hw/hw_host1x01_channel.h new file mode 100644 index 000000000000..b4bc7ca4e051 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x01_channel.h | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012-2013, NVIDIA Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * Function naming determines intended use: | ||
20 | * | ||
21 | * <x>_r(void) : Returns the offset for register <x>. | ||
22 | * | ||
23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
24 | * | ||
25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
26 | * | ||
27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
28 | * and masked to place it at field <y> of register <x>. This value | ||
29 | * can be |'d with others to produce a full register value for | ||
30 | * register <x>. | ||
31 | * | ||
32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
34 | * register <x>. | ||
35 | * | ||
36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
37 | * to place it at field <y> of register <x>. This value can be |'d | ||
38 | * with others to produce a full register value for <x>. | ||
39 | * | ||
40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
42 | * This value is suitable for direct comparison with other unshifted | ||
43 | * values appropriate for use in field <y> of register <x>. | ||
44 | * | ||
45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
46 | * field <y> of register <x>. This value is suitable for direct | ||
47 | * comparison with unshifted values appropriate for use in field <y> | ||
48 | * of register <x>. | ||
49 | */ | ||
50 | |||
51 | #ifndef __hw_host1x_channel_host1x_h__ | ||
52 | #define __hw_host1x_channel_host1x_h__ | ||
53 | |||
54 | static inline u32 host1x_channel_fifostat_r(void) | ||
55 | { | ||
56 | return 0x0; | ||
57 | } | ||
58 | #define HOST1X_CHANNEL_FIFOSTAT \ | ||
59 | host1x_channel_fifostat_r() | ||
60 | static inline u32 host1x_channel_fifostat_cfempty_v(u32 r) | ||
61 | { | ||
62 | return (r >> 10) & 0x1; | ||
63 | } | ||
64 | #define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(r) \ | ||
65 | host1x_channel_fifostat_cfempty_v(r) | ||
66 | static inline u32 host1x_channel_dmastart_r(void) | ||
67 | { | ||
68 | return 0x14; | ||
69 | } | ||
70 | #define HOST1X_CHANNEL_DMASTART \ | ||
71 | host1x_channel_dmastart_r() | ||
72 | static inline u32 host1x_channel_dmaput_r(void) | ||
73 | { | ||
74 | return 0x18; | ||
75 | } | ||
76 | #define HOST1X_CHANNEL_DMAPUT \ | ||
77 | host1x_channel_dmaput_r() | ||
78 | static inline u32 host1x_channel_dmaget_r(void) | ||
79 | { | ||
80 | return 0x1c; | ||
81 | } | ||
82 | #define HOST1X_CHANNEL_DMAGET \ | ||
83 | host1x_channel_dmaget_r() | ||
84 | static inline u32 host1x_channel_dmaend_r(void) | ||
85 | { | ||
86 | return 0x20; | ||
87 | } | ||
88 | #define HOST1X_CHANNEL_DMAEND \ | ||
89 | host1x_channel_dmaend_r() | ||
90 | static inline u32 host1x_channel_dmactrl_r(void) | ||
91 | { | ||
92 | return 0x24; | ||
93 | } | ||
94 | #define HOST1X_CHANNEL_DMACTRL \ | ||
95 | host1x_channel_dmactrl_r() | ||
96 | static inline u32 host1x_channel_dmactrl_dmastop(void) | ||
97 | { | ||
98 | return 1 << 0; | ||
99 | } | ||
100 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP \ | ||
101 | host1x_channel_dmactrl_dmastop() | ||
102 | static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r) | ||
103 | { | ||
104 | return (r >> 0) & 0x1; | ||
105 | } | ||
106 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP_V(r) \ | ||
107 | host1x_channel_dmactrl_dmastop_v(r) | ||
108 | static inline u32 host1x_channel_dmactrl_dmagetrst(void) | ||
109 | { | ||
110 | return 1 << 1; | ||
111 | } | ||
112 | #define HOST1X_CHANNEL_DMACTRL_DMAGETRST \ | ||
113 | host1x_channel_dmactrl_dmagetrst() | ||
114 | static inline u32 host1x_channel_dmactrl_dmainitget(void) | ||
115 | { | ||
116 | return 1 << 2; | ||
117 | } | ||
118 | #define HOST1X_CHANNEL_DMACTRL_DMAINITGET \ | ||
119 | host1x_channel_dmactrl_dmainitget() | ||
120 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x01_sync.h b/drivers/gpu/host1x/hw/hw_host1x01_sync.h new file mode 100644 index 000000000000..ac704e579977 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x01_sync.h | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012-2013, NVIDIA Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * Function naming determines intended use: | ||
20 | * | ||
21 | * <x>_r(void) : Returns the offset for register <x>. | ||
22 | * | ||
23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
24 | * | ||
25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
26 | * | ||
27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
28 | * and masked to place it at field <y> of register <x>. This value | ||
29 | * can be |'d with others to produce a full register value for | ||
30 | * register <x>. | ||
31 | * | ||
32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
34 | * register <x>. | ||
35 | * | ||
36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
37 | * to place it at field <y> of register <x>. This value can be |'d | ||
38 | * with others to produce a full register value for <x>. | ||
39 | * | ||
40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
42 | * This value is suitable for direct comparison with other unshifted | ||
43 | * values appropriate for use in field <y> of register <x>. | ||
44 | * | ||
45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
46 | * field <y> of register <x>. This value is suitable for direct | ||
47 | * comparison with unshifted values appropriate for use in field <y> | ||
48 | * of register <x>. | ||
49 | */ | ||
50 | |||
51 | #ifndef __hw_host1x01_sync_h__ | ||
52 | #define __hw_host1x01_sync_h__ | ||
53 | |||
54 | #define REGISTER_STRIDE 4 | ||
55 | |||
56 | static inline u32 host1x_sync_syncpt_r(unsigned int id) | ||
57 | { | ||
58 | return 0x400 + id * REGISTER_STRIDE; | ||
59 | } | ||
60 | #define HOST1X_SYNC_SYNCPT(id) \ | ||
61 | host1x_sync_syncpt_r(id) | ||
62 | static inline u32 host1x_sync_syncpt_thresh_cpu0_int_status_r(unsigned int id) | ||
63 | { | ||
64 | return 0x40 + id * REGISTER_STRIDE; | ||
65 | } | ||
66 | #define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id) \ | ||
67 | host1x_sync_syncpt_thresh_cpu0_int_status_r(id) | ||
68 | static inline u32 host1x_sync_syncpt_thresh_int_disable_r(unsigned int id) | ||
69 | { | ||
70 | return 0x60 + id * REGISTER_STRIDE; | ||
71 | } | ||
72 | #define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id) \ | ||
73 | host1x_sync_syncpt_thresh_int_disable_r(id) | ||
74 | static inline u32 host1x_sync_syncpt_thresh_int_enable_cpu0_r(unsigned int id) | ||
75 | { | ||
76 | return 0x68 + id * REGISTER_STRIDE; | ||
77 | } | ||
78 | #define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \ | ||
79 | host1x_sync_syncpt_thresh_int_enable_cpu0_r(id) | ||
80 | static inline u32 host1x_sync_cf_setup_r(unsigned int channel) | ||
81 | { | ||
82 | return 0x80 + channel * REGISTER_STRIDE; | ||
83 | } | ||
84 | #define HOST1X_SYNC_CF_SETUP(channel) \ | ||
85 | host1x_sync_cf_setup_r(channel) | ||
86 | static inline u32 host1x_sync_cf_setup_base_v(u32 r) | ||
87 | { | ||
88 | return (r >> 0) & 0x1ff; | ||
89 | } | ||
90 | #define HOST1X_SYNC_CF_SETUP_BASE_V(r) \ | ||
91 | host1x_sync_cf_setup_base_v(r) | ||
92 | static inline u32 host1x_sync_cf_setup_limit_v(u32 r) | ||
93 | { | ||
94 | return (r >> 16) & 0x1ff; | ||
95 | } | ||
96 | #define HOST1X_SYNC_CF_SETUP_LIMIT_V(r) \ | ||
97 | host1x_sync_cf_setup_limit_v(r) | ||
98 | static inline u32 host1x_sync_cmdproc_stop_r(void) | ||
99 | { | ||
100 | return 0xac; | ||
101 | } | ||
102 | #define HOST1X_SYNC_CMDPROC_STOP \ | ||
103 | host1x_sync_cmdproc_stop_r() | ||
104 | static inline u32 host1x_sync_ch_teardown_r(void) | ||
105 | { | ||
106 | return 0xb0; | ||
107 | } | ||
108 | #define HOST1X_SYNC_CH_TEARDOWN \ | ||
109 | host1x_sync_ch_teardown_r() | ||
110 | static inline u32 host1x_sync_usec_clk_r(void) | ||
111 | { | ||
112 | return 0x1a4; | ||
113 | } | ||
114 | #define HOST1X_SYNC_USEC_CLK \ | ||
115 | host1x_sync_usec_clk_r() | ||
116 | static inline u32 host1x_sync_ctxsw_timeout_cfg_r(void) | ||
117 | { | ||
118 | return 0x1a8; | ||
119 | } | ||
120 | #define HOST1X_SYNC_CTXSW_TIMEOUT_CFG \ | ||
121 | host1x_sync_ctxsw_timeout_cfg_r() | ||
122 | static inline u32 host1x_sync_ip_busy_timeout_r(void) | ||
123 | { | ||
124 | return 0x1bc; | ||
125 | } | ||
126 | #define HOST1X_SYNC_IP_BUSY_TIMEOUT \ | ||
127 | host1x_sync_ip_busy_timeout_r() | ||
128 | static inline u32 host1x_sync_mlock_owner_r(unsigned int id) | ||
129 | { | ||
130 | return 0x340 + id * REGISTER_STRIDE; | ||
131 | } | ||
132 | #define HOST1X_SYNC_MLOCK_OWNER(id) \ | ||
133 | host1x_sync_mlock_owner_r(id) | ||
134 | static inline u32 host1x_sync_mlock_owner_chid_f(u32 v) | ||
135 | { | ||
136 | return (v & 0xf) << 8; | ||
137 | } | ||
138 | #define HOST1X_SYNC_MLOCK_OWNER_CHID_F(v) \ | ||
139 | host1x_sync_mlock_owner_chid_f(v) | ||
140 | static inline u32 host1x_sync_mlock_owner_cpu_owns_v(u32 r) | ||
141 | { | ||
142 | return (r >> 1) & 0x1; | ||
143 | } | ||
144 | #define HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(r) \ | ||
145 | host1x_sync_mlock_owner_cpu_owns_v(r) | ||
146 | static inline u32 host1x_sync_mlock_owner_ch_owns_v(u32 r) | ||
147 | { | ||
148 | return (r >> 0) & 0x1; | ||
149 | } | ||
150 | #define HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(r) \ | ||
151 | host1x_sync_mlock_owner_ch_owns_v(r) | ||
152 | static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id) | ||
153 | { | ||
154 | return 0x500 + id * REGISTER_STRIDE; | ||
155 | } | ||
156 | #define HOST1X_SYNC_SYNCPT_INT_THRESH(id) \ | ||
157 | host1x_sync_syncpt_int_thresh_r(id) | ||
158 | static inline u32 host1x_sync_syncpt_base_r(unsigned int id) | ||
159 | { | ||
160 | return 0x600 + id * REGISTER_STRIDE; | ||
161 | } | ||
162 | #define HOST1X_SYNC_SYNCPT_BASE(id) \ | ||
163 | host1x_sync_syncpt_base_r(id) | ||
164 | static inline u32 host1x_sync_syncpt_cpu_incr_r(unsigned int id) | ||
165 | { | ||
166 | return 0x700 + id * REGISTER_STRIDE; | ||
167 | } | ||
168 | #define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \ | ||
169 | host1x_sync_syncpt_cpu_incr_r(id) | ||
170 | static inline u32 host1x_sync_cbread_r(unsigned int channel) | ||
171 | { | ||
172 | return 0x720 + channel * REGISTER_STRIDE; | ||
173 | } | ||
174 | #define HOST1X_SYNC_CBREAD(channel) \ | ||
175 | host1x_sync_cbread_r(channel) | ||
176 | static inline u32 host1x_sync_cfpeek_ctrl_r(void) | ||
177 | { | ||
178 | return 0x74c; | ||
179 | } | ||
180 | #define HOST1X_SYNC_CFPEEK_CTRL \ | ||
181 | host1x_sync_cfpeek_ctrl_r() | ||
182 | static inline u32 host1x_sync_cfpeek_ctrl_addr_f(u32 v) | ||
183 | { | ||
184 | return (v & 0x1ff) << 0; | ||
185 | } | ||
186 | #define HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(v) \ | ||
187 | host1x_sync_cfpeek_ctrl_addr_f(v) | ||
188 | static inline u32 host1x_sync_cfpeek_ctrl_channr_f(u32 v) | ||
189 | { | ||
190 | return (v & 0x7) << 16; | ||
191 | } | ||
192 | #define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(v) \ | ||
193 | host1x_sync_cfpeek_ctrl_channr_f(v) | ||
194 | static inline u32 host1x_sync_cfpeek_ctrl_ena_f(u32 v) | ||
195 | { | ||
196 | return (v & 0x1) << 31; | ||
197 | } | ||
198 | #define HOST1X_SYNC_CFPEEK_CTRL_ENA_F(v) \ | ||
199 | host1x_sync_cfpeek_ctrl_ena_f(v) | ||
200 | static inline u32 host1x_sync_cfpeek_read_r(void) | ||
201 | { | ||
202 | return 0x750; | ||
203 | } | ||
204 | #define HOST1X_SYNC_CFPEEK_READ \ | ||
205 | host1x_sync_cfpeek_read_r() | ||
206 | static inline u32 host1x_sync_cfpeek_ptrs_r(void) | ||
207 | { | ||
208 | return 0x754; | ||
209 | } | ||
210 | #define HOST1X_SYNC_CFPEEK_PTRS \ | ||
211 | host1x_sync_cfpeek_ptrs_r() | ||
212 | static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r) | ||
213 | { | ||
214 | return (r >> 0) & 0x1ff; | ||
215 | } | ||
216 | #define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(r) \ | ||
217 | host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(r) | ||
218 | static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r) | ||
219 | { | ||
220 | return (r >> 16) & 0x1ff; | ||
221 | } | ||
222 | #define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(r) \ | ||
223 | host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(r) | ||
224 | static inline u32 host1x_sync_cbstat_r(unsigned int channel) | ||
225 | { | ||
226 | return 0x758 + channel * REGISTER_STRIDE; | ||
227 | } | ||
228 | #define HOST1X_SYNC_CBSTAT(channel) \ | ||
229 | host1x_sync_cbstat_r(channel) | ||
230 | static inline u32 host1x_sync_cbstat_cboffset_v(u32 r) | ||
231 | { | ||
232 | return (r >> 0) & 0xffff; | ||
233 | } | ||
234 | #define HOST1X_SYNC_CBSTAT_CBOFFSET_V(r) \ | ||
235 | host1x_sync_cbstat_cboffset_v(r) | ||
236 | static inline u32 host1x_sync_cbstat_cbclass_v(u32 r) | ||
237 | { | ||
238 | return (r >> 16) & 0x3ff; | ||
239 | } | ||
240 | #define HOST1X_SYNC_CBSTAT_CBCLASS_V(r) \ | ||
241 | host1x_sync_cbstat_cbclass_v(r) | ||
242 | |||
243 | #endif /* __hw_host1x01_sync_h__ */ | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x01_uclass.h b/drivers/gpu/host1x/hw/hw_host1x01_uclass.h new file mode 100644 index 000000000000..42f3ce19ca32 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x01_uclass.h | |||
@@ -0,0 +1,174 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012-2013, NVIDIA Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * Function naming determines intended use: | ||
20 | * | ||
21 | * <x>_r(void) : Returns the offset for register <x>. | ||
22 | * | ||
23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
24 | * | ||
25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
26 | * | ||
27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
28 | * and masked to place it at field <y> of register <x>. This value | ||
29 | * can be |'d with others to produce a full register value for | ||
30 | * register <x>. | ||
31 | * | ||
32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
34 | * register <x>. | ||
35 | * | ||
36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
37 | * to place it at field <y> of register <x>. This value can be |'d | ||
38 | * with others to produce a full register value for <x>. | ||
39 | * | ||
40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
42 | * This value is suitable for direct comparison with other unshifted | ||
43 | * values appropriate for use in field <y> of register <x>. | ||
44 | * | ||
45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
46 | * field <y> of register <x>. This value is suitable for direct | ||
47 | * comparison with unshifted values appropriate for use in field <y> | ||
48 | * of register <x>. | ||
49 | */ | ||
50 | |||
51 | #ifndef __hw_host1x_uclass_host1x_h__ | ||
52 | #define __hw_host1x_uclass_host1x_h__ | ||
53 | |||
54 | static inline u32 host1x_uclass_incr_syncpt_r(void) | ||
55 | { | ||
56 | return 0x0; | ||
57 | } | ||
58 | #define HOST1X_UCLASS_INCR_SYNCPT \ | ||
59 | host1x_uclass_incr_syncpt_r() | ||
60 | static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v) | ||
61 | { | ||
62 | return (v & 0xff) << 8; | ||
63 | } | ||
64 | #define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \ | ||
65 | host1x_uclass_incr_syncpt_cond_f(v) | ||
66 | static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v) | ||
67 | { | ||
68 | return (v & 0xff) << 0; | ||
69 | } | ||
70 | #define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \ | ||
71 | host1x_uclass_incr_syncpt_indx_f(v) | ||
72 | static inline u32 host1x_uclass_wait_syncpt_r(void) | ||
73 | { | ||
74 | return 0x8; | ||
75 | } | ||
76 | #define HOST1X_UCLASS_WAIT_SYNCPT \ | ||
77 | host1x_uclass_wait_syncpt_r() | ||
78 | static inline u32 host1x_uclass_wait_syncpt_indx_f(u32 v) | ||
79 | { | ||
80 | return (v & 0xff) << 24; | ||
81 | } | ||
82 | #define HOST1X_UCLASS_WAIT_SYNCPT_INDX_F(v) \ | ||
83 | host1x_uclass_wait_syncpt_indx_f(v) | ||
84 | static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v) | ||
85 | { | ||
86 | return (v & 0xffffff) << 0; | ||
87 | } | ||
88 | #define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \ | ||
89 | host1x_uclass_wait_syncpt_thresh_f(v) | ||
90 | static inline u32 host1x_uclass_wait_syncpt_base_r(void) | ||
91 | { | ||
92 | return 0x9; | ||
93 | } | ||
94 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE \ | ||
95 | host1x_uclass_wait_syncpt_base_r() | ||
96 | static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v) | ||
97 | { | ||
98 | return (v & 0xff) << 24; | ||
99 | } | ||
100 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_INDX_F(v) \ | ||
101 | host1x_uclass_wait_syncpt_base_indx_f(v) | ||
102 | static inline u32 host1x_uclass_wait_syncpt_base_base_indx_f(u32 v) | ||
103 | { | ||
104 | return (v & 0xff) << 16; | ||
105 | } | ||
106 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
107 | host1x_uclass_wait_syncpt_base_base_indx_f(v) | ||
108 | static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v) | ||
109 | { | ||
110 | return (v & 0xffff) << 0; | ||
111 | } | ||
112 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \ | ||
113 | host1x_uclass_wait_syncpt_base_offset_f(v) | ||
114 | static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v) | ||
115 | { | ||
116 | return (v & 0xff) << 24; | ||
117 | } | ||
118 | #define HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
119 | host1x_uclass_load_syncpt_base_base_indx_f(v) | ||
120 | static inline u32 host1x_uclass_load_syncpt_base_value_f(u32 v) | ||
121 | { | ||
122 | return (v & 0xffffff) << 0; | ||
123 | } | ||
124 | #define HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(v) \ | ||
125 | host1x_uclass_load_syncpt_base_value_f(v) | ||
126 | static inline u32 host1x_uclass_incr_syncpt_base_base_indx_f(u32 v) | ||
127 | { | ||
128 | return (v & 0xff) << 24; | ||
129 | } | ||
130 | #define HOST1X_UCLASS_INCR_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
131 | host1x_uclass_incr_syncpt_base_base_indx_f(v) | ||
132 | static inline u32 host1x_uclass_incr_syncpt_base_offset_f(u32 v) | ||
133 | { | ||
134 | return (v & 0xffffff) << 0; | ||
135 | } | ||
136 | #define HOST1X_UCLASS_INCR_SYNCPT_BASE_OFFSET_F(v) \ | ||
137 | host1x_uclass_incr_syncpt_base_offset_f(v) | ||
138 | static inline u32 host1x_uclass_indoff_r(void) | ||
139 | { | ||
140 | return 0x2d; | ||
141 | } | ||
142 | #define HOST1X_UCLASS_INDOFF \ | ||
143 | host1x_uclass_indoff_r() | ||
144 | static inline u32 host1x_uclass_indoff_indbe_f(u32 v) | ||
145 | { | ||
146 | return (v & 0xf) << 28; | ||
147 | } | ||
148 | #define HOST1X_UCLASS_INDOFF_INDBE_F(v) \ | ||
149 | host1x_uclass_indoff_indbe_f(v) | ||
150 | static inline u32 host1x_uclass_indoff_autoinc_f(u32 v) | ||
151 | { | ||
152 | return (v & 0x1) << 27; | ||
153 | } | ||
154 | #define HOST1X_UCLASS_INDOFF_AUTOINC_F(v) \ | ||
155 | host1x_uclass_indoff_autoinc_f(v) | ||
156 | static inline u32 host1x_uclass_indoff_indmodid_f(u32 v) | ||
157 | { | ||
158 | return (v & 0xff) << 18; | ||
159 | } | ||
160 | #define HOST1X_UCLASS_INDOFF_INDMODID_F(v) \ | ||
161 | host1x_uclass_indoff_indmodid_f(v) | ||
162 | static inline u32 host1x_uclass_indoff_indroffset_f(u32 v) | ||
163 | { | ||
164 | return (v & 0xffff) << 2; | ||
165 | } | ||
166 | #define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \ | ||
167 | host1x_uclass_indoff_indroffset_f(v) | ||
168 | static inline u32 host1x_uclass_indoff_rwn_read_v(void) | ||
169 | { | ||
170 | return 1; | ||
171 | } | ||
172 | #define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \ | ||
173 | host1x_uclass_indoff_indroffset_f(v) | ||
174 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/intr_hw.c b/drivers/gpu/host1x/hw/intr_hw.c new file mode 100644 index 000000000000..b592eef1efcb --- /dev/null +++ b/drivers/gpu/host1x/hw/intr_hw.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * Tegra host1x Interrupt Management | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Copyright (c) 2010-2013, NVIDIA Corporation. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/irq.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <asm/mach/irq.h> | ||
24 | |||
25 | #include "intr.h" | ||
26 | #include "dev.h" | ||
27 | |||
28 | /* | ||
29 | * Sync point threshold interrupt service function | ||
30 | * Handles sync point threshold triggers, in interrupt context | ||
31 | */ | ||
32 | static void host1x_intr_syncpt_handle(struct host1x_syncpt *syncpt) | ||
33 | { | ||
34 | unsigned int id = syncpt->id; | ||
35 | struct host1x *host = syncpt->host; | ||
36 | |||
37 | host1x_sync_writel(host, BIT_MASK(id), | ||
38 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id))); | ||
39 | host1x_sync_writel(host, BIT_MASK(id), | ||
40 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id))); | ||
41 | |||
42 | queue_work(host->intr_wq, &syncpt->intr.work); | ||
43 | } | ||
44 | |||
45 | static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) | ||
46 | { | ||
47 | struct host1x *host = dev_id; | ||
48 | unsigned long reg; | ||
49 | int i, id; | ||
50 | |||
51 | for (i = 0; i <= BIT_WORD(host->info->nb_pts); i++) { | ||
52 | reg = host1x_sync_readl(host, | ||
53 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); | ||
54 | for_each_set_bit(id, ®, BITS_PER_LONG) { | ||
55 | struct host1x_syncpt *syncpt = | ||
56 | host->syncpt + (i * BITS_PER_LONG + id); | ||
57 | host1x_intr_syncpt_handle(syncpt); | ||
58 | } | ||
59 | } | ||
60 | |||
61 | return IRQ_HANDLED; | ||
62 | } | ||
63 | |||
64 | static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host) | ||
65 | { | ||
66 | u32 i; | ||
67 | |||
68 | for (i = 0; i <= BIT_WORD(host->info->nb_pts); ++i) { | ||
69 | host1x_sync_writel(host, 0xffffffffu, | ||
70 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i)); | ||
71 | host1x_sync_writel(host, 0xffffffffu, | ||
72 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | static int _host1x_intr_init_host_sync(struct host1x *host, u32 cpm, | ||
77 | void (*syncpt_thresh_work)(struct work_struct *)) | ||
78 | { | ||
79 | int i, err; | ||
80 | |||
81 | host1x_hw_intr_disable_all_syncpt_intrs(host); | ||
82 | |||
83 | for (i = 0; i < host->info->nb_pts; i++) | ||
84 | INIT_WORK(&host->syncpt[i].intr.work, syncpt_thresh_work); | ||
85 | |||
86 | err = devm_request_irq(host->dev, host->intr_syncpt_irq, | ||
87 | syncpt_thresh_isr, IRQF_SHARED, | ||
88 | "host1x_syncpt", host); | ||
89 | if (IS_ERR_VALUE(err)) { | ||
90 | WARN_ON(1); | ||
91 | return err; | ||
92 | } | ||
93 | |||
94 | /* disable the ip_busy_timeout. this prevents write drops */ | ||
95 | host1x_sync_writel(host, 0, HOST1X_SYNC_IP_BUSY_TIMEOUT); | ||
96 | |||
97 | /* | ||
98 | * increase the auto-ack timout to the maximum value. 2d will hang | ||
99 | * otherwise on Tegra2. | ||
100 | */ | ||
101 | host1x_sync_writel(host, 0xff, HOST1X_SYNC_CTXSW_TIMEOUT_CFG); | ||
102 | |||
103 | /* update host clocks per usec */ | ||
104 | host1x_sync_writel(host, cpm, HOST1X_SYNC_USEC_CLK); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static void _host1x_intr_set_syncpt_threshold(struct host1x *host, | ||
110 | u32 id, u32 thresh) | ||
111 | { | ||
112 | host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id)); | ||
113 | } | ||
114 | |||
115 | static void _host1x_intr_enable_syncpt_intr(struct host1x *host, u32 id) | ||
116 | { | ||
117 | host1x_sync_writel(host, BIT_MASK(id), | ||
118 | HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(BIT_WORD(id))); | ||
119 | } | ||
120 | |||
121 | static void _host1x_intr_disable_syncpt_intr(struct host1x *host, u32 id) | ||
122 | { | ||
123 | host1x_sync_writel(host, BIT_MASK(id), | ||
124 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id))); | ||
125 | host1x_sync_writel(host, BIT_MASK(id), | ||
126 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id))); | ||
127 | } | ||
128 | |||
129 | static int _host1x_free_syncpt_irq(struct host1x *host) | ||
130 | { | ||
131 | devm_free_irq(host->dev, host->intr_syncpt_irq, host); | ||
132 | flush_workqueue(host->intr_wq); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static const struct host1x_intr_ops host1x_intr_ops = { | ||
137 | .init_host_sync = _host1x_intr_init_host_sync, | ||
138 | .set_syncpt_threshold = _host1x_intr_set_syncpt_threshold, | ||
139 | .enable_syncpt_intr = _host1x_intr_enable_syncpt_intr, | ||
140 | .disable_syncpt_intr = _host1x_intr_disable_syncpt_intr, | ||
141 | .disable_all_syncpt_intrs = _host1x_intr_disable_all_syncpt_intrs, | ||
142 | .free_syncpt_irq = _host1x_free_syncpt_irq, | ||
143 | }; | ||
diff --git a/drivers/gpu/host1x/hw/syncpt_hw.c b/drivers/gpu/host1x/hw/syncpt_hw.c new file mode 100644 index 000000000000..61174990102a --- /dev/null +++ b/drivers/gpu/host1x/hw/syncpt_hw.c | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * Tegra host1x Syncpoints | ||
3 | * | ||
4 | * Copyright (c) 2010-2013, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/io.h> | ||
20 | |||
21 | #include "dev.h" | ||
22 | #include "syncpt.h" | ||
23 | |||
24 | /* | ||
25 | * Write the current syncpoint value back to hw. | ||
26 | */ | ||
27 | static void syncpt_restore(struct host1x_syncpt *sp) | ||
28 | { | ||
29 | struct host1x *host = sp->host; | ||
30 | int min = host1x_syncpt_read_min(sp); | ||
31 | host1x_sync_writel(host, min, HOST1X_SYNC_SYNCPT(sp->id)); | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * Write the current waitbase value back to hw. | ||
36 | */ | ||
37 | static void syncpt_restore_wait_base(struct host1x_syncpt *sp) | ||
38 | { | ||
39 | struct host1x *host = sp->host; | ||
40 | host1x_sync_writel(host, sp->base_val, | ||
41 | HOST1X_SYNC_SYNCPT_BASE(sp->id)); | ||
42 | } | ||
43 | |||
44 | /* | ||
45 | * Read waitbase value from hw. | ||
46 | */ | ||
47 | static void syncpt_read_wait_base(struct host1x_syncpt *sp) | ||
48 | { | ||
49 | struct host1x *host = sp->host; | ||
50 | sp->base_val = | ||
51 | host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id)); | ||
52 | } | ||
53 | |||
54 | /* | ||
55 | * Updates the last value read from hardware. | ||
56 | */ | ||
57 | static u32 syncpt_load(struct host1x_syncpt *sp) | ||
58 | { | ||
59 | struct host1x *host = sp->host; | ||
60 | u32 old, live; | ||
61 | |||
62 | /* Loop in case there's a race writing to min_val */ | ||
63 | do { | ||
64 | old = host1x_syncpt_read_min(sp); | ||
65 | live = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT(sp->id)); | ||
66 | } while ((u32)atomic_cmpxchg(&sp->min_val, old, live) != old); | ||
67 | |||
68 | if (!host1x_syncpt_check_max(sp, live)) | ||
69 | dev_err(host->dev, "%s failed: id=%u, min=%d, max=%d\n", | ||
70 | __func__, sp->id, host1x_syncpt_read_min(sp), | ||
71 | host1x_syncpt_read_max(sp)); | ||
72 | |||
73 | return live; | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Write a cpu syncpoint increment to the hardware, without touching | ||
78 | * the cache. | ||
79 | */ | ||
80 | static void syncpt_cpu_incr(struct host1x_syncpt *sp) | ||
81 | { | ||
82 | struct host1x *host = sp->host; | ||
83 | u32 reg_offset = sp->id / 32; | ||
84 | |||
85 | if (!host1x_syncpt_client_managed(sp) && | ||
86 | host1x_syncpt_idle(sp)) { | ||
87 | dev_err(host->dev, "Trying to increment syncpoint id %d beyond max\n", | ||
88 | sp->id); | ||
89 | host1x_debug_dump(sp->host); | ||
90 | return; | ||
91 | } | ||
92 | host1x_sync_writel(host, BIT_MASK(sp->id), | ||
93 | HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset)); | ||
94 | wmb(); | ||
95 | } | ||
96 | |||
97 | /* remove a wait pointed to by patch_addr */ | ||
98 | static int syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr) | ||
99 | { | ||
100 | u32 override = host1x_class_host_wait_syncpt( | ||
101 | HOST1X_SYNCPT_RESERVED, 0); | ||
102 | |||
103 | *((u32 *)patch_addr) = override; | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static const struct host1x_syncpt_ops host1x_syncpt_ops = { | ||
108 | .restore = syncpt_restore, | ||
109 | .restore_wait_base = syncpt_restore_wait_base, | ||
110 | .load_wait_base = syncpt_read_wait_base, | ||
111 | .load = syncpt_load, | ||
112 | .cpu_incr = syncpt_cpu_incr, | ||
113 | .patch_wait = syncpt_patch_wait, | ||
114 | }; | ||