[RFC 1/3] drm/i915/display: Introduce intel_display_guc_metrics

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a generic component part of intel_display that collects
display information that could be used with GuC SLPC for a optimal
frequency selection.

This is also an experimental way to share the code with Xe without
a compact-headers, on an attempt to move towards the full detachment
of the intel_display from the i915.

Cc: Jani Nikula <jani.nikula@xxxxxxxxx>
Cc: Lucas De Marchi <lucas.demarchi@xxxxxxxxx>
Cc: Vinay Belgaumkar <vinay.belgaumkar@xxxxxxxxx>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@xxxxxxxxx>
---
 drivers/gpu/drm/i915/Makefile                 |   1 +
 drivers/gpu/drm/i915/display/intel_display.c  |  14 +-
 .../gpu/drm/i915/display/intel_display_core.h |   2 +
 .../i915/display/intel_display_guc_metrics.c  | 153 ++++++++++++++++++
 .../i915/display/intel_display_guc_metrics.h  |  26 +++
 .../display/intel_display_guc_metrics_types.h |  32 ++++
 .../gpu/drm/i915/display/intel_display_irq.c  |   3 +
 .../drm/i915/display/skl_universal_plane.c    |   3 +
 drivers/gpu/drm/xe/Makefile                   |   1 +
 9 files changed, 234 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/display/intel_display_guc_metrics.c
 create mode 100644 drivers/gpu/drm/i915/display/intel_display_guc_metrics.h
 create mode 100644 drivers/gpu/drm/i915/display/intel_display_guc_metrics_types.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index c13f14edb508..3bd77d61d956 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -262,6 +262,7 @@ i915-y += \
 	display/intel_display.o \
 	display/intel_display_driver.o \
 	display/intel_display_irq.o \
+	display/intel_display_guc_metrics.o \
 	display/intel_display_params.o \
 	display/intel_display_power.o \
 	display/intel_display_power_map.o \
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 7db0655d8c9e..8c659561e729 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -67,6 +67,7 @@
 #include "intel_ddi.h"
 #include "intel_de.h"
 #include "intel_display_driver.h"
+#include "intel_display_guc_metrics.h"
 #include "intel_display_power.h"
 #include "intel_display_types.h"
 #include "intel_dmc.h"
@@ -1020,11 +1021,15 @@ static void intel_post_plane_update(struct intel_atomic_state *state,
 				    struct intel_crtc *crtc)
 {
 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+	struct intel_display *display = &dev_priv->display;
 	const struct intel_crtc_state *old_crtc_state =
 		intel_atomic_get_old_crtc_state(state, crtc);
 	const struct intel_crtc_state *new_crtc_state =
 		intel_atomic_get_new_crtc_state(state, crtc);
 	enum pipe pipe = crtc->pipe;
+	const struct intel_plane_state __maybe_unused *plane_state;
+	struct intel_plane *plane;
+	int i;
 
 	intel_psr_post_plane_update(state, crtc);
 
@@ -1056,6 +1061,10 @@ static void intel_post_plane_update(struct intel_atomic_state *state,
 
 	if (audio_enabling(old_crtc_state, new_crtc_state))
 		intel_encoders_audio_enable(state, crtc);
+
+	for_each_new_intel_plane_in_state(state, plane, plane_state, i)
+		intel_display_guc_metrics_flip(display, new_crtc_state,
+					       plane->id, false);
 }
 
 static void intel_crtc_enable_flip_done(struct intel_atomic_state *state,
@@ -7066,6 +7075,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
 {
 	struct drm_device *dev = state->base.dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct intel_display *display = &dev_priv->display;
 	struct intel_crtc_state *new_crtc_state, *old_crtc_state;
 	struct intel_crtc *crtc;
 	struct intel_power_domain_mask put_domains[I915_MAX_PIPES] = {};
@@ -7112,8 +7122,10 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
 	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
 					    new_crtc_state, i) {
 		if (intel_crtc_needs_modeset(new_crtc_state) ||
-		    intel_crtc_needs_fastset(new_crtc_state))
+		    intel_crtc_needs_fastset(new_crtc_state)) {
 			intel_modeset_get_crtc_power_domains(new_crtc_state, &put_domains[crtc->pipe]);
+			intel_display_guc_metrics_refresh_info(display, new_crtc_state);
+		}
 	}
 
 	intel_commit_modeset_disables(state);
diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h
index fdeaac994e17..58bb0e9d40dc 100644
--- a/drivers/gpu/drm/i915/display/intel_display_core.h
+++ b/drivers/gpu/drm/i915/display/intel_display_core.h
@@ -43,6 +43,7 @@ struct intel_color_funcs;
 struct intel_crtc;
 struct intel_crtc_state;
 struct intel_dmc;
+struct intel_display_guc_metrics;
 struct intel_dpll_funcs;
 struct intel_dpll_mgr;
 struct intel_fbdev;
@@ -529,6 +530,7 @@ struct intel_display {
 	struct intel_fbc *fbc[I915_MAX_FBCS];
 	struct intel_frontbuffer_tracking fb_tracking;
 	struct intel_hotplug hotplug;
+	struct intel_display_guc_metrics *guc_metrics;
 	struct intel_opregion *opregion;
 	struct intel_overlay *overlay;
 	struct intel_display_params params;
diff --git a/drivers/gpu/drm/i915/display/intel_display_guc_metrics.c b/drivers/gpu/drm/i915/display/intel_display_guc_metrics.c
new file mode 100644
index 000000000000..037421e61b90
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_display_guc_metrics.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+
+#include "intel_display_guc_metrics.h"
+#include "intel_display_guc_metrics_types.h"
+
+#include <drm/drm_modes.h>
+
+#include "i915_drv.h"
+#include "intel_de.h"
+#include "intel_display_types.h"
+
+/**
+ * Display GuC Metrics
+ *
+ * GuC SLPC has many optimized strategies to best select the running GT
+ * frequency.
+ * One common strategy is to take display metrics as input through a shared
+ * data buffer. The GuC SLPC will then use these metrics for a optimal balance
+ * between power savings and performance.
+ *
+ * This intel_display_guc_metrics, provides a generic interface where xe_guc_pc
+ * or i915's intel_guc_slpc could register themselves in order to recieve the
+ * metrics from the running intel_display.
+ *
+ * Since this is a generic interface, it won't take any further action, but only
+ * pass the generic display information about refresh_info, flips and vblank.
+ * The GuC SLPC component of the registered driver (Xe or i915) will then be
+ * responsible for allocating the shared display buffer, for collecting the
+ * right timestamp registers of the GT, and for programming the shared buffer
+ * as requested by GuC.
+ *
+ * The Display Shared Data is a block of global GTT memory into which the host
+ * continually writes display related information for SLPC to read and use in
+ * its algorithms.
+ *
+ * The programming flow is as follows.
+ *
+ * The host allocates sufficient memory in the global GTT for the Display
+ * Shared Data.
+ *
+ * The host initializes the Display Shared Data by setting the Version,
+ * Number of Pipes, and Number of Planes per Pipe fields in the Global Info.
+ * All other fields should start at 0.
+ *
+ * The host provides the Display Shared Data memory address in the Shared Data
+ * while (re-)activating SLPC through the GUC_ACTION_HOST2GUC_PCV2_SLPC_REQUEST
+ * Reset event. SLPC will now begin reading the Display Shared Data as part of
+ * its periodic processing. It reads the Global Info section and proceeds to the
+ * other sections only if a change count has been incremented.
+ *
+ * On a display connection to a pipe, the host writes the Refresh Info for the
+ * given pipe, then increments the Refresh Info Change Count field of the Global
+ * Info to alert SLPC to the change. This is also done if an existing display
+ * changes its refresh configuration.
+ *
+ * On a vblank event, the host updates the Vblank Metrics for the given pipe,
+ * then increments the Vblank Metrics Change Count field of the Global Info to
+ * alert SLPC to the change.
+ *
+ * On a flip event, the host updates the Flip Metrics for the given plane on the
+ * given pipe, then increments the Flip Metrics Change Count field of the Global
+ * Info to alert SLPC to the change.
+ */
+
+/**
+ * intel_display_guc_metrics_init - For device driver registration (i915 or xe)
+ * @gfx_device: Back pointer to whatever device is driving display (i915 or xe).
+ * @display: Pointer to the intel_display struct that was initialized by gfx_device.
+ * @guc_metrics: Struct with the callback function pointers to get notication from display.
+ */
+void intel_display_guc_metrics_init(void *gfx_device,
+				    struct intel_display *display,
+				    struct intel_display_guc_metrics *guc_metrics)
+{
+	guc_metrics->gfx_device = gfx_device;
+	display->guc_metrics = guc_metrics;
+}
+
+/**
+ * intel_display_guc_metrics_refresh_info - Refresh rate information
+ * @display: Pointer to the intel_display struct that is in use by the gfx device.
+ * @crtc_state: New CRTC state upon a modeset.
+ *
+ * To be called on a modeset. It gets current refresh interval in micro seconds
+ * and pass back to the gfx device if the refresh_info_update callback is registered.
+ */
+void intel_display_guc_metrics_refresh_info(struct intel_display *display,
+					    struct intel_crtc_state *crtc_state)
+{
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+	struct drm_display_mode *mode = &crtc_state->hw.adjusted_mode;
+	struct intel_display_guc_metrics *guc_metrics = display->guc_metrics;
+	u32 interval_us;
+
+	if (!guc_metrics)
+		return;
+
+	interval_us = crtc_state->hw.active ? DIV_ROUND_UP(1000000,
+						drm_mode_vrefresh(mode)) : 0;
+
+	if (guc_metrics->refresh_info_update)
+		guc_metrics->refresh_info_update(guc_metrics->gfx_device,
+						 crtc->pipe, interval_us,
+						 crtc_state->vrr.enable);
+}
+
+/**
+ * intel_display_guc_metrics_vblank - Vblank information
+ * @display: Pointer to the intel_display struct that is in use by the gfx device.
+ * @crtc: The Intel CRTC that received the vblank interrupt.
+ *
+ * To be called when a vblank is passed. It extracts the pipe from the intel_crtc
+ * and pass back to the gfx device if the vblank_update callback is registered.
+ */
+void intel_display_guc_metrics_vblank(struct intel_display *display,
+				      struct intel_crtc *crtc)
+{
+	struct intel_display_guc_metrics *guc_metrics = display->guc_metrics;
+
+	if (!guc_metrics)
+		return;
+
+	if (guc_metrics->vblank_update)
+		guc_metrics->vblank_update(guc_metrics->gfx_device, crtc->pipe);
+}
+
+/**
+ * intel_display_guc_metrics_flip - Flip information
+ * @display: Pointer to the intel_display struct that is in use by the gfx device.
+ * @crtc_state: New CRTC state upon a page flip.
+ * @plane: Which plane ID got the page flip.
+ * @async_flip: A boolean to indicate if the page flip was async.
+ *
+ * To be called on a page flip. Then it pass the relevant information
+ * to the gfx device if the flip_update callback is registered.
+ */
+void intel_display_guc_metrics_flip(struct intel_display *display,
+				    const struct intel_crtc_state *crtc_state,
+				    int plane, bool async_flip)
+{
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+	struct intel_display_guc_metrics *guc_metrics = display->guc_metrics;
+
+	if (!guc_metrics)
+		return;
+
+	if (guc_metrics->flip_update)
+		guc_metrics->flip_update(guc_metrics->gfx_device,
+					 crtc->pipe, plane, async_flip);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_display_guc_metrics.h b/drivers/gpu/drm/i915/display/intel_display_guc_metrics.h
new file mode 100644
index 000000000000..9a9b8673f2b0
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_display_guc_metrics.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+
+#ifndef __INTEL_DISPLAY_GUC_METRICS_H__
+#define __INTEL_DISPLAY_GUC_METRICS_H__
+
+#include <linux/types.h>
+
+struct intel_crtc;
+struct intel_crtc_state;
+struct intel_display;
+struct intel_display_guc_metrics;
+
+void intel_display_guc_metrics_init(void *gfx_device,
+				    struct intel_display *display,
+				    struct intel_display_guc_metrics *guc_metrics);
+void intel_display_guc_metrics_refresh_info(struct intel_display *display,
+					    struct intel_crtc_state *crtc_state);
+void intel_display_guc_metrics_vblank(struct intel_display *display,
+				      struct intel_crtc *intel_crtc);
+void intel_display_guc_metrics_flip(struct intel_display *display,
+				    const struct intel_crtc_state *crtc_state,
+				    int plane, bool async_flip);
+#endif
diff --git a/drivers/gpu/drm/i915/display/intel_display_guc_metrics_types.h b/drivers/gpu/drm/i915/display/intel_display_guc_metrics_types.h
new file mode 100644
index 000000000000..036cf55d58a0
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_display_guc_metrics_types.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+
+#ifndef __INTEL_DISPLAY_GUC_METRICS_TYPES_H__
+#define __INTEL_DISPLAY_GUC_METRICS_TYPES_H__
+
+/**
+ * struct intel_display_guc_metrics - Intel Display GuC Metrics main struct
+ *
+ * The graphics device can register with intel_display to get information
+ * about display events that will then be used with GuC SLPC.
+ */
+struct intel_display_guc_metrics {
+	/**
+	 * @gfx_device: A pointer to the private device,
+	 * either to struct drm_i915_private or to struct xe_device.
+	 */
+	void *gfx_device;
+
+	/** @refresh_info_update: Callback for getting refresh information on modeset */
+	void (*refresh_info_update)(void *gfx_device, int pipe,
+				    u32 refresh_interval, bool vrr_enabled);
+	/** @vblank_update: Callback for getting vblank information updates */
+	void (*vblank_update)(void *gfx_device, int pipe);
+	/** @flip_update: Callback for getting page flip information updates */
+	void (*flip_update)(void *gfx_device, int pipe, int plane,
+			    bool async_flip);
+};
+
+#endif
diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c
index f846c5b108b5..339bfbbe9314 100644
--- a/drivers/gpu/drm/i915/display/intel_display_irq.c
+++ b/drivers/gpu/drm/i915/display/intel_display_irq.c
@@ -10,6 +10,7 @@
 #include "icl_dsi_regs.h"
 #include "intel_crtc.h"
 #include "intel_de.h"
+#include "intel_display_guc_metrics.h"
 #include "intel_display_irq.h"
 #include "intel_display_trace.h"
 #include "intel_display_types.h"
@@ -25,8 +26,10 @@
 static void
 intel_handle_vblank(struct drm_i915_private *dev_priv, enum pipe pipe)
 {
+	struct intel_display *display = &dev_priv->display;
 	struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
 
+	intel_display_guc_metrics_vblank(display, crtc);
 	drm_crtc_handle_vblank(&crtc->base);
 }
 
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c
index e941e2e4fd14..0e98ec0665b9 100644
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
@@ -12,6 +12,7 @@
 #include "i915_reg.h"
 #include "intel_atomic_plane.h"
 #include "intel_de.h"
+#include "intel_display_guc_metrics.h"
 #include "intel_display_irq.h"
 #include "intel_display_types.h"
 #include "intel_fb.h"
@@ -1392,6 +1393,7 @@ skl_plane_async_flip(struct intel_plane *plane,
 		     bool async_flip)
 {
 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+	struct intel_display *display = &dev_priv->display;
 	enum plane_id plane_id = plane->id;
 	enum pipe pipe = plane->pipe;
 	u32 plane_ctl = plane_state->ctl;
@@ -1404,6 +1406,7 @@ skl_plane_async_flip(struct intel_plane *plane,
 	intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
 	intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id),
 			  skl_plane_surf(plane_state, 0));
+	intel_display_guc_metrics_flip(display, crtc_state, plane_id, async_flip);
 }
 
 static bool intel_format_is_p01x(u32 format)
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index c531210695db..e5b62cfbac8b 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -224,6 +224,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
 	i915-display/intel_display_device.o \
 	i915-display/intel_display_driver.o \
 	i915-display/intel_display_irq.o \
+	i915-display/intel_display_guc_metrics.o \
 	i915-display/intel_display_params.o \
 	i915-display/intel_display_power.o \
 	i915-display/intel_display_power_map.o \
-- 
2.43.2




[Index of Archives]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux