[RFC 2/3] drm/i915/darkscreen: Enable darkscreen detection
Suraj Kandpal
suraj.kandpal at intel.com
Wed Apr 24 07:38:18 UTC 2024
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 <suraj.kandpal at intel.com>
Signed-off-by: Nemesa Garg <nemesa.garg at intel.com>
---
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
More information about the Intel-gfx
mailing list