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