From patchwork Thu Dec 15 16:23:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: INTEL_DII: drm/i915/display: Dark Screen Detection From: Nischal Varide X-Patchwork-Id: 515141 Message-Id: <20221215162342.32242-1-nischal.varide@intel.com> To: intel-gfx-trybot@lists.freedesktop.org, nischal.varide@intel.com Date: Thu, 15 Dec 2022 21:53:42 +0530 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 --- .../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_ */