Commit 8bf1e9f1 authored by Shuang He's avatar Shuang He Committed by Daniel Vetter

drm/i915: Expose latest 200 CRC value for pipe through debugfs

There are several points in the display pipeline where CRCs can be
computed on the bits flowing there. For instance, it's usually possible
to compute the CRCs of the primary plane, the sprite plane or the CRCs
of the bits after the panel fitter (collectively called pipe CRCs).

v2: Quite a bit of rework here and there (Damien)
Signed-off-by: default avatarShuang He <shuang.he@intel.com>
Signed-off-by: default avatarDamien Lespiau <damien.lespiau@intel.com>
[danvet: Fix intermediate compile file reported by Wu Fengguang's
kernel builder.]
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 73ae478c
......@@ -1732,6 +1732,36 @@ static int i915_pc8_status(struct seq_file *m, void *unused)
return 0;
}
static int i915_pipe_crc(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe = (enum pipe)node->info_ent->data;
const struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
int i;
int start;
if (!IS_IVYBRIDGE(dev)) {
seq_puts(m, "unsupported\n");
return 0;
}
start = atomic_read(&pipe_crc->slot) + 1;
seq_puts(m, " timestamp CRC1 CRC2 CRC3 CRC4 CRC5\n");
for (i = 0; i < INTEL_PIPE_CRC_ENTRIES_NR; i++) {
const struct intel_pipe_crc_entry *entry =
&pipe_crc->entries[(start + i) %
INTEL_PIPE_CRC_ENTRIES_NR];
seq_printf(m, "%12u %8x %8x %8x %8x %8x\n", entry->timestamp,
entry->crc[0], entry->crc[1], entry->crc[2],
entry->crc[3], entry->crc[4]);
}
return 0;
}
static int
i915_wedged_get(void *data, u64 *val)
{
......@@ -2247,6 +2277,9 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_edp_psr_status", i915_edp_psr_status, 0},
{"i915_energy_uJ", i915_energy_uJ, 0},
{"i915_pc8_status", i915_pc8_status, 0},
{"i915_pipe_A_crc", i915_pipe_crc, 0, (void *)PIPE_A},
{"i915_pipe_B_crc", i915_pipe_crc, 0, (void *)PIPE_B},
{"i915_pipe_C_crc", i915_pipe_crc, 0, (void *)PIPE_C},
};
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
......
......@@ -1217,6 +1217,17 @@ struct i915_package_c8 {
} regsave;
};
struct intel_pipe_crc_entry {
uint32_t timestamp;
uint32_t crc[5];
};
#define INTEL_PIPE_CRC_ENTRIES_NR 200
struct intel_pipe_crc {
struct intel_pipe_crc_entry entries[INTEL_PIPE_CRC_ENTRIES_NR];
atomic_t slot;
};
typedef struct drm_i915_private {
struct drm_device *dev;
struct kmem_cache *slab;
......@@ -1421,6 +1432,10 @@ typedef struct drm_i915_private {
struct i915_dri1_state dri1;
/* Old ums support infrastructure, same warning applies. */
struct i915_ums_state ums;
#ifdef CONFIG_DEBUG_FS
struct intel_pipe_crc pipe_crc[I915_MAX_PIPES];
#endif
} drm_i915_private_t;
static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
......
......@@ -1188,6 +1188,32 @@ static void dp_aux_irq_handler(struct drm_device *dev)
wake_up_all(&dev_priv->gmbus_wait_queue);
}
#if defined(CONFIG_DEBUG_FS)
static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
struct intel_pipe_crc_entry *entry;
ktime_t now;
int ts, slot;
now = ktime_get();
ts = ktime_to_us(now);
slot = (atomic_read(&pipe_crc->slot) + 1) % INTEL_PIPE_CRC_ENTRIES_NR;
entry = &pipe_crc->entries[slot];
entry->timestamp = ts;
entry->crc[0] = I915_READ(PIPE_CRC_RES_1_IVB(pipe));
entry->crc[1] = I915_READ(PIPE_CRC_RES_2_IVB(pipe));
entry->crc[2] = I915_READ(PIPE_CRC_RES_3_IVB(pipe));
entry->crc[3] = I915_READ(PIPE_CRC_RES_4_IVB(pipe));
entry->crc[4] = I915_READ(PIPE_CRC_RES_5_IVB(pipe));
atomic_set(&dev_priv->pipe_crc[pipe].slot, slot);
}
#else
static void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {}
#endif
/* The RPS events need forcewake, so we add them to a work queue and mask their
* IMR bits until the work is done. Other interrupts can be processed without
* the work queue. */
......@@ -1366,6 +1392,15 @@ static void ivb_err_int_handler(struct drm_device *dev)
if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_C, false))
DRM_DEBUG_DRIVER("Pipe C FIFO underrun\n");
if (err_int & ERR_INT_PIPE_CRC_DONE_A)
ivb_pipe_crc_update(dev, PIPE_A);
if (err_int & ERR_INT_PIPE_CRC_DONE_B)
ivb_pipe_crc_update(dev, PIPE_B);
if (err_int & ERR_INT_PIPE_CRC_DONE_C)
ivb_pipe_crc_update(dev, PIPE_C);
I915_WRITE(GEN7_ERR_INT, err_int);
}
......
......@@ -722,8 +722,11 @@
#define GEN7_ERR_INT 0x44040
#define ERR_INT_POISON (1<<31)
#define ERR_INT_MMIO_UNCLAIMED (1<<13)
#define ERR_INT_PIPE_CRC_DONE_C (1<<8)
#define ERR_INT_FIFO_UNDERRUN_C (1<<6)
#define ERR_INT_PIPE_CRC_DONE_B (1<<5)
#define ERR_INT_FIFO_UNDERRUN_B (1<<3)
#define ERR_INT_PIPE_CRC_DONE_A (1<<2)
#define ERR_INT_FIFO_UNDERRUN_A (1<<0)
#define ERR_INT_FIFO_UNDERRUN(pipe) (1<<(pipe*3))
......@@ -1835,6 +1838,38 @@
* Display engine regs
*/
/* Pipe A CRC regs */
#define _PIPE_CRC_CTL_A (dev_priv->info->display_mmio_offset + 0x60050)
#define PIPE_CRC_ENABLE (1 << 31)
#define PIPE_CRC_SOURCE_PRIMARY_IVB (0 << 29)
#define PIPE_CRC_SOURCE_SPRITE_IVB (1 << 29)
#define PIPE_CRC_SOURCE_PF_IVB (2 << 29)
#define _PIPE_CRC_RES_1_A_IVB (dev_priv->info->display_mmio_offset + 0x60064)
#define _PIPE_CRC_RES_2_A_IVB (dev_priv->info->display_mmio_offset + 0x60068)
#define _PIPE_CRC_RES_3_A_IVB (dev_priv->info->display_mmio_offset + 0x6006c)
#define _PIPE_CRC_RES_4_A_IVB (dev_priv->info->display_mmio_offset + 0x60070)
#define _PIPE_CRC_RES_5_A_IVB (dev_priv->info->display_mmio_offset + 0x60074)
/* Pipe B CRC regs */
#define _PIPE_CRC_CTL_B (dev_priv->info->display_mmio_offset + 0x61050)
#define _PIPE_CRC_RES_1_B_IVB (dev_priv->info->display_mmio_offset + 0x61064)
#define _PIPE_CRC_RES_2_B_IVB (dev_priv->info->display_mmio_offset + 0x61068)
#define _PIPE_CRC_RES_3_B_IVB (dev_priv->info->display_mmio_offset + 0x6106c)
#define _PIPE_CRC_RES_4_B_IVB (dev_priv->info->display_mmio_offset + 0x61070)
#define _PIPE_CRC_RES_5_B_IVB (dev_priv->info->display_mmio_offset + 0x61074)
#define PIPE_CRC_CTL(pipe) _PIPE(pipe, _PIPE_CRC_CTL_A, _PIPE_CRC_CTL_B)
#define PIPE_CRC_RES_1_IVB(pipe) \
_PIPE(pipe, _PIPE_CRC_RES_1_A_IVB, _PIPE_CRC_RES_1_B_IVB)
#define PIPE_CRC_RES_2_IVB(pipe) \
_PIPE(pipe, _PIPE_CRC_RES_2_A_IVB, _PIPE_CRC_RES_2_B_IVB)
#define PIPE_CRC_RES_3_IVB(pipe) \
_PIPE(pipe, _PIPE_CRC_RES_3_A_IVB, _PIPE_CRC_RES_3_B_IVB)
#define PIPE_CRC_RES_4_IVB(pipe) \
_PIPE(pipe, _PIPE_CRC_RES_4_A_IVB, _PIPE_CRC_RES_4_B_IVB)
#define PIPE_CRC_RES_5_IVB(pipe) \
_PIPE(pipe, _PIPE_CRC_RES_5_A_IVB, _PIPE_CRC_RES_5_B_IVB)
/* Pipe A timing regs */
#define _HTOTAL_A (dev_priv->info->display_mmio_offset + 0x60000)
#define _HBLANK_A (dev_priv->info->display_mmio_offset + 0x60004)
......@@ -1857,7 +1892,6 @@
#define _BCLRPAT_B (dev_priv->info->display_mmio_offset + 0x61020)
#define _VSYNCSHIFT_B (dev_priv->info->display_mmio_offset + 0x61028)
#define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B)
#define HBLANK(trans) _TRANSCODER(trans, _HBLANK_A, _HBLANK_B)
#define HSYNC(trans) _TRANSCODER(trans, _HSYNC_A, _HSYNC_B)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment