nvhost: Fix tegra_host/status debug output
[linux-2.6.git] / drivers / video / tegra / host / t20 / channel_t20.c
1 /*
2  * drivers/video/tegra/host/t20/channel_t20.c
3  *
4  * Tegra Graphics Host Channel
5  *
6  * Copyright (c) 2010-2011, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  */
22
23 #include "../nvhost_channel.h"
24 #include "../dev.h"
25 #include "../nvhost_hwctx.h"
26 #include <trace/events/nvhost.h>
27
28 #include "hardware_t20.h"
29 #include "syncpt_t20.h"
30
31 #define NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
32 #define NVHOST_CHANNEL_BASE 0
33
34 #define NVMODMUTEX_2D_FULL   (1)
35 #define NVMODMUTEX_2D_SIMPLE (2)
36 #define NVMODMUTEX_2D_SB_A   (3)
37 #define NVMODMUTEX_2D_SB_B   (4)
38 #define NVMODMUTEX_3D        (5)
39 #define NVMODMUTEX_DISPLAYA  (6)
40 #define NVMODMUTEX_DISPLAYB  (7)
41 #define NVMODMUTEX_VI        (8)
42 #define NVMODMUTEX_DSI       (9)
43 #define NV_FIFO_READ_TIMEOUT 200000
44
45 static void power_2d(struct nvhost_module *mod, enum nvhost_power_action action);
46 static void power_3d(struct nvhost_module *mod, enum nvhost_power_action action);
47 static void power_mpe(struct nvhost_module *mod, enum nvhost_power_action action);
48
49
50
51 static const struct nvhost_channeldesc channelmap[] = {
52 {
53         /* channel 0 */
54         .name          = "display",
55         .syncpts       = BIT(NVSYNCPT_DISP0_A) | BIT(NVSYNCPT_DISP1_A) |
56                          BIT(NVSYNCPT_DISP0_B) | BIT(NVSYNCPT_DISP1_B) |
57                          BIT(NVSYNCPT_DISP0_C) | BIT(NVSYNCPT_DISP1_C) |
58                          BIT(NVSYNCPT_VBLANK0) | BIT(NVSYNCPT_VBLANK1),
59         .modulemutexes = BIT(NVMODMUTEX_DISPLAYA) | BIT(NVMODMUTEX_DISPLAYB),
60 },
61 {
62         /* channel 1 */
63         .name          = "gr3d",
64         .syncpts       = BIT(NVSYNCPT_3D),
65         .waitbases     = BIT(NVWAITBASE_3D),
66         .modulemutexes = BIT(NVMODMUTEX_3D),
67         .class         = NV_GRAPHICS_3D_CLASS_ID,
68         .power         = power_3d,
69 },
70 {
71         /* channel 2 */
72         .name          = "gr2d",
73         .syncpts       = BIT(NVSYNCPT_2D_0) | BIT(NVSYNCPT_2D_1),
74         .waitbases     = BIT(NVWAITBASE_2D_0) | BIT(NVWAITBASE_2D_1),
75         .modulemutexes = BIT(NVMODMUTEX_2D_FULL) | BIT(NVMODMUTEX_2D_SIMPLE) |
76                          BIT(NVMODMUTEX_2D_SB_A) | BIT(NVMODMUTEX_2D_SB_B),
77         .power         = power_2d,
78 },
79 {
80         /* channel 3 */
81         .name    = "isp",
82         .syncpts = 0,
83 },
84 {
85         /* channel 4 */
86         .name          = "vi",
87         .syncpts       = BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) |
88                          BIT(NVSYNCPT_VI_ISP_0) | BIT(NVSYNCPT_VI_ISP_1) |
89                          BIT(NVSYNCPT_VI_ISP_2) | BIT(NVSYNCPT_VI_ISP_3) |
90                          BIT(NVSYNCPT_VI_ISP_4),
91         .modulemutexes = BIT(NVMODMUTEX_VI),
92         .exclusive     = true,
93 },
94 {
95         /* channel 5 */
96         .name          = "mpe",
97         .syncpts       = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) |
98                          BIT(NVSYNCPT_MPE_WR_SAFE),
99         .waitbases     = BIT(NVWAITBASE_MPE),
100         .class         = NV_VIDEO_ENCODE_MPEG_CLASS_ID,
101         .power         = power_mpe,
102         .exclusive     = true,
103         .keepalive     = true,
104 },
105 {
106         /* channel 6 */
107         .name          = "dsi",
108         .syncpts       = BIT(NVSYNCPT_DSI),
109         .modulemutexes = BIT(NVMODMUTEX_DSI),
110 }};
111
112 static inline void __iomem *t20_channel_aperture(void __iomem *p, int ndx)
113 {
114         ndx += NVHOST_CHANNEL_BASE;
115         p += NV_HOST1X_CHANNEL0_BASE;
116         p += ndx * NV_HOST1X_CHANNEL_MAP_SIZE_BYTES;
117         return p;
118 }
119
120
121 int t20_nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h);
122 int t20_nvhost_mpectx_handler_init(struct nvhost_hwctx_handler *h);
123
124 static inline int t20_nvhost_hwctx_handler_init(
125         struct nvhost_hwctx_handler *h,
126         const char *module)
127 {
128         if (strcmp(module, "gr3d") == 0)
129                 return t20_nvhost_3dctx_handler_init(h);
130         else if (strcmp(module, "mpe") == 0)
131                 return t20_nvhost_mpectx_handler_init(h);
132
133         return 0;
134 }
135
136
137 static int t20_channel_init(struct nvhost_channel *ch,
138                             struct nvhost_master *dev, int index)
139 {
140         ch->dev = dev;
141         ch->desc = channelmap + index;
142         mutex_init(&ch->reflock);
143         mutex_init(&ch->submitlock);
144
145         ch->aperture = t20_channel_aperture(dev->aperture, index);
146
147         return t20_nvhost_hwctx_handler_init(&ch->ctxhandler, ch->desc->name);
148 }
149
150
151
152 static int t20_channel_submit(struct nvhost_channel *channel,
153                               struct nvhost_hwctx *hwctx,
154                               struct nvmap_client *user_nvmap,
155                               u32 *gather,
156                               u32 *gather_end,
157                               struct nvhost_waitchk *waitchk,
158                               struct nvhost_waitchk *waitchk_end,
159                               u32 waitchk_mask,
160                               struct nvmap_handle **unpins,
161                               int nr_unpins,
162                               u32 syncpt_id,
163                               u32 syncpt_incrs,
164                               u32 *syncpt_value,
165                               bool null_kickoff)
166 {
167         struct nvhost_hwctx *hwctx_to_save = NULL;
168         struct nvhost_syncpt *sp = &channel->dev->syncpt;
169         u32 user_syncpt_incrs = syncpt_incrs;
170         bool need_restore = false;
171         u32 syncval;
172         int err;
173
174         /* keep module powered */
175         nvhost_module_busy(&channel->mod);
176         if (strcmp(channel->mod.name, "gr3d") == 0)
177                 module3d_notify_busy();
178
179         /* get submit lock */
180         err = mutex_lock_interruptible(&channel->submitlock);
181         if (err) {
182                 nvhost_module_idle(&channel->mod);
183                 return err;
184         }
185
186         /* remove stale waits */
187         if (waitchk != waitchk_end) {
188                 err = nvhost_syncpt_wait_check(sp,
189                                                user_nvmap,
190                                                waitchk_mask,
191                                                waitchk, waitchk_end);
192                 if (err) {
193                         dev_warn(&channel->dev->pdev->dev,
194                                  "nvhost_syncpt_wait_check failed: %d\n", err);
195                         mutex_unlock(&channel->submitlock);
196                         nvhost_module_idle(&channel->mod);
197                         return err;
198                 }
199         }
200
201         /* context switch */
202         if (channel->cur_ctx != hwctx) {
203                 trace_nvhost_channel_context_switch(channel->desc->name,
204                   channel->cur_ctx, hwctx);
205                 hwctx_to_save = channel->cur_ctx;
206                 if (hwctx_to_save) {
207                         syncpt_incrs += hwctx_to_save->save_incrs;
208                         hwctx_to_save->valid = true;
209                         channel->ctxhandler.get(hwctx_to_save);
210                 }
211                 channel->cur_ctx = hwctx;
212                 if (channel->cur_ctx && channel->cur_ctx->valid) {
213                         need_restore = true;
214                         syncpt_incrs += channel->cur_ctx->restore_incrs;
215                 }
216         }
217
218         /* get absolute sync value */
219         if (BIT(syncpt_id) & sp->client_managed)
220                 syncval = nvhost_syncpt_set_max(sp,
221                                                 syncpt_id, syncpt_incrs);
222         else
223                 syncval = nvhost_syncpt_incr_max(sp,
224                                                 syncpt_id, syncpt_incrs);
225
226         /* begin a CDMA submit */
227         nvhost_cdma_begin(&channel->cdma);
228
229         /* push save buffer (pre-gather setup depends on unit) */
230         if (hwctx_to_save)
231                 channel->ctxhandler.save_push(&channel->cdma, hwctx_to_save);
232
233         /* gather restore buffer */
234         if (need_restore)
235                 nvhost_cdma_push_gather(&channel->cdma,
236                         nvmap_ref_to_handle(channel->cur_ctx->restore),
237                         nvhost_opcode_gather(channel->cur_ctx->restore_size),
238                         channel->cur_ctx->restore_phys);
239
240         /* add a setclass for modules that require it (unless ctxsw added it) */
241         if (!hwctx_to_save && !need_restore && channel->desc->class)
242                 nvhost_cdma_push(&channel->cdma,
243                         nvhost_opcode_setclass(channel->desc->class, 0, 0),
244                         NVHOST_OPCODE_NOOP);
245
246         if (null_kickoff) {
247                 int incr;
248                 u32 op_incr;
249
250                 /* TODO ideally we'd also perform host waits here */
251
252                 /* push increments that correspond to nulled out commands */
253                 op_incr = nvhost_opcode_imm(0, 0x100 | syncpt_id);
254                 for (incr = 0; incr < (user_syncpt_incrs >> 1); incr++)
255                         nvhost_cdma_push(&channel->cdma, op_incr, op_incr);
256                 if (user_syncpt_incrs & 1)
257                         nvhost_cdma_push(&channel->cdma,
258                                         op_incr, NVHOST_OPCODE_NOOP);
259
260                 /* for 3d, waitbase needs to be incremented after each submit */
261                 if (channel->desc->class == NV_GRAPHICS_3D_CLASS_ID)
262                         nvhost_cdma_push(&channel->cdma,
263                                         nvhost_opcode_setclass(
264                                                 NV_HOST1X_CLASS_ID,
265                                                 NV_CLASS_HOST_INCR_SYNCPT_BASE,
266                                                 1),
267                                         nvhost_class_host_incr_syncpt_base(
268                                                 NVWAITBASE_3D,
269                                                 user_syncpt_incrs));
270         }
271         else {
272                 /* push user gathers */
273                 int i = 0;
274                 for ( ; i < gather_end-gather; i += 2) {
275                         nvhost_cdma_push_gather(&channel->cdma,
276                                         unpins[i/2],
277                                         nvhost_opcode_gather(gather[i]),
278                                         gather[i+1]);
279                 }
280         }
281
282         /* end CDMA submit & stash pinned hMems into sync queue */
283         nvhost_cdma_end(&channel->cdma, user_nvmap,
284                         syncpt_id, syncval, unpins, nr_unpins);
285
286         trace_nvhost_channel_submitted(channel->desc->name,
287                         syncval-syncpt_incrs, syncval);
288
289         /*
290          * schedule a context save interrupt (to drain the host FIFO
291          * if necessary, and to release the restore buffer)
292          */
293         if (hwctx_to_save)
294                 nvhost_intr_add_action(&channel->dev->intr, syncpt_id,
295                         syncval - syncpt_incrs + hwctx_to_save->save_thresh,
296                         NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, NULL);
297
298         /* schedule a submit complete interrupt */
299         err = nvhost_intr_add_action(&channel->dev->intr, syncpt_id, syncval,
300                         NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel, NULL);
301         /*  if add_action failed, the submit has been already completed */
302         if (err)
303                 trace_nvhost_channel_submit_complete(channel->desc->name, 1);
304
305         mutex_unlock(&channel->submitlock);
306
307         *syncpt_value = syncval;
308         return 0;
309 }
310
311 static void power_2d(struct nvhost_module *mod, enum nvhost_power_action action)
312 {
313         /* TODO: [ahatala 2010-06-17] reimplement EPP hang war */
314         if (action == NVHOST_POWER_ACTION_OFF) {
315                 /* TODO: [ahatala 2010-06-17] reset EPP */
316         }
317 }
318
319 static void power_3d(struct nvhost_module *mod, enum nvhost_power_action action)
320 {
321         struct nvhost_channel *ch = container_of(mod, struct nvhost_channel, mod);
322         struct nvhost_hwctx *hwctx_to_save;
323         DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
324         u32 syncpt_incrs, syncpt_val;
325         void *ref;
326
327         if (action != NVHOST_POWER_ACTION_OFF)
328                 return;
329
330         mutex_lock(&ch->submitlock);
331         hwctx_to_save = ch->cur_ctx;
332         if (!hwctx_to_save) {
333                 mutex_unlock(&ch->submitlock);
334                 return;
335         }
336
337         if (strcmp(mod->name, "gr3d") == 0)
338                 module3d_notify_busy();
339
340         hwctx_to_save->valid = true;
341         ch->ctxhandler.get(hwctx_to_save);
342         ch->cur_ctx = NULL;
343
344         syncpt_incrs = hwctx_to_save->save_incrs;
345         syncpt_val = nvhost_syncpt_incr_max(&ch->dev->syncpt,
346                                         NVSYNCPT_3D, syncpt_incrs);
347
348         nvhost_cdma_begin(&ch->cdma);
349         ch->ctxhandler.save_push(&ch->cdma, hwctx_to_save);
350         nvhost_cdma_end(&ch->cdma, ch->dev->nvmap, NVSYNCPT_3D, syncpt_val, NULL, 0);
351
352         nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D,
353                         syncpt_val - syncpt_incrs + hwctx_to_save->save_thresh,
354                         NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, NULL);
355
356         nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D, syncpt_val,
357                         NVHOST_INTR_ACTION_WAKEUP, &wq, &ref);
358         wait_event(wq,
359                 nvhost_syncpt_min_cmp(&ch->dev->syncpt,
360                                 NVSYNCPT_3D, syncpt_val));
361
362         nvhost_intr_put_ref(&ch->dev->intr, ref);
363
364         nvhost_cdma_update(&ch->cdma);
365
366         mutex_unlock(&ch->submitlock);
367 }
368
369 static void power_mpe(struct nvhost_module *mod, enum nvhost_power_action action)
370 {
371 }
372
373 static int t20_channel_read_3d_reg(
374         struct nvhost_channel *channel,
375         struct nvhost_hwctx *hwctx,
376         u32 offset,
377         u32 *value)
378 {
379         struct nvhost_hwctx *hwctx_to_save = NULL;
380         bool need_restore = false;
381         u32 syncpt_incrs = 4;
382         unsigned int pending = 0;
383         DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
384         void *ref;
385         u32 syncval;
386         int err;
387
388         /* keep module powered */
389         nvhost_module_busy(&channel->mod);
390
391         /* get submit lock */
392         err = mutex_lock_interruptible(&channel->submitlock);
393         if (err) {
394                 nvhost_module_idle(&channel->mod);
395                 return err;
396         }
397
398         /* context switch */
399         if (channel->cur_ctx != hwctx) {
400                 hwctx_to_save = channel->cur_ctx;
401                 if (hwctx_to_save) {
402                         syncpt_incrs += hwctx_to_save->save_incrs;
403                         hwctx_to_save->valid = true;
404                         channel->ctxhandler.get(hwctx_to_save);
405                 }
406                 channel->cur_ctx = hwctx;
407                 if (channel->cur_ctx && channel->cur_ctx->valid) {
408                         need_restore = true;
409                         syncpt_incrs += channel->cur_ctx->restore_incrs;
410                 }
411         }
412
413         syncval = nvhost_syncpt_incr_max(&channel->dev->syncpt,
414                 NVSYNCPT_3D, syncpt_incrs);
415
416         /* begin a CDMA submit */
417         nvhost_cdma_begin(&channel->cdma);
418
419         /* push save buffer (pre-gather setup depends on unit) */
420         if (hwctx_to_save)
421                 channel->ctxhandler.save_push(&channel->cdma, hwctx_to_save);
422
423         /* gather restore buffer */
424         if (need_restore)
425                 nvhost_cdma_push(&channel->cdma,
426                         nvhost_opcode_gather(channel->cur_ctx->restore_size),
427                         channel->cur_ctx->restore_phys);
428
429         /* Switch to 3D - wait for it to complete what it was doing */
430         nvhost_cdma_push(&channel->cdma,
431                 nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
432                 nvhost_opcode_imm(NV_CLASS_HOST_INCR_SYNCPT,
433                     NV_CLASS_HOST_SYNCPT_OP_DONE << 8 | NVSYNCPT_3D));
434         nvhost_cdma_push(&channel->cdma,
435                 nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
436                         NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
437                 nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
438                         NVWAITBASE_3D, 1));
439         /*  Tell 3D to send register value to FIFO */
440         nvhost_cdma_push(&channel->cdma,
441                 nvhost_opcode_nonincr(NV_CLASS_HOST_INDOFF, 1),
442                 nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
443                         offset, false));
444         nvhost_cdma_push(&channel->cdma,
445                 nvhost_opcode_imm(NV_CLASS_HOST_INDDATA, 0),
446                 NVHOST_OPCODE_NOOP);
447         /*  Increment syncpt to indicate that FIFO can be read */
448         nvhost_cdma_push(&channel->cdma,
449                 nvhost_opcode_imm(NV_CLASS_HOST_INCR_SYNCPT, NVSYNCPT_3D),
450                 NVHOST_OPCODE_NOOP);
451         /*  Wait for value to be read from FIFO */
452         nvhost_cdma_push(&channel->cdma,
453                 nvhost_opcode_nonincr(NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
454                 nvhost_class_host_wait_syncpt_base(NVSYNCPT_3D,
455                         NVWAITBASE_3D, 3));
456         /*  Indicate submit complete */
457         nvhost_cdma_push(&channel->cdma,
458                 nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1),
459                 nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D, 4));
460         nvhost_cdma_push(&channel->cdma,
461                 NVHOST_OPCODE_NOOP,
462                 nvhost_opcode_imm(NV_CLASS_HOST_INCR_SYNCPT, NVSYNCPT_3D));
463
464         /* end CDMA submit  */
465         nvhost_cdma_end(&channel->cdma, channel->dev->nvmap,
466                         NVSYNCPT_3D, syncval, NULL, 0);
467
468         /*
469          * schedule a context save interrupt (to drain the host FIFO
470          * if necessary, and to release the restore buffer)
471          */
472         if (hwctx_to_save)
473                 nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D,
474                         syncval - syncpt_incrs + hwctx_to_save->save_incrs - 1,
475                         NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, NULL);
476
477         /* Wait for FIFO to be ready */
478         nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D, syncval - 2,
479                         NVHOST_INTR_ACTION_WAKEUP, &wq, &ref);
480         wait_event(wq,
481                 nvhost_syncpt_min_cmp(&channel->dev->syncpt,
482                                 NVSYNCPT_3D, syncval - 2));
483         nvhost_intr_put_ref(&channel->dev->intr, ref);
484
485         /* Read the register value from FIFO */
486         err = nvhost_drain_read_fifo(channel->aperture,
487                 value, 1, &pending);
488
489         /* Indicate we've read the value */
490         nvhost_syncpt_cpu_incr(&channel->dev->syncpt, NVSYNCPT_3D);
491
492         /* Schedule a submit complete interrupt */
493         nvhost_intr_add_action(&channel->dev->intr, NVSYNCPT_3D, syncval,
494                         NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel, NULL);
495
496         mutex_unlock(&channel->submitlock);
497
498         return err;
499 }
500
501 int nvhost_init_t20_channel_support(struct nvhost_master *host)
502 {
503
504         BUILD_BUG_ON(NVHOST_NUMCHANNELS != ARRAY_SIZE(channelmap));
505
506         host->nb_mlocks =  NV_HOST1X_SYNC_MLOCK_NUM;
507         host->nb_channels =  NVHOST_NUMCHANNELS;
508
509         host->op.channel.init = t20_channel_init;
510         host->op.channel.submit = t20_channel_submit;
511         host->op.channel.read3dreg = t20_channel_read_3d_reg;
512
513         return 0;
514 }
515
516 int nvhost_drain_read_fifo(void __iomem *chan_regs,
517         u32 *ptr, unsigned int count, unsigned int *pending)
518 {
519         unsigned int entries = *pending;
520         unsigned long timeout = jiffies + NV_FIFO_READ_TIMEOUT;
521         while (count) {
522                 unsigned int num;
523
524                 while (!entries && time_before(jiffies, timeout)) {
525                         /* query host for number of entries in fifo */
526                         entries = nvhost_channel_fifostat_outfentries(
527                                 readl(chan_regs + HOST1X_CHANNEL_FIFOSTAT));
528                         if (!entries)
529                                 cpu_relax();
530                 }
531
532                 /*  timeout -> return error */
533                 if (!entries)
534                         return -EIO;
535
536                 num = min(entries, count);
537                 entries -= num;
538                 count -= num;
539
540                 while (num & ~0x3) {
541                         u32 arr[4];
542                         arr[0] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
543                         arr[1] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
544                         arr[2] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
545                         arr[3] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
546                         memcpy(ptr, arr, 4*sizeof(u32));
547                         ptr += 4;
548                         num -= 4;
549                 }
550                 while (num--)
551                         *ptr++ = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
552         }
553         *pending = entries;
554
555         return 0;
556 }