drm/tegra: dc: Record statistics

Record interrupt statistics, such as the number of frames and VBLANKs
received and the number of FIFO underflow and overflows.

Signed-off-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
Thierry Reding 2015-07-28 21:27:05 +02:00
parent 01a5da0c10
commit 791ddb1e1c
2 changed files with 49 additions and 3 deletions

View file

@ -76,6 +76,14 @@ to_tegra_plane_state(struct drm_plane_state *state)
return NULL;
}
static void tegra_dc_stats_reset(struct tegra_dc_stats *stats)
{
stats->frames = 0;
stats->vblank = 0;
stats->underflow = 0;
stats->overflow = 0;
}
/*
* Reads the active copy of a register. This takes the dc->lock spinlock to
* prevent races with the VBLANK processing which also needs access to the
@ -1129,6 +1137,7 @@ static void tegra_crtc_disable(struct drm_crtc *crtc)
tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
}
tegra_dc_stats_reset(&dc->stats);
drm_crtc_vblank_off(crtc);
}
@ -1326,6 +1335,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
/*
dev_dbg(dc->dev, "%s(): frame end\n", __func__);
*/
dc->stats.frames++;
}
if (status & VBLANK_INT) {
@ -1334,12 +1344,21 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
*/
drm_crtc_handle_vblank(&dc->base);
tegra_dc_finish_page_flip(dc);
dc->stats.vblank++;
}
if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) {
/*
dev_dbg(dc->dev, "%s(): underflow\n", __func__);
*/
dc->stats.underflow++;
}
if (status & (WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT)) {
/*
dev_dbg(dc->dev, "%s(): overflow\n", __func__);
*/
dc->stats.overflow++;
}
return IRQ_HANDLED;
@ -1593,9 +1612,23 @@ static int tegra_dc_show_crc(struct seq_file *s, void *data)
return 0;
}
static int tegra_dc_show_stats(struct seq_file *s, void *data)
{
struct drm_info_node *node = s->private;
struct tegra_dc *dc = node->info_ent->data;
seq_printf(s, "frames: %lu\n", dc->stats.frames);
seq_printf(s, "vblank: %lu\n", dc->stats.vblank);
seq_printf(s, "underflow: %lu\n", dc->stats.underflow);
seq_printf(s, "overflow: %lu\n", dc->stats.overflow);
return 0;
}
static struct drm_info_list debugfs_files[] = {
{ "regs", tegra_dc_show_regs, 0, NULL },
{ "crc", tegra_dc_show_crc, 0, NULL },
{ "stats", tegra_dc_show_stats, 0, NULL },
};
static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor)
@ -1741,7 +1774,8 @@ static int tegra_dc_init(struct host1x_client *client)
tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC);
}
value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
@ -1757,15 +1791,19 @@ static int tegra_dc_init(struct host1x_client *client)
WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
if (dc->soc->supports_border_color)
tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);
tegra_dc_stats_reset(&dc->stats);
return 0;
cleanup:

View file

@ -105,6 +105,13 @@ int tegra_drm_exit(struct tegra_drm *tegra);
struct tegra_dc_soc_info;
struct tegra_output;
struct tegra_dc_stats {
unsigned long frames;
unsigned long vblank;
unsigned long underflow;
unsigned long overflow;
};
struct tegra_dc {
struct host1x_client client;
struct host1x_syncpt *syncpt;
@ -122,6 +129,7 @@ struct tegra_dc {
struct tegra_output *rgb;
struct tegra_dc_stats stats;
struct list_head list;
struct drm_info_list *debugfs_files;