video: tegra: host: Add syncpt trace events
[linux-2.6.git] / drivers / video / tegra / host / host1x / host1x_syncpt.c
1 /*
2  * drivers/video/tegra/host/host1x/host1x_syncpt.c
3  *
4  * Tegra Graphics Host Syncpoints for HOST1X
5  *
6  * Copyright (c) 2010-2012, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <linux/nvhost_ioctl.h>
22 #include <linux/io.h>
23 #include <trace/events/nvhost.h>
24 #include "nvhost_syncpt.h"
25 #include "nvhost_acm.h"
26 #include "dev.h"
27 #include "host1x_syncpt.h"
28 #include "host1x_hardware.h"
29
30 /**
31  * Write the current syncpoint value back to hw.
32  */
33 static void t20_syncpt_reset(struct nvhost_syncpt *sp, u32 id)
34 {
35         struct nvhost_master *dev = syncpt_to_dev(sp);
36         int min = nvhost_syncpt_read_min(sp, id);
37         writel(min, dev->sync_aperture + (HOST1X_SYNC_SYNCPT_0 + id * 4));
38 }
39
40 /**
41  * Write the current waitbase value back to hw.
42  */
43 static void t20_syncpt_reset_wait_base(struct nvhost_syncpt *sp, u32 id)
44 {
45         struct nvhost_master *dev = syncpt_to_dev(sp);
46         writel(sp->base_val[id],
47                 dev->sync_aperture + (HOST1X_SYNC_SYNCPT_BASE_0 + id * 4));
48 }
49
50 /**
51  * Read waitbase value from hw.
52  */
53 static void t20_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
54 {
55         struct nvhost_master *dev = syncpt_to_dev(sp);
56         sp->base_val[id] = readl(dev->sync_aperture +
57                                 (HOST1X_SYNC_SYNCPT_BASE_0 + id * 4));
58 }
59
60 /**
61  * Updates the last value read from hardware.
62  * (was nvhost_syncpt_update_min)
63  */
64 static u32 t20_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
65 {
66         struct nvhost_master *dev = syncpt_to_dev(sp);
67         void __iomem *sync_regs = dev->sync_aperture;
68         u32 old, live;
69
70         do {
71                 old = nvhost_syncpt_read_min(sp, id);
72                 live = readl(sync_regs + (HOST1X_SYNC_SYNCPT_0 + id * 4));
73         } while ((u32)atomic_cmpxchg(&sp->min_val[id], old, live) != old);
74
75         if (!nvhost_syncpt_check_max(sp, id, live))
76                 dev_err(&syncpt_to_dev(sp)->dev->dev,
77                                 "%s failed: id=%u, min=%d, max=%d\n",
78                                 __func__,
79                                 nvhost_syncpt_read_min(sp, id),
80                                 nvhost_syncpt_read_max(sp, id),
81                                 id);
82
83         return live;
84 }
85
86 /**
87  * Write a cpu syncpoint increment to the hardware, without touching
88  * the cache. Caller is responsible for host being powered.
89  */
90 static void t20_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
91 {
92         struct nvhost_master *dev = syncpt_to_dev(sp);
93         BUG_ON(!nvhost_module_powered(dev->dev));
94         if (!client_managed(id) && nvhost_syncpt_min_eq_max(sp, id)) {
95                 dev_err(&syncpt_to_dev(sp)->dev->dev,
96                         "Trying to increment syncpoint id %d beyond max\n",
97                         id);
98                 nvhost_debug_dump(syncpt_to_dev(sp));
99                 return;
100         }
101         writel(BIT(id), dev->sync_aperture + HOST1X_SYNC_SYNCPT_CPU_INCR);
102         wmb();
103 }
104
105 /* check for old WAITs to be removed (avoiding a wrap) */
106 static int t20_syncpt_wait_check(struct nvhost_syncpt *sp,
107                                  struct nvmap_client *nvmap,
108                                  u32 waitchk_mask,
109                                  struct nvhost_waitchk *wait,
110                                  int num_waitchk)
111 {
112         u32 idx;
113         int err = 0;
114
115         /* get current syncpt values */
116         for (idx = 0; idx < NV_HOST1X_SYNCPT_NB_PTS; idx++) {
117                 if (BIT(idx) & waitchk_mask)
118                         nvhost_syncpt_update_min(sp, idx);
119         }
120
121         BUG_ON(!wait && !num_waitchk);
122
123         /* compare syncpt vs wait threshold */
124         while (num_waitchk) {
125                 u32 override;
126
127                 BUG_ON(wait->syncpt_id >= NV_HOST1X_SYNCPT_NB_PTS);
128                 trace_nvhost_syncpt_wait_check(wait->mem, wait->offset,
129                                 wait->syncpt_id, wait->thresh);
130                 if (nvhost_syncpt_is_expired(sp,
131                                         wait->syncpt_id, wait->thresh)) {
132                         /*
133                          * NULL an already satisfied WAIT_SYNCPT host method,
134                          * by patching its args in the command stream. The
135                          * method data is changed to reference a reserved
136                          * (never given out or incr) NVSYNCPT_GRAPHICS_HOST
137                          * syncpt with a matching threshold value of 0, so
138                          * is guaranteed to be popped by the host HW.
139                          */
140                         dev_dbg(&syncpt_to_dev(sp)->dev->dev,
141                             "drop WAIT id %d (%s) thresh 0x%x, min 0x%x\n",
142                             wait->syncpt_id,
143                             syncpt_op(sp).name(sp, wait->syncpt_id),
144                             wait->thresh,
145                             nvhost_syncpt_read_min(sp, wait->syncpt_id));
146
147                         /* patch the wait */
148                         override = nvhost_class_host_wait_syncpt(
149                                         NVSYNCPT_GRAPHICS_HOST, 0);
150                         err = nvmap_patch_word(nvmap,
151                                         (struct nvmap_handle *)wait->mem,
152                                         wait->offset, override);
153                         if (err)
154                                 break;
155                 }
156
157                 wait++;
158                 num_waitchk--;
159         }
160         return err;
161 }
162
163
164 static const char *s_syncpt_names[32] = {
165         "gfx_host",
166         "", "", "", "", "", "", "",
167         "disp0_a", "disp1_a", "avp_0",
168         "csi_vi_0", "csi_vi_1",
169         "vi_isp_0", "vi_isp_1", "vi_isp_2", "vi_isp_3", "vi_isp_4",
170         "2d_0", "2d_1",
171         "disp0_b", "disp1_b",
172         "3d",
173         "mpe",
174         "disp0_c", "disp1_c",
175         "vblank0", "vblank1",
176         "mpe_ebm_eof", "mpe_wr_safe",
177         "2d_tinyblt",
178         "dsi"
179 };
180
181 static const char *t20_syncpt_name(struct nvhost_syncpt *s, u32 id)
182 {
183         BUG_ON(id >= ARRAY_SIZE(s_syncpt_names));
184         return s_syncpt_names[id];
185 }
186
187 static void t20_syncpt_debug(struct nvhost_syncpt *sp)
188 {
189         u32 i;
190         for (i = 0; i < NV_HOST1X_SYNCPT_NB_PTS; i++) {
191                 u32 max = nvhost_syncpt_read_max(sp, i);
192                 u32 min = nvhost_syncpt_update_min(sp, i);
193                 if (!max && !min)
194                         continue;
195                 dev_info(&syncpt_to_dev(sp)->dev->dev,
196                         "id %d (%s) min %d max %d\n",
197                         i, syncpt_op(sp).name(sp, i),
198                         min, max);
199
200         }
201
202         for (i = 0; i < NV_HOST1X_SYNCPT_NB_BASES; i++) {
203                 u32 base_val;
204                 t20_syncpt_read_wait_base(sp, i);
205                 base_val = sp->base_val[i];
206                 if (base_val)
207                         dev_info(&syncpt_to_dev(sp)->dev->dev,
208                                         "waitbase id %d val %d\n",
209                                         i, base_val);
210
211         }
212 }
213
214 static int syncpt_mutex_try_lock(struct nvhost_syncpt *sp,
215                 unsigned int idx)
216 {
217         void __iomem *sync_regs = syncpt_to_dev(sp)->sync_aperture;
218         /* mlock registers returns 0 when the lock is aquired.
219          * writing 0 clears the lock. */
220         return !!readl(sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
221 }
222
223 static void syncpt_mutex_unlock(struct nvhost_syncpt *sp,
224                unsigned int idx)
225 {
226         void __iomem *sync_regs = syncpt_to_dev(sp)->sync_aperture;
227
228         writel(0, sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
229 }
230
231 int host1x_init_syncpt_support(struct nvhost_master *host)
232 {
233
234         host->sync_aperture = host->aperture +
235                 (NV_HOST1X_CHANNEL0_BASE +
236                         HOST1X_CHANNEL_SYNC_REG_BASE);
237
238         host->op.syncpt.reset = t20_syncpt_reset;
239         host->op.syncpt.reset_wait_base = t20_syncpt_reset_wait_base;
240         host->op.syncpt.read_wait_base = t20_syncpt_read_wait_base;
241         host->op.syncpt.update_min = t20_syncpt_update_min;
242         host->op.syncpt.cpu_incr = t20_syncpt_cpu_incr;
243         host->op.syncpt.wait_check = t20_syncpt_wait_check;
244         host->op.syncpt.debug = t20_syncpt_debug;
245         host->op.syncpt.name = t20_syncpt_name;
246         host->op.syncpt.mutex_try_lock = syncpt_mutex_try_lock;
247         host->op.syncpt.mutex_unlock = syncpt_mutex_unlock;
248
249         host->syncpt.nb_pts = NV_HOST1X_SYNCPT_NB_PTS;
250         host->syncpt.nb_bases = NV_HOST1X_SYNCPT_NB_BASES;
251         host->syncpt.client_managed = NVSYNCPTS_CLIENT_MANAGED;
252         host->syncpt.nb_mlocks =  NV_HOST1X_SYNC_MLOCK_NUM;
253
254         return 0;
255 }