video: tegra: add channel command fifo debugging support
authorErik Gilling <konkers@dirtysouth.mtv.corp.google.com>
Wed, 15 Sep 2010 21:37:10 +0000 (14:37 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:51:33 +0000 (16:51 -0700)
Change-Id: Iaab4b04aec8feb61000e5423ea32811cca007444
Signed-off-by: Erik Gilling <konkers@dirtysouth.mtv.corp.google.com>
drivers/video/tegra/host/Makefile
drivers/video/tegra/host/debug.c [new file with mode: 0644]
drivers/video/tegra/host/dev.c
drivers/video/tegra/host/dev.h
drivers/video/tegra/host/nvhost_hardware.h

index 6357c88355850bf1c05f4cbf9bc7e29bf8b276d2..c13f8348ed9c12f4a60afed708cfb51f8f805e4a 100644 (file)
@@ -7,6 +7,7 @@ nvhost-objs = \
        nvhost_channel.o \
        nvhost_3dctx.o \
        dev.o \
-       bus.o
+       bus.o \
+       debug.o
 
 obj-$(CONFIG_TEGRA_GRHOST) += nvhost.o
diff --git a/drivers/video/tegra/host/debug.c b/drivers/video/tegra/host/debug.c
new file mode 100644 (file)
index 0000000..c2dfe31
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * drivers/video/tegra/dc/dc.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <konkers@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/io.h>
+
+#include "dev.h"
+
+#ifdef CONFIG_DEBUG_FS
+
+enum {
+       NVHOST_DBG_STATE_CMD = 0,
+       NVHOST_DBG_STATE_DATA = 1,
+};
+
+static int nvhost_debug_handle_cmd(struct seq_file *s, u32 val, int *count)
+{
+       unsigned mask;
+       unsigned subop;
+
+       switch (val >> 28) {
+       case 0x0:
+               mask = val & 0x3f;
+               if (mask) {
+                       seq_printf(s, "SETCL(class=%03x, offset=%03x, mask=%02x, [",
+                                  val >> 6 & 0x3ff, val >> 16 & 0xfff, mask);
+                       *count = hweight8(mask);
+                       return NVHOST_DBG_STATE_DATA;
+               } else {
+                       seq_printf(s, "SETCL(class=%03x)\n", val >> 6 & 0x3ff);
+                       return NVHOST_DBG_STATE_CMD;
+               }
+
+       case 0x1:
+               seq_printf(s, "INCR(offset=%03x, [", val >> 16 & 0x3ff);
+               *count = val & 0xffff;
+               return NVHOST_DBG_STATE_DATA;
+
+       case 0x2:
+               seq_printf(s, "NOMINCR(offset=%03x, [", val >> 16 & 0x3ff);
+               *count = val & 0xffff;
+               return NVHOST_DBG_STATE_DATA;
+
+       case 0x3:
+               mask = val & 0xffff;
+               seq_printf(s, "MASK(offset=%03x, mask=%03x, [",
+                          val >> 16 & 0x3ff, mask);
+               *count = hweight16(mask);
+               return NVHOST_DBG_STATE_DATA;
+
+       case 0x4:
+               seq_printf(s, "IMM(offset=%03x, data=%03x)\n",
+                          val >> 16 & 0x3ff, val & 0xffff);
+               return NVHOST_DBG_STATE_CMD;
+
+       case 0x5:
+               seq_printf(s, "RESTART(offset=%08x)\n", val << 4);
+               return NVHOST_DBG_STATE_CMD;
+
+       case 0x6:
+               seq_printf(s, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
+                          val >> 16 & 0x3ff, val >> 15 & 0x1, val >> 15 & 0x1,
+                          val & 0x3fff);
+               *count = 1;
+               return NVHOST_DBG_STATE_DATA;
+
+       case 0xe:
+               subop = val >> 24 & 0xf;
+               if (subop == 0)
+                       seq_printf(s, "ACQUIRE_MLOCK(index=%d)\n", val & 0xff);
+               else if (subop == 1)
+                       seq_printf(s, "RELEASE_MLOCK(index=%d)\n", val & 0xff);
+               else
+                       seq_printf(s, "EXTEND_UNKNOWN(%08x)\n", val);
+
+               return NVHOST_DBG_STATE_CMD;
+
+       case 0xf:
+               seq_printf(s, "DONE()\n");
+               return NVHOST_DBG_STATE_CMD;
+
+       default:
+               return NVHOST_DBG_STATE_CMD;
+       }
+}
+
+static int nvhost_debug_show(struct seq_file *s, void *unused)
+{
+       struct nvhost_master *m = s->private;
+       int i;
+
+       nvhost_module_busy(&m->mod);
+
+       for (i = 0; i < NVHOST_NUMCHANNELS; i++) {
+               void __iomem *regs = m->channels[i].aperture;
+               u32 dmaput, dmaget, dmactrl;
+               u32 cbstat, cbread;
+               u32 fifostat;
+               u32 val, base;
+               unsigned start, end;
+               unsigned wr_ptr, rd_ptr;
+               int state;
+               int count = 0;
+
+               dmaput = readl(regs + HOST1X_CHANNEL_DMAPUT);
+               dmaget = readl(regs + HOST1X_CHANNEL_DMAGET);
+               dmactrl = readl(regs + HOST1X_CHANNEL_DMACTRL);
+               cbread = readl(m->aperture + HOST1X_SYNC_CBREAD(i));
+               cbstat = readl(m->aperture + HOST1X_SYNC_CBSTAT(i));
+
+               if (dmactrl != 0x0 || !m->channels[i].cdma.push_buffer.mapped) {
+                       seq_printf(s, "%d: inactive\n\n", i);
+                       continue;
+               }
+
+               switch (cbstat) {
+               case 0x00010008:
+                       seq_printf(s, "%d: waiting on syncpt %d val %d\n",
+                                  i, cbread >> 24, cbread & 0xffffff);
+                       break;
+
+               case 0x00010009:
+                       base = cbread >> 15 & 0xf;
+
+                       val = readl(m->aperture + HOST1X_SYNC_SYNCPT_BASE(base)) & 0xffff;
+                       val += cbread & 0xffff;
+
+                       seq_printf(s, "%d: waiting on syncpt %d val %d\n",
+                                  i, cbread >> 24, val);
+                       break;
+
+               default:
+                       seq_printf(s, "%d: active class %02x, offset %04x, val %08x\n",
+                                  i, cbstat >> 16, cbstat & 0xffff, cbread);
+                       break;
+               }
+
+               fifostat = readl(regs + HOST1X_CHANNEL_FIFOSTAT);
+               if ((fifostat & 1 << 10) == 0 ) {
+
+                       writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+                       writel(1 << 31 | i << 16, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+                       rd_ptr = readl(m->aperture + HOST1X_SYNC_CFPEEK_PTRS) & 0x1ff;
+                       wr_ptr = readl(m->aperture + HOST1X_SYNC_CFPEEK_PTRS) >> 16 & 0x1ff;
+
+                       start = readl(m->aperture + HOST1X_SYNC_CF_SETUP(i)) & 0x1ff;
+                       end = (readl(m->aperture + HOST1X_SYNC_CF_SETUP(i)) >> 16) & 0x1ff;
+
+                       state = NVHOST_DBG_STATE_CMD;
+
+                       do {
+                               writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+                               writel(1 << 31 | i << 16 | rd_ptr, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+                               val = readl(m->aperture + HOST1X_SYNC_CFPEEK_READ);
+
+                               switch (state) {
+                               case NVHOST_DBG_STATE_CMD:
+                                       seq_printf(s, "%d: %08x:", i, val);
+
+                                       state = nvhost_debug_handle_cmd(s, val, &count);
+                                       if (state == NVHOST_DBG_STATE_DATA && count == 0) {
+                                               state = NVHOST_DBG_STATE_CMD;
+                                               seq_printf(s, "])\n");
+                                       }
+                                       break;
+
+                               case NVHOST_DBG_STATE_DATA:
+                                       count--;
+                                       seq_printf(s, "%08x%s", val, count > 0 ? ", " : "])\n");
+                                       if (count == 0)
+                                               state = NVHOST_DBG_STATE_CMD;
+                                       break;
+                               }
+
+                               if (rd_ptr == end)
+                                       rd_ptr = start;
+                               else
+                                       rd_ptr++;
+
+
+                       } while (rd_ptr != wr_ptr);
+
+                       if (state == NVHOST_DBG_STATE_DATA)
+                               seq_printf(s, ", ...])\n");
+               }
+               seq_printf(s, "\n");
+       }
+
+       nvhost_module_idle(&m->mod);
+       return 0;
+}
+
+
+static int nvhost_debug_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, nvhost_debug_show, inode->i_private);
+}
+
+static const struct file_operations nvhost_debug_fops = {
+       .open           = nvhost_debug_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+void nvhost_debug_init(struct nvhost_master *master)
+{
+       debugfs_create_file("tegra_host", S_IRUGO, NULL, master, &nvhost_debug_fops);
+}
+#else
+void nvhost_debug_add(struct nvhost_master *master)
+{
+}
+
+#endif
+
index 61ccc1e1bfaeba8c68d082ad7a66a750d382bae3..721504671bd9935c7e78fa321d01d38f7773f800 100644 (file)
@@ -700,6 +700,8 @@ static int __devinit nvhost_probe(struct platform_device *pdev)
 
        nvhost_bus_register(host);
 
+       nvhost_debug_init(host);
+
        dev_info(&pdev->dev, "initialized\n");
        return 0;
 
index 4529cf0ba4814cd64e97039715910a7225ff72f7..fdf755f1af9f0df9ce668a927838b9ef476870f8 100644 (file)
@@ -46,4 +46,6 @@ struct nvhost_master {
        struct nvhost_channel channels[NVHOST_NUMCHANNELS];
 };
 
+void nvhost_debug_init(struct nvhost_master *master);
+
 #endif
index d1d4ede89e06a436d0690b76d28da9e463139c7b..f69f467dd64e3ca2058fb2ab36efff1234b8f4eb 100644 (file)
@@ -39,14 +39,24 @@ enum {
 #define NV_HOST1X_CHANNEL0_BASE 0
 #define NV_HOST1X_CHANNEL_MAP_SIZE_BYTES 16384
 
-enum {
-       HOST1X_CHANNEL_FIFOSTAT = 0x00,
-       HOST1X_CHANNEL_INDDATA  = 0x0c,
-       HOST1X_CHANNEL_DMASTART = 0x14,
-       HOST1X_CHANNEL_DMAPUT   = 0x18,
-       HOST1X_CHANNEL_DMAEND   = 0x20,
-       HOST1X_CHANNEL_DMACTRL  = 0x24
-};
+
+#define HOST1X_CHANNEL_FIFOSTAT                0x00
+#define HOST1X_CHANNEL_INDDATA         0x0c
+#define HOST1X_CHANNEL_DMASTART                0x14
+#define HOST1X_CHANNEL_DMAPUT          0x18
+#define HOST1X_CHANNEL_DMAGET          0x1c
+#define HOST1X_CHANNEL_DMAEND          0x20
+#define HOST1X_CHANNEL_DMACTRL         0x24
+
+#define HOST1X_SYNC_CF_SETUP(x)                (0x3080 + (4 * (x)))
+
+#define HOST1X_SYNC_SYNCPT_BASE(x)     (0x3600 + (4 * (x)))
+
+#define HOST1X_SYNC_CBREAD(x)          (0x3720 + (4 * (x)))
+#define HOST1X_SYNC_CFPEEK_CTRL                0x374c
+#define HOST1X_SYNC_CFPEEK_READ                0x3750
+#define HOST1X_SYNC_CFPEEK_PTRS                0x3754
+#define HOST1X_SYNC_CBSTAT(x)          (0x3758 + (4 * (x)))
 
 static inline unsigned nvhost_channel_fifostat_outfentries(u32 reg)
 {