aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/host1x/hw
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/host1x/hw')
-rw-r--r--drivers/gpu/host1x/hw/Makefile6
-rw-r--r--drivers/gpu/host1x/hw/cdma_hw.c326
-rw-r--r--drivers/gpu/host1x/hw/channel_hw.c168
-rw-r--r--drivers/gpu/host1x/hw/debug_hw.c322
-rw-r--r--drivers/gpu/host1x/hw/host1x01.c42
-rw-r--r--drivers/gpu/host1x/hw/host1x01.h25
-rw-r--r--drivers/gpu/host1x/hw/host1x01_hardware.h143
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x01_channel.h120
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x01_sync.h243
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x01_uclass.h174
-rw-r--r--drivers/gpu/host1x/hw/intr_hw.c143
-rw-r--r--drivers/gpu/host1x/hw/syncpt_hw.c114
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 @@
1ccflags-y = -Idrivers/gpu/host1x
2
3host1x-hw-objs = \
4 host1x01.o
5
6obj-$(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 */
31static 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 */
39static 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 */
67static 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 */
103static 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 */
149static 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
160static 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 */
178static 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
209static 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 */
232static 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 */
294static 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 */
305static 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
312static 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
324static 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
32static 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
56static 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
70static 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
149error:
150 kfree(completed_waiter);
151 return err;
152}
153
154static 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
165static 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
33enum {
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
44enum {
45 HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK = 0x00,
46 HOST1X_OPCODE_EXTEND_RELEASE_MLOCK = 0x01,
47};
48
49static 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
116static 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
149static 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
186static 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
240static 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
299static 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
318static 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
32int 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
21struct host1x;
22
23int 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
29static 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
36static 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
43static 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
51static 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
58static 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
65static 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
76static 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 */
89static 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
95static inline u32 host1x_opcode_incr(unsigned offset, unsigned count)
96{
97 return (1 << 28) | (offset << 16) | count;
98}
99
100static inline u32 host1x_opcode_nonincr(unsigned offset, unsigned count)
101{
102 return (2 << 28) | (offset << 16) | count;
103}
104
105static inline u32 host1x_opcode_mask(unsigned offset, unsigned mask)
106{
107 return (3 << 28) | (offset << 16) | mask;
108}
109
110static inline u32 host1x_opcode_imm(unsigned offset, unsigned value)
111{
112 return (4 << 28) | (offset << 16) | value;
113}
114
115static 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
121static inline u32 host1x_opcode_restart(unsigned address)
122{
123 return (5 << 28) | (address >> 4);
124}
125
126static inline u32 host1x_opcode_gather(unsigned count)
127{
128 return (6 << 28) | count;
129}
130
131static inline u32 host1x_opcode_gather_nonincr(unsigned offset, unsigned count)
132{
133 return (6 << 28) | (offset << 16) | BIT(15) | count;
134}
135
136static 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
54static inline u32 host1x_channel_fifostat_r(void)
55{
56 return 0x0;
57}
58#define HOST1X_CHANNEL_FIFOSTAT \
59 host1x_channel_fifostat_r()
60static 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)
66static inline u32 host1x_channel_dmastart_r(void)
67{
68 return 0x14;
69}
70#define HOST1X_CHANNEL_DMASTART \
71 host1x_channel_dmastart_r()
72static inline u32 host1x_channel_dmaput_r(void)
73{
74 return 0x18;
75}
76#define HOST1X_CHANNEL_DMAPUT \
77 host1x_channel_dmaput_r()
78static inline u32 host1x_channel_dmaget_r(void)
79{
80 return 0x1c;
81}
82#define HOST1X_CHANNEL_DMAGET \
83 host1x_channel_dmaget_r()
84static inline u32 host1x_channel_dmaend_r(void)
85{
86 return 0x20;
87}
88#define HOST1X_CHANNEL_DMAEND \
89 host1x_channel_dmaend_r()
90static inline u32 host1x_channel_dmactrl_r(void)
91{
92 return 0x24;
93}
94#define HOST1X_CHANNEL_DMACTRL \
95 host1x_channel_dmactrl_r()
96static inline u32 host1x_channel_dmactrl_dmastop(void)
97{
98 return 1 << 0;
99}
100#define HOST1X_CHANNEL_DMACTRL_DMASTOP \
101 host1x_channel_dmactrl_dmastop()
102static 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)
108static inline u32 host1x_channel_dmactrl_dmagetrst(void)
109{
110 return 1 << 1;
111}
112#define HOST1X_CHANNEL_DMACTRL_DMAGETRST \
113 host1x_channel_dmactrl_dmagetrst()
114static 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
56static 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)
62static 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)
68static 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)
74static 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)
80static 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)
86static 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)
92static 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)
98static 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()
104static 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()
110static 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()
116static 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()
122static 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()
128static 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)
134static 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)
140static 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)
146static 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)
152static 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)
158static 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)
164static 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)
170static 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)
176static 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()
182static 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)
188static 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)
194static 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)
200static 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()
206static 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()
212static 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)
218static 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)
224static 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)
230static 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)
236static 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
54static 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()
60static 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)
66static 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)
72static 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()
78static 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)
84static 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)
90static 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()
96static 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)
102static 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)
108static 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)
114static 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)
120static 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)
126static 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)
132static 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)
138static inline u32 host1x_uclass_indoff_r(void)
139{
140 return 0x2d;
141}
142#define HOST1X_UCLASS_INDOFF \
143 host1x_uclass_indoff_r()
144static 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)
150static 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)
156static 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)
162static 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)
168static 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 */
32static 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
45static 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, &reg, 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
64static 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
76static 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
109static 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
115static 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
121static 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
129static 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
136static 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 */
27static 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 */
37static 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 */
47static 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 */
57static 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 */
80static 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 */
98static 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
107static 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};