[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