[PATCH] INTEL_DII: drm/i915/display: Dark Screen Detection
Nischal Varide
nischal.varide at intel.com
Thu Dec 15 16:23:42 UTC 2022
Blank Screen can be caused by a number of errors like - invalid input
buffers(black), some issues with display programming(no planes enabled,
LUTS zeroed) or some issue between the DE and the screen.
This patch address a generic way to detect a blank screen and inform
the user space.
Signed-off-by: Nischal Varide <nischal.varide at intel.com>
---
.../drm/i915/display/intel_display_debugfs.c | 8 +++++
drivers/gpu/drm/i915/i915_debugfs.h | 2 ++
drivers/gpu/drm/i915/i915_driver.c | 33 +++++++++++++++++
drivers/gpu/drm/i915/i915_drv.h | 11 ++++++
drivers/gpu/drm/i915/i915_irq.c | 36 +++++++++++++++++--
drivers/gpu/drm/i915/i915_irq.h | 3 ++
drivers/gpu/drm/i915/i915_reg.h | 14 ++++++++
7 files changed, 105 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 0e4c4ffb232c1c..b6b664db1d6cb0 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -1191,6 +1191,13 @@ static int i915_fifo_underruns(struct seq_file *m, void *unused)
return 0;
}
+int dark_screen_detection(struct seq_file *m, void *unused)
+{
+ struct drm_i915_private *dev_priv = node_to_i915(m->private);
+ init_dark_screen_detection(dev_priv);
+ return 0;
+}
+
static int i915_dp_mst_info(struct seq_file *m, void *unused)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
@@ -1978,6 +1985,7 @@ static const struct drm_info_list intel_display_debugfs_list[] = {
{"i915_drrs_status", i915_drrs_status, 0},
{"i915_lpsp_status", i915_lpsp_status, 0},
{"i915_fifo_underruns", i915_fifo_underruns, 0},
+ {"dark_screen_detection", dark_screen_detection, 0},
};
static const struct {
diff --git a/drivers/gpu/drm/i915/i915_debugfs.h b/drivers/gpu/drm/i915/i915_debugfs.h
index 8776ffc7df7e88..bc599e67032ee9 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.h
+++ b/drivers/gpu/drm/i915/i915_debugfs.h
@@ -45,6 +45,8 @@ void i915_register_debugfs_show_files(struct dentry *root,
const struct i915_debugfs_file *files,
unsigned long count, void *data);
+extern u8 init_dark_screen_detection(struct drm_i915_private *dev_priv);
+
#define DEFINE_I915_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \
static int __fops ## _open(struct inode *inode, struct file *file) \
{ \
diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c
index 2c90ee3bd80bbb..bc18a1486131f0 100644
--- a/drivers/gpu/drm/i915/i915_driver.c
+++ b/drivers/gpu/drm/i915/i915_driver.c
@@ -398,6 +398,39 @@ static void intel_detect_preproduction_hw(struct drm_i915_private *dev_priv)
}
}
+u8 init_dark_screen_detection(struct drm_i915_private *dev_priv)
+{
+ u32 ret = 0;
+
+ if (DISPLAY_VER(dev_priv) < 15)
+ return ret;
+
+ /*Setting up the comparision value*/
+ ret = DARK_SCREE_COMPARE_VALUE(DARK_SCREEN_VALUE);
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_A, ret);
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_B, ret);
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_C, ret);
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_D, ret);
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_E, ret);
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_F, ret);
+ /*Enabling dark screen detection for all pipes*/
+ ret = intel_uncore_read(&dev_priv->uncore, PIPE_DARKCHECK_A);
+ ret = ret | DARK_SCREEN_ENABLE;
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_A, ret);
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_B, ret);
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_C, ret);
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_D, ret);
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_E, ret);
+ intel_uncore_write(&dev_priv->uncore, PIPE_DARKCHECK_F, ret);
+
+ if(ret)
+ dev_priv->darK_screen_detection_active = 1;
+
+ return dev_priv->darK_screen_detection_active;
+}
+EXPORT_SYMBOL(init_dark_screen_detection);
+
+
static void sanitize_gpu(struct drm_i915_private *i915)
{
if (!INTEL_INFO(i915)->gpu_reset_clobbers_display) {
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 453ffb6ebf265a..31a0d780e03ebe 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -277,6 +277,12 @@ struct intel_l3_parity {
int which_slice;
};
+
+struct dark_scr {
+ struct work_struct dark_screen_work;
+ enum pipe pipe;
+};
+
struct i915_mm_swap_stat {
seqlock_t lock;
unsigned long pages;
@@ -696,6 +702,8 @@ struct drm_i915_private {
struct intel_l3_parity l3_parity;
+ struct dark_scr dark_scr;
+
/*
* HTI (aka HDPORT) state read during initial hw readout. Most
* platforms don't have HTI, so this will just stay 0. Those that do
@@ -988,6 +996,9 @@ struct drm_i915_private {
bool device_faulted;
struct pci_saved_state *pci_state;
+ int dark_screen_detected;
+ struct work_struct *dark_screen_work;
+ u8 darK_screen_detection_active;
};
static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 9ed9119c43e6a8..de0469b2916b78 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -252,8 +252,9 @@ static void
intel_handle_vblank(struct drm_i915_private *dev_priv, enum pipe pipe)
{
struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
-
drm_crtc_handle_vblank(&crtc->base);
+ dev_priv->dark_scr.pipe = pipe;
+ schedule_work(&dev_priv->dark_scr.dark_screen_work);
}
void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr,
@@ -1100,6 +1101,7 @@ int intel_get_crtc_scanline(struct intel_crtc *crtc)
#define SIM_IRQ_TIMER_INTERVAL 30
+
static void sim_irq_timer_fn(struct timer_list *t)
{
struct drm_i915_private *dev_priv = from_timer(dev_priv, t,
@@ -1146,6 +1148,7 @@ static void ivb_parity_work(struct work_struct *work)
struct intel_gt *gt = to_gt(dev_priv);
u32 error_status, row, bank, subbank;
char *parity_event[6];
+
u32 misccpctl;
u8 slice = 0;
@@ -1213,6 +1216,34 @@ static void ivb_parity_work(struct work_struct *work)
mutex_unlock(&dev_priv->drm.struct_mutex);
}
+
+
+static void darkscreen_work(struct work_struct *work)
+{
+ struct drm_i915_private *dev_priv =
+ container_of(work, typeof(*dev_priv), dark_scr.dark_screen_work);
+
+ enum pipe pipe = dev_priv->dark_scr.pipe;
+
+ char *dark_screen_envp[] = {
+ I915_UEVENT_DARK_SCREEN_DETECTED"=1",
+ NULL,
+ };
+
+ if (DISPLAY_VER(dev_priv) >= 15)
+ if ((intel_uncore_read(&dev_priv->uncore, DARK_SCREEN_PIPE(pipe))
+ & DARK_SCREEN_CHECK))
+ dev_priv->dark_screen_detected++;
+
+ if (dev_priv->dark_screen_detected == 3) {
+ /*Send Uevent to USER Space*/
+ kobject_uevent_env(&dev_priv->drm.primary->kdev->kobj,
+ KOBJ_CHANGE, dark_screen_envp);
+ } else
+ dev_priv->dark_screen_detected = 0;
+}
+
+
static bool gen11_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
{
switch (pin) {
@@ -1471,7 +1502,6 @@ static void flip_done_handler(struct drm_i915_private *i915,
crtc_state->event = NULL;
drm_crtc_send_vblank_event(&crtc->base, e);
-
spin_unlock_irqrestore(&dev->event_lock, irqflags);
}
@@ -5405,6 +5435,8 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
int i;
INIT_WORK(&dev_priv->l3_parity.error_work, ivb_parity_work);
+ INIT_WORK(&dev_priv->dark_scr.dark_screen_work, darkscreen_work);
+
for (i = 0; i < MAX_L3_SLICES; ++i)
dev_priv->l3_parity.remap_info[i] = NULL;
diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h
index 82639d9d7e8207..59895cb136067b 100644
--- a/drivers/gpu/drm/i915/i915_irq.h
+++ b/drivers/gpu/drm/i915/i915_irq.h
@@ -101,6 +101,9 @@ void gen3_irq_init(struct intel_uncore *uncore,
i915_reg_t ier, u32 ier_val,
i915_reg_t iir);
+
+#define I915_UEVENT_DARK_SCREEN_DETECTED "DARK_SCREEN_DETECTED"
+
#define GEN8_IRQ_RESET_NDX(uncore, type, which) \
({ \
unsigned int which_ = which; \
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 9883e6854c803c..53bcf833809787 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -9552,4 +9552,18 @@ enum skl_power_gate {
/* PXP regs */
#define GEN12_KCR_SIP _MMIO(0x32260) /* KCR hwdrm session in play 0-31 */
+
+/*Dark Screen Detection*/
+#define PIPE_DARKCHECK_A _MMIO(0x60120)
+#define PIPE_DARKCHECK_B _MMIO(0x61120)
+#define PIPE_DARKCHECK_C _MMIO(0x62120)
+#define PIPE_DARKCHECK_D _MMIO(0x63120)
+#define PIPE_DARKCHECK_E _MMIO(0x6B120)
+#define PIPE_DARKCHECK_F _MMIO(0x6C120)
+#define DARK_SCREEN_ENABLE REG_BIT(31)
+#define DARK_SCREEN_CHECK REG_BIT(29)
+#define DARK_SCREE_COMPARE_VALUE(val) (val & 0xffc00000)
+#define DARK_SCREEN_PIPE(pipe) _MMIO(0x60120 + ((pipe <= 3) ? \
+ (4096 * pipe) : (4096 * (pipe + 7))))
+#define DARK_SCREEN_VALUE 1
#endif /* _I915_REG_H_ */
--
2.36.0
More information about the Intel-gfx-trybot
mailing list