summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/dc.c
diff options
context:
space:
mode:
authorHeechul Yun <hyun@nvidia.com>2011-05-19 17:18:56 -0700
committerNiket Sirsi <nsirsi@nvidia.com>2011-06-15 21:46:50 -0700
commit712d1de6967c79b6dc227a5a573836b799bf5386 (patch)
treee9ead71fc886eda4a7435b8066ca9ec804090758 /drivers/video/tegra/dc/dc.c
parent40c8a6e8551e81ad4d7647029e0d85f7b0a7e496 (diff)
video: tegra: dc: DC and HDMI debug info display
Following files will show information of DC and hdmi /sys/kernel/debug/tegradc.[01]/{regs,mode,stats} /sys/kernel/debug/tegra_hdmi/regs /sys/devices/nvhost/tegradc.[01]/stats_enable Bug 827295 Change-Id: I60bcf4454b9ea7d0ed73a6199595b06dbfa32cd7 Reviewed-on: http://git-master/r/32454 Reviewed-by: Niket Sirsi <nsirsi@nvidia.com> Tested-by: Niket Sirsi <nsirsi@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/dc/dc.c')
-rw-r--r--drivers/video/tegra/dc/dc.c175
1 files changed, 159 insertions, 16 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 8d10d4cc0a69..5b5631d3aaf9 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -293,11 +293,11 @@ static void dump_regs(struct tegra_dc *dc)
{
_dump_regs(dc, dc, dump_regs_print);
}
-#else
+#else /* !DEBUG */
static void dump_regs(struct tegra_dc *dc) {}
-#endif
+#endif /* DEBUG */
#ifdef CONFIG_DEBUG_FS
@@ -325,25 +325,126 @@ static int dbg_dc_open(struct inode *inode, struct file *file)
return single_open(file, dbg_dc_show, inode->i_private);
}
-static const struct file_operations dbg_fops = {
+static const struct file_operations regs_fops = {
.open = dbg_dc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static void tegra_dc_dbg_add(struct tegra_dc *dc)
+static int dbg_dc_mode_show(struct seq_file *s, void *unused)
{
- char name[32];
+ struct tegra_dc *dc = s->private;
+ struct tegra_dc_mode *m;
- snprintf(name, sizeof(name), "tegra_dc%d_regs", dc->ndev->id);
- (void) debugfs_create_file(name, S_IRUGO, NULL, dc, &dbg_fops);
+ mutex_lock(&dc->lock);
+ m = &dc->mode;
+ seq_printf(s,
+ "pclk: %d\n"
+ "h_ref_to_sync: %d\n"
+ "v_ref_to_sync: %d\n"
+ "h_sync_width: %d\n"
+ "v_sync_width: %d\n"
+ "h_back_porch: %d\n"
+ "v_back_porch: %d\n"
+ "h_active: %d\n"
+ "v_active: %d\n"
+ "h_front_porch: %d\n"
+ "v_front_porch: %d\n"
+ "stereo_mode: %d\n",
+ m->pclk, m->h_ref_to_sync, m->v_ref_to_sync,
+ m->h_sync_width, m->v_sync_width,
+ m->h_back_porch, m->v_back_porch,
+ m->h_active, m->v_active,
+ m->h_front_porch, m->v_front_porch,
+ m->stereo_mode);
+ mutex_unlock(&dc->lock);
+ return 0;
}
-#else
-static void tegra_dc_dbg_add(struct tegra_dc *dc) {}
-#endif
+static int dbg_dc_mode_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dbg_dc_mode_show, inode->i_private);
+}
+
+static const struct file_operations mode_fops = {
+ .open = dbg_dc_mode_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int dbg_dc_stats_show(struct seq_file *s, void *unused)
+{
+ struct tegra_dc *dc = s->private;
+
+ mutex_lock(&dc->lock);
+ seq_printf(s,
+ "underflows: %u\n"
+ "underflows_a: %u\n"
+ "underflows_b: %u\n"
+ "underflows_c: %u\n",
+ dc->stats.underflows,
+ dc->stats.underflows_a,
+ dc->stats.underflows_b,
+ dc->stats.underflows_c);
+ mutex_unlock(&dc->lock);
+
+ return 0;
+}
+
+static int dbg_dc_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dbg_dc_stats_show, inode->i_private);
+}
+
+static const struct file_operations stats_fops = {
+ .open = dbg_dc_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void __devexit tegra_dc_remove_debugfs(struct tegra_dc *dc)
+{
+ if (dc->debugdir)
+ debugfs_remove_recursive(dc->debugdir);
+ dc->debugdir = NULL;
+}
+
+static void tegra_dc_create_debugfs(struct tegra_dc *dc)
+{
+ struct dentry *retval;
+
+ dc->debugdir = debugfs_create_dir(dev_name(&dc->ndev->dev), NULL);
+ if (!dc->debugdir)
+ goto remove_out;
+ retval = debugfs_create_file("regs", S_IRUGO, dc->debugdir, dc,
+ &regs_fops);
+ if (!retval)
+ goto remove_out;
+
+ retval = debugfs_create_file("mode", S_IRUGO, dc->debugdir, dc,
+ &mode_fops);
+ if (!retval)
+ goto remove_out;
+
+ retval = debugfs_create_file("stats", S_IRUGO, dc->debugdir, dc,
+ &stats_fops);
+ if (!retval)
+ goto remove_out;
+
+ return;
+remove_out:
+ dev_err(&dc->ndev->dev, "could not create debugfs\n");
+ tegra_dc_remove_debugfs(dc);
+}
+
+#else /* !CONFIG_DEBUGFS */
+static inline void tegra_dc_create_debugfs(struct tegra_dc *dc) { };
+static inline void __devexit tegra_dc_remove_debugfs(struct tegra_dc *dc) { };
+#endif /* CONFIG_DEBUGFS */
static int tegra_dc_add(struct tegra_dc *dc, int index)
{
@@ -914,10 +1015,10 @@ static void print_mode(struct tegra_dc *dc,
mode->pclk);
}
}
-#else
+#else /* !DEBUG */
static inline void print_mode(struct tegra_dc *dc,
const struct tegra_dc_mode *mode, const char *note) { }
-#endif
+#endif /* DEBUG */
static inline void enable_dc_irq(unsigned int irq)
{
@@ -1274,11 +1375,19 @@ static irqreturn_t tegra_dc_irq(int irq, void *ptr)
* hosed and reset.
*/
underflow_mask = status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT);
+
if (underflow_mask) {
val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
val |= V_BLANK_INT;
tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
dc->underflow_mask |= underflow_mask;
+ dc->stats.underflows++;
+ if (status & WIN_A_UF_INT)
+ dc->stats.underflows_a++;
+ if (status & WIN_B_UF_INT)
+ dc->stats.underflows_b++;
+ if (status & WIN_C_UF_INT)
+ dc->stats.underflows_c++;
}
if (status & V_BLANK_INT) {
@@ -1355,9 +1464,9 @@ static irqreturn_t tegra_dc_irq(int irq, void *ptr)
}
return IRQ_HANDLED;
-#else
+#else /* CONFIG_TEGRA_FPGA_PLATFORM */
return IRQ_NONE;
-#endif
+#endif /* !CONFIG_TEGRA_FPGA_PLATFORM */
}
static void tegra_dc_set_color_control(struct tegra_dc *dc)
@@ -1627,6 +1736,39 @@ static void _tegra_dc_controller_disable(struct tegra_dc *dc)
}
}
+void tegra_dc_stats_enable(struct tegra_dc *dc, bool enable)
+{
+#if 0 /* underflow interrupt is already enabled by dc reset worker */
+ u32 val;
+ if (dc->enabled) {
+ val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
+ if (enable)
+ val |= (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT);
+ else
+ val &= ~(WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT);
+ tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
+ }
+#endif
+}
+
+bool tegra_dc_stats_get(struct tegra_dc *dc)
+{
+#if 0 /* right now it is always enabled */
+ u32 val;
+ bool res;
+
+ if (dc->enabled) {
+ val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
+ res = !!(val & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT));
+ } else {
+ res = false;
+ }
+
+ return res;
+#endif
+ return true;
+}
+
static void _tegra_dc_disable(struct tegra_dc *dc)
{
_tegra_dc_controller_disable(dc);
@@ -1841,7 +1983,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
_tegra_dc_enable(dc);
mutex_unlock(&dc->lock);
- tegra_dc_dbg_add(dc);
+ tegra_dc_create_debugfs(dc);
dev_info(&ndev->dev, "probed\n");
@@ -1901,6 +2043,7 @@ static int tegra_dc_remove(struct nvhost_device *ndev)
struct tegra_dc *dc = nvhost_get_drvdata(ndev);
tegra_dc_remove_sysfs(&dc->ndev->dev);
+ tegra_dc_remove_debugfs(dc);
if (dc->overlay) {
tegra_overlay_unregister(dc->overlay);
@@ -1981,7 +2124,7 @@ static int tegra_dc_resume(struct nvhost_device *ndev)
return 0;
}
-#endif
+#endif /* CONFIG_PM */
extern int suspend_set(const char *val, struct kernel_param *kp)
{