Add functions to enable darkscreen detection and corresponding
additions to Makefile to build them.
The enable and detect functions will be used in case we encounter
a FIFO underrun which will help to check if a darkscreen occurred.

Signed-off-by: Suraj Kandpal <[email protected]>
Signed-off-by: Nemesa Garg <[email protected]>
---
 drivers/gpu/drm/i915/Makefile                 |   1 +
 .../gpu/drm/i915/display/intel_darkscreen.c   | 139 ++++++++++++++++++
 .../gpu/drm/i915/display/intel_darkscreen.h   |  25 ++++
 .../drm/i915/display/intel_display_types.h    |   3 +
 drivers/gpu/drm/xe/Makefile                   |   1 +
 5 files changed, 169 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/display/intel_darkscreen.c
 create mode 100644 drivers/gpu/drm/i915/display/intel_darkscreen.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 7cad944b825c..00e36169a74d 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -255,6 +255,7 @@ i915-y += \
        display/intel_crtc.o \
        display/intel_crtc_state_dump.o \
        display/intel_cursor.o \
+       display/intel_darkscreen.o \
        display/intel_display.o \
        display/intel_display_driver.o \
        display/intel_display_irq.o \
diff --git a/drivers/gpu/drm/i915/display/intel_darkscreen.c 
b/drivers/gpu/drm/i915/display/intel_darkscreen.c
new file mode 100644
index 000000000000..3ac3e8e6c1e3
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_darkscreen.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include "i915_reg.h"
+#include "intel_de.h"
+#include "intel_display_types.h"
+
+#define COLOR_DEPTH_6BPC 6
+#define COLOR_DEPTH_8BPC 8
+#define COLOR_DEPTH_10BPC 10
+#define COLOR_DEPTH_12BPC 12
+
+#define COMPARE_VALUE_6_BPC 4
+#define COMPARE_VALUE_8_BPC 16
+#define COMPARE_VALUE_10_BPC 64
+#define COMPARE_VALUE_12_BPC 256
+
+#define COMPARE_VALUE_CALCULATION_FACTOR 12
+
+static void intel_darkscreen_detect(struct intel_crtc *crtc);
+
+static u32 intel_darkscreen_get_comp_val(struct drm_i915_private *i915, int 
bpc)
+{
+       u32 compare_value = 0;
+
+       switch (bpc) {
+       case COLOR_DEPTH_6BPC:
+               compare_value = COMPARE_VALUE_6_BPC;
+               break;
+       case COLOR_DEPTH_8BPC:
+               compare_value = COMPARE_VALUE_8_BPC;
+               break;
+       case COLOR_DEPTH_10BPC:
+               compare_value = COMPARE_VALUE_10_BPC;
+               break;
+       case COLOR_DEPTH_12BPC:
+               compare_value = COMPARE_VALUE_12_BPC;
+               break;
+       default:
+               drm_dbg(&i915->drm, "Bpc value is incorrect:%d\n", bpc);
+               return -EINVAL;
+       }
+
+       compare_value = compare_value << (COMPARE_VALUE_CALCULATION_FACTOR - 
bpc);
+       return DARK_SCREEN_COMPARE_VAL(compare_value);
+}
+
+static void intel_darkscreen_work_fn(struct work_struct *work)
+{
+       struct intel_darkscreen *dark_screen =
+               container_of(work, typeof(*dark_screen), 
darkscreen_detect_work);
+
+       if (!dark_screen->enable)
+               intel_darkscreen_enable(dark_screen->crtc);
+
+       intel_darkscreen_detect(dark_screen->crtc);
+}
+
+void intel_darkscreen_schedule_work(struct intel_crtc *crtc)
+{
+       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+       struct intel_darkscreen *dark_screen = &crtc->dark_screen;
+
+       dark_screen->crtc = crtc;
+       queue_work(i915->unordered_wq, &dark_screen->darkscreen_detect_work);
+}
+
+void intel_darkscreen_setup(struct intel_crtc *crtc)
+{
+       struct intel_darkscreen *dark_screen;
+
+       dark_screen = &crtc->dark_screen;
+       dark_screen = kzalloc(sizeof(*dark_screen), GFP_KERNEL);
+       if (!dark_screen)
+               return;
+       dark_screen->enable = false;
+
+       INIT_WORK(&dark_screen->darkscreen_detect_work, 
intel_darkscreen_work_fn);
+}
+
+/*
+ * Check the color format and compute the compare value based on bpc.
+ */
+int intel_darkscreen_enable(struct intel_crtc *crtc)
+{
+       struct intel_crtc_state *crtc_state = crtc->config;
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       int bpc = crtc_state->pipe_bpp / 3;
+       u32 val;
+
+       if (!crtc->dark_screen.enable)
+               return 0;
+
+       if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "YUV format not supported:%c for darkscreen 
detection\n",
+                           pipe_name(crtc->pipe));
+               return -EPROTO;
+       }
+
+       val = intel_darkscreen_get_comp_val(dev_priv, bpc);
+       val |= DARK_SCREEN_ENABLE;
+       intel_de_write(dev_priv, DARK_SCREEN(cpu_transcoder), val);
+       crtc->dark_screen.enable = true;
+
+       return 0;
+}
+
+static void intel_darkscreen_detect(struct intel_crtc *crtc)
+{
+       struct intel_crtc_state *crtc_state = crtc->config;
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       unsigned int frame_time_in_us;
+       u32 val = 0;
+
+       val |= DARK_SCREEN_DETECT | DARK_SCREEN_DONE;
+       intel_de_rmw(dev_priv, DARK_SCREEN(crtc->config->cpu_transcoder), 0, 
val);
+
+       frame_time_in_us = (1000 / 
drm_mode_vrefresh(&crtc_state->hw.adjusted_mode)) * 2;
+       intel_de_wait_for_set(dev_priv, 
DARK_SCREEN(crtc->config->cpu_transcoder),
+                             DARK_SCREEN_DONE, frame_time_in_us);
+
+       if (intel_de_read(dev_priv, DARK_SCREEN(crtc->config->cpu_transcoder)) &
+           DARK_SCREEN_DETECT) {
+               drm_dbg_kms(&dev_priv->drm, "Dark screen detected:%c\n", 
pipe_name(crtc->pipe));
+       }
+}
+
+void intel_darkscreen_disable(struct intel_crtc *crtc)
+{
+       struct intel_crtc_state *crtc_state = crtc->config;
+       enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+
+       intel_de_write(dev_priv, DARK_SCREEN(cpu_transcoder), 0);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_darkscreen.h 
b/drivers/gpu/drm/i915/display/intel_darkscreen.h
new file mode 100644
index 000000000000..3b4b3d3df672
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_darkscreen.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __INTEL_DARKSCREEN_H__
+#define __INTEL_DARKSCREEN_H__
+
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+struct intel_crtc;
+
+struct intel_darkscreen {
+       bool enable;
+       struct work_struct darkscreen_detect_work;
+       struct intel_crtc *crtc;
+};
+
+void intel_darkscreen_setup(struct intel_crtc *crtc);
+int intel_darkscreen_enable(struct intel_crtc *crtc);
+void intel_darkscreen_disable(struct intel_crtc *crtc);
+void intel_darkscreen_schedule_work(struct intel_crtc *crtc);
+
+#endif /* __INTEL_DARKSCREEN_H_ */
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index 62f7a30c37dc..177cf5ff8d77 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -50,6 +50,7 @@
 #include "i915_vma.h"
 #include "i915_vma_types.h"
 #include "intel_bios.h"
+#include "intel_darkscreen.h"
 #include "intel_display.h"
 #include "intel_display_limits.h"
 #include "intel_display_power.h"
@@ -1511,6 +1512,8 @@ struct intel_crtc {
        /* for loading single buffered registers during vblank */
        struct pm_qos_request vblank_pm_qos;
 
+       struct intel_darkscreen dark_screen;
+
 #ifdef CONFIG_DEBUG_FS
        struct intel_pipe_crc pipe_crc;
 #endif
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 8321ec4f9b46..c83217e20cb9 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -228,6 +228,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
        i915-display/intel_crtc_state_dump.o \
        i915-display/intel_cursor.o \
        i915-display/intel_cx0_phy.o \
+       i915-display/intel_darkscreen.o \
        i915-display/intel_ddi.o \
        i915-display/intel_ddi_buf_trans.o \
        i915-display/intel_display.o \
-- 
2.43.2

Reply via email to