From 820e067b94729f4b93a01555a3d7d775510021aa Mon Sep 17 00:00:00 2001 From: Matt Atwood Date: Wed, 3 Sep 2025 10:08:21 -0700 Subject: drm/i915/display: Use DISPLAY_VER over GRAPHICS_VER The checks in plane_has_modifier() should check against display version instead of graphics version. Bspec: 67165, 70815 Signed-off-by: Matt Atwood Reviewed-by: Juha-Pekka Heikkila Link: https://lore.kernel.org/r/20250903170821.310143-1-matthew.s.atwood@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/i915/display/intel_fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 22a4a1575d22..69237dabdae8 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -564,11 +564,11 @@ static bool plane_has_modifier(struct intel_display *display, return false; if (md->modifier == I915_FORMAT_MOD_4_TILED_BMG_CCS && - (GRAPHICS_VER(i915) < 20 || !display->platform.dgfx)) + (DISPLAY_VER(display) < 14 || !display->platform.dgfx)) return false; if (md->modifier == I915_FORMAT_MOD_4_TILED_LNL_CCS && - (GRAPHICS_VER(i915) < 20 || display->platform.dgfx)) + (DISPLAY_VER(display) < 20 || display->platform.dgfx)) return false; return true; -- cgit v1.2.3 From c8cf6e3cc27c52cfe42d246e96f6e83266b9a0db Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:40 +0300 Subject: drm/i915: do cck get/put inside vlv_get_hpll_vco() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move towards VLV/CHV clock interfaces that handle sideband get/put inside them instead of at the caller. We'll need to move the calls outside of existing get/put. Suggested-by: Ville Syrjälä Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/1a6553f54619275aa05512421e19115a71cd3eb0.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 3 ++- drivers/gpu/drm/i915/display/intel_display.c | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 9725eebe5706..c54c7fd93f97 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -608,9 +608,10 @@ static void vlv_get_cdclk(struct intel_display *display, { u32 val; + cdclk_config->vco = vlv_get_hpll_vco(display->drm); + vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_CCK) | BIT(VLV_IOSF_SB_PUNIT)); - cdclk_config->vco = vlv_get_hpll_vco(display->drm); cdclk_config->cdclk = vlv_get_cck_clock(display->drm, "cdclk", CCK_DISPLAY_CLOCK_CONTROL, cdclk_config->vco); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 5dca7f96b425..f5208583235d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -146,10 +146,14 @@ int vlv_get_hpll_vco(struct drm_device *drm) { int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; + vlv_cck_get(drm); + /* Obtain SKU information */ hpll_freq = vlv_cck_read(drm, CCK_FUSE_REG) & CCK_FUSE_HPLL_FREQ_MASK; + vlv_cck_put(drm); + return vco_freq[hpll_freq] * 1000; } @@ -175,11 +179,11 @@ int vlv_get_cck_clock_hpll(struct drm_device *drm, struct drm_i915_private *dev_priv = to_i915(drm); int hpll; - vlv_cck_get(drm); - if (dev_priv->hpll_freq == 0) dev_priv->hpll_freq = vlv_get_hpll_vco(drm); + vlv_cck_get(drm); + hpll = vlv_get_cck_clock(drm, name, reg, dev_priv->hpll_freq); vlv_cck_put(drm); -- cgit v1.2.3 From 7d112811787f03030f301975af4079a1efe7cdcc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:41 +0300 Subject: drm/i915: do cck get/put inside vlv_get_cck_clock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move towards VLV/CHV clock interfaces that handle sideband get/put inside them instead of at the caller. With this, we can switch to the simpler vlv_punit_get()/vlv_punit_put() in vlv_get_cdclk(). We'll need to move vlv_init_gpll_ref_freq() outside of the existing get/put in vlv_rps_init() and chv_rps_init(). Suggested-by: Ville Syrjälä Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/480b654b6c736a03343dfd17eb130c39fd82c637.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 8 ++------ drivers/gpu/drm/i915/display/intel_display.c | 7 +++---- drivers/gpu/drm/i915/gt/intel_rps.c | 8 ++++---- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index c54c7fd93f97..bf4e975ac41c 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -609,17 +609,13 @@ static void vlv_get_cdclk(struct intel_display *display, u32 val; cdclk_config->vco = vlv_get_hpll_vco(display->drm); - - vlv_iosf_sb_get(display->drm, BIT(VLV_IOSF_SB_CCK) | BIT(VLV_IOSF_SB_PUNIT)); - cdclk_config->cdclk = vlv_get_cck_clock(display->drm, "cdclk", CCK_DISPLAY_CLOCK_CONTROL, cdclk_config->vco); + vlv_punit_get(display->drm); val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); - - vlv_iosf_sb_put(display->drm, - BIT(VLV_IOSF_SB_CCK) | BIT(VLV_IOSF_SB_PUNIT)); + vlv_punit_put(display->drm); if (display->platform.valleyview) cdclk_config->voltage_level = (val & DSPFREQGUAR_MASK) >> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index f5208583235d..aef136a1be25 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -163,7 +163,10 @@ int vlv_get_cck_clock(struct drm_device *drm, u32 val; int divider; + vlv_cck_get(drm); val = vlv_cck_read(drm, reg); + vlv_cck_put(drm); + divider = val & CCK_FREQUENCY_VALUES; drm_WARN(drm, (val & CCK_FREQUENCY_STATUS) != @@ -182,12 +185,8 @@ int vlv_get_cck_clock_hpll(struct drm_device *drm, if (dev_priv->hpll_freq == 0) dev_priv->hpll_freq = vlv_get_hpll_vco(drm); - vlv_cck_get(drm); - hpll = vlv_get_cck_clock(drm, name, reg, dev_priv->hpll_freq); - vlv_cck_put(drm); - return hpll; } diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 4da94098bd3e..afc934b7f5bc 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -1703,13 +1703,13 @@ static void vlv_rps_init(struct intel_rps *rps) { struct drm_i915_private *i915 = rps_to_i915(rps); + vlv_init_gpll_ref_freq(rps); + vlv_iosf_sb_get(&i915->drm, BIT(VLV_IOSF_SB_PUNIT) | BIT(VLV_IOSF_SB_NC) | BIT(VLV_IOSF_SB_CCK)); - vlv_init_gpll_ref_freq(rps); - rps->max_freq = vlv_rps_max_freq(rps); rps->rp0_freq = rps->max_freq; drm_dbg(&i915->drm, "max GPU freq: %d MHz (%u)\n", @@ -1737,13 +1737,13 @@ static void chv_rps_init(struct intel_rps *rps) { struct drm_i915_private *i915 = rps_to_i915(rps); + vlv_init_gpll_ref_freq(rps); + vlv_iosf_sb_get(&i915->drm, BIT(VLV_IOSF_SB_PUNIT) | BIT(VLV_IOSF_SB_NC) | BIT(VLV_IOSF_SB_CCK)); - vlv_init_gpll_ref_freq(rps); - rps->max_freq = chv_rps_max_freq(rps); rps->rp0_freq = rps->max_freq; drm_dbg(&i915->drm, "max GPU freq: %d MHz (%u)\n", -- cgit v1.2.3 From 01c46fcef51f980219cfcd4ee8b3f2688ffcf509 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:42 +0300 Subject: drm/i915: add vlv_clock_get_gpll() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a vlv_clock_get_gpll() helper to hide the details from the callers. Reviewed-by: Mika Kahola Reviewed-by: Michał Grzelak Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/2589396fa14388d7709d2b01f1d32f9f38dab11a.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 8 ++++++++ drivers/gpu/drm/i915/display/intel_display.h | 1 + drivers/gpu/drm/i915/gt/intel_rps.c | 5 +---- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index aef136a1be25..4599c2f37682 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -190,6 +190,14 @@ int vlv_get_cck_clock_hpll(struct drm_device *drm, return hpll; } +int vlv_clock_get_gpll(struct drm_device *drm) +{ + struct drm_i915_private *i915 = to_i915(drm); + + return vlv_get_cck_clock(drm, "GPLL ref", CCK_GPLL_CLOCK_CONTROL, + i915->czclk_freq); +} + void intel_update_czclk(struct intel_display *display) { struct drm_i915_private *dev_priv = to_i915(display->drm); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 37e2ab301a80..7ae899b8787a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -440,6 +440,7 @@ int vlv_get_cck_clock(struct drm_device *drm, const char *name, u32 reg, int ref_freq); int vlv_get_cck_clock_hpll(struct drm_device *drm, const char *name, u32 reg); +int vlv_clock_get_gpll(struct drm_device *drm); bool intel_has_pending_fb_unpin(struct intel_display *display); void intel_encoder_destroy(struct drm_encoder *encoder); struct drm_display_mode * diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index afc934b7f5bc..f19353f04228 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -1690,10 +1690,7 @@ static void vlv_init_gpll_ref_freq(struct intel_rps *rps) { struct drm_i915_private *i915 = rps_to_i915(rps); - rps->gpll_ref_freq = - vlv_get_cck_clock(&i915->drm, "GPLL ref", - CCK_GPLL_CLOCK_CONTROL, - i915->czclk_freq); + rps->gpll_ref_freq = vlv_clock_get_gpll(&i915->drm); drm_dbg(&i915->drm, "GPLL reference freq: %d kHz\n", rps->gpll_ref_freq); -- cgit v1.2.3 From 8c2833ff1df3e2e39a513b756cc06f2fd43d6a02 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:43 +0300 Subject: drm/i915: add vlv_clock_get_czclk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add vlv_clock_get_czclk() helper to avoid looking at i915->czclk_freq directly. Reviewed-by: Mika Kahola Reviewed-by: Michał Grzelak Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/4885f6e486a31c773a3bfebd6936670234e57bd0.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 3 +-- drivers/gpu/drm/i915/display/intel_display.c | 20 ++++++++++++++------ drivers/gpu/drm/i915/display/intel_display.h | 1 + drivers/gpu/drm/i915/gt/intel_rc6.c | 3 ++- drivers/gpu/drm/i915/gt/intel_rps.c | 3 ++- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index bf4e975ac41c..3025951eac28 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -627,7 +627,6 @@ static void vlv_get_cdclk(struct intel_display *display, static void vlv_program_pfi_credits(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(display->drm); unsigned int credits, default_credits; if (display->platform.cherryview) @@ -635,7 +634,7 @@ static void vlv_program_pfi_credits(struct intel_display *display) else default_credits = PFI_CREDIT(8); - if (display->cdclk.hw.cdclk >= dev_priv->czclk_freq) { + if (display->cdclk.hw.cdclk >= vlv_clock_get_czclk(display->drm)) { /* CHV suggested value is 31 or 63 */ if (display->platform.cherryview) credits = PFI_CREDIT_63; diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 4599c2f37682..eca9f2508e9d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -190,25 +190,33 @@ int vlv_get_cck_clock_hpll(struct drm_device *drm, return hpll; } -int vlv_clock_get_gpll(struct drm_device *drm) +int vlv_clock_get_czclk(struct drm_device *drm) { struct drm_i915_private *i915 = to_i915(drm); + if (!i915->czclk_freq) + i915->czclk_freq = vlv_get_cck_clock_hpll(drm, "czclk", + CCK_CZ_CLOCK_CONTROL); + + return i915->czclk_freq; +} + +int vlv_clock_get_gpll(struct drm_device *drm) +{ return vlv_get_cck_clock(drm, "GPLL ref", CCK_GPLL_CLOCK_CONTROL, - i915->czclk_freq); + vlv_clock_get_czclk(drm)); } void intel_update_czclk(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(display->drm); + int czclk_freq; if (!display->platform.valleyview && !display->platform.cherryview) return; - dev_priv->czclk_freq = vlv_get_cck_clock_hpll(display->drm, "czclk", - CCK_CZ_CLOCK_CONTROL); + czclk_freq = vlv_clock_get_czclk(display->drm); - drm_dbg_kms(display->drm, "CZ clock rate: %d kHz\n", dev_priv->czclk_freq); + drm_dbg_kms(display->drm, "CZ clock rate: %d kHz\n", czclk_freq); } static bool is_hdr_mode(const struct intel_crtc_state *crtc_state) diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 7ae899b8787a..811066a9e69d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -440,6 +440,7 @@ int vlv_get_cck_clock(struct drm_device *drm, const char *name, u32 reg, int ref_freq); int vlv_get_cck_clock_hpll(struct drm_device *drm, const char *name, u32 reg); +int vlv_clock_get_czclk(struct drm_device *drm); int vlv_clock_get_gpll(struct drm_device *drm); bool intel_has_pending_fb_unpin(struct intel_display *display); void intel_encoder_destroy(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c index bf38cc5fe872..ef8b2fd2ae69 100644 --- a/drivers/gpu/drm/i915/gt/intel_rc6.c +++ b/drivers/gpu/drm/i915/gt/intel_rc6.c @@ -6,6 +6,7 @@ #include #include +#include "display/intel_display.h" #include "gem/i915_gem_region.h" #include "i915_drv.h" #include "i915_reg.h" @@ -802,7 +803,7 @@ u64 intel_rc6_residency_ns(struct intel_rc6 *rc6, enum intel_rc6_res_type id) /* On VLV and CHV, residency time is in CZ units rather than 1.28us */ if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { mul = 1000000; - div = i915->czclk_freq; + div = vlv_clock_get_czclk(&i915->drm); overflow_hw = BIT_ULL(40); time_hw = vlv_residency_raw(uncore, reg); } else { diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index f19353f04228..db9cfd2b2b89 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -1777,6 +1777,7 @@ static void vlv_c0_read(struct intel_uncore *uncore, struct intel_rps_ei *ei) static u32 vlv_wa_c0_ei(struct intel_rps *rps, u32 pm_iir) { + struct drm_i915_private *i915 = rps_to_i915(rps); struct intel_uncore *uncore = rps_to_uncore(rps); const struct intel_rps_ei *prev = &rps->ei; struct intel_rps_ei now; @@ -1793,7 +1794,7 @@ static u32 vlv_wa_c0_ei(struct intel_rps *rps, u32 pm_iir) time = ktime_us_delta(now.ktime, prev->ktime); - time *= rps_to_i915(rps)->czclk_freq; + time *= vlv_clock_get_czclk(&i915->drm); /* Workload can be split between render + media, * e.g. SwapBuffers being blitted in X after being rendered in -- cgit v1.2.3 From 9c2f7992551f4addd4a6343d9b58b39ad014e6dc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:44 +0300 Subject: drm/i915: add vlv_clock_get_hrawclk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add vlv_clock_get_hrawclk() helper to hide the details from the callers. Reviewed-by: Michał Grzelak Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/ad3c3d0baf16eb0ef3a0ac3edfbab327c564e743.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 9 +-------- drivers/gpu/drm/i915/display/intel_display.c | 6 ++++++ drivers/gpu/drm/i915/display/intel_display.h | 1 + 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 3025951eac28..45ac378922ff 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -3561,13 +3561,6 @@ static int pch_rawclk(struct intel_display *display) return (intel_de_read(display, PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK) * 1000; } -static int vlv_hrawclk(struct intel_display *display) -{ - /* RAWCLK_FREQ_VLV register updated from power well code */ - return vlv_get_cck_clock_hpll(display->drm, "hrawclk", - CCK_DISPLAY_REF_CLOCK_CONTROL); -} - static int i9xx_hrawclk(struct intel_display *display) { struct drm_i915_private *i915 = to_i915(display->drm); @@ -3601,7 +3594,7 @@ u32 intel_read_rawclk(struct intel_display *display) else if (HAS_PCH_SPLIT(display)) freq = pch_rawclk(display); else if (display->platform.valleyview || display->platform.cherryview) - freq = vlv_hrawclk(display); + freq = vlv_clock_get_hrawclk(display->drm); else if (DISPLAY_VER(display) >= 3) freq = i9xx_hrawclk(display); else diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index eca9f2508e9d..487870811d3a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -190,6 +190,12 @@ int vlv_get_cck_clock_hpll(struct drm_device *drm, return hpll; } +int vlv_clock_get_hrawclk(struct drm_device *drm) +{ + /* RAWCLK_FREQ_VLV register updated from power well code */ + return vlv_get_cck_clock_hpll(drm, "hrawclk", CCK_DISPLAY_REF_CLOCK_CONTROL); +} + int vlv_clock_get_czclk(struct drm_device *drm) { struct drm_i915_private *i915 = to_i915(drm); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 811066a9e69d..dbfb4b4aee4e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -440,6 +440,7 @@ int vlv_get_cck_clock(struct drm_device *drm, const char *name, u32 reg, int ref_freq); int vlv_get_cck_clock_hpll(struct drm_device *drm, const char *name, u32 reg); +int vlv_clock_get_hrawclk(struct drm_device *drm); int vlv_clock_get_czclk(struct drm_device *drm); int vlv_clock_get_gpll(struct drm_device *drm); bool intel_has_pending_fb_unpin(struct intel_display *display); -- cgit v1.2.3 From ffbc0de5d3bca69700196fe090d45002c72f881e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:45 +0300 Subject: drm/i915: make vlv_get_cck_clock_hpll() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vlv_get_cck_clock_hpll() is no longer used outside of intel_display.c, make it static. Reviewed-by: Michał Grzelak Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/0a778d82e2be112b0cd37cd3329103a764967a1d.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 4 ++-- drivers/gpu/drm/i915/display/intel_display.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 487870811d3a..9ba6f439205a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -176,8 +176,8 @@ int vlv_get_cck_clock(struct drm_device *drm, return DIV_ROUND_CLOSEST(ref_freq << 1, divider + 1); } -int vlv_get_cck_clock_hpll(struct drm_device *drm, - const char *name, u32 reg) +static int vlv_get_cck_clock_hpll(struct drm_device *drm, + const char *name, u32 reg) { struct drm_i915_private *dev_priv = to_i915(drm); int hpll; diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index dbfb4b4aee4e..5c9b57e94a65 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -438,8 +438,6 @@ void i830_disable_pipe(struct intel_display *display, enum pipe pipe); int vlv_get_hpll_vco(struct drm_device *drm); int vlv_get_cck_clock(struct drm_device *drm, const char *name, u32 reg, int ref_freq); -int vlv_get_cck_clock_hpll(struct drm_device *drm, - const char *name, u32 reg); int vlv_clock_get_hrawclk(struct drm_device *drm); int vlv_clock_get_czclk(struct drm_device *drm); int vlv_clock_get_gpll(struct drm_device *drm); -- cgit v1.2.3 From d451c5bff573681a277e2b77678c38441c8ec285 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:46 +0300 Subject: drm/i915: add vlv_clock_get_cdclk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add vlv_clock_get_cdclk() helper to hide the details from the callers. For now, this means running vlv_get_hpll_vco() twice in vlv_get_cdclk(), but this will be improved later. v2: Rebase Reviewed-by: Michał Grzelak Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/fc93ccf998300048432d18ce7e8690bd54e1e18d.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 4 +--- drivers/gpu/drm/i915/display/intel_display.c | 6 ++++++ drivers/gpu/drm/i915/display/intel_display.h | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 45ac378922ff..6ea44bec4da5 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -609,9 +609,7 @@ static void vlv_get_cdclk(struct intel_display *display, u32 val; cdclk_config->vco = vlv_get_hpll_vco(display->drm); - cdclk_config->cdclk = vlv_get_cck_clock(display->drm, "cdclk", - CCK_DISPLAY_CLOCK_CONTROL, - cdclk_config->vco); + cdclk_config->cdclk = vlv_clock_get_cdclk(display->drm); vlv_punit_get(display->drm); val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9ba6f439205a..4a19a3ce060c 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -207,6 +207,12 @@ int vlv_clock_get_czclk(struct drm_device *drm) return i915->czclk_freq; } +int vlv_clock_get_cdclk(struct drm_device *drm) +{ + return vlv_get_cck_clock(drm, "cdclk", CCK_DISPLAY_CLOCK_CONTROL, + vlv_get_hpll_vco(drm)); +} + int vlv_clock_get_gpll(struct drm_device *drm) { return vlv_get_cck_clock(drm, "GPLL ref", CCK_GPLL_CLOCK_CONTROL, diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 5c9b57e94a65..9fdbc4ad5391 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -440,6 +440,7 @@ int vlv_get_cck_clock(struct drm_device *drm, const char *name, u32 reg, int ref_freq); int vlv_clock_get_hrawclk(struct drm_device *drm); int vlv_clock_get_czclk(struct drm_device *drm); +int vlv_clock_get_cdclk(struct drm_device *drm); int vlv_clock_get_gpll(struct drm_device *drm); bool intel_has_pending_fb_unpin(struct intel_display *display); void intel_encoder_destroy(struct drm_encoder *encoder); -- cgit v1.2.3 From a6767dbba64cbe200e620ba72f1bc96a0a06fbc8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:47 +0300 Subject: drm/i915: make vlv_get_cck_clock() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vlv_get_cck_clock() is no longer used outside of intel_display.c, make it static. Reviewed-by: Michał Grzelak Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/bac1fe98d9d458ef30e973f680342b69a6cde4d6.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 4 ++-- drivers/gpu/drm/i915/display/intel_display.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 4a19a3ce060c..462771435c4b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -157,8 +157,8 @@ int vlv_get_hpll_vco(struct drm_device *drm) return vco_freq[hpll_freq] * 1000; } -int vlv_get_cck_clock(struct drm_device *drm, - const char *name, u32 reg, int ref_freq) +static int vlv_get_cck_clock(struct drm_device *drm, + const char *name, u32 reg, int ref_freq) { u32 val; int divider; diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 9fdbc4ad5391..57b06cad314b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -436,8 +436,6 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state); void i830_enable_pipe(struct intel_display *display, enum pipe pipe); void i830_disable_pipe(struct intel_display *display, enum pipe pipe); int vlv_get_hpll_vco(struct drm_device *drm); -int vlv_get_cck_clock(struct drm_device *drm, - const char *name, u32 reg, int ref_freq); int vlv_clock_get_hrawclk(struct drm_device *drm); int vlv_clock_get_czclk(struct drm_device *drm); int vlv_clock_get_cdclk(struct drm_device *drm); -- cgit v1.2.3 From f6b784c44aa3a843596bb3143f6a9da025413d09 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:48 +0300 Subject: drm/i915: rename vlv_get_hpll_vco() to vlv_clock_get_hpll_vco() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the new vlv_clock_*() naming pattern for all the related VLV clock functions. v2: Rebase Reviewed-by: Michał Grzelak Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/75ac6b1cda2cb0afe3171250c4d5ba1ff81df877.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 6 +++--- drivers/gpu/drm/i915/display/intel_display.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 6ea44bec4da5..ea1e6d964764 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -608,7 +608,7 @@ static void vlv_get_cdclk(struct intel_display *display, { u32 val; - cdclk_config->vco = vlv_get_hpll_vco(display->drm); + cdclk_config->vco = vlv_clock_get_hpll_vco(display->drm); cdclk_config->cdclk = vlv_clock_get_cdclk(display->drm); vlv_punit_get(display->drm); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 462771435c4b..022f32ffd697 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -142,7 +142,7 @@ static void bdw_set_pipe_misc(struct intel_dsb *dsb, const struct intel_crtc_state *crtc_state); /* returns HPLL frequency in kHz */ -int vlv_get_hpll_vco(struct drm_device *drm) +int vlv_clock_get_hpll_vco(struct drm_device *drm) { int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; @@ -183,7 +183,7 @@ static int vlv_get_cck_clock_hpll(struct drm_device *drm, int hpll; if (dev_priv->hpll_freq == 0) - dev_priv->hpll_freq = vlv_get_hpll_vco(drm); + dev_priv->hpll_freq = vlv_clock_get_hpll_vco(drm); hpll = vlv_get_cck_clock(drm, name, reg, dev_priv->hpll_freq); @@ -210,7 +210,7 @@ int vlv_clock_get_czclk(struct drm_device *drm) int vlv_clock_get_cdclk(struct drm_device *drm) { return vlv_get_cck_clock(drm, "cdclk", CCK_DISPLAY_CLOCK_CONTROL, - vlv_get_hpll_vco(drm)); + vlv_clock_get_hpll_vco(drm)); } int vlv_clock_get_gpll(struct drm_device *drm) diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 57b06cad314b..5c406b276a76 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -435,7 +435,7 @@ void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state); void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state); void i830_enable_pipe(struct intel_display *display, enum pipe pipe); void i830_disable_pipe(struct intel_display *display, enum pipe pipe); -int vlv_get_hpll_vco(struct drm_device *drm); +int vlv_clock_get_hpll_vco(struct drm_device *drm); int vlv_clock_get_hrawclk(struct drm_device *drm); int vlv_clock_get_czclk(struct drm_device *drm); int vlv_clock_get_cdclk(struct drm_device *drm); -- cgit v1.2.3 From a6e8325b862cf7db005b565424c59e277ac55539 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:49 +0300 Subject: drm/i915: cache the results in vlv_clock_get_hpll_vco() and use it more MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use vlv_clock_get_hpll_vco() helper more to avoid looking at i915->hpll_freq directly. Cache and return the cached results to avoid repeated lookups. v2: Rebase Reviewed-by: Michał Grzelak # v1 Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/14695618682d8d8fad1adc485de7a122c8e1494a.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 10 +++------- drivers/gpu/drm/i915/display/intel_display.c | 27 +++++++++++---------------- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index ea1e6d964764..e77efa0f33ed 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -563,8 +563,7 @@ static void hsw_get_cdclk(struct intel_display *display, static int vlv_calc_cdclk(struct intel_display *display, int min_cdclk) { - struct drm_i915_private *dev_priv = to_i915(display->drm); - int freq_320 = (dev_priv->hpll_freq << 1) % 320000 != 0 ? + int freq_320 = (vlv_clock_get_hpll_vco(display->drm) << 1) % 320000 != 0 ? 333333 : 320000; /* @@ -584,8 +583,6 @@ static int vlv_calc_cdclk(struct intel_display *display, int min_cdclk) static u8 vlv_calc_voltage_level(struct intel_display *display, int cdclk) { - struct drm_i915_private *dev_priv = to_i915(display->drm); - if (display->platform.valleyview) { if (cdclk >= 320000) /* jump to highest voltage for 400MHz too */ return 2; @@ -599,7 +596,7 @@ static u8 vlv_calc_voltage_level(struct intel_display *display, int cdclk) * hardware has shown that we just need to write the desired * CCK divider into the Punit register. */ - return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, cdclk) - 1; + return DIV_ROUND_CLOSEST(vlv_clock_get_hpll_vco(display->drm) << 1, cdclk) - 1; } } @@ -664,7 +661,6 @@ static void vlv_set_cdclk(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { - struct drm_i915_private *dev_priv = to_i915(display->drm); int cdclk = cdclk_config->cdclk; u32 val, cmd = cdclk_config->voltage_level; intel_wakeref_t wakeref; @@ -709,7 +705,7 @@ static void vlv_set_cdclk(struct intel_display *display, if (cdclk == 400000) { u32 divider; - divider = DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, + divider = DIV_ROUND_CLOSEST(vlv_clock_get_hpll_vco(display->drm) << 1, cdclk) - 1; /* adjust cdclk divider */ diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 022f32ffd697..7b5379262a37 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -144,17 +144,20 @@ static void bdw_set_pipe_misc(struct intel_dsb *dsb, /* returns HPLL frequency in kHz */ int vlv_clock_get_hpll_vco(struct drm_device *drm) { + struct drm_i915_private *i915 = to_i915(drm); int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; - vlv_cck_get(drm); - - /* Obtain SKU information */ - hpll_freq = vlv_cck_read(drm, CCK_FUSE_REG) & - CCK_FUSE_HPLL_FREQ_MASK; + if (!i915->hpll_freq) { + vlv_cck_get(drm); + /* Obtain SKU information */ + hpll_freq = vlv_cck_read(drm, CCK_FUSE_REG) & + CCK_FUSE_HPLL_FREQ_MASK; + vlv_cck_put(drm); - vlv_cck_put(drm); + i915->hpll_freq = vco_freq[hpll_freq] * 1000; + } - return vco_freq[hpll_freq] * 1000; + return i915->hpll_freq; } static int vlv_get_cck_clock(struct drm_device *drm, @@ -179,15 +182,7 @@ static int vlv_get_cck_clock(struct drm_device *drm, static int vlv_get_cck_clock_hpll(struct drm_device *drm, const char *name, u32 reg) { - struct drm_i915_private *dev_priv = to_i915(drm); - int hpll; - - if (dev_priv->hpll_freq == 0) - dev_priv->hpll_freq = vlv_clock_get_hpll_vco(drm); - - hpll = vlv_get_cck_clock(drm, name, reg, dev_priv->hpll_freq); - - return hpll; + return vlv_get_cck_clock(drm, name, reg, vlv_clock_get_hpll_vco(drm)); } int vlv_clock_get_hrawclk(struct drm_device *drm) -- cgit v1.2.3 From 73383c3062e895125abe76fa3cbb8febc2deb73b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:50 +0300 Subject: drm/i915: remove vlv_get_cck_clock_hpll() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function has become so trivial it's no longer necessary. Inline it at the call sites. Reviewed-by: Michał Grzelak # v1 Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/1e5ef7a14cdf42048a03719cff380fee6c3016e0.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 7b5379262a37..8f200593053e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -179,16 +179,11 @@ static int vlv_get_cck_clock(struct drm_device *drm, return DIV_ROUND_CLOSEST(ref_freq << 1, divider + 1); } -static int vlv_get_cck_clock_hpll(struct drm_device *drm, - const char *name, u32 reg) -{ - return vlv_get_cck_clock(drm, name, reg, vlv_clock_get_hpll_vco(drm)); -} - int vlv_clock_get_hrawclk(struct drm_device *drm) { /* RAWCLK_FREQ_VLV register updated from power well code */ - return vlv_get_cck_clock_hpll(drm, "hrawclk", CCK_DISPLAY_REF_CLOCK_CONTROL); + return vlv_get_cck_clock(drm, "hrawclk", CCK_DISPLAY_REF_CLOCK_CONTROL, + vlv_clock_get_hpll_vco(drm)); } int vlv_clock_get_czclk(struct drm_device *drm) @@ -196,8 +191,8 @@ int vlv_clock_get_czclk(struct drm_device *drm) struct drm_i915_private *i915 = to_i915(drm); if (!i915->czclk_freq) - i915->czclk_freq = vlv_get_cck_clock_hpll(drm, "czclk", - CCK_CZ_CLOCK_CONTROL); + i915->czclk_freq = vlv_get_cck_clock(drm, "czclk", CCK_CZ_CLOCK_CONTROL, + vlv_clock_get_hpll_vco(drm)); return i915->czclk_freq; } -- cgit v1.2.3 From e3aae3e40190dcd4a49d927ed10c798c05a5627f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:51 +0300 Subject: drm/i915: remove intel_update_czclk() as unnecessary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With vlv_clock_get_czclk() caching the result on first use, we no longer need a separate initializer. Remove intel_update_czclk() as unnecessary. Log the CZCLK in vlv_clock_get_czclk() instead. v2: Rebase Reviewed-by: Michał Grzelak # v1 Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/3f90b5e67258f485db09b6f48381682cbd96153f.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 16 +++------------- drivers/gpu/drm/i915/display/intel_display.h | 1 - drivers/gpu/drm/i915/display/intel_display_driver.c | 1 - 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 8f200593053e..fb1882494543 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -190,9 +190,11 @@ int vlv_clock_get_czclk(struct drm_device *drm) { struct drm_i915_private *i915 = to_i915(drm); - if (!i915->czclk_freq) + if (!i915->czclk_freq) { i915->czclk_freq = vlv_get_cck_clock(drm, "czclk", CCK_CZ_CLOCK_CONTROL, vlv_clock_get_hpll_vco(drm)); + drm_dbg_kms(drm, "CZ clock rate: %d kHz\n", i915->czclk_freq); + } return i915->czclk_freq; } @@ -209,18 +211,6 @@ int vlv_clock_get_gpll(struct drm_device *drm) vlv_clock_get_czclk(drm)); } -void intel_update_czclk(struct intel_display *display) -{ - int czclk_freq; - - if (!display->platform.valleyview && !display->platform.cherryview) - return; - - czclk_freq = vlv_clock_get_czclk(display->drm); - - drm_dbg_kms(display->drm, "CZ clock rate: %d kHz\n", czclk_freq); -} - static bool is_hdr_mode(const struct intel_crtc_state *crtc_state) { return (crtc_state->active_planes & diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 5c406b276a76..54961cb656c3 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -528,7 +528,6 @@ void intel_init_display_hooks(struct intel_display *display); void intel_setup_outputs(struct intel_display *display); int intel_initial_commit(struct intel_display *display); void intel_panel_sanitize_ssc(struct intel_display *display); -void intel_update_czclk(struct intel_display *display); enum drm_mode_status intel_mode_valid(struct drm_device *dev, const struct drm_display_mode *mode); int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index cf1c14412abe..f84a0b26b7a6 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -482,7 +482,6 @@ int intel_display_driver_probe_nogem(struct intel_display *display) intel_dpll_init(display); intel_fdi_pll_freq_update(display); - intel_update_czclk(display); intel_display_driver_init_hw(display); intel_dpll_update_ref_clks(display); -- cgit v1.2.3 From b478f2035c59fa81c4bdc0ddefbf692b2797676a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:52 +0300 Subject: drm/i915: log HPLL frequency similar to CZCLK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With vlv_clock_get_czclk() logging the CZ clock rate when first cached, do the same for HPLL VCO. v2: Rebase Reviewed-by: Michał Grzelak Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/bfc3082f90cf9f74aa40308e10f20da824b1db55.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index fb1882494543..b49661b4e959 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -155,6 +155,8 @@ int vlv_clock_get_hpll_vco(struct drm_device *drm) vlv_cck_put(drm); i915->hpll_freq = vco_freq[hpll_freq] * 1000; + + drm_dbg_kms(drm, "HPLL frequency: %d kHz\n", i915->hpll_freq); } return i915->hpll_freq; -- cgit v1.2.3 From 869d0e96398dca38862b3263244415a05d8a4cf1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:53 +0300 Subject: drm/i915: move hpll and czclk caching under display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Perhaps not the ideal place, but better than having to have the fields in both struct drm_i915_private and struct xe_device. v2: Rebase Reviewed-by: Michał Grzelak # v1 Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/cbca9b13f2235a624a21bf7617ffe763e25c848c.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 22 +++++++++++----------- drivers/gpu/drm/i915/display/intel_display_core.h | 5 +++++ drivers/gpu/drm/i915/i915_drv.h | 3 --- drivers/gpu/drm/xe/xe_device_types.h | 6 ------ 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b49661b4e959..02f50d0f370a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -144,22 +144,22 @@ static void bdw_set_pipe_misc(struct intel_dsb *dsb, /* returns HPLL frequency in kHz */ int vlv_clock_get_hpll_vco(struct drm_device *drm) { - struct drm_i915_private *i915 = to_i915(drm); + struct intel_display *display = to_intel_display(drm); int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; - if (!i915->hpll_freq) { + if (!display->vlv_clock.hpll_freq) { vlv_cck_get(drm); /* Obtain SKU information */ hpll_freq = vlv_cck_read(drm, CCK_FUSE_REG) & CCK_FUSE_HPLL_FREQ_MASK; vlv_cck_put(drm); - i915->hpll_freq = vco_freq[hpll_freq] * 1000; + display->vlv_clock.hpll_freq = vco_freq[hpll_freq] * 1000; - drm_dbg_kms(drm, "HPLL frequency: %d kHz\n", i915->hpll_freq); + drm_dbg_kms(drm, "HPLL frequency: %d kHz\n", display->vlv_clock.hpll_freq); } - return i915->hpll_freq; + return display->vlv_clock.hpll_freq; } static int vlv_get_cck_clock(struct drm_device *drm, @@ -190,15 +190,15 @@ int vlv_clock_get_hrawclk(struct drm_device *drm) int vlv_clock_get_czclk(struct drm_device *drm) { - struct drm_i915_private *i915 = to_i915(drm); + struct intel_display *display = to_intel_display(drm); - if (!i915->czclk_freq) { - i915->czclk_freq = vlv_get_cck_clock(drm, "czclk", CCK_CZ_CLOCK_CONTROL, - vlv_clock_get_hpll_vco(drm)); - drm_dbg_kms(drm, "CZ clock rate: %d kHz\n", i915->czclk_freq); + if (!display->vlv_clock.czclk_freq) { + display->vlv_clock.czclk_freq = vlv_get_cck_clock(drm, "czclk", CCK_CZ_CLOCK_CONTROL, + vlv_clock_get_hpll_vco(drm)); + drm_dbg_kms(drm, "CZ clock rate: %d kHz\n", display->vlv_clock.czclk_freq); } - return i915->czclk_freq; + return display->vlv_clock.czclk_freq; } int vlv_clock_get_cdclk(struct drm_device *drm) diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 8c226406c5cd..791021a4e3bb 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -567,6 +567,11 @@ struct intel_display { u32 bxt_phy_grc; } state; + struct { + unsigned int hpll_freq; + unsigned int czclk_freq; + } vlv_clock; + struct { /* ordered wq for modesets */ struct workqueue_struct *modeset; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6a768aad8edd..37970d8db255 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -239,9 +239,6 @@ struct drm_i915_private { bool preserve_bios_swizzle; - unsigned int hpll_freq; - unsigned int czclk_freq; - /** * wq - Driver workqueue for GEM. * diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 092004d14db2..4353256452aa 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -617,12 +617,6 @@ struct xe_device { struct intel_uncore { spinlock_t lock; } uncore; - - /* only to allow build, not used functionally */ - struct { - unsigned int hpll_freq; - unsigned int czclk_freq; - }; #endif }; -- cgit v1.2.3 From 5615e78e813ee50609b94cbd6a376e29af01814f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Sep 2025 17:48:54 +0300 Subject: drm/i915: split out vlv_clock.[ch] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the VLV clock related functions to their own file. v2: Rebase Reviewed-by: Michał Grzelak # v1 Acked-by: Ville Syrjälä Link: https://lore.kernel.org/r/0bc4a930f3e364c4fc37479f56bf07ccee854fcc.1757688216.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_cdclk.c | 1 + drivers/gpu/drm/i915/display/intel_display.c | 74 ------------------------- drivers/gpu/drm/i915/display/intel_display.h | 5 -- drivers/gpu/drm/i915/display/vlv_clock.c | 81 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/display/vlv_clock.h | 38 +++++++++++++ drivers/gpu/drm/i915/gt/intel_rc6.c | 2 +- drivers/gpu/drm/i915/gt/intel_rps.c | 2 +- 8 files changed, 123 insertions(+), 81 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/vlv_clock.c create mode 100644 drivers/gpu/drm/i915/display/vlv_clock.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index e58c0c158b3a..78a45a6681df 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -300,6 +300,7 @@ i915-y += \ display/skl_scaler.o \ display/skl_universal_plane.o \ display/skl_watermark.o \ + display/vlv_clock.o \ display/vlv_sideband.o i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index e77efa0f33ed..b54b1006aeb0 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -49,6 +49,7 @@ #include "intel_vdsc.h" #include "skl_watermark.h" #include "skl_watermark_regs.h" +#include "vlv_clock.h" #include "vlv_dsi.h" #include "vlv_sideband.h" diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 02f50d0f370a..a743d1339550 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -129,11 +129,9 @@ #include "skl_scaler.h" #include "skl_universal_plane.h" #include "skl_watermark.h" -#include "vlv_dpio_phy_regs.h" #include "vlv_dsi.h" #include "vlv_dsi_pll.h" #include "vlv_dsi_regs.h" -#include "vlv_sideband.h" static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state); static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state); @@ -141,78 +139,6 @@ static void hsw_set_transconf(const struct intel_crtc_state *crtc_state); static void bdw_set_pipe_misc(struct intel_dsb *dsb, const struct intel_crtc_state *crtc_state); -/* returns HPLL frequency in kHz */ -int vlv_clock_get_hpll_vco(struct drm_device *drm) -{ - struct intel_display *display = to_intel_display(drm); - int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; - - if (!display->vlv_clock.hpll_freq) { - vlv_cck_get(drm); - /* Obtain SKU information */ - hpll_freq = vlv_cck_read(drm, CCK_FUSE_REG) & - CCK_FUSE_HPLL_FREQ_MASK; - vlv_cck_put(drm); - - display->vlv_clock.hpll_freq = vco_freq[hpll_freq] * 1000; - - drm_dbg_kms(drm, "HPLL frequency: %d kHz\n", display->vlv_clock.hpll_freq); - } - - return display->vlv_clock.hpll_freq; -} - -static int vlv_get_cck_clock(struct drm_device *drm, - const char *name, u32 reg, int ref_freq) -{ - u32 val; - int divider; - - vlv_cck_get(drm); - val = vlv_cck_read(drm, reg); - vlv_cck_put(drm); - - divider = val & CCK_FREQUENCY_VALUES; - - drm_WARN(drm, (val & CCK_FREQUENCY_STATUS) != - (divider << CCK_FREQUENCY_STATUS_SHIFT), - "%s change in progress\n", name); - - return DIV_ROUND_CLOSEST(ref_freq << 1, divider + 1); -} - -int vlv_clock_get_hrawclk(struct drm_device *drm) -{ - /* RAWCLK_FREQ_VLV register updated from power well code */ - return vlv_get_cck_clock(drm, "hrawclk", CCK_DISPLAY_REF_CLOCK_CONTROL, - vlv_clock_get_hpll_vco(drm)); -} - -int vlv_clock_get_czclk(struct drm_device *drm) -{ - struct intel_display *display = to_intel_display(drm); - - if (!display->vlv_clock.czclk_freq) { - display->vlv_clock.czclk_freq = vlv_get_cck_clock(drm, "czclk", CCK_CZ_CLOCK_CONTROL, - vlv_clock_get_hpll_vco(drm)); - drm_dbg_kms(drm, "CZ clock rate: %d kHz\n", display->vlv_clock.czclk_freq); - } - - return display->vlv_clock.czclk_freq; -} - -int vlv_clock_get_cdclk(struct drm_device *drm) -{ - return vlv_get_cck_clock(drm, "cdclk", CCK_DISPLAY_CLOCK_CONTROL, - vlv_clock_get_hpll_vco(drm)); -} - -int vlv_clock_get_gpll(struct drm_device *drm) -{ - return vlv_get_cck_clock(drm, "GPLL ref", CCK_GPLL_CLOCK_CONTROL, - vlv_clock_get_czclk(drm)); -} - static bool is_hdr_mode(const struct intel_crtc_state *crtc_state) { return (crtc_state->active_planes & diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 54961cb656c3..9a9a44b61f7f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -435,11 +435,6 @@ void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state); void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state); void i830_enable_pipe(struct intel_display *display, enum pipe pipe); void i830_disable_pipe(struct intel_display *display, enum pipe pipe); -int vlv_clock_get_hpll_vco(struct drm_device *drm); -int vlv_clock_get_hrawclk(struct drm_device *drm); -int vlv_clock_get_czclk(struct drm_device *drm); -int vlv_clock_get_cdclk(struct drm_device *drm); -int vlv_clock_get_gpll(struct drm_device *drm); bool intel_has_pending_fb_unpin(struct intel_display *display); void intel_encoder_destroy(struct drm_encoder *encoder); struct drm_display_mode * diff --git a/drivers/gpu/drm/i915/display/vlv_clock.c b/drivers/gpu/drm/i915/display/vlv_clock.c new file mode 100644 index 000000000000..2c55083d8fdb --- /dev/null +++ b/drivers/gpu/drm/i915/display/vlv_clock.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +/* Copyright © 2025 Intel Corporation */ + +#include + +#include "intel_display_core.h" +#include "intel_display_types.h" +#include "vlv_clock.h" +#include "vlv_sideband.h" + +/* returns HPLL frequency in kHz */ +int vlv_clock_get_hpll_vco(struct drm_device *drm) +{ + struct intel_display *display = to_intel_display(drm); + int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; + + if (!display->vlv_clock.hpll_freq) { + vlv_cck_get(drm); + /* Obtain SKU information */ + hpll_freq = vlv_cck_read(drm, CCK_FUSE_REG) & + CCK_FUSE_HPLL_FREQ_MASK; + vlv_cck_put(drm); + + display->vlv_clock.hpll_freq = vco_freq[hpll_freq] * 1000; + + drm_dbg_kms(drm, "HPLL frequency: %d kHz\n", display->vlv_clock.hpll_freq); + } + + return display->vlv_clock.hpll_freq; +} + +static int vlv_get_cck_clock(struct drm_device *drm, + const char *name, u32 reg, int ref_freq) +{ + u32 val; + int divider; + + vlv_cck_get(drm); + val = vlv_cck_read(drm, reg); + vlv_cck_put(drm); + + divider = val & CCK_FREQUENCY_VALUES; + + drm_WARN(drm, (val & CCK_FREQUENCY_STATUS) != + (divider << CCK_FREQUENCY_STATUS_SHIFT), + "%s change in progress\n", name); + + return DIV_ROUND_CLOSEST(ref_freq << 1, divider + 1); +} + +int vlv_clock_get_hrawclk(struct drm_device *drm) +{ + /* RAWCLK_FREQ_VLV register updated from power well code */ + return vlv_get_cck_clock(drm, "hrawclk", CCK_DISPLAY_REF_CLOCK_CONTROL, + vlv_clock_get_hpll_vco(drm)); +} + +int vlv_clock_get_czclk(struct drm_device *drm) +{ + struct intel_display *display = to_intel_display(drm); + + if (!display->vlv_clock.czclk_freq) { + display->vlv_clock.czclk_freq = vlv_get_cck_clock(drm, "czclk", CCK_CZ_CLOCK_CONTROL, + vlv_clock_get_hpll_vco(drm)); + drm_dbg_kms(drm, "CZ clock rate: %d kHz\n", display->vlv_clock.czclk_freq); + } + + return display->vlv_clock.czclk_freq; +} + +int vlv_clock_get_cdclk(struct drm_device *drm) +{ + return vlv_get_cck_clock(drm, "cdclk", CCK_DISPLAY_CLOCK_CONTROL, + vlv_clock_get_hpll_vco(drm)); +} + +int vlv_clock_get_gpll(struct drm_device *drm) +{ + return vlv_get_cck_clock(drm, "GPLL ref", CCK_GPLL_CLOCK_CONTROL, + vlv_clock_get_czclk(drm)); +} diff --git a/drivers/gpu/drm/i915/display/vlv_clock.h b/drivers/gpu/drm/i915/display/vlv_clock.h new file mode 100644 index 000000000000..5742ed3c628d --- /dev/null +++ b/drivers/gpu/drm/i915/display/vlv_clock.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2025 Intel Corporation */ + +#ifndef __VLV_CLOCK_H__ +#define __VLV_CLOCK_H__ + +struct drm_device; + +#ifdef I915 +int vlv_clock_get_hpll_vco(struct drm_device *drm); +int vlv_clock_get_hrawclk(struct drm_device *drm); +int vlv_clock_get_czclk(struct drm_device *drm); +int vlv_clock_get_cdclk(struct drm_device *drm); +int vlv_clock_get_gpll(struct drm_device *drm); +#else +static inline int vlv_clock_get_hpll_vco(struct drm_device *drm) +{ + return 0; +} +static inline int vlv_clock_get_hrawclk(struct drm_device *drm) +{ + return 0; +} +static inline int vlv_clock_get_czclk(struct drm_device *drm) +{ + return 0; +} +static inline int vlv_clock_get_cdclk(struct drm_device *drm) +{ + return 0; +} +static inline int vlv_clock_get_gpll(struct drm_device *drm) +{ + return 0; +} +#endif + +#endif /* __VLV_CLOCK_H__ */ diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c index ef8b2fd2ae69..932f9f1b06b2 100644 --- a/drivers/gpu/drm/i915/gt/intel_rc6.c +++ b/drivers/gpu/drm/i915/gt/intel_rc6.c @@ -6,7 +6,7 @@ #include #include -#include "display/intel_display.h" +#include "display/vlv_clock.h" #include "gem/i915_gem_region.h" #include "i915_drv.h" #include "i915_reg.h" diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index db9cfd2b2b89..b01c837ab646 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -7,8 +7,8 @@ #include -#include "display/intel_display.h" #include "display/intel_display_rps.h" +#include "display/vlv_clock.h" #include "soc/intel_dram.h" #include "i915_drv.h" -- cgit v1.2.3 From fcf2af765c1e4f47f2fc8aa8ce7d368fc5728f46 Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Fri, 12 Sep 2025 09:40:35 +0300 Subject: drm/i915/alpm: Remove error handling from get_lfps_cycle_min_max_time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Getter for LFPS cycle min/max times is unnecessarily checking faulty port clock value. This doesn't make sense as erroneous port clock value would have been noticed already at this point. Remove this check and use 140/800 ns always when port clock > 540000. Signed-off-by: Jouni Högander Reviewed-by: Mika Kahola Link: https://lore.kernel.org/r/20250912064035.335329-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_alpm.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_alpm.c b/drivers/gpu/drm/i915/display/intel_alpm.c index ed7a7ed486b5..749119cc0b28 100644 --- a/drivers/gpu/drm/i915/display/intel_alpm.c +++ b/drivers/gpu/drm/i915/display/intel_alpm.c @@ -58,43 +58,32 @@ static int get_silence_period_symbols(const struct intel_crtc_state *crtc_state) 1000 / 1000; } -static int get_lfps_cycle_min_max_time(const struct intel_crtc_state *crtc_state, - int *min, int *max) +static void get_lfps_cycle_min_max_time(const struct intel_crtc_state *crtc_state, + int *min, int *max) { if (crtc_state->port_clock < 540000) { *min = 65 * LFPS_CYCLE_COUNT; *max = 75 * LFPS_CYCLE_COUNT; - } else if (crtc_state->port_clock <= 810000) { + } else { *min = 140; *max = 800; - } else { - *min = *max = -1; - return -1; } - - return 0; } static int get_lfps_cycle_time(const struct intel_crtc_state *crtc_state) { - int tlfps_cycle_min, tlfps_cycle_max, ret; + int tlfps_cycle_min, tlfps_cycle_max; - ret = get_lfps_cycle_min_max_time(crtc_state, &tlfps_cycle_min, - &tlfps_cycle_max); - if (ret) - return ret; + get_lfps_cycle_min_max_time(crtc_state, &tlfps_cycle_min, + &tlfps_cycle_max); return tlfps_cycle_min + (tlfps_cycle_max - tlfps_cycle_min) / 2; } static int get_lfps_half_cycle_clocks(const struct intel_crtc_state *crtc_state) { - int lfps_cycle_time = get_lfps_cycle_time(crtc_state); - - if (lfps_cycle_time < 0) - return -1; - - return lfps_cycle_time * crtc_state->port_clock / 1000 / 1000 / (2 * LFPS_CYCLE_COUNT); + return get_lfps_cycle_time(crtc_state) * crtc_state->port_clock / 1000 / + 1000 / (2 * LFPS_CYCLE_COUNT); } /* @@ -146,8 +135,6 @@ _lnl_compute_aux_less_alpm_params(struct intel_dp *intel_dp, silence_period = get_silence_period_symbols(crtc_state); lfps_half_cycle = get_lfps_half_cycle_clocks(crtc_state); - if (lfps_half_cycle < 0) - return false; if (aux_less_wake_lines > ALPM_CTL_AUX_LESS_WAKE_TIME_MASK || silence_period > PORT_ALPM_CTL_SILENCE_PERIOD_MASK || -- cgit v1.2.3 From 7a356ee5cf6dad1c7d305eea261a03a925454ed6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 17 Sep 2025 16:52:00 +0300 Subject: drm/i915: add note on VLV/CHV hpll_freq and czclk_freq caching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The caching at the initial read is a bit fragile in case, say, a further refactoring starts reading the frequencies at a time where it's not possible. Add a note about it. Suggested-by: Ville Syrjälä Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/20250917135200.1932903-1-jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/vlv_clock.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/display/vlv_clock.c b/drivers/gpu/drm/i915/display/vlv_clock.c index 2c55083d8fdb..42c2837b32c1 100644 --- a/drivers/gpu/drm/i915/display/vlv_clock.c +++ b/drivers/gpu/drm/i915/display/vlv_clock.c @@ -8,6 +8,13 @@ #include "vlv_clock.h" #include "vlv_sideband.h" +/* + * FIXME: The caching of hpll_freq and czclk_freq relies on the first calls + * occurring at a time when they can actually be read. This appears to be the + * case, but is somewhat fragile. Make the initialization explicit at a point + * where they can be reliably read. + */ + /* returns HPLL frequency in kHz */ int vlv_clock_get_hpll_vco(struct drm_device *drm) { -- cgit v1.2.3 From f80fb921747b46d3e65887099977e457fba7256a Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Tue, 16 Sep 2025 17:43:19 +0000 Subject: drm/i915/gvt: Remove unnecessary check in reg_is_mmio The reg >= 0 check in reg_is_mmio is unnecessary because reg is always greater than zero in all current use cases. This is obvious when checking 'offset' by itself (as offset is defined as an unsigned integer), but it's also true for the offset + bytes - 1 use case in intel_vgpu_emulate_mmio_read because bytes > 0. Signed-off-by: Jonathan Cavitt Reviewed-by: Andi Shyti Reviewed-by: Zhenyu Wang Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250916174317.76521-5-jonathan.cavitt@intel.com --- drivers/gpu/drm/i915/gvt/mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c index da1135fa7cda..c60d1e548800 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.c +++ b/drivers/gpu/drm/i915/gvt/mmio.c @@ -58,7 +58,7 @@ int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa) } #define reg_is_mmio(gvt, reg) \ - (reg >= 0 && reg < gvt->device_info.mmio_size) + (reg < gvt->device_info.mmio_size) #define reg_is_gtt(gvt, reg) \ (reg >= gvt->device_info.gtt_start_offset \ -- cgit v1.2.3 From 96e556ef5ced51eec140db4bd89204c9322959cc Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Tue, 16 Sep 2025 17:43:20 +0000 Subject: drm/i915/gvt: Fix intel_vgpu_gpa_to_mmio_offset kernel docs intel_vgpu_gpa_to_mmio_offset states that it returns 'Zero on success, negative error code if failed' in the kernel docs. This is false. The function actually returns 'The MMIO offset of the given GPA'. Correct the docs. Signed-off-by: Jonathan Cavitt Reviewed-by: Andi Shyti Reviewed-by: Zhenyu Wang Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250916174317.76521-6-jonathan.cavitt@intel.com --- drivers/gpu/drm/i915/gvt/mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c index c60d1e548800..db5cd65100fe 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.c +++ b/drivers/gpu/drm/i915/gvt/mmio.c @@ -49,7 +49,7 @@ * @gpa: guest physical address * * Returns: - * Zero on success, negative error code if failed + * The MMIO offset of the given GPA */ int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa) { -- cgit v1.2.3 From 089b5773c219b9bd5e3c7ac72d6ad933dd050f4d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 12 Sep 2025 16:59:26 +0300 Subject: drm/i915: Defeature DRRS on LNL+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DRRS has been defeatured on LNL+. Adjust HAS_DOUBLE_BUFFERED_M_N() to match. Note that the M/N registers still appear to be double buffered under the hood but the double buffer update point is now documented to be just the last register write to the M/N registers, so it no longer happens synchronously with the vblank/MSA transmission. We should perhaps rename HAS_DOUBLE_BUFFERED_M_N() to more accurately reflect reality, but couldn't come up with a decent name right now... Bspec: 68917 HSD: 14016007525 Cc: Ankit Nautiyal Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250912135926.18910-1-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_display_device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index f329f1beafef..1f091fbcd0ec 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -155,7 +155,7 @@ struct intel_display_platforms { #define HAS_DISPLAY(__display) (DISPLAY_RUNTIME_INFO(__display)->pipe_mask != 0) #define HAS_DMC(__display) (DISPLAY_RUNTIME_INFO(__display)->has_dmc) #define HAS_DMC_WAKELOCK(__display) (DISPLAY_VER(__display) >= 20) -#define HAS_DOUBLE_BUFFERED_M_N(__display) (DISPLAY_VER(__display) >= 9 || (__display)->platform.broadwell) +#define HAS_DOUBLE_BUFFERED_M_N(__display) (IS_DISPLAY_VER((__display), 9, 14) || (__display)->platform.broadwell) #define HAS_DOUBLE_BUFFERED_LUT(__display) (DISPLAY_VER(__display) >= 30) #define HAS_DOUBLE_WIDE(__display) (DISPLAY_VER(__display) < 4) #define HAS_DP20(__display) ((__display)->platform.dg2 || DISPLAY_VER(__display) >= 14) -- cgit v1.2.3 From a0f8dd08a55b6a5c456c0124dc9a978aa65b651c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Sep 2025 23:34:42 +0300 Subject: drm/i915/vrr: Extract helpers to convert between guardband and pipeline_full values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'd like to move towards a world where we can't more or less pretend that the ICl/TGL VRR hardware works the same way as ADL+. To that end extract some helpers to convert between the guardband and pipeline_full representations. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250917203446.14374-2-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_vrr.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 3eed37f271b0..5fee85b0bc99 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -119,6 +119,20 @@ static int intel_vrr_vmin_flipline(const struct intel_crtc_state *crtc_state) return crtc_state->vrr.vmin + intel_vrr_flipline_offset(display); } +static int intel_vrr_guardband_to_pipeline_full(const struct intel_crtc_state *crtc_state, + int guardband) +{ + /* hardware imposes one extra scanline somewhere */ + return guardband - crtc_state->framestart_delay - 1; +} + +static int intel_vrr_pipeline_full_to_guardband(const struct intel_crtc_state *crtc_state, + int pipeline_full) +{ + /* hardware imposes one extra scanline somewhere */ + return pipeline_full + crtc_state->framestart_delay + 1; +} + /* * Without VRR registers get latched at: * vblank_start @@ -142,8 +156,8 @@ static int intel_vrr_vblank_exit_length(const struct intel_crtc_state *crtc_stat if (DISPLAY_VER(display) >= 13) return crtc_state->vrr.guardband; else - /* hardware imposes one extra scanline somewhere */ - return crtc_state->vrr.pipeline_full + crtc_state->framestart_delay + 1; + return intel_vrr_pipeline_full_to_guardband(crtc_state, + crtc_state->vrr.pipeline_full); } int intel_vrr_vmin_vtotal(const struct intel_crtc_state *crtc_state) @@ -417,18 +431,18 @@ void intel_vrr_compute_config_late(struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + int guardband; if (!intel_vrr_possible(crtc_state)) return; + guardband = crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start; + if (DISPLAY_VER(display) >= 13) { - crtc_state->vrr.guardband = - crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start; + crtc_state->vrr.guardband = guardband; } else { - /* hardware imposes one extra scanline somewhere */ crtc_state->vrr.pipeline_full = - min(255, crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start - - crtc_state->framestart_delay - 1); + min(255, intel_vrr_guardband_to_pipeline_full(crtc_state, guardband)); /* * vmin/vmax/flipline also need to be adjusted by -- cgit v1.2.3 From 6559ca4a42d7976497fcf49e4c4fad9639fc1f76 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Sep 2025 23:34:43 +0300 Subject: drm/i915/vrr: Readout framestart_delay earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to pretend that ICL/TGL VRR hardware has a similar guardband as on ADL+ we'll need access to framestart_delay already during intel_vrr_get_config(). Hoist the framestart_delay to an earlier point to make that possible. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250917203446.14374-3-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_display.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index a743d1339550..c7d85fd38890 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -3891,6 +3891,15 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, intel_joiner_get_config(pipe_config); intel_dsc_get_config(pipe_config); + if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) { + tmp = intel_de_read(display, CHICKEN_TRANS(display, pipe_config->cpu_transcoder)); + + pipe_config->framestart_delay = REG_FIELD_GET(HSW_FRAME_START_DELAY_MASK, tmp) + 1; + } else { + /* no idea if this is correct */ + pipe_config->framestart_delay = 1; + } + if (!transcoder_is_dsi(pipe_config->cpu_transcoder) || DISPLAY_VER(display) >= 11) intel_get_transcoder_timings(crtc, pipe_config); @@ -3942,15 +3951,6 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, pipe_config->pixel_multiplier = 1; } - if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) { - tmp = intel_de_read(display, CHICKEN_TRANS(display, pipe_config->cpu_transcoder)); - - pipe_config->framestart_delay = REG_FIELD_GET(HSW_FRAME_START_DELAY_MASK, tmp) + 1; - } else { - /* no idea if this is correct */ - pipe_config->framestart_delay = 1; - } - out: intel_display_power_put_all_in_set(display, &crtc->hw_readout_power_domains); -- cgit v1.2.3 From 291ddb993ac967a519cdb5394fd06871b9fa74bf Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Sep 2025 23:34:44 +0300 Subject: drm/i915/vrr: Store guardband in crtc state even for icl/tgl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While ICL/TGL VRR hardware doesn't have a register for the guardband value, our lives will be simpler if we pretend that it does. Start by computing the guardband the same as on ADL+ and storing it in the state, and only then we convert it into the corresponding pipeline_full value that the hardware can consume. During readout we do the opposite. I was debating whether to completely remove pipeline_full from the crtc state, but decided to keep it for now. Mainly because we check it in vrr_params_changed() and simply checking the guardband instead isn't 100% equivalent; Theoretically, framestart_delay may have changed in the opposite direction to pipeline_full, keeping the derived guardband value unchaged. One solution would be to also check framestart_delay, but that feels a bit leaky abstraction wise. Also note that we don't currently handle the maximum limit of 255 scanlines for the pipeline_full in a very nice way. The actual position of the delayed vblank will move because of that clamping, and so some of our code may get confused. But fixing this shall wait a for now. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250917203446.14374-4-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_display.c | 1 + drivers/gpu/drm/i915/display/intel_vrr.c | 36 +++++++++++++++------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index c7d85fd38890..f4124c79bc83 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -3891,6 +3891,7 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, intel_joiner_get_config(pipe_config); intel_dsc_get_config(pipe_config); + /* intel_vrr_get_config() depends on .framestart_delay */ if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) { tmp = intel_de_read(display, CHICKEN_TRANS(display, pipe_config->cpu_transcoder)); diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 5fee85b0bc99..9cdcc2558ead 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -151,13 +151,7 @@ static int intel_vrr_pipeline_full_to_guardband(const struct intel_crtc_state *c */ static int intel_vrr_vblank_exit_length(const struct intel_crtc_state *crtc_state) { - struct intel_display *display = to_intel_display(crtc_state); - - if (DISPLAY_VER(display) >= 13) - return crtc_state->vrr.guardband; - else - return intel_vrr_pipeline_full_to_guardband(crtc_state, - crtc_state->vrr.pipeline_full); + return crtc_state->vrr.guardband; } int intel_vrr_vmin_vtotal(const struct intel_crtc_state *crtc_state) @@ -431,18 +425,22 @@ void intel_vrr_compute_config_late(struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; - int guardband; if (!intel_vrr_possible(crtc_state)) return; - guardband = crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start; + crtc_state->vrr.guardband = + crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start; + + if (DISPLAY_VER(display) < 13) { + /* FIXME handle the limit in a proper way */ + crtc_state->vrr.guardband = + min(crtc_state->vrr.guardband, + intel_vrr_pipeline_full_to_guardband(crtc_state, 255)); - if (DISPLAY_VER(display) >= 13) { - crtc_state->vrr.guardband = guardband; - } else { crtc_state->vrr.pipeline_full = - min(255, intel_vrr_guardband_to_pipeline_full(crtc_state, guardband)); + intel_vrr_guardband_to_pipeline_full(crtc_state, + crtc_state->vrr.guardband); /* * vmin/vmax/flipline also need to be adjusted by @@ -734,14 +732,20 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) TRANS_CMRR_M_HI(display, cpu_transcoder)); } - if (DISPLAY_VER(display) >= 13) + if (DISPLAY_VER(display) >= 13) { crtc_state->vrr.guardband = REG_FIELD_GET(XELPD_VRR_CTL_VRR_GUARDBAND_MASK, trans_vrr_ctl); - else - if (trans_vrr_ctl & VRR_CTL_PIPELINE_FULL_OVERRIDE) + } else { + if (trans_vrr_ctl & VRR_CTL_PIPELINE_FULL_OVERRIDE) { crtc_state->vrr.pipeline_full = REG_FIELD_GET(VRR_CTL_PIPELINE_FULL_MASK, trans_vrr_ctl); + crtc_state->vrr.guardband = + intel_vrr_pipeline_full_to_guardband(crtc_state, + crtc_state->vrr.pipeline_full); + } + } + if (trans_vrr_ctl & VRR_CTL_FLIP_LINE_EN) { crtc_state->vrr.flipline = intel_de_read(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder)) + 1; -- cgit v1.2.3 From 1e2266dc68ae3d8c5017f07d2002a2ba79549f01 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Sep 2025 23:34:45 +0300 Subject: drm/i915/vrr: Annotate some functions with "hw" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_vrr_fixed_rr_*() return values that have had the TGL SCL adjustment applied to them. So we should indicate that these values are only really useful when fed to the hardware. Add a "_hw_" indicator to the function names to reflect that fact. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250917203446.14374-5-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_vrr.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 9cdcc2558ead..71fb64c92165 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -263,7 +263,7 @@ void intel_vrr_compute_vrr_timings(struct intel_crtc_state *crtc_state) * Vtotal value. */ static -int intel_vrr_fixed_rr_vtotal(const struct intel_crtc_state *crtc_state) +int intel_vrr_fixed_rr_hw_vtotal(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); int crtc_vtotal = crtc_state->hw.adjusted_mode.crtc_vtotal; @@ -276,24 +276,24 @@ int intel_vrr_fixed_rr_vtotal(const struct intel_crtc_state *crtc_state) } static -int intel_vrr_fixed_rr_vmax(const struct intel_crtc_state *crtc_state) +int intel_vrr_fixed_rr_hw_vmax(const struct intel_crtc_state *crtc_state) { - return intel_vrr_fixed_rr_vtotal(crtc_state); + return intel_vrr_fixed_rr_hw_vtotal(crtc_state); } static -int intel_vrr_fixed_rr_vmin(const struct intel_crtc_state *crtc_state) +int intel_vrr_fixed_rr_hw_vmin(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - return intel_vrr_fixed_rr_vtotal(crtc_state) - + return intel_vrr_fixed_rr_hw_vtotal(crtc_state) - intel_vrr_flipline_offset(display); } static -int intel_vrr_fixed_rr_flipline(const struct intel_crtc_state *crtc_state) +int intel_vrr_fixed_rr_hw_flipline(const struct intel_crtc_state *crtc_state) { - return intel_vrr_fixed_rr_vtotal(crtc_state); + return intel_vrr_fixed_rr_hw_vtotal(crtc_state); } void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state) @@ -305,11 +305,11 @@ void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state) return; intel_de_write(display, TRANS_VRR_VMIN(display, cpu_transcoder), - intel_vrr_fixed_rr_vmin(crtc_state) - 1); + intel_vrr_fixed_rr_hw_vmin(crtc_state) - 1); intel_de_write(display, TRANS_VRR_VMAX(display, cpu_transcoder), - intel_vrr_fixed_rr_vmax(crtc_state) - 1); + intel_vrr_fixed_rr_hw_vmax(crtc_state) - 1); intel_de_write(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder), - intel_vrr_fixed_rr_flipline(crtc_state) - 1); + intel_vrr_fixed_rr_hw_flipline(crtc_state) - 1); } static -- cgit v1.2.3 From a58b9e3d6e6777fc52040fcd93a46d107f87c7ec Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Sep 2025 23:34:46 +0300 Subject: drm/i915/vrr: Move the TGL SCL mangling of vmin/vmax/flipline deeper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently our crtc_state->vrr.{vmin.vmax,flipline} are mangled on TGL to account for the SCL delay (the hardware requires this mangling or the actual vtotals will become incorrect). Unfortunately this means that one can't simply use these values directly in many places, and instead we always have to go through functions that undo the damage first. This is all rather fragile. Simplify our lives a bit by hiding this mangling deeper inside the low level VRR code, leaving the number stored in the crtc state actually something that humans can use. This does introduce a dependdency as intel_vrr_get_config() will now need to know the SCL value, which is read out in intel_get_transcoder_timings(). I suppose we could simply duplicate the SCL readout in both places should this become a real hinderance. For now just leave a note around the intel_get_transcoder_timings() call to remind us. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250917203446.14374-6-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_display.c | 4 ++ drivers/gpu/drm/i915/display/intel_vrr.c | 76 ++++++++++++++++------------ 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index f4124c79bc83..18b9baa96241 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -3901,6 +3901,10 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, pipe_config->framestart_delay = 1; } + /* + * intel_vrr_get_config() depends on TRANS_SET_CONTEXT_LATENCY + * readout done by intel_get_transcoder_timings(). + */ if (!transcoder_is_dsi(pipe_config->cpu_transcoder) || DISPLAY_VER(display) >= 11) intel_get_transcoder_timings(crtc, pipe_config); diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 71fb64c92165..71a985d00604 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -156,25 +156,13 @@ static int intel_vrr_vblank_exit_length(const struct intel_crtc_state *crtc_stat int intel_vrr_vmin_vtotal(const struct intel_crtc_state *crtc_state) { - struct intel_display *display = to_intel_display(crtc_state); - /* Min vblank actually determined by flipline */ - if (DISPLAY_VER(display) >= 13) - return intel_vrr_vmin_flipline(crtc_state); - else - return intel_vrr_vmin_flipline(crtc_state) + - intel_vrr_real_vblank_delay(crtc_state); + return intel_vrr_vmin_flipline(crtc_state); } int intel_vrr_vmax_vtotal(const struct intel_crtc_state *crtc_state) { - struct intel_display *display = to_intel_display(crtc_state); - - if (DISPLAY_VER(display) >= 13) - return crtc_state->vrr.vmax; - else - return crtc_state->vrr.vmax + - intel_vrr_real_vblank_delay(crtc_state); + return crtc_state->vrr.vmax; } int intel_vrr_vmin_vblank_start(const struct intel_crtc_state *crtc_state) @@ -258,6 +246,21 @@ void intel_vrr_compute_vrr_timings(struct intel_crtc_state *crtc_state) crtc_state->mode_flags |= I915_MODE_FLAG_VRR; } +static int intel_vrr_hw_value(const struct intel_crtc_state *crtc_state, + int value) +{ + struct intel_display *display = to_intel_display(crtc_state); + + /* + * On TGL vmin/vmax/flipline also need to be + * adjusted by the SCL to maintain correct vtotals. + */ + if (DISPLAY_VER(display) >= 13) + return value; + else + return value - intel_vrr_real_vblank_delay(crtc_state); +} + /* * For fixed refresh rate mode Vmin, Vmax and Flipline all are set to * Vtotal value. @@ -265,14 +268,7 @@ void intel_vrr_compute_vrr_timings(struct intel_crtc_state *crtc_state) static int intel_vrr_fixed_rr_hw_vtotal(const struct intel_crtc_state *crtc_state) { - struct intel_display *display = to_intel_display(crtc_state); - int crtc_vtotal = crtc_state->hw.adjusted_mode.crtc_vtotal; - - if (DISPLAY_VER(display) >= 13) - return crtc_vtotal; - else - return crtc_vtotal - - intel_vrr_real_vblank_delay(crtc_state); + return intel_vrr_hw_value(crtc_state, crtc_state->hw.adjusted_mode.crtc_vtotal); } static @@ -441,14 +437,6 @@ void intel_vrr_compute_config_late(struct intel_crtc_state *crtc_state) crtc_state->vrr.pipeline_full = intel_vrr_guardband_to_pipeline_full(crtc_state, crtc_state->vrr.guardband); - - /* - * vmin/vmax/flipline also need to be adjusted by - * the vblank delay to maintain correct vtotals. - */ - crtc_state->vrr.vmin -= intel_vrr_real_vblank_delay(crtc_state); - crtc_state->vrr.vmax -= intel_vrr_real_vblank_delay(crtc_state); - crtc_state->vrr.flipline -= intel_vrr_real_vblank_delay(crtc_state); } } @@ -607,6 +595,21 @@ void intel_vrr_set_db_point_and_transmission_line(const struct intel_crtc_state EMP_AS_SDP_DB_TL(crtc_state->vrr.vsync_start)); } +static int intel_vrr_hw_vmin(const struct intel_crtc_state *crtc_state) +{ + return intel_vrr_hw_value(crtc_state, crtc_state->vrr.vmin); +} + +static int intel_vrr_hw_vmax(const struct intel_crtc_state *crtc_state) +{ + return intel_vrr_hw_value(crtc_state, crtc_state->vrr.vmax); +} + +static int intel_vrr_hw_flipline(const struct intel_crtc_state *crtc_state) +{ + return intel_vrr_hw_value(crtc_state, crtc_state->vrr.flipline); +} + void intel_vrr_enable(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); @@ -616,11 +619,11 @@ void intel_vrr_enable(const struct intel_crtc_state *crtc_state) return; intel_de_write(display, TRANS_VRR_VMIN(display, cpu_transcoder), - crtc_state->vrr.vmin - 1); + intel_vrr_hw_vmin(crtc_state) - 1); intel_de_write(display, TRANS_VRR_VMAX(display, cpu_transcoder), - crtc_state->vrr.vmax - 1); + intel_vrr_hw_vmax(crtc_state) - 1); intel_de_write(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder), - crtc_state->vrr.flipline - 1); + intel_vrr_hw_flipline(crtc_state) - 1); intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), TRANS_PUSH_EN); @@ -754,6 +757,13 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) crtc_state->vrr.vmin = intel_de_read(display, TRANS_VRR_VMIN(display, cpu_transcoder)) + 1; + if (DISPLAY_VER(display) < 13) { + /* undo what intel_vrr_hw_value() does when writing the values */ + crtc_state->vrr.flipline += intel_vrr_real_vblank_delay(crtc_state); + crtc_state->vrr.vmax += intel_vrr_real_vblank_delay(crtc_state); + crtc_state->vrr.vmin += intel_vrr_real_vblank_delay(crtc_state); + } + /* * For platforms that always use VRR Timing Generator, the VTOTAL.Vtotal * bits are not filled. Since for these platforms TRAN_VMIN is always -- cgit v1.2.3 From 4a36b339a14ae6f2a366125e3d64f0c165193293 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:51 +0300 Subject: drm/xe/fbdev: use the same 64-byte stride alignment as i915 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For reasons unknown, xe uses XE_PAGE_SIZE alignment for stride. Presumably it's just a confusion between stride alignment and bo allocation size alignment. Switch to 64 byte alignment to, uh, align with i915. This will also be helpful in deduplicating and unifying the xe and i915 framebuffer allocation. Link: https://lore.kernel.org/r/aLqsC87Ol_zCXOkN@intel.com Suggested-by: Ville Syrjälä Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/7f4972104de8b179d5724ae83892ee294d3f3fd3.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c index d96ba2b51065..7dd581da7b79 100644 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c @@ -33,7 +33,7 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, mode_cmd.height = sizes->surface_height; mode_cmd.pitches[0] = ALIGN(mode_cmd.width * - DIV_ROUND_UP(sizes->surface_bpp, 8), XE_PAGE_SIZE); + DIV_ROUND_UP(sizes->surface_bpp, 8), 64); mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); -- cgit v1.2.3 From 6979d2c80c2a5b1f04157c4d6eb038bb32861cfa Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:52 +0300 Subject: drm/i915/fbdev: make intel_framebuffer_create() error return handling explicit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's sketchy to pass error pointers via to_intel_framebuffer(). It probably works as long as struct intel_framebuffer embeds struct drm_framebuffer at offset 0, but be explicit about it. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/17631db227d527d6c67f5d6b67adec1ff8dc6f8d.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index 210aee9ae88b..b9dfd00a7d05 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -67,9 +67,16 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, mode_cmd.pixel_format, mode_cmd.modifier[0]), &mode_cmd); + if (IS_ERR(fb)) { + i915_gem_object_put(obj); + goto err; + } + i915_gem_object_put(obj); return to_intel_framebuffer(fb); +err: + return ERR_CAST(fb); } int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, -- cgit v1.2.3 From 9e5cf822a207ee8c9856024c047abaccb4d185e5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:53 +0300 Subject: drm/{i915, xe}/fbdev: pass struct drm_device to intel_fbdev_fb_alloc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function doesn't actually need struct drm_fb_helper for anything, just pass struct drm_device. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/16360584f80cdc5ee35fd94cfd92fd3955588dfd.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbdev.c | 2 +- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 10 +++++----- drivers/gpu/drm/i915/display/intel_fbdev_fb.h | 4 ++-- drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 7 +++---- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 7c4709d58aa3..46c6de5f6088 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -237,7 +237,7 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, if (!fb || drm_WARN_ON(display->drm, !intel_fb_bo(&fb->base))) { drm_dbg_kms(display->drm, "no BIOS fb, allocating a new one\n"); - fb = intel_fbdev_fb_alloc(helper, sizes); + fb = intel_fbdev_fb_alloc(display->drm, sizes); if (IS_ERR(fb)) return PTR_ERR(fb); } else { diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index b9dfd00a7d05..4de13d1a4c7a 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -13,11 +13,11 @@ #include "intel_fb.h" #include "intel_fbdev_fb.h" -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, +struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, struct drm_fb_helper_surface_size *sizes) { - struct intel_display *display = to_intel_display(helper->dev); - struct drm_i915_private *dev_priv = to_i915(display->drm); + struct intel_display *display = to_intel_display(drm); + struct drm_i915_private *dev_priv = to_i915(drm); struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd = {}; struct drm_i915_gem_object *obj; @@ -58,12 +58,12 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, } if (IS_ERR(obj)) { - drm_err(display->drm, "failed to allocate framebuffer (%pe)\n", obj); + drm_err(drm, "failed to allocate framebuffer (%pe)\n", obj); return ERR_PTR(-ENOMEM); } fb = intel_framebuffer_create(intel_bo_to_drm_bo(obj), - drm_get_format_info(display->drm, + drm_get_format_info(drm, mode_cmd.pixel_format, mode_cmd.modifier[0]), &mode_cmd); diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h index cb7957272715..668ae355f5e5 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -6,14 +6,14 @@ #ifndef __INTEL_FBDEV_FB_H__ #define __INTEL_FBDEV_FB_H__ -struct drm_fb_helper; +struct drm_device; struct drm_fb_helper_surface_size; struct drm_gem_object; struct fb_info; struct i915_vma; struct intel_display; -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, +struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, struct drm_fb_helper_surface_size *sizes); int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, struct drm_gem_object *obj, struct i915_vma *vma); diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c index 7dd581da7b79..b9e855c54304 100644 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c @@ -15,12 +15,11 @@ #include -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, +struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, struct drm_fb_helper_surface_size *sizes) { struct drm_framebuffer *fb; - struct drm_device *dev = helper->dev; - struct xe_device *xe = to_xe_device(dev); + struct xe_device *xe = to_xe_device(drm); struct drm_mode_fb_cmd2 mode_cmd = {}; struct xe_bo *obj; int size; @@ -67,7 +66,7 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, } fb = intel_framebuffer_create(&obj->ttm.base, - drm_get_format_info(dev, + drm_get_format_info(drm, mode_cmd.pixel_format, mode_cmd.modifier[0]), &mode_cmd); -- cgit v1.2.3 From f9ff39f940f5ddd1d4ffcff602de7206aa1ff05d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:54 +0300 Subject: drm/{i915, xe}/fbdev: deduplicate struct drm_mode_fb_cmd2 init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull struct drm_mode_fb_cmd2 initialization out of the driver dependent code into shared display code. v2: Rebase on xe stride alignment change Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/e922e47bfd39f9c5777f869ff23c23309ebbb380.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbdev.c | 32 ++++++++++++++++++++++++++- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 25 +++++---------------- drivers/gpu/drm/i915/display/intel_fbdev_fb.h | 4 ++-- drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 25 +++++---------------- 4 files changed, 45 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 46c6de5f6088..e46c08762b84 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -207,6 +207,35 @@ static const struct drm_fb_helper_funcs intel_fb_helper_funcs = { .fb_set_suspend = intelfb_set_suspend, }; +static void intel_fbdev_fill_mode_cmd(struct drm_fb_helper_surface_size *sizes, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + /* we don't do packed 24bpp */ + if (sizes->surface_bpp == 24) + sizes->surface_bpp = 32; + + mode_cmd->width = sizes->surface_width; + mode_cmd->height = sizes->surface_height; + + mode_cmd->pitches[0] = ALIGN(mode_cmd->width * DIV_ROUND_UP(sizes->surface_bpp, 8), 64); + mode_cmd->pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); +} + +static struct intel_framebuffer * +__intel_fbdev_fb_alloc(struct intel_display *display, + struct drm_fb_helper_surface_size *sizes) +{ + struct drm_mode_fb_cmd2 mode_cmd = {}; + struct intel_framebuffer *fb; + + intel_fbdev_fill_mode_cmd(sizes, &mode_cmd); + + fb = intel_fbdev_fb_alloc(display->drm, &mode_cmd); + + return fb; +} + int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { @@ -237,7 +266,8 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, if (!fb || drm_WARN_ON(display->drm, !intel_fb_bo(&fb->base))) { drm_dbg_kms(display->drm, "no BIOS fb, allocating a new one\n"); - fb = intel_fbdev_fb_alloc(display->drm, sizes); + + fb = __intel_fbdev_fb_alloc(display, sizes); if (IS_ERR(fb)) return PTR_ERR(fb); } else { diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index 4de13d1a4c7a..685612e6afc5 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -3,7 +3,7 @@ * Copyright © 2023 Intel Corporation */ -#include +#include #include "gem/i915_gem_lmem.h" @@ -14,28 +14,15 @@ #include "intel_fbdev_fb.h" struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, - struct drm_fb_helper_surface_size *sizes) + struct drm_mode_fb_cmd2 *mode_cmd) { struct intel_display *display = to_intel_display(drm); struct drm_i915_private *dev_priv = to_i915(drm); struct drm_framebuffer *fb; - struct drm_mode_fb_cmd2 mode_cmd = {}; struct drm_i915_gem_object *obj; int size; - /* we don't do packed 24bpp */ - if (sizes->surface_bpp == 24) - sizes->surface_bpp = 32; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - mode_cmd.pitches[0] = ALIGN(mode_cmd.width * - DIV_ROUND_UP(sizes->surface_bpp, 8), 64); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = mode_cmd.pitches[0] * mode_cmd.height; + size = mode_cmd->pitches[0] * mode_cmd->height; size = PAGE_ALIGN(size); obj = ERR_PTR(-ENODEV); @@ -64,9 +51,9 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, fb = intel_framebuffer_create(intel_bo_to_drm_bo(obj), drm_get_format_info(drm, - mode_cmd.pixel_format, - mode_cmd.modifier[0]), - &mode_cmd); + mode_cmd->pixel_format, + mode_cmd->modifier[0]), + mode_cmd); if (IS_ERR(fb)) { i915_gem_object_put(obj); goto err; diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h index 668ae355f5e5..83454ffbf79c 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -7,14 +7,14 @@ #define __INTEL_FBDEV_FB_H__ struct drm_device; -struct drm_fb_helper_surface_size; struct drm_gem_object; +struct drm_mode_fb_cmd2; struct fb_info; struct i915_vma; struct intel_display; struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, - struct drm_fb_helper_surface_size *sizes); + struct drm_mode_fb_cmd2 *mode_cmd); int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, struct drm_gem_object *obj, struct i915_vma *vma); diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c index b9e855c54304..9c9fb34b3407 100644 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c @@ -3,7 +3,7 @@ * Copyright © 2023 Intel Corporation */ -#include +#include #include "intel_display_core.h" #include "intel_display_types.h" @@ -16,27 +16,14 @@ #include struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, - struct drm_fb_helper_surface_size *sizes) + struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_framebuffer *fb; struct xe_device *xe = to_xe_device(drm); - struct drm_mode_fb_cmd2 mode_cmd = {}; struct xe_bo *obj; int size; - /* we don't do packed 24bpp */ - if (sizes->surface_bpp == 24) - sizes->surface_bpp = 32; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - mode_cmd.pitches[0] = ALIGN(mode_cmd.width * - DIV_ROUND_UP(sizes->surface_bpp, 8), 64); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = mode_cmd.pitches[0] * mode_cmd.height; + size = mode_cmd->pitches[0] * mode_cmd->height; size = PAGE_ALIGN(size); obj = ERR_PTR(-ENODEV); @@ -67,9 +54,9 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, fb = intel_framebuffer_create(&obj->ttm.base, drm_get_format_info(drm, - mode_cmd.pixel_format, - mode_cmd.modifier[0]), - &mode_cmd); + mode_cmd->pixel_format, + mode_cmd->modifier[0]), + mode_cmd); if (IS_ERR(fb)) { xe_bo_unpin_map_no_vm(obj); goto err; -- cgit v1.2.3 From 7326099d71243ba31ef486931279d9573482292b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:55 +0300 Subject: drm/i915/fbdev: abstract bo creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Separate fbdev bo creation into a separate function intel_fbdev_fb_bo_create(). Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/cb3999ceae43d56e075c28a1f4581169ce457ab0.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 33 +++++++++++++++++++-------- drivers/gpu/drm/i915/display/intel_fbdev_fb.h | 1 + 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index 685612e6afc5..bfd05fd34348 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -13,17 +13,11 @@ #include "intel_fb.h" #include "intel_fbdev_fb.h" -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, - struct drm_mode_fb_cmd2 *mode_cmd) +struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size) { struct intel_display *display = to_intel_display(drm); struct drm_i915_private *dev_priv = to_i915(drm); - struct drm_framebuffer *fb; struct drm_i915_gem_object *obj; - int size; - - size = mode_cmd->pitches[0] * mode_cmd->height; - size = PAGE_ALIGN(size); obj = ERR_PTR(-ENODEV); if (HAS_LMEM(dev_priv)) { @@ -49,17 +43,36 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, return ERR_PTR(-ENOMEM); } - fb = intel_framebuffer_create(intel_bo_to_drm_bo(obj), + return &obj->base; +} + +struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_framebuffer *fb; + struct drm_gem_object *obj; + int size; + + size = mode_cmd->pitches[0] * mode_cmd->height; + size = PAGE_ALIGN(size); + + obj = intel_fbdev_fb_bo_create(drm, size); + if (IS_ERR(obj)) { + fb = ERR_CAST(obj); + goto err; + } + + fb = intel_framebuffer_create(obj, drm_get_format_info(drm, mode_cmd->pixel_format, mode_cmd->modifier[0]), mode_cmd); if (IS_ERR(fb)) { - i915_gem_object_put(obj); + drm_gem_object_put(obj); goto err; } - i915_gem_object_put(obj); + drm_gem_object_put(obj); return to_intel_framebuffer(fb); err: diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h index 83454ffbf79c..6a4ba40d5831 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -13,6 +13,7 @@ struct fb_info; struct i915_vma; struct intel_display; +struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size); struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, struct drm_mode_fb_cmd2 *mode_cmd); int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, -- cgit v1.2.3 From ec4dae5e9b2cbdadcc9e22c0472f8a2749674355 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:56 +0300 Subject: drm/xe/fbdev: abstract bo creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Separate fbdev bo creation into a separate function intel_fbdev_fb_bo_create(). Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/74dfb9f3e6e05a93d54a8ab534e4384145b52571.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 33 ++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c index 9c9fb34b3407..3ae9d41cb62c 100644 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c @@ -15,16 +15,11 @@ #include -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, - struct drm_mode_fb_cmd2 *mode_cmd) +struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size) { - struct drm_framebuffer *fb; struct xe_device *xe = to_xe_device(drm); struct xe_bo *obj; - int size; - size = mode_cmd->pitches[0] * mode_cmd->height; - size = PAGE_ALIGN(size); obj = ERR_PTR(-ENODEV); if (!IS_DGFX(xe) && !XE_GT_WA(xe_root_mmio_gt(xe), 22019338487_display)) { @@ -48,21 +43,39 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, if (IS_ERR(obj)) { drm_err(&xe->drm, "failed to allocate framebuffer (%pe)\n", obj); - fb = ERR_PTR(-ENOMEM); + return ERR_PTR(-ENOMEM); + } + + return &obj->ttm.base; +} + +struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_framebuffer *fb; + struct drm_gem_object *obj; + int size; + + size = mode_cmd->pitches[0] * mode_cmd->height; + size = PAGE_ALIGN(size); + + obj = intel_fbdev_fb_bo_create(drm, size); + if (IS_ERR(obj)) { + fb = ERR_CAST(obj); goto err; } - fb = intel_framebuffer_create(&obj->ttm.base, + fb = intel_framebuffer_create(obj, drm_get_format_info(drm, mode_cmd->pixel_format, mode_cmd->modifier[0]), mode_cmd); if (IS_ERR(fb)) { - xe_bo_unpin_map_no_vm(obj); + xe_bo_unpin_map_no_vm(gem_to_xe_bo(obj)); goto err; } - drm_gem_object_put(&obj->ttm.base); + drm_gem_object_put(obj); return to_intel_framebuffer(fb); -- cgit v1.2.3 From a170c6ca8ba84c3a901796814e4b1d07157f0620 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:57 +0300 Subject: drm/{i915, xe}/fbdev: add intel_fbdev_fb_bo_destroy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i915 and xe do different things on the failure path; i915 calls drm_gem_object_put() while xe calls xe_bo_unpin_map_no_vm(). Add a helper to enable further refactoring. v2: Call drm_gem_object_put() on intel_fbdev_fb_bo_destroy() Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/22bc3c3158f5a22ab258ada8684766fdf75fefec.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 7 ++++++- drivers/gpu/drm/i915/display/intel_fbdev_fb.h | 1 + drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 7 ++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index bfd05fd34348..a7dab8cd3aa2 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -46,6 +46,11 @@ struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size return &obj->base; } +void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) +{ + drm_gem_object_put(obj); +} + struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, struct drm_mode_fb_cmd2 *mode_cmd) { @@ -68,7 +73,7 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, mode_cmd->modifier[0]), mode_cmd); if (IS_ERR(fb)) { - drm_gem_object_put(obj); + intel_fbdev_fb_bo_destroy(obj); goto err; } diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h index 6a4ba40d5831..8b6214b0ad0e 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -14,6 +14,7 @@ struct i915_vma; struct intel_display; struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size); +void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj); struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, struct drm_mode_fb_cmd2 *mode_cmd); int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c index 3ae9d41cb62c..e1043617c3ae 100644 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c @@ -49,6 +49,11 @@ struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size return &obj->ttm.base; } +void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) +{ + xe_bo_unpin_map_no_vm(gem_to_xe_bo(obj)); +} + struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, struct drm_mode_fb_cmd2 *mode_cmd) { @@ -71,7 +76,7 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, mode_cmd->modifier[0]), mode_cmd); if (IS_ERR(fb)) { - xe_bo_unpin_map_no_vm(gem_to_xe_bo(obj)); + intel_fbdev_fb_bo_destroy(obj); goto err; } -- cgit v1.2.3 From f379035fdf89eaa7e411ab589b3a8845bc2d5481 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:58 +0300 Subject: drm/{i915,xe}/fbdev: deduplicate fbdev creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the bo creation helper in place, we can lift intel_framebuffer_create() part to common code. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/7289deac730a877ab1bfcc467f9d063fdccf3930.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbdev.c | 31 +++++++++++++++++++++--- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 34 -------------------------- drivers/gpu/drm/i915/display/intel_fbdev_fb.h | 2 -- drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 35 --------------------------- 4 files changed, 28 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index e46c08762b84..4bc9a053ca40 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -227,13 +227,38 @@ __intel_fbdev_fb_alloc(struct intel_display *display, struct drm_fb_helper_surface_size *sizes) { struct drm_mode_fb_cmd2 mode_cmd = {}; - struct intel_framebuffer *fb; + struct drm_framebuffer *fb; + struct drm_gem_object *obj; + int size; intel_fbdev_fill_mode_cmd(sizes, &mode_cmd); - fb = intel_fbdev_fb_alloc(display->drm, &mode_cmd); + size = mode_cmd.pitches[0] * mode_cmd.height; + size = PAGE_ALIGN(size); + + obj = intel_fbdev_fb_bo_create(display->drm, size); + if (IS_ERR(obj)) { + fb = ERR_CAST(obj); + goto err; + } + + fb = intel_framebuffer_create(obj, + drm_get_format_info(display->drm, + mode_cmd.pixel_format, + mode_cmd.modifier[0]), + &mode_cmd); + if (IS_ERR(fb)) { + intel_fbdev_fb_bo_destroy(obj); + goto err; + } + + drm_gem_object_put(obj); + + return to_intel_framebuffer(fb); + +err: + return ERR_CAST(fb); - return fb; } int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index a7dab8cd3aa2..c802a4b2bfc7 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -10,7 +10,6 @@ #include "i915_drv.h" #include "intel_display_core.h" #include "intel_display_types.h" -#include "intel_fb.h" #include "intel_fbdev_fb.h" struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size) @@ -51,39 +50,6 @@ void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) drm_gem_object_put(obj); } -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, - struct drm_mode_fb_cmd2 *mode_cmd) -{ - struct drm_framebuffer *fb; - struct drm_gem_object *obj; - int size; - - size = mode_cmd->pitches[0] * mode_cmd->height; - size = PAGE_ALIGN(size); - - obj = intel_fbdev_fb_bo_create(drm, size); - if (IS_ERR(obj)) { - fb = ERR_CAST(obj); - goto err; - } - - fb = intel_framebuffer_create(obj, - drm_get_format_info(drm, - mode_cmd->pixel_format, - mode_cmd->modifier[0]), - mode_cmd); - if (IS_ERR(fb)) { - intel_fbdev_fb_bo_destroy(obj); - goto err; - } - - drm_gem_object_put(obj); - - return to_intel_framebuffer(fb); -err: - return ERR_CAST(fb); -} - int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, struct drm_gem_object *_obj, struct i915_vma *vma) { diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h index 8b6214b0ad0e..3b7b59d664b5 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -15,8 +15,6 @@ struct intel_display; struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size); void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj); -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, - struct drm_mode_fb_cmd2 *mode_cmd); int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, struct drm_gem_object *obj, struct i915_vma *vma); diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c index e1043617c3ae..c23da0dd5336 100644 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c @@ -7,7 +7,6 @@ #include "intel_display_core.h" #include "intel_display_types.h" -#include "intel_fb.h" #include "intel_fbdev_fb.h" #include "xe_bo.h" #include "xe_ttm_stolen_mgr.h" @@ -54,40 +53,6 @@ void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) xe_bo_unpin_map_no_vm(gem_to_xe_bo(obj)); } -struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_device *drm, - struct drm_mode_fb_cmd2 *mode_cmd) -{ - struct drm_framebuffer *fb; - struct drm_gem_object *obj; - int size; - - size = mode_cmd->pitches[0] * mode_cmd->height; - size = PAGE_ALIGN(size); - - obj = intel_fbdev_fb_bo_create(drm, size); - if (IS_ERR(obj)) { - fb = ERR_CAST(obj); - goto err; - } - - fb = intel_framebuffer_create(obj, - drm_get_format_info(drm, - mode_cmd->pixel_format, - mode_cmd->modifier[0]), - mode_cmd); - if (IS_ERR(fb)) { - intel_fbdev_fb_bo_destroy(obj); - goto err; - } - - drm_gem_object_put(obj); - - return to_intel_framebuffer(fb); - -err: - return ERR_CAST(fb); -} - int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, struct drm_gem_object *_obj, struct i915_vma *vma) { -- cgit v1.2.3 From 5c3a68857ddb1d9544f90d2ae7f5b45b16822917 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:40:59 +0300 Subject: drm/{i915, xe}/fbdev: pass struct drm_device to intel_fbdev_fb_fill_info() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code is in fact driver core rather than display specific. Pass struct drm_device instead of struct intel_display. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/1f633154f5f3106f55d7525a711bf347f5635ea7.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbdev.c | 2 +- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 6 +++--- drivers/gpu/drm/i915/display/intel_fbdev_fb.h | 3 +-- drivers/gpu/drm/xe/display/intel_fbdev_fb.c | 6 ++---- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 4bc9a053ca40..3fbdf75415cc 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -332,7 +332,7 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, obj = intel_fb_bo(&fb->base); - ret = intel_fbdev_fb_fill_info(display, info, obj, vma); + ret = intel_fbdev_fb_fill_info(display->drm, info, obj, vma); if (ret) goto out_unpin; diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index c802a4b2bfc7..8af409bff0f0 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -50,10 +50,10 @@ void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) drm_gem_object_put(obj); } -int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, +int intel_fbdev_fb_fill_info(struct drm_device *drm, struct fb_info *info, struct drm_gem_object *_obj, struct i915_vma *vma) { - struct drm_i915_private *i915 = to_i915(display->drm); + struct drm_i915_private *i915 = to_i915(drm); struct drm_i915_gem_object *obj = to_intel_bo(_obj); struct i915_gem_ww_ctx ww; void __iomem *vaddr; @@ -85,7 +85,7 @@ int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info vaddr = i915_vma_pin_iomap(vma); if (IS_ERR(vaddr)) { - drm_err(display->drm, + drm_err(drm, "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr); ret = PTR_ERR(vaddr); continue; diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h index 3b7b59d664b5..1fa44ed28543 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -11,11 +11,10 @@ struct drm_gem_object; struct drm_mode_fb_cmd2; struct fb_info; struct i915_vma; -struct intel_display; struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size); void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj); -int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, +int intel_fbdev_fb_fill_info(struct drm_device *drm, struct fb_info *info, struct drm_gem_object *obj, struct i915_vma *vma); #endif diff --git a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c index c23da0dd5336..3dfab0c2b827 100644 --- a/drivers/gpu/drm/xe/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/xe/display/intel_fbdev_fb.c @@ -5,8 +5,6 @@ #include -#include "intel_display_core.h" -#include "intel_display_types.h" #include "intel_fbdev_fb.h" #include "xe_bo.h" #include "xe_ttm_stolen_mgr.h" @@ -53,11 +51,11 @@ void intel_fbdev_fb_bo_destroy(struct drm_gem_object *obj) xe_bo_unpin_map_no_vm(gem_to_xe_bo(obj)); } -int intel_fbdev_fb_fill_info(struct intel_display *display, struct fb_info *info, +int intel_fbdev_fb_fill_info(struct drm_device *drm, struct fb_info *info, struct drm_gem_object *_obj, struct i915_vma *vma) { struct xe_bo *obj = gem_to_xe_bo(_obj); - struct pci_dev *pdev = to_pci_dev(display->drm->dev); + struct pci_dev *pdev = to_pci_dev(drm->dev); if (!(obj->flags & XE_BO_FLAG_SYSTEM)) { if (obj->flags & XE_BO_FLAG_STOLEN) -- cgit v1.2.3 From ffce45f241833084f526d44666e9de677bd70f2b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 11:41:00 +0300 Subject: drm/i915/fbdev: drop dependency on display in i915 specific code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code is in fact i915 driver core rather than display specific. Stop using struct intel_display, and drop the dependency on display headers. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/a2faad2b47c63ea773a96b2885fb759602374264.1758184771.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbdev_fb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index 8af409bff0f0..56b145841473 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -8,13 +8,10 @@ #include "gem/i915_gem_lmem.h" #include "i915_drv.h" -#include "intel_display_core.h" -#include "intel_display_types.h" #include "intel_fbdev_fb.h" struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size) { - struct intel_display *display = to_intel_display(drm); struct drm_i915_private *dev_priv = to_i915(drm); struct drm_i915_gem_object *obj; @@ -31,7 +28,7 @@ struct drm_gem_object *intel_fbdev_fb_bo_create(struct drm_device *drm, int size * * Also skip stolen on MTL as Wa_22018444074 mitigation. */ - if (!display->platform.meteorlake && size * 2 < dev_priv->dsm.usable_size) + if (!IS_METEORLAKE(dev_priv) && size * 2 < dev_priv->dsm.usable_size) obj = i915_gem_object_create_stolen(dev_priv, size); if (IS_ERR(obj)) obj = i915_gem_object_create_shmem(dev_priv, size); -- cgit v1.2.3 From 96b8ccbe7ffa5bb49caf82167ea54a7755f06f3d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 15:25:44 +0300 Subject: drm/i915/irq: use a dedicated IMR cache for VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are three groups of platforms using i915->irq_mask independently: gen 2-4, VLV/CHV, and gen 5-7. The VLV/CHV usage is purely limited to display. Move its irq_mask usage to struct intel_display as vlv_imr_mask for VLV/CHV. vlv_imr_mask could be put inside a union with de_irq_mask[], but keep them separate to avoid accidental aliasing of the values. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/cef6dee8d0b02ff76180c5879f3056e102947a57.1758198300.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display_core.h | 5 +++++ drivers/gpu/drm/i915/display/intel_display_irq.c | 11 ++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 791021a4e3bb..48a707557c29 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -475,6 +475,11 @@ struct intel_display { struct work_struct vblank_notify_work; + /* + * Cached value of VLV/CHV IMR to avoid reads in updating the + * bitfield. + */ + u32 vlv_imr_mask; u32 de_irq_mask[I915_MAX_PIPES]; u32 pipestat_irq_mask[I915_MAX_PIPES]; } irq; diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 123e054affbe..df718670546b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -1865,8 +1865,6 @@ void vlv_display_error_irq_handler(struct intel_display *display, static void _vlv_display_irq_reset(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(display->drm); - if (display->platform.cherryview) intel_de_write(display, DPINVGTT, DPINVGTT_STATUS_MASK_CHV); else @@ -1881,7 +1879,7 @@ static void _vlv_display_irq_reset(struct intel_display *display) i9xx_pipestat_irq_reset(display); intel_display_irq_regs_reset(display, VLV_IRQ_REGS); - dev_priv->irq_mask = ~0u; + display->irq.vlv_imr_mask = ~0u; } void vlv_display_irq_reset(struct intel_display *display) @@ -1939,7 +1937,6 @@ static u32 vlv_error_mask(void) static void _vlv_display_irq_postinstall(struct intel_display *display) { - struct drm_i915_private *dev_priv = to_i915(display->drm); u32 pipestat_mask; u32 enable_mask; enum pipe pipe; @@ -1973,11 +1970,11 @@ static void _vlv_display_irq_postinstall(struct intel_display *display) enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT | I915_LPE_PIPE_C_INTERRUPT; - drm_WARN_ON(display->drm, dev_priv->irq_mask != ~0u); + drm_WARN_ON(display->drm, display->irq.vlv_imr_mask != ~0u); - dev_priv->irq_mask = ~enable_mask; + display->irq.vlv_imr_mask = ~enable_mask; - intel_display_irq_regs_init(display, VLV_IRQ_REGS, dev_priv->irq_mask, enable_mask); + intel_display_irq_regs_init(display, VLV_IRQ_REGS, display->irq.vlv_imr_mask, enable_mask); } void vlv_display_irq_postinstall(struct intel_display *display) -- cgit v1.2.3 From f2c6777dd9f733f76fb6658d62a301ed57f4cd61 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 15:25:45 +0300 Subject: drm/i915/irq: use a dedicated IMR cache for gen 5-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are three groups of platforms using i915->irq_mask independently: gen 2-4, VLV/CHV, and gen 5-7. The gen 5-7 usage is primarily limited to display. Move its irq_mask usage to struct intel_display as ilk_de_imr_mask for gen 5-7. ilk_de_imr_mask could be put inside a union with with vlv_imr_mask and de_irq_mask[], but keep them separate to avoid accidental aliasing of the values. With this, we can also drop the irq_mask member from struct xe_device. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/adf60e74b890d52dd20ab4673111ae2063d33b49.1758198300.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display_core.h | 5 +++++ drivers/gpu/drm/i915/display/intel_display_irq.c | 14 ++++++-------- drivers/gpu/drm/i915/i915_irq.c | 2 +- drivers/gpu/drm/xe/xe_device_types.h | 3 --- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 48a707557c29..4a52bbe327b7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -480,6 +480,11 @@ struct intel_display { * bitfield. */ u32 vlv_imr_mask; + /* + * Cached value of gen 5-7 DE IMR to avoid reads in updating the + * bitfield. + */ + u32 ilk_de_imr_mask; u32 de_irq_mask[I915_MAX_PIPES]; u32 pipestat_irq_mask[I915_MAX_PIPES]; } irq; diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index df718670546b..f4ba9b08e044 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -140,14 +140,14 @@ void ilk_update_display_irq(struct intel_display *display, lockdep_assert_held(&display->irq.lock); drm_WARN_ON(display->drm, enabled_irq_mask & ~interrupt_mask); - new_val = dev_priv->irq_mask; + new_val = display->irq.ilk_de_imr_mask; new_val &= ~interrupt_mask; new_val |= (~enabled_irq_mask & interrupt_mask); - if (new_val != dev_priv->irq_mask && + if (new_val != display->irq.ilk_de_imr_mask && !drm_WARN_ON(display->drm, !intel_irqs_enabled(dev_priv))) { - dev_priv->irq_mask = new_val; - intel_de_write(display, DEIMR, dev_priv->irq_mask); + display->irq.ilk_de_imr_mask = new_val; + intel_de_write(display, DEIMR, display->irq.ilk_de_imr_mask); intel_de_posting_read(display, DEIMR); } } @@ -2180,8 +2180,6 @@ out: void ilk_de_irq_postinstall(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); - u32 display_mask, extra_mask; if (DISPLAY_VER(display) >= 7) { @@ -2213,11 +2211,11 @@ void ilk_de_irq_postinstall(struct intel_display *display) if (display->platform.ironlake && display->platform.mobile) extra_mask |= DE_PCU_EVENT; - i915->irq_mask = ~display_mask; + display->irq.ilk_de_imr_mask = ~display_mask; ibx_irq_postinstall(display); - intel_display_irq_regs_init(display, DE_IRQ_REGS, i915->irq_mask, + intel_display_irq_regs_init(display, DE_IRQ_REGS, display->irq.ilk_de_imr_mask, display_mask | extra_mask); } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8d5da222a187..e5fdfd51b549 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -659,7 +659,7 @@ static void ilk_irq_reset(struct drm_i915_private *dev_priv) struct intel_uncore *uncore = &dev_priv->uncore; gen2_irq_reset(uncore, DE_IRQ_REGS); - dev_priv->irq_mask = ~0u; + display->irq.ilk_de_imr_mask = ~0u; if (GRAPHICS_VER(dev_priv) == 7) intel_uncore_write(uncore, GEN7_ERR_INT, 0xffffffff); diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 4353256452aa..79d3a59762d9 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -611,9 +611,6 @@ struct xe_device { /* To shut up runtime pm macros.. */ struct xe_runtime_pm {} runtime_pm; - /* only to allow build, not used functionally */ - u32 irq_mask; - struct intel_uncore { spinlock_t lock; } uncore; -- cgit v1.2.3 From cb4242e34ff82857ef814cbd9d77d4d73b31d0eb Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 15:25:46 +0300 Subject: drm/i915/irq: rename irq_mask to gen2_imr_mask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the struct drm_i915_private irq_mask member to gen2_imr_mask to reflect its usage more accurately. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/2c193663cd3ae524d8159b4216e45462017042fa.1758198300.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/gt/gen2_engine_cs.c | 8 ++++---- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- drivers/gpu/drm/i915/i915_irq.c | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen2_engine_cs.c b/drivers/gpu/drm/i915/gt/gen2_engine_cs.c index 8116fd5987e2..8c01fb6d4e7b 100644 --- a/drivers/gpu/drm/i915/gt/gen2_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen2_engine_cs.c @@ -292,15 +292,15 @@ int gen4_emit_bb_start(struct i915_request *rq, void gen2_irq_enable(struct intel_engine_cs *engine) { - engine->i915->irq_mask &= ~engine->irq_enable_mask; - intel_uncore_write(engine->uncore, GEN2_IMR, engine->i915->irq_mask); + engine->i915->gen2_imr_mask &= ~engine->irq_enable_mask; + intel_uncore_write(engine->uncore, GEN2_IMR, engine->i915->gen2_imr_mask); intel_uncore_posting_read_fw(engine->uncore, GEN2_IMR); } void gen2_irq_disable(struct intel_engine_cs *engine) { - engine->i915->irq_mask |= engine->irq_enable_mask; - intel_uncore_write(engine->uncore, GEN2_IMR, engine->i915->irq_mask); + engine->i915->gen2_imr_mask |= engine->irq_enable_mask; + intel_uncore_write(engine->uncore, GEN2_IMR, engine->i915->gen2_imr_mask); } void gen5_irq_enable(struct intel_engine_cs *engine) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 37970d8db255..03e497d2081e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -234,8 +234,8 @@ struct drm_i915_private { /* Sideband mailbox protection */ struct mutex sb_lock; - /** Cached value of IMR to avoid reads in updating the bitfield */ - u32 irq_mask; + /* Cached value of gen 2-4 IMR to avoid reads in updating the bitfield */ + u32 gen2_imr_mask; bool preserve_bios_swizzle; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e5fdfd51b549..ab65402bc6bf 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -897,7 +897,7 @@ static void i915_irq_reset(struct drm_i915_private *dev_priv) gen2_error_reset(uncore, GEN2_ERROR_REGS); gen2_irq_reset(uncore, GEN2_IRQ_REGS); - dev_priv->irq_mask = ~0u; + dev_priv->gen2_imr_mask = ~0u; } static void i915_irq_postinstall(struct drm_i915_private *dev_priv) @@ -908,7 +908,7 @@ static void i915_irq_postinstall(struct drm_i915_private *dev_priv) gen2_error_init(uncore, GEN2_ERROR_REGS, ~i9xx_error_mask(dev_priv)); - dev_priv->irq_mask = + dev_priv->gen2_imr_mask = ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | I915_MASTER_ERROR_INTERRUPT); @@ -920,16 +920,16 @@ static void i915_irq_postinstall(struct drm_i915_private *dev_priv) I915_USER_INTERRUPT; if (DISPLAY_VER(display) >= 3) { - dev_priv->irq_mask &= ~I915_ASLE_INTERRUPT; + dev_priv->gen2_imr_mask &= ~I915_ASLE_INTERRUPT; enable_mask |= I915_ASLE_INTERRUPT; } if (HAS_HOTPLUG(display)) { - dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT; + dev_priv->gen2_imr_mask &= ~I915_DISPLAY_PORT_INTERRUPT; enable_mask |= I915_DISPLAY_PORT_INTERRUPT; } - gen2_irq_init(uncore, GEN2_IRQ_REGS, dev_priv->irq_mask, enable_mask); + gen2_irq_init(uncore, GEN2_IRQ_REGS, dev_priv->gen2_imr_mask, enable_mask); i915_display_irq_postinstall(display); } @@ -999,7 +999,7 @@ static void i965_irq_reset(struct drm_i915_private *dev_priv) gen2_error_reset(uncore, GEN2_ERROR_REGS); gen2_irq_reset(uncore, GEN2_IRQ_REGS); - dev_priv->irq_mask = ~0u; + dev_priv->gen2_imr_mask = ~0u; } static u32 i965_error_mask(struct drm_i915_private *i915) @@ -1029,7 +1029,7 @@ static void i965_irq_postinstall(struct drm_i915_private *dev_priv) gen2_error_init(uncore, GEN2_ERROR_REGS, ~i965_error_mask(dev_priv)); - dev_priv->irq_mask = + dev_priv->gen2_imr_mask = ~(I915_ASLE_INTERRUPT | I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | @@ -1047,7 +1047,7 @@ static void i965_irq_postinstall(struct drm_i915_private *dev_priv) if (IS_G4X(dev_priv)) enable_mask |= I915_BSD_USER_INTERRUPT; - gen2_irq_init(uncore, GEN2_IRQ_REGS, dev_priv->irq_mask, enable_mask); + gen2_irq_init(uncore, GEN2_IRQ_REGS, dev_priv->gen2_imr_mask, enable_mask); i965_display_irq_postinstall(display); } -- cgit v1.2.3 From a5ef491e903e4bbb681bdaddfc2bcd7cdf43cea6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 15:25:47 +0300 Subject: drm/i915/irq: rename de_irq_mask[] to de_pipe_imr_mask[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the struct intel_display de_irq_mask[] member to de_pipe_imr_mask[] to reflect its usage more accurately. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/55bbf17df871331c2c34af748cf9cf812d6a65d7.1758198300.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display_core.h | 6 +++++- drivers/gpu/drm/i915/display/intel_display_irq.c | 16 ++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 4a52bbe327b7..df4da52cbdb3 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -485,7 +485,11 @@ struct intel_display { * bitfield. */ u32 ilk_de_imr_mask; - u32 de_irq_mask[I915_MAX_PIPES]; + /* + * Cached value of BDW+ DE pipe IMR to avoid reads in updating + * the bitfield. + */ + u32 de_pipe_imr_mask[I915_MAX_PIPES]; u32 pipestat_irq_mask[I915_MAX_PIPES]; } irq; diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index f4ba9b08e044..93c2e42f98c9 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -215,13 +215,13 @@ static void bdw_update_pipe_irq(struct intel_display *display, if (drm_WARN_ON(display->drm, !intel_irqs_enabled(dev_priv))) return; - new_val = display->irq.de_irq_mask[pipe]; + new_val = display->irq.de_pipe_imr_mask[pipe]; new_val &= ~interrupt_mask; new_val |= (~enabled_irq_mask & interrupt_mask); - if (new_val != display->irq.de_irq_mask[pipe]) { - display->irq.de_irq_mask[pipe] = new_val; - intel_de_write(display, GEN8_DE_PIPE_IMR(pipe), display->irq.de_irq_mask[pipe]); + if (new_val != display->irq.de_pipe_imr_mask[pipe]) { + display->irq.de_pipe_imr_mask[pipe] = new_val; + intel_de_write(display, GEN8_DE_PIPE_IMR(pipe), display->irq.de_pipe_imr_mask[pipe]); intel_de_posting_read(display, GEN8_DE_PIPE_IMR(pipe)); } } @@ -2085,8 +2085,8 @@ void gen8_irq_power_well_post_enable(struct intel_display *display, for_each_pipe_masked(display, pipe, pipe_mask) intel_display_irq_regs_init(display, GEN8_DE_PIPE_IRQ_REGS(pipe), - display->irq.de_irq_mask[pipe], - ~display->irq.de_irq_mask[pipe] | extra_ier); + display->irq.de_pipe_imr_mask[pipe], + ~display->irq.de_pipe_imr_mask[pipe] | extra_ier); spin_unlock_irq(&display->irq.lock); } @@ -2300,12 +2300,12 @@ void gen8_de_irq_postinstall(struct intel_display *display) } for_each_pipe(display, pipe) { - display->irq.de_irq_mask[pipe] = ~de_pipe_masked; + display->irq.de_pipe_imr_mask[pipe] = ~de_pipe_masked; if (intel_display_power_is_enabled(display, POWER_DOMAIN_PIPE(pipe))) intel_display_irq_regs_init(display, GEN8_DE_PIPE_IRQ_REGS(pipe), - display->irq.de_irq_mask[pipe], + display->irq.de_pipe_imr_mask[pipe], de_pipe_enables); } -- cgit v1.2.3 From 4c26361cc68f72299a8d0eea48734e39eb3b78b3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Sep 2025 16:38:35 +0300 Subject: drm/i915/irq: add ilk_display_irq_reset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Abstract ilk_display_irq_reset(), moving display related reset there. This results in a slightly different order between GT and PCH reset, hopefully with no impact. v3: Reset display first (Ville) v2: Also move GEN7_ERR_INT (Ville) Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/20250918133835.2412980-1-jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display_irq.c | 20 +++++++++++++++++++- drivers/gpu/drm/i915/display/intel_display_irq.h | 2 +- drivers/gpu/drm/i915/i915_irq.c | 16 ++-------------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 93c2e42f98c9..c6f367e6159e 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -1985,7 +1985,7 @@ void vlv_display_irq_postinstall(struct intel_display *display) spin_unlock_irq(&display->irq.lock); } -void ibx_display_irq_reset(struct intel_display *display) +static void ibx_display_irq_reset(struct intel_display *display) { if (HAS_PCH_NOP(display)) return; @@ -1996,6 +1996,24 @@ void ibx_display_irq_reset(struct intel_display *display) intel_de_write(display, SERR_INT, 0xffffffff); } +void ilk_display_irq_reset(struct intel_display *display) +{ + struct intel_uncore *uncore = to_intel_uncore(display->drm); + + gen2_irq_reset(uncore, DE_IRQ_REGS); + display->irq.ilk_de_imr_mask = ~0u; + + if (DISPLAY_VER(display) == 7) + intel_de_write(display, GEN7_ERR_INT, 0xffffffff); + + if (display->platform.haswell) { + intel_de_write(display, EDP_PSR_IMR, 0xffffffff); + intel_de_write(display, EDP_PSR_IIR, 0xffffffff); + } + + ibx_display_irq_reset(display); +} + void gen8_display_irq_reset(struct intel_display *display) { enum pipe pipe; diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.h b/drivers/gpu/drm/i915/display/intel_display_irq.h index c66db3851da4..cee120347064 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.h +++ b/drivers/gpu/drm/i915/display/intel_display_irq.h @@ -56,7 +56,7 @@ u32 gen11_gu_misc_irq_ack(struct intel_display *display, const u32 master_ctl); void gen11_gu_misc_irq_handler(struct intel_display *display, const u32 iir); void i9xx_display_irq_reset(struct intel_display *display); -void ibx_display_irq_reset(struct intel_display *display); +void ilk_display_irq_reset(struct intel_display *display); void vlv_display_irq_reset(struct intel_display *display); void gen8_display_irq_reset(struct intel_display *display); void gen11_display_irq_reset(struct intel_display *display); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ab65402bc6bf..7c7c6dcbce88 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -656,22 +656,10 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg) static void ilk_irq_reset(struct drm_i915_private *dev_priv) { struct intel_display *display = dev_priv->display; - struct intel_uncore *uncore = &dev_priv->uncore; - - gen2_irq_reset(uncore, DE_IRQ_REGS); - display->irq.ilk_de_imr_mask = ~0u; - - if (GRAPHICS_VER(dev_priv) == 7) - intel_uncore_write(uncore, GEN7_ERR_INT, 0xffffffff); - - if (IS_HASWELL(dev_priv)) { - intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff); - intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff); - } + /* The master interrupt enable is in DEIER, reset display irq first */ + ilk_display_irq_reset(display); gen5_gt_irq_reset(to_gt(dev_priv)); - - ibx_display_irq_reset(display); } static void valleyview_irq_reset(struct drm_i915_private *dev_priv) -- cgit v1.2.3 From cef58ce505a04a896d59cb207f0a0ccea1eec5ca Mon Sep 17 00:00:00 2001 From: Nemesa Garg Date: Wed, 13 Aug 2025 10:50:17 +0530 Subject: drm/i915: Soft defeature of cursor size reduction From display 14 onward do not enable the cursor size reduction bit as it has been defeatured. Bspec: 50372 Signed-off-by: Nemesa Garg Reviewed-by: Chaitanya Kumar Borah Signed-off-by: Animesh Manna Link: https://lore.kernel.org/r/20250813052017.3591331-1-nemesa.garg@intel.com --- drivers/gpu/drm/i915/display/intel_cursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index d4d181f9dca5..c47c84935871 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -662,7 +662,7 @@ static void i9xx_cursor_update_arm(struct intel_dsb *dsb, cntl = plane_state->ctl | i9xx_cursor_ctl_crtc(crtc_state); - if (width != height) + if (DISPLAY_VER(display) < 14 && width != height) fbc_ctl = CUR_FBC_EN | CUR_FBC_HEIGHT(height - 1); base = plane_state->surf; -- cgit v1.2.3 From db7944458f4e5cdc11402e18ccbbc7aac4286f4b Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 9 Sep 2025 11:30:11 +0300 Subject: drm/i915/dmc: explicitly sanitize num_entries from package_header num_entries comes from package_header, which is read from an external firmware blob and thus untrusted. In parse_dmc_fw_package() we assign package_header->num_entries to a local variable, but the range check still uses the struct field directly. Switch the check to use the local copy instead. This makes the sanitization explicit and avoids a redundant dereference. Reviewed-by: Mitul Golani Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/20250909083042.1292672-1-luciano.coelho@intel.com --- drivers/gpu/drm/i915/display/intel_dmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 77a0199f9ea5..517bebb0b4aa 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -1141,7 +1141,7 @@ parse_dmc_fw_package(struct intel_dmc *dmc, } num_entries = package_header->num_entries; - if (WARN_ON(package_header->num_entries > max_entries)) + if (WARN_ON(num_entries > max_entries)) num_entries = max_entries; fw_info = (const struct intel_fw_info *) -- cgit v1.2.3 From fab82f47246b768c0ea51564e4a3f2ad9e6fa7d3 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 02:22:25 +0300 Subject: drm/i915/vrr: Hide the ICL/TGL intel_vrr_flipline_offset() mangling better MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ICL/TGL VRR hardware won't allow us to program flipline==vmin. If we do that the actual effect will be the same as if we had programmed flipline=vmin+1, which would make the minimum vtotal one scanline taller than expected. To compensate for this we reduce vmin by one, and then program flipline=vmin+1. So we end up with a flipline value that matches the expected minimum vtotal. Currently this adjustment happens in intel_vrr_compute_config() which means that crtc_state->vrr.vmin will no longer be directly usable for the remainder of the high level VRR code. That is annoying at best, fragile at worst. Hide the adjustment in low level code instead. This will allow most of the higher level VRR code to remain blissfully ignorant about this fact. Afterwards crtc_state->vrr.{vmin,flipline} will be equal and match the minimum vtotal, exactly how things already work on ADL+. The only slight downside is that the actual register value will no longer match crtc_state->vrr.vmin on ICL/TGL, but that may already be the case on TGL because the register value will also have been adjusted by the SCL. Note that we must change the guardband calculation to account for intel_vrr_extra_vblank_delay() explicitly. Previously that was accidentally handled by the earlier vmin reduction by intel_vrr_flipline_offset(). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250918232226.25295-2-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_vrr.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 71a985d00604..e725b4581e81 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -108,15 +108,20 @@ int intel_vrr_vblank_delay(const struct intel_crtc_state *crtc_state) static int intel_vrr_flipline_offset(struct intel_display *display) { - /* ICL/TGL hardware imposes flipline>=vmin+1 */ + /* + * ICL/TGL hardware imposes flipline>=vmin+1 + * + * We reduce the vmin value to compensate when programming the + * hardware. This approach allows flipline to remain set at the + * original value, and thus the frame will have the desired + * minimum vtotal. + */ return DISPLAY_VER(display) < 13 ? 1 : 0; } static int intel_vrr_vmin_flipline(const struct intel_crtc_state *crtc_state) { - struct intel_display *display = to_intel_display(crtc_state); - - return crtc_state->vrr.vmin + intel_vrr_flipline_offset(display); + return crtc_state->vrr.vmin; } static int intel_vrr_guardband_to_pipeline_full(const struct intel_crtc_state *crtc_state, @@ -400,13 +405,6 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state, else intel_vrr_compute_fixed_rr_timings(crtc_state); - /* - * flipline determines the min vblank length the hardware will - * generate, and on ICL/TGL flipline>=vmin+1, hence we reduce - * vmin by one to make sure we can get the actual min vblank length. - */ - crtc_state->vrr.vmin -= intel_vrr_flipline_offset(display); - if (HAS_AS_SDP(display)) { crtc_state->vrr.vsync_start = (crtc_state->hw.adjusted_mode.crtc_vtotal - @@ -426,7 +424,8 @@ void intel_vrr_compute_config_late(struct intel_crtc_state *crtc_state) return; crtc_state->vrr.guardband = - crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start; + crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start - + intel_vrr_extra_vblank_delay(display); if (DISPLAY_VER(display) < 13) { /* FIXME handle the limit in a proper way */ @@ -597,7 +596,10 @@ void intel_vrr_set_db_point_and_transmission_line(const struct intel_crtc_state static int intel_vrr_hw_vmin(const struct intel_crtc_state *crtc_state) { - return intel_vrr_hw_value(crtc_state, crtc_state->vrr.vmin); + struct intel_display *display = to_intel_display(crtc_state); + + return intel_vrr_hw_value(crtc_state, crtc_state->vrr.vmin) - + intel_vrr_flipline_offset(display); } static int intel_vrr_hw_vmax(const struct intel_crtc_state *crtc_state) @@ -762,6 +764,8 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) crtc_state->vrr.flipline += intel_vrr_real_vblank_delay(crtc_state); crtc_state->vrr.vmax += intel_vrr_real_vblank_delay(crtc_state); crtc_state->vrr.vmin += intel_vrr_real_vblank_delay(crtc_state); + + crtc_state->vrr.vmin += intel_vrr_flipline_offset(display); } /* -- cgit v1.2.3 From 50720b6708010333a857ff572ff9e4387ba0fd1a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 02:22:26 +0300 Subject: drm/i915/vrr: s/intel_vrr_flipline_offset/intel_vrr_vmin_flipline_offset/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename intel_vrr_flipline_offset() to intel_vrr_vmin_flipline_offset() to better reflect the fact that it gives us the minimum offset allowed between vmin and flipline. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250918232226.25295-3-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_vrr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index e725b4581e81..9e007aab1452 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -106,7 +106,7 @@ int intel_vrr_vblank_delay(const struct intel_crtc_state *crtc_state) intel_vrr_extra_vblank_delay(display); } -static int intel_vrr_flipline_offset(struct intel_display *display) +static int intel_vrr_vmin_flipline_offset(struct intel_display *display) { /* * ICL/TGL hardware imposes flipline>=vmin+1 @@ -288,7 +288,7 @@ int intel_vrr_fixed_rr_hw_vmin(const struct intel_crtc_state *crtc_state) struct intel_display *display = to_intel_display(crtc_state); return intel_vrr_fixed_rr_hw_vtotal(crtc_state) - - intel_vrr_flipline_offset(display); + intel_vrr_vmin_flipline_offset(display); } static @@ -599,7 +599,7 @@ static int intel_vrr_hw_vmin(const struct intel_crtc_state *crtc_state) struct intel_display *display = to_intel_display(crtc_state); return intel_vrr_hw_value(crtc_state, crtc_state->vrr.vmin) - - intel_vrr_flipline_offset(display); + intel_vrr_vmin_flipline_offset(display); } static int intel_vrr_hw_vmax(const struct intel_crtc_state *crtc_state) @@ -765,7 +765,7 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) crtc_state->vrr.vmax += intel_vrr_real_vblank_delay(crtc_state); crtc_state->vrr.vmin += intel_vrr_real_vblank_delay(crtc_state); - crtc_state->vrr.vmin += intel_vrr_flipline_offset(display); + crtc_state->vrr.vmin += intel_vrr_vmin_flipline_offset(display); } /* -- cgit v1.2.3 From c8e8e9ab14a6ea926641d161768e1e3ef286a853 Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Mon, 8 Sep 2025 09:52:08 +0530 Subject: drm/i915/ddi: Guard reg_val against a INVALID_TRANSCODER Currently we check if the encoder is INVALID or -1 and throw a WARN_ON but we still end up writing the temp value which will overflow and corrupt the whole programmed value. --v2 -Assign a bogus transcoder to master in case we get a INVALID TRANSCODER [Jani] Fixes: 6671c367a9bea ("drm/i915/tgl: Select master transcoder for MST stream") Signed-off-by: Suraj Kandpal Reviewed-by: Jani Nikula Link: https://lore.kernel.org/r/20250908042208.1011144-1-suraj.kandpal@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 08083ac83a74..c09aa759f4d4 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -597,8 +597,9 @@ intel_ddi_transcoder_func_reg_val_get(struct intel_encoder *encoder, enum transcoder master; master = crtc_state->mst_master_transcoder; - drm_WARN_ON(display->drm, - master == INVALID_TRANSCODER); + if (drm_WARN_ON(display->drm, + master == INVALID_TRANSCODER)) + master = TRANSCODER_A; temp |= TRANS_DDI_MST_TRANSPORT_SELECT(master); } } else { -- cgit v1.2.3 From 90930b637dce2e600728829250645734929d7388 Mon Sep 17 00:00:00 2001 From: Michał Grzelak Date: Fri, 19 Sep 2025 23:54:13 +0200 Subject: drm/i915: rename vlv_get_cck_clock() to vlv_clock_get_cck() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep the convention of naming vlv_clock* instead of vlv_*_clock. Signed-off-by: Michał Grzelak Link: https://lore.kernel.org/r/20250919215413.1006296-1-michal.grzelak@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/vlv_clock.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/vlv_clock.c b/drivers/gpu/drm/i915/display/vlv_clock.c index 42c2837b32c1..1abdae453514 100644 --- a/drivers/gpu/drm/i915/display/vlv_clock.c +++ b/drivers/gpu/drm/i915/display/vlv_clock.c @@ -36,7 +36,7 @@ int vlv_clock_get_hpll_vco(struct drm_device *drm) return display->vlv_clock.hpll_freq; } -static int vlv_get_cck_clock(struct drm_device *drm, +static int vlv_clock_get_cck(struct drm_device *drm, const char *name, u32 reg, int ref_freq) { u32 val; @@ -58,7 +58,7 @@ static int vlv_get_cck_clock(struct drm_device *drm, int vlv_clock_get_hrawclk(struct drm_device *drm) { /* RAWCLK_FREQ_VLV register updated from power well code */ - return vlv_get_cck_clock(drm, "hrawclk", CCK_DISPLAY_REF_CLOCK_CONTROL, + return vlv_clock_get_cck(drm, "hrawclk", CCK_DISPLAY_REF_CLOCK_CONTROL, vlv_clock_get_hpll_vco(drm)); } @@ -67,7 +67,7 @@ int vlv_clock_get_czclk(struct drm_device *drm) struct intel_display *display = to_intel_display(drm); if (!display->vlv_clock.czclk_freq) { - display->vlv_clock.czclk_freq = vlv_get_cck_clock(drm, "czclk", CCK_CZ_CLOCK_CONTROL, + display->vlv_clock.czclk_freq = vlv_clock_get_cck(drm, "czclk", CCK_CZ_CLOCK_CONTROL, vlv_clock_get_hpll_vco(drm)); drm_dbg_kms(drm, "CZ clock rate: %d kHz\n", display->vlv_clock.czclk_freq); } @@ -77,12 +77,12 @@ int vlv_clock_get_czclk(struct drm_device *drm) int vlv_clock_get_cdclk(struct drm_device *drm) { - return vlv_get_cck_clock(drm, "cdclk", CCK_DISPLAY_CLOCK_CONTROL, + return vlv_clock_get_cck(drm, "cdclk", CCK_DISPLAY_CLOCK_CONTROL, vlv_clock_get_hpll_vco(drm)); } int vlv_clock_get_gpll(struct drm_device *drm) { - return vlv_get_cck_clock(drm, "GPLL ref", CCK_GPLL_CLOCK_CONTROL, + return vlv_clock_get_cck(drm, "GPLL ref", CCK_GPLL_CLOCK_CONTROL, vlv_clock_get_czclk(drm)); } -- cgit v1.2.3 From bc412f9a993b49b1af22cc4c2f834f4350b06957 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 21:50:10 +0300 Subject: drm/i915/pm: Simplify pm hook documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop spelling out each variant of the hook ("" vs. "_late" vs. "_early") and just say eg. "@thaw*" to indicate all of them. Avoids having to update the docs whenever we start/stop using one of the variants. Reviewed-by: Rodrigo Vivi Reviewed-by: Jouni Högander Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919185015.14561-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_driver.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index a28c3710c4d5..76bda4376fe0 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1670,18 +1670,18 @@ const struct dev_pm_ops i915_pm_ops = { /* * S4 event handlers - * @freeze, @freeze_late : called (1) before creating the - * hibernation image [PMSG_FREEZE] and - * (2) after rebooting, before restoring - * the image [PMSG_QUIESCE] - * @thaw, @thaw_early : called (1) after creating the hibernation - * image, before writing it [PMSG_THAW] - * and (2) after failing to create or - * restore the image [PMSG_RECOVER] - * @poweroff, @poweroff_late: called after writing the hibernation - * image, before rebooting [PMSG_HIBERNATE] - * @restore, @restore_early : called after rebooting and restoring the - * hibernation image [PMSG_RESTORE] + * @freeze* : called (1) before creating the + * hibernation image [PMSG_FREEZE] and + * (2) after rebooting, before restoring + * the image [PMSG_QUIESCE] + * @thaw* : called (1) after creating the hibernation + * image, before writing it [PMSG_THAW] + * and (2) after failing to create or + * restore the image [PMSG_RECOVER] + * @poweroff* : called after writing the hibernation + * image, before rebooting [PMSG_HIBERNATE] + * @restore* : called after rebooting and restoring the + * hibernation image [PMSG_RESTORE] */ .freeze = i915_pm_freeze, .freeze_late = i915_pm_freeze_late, -- cgit v1.2.3 From cead397a976dde554f5bfba48a06f49c29bc3982 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 21:50:11 +0300 Subject: drm/i915/pm: Hoist pci_save_state()+pci_set_power_state() to the end of pm _late() hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/pci does the pci_save_state()+pci_set_power_state() from the _noirq() pm hooks. Move our manual calls (needed for the hibernate vs. D3 workaround with buggy BIOSes) towards that same point. We currently have no _noirq() hooks, so end of _late() hooks is the best we can do right now. Reviewed-by: Rodrigo Vivi Reviewed-by: Jouni Högander Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919185015.14561-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_driver.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 76bda4376fe0..66f2acacd516 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1053,7 +1053,6 @@ static int i915_drm_suspend(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); struct intel_display *display = dev_priv->display; - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); pci_power_t opregion_target_state; disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); @@ -1067,8 +1066,6 @@ static int i915_drm_suspend(struct drm_device *dev) intel_display_driver_disable_user_access(display); } - pci_save_state(pdev); - intel_display_driver_suspend(display); intel_irq_suspend(dev_priv); @@ -1125,10 +1122,16 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) drm_err(&dev_priv->drm, "Suspend complete failed: %d\n", ret); intel_display_power_resume_early(display); - goto out; + goto fail; } + enable_rpm_wakeref_asserts(rpm); + + if (!dev_priv->uncore.user_forcewake_count) + intel_runtime_pm_driver_release(rpm); + pci_disable_device(pdev); + /* * During hibernation on some platforms the BIOS may try to access * the device even though it's already in D3 and hang the machine. So @@ -1140,11 +1143,17 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) * Lenovo Thinkpad X301, X61s, X60, T60, X41 * Fujitsu FSC S7110 * Acer Aspire 1830T + * + * pci_save_state() prevents drivers/pci from + * automagically putting the device into D3. */ + pci_save_state(pdev); if (!(hibernation && GRAPHICS_VER(dev_priv) < 6)) pci_set_power_state(pdev, PCI_D3hot); -out: + return 0; + +fail: enable_rpm_wakeref_asserts(rpm); if (!dev_priv->uncore.user_forcewake_count) intel_runtime_pm_driver_release(rpm); -- cgit v1.2.3 From f3d8e898ce5e97b2fbc3321b8fbfd31826357f6e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 21:50:12 +0300 Subject: drm/i915/pm: Move the hibernate+D3 quirk stuff into noirq() pm hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the driver doesn't call pci_save_state() drivers/pci will normally save+power manage the device from the _noirq() pm hooks. We can't let that happen as some old BIOSes fail to hibernate when the device is in D3. However, we can get very close to the standard behaviour by doing our explicit pci_save_state() and pci_set_power_state() stuff from driver provided _noirq() hooks. This results in a change of behaviour where we no longer go into D3 at the end of freeze_late, so when it comes time to thaw() we'll already be in D0, and thus we can drop the explicit pci_set_power_state(D0) call. Presumably switcheroo suspend will want to go into D3 so call the _noirq() stuff from the switcheroo suspend hook, and since we dropped the pci_set_power_state(D0) from resume_early() we'll need to add one back into the switcheroo resume hook. Cc: Rodrigo Vivi Reviewed-by: Jouni Högander Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919185015.14561-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_driver.c | 76 +++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 66f2acacd516..327e5fe7dfff 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1132,6 +1132,21 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) pci_disable_device(pdev); + return 0; + +fail: + enable_rpm_wakeref_asserts(rpm); + if (!dev_priv->uncore.user_forcewake_count) + intel_runtime_pm_driver_release(rpm); + + return ret; +} + +static int i915_drm_suspend_noirq(struct drm_device *dev, bool hibernation) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + /* * During hibernation on some platforms the BIOS may try to access * the device even though it's already in D3 and hang the machine. So @@ -1152,13 +1167,6 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) pci_set_power_state(pdev, PCI_D3hot); return 0; - -fail: - enable_rpm_wakeref_asserts(rpm); - if (!dev_priv->uncore.user_forcewake_count) - intel_runtime_pm_driver_release(rpm); - - return ret; } int i915_driver_suspend_switcheroo(struct drm_i915_private *i915, @@ -1177,7 +1185,15 @@ int i915_driver_suspend_switcheroo(struct drm_i915_private *i915, if (error) return error; - return i915_drm_suspend_late(&i915->drm, false); + error = i915_drm_suspend_late(&i915->drm, false); + if (error) + return error; + + error = i915_drm_suspend_noirq(&i915->drm, false); + if (error) + return error; + + return 0; } static int i915_drm_resume(struct drm_device *dev) @@ -1283,23 +1299,6 @@ static int i915_drm_resume_early(struct drm_device *dev) * similar so that power domains can be employed. */ - /* - * Note that we need to set the power state explicitly, since we - * powered off the device during freeze and the PCI core won't power - * it back up for us during thaw. Powering off the device during - * freeze is not a hard requirement though, and during the - * suspend/resume phases the PCI core makes sure we get here with the - * device powered on. So in case we change our freeze logic and keep - * the device powered we can also remove the following set power state - * call. - */ - ret = pci_set_power_state(pdev, PCI_D0); - if (ret) { - drm_err(&dev_priv->drm, - "failed to set PCI D0 power state (%d)\n", ret); - return ret; - } - /* * Note that pci_enable_device() first enables any parent bridge * device and only then sets the power state for this device. The @@ -1337,11 +1336,16 @@ static int i915_drm_resume_early(struct drm_device *dev) int i915_driver_resume_switcheroo(struct drm_i915_private *i915) { + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); int ret; if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) return 0; + ret = pci_set_power_state(pdev, PCI_D0); + if (ret) + return ret; + ret = i915_drm_resume_early(&i915->drm); if (ret) return ret; @@ -1398,6 +1402,16 @@ static int i915_pm_suspend_late(struct device *kdev) return i915_drm_suspend_late(&i915->drm, false); } +static int i915_pm_suspend_noirq(struct device *kdev) +{ + struct drm_i915_private *i915 = kdev_to_i915(kdev); + + if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + + return i915_drm_suspend_noirq(&i915->drm, false); +} + static int i915_pm_poweroff_late(struct device *kdev) { struct drm_i915_private *i915 = kdev_to_i915(kdev); @@ -1408,6 +1422,16 @@ static int i915_pm_poweroff_late(struct device *kdev) return i915_drm_suspend_late(&i915->drm, true); } +static int i915_pm_poweroff_noirq(struct device *kdev) +{ + struct drm_i915_private *i915 = kdev_to_i915(kdev); + + if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + + return i915_drm_suspend_noirq(&i915->drm, true); +} + static int i915_pm_resume_early(struct device *kdev) { struct drm_i915_private *i915 = kdev_to_i915(kdev); @@ -1673,6 +1697,7 @@ const struct dev_pm_ops i915_pm_ops = { .prepare = i915_pm_prepare, .suspend = i915_pm_suspend, .suspend_late = i915_pm_suspend_late, + .suspend_noirq = i915_pm_suspend_noirq, .resume_early = i915_pm_resume_early, .resume = i915_pm_resume, .complete = i915_pm_complete, @@ -1698,6 +1723,7 @@ const struct dev_pm_ops i915_pm_ops = { .thaw = i915_pm_thaw, .poweroff = i915_pm_suspend, .poweroff_late = i915_pm_poweroff_late, + .poweroff_noirq = i915_pm_poweroff_noirq, .restore_early = i915_pm_restore_early, .restore = i915_pm_restore, -- cgit v1.2.3 From 03a37f5c3a169bea3c25b1e07e632cd0ddbcf302 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 21:50:13 +0300 Subject: drm/i915/pm: Do pci_restore_state() in switcheroo resume hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since this switcheroo garbage bypasses all the core pm we have to manually manage the pci state. To that end add the missing pci_restore_state() to the switcheroo resume hook. We already have the pci_save_state() counterpart on the suspend side. Arguably none of this code should exist in the driver in the first place, and instead the entire switcheroo mechanism should be rewritten and properly integrated into core pm code... Reviewed-by: Rodrigo Vivi Reviewed-by: Jouni Högander Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919185015.14561-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_driver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 327e5fe7dfff..009f4e27cf49 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1346,6 +1346,8 @@ int i915_driver_resume_switcheroo(struct drm_i915_private *i915) if (ret) return ret; + pci_restore_state(pdev); + ret = i915_drm_resume_early(&i915->drm); if (ret) return ret; -- cgit v1.2.3 From 3a3d9cb0b18df22d0d6466e3eca45cd0ad2ddbc8 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 21:50:14 +0300 Subject: drm/i915/pm: Allow drivers/pci to manage our pci state normally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop doing the pci_save_state(), except when we need to prevent D3 due to BIOS bugs, so that the code in drivers/pci is allowed to manage the state of the PCI device. Less chance something getting left by the wayside by i915 if/when the things change in drivers/pci. Cc: Badal Nilawar Reviewed-by: Jouni Högander Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919185015.14561-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_driver.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 009f4e27cf49..0cb874e64971 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1162,9 +1162,8 @@ static int i915_drm_suspend_noirq(struct drm_device *dev, bool hibernation) * pci_save_state() prevents drivers/pci from * automagically putting the device into D3. */ - pci_save_state(pdev); - if (!(hibernation && GRAPHICS_VER(dev_priv) < 6)) - pci_set_power_state(pdev, PCI_D3hot); + if (hibernation && GRAPHICS_VER(dev_priv) < 6) + pci_save_state(pdev); return 0; } @@ -1172,6 +1171,7 @@ static int i915_drm_suspend_noirq(struct drm_device *dev, bool hibernation) int i915_driver_suspend_switcheroo(struct drm_i915_private *i915, pm_message_t state) { + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); int error; if (drm_WARN_ON_ONCE(&i915->drm, state.event != PM_EVENT_SUSPEND && @@ -1189,9 +1189,8 @@ int i915_driver_suspend_switcheroo(struct drm_i915_private *i915, if (error) return error; - error = i915_drm_suspend_noirq(&i915->drm, false); - if (error) - return error; + pci_save_state(pdev); + pci_set_power_state(pdev, PCI_D3hot); return 0; } -- cgit v1.2.3 From 97fd25f8b6380525dafe4f3b8f7f215ac8560caf Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 21:50:15 +0300 Subject: drm/i915/pm: Drop redundant pci stuff from suspend/resume paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I don't think there should be any need for us to call any of pci_enable_device(), pci_disable_device() or pci_set_master() from the suspend/resume paths. The config space save/restore should take care of all of this. Cc: Karthik Poosa Reviewed-by: Jouni Högander Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919185015.14561-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_driver.c | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 0cb874e64971..95165e45de74 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1100,7 +1100,6 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) { struct drm_i915_private *dev_priv = to_i915(dev); struct intel_display *display = dev_priv->display; - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; struct intel_gt *gt; int ret, i; @@ -1121,21 +1120,10 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) if (ret) { drm_err(&dev_priv->drm, "Suspend complete failed: %d\n", ret); intel_display_power_resume_early(display); - - goto fail; } enable_rpm_wakeref_asserts(rpm); - if (!dev_priv->uncore.user_forcewake_count) - intel_runtime_pm_driver_release(rpm); - - pci_disable_device(pdev); - - return 0; - -fail: - enable_rpm_wakeref_asserts(rpm); if (!dev_priv->uncore.user_forcewake_count) intel_runtime_pm_driver_release(rpm); @@ -1284,7 +1272,6 @@ static int i915_drm_resume_early(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); struct intel_display *display = dev_priv->display; - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); struct intel_gt *gt; int ret, i; @@ -1298,24 +1285,6 @@ static int i915_drm_resume_early(struct drm_device *dev) * similar so that power domains can be employed. */ - /* - * Note that pci_enable_device() first enables any parent bridge - * device and only then sets the power state for this device. The - * bridge enabling is a nop though, since bridge devices are resumed - * first. The order of enabling power and enabling the device is - * imposed by the PCI core as described above, so here we preserve the - * same order for the freeze/thaw phases. - * - * TODO: eventually we should remove pci_disable_device() / - * pci_enable_enable_device() from suspend/resume. Due to how they - * depend on the device enable refcount we can't anyway depend on them - * disabling/enabling the device. - */ - if (pci_enable_device(pdev)) - return -EIO; - - pci_set_master(pdev); - disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); ret = vlv_resume_prepare(dev_priv, false); -- cgit v1.2.3 From a1d0a0549d425cb21e2be4b7fd4f76e0379e6f2d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:48 +0300 Subject: drm/i915/dram: Also apply the 16Gb DIMM w/a for larger DRAM chips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the spec only asks us to do the WM0 latency bump for 16Gb DRAM devices I believe we should apply it for larger DRAM chips. At the time the w/a was added there were no larger chips on the market, but I think I've seen at least 32Gb DDR4 chips being available these days. Whether it's possible to actually find suitable DIMMs for the affected systems with largers chips I don't know. Also it's not known whether the 1 usec latency bump would be sufficient for larger chips. Someone would need to find such DIMMs and test this. Fortunately we do have a bit of extra latency already with the 1 usec bump, as the actual requirement was .4 usec for for 16Gb chips. Reviewed-by: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 4 ++-- drivers/gpu/drm/i915/soc/intel_dram.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index d74cbb43ae6f..83ec42646e82 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3209,9 +3209,9 @@ adjust_wm_latency(struct intel_display *display, } /* - * WA Level-0 adjustment for 16Gb DIMMs: SKL+ + * WA Level-0 adjustment for 16Gb+ DIMMs: SKL+ * If we could not get dimm info enable this WA to prevent from - * any underrun. If not able to get DIMM info assume 16Gb DIMM + * any underrun. If not able to get DIMM info assume 16Gb+ DIMM * to avoid any underrun. */ if (!display->platform.dg2 && dram_info->has_16gb_dimms) diff --git a/drivers/gpu/drm/i915/soc/intel_dram.c b/drivers/gpu/drm/i915/soc/intel_dram.c index edffaed8f9a7..8841cfe1cac8 100644 --- a/drivers/gpu/drm/i915/soc/intel_dram.c +++ b/drivers/gpu/drm/i915/soc/intel_dram.c @@ -335,7 +335,7 @@ static bool skl_is_16gb_dimm(const struct dram_dimm_info *dimm) { /* Convert total Gb to Gb per DRAM device */ - return dimm->size / (intel_dimm_num_devices(dimm) ?: 1) == 16; + return dimm->size / (intel_dimm_num_devices(dimm) ?: 1) >= 16; } static void @@ -354,7 +354,7 @@ skl_dram_get_dimm_info(struct drm_i915_private *i915, } drm_dbg_kms(&i915->drm, - "CH%u DIMM %c size: %u Gb, width: X%u, ranks: %u, 16Gb DIMMs: %s\n", + "CH%u DIMM %c size: %u Gb, width: X%u, ranks: %u, 16Gb+ DIMMs: %s\n", channel, dimm_name, dimm->size, dimm->width, dimm->ranks, str_yes_no(skl_is_16gb_dimm(dimm))); } @@ -384,7 +384,7 @@ skl_dram_get_channel_info(struct drm_i915_private *i915, ch->is_16gb_dimm = skl_is_16gb_dimm(&ch->dimm_l) || skl_is_16gb_dimm(&ch->dimm_s); - drm_dbg_kms(&i915->drm, "CH%u ranks: %u, 16Gb DIMMs: %s\n", + drm_dbg_kms(&i915->drm, "CH%u ranks: %u, 16Gb+ DIMMs: %s\n", channel, ch->ranks, str_yes_no(ch->is_16gb_dimm)); return 0; @@ -406,7 +406,7 @@ skl_dram_get_channels_info(struct drm_i915_private *i915, struct dram_info *dram u32 val; int ret; - /* Assume 16Gb DIMMs are present until proven otherwise */ + /* Assume 16Gb+ DIMMs are present until proven otherwise */ dram_info->has_16gb_dimms = true; val = intel_uncore_read(&i915->uncore, @@ -438,7 +438,7 @@ skl_dram_get_channels_info(struct drm_i915_private *i915, struct dram_info *dram drm_dbg_kms(&i915->drm, "Memory configuration is symmetric? %s\n", str_yes_no(dram_info->symmetric_memory)); - drm_dbg_kms(&i915->drm, "16Gb DIMMs: %s\n", + drm_dbg_kms(&i915->drm, "16Gb+ DIMMs: %s\n", str_yes_no(dram_info->has_16gb_dimms)); return 0; -- cgit v1.2.3 From 8ebb8e1a0ef84bc672105d07b8d9fd3ebbda6427 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:49 +0300 Subject: drm/i915: Apply the 16Gb DIMM w/a only for the platforms that need it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the code assumes that every platform except dg2 need the 16Gb DIMM w/a, while in reality it's only needed by skl and icl (and derivatives). Switch to a more specific platform check. Reviewed-by: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 83ec42646e82..2bf334fe63c9 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3174,11 +3174,19 @@ void skl_watermark_ipc_init(struct intel_display *display) skl_watermark_ipc_update(display); } +static bool need_16gb_dimm_wa(struct intel_display *display) +{ + const struct dram_info *dram_info = intel_dram_info(display->drm); + + return (display->platform.skylake || display->platform.kabylake || + display->platform.coffeelake || display->platform.cometlake || + DISPLAY_VER(display) == 11) && dram_info->has_16gb_dimms; +} + static void adjust_wm_latency(struct intel_display *display, u16 wm[], int num_levels, int read_latency) { - const struct dram_info *dram_info = intel_dram_info(display->drm); int i, level; /* @@ -3214,7 +3222,7 @@ adjust_wm_latency(struct intel_display *display, * any underrun. If not able to get DIMM info assume 16Gb+ DIMM * to avoid any underrun. */ - if (!display->platform.dg2 && dram_info->has_16gb_dimms) + if (need_16gb_dimm_wa(display)) wm[0] += 1; } -- cgit v1.2.3 From 07816e8117a2ecb6a126264f3c16ca02668ca2be Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:50 +0300 Subject: drm/i915: Tweak the read latency fixup code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If WM0 latency is zero we need to bump it (and the WM1+ latencies) but a fixed amount. But any WM1+ level with zero latency must not be touched since that indicates that corresponding WM level isn't supported. Currently the loop doing that adjustment does work, but only because the previous loop modified the num_levels used as the loop boundary. This all seems a bit too fragile. Remove the num_levels adjustment and instead adjust the read latency loop to abort when it encounters a zero latency value. Reviewed-by: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 2bf334fe63c9..2969cc58dabe 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3198,8 +3198,6 @@ adjust_wm_latency(struct intel_display *display, if (wm[level] == 0) { for (i = level + 1; i < num_levels; i++) wm[i] = 0; - - num_levels = level; break; } } @@ -3212,8 +3210,14 @@ adjust_wm_latency(struct intel_display *display, * from the punit when level 0 response data is 0us. */ if (wm[0] == 0) { - for (level = 0; level < num_levels; level++) + wm[0] += read_latency; + + for (level = 1; level < num_levels; level++) { + if (wm[level] == 0) + break; + wm[level] += read_latency; + } } /* -- cgit v1.2.3 From 76742daf75419eacdb4777980746f65f7c18a551 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:51 +0300 Subject: drm/i915: Don't pass the latency array to {skl,mtl}_read_wm_latency() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We always operate on i915->display.wm.skl_latency in {skl,mtl}_read_wm_latency(). No real need for the caller to have to pass that in explicitly. Reviewed-by: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 2969cc58dabe..43e481759e6e 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3184,9 +3184,10 @@ static bool need_16gb_dimm_wa(struct intel_display *display) } static void -adjust_wm_latency(struct intel_display *display, - u16 wm[], int num_levels, int read_latency) +adjust_wm_latency(struct intel_display *display, int read_latency) { + u16 *wm = display->wm.skl_latency; + int num_levels = display->wm.num_levels; int i, level; /* @@ -3230,9 +3231,9 @@ adjust_wm_latency(struct intel_display *display, wm[0] += 1; } -static void mtl_read_wm_latency(struct intel_display *display, u16 wm[]) +static void mtl_read_wm_latency(struct intel_display *display) { - int num_levels = display->wm.num_levels; + u16 *wm = display->wm.skl_latency; u32 val; val = intel_de_read(display, MTL_LATENCY_LP0_LP1); @@ -3247,12 +3248,12 @@ static void mtl_read_wm_latency(struct intel_display *display, u16 wm[]) wm[4] = REG_FIELD_GET(MTL_LATENCY_LEVEL_EVEN_MASK, val); wm[5] = REG_FIELD_GET(MTL_LATENCY_LEVEL_ODD_MASK, val); - adjust_wm_latency(display, wm, num_levels, 6); + adjust_wm_latency(display, 6); } -static void skl_read_wm_latency(struct intel_display *display, u16 wm[]) +static void skl_read_wm_latency(struct intel_display *display) { - int num_levels = display->wm.num_levels; + u16 *wm = display->wm.skl_latency; int read_latency = DISPLAY_VER(display) >= 12 ? 3 : 2; int mult = display->platform.dg2 ? 2 : 1; u32 val; @@ -3284,7 +3285,7 @@ static void skl_read_wm_latency(struct intel_display *display, u16 wm[]) wm[6] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_2_6_MASK, val) * mult; wm[7] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_3_7_MASK, val) * mult; - adjust_wm_latency(display, wm, num_levels, read_latency); + adjust_wm_latency(display, read_latency); } static void skl_setup_wm_latency(struct intel_display *display) @@ -3295,9 +3296,9 @@ static void skl_setup_wm_latency(struct intel_display *display) display->wm.num_levels = 8; if (DISPLAY_VER(display) >= 14) - mtl_read_wm_latency(display, display->wm.skl_latency); + mtl_read_wm_latency(display); else - skl_read_wm_latency(display, display->wm.skl_latency); + skl_read_wm_latency(display); intel_print_wm_latency(display, "Gen9 Plane", display->wm.skl_latency); } -- cgit v1.2.3 From e6619d22c8417c2630c37ed4e047c60e97b82110 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:52 +0300 Subject: drm/i915: Move adjust_wm_latency() out from {mtl,skl}_read_wm_latency() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit {mtl,skl}_read_wm_latency() are doing way too many things for my liking. Move the adjustment stuff out into the caller. This also gives us one place where we specify the 'read_latency' for all the platforms, instead of two places. Reviewed-by: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 43e481759e6e..2bc797aba2ec 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3183,12 +3183,22 @@ static bool need_16gb_dimm_wa(struct intel_display *display) DISPLAY_VER(display) == 11) && dram_info->has_16gb_dimms; } +static int wm_read_latency(struct intel_display *display) +{ + if (DISPLAY_VER(display) >= 14) + return 6; + else if (DISPLAY_VER(display) >= 12) + return 3; + else + return 2; +} + static void -adjust_wm_latency(struct intel_display *display, int read_latency) +adjust_wm_latency(struct intel_display *display) { u16 *wm = display->wm.skl_latency; - int num_levels = display->wm.num_levels; - int i, level; + int i, level, num_levels = display->wm.num_levels; + int read_latency = wm_read_latency(display); /* * If a level n (n > 1) has a 0us latency, all levels m (m >= n) @@ -3247,14 +3257,11 @@ static void mtl_read_wm_latency(struct intel_display *display) val = intel_de_read(display, MTL_LATENCY_LP4_LP5); wm[4] = REG_FIELD_GET(MTL_LATENCY_LEVEL_EVEN_MASK, val); wm[5] = REG_FIELD_GET(MTL_LATENCY_LEVEL_ODD_MASK, val); - - adjust_wm_latency(display, 6); } static void skl_read_wm_latency(struct intel_display *display) { u16 *wm = display->wm.skl_latency; - int read_latency = DISPLAY_VER(display) >= 12 ? 3 : 2; int mult = display->platform.dg2 ? 2 : 1; u32 val; int ret; @@ -3284,8 +3291,6 @@ static void skl_read_wm_latency(struct intel_display *display) wm[5] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_1_5_MASK, val) * mult; wm[6] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_2_6_MASK, val) * mult; wm[7] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_3_7_MASK, val) * mult; - - adjust_wm_latency(display, read_latency); } static void skl_setup_wm_latency(struct intel_display *display) @@ -3300,6 +3305,8 @@ static void skl_setup_wm_latency(struct intel_display *display) else skl_read_wm_latency(display); + adjust_wm_latency(display); + intel_print_wm_latency(display, "Gen9 Plane", display->wm.skl_latency); } -- cgit v1.2.3 From 91acc6317814d86258dc6ad9e3ef77164d9af148 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:53 +0300 Subject: drm/i915: Extract multiply_wm_latency() from skl_read_wm_latency() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I want skl_read_wm_latency() to just do what it says on the tin, ie. read the latency values from the pcode mailbox. Move the DG2 "multiply by two" trick elsewhere. Reviewed-by: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 29 +++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 2bc797aba2ec..1ac94cb4f27d 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3174,6 +3174,15 @@ void skl_watermark_ipc_init(struct intel_display *display) skl_watermark_ipc_update(display); } +static void multiply_wm_latency(struct intel_display *display, int mult) +{ + u16 *wm = display->wm.skl_latency; + int level, num_levels = display->wm.num_levels; + + for (level = 0; level < num_levels; level++) + wm[level] *= mult; +} + static bool need_16gb_dimm_wa(struct intel_display *display) { const struct dram_info *dram_info = intel_dram_info(display->drm); @@ -3200,6 +3209,9 @@ adjust_wm_latency(struct intel_display *display) int i, level, num_levels = display->wm.num_levels; int read_latency = wm_read_latency(display); + if (display->platform.dg2) + multiply_wm_latency(display, 2); + /* * If a level n (n > 1) has a 0us latency, all levels m (m >= n) * need to be disabled. We make sure to sanitize the values out @@ -3262,7 +3274,6 @@ static void mtl_read_wm_latency(struct intel_display *display) static void skl_read_wm_latency(struct intel_display *display) { u16 *wm = display->wm.skl_latency; - int mult = display->platform.dg2 ? 2 : 1; u32 val; int ret; @@ -3274,10 +3285,10 @@ static void skl_read_wm_latency(struct intel_display *display) return; } - wm[0] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_0_4_MASK, val) * mult; - wm[1] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_1_5_MASK, val) * mult; - wm[2] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_2_6_MASK, val) * mult; - wm[3] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_3_7_MASK, val) * mult; + wm[0] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_0_4_MASK, val); + wm[1] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_1_5_MASK, val); + wm[2] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_2_6_MASK, val); + wm[3] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_3_7_MASK, val); /* read the second set of memory latencies[4:7] */ val = 1; /* data0 to be programmed to 1 for second set */ @@ -3287,10 +3298,10 @@ static void skl_read_wm_latency(struct intel_display *display) return; } - wm[4] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_0_4_MASK, val) * mult; - wm[5] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_1_5_MASK, val) * mult; - wm[6] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_2_6_MASK, val) * mult; - wm[7] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_3_7_MASK, val) * mult; + wm[4] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_0_4_MASK, val); + wm[5] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_1_5_MASK, val); + wm[6] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_2_6_MASK, val); + wm[7] = REG_FIELD_GET(GEN9_MEM_LATENCY_LEVEL_3_7_MASK, val); } static void skl_setup_wm_latency(struct intel_display *display) -- cgit v1.2.3 From 030778ab8d22cb52c53560d04ad3649cae4e18ff Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:54 +0300 Subject: drm/i915: Extract increase_wm_latency() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the "increase wm latencies by some amount" code into a helper that can be reused. Reviewed-by: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-8-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 1ac94cb4f27d..98ca592f6042 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3183,6 +3183,21 @@ static void multiply_wm_latency(struct intel_display *display, int mult) wm[level] *= mult; } +static void increase_wm_latency(struct intel_display *display, int inc) +{ + u16 *wm = display->wm.skl_latency; + int level, num_levels = display->wm.num_levels; + + wm[0] += inc; + + for (level = 1; level < num_levels; level++) { + if (wm[level] == 0) + break; + + wm[level] += inc; + } +} + static bool need_16gb_dimm_wa(struct intel_display *display) { const struct dram_info *dram_info = intel_dram_info(display->drm); @@ -3207,7 +3222,6 @@ adjust_wm_latency(struct intel_display *display) { u16 *wm = display->wm.skl_latency; int i, level, num_levels = display->wm.num_levels; - int read_latency = wm_read_latency(display); if (display->platform.dg2) multiply_wm_latency(display, 2); @@ -3232,16 +3246,8 @@ adjust_wm_latency(struct intel_display *display) * to add proper adjustment to each valid level we retrieve * from the punit when level 0 response data is 0us. */ - if (wm[0] == 0) { - wm[0] += read_latency; - - for (level = 1; level < num_levels; level++) { - if (wm[level] == 0) - break; - - wm[level] += read_latency; - } - } + if (wm[0] == 0) + increase_wm_latency(display, wm_read_latency(display)); /* * WA Level-0 adjustment for 16Gb+ DIMMs: SKL+ -- cgit v1.2.3 From 84953731f9170b3b51013f1f4deb59cc916dfa7b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:55 +0300 Subject: drm/i915: Use increase_wm_latency() for the 16Gb DIMM w/a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump the latency for all watermark levels in the 16Gb+ DIMM w/a. The spec does ask us to do it only for level 0, but it seems more sane to bump all the levels. If the actual memory access is slower then the wakeup (WM1+) should also potentially happen earlier. This also avoids the theoretical case that WM0 would get bumped higher than WM1+. Not that it is likely to happen because the WM0 latency is always significantly lower than the WM1 latency. Reviewed-by: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-9-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 98ca592f6042..21dd15be74f9 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3256,7 +3256,7 @@ adjust_wm_latency(struct intel_display *display) * to avoid any underrun. */ if (need_16gb_dimm_wa(display)) - wm[0] += 1; + increase_wm_latency(display, 1); } static void mtl_read_wm_latency(struct intel_display *display) -- cgit v1.2.3 From e407ea78abdf20bb64998e178b7944dd297ffcb3 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:56 +0300 Subject: drm/i915: Extract sanitize_wm_latency() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull the "zero out invalid WM latencies" stuff into a helper. Mainly to avoid mixing higher level and lower level stuff in the same adjust_wm_latency() function. Reviewed-by: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-10-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 21dd15be74f9..1acb9285bd05 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3217,14 +3217,10 @@ static int wm_read_latency(struct intel_display *display) return 2; } -static void -adjust_wm_latency(struct intel_display *display) +static void sanitize_wm_latency(struct intel_display *display) { u16 *wm = display->wm.skl_latency; - int i, level, num_levels = display->wm.num_levels; - - if (display->platform.dg2) - multiply_wm_latency(display, 2); + int level, num_levels = display->wm.num_levels; /* * If a level n (n > 1) has a 0us latency, all levels m (m >= n) @@ -3233,11 +3229,24 @@ adjust_wm_latency(struct intel_display *display) */ for (level = 1; level < num_levels; level++) { if (wm[level] == 0) { + int i; + for (i = level + 1; i < num_levels; i++) wm[i] = 0; - break; + return; } } +} + +static void +adjust_wm_latency(struct intel_display *display) +{ + u16 *wm = display->wm.skl_latency; + + if (display->platform.dg2) + multiply_wm_latency(display, 2); + + sanitize_wm_latency(display); /* * WaWmMemoryReadLatency -- cgit v1.2.3 From 15bdae1072061db72027192badb276f95094da5f Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:57 +0300 Subject: drm/i915: Flatten sanitize_wm_latency() a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the inner loop out from the outer loop in sanitize_wm_latency() to flatten things a bit. Easier to read flat code. v2: Move the inner loop out completely (Luca) Cc: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-11-ville.syrjala@linux.intel.com Reviewed-by: Luca Coelho --- drivers/gpu/drm/i915/display/skl_watermark.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 1acb9285bd05..d83772c6ea9a 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3228,14 +3228,12 @@ static void sanitize_wm_latency(struct intel_display *display) * of the punit to satisfy this requirement. */ for (level = 1; level < num_levels; level++) { - if (wm[level] == 0) { - int i; - - for (i = level + 1; i < num_levels; i++) - wm[i] = 0; - return; - } + if (wm[level] == 0) + break; } + + for (level = level + 1; level < num_levels; level++) + wm[level] = 0; } static void -- cgit v1.2.3 From d49564a5f7e23f08486697080e0006c606c5ebd2 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:58 +0300 Subject: drm/i915: Make wm latencies monotonic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some systems (eg. LNL Lenovo Thinkapd X1 Carbon) declare semi-bogus non-monotonic WM latency values: WM0 latency not provided WM1 latency 100 usec WM2 latency 100 usec WM3 latency 100 usec WM4 latency 93 usec WM5 latency 100 usec Apparently Windows just papers over the issue by bumping the latencies for the higher watermark levels to make them monotonic again. Do the same. Cc: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-12-ville.syrjala@linux.intel.com Reviewed-by: Luca Coelho --- drivers/gpu/drm/i915/display/skl_watermark.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index d83772c6ea9a..2a40c135cb96 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3236,6 +3236,19 @@ static void sanitize_wm_latency(struct intel_display *display) wm[level] = 0; } +static void make_wm_latency_monotonic(struct intel_display *display) +{ + u16 *wm = display->wm.skl_latency; + int level, num_levels = display->wm.num_levels; + + for (level = 1; level < num_levels; level++) { + if (wm[level] == 0) + break; + + wm[level] = max(wm[level], wm[level-1]); + } +} + static void adjust_wm_latency(struct intel_display *display) { @@ -3246,6 +3259,8 @@ adjust_wm_latency(struct intel_display *display) sanitize_wm_latency(display); + make_wm_latency_monotonic(display); + /* * WaWmMemoryReadLatency * -- cgit v1.2.3 From b86cb7beed45e30fd5701ac58866f57d99a55fa9 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:29:59 +0300 Subject: drm/i915: Print both the original and adjusted wm latencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to help with debugging print both the original wm latencies read from the mailbox/etc., and the final fixed/adjusted values. Reviewed-by: Luca Coelho Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-13-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 2a40c135cb96..9d58c28d3bdf 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3344,9 +3344,11 @@ static void skl_setup_wm_latency(struct intel_display *display) else skl_read_wm_latency(display); + intel_print_wm_latency(display, "original", display->wm.skl_latency); + adjust_wm_latency(display); - intel_print_wm_latency(display, "Gen9 Plane", display->wm.skl_latency); + intel_print_wm_latency(display, "adjusted", display->wm.skl_latency); } static struct intel_global_state *intel_dbuf_duplicate_state(struct intel_global_obj *obj) -- cgit v1.2.3 From 840f6b9e480c514d8147abfb729c95a19ea1b2d2 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 22:30:00 +0300 Subject: drm/i915: Make sure wm block/lines are non-decreasing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The watermark algorithm sometimes produces results where higher watermark levels have smaller blocks/lines watermarks than the lower levels. That doesn't really make sense as the corresponding latencies are supposed to be non-decreasing. It's unclear how the hardware responds to such watermark values, so it seems better to avoid that case and just make sure the values are always non-decreasing. Here's an example how things change for such a case on a GLK NUC: [PLANE:70:cursor A] level wm0, wm1, wm2, wm3, wm4, wm5, wm6, wm7, twm, swm, stwm -> *wm0,*wm1,*wm2,*wm3,*wm4,*wm5,*wm6,*wm7,*twm, swm, stwm [PLANE:70:cursor A] lines 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -> 4, 4, 4, 2, 2, 2, 2, 2, 0, 0, 0 [PLANE:70:cursor A] blocks 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -> 11, 11, 12, 7, 7, 7, 7, 7, 25, 0, 0 [PLANE:70:cursor A] min_ddb 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -> 12, 12, 13, 8, 8, 8, 8, 8, 26, 0, 0 -> [PLANE:70:cursor A] level wm0, wm1, wm2, wm3, wm4, wm5, wm6, wm7, twm, swm, stwm -> *wm0,*wm1,*wm2,*wm3,*wm4,*wm5,*wm6,*wm7,*twm, swm, stwm [PLANE:70:cursor A] lines 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -> 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0 [PLANE:70:cursor A] blocks 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -> 11, 11, 12, 12, 12, 12, 12, 12, 25, 0, 0 [PLANE:70:cursor A] min_ddb 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -> 12, 12, 13, 13, 13, 13, 13, 13, 26, 0, 0 Whether this actually helps on any display blinking issues is unclear. Reviewed-by: Luca Coelho References: https://gitlab.freedesktop.org/drm/intel/-/issues/8683 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919193000.17665-14-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 9d58c28d3bdf..9eb28d935757 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1878,18 +1878,21 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, } else { blocks++; } - - /* - * Make sure result blocks for higher latency levels are - * at least as high as level below the current level. - * Assumption in DDB algorithm optimization for special - * cases. Also covers Display WA #1125 for RC. - */ - if (result_prev->blocks > blocks) - blocks = result_prev->blocks; } } + /* + * Make sure result blocks for higher latency levels are + * at least as high as level below the current level. + * Assumption in DDB algorithm optimization for special + * cases. Also covers Display WA #1125 for RC. + * + * Let's always do this as the algorithm can give non + * monotonic results on any platform. + */ + blocks = max_t(u32, blocks, result_prev->blocks); + lines = max_t(u32, lines, result_prev->lines); + if (DISPLAY_VER(display) >= 11) { if (wp->y_tiled) { int extra_lines; -- cgit v1.2.3 From 32620e176443bf23ec81bfe8f177c6721a904864 Mon Sep 17 00:00:00 2001 From: Dnyaneshwar Bhadane Date: Mon, 22 Sep 2025 20:33:15 +0530 Subject: drm/pcids: Split PTL pciids group to make wcl subplatform To form the WCL platform as a subplatform of PTL in definition, WCL pci ids are splited into saparate group from PTL. So update the pciidlist struct to cover all the pci ids. v2: - Squash wcl description in single patch for display and xe.(jani,gustavo) Signed-off-by: Dnyaneshwar Bhadane Reviewed-by: Gustavo Sousa Signed-off-by: Suraj Kandpal Link: https://lore.kernel.org/r/20250922150317.2334680-2-dnyaneshwar.bhadane@intel.com --- drivers/gpu/drm/i915/display/intel_display_device.c | 1 + drivers/gpu/drm/xe/xe_pci.c | 1 + include/drm/intel/pciids.h | 5 ++++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index a002bc6ce7b0..a9a36176096f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -1482,6 +1482,7 @@ static const struct { INTEL_LNL_IDS(INTEL_DISPLAY_DEVICE, &lnl_desc), INTEL_BMG_IDS(INTEL_DISPLAY_DEVICE, &bmg_desc), INTEL_PTL_IDS(INTEL_DISPLAY_DEVICE, &ptl_desc), + INTEL_WCL_IDS(INTEL_DISPLAY_DEVICE, &ptl_desc), }; static const struct { diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 046d330bad34..7ae316534eb6 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -374,6 +374,7 @@ static const struct pci_device_id pciidlist[] = { INTEL_LNL_IDS(INTEL_VGA_DEVICE, &lnl_desc), INTEL_BMG_IDS(INTEL_VGA_DEVICE, &bmg_desc), INTEL_PTL_IDS(INTEL_VGA_DEVICE, &ptl_desc), + INTEL_WCL_IDS(INTEL_VGA_DEVICE, &ptl_desc), { } }; MODULE_DEVICE_TABLE(pci, pciidlist); diff --git a/include/drm/intel/pciids.h b/include/drm/intel/pciids.h index da6301a6fcea..69d4ae92d822 100644 --- a/include/drm/intel/pciids.h +++ b/include/drm/intel/pciids.h @@ -877,7 +877,10 @@ MACRO__(0xB08F, ## __VA_ARGS__), \ MACRO__(0xB090, ## __VA_ARGS__), \ MACRO__(0xB0A0, ## __VA_ARGS__), \ - MACRO__(0xB0B0, ## __VA_ARGS__), \ + MACRO__(0xB0B0, ## __VA_ARGS__) + +/* WCL */ +#define INTEL_WCL_IDS(MACRO__, ...) \ MACRO__(0xFD80, ## __VA_ARGS__), \ MACRO__(0xFD81, ## __VA_ARGS__) -- cgit v1.2.3 From 4dfaae643e59cf3ab71b88689dce1b874f036f00 Mon Sep 17 00:00:00 2001 From: Dnyaneshwar Bhadane Date: Mon, 22 Sep 2025 20:33:16 +0530 Subject: drm/i915/display: Add definition for wcl as subplatform We will need to differentiate between WCL and PTL in intel_encoder_is_c10phy(). Since WCL and PTL use the same display architecture, let's define WCL as a subplatform of PTL to allow the differentiation. v2: Update commit message and reorder wcl define (Gustavo) Signed-off-by: Dnyaneshwar Bhadane Reviewed-by: Gustavo Sousa Signed-off-by: Suraj Kandpal Link: https://lore.kernel.org/r/20250922150317.2334680-3-dnyaneshwar.bhadane@intel.com --- drivers/gpu/drm/i915/display/intel_display_device.c | 12 ++++++++++++ drivers/gpu/drm/i915/display/intel_display_device.h | 4 +++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index a9a36176096f..f3f1f25b0f38 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -1404,8 +1404,20 @@ static const struct platform_desc bmg_desc = { PLATFORM_GROUP(dgfx), }; +static const u16 wcl_ids[] = { + INTEL_WCL_IDS(ID), + 0 +}; + static const struct platform_desc ptl_desc = { PLATFORM(pantherlake), + .subplatforms = (const struct subplatform_desc[]) { + { + SUBPLATFORM(pantherlake, wildcatlake), + .pciidlist = wcl_ids, + }, + {}, + } }; __diag_pop(); diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index 1f091fbcd0ec..0e062753cf9b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -101,7 +101,9 @@ struct pci_dev; /* Display ver 14.1 (based on GMD ID) */ \ func(battlemage) \ /* Display ver 30 (based on GMD ID) */ \ - func(pantherlake) + func(pantherlake) \ + func(pantherlake_wildcatlake) + #define __MEMBER(name) unsigned long name:1; #define __COUNT(x) 1 + -- cgit v1.2.3 From 8147f7a1c083fd565fb958824f7c552de3b2dc46 Mon Sep 17 00:00:00 2001 From: Dnyaneshwar Bhadane Date: Mon, 22 Sep 2025 20:33:17 +0530 Subject: drm/i915/xe3: Restrict PTL intel_encoder_is_c10phy() to only PHY A On PTL, no combo PHY is connected to PORT B. However, PORT B can still be used for Type-C and will utilize the C20 PHY for eDP over Type-C. In such configurations, VBTs also enumerate PORT B. This leads to issues where PORT B is incorrectly identified as using the C10 PHY, due to the assumption that returning true for PORT B in intel_encoder_is_c10phy() would not cause problems. From PTL's perspective, only PORT A/PHY A uses the C10 PHY. Update the helper intel_encoder_is_c10phy() to return true only for PORT A/PHY on PTL. v2: Change the condition code style for ptl/wcl Bspec: 72571,73944 Fixes: 9d10de78a37f ("drm/i915/wcl: C10 phy connected to port A and B") Signed-off-by: Dnyaneshwar Bhadane Reviewed-by: Gustavo Sousa Signed-off-by: Suraj Kandpal Link: https://lore.kernel.org/r/20250922150317.2334680-4-dnyaneshwar.bhadane@intel.com --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 801235a5bc0a..a2d2cecf7121 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -39,14 +39,12 @@ bool intel_encoder_is_c10phy(struct intel_encoder *encoder) struct intel_display *display = to_intel_display(encoder); enum phy phy = intel_encoder_to_phy(encoder); - /* PTL doesn't have a PHY connected to PORT B; as such, - * there will never be a case where PTL uses PHY B. - * WCL uses PORT A and B with the C10 PHY. - * Reusing the condition for WCL and extending it for PORT B - * should not cause any issues for PTL. - */ - if (display->platform.pantherlake && phy < PHY_C) - return true; + if (display->platform.pantherlake) { + if (display->platform.pantherlake_wildcatlake) + return phy <= PHY_B; + else + return phy == PHY_A; + } if ((display->platform.lunarlake || display->platform.meteorlake) && phy < PHY_C) return true; -- cgit v1.2.3 From 3dc42238788bc70b94d946dfd4683ebf30a3252b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 23 Sep 2025 17:31:04 +0300 Subject: drm/i915/irq: drop intel_psr_regs.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i915_irq.c no longer needs display/intel_psr_regs.h. Drop it. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/29752bb1942fc2ceceb5140bb49f67e44e1b0676.1758637773.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_irq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7c7c6dcbce88..56f231591a3e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -38,7 +38,6 @@ #include "display/intel_hotplug.h" #include "display/intel_hotplug_irq.h" #include "display/intel_lpe_audio.h" -#include "display/intel_psr_regs.h" #include "gt/intel_breadcrumbs.h" #include "gt/intel_gt.h" -- cgit v1.2.3 From 381f04d8c0276c703956c749b3c333eb32acf668 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 23 Sep 2025 17:31:05 +0300 Subject: drm/i915/irq: initialize gen2_imr_mask in terms of enable_mask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of initializing gen2_imr_mask and enable_mask independently, use the latter for initializing the former. This also highlights the differences in the masks, i.e. what's set to enable_mask after it's been used to initialize gen2_imr_mask. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/e3b612ce4decea699bde2c52aeaef48bf95f7abc.1758637773.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_irq.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 56f231591a3e..04de02fc08d9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -895,26 +895,20 @@ static void i915_irq_postinstall(struct drm_i915_private *dev_priv) gen2_error_init(uncore, GEN2_ERROR_REGS, ~i9xx_error_mask(dev_priv)); - dev_priv->gen2_imr_mask = - ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_MASTER_ERROR_INTERRUPT); - enable_mask = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_MASTER_ERROR_INTERRUPT | - I915_USER_INTERRUPT; + I915_MASTER_ERROR_INTERRUPT; - if (DISPLAY_VER(display) >= 3) { - dev_priv->gen2_imr_mask &= ~I915_ASLE_INTERRUPT; + if (DISPLAY_VER(display) >= 3) enable_mask |= I915_ASLE_INTERRUPT; - } - if (HAS_HOTPLUG(display)) { - dev_priv->gen2_imr_mask &= ~I915_DISPLAY_PORT_INTERRUPT; + if (HAS_HOTPLUG(display)) enable_mask |= I915_DISPLAY_PORT_INTERRUPT; - } + + dev_priv->gen2_imr_mask = ~enable_mask; + + enable_mask |= I915_USER_INTERRUPT; gen2_irq_init(uncore, GEN2_IRQ_REGS, dev_priv->gen2_imr_mask, enable_mask); @@ -1016,20 +1010,16 @@ static void i965_irq_postinstall(struct drm_i915_private *dev_priv) gen2_error_init(uncore, GEN2_ERROR_REGS, ~i965_error_mask(dev_priv)); - dev_priv->gen2_imr_mask = - ~(I915_ASLE_INTERRUPT | - I915_DISPLAY_PORT_INTERRUPT | - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_MASTER_ERROR_INTERRUPT); - enable_mask = I915_ASLE_INTERRUPT | I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_MASTER_ERROR_INTERRUPT | - I915_USER_INTERRUPT; + I915_MASTER_ERROR_INTERRUPT; + + dev_priv->gen2_imr_mask = ~enable_mask; + + enable_mask |= I915_USER_INTERRUPT; if (IS_G4X(dev_priv)) enable_mask |= I915_BSD_USER_INTERRUPT; -- cgit v1.2.3 From d54c636db529d2c73e49a7be8a55afd530977f5c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 23 Sep 2025 17:31:06 +0300 Subject: drm/i915/irq: abstract i9xx_display_irq_enable_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Figure out the enable mask for display things in display code. Reuse the same function for both i915 and i965 code, the end result remains the same. This removes a pair of DISPLAY_VER() and HAS_HOTPLUG() checks from core irq code. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/dd7cd63a4019ff24098d565b67ea827df6b9ed45.1758637773.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display_irq.c | 16 ++++++++++++++++ drivers/gpu/drm/i915/display/intel_display_irq.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 16 ++-------------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index c6f367e6159e..4d51900123ea 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -1900,6 +1900,22 @@ void i9xx_display_irq_reset(struct intel_display *display) i9xx_pipestat_irq_reset(display); } +u32 i9xx_display_irq_enable_mask(struct intel_display *display) +{ + u32 enable_mask; + + enable_mask = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; + + if (DISPLAY_VER(display) >= 3) + enable_mask |= I915_ASLE_INTERRUPT; + + if (HAS_HOTPLUG(display)) + enable_mask |= I915_DISPLAY_PORT_INTERRUPT; + + return enable_mask; +} + void i915_display_irq_postinstall(struct intel_display *display) { /* diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.h b/drivers/gpu/drm/i915/display/intel_display_irq.h index cee120347064..e44d88e0d7e7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.h +++ b/drivers/gpu/drm/i915/display/intel_display_irq.h @@ -61,6 +61,7 @@ void vlv_display_irq_reset(struct intel_display *display); void gen8_display_irq_reset(struct intel_display *display); void gen11_display_irq_reset(struct intel_display *display); +u32 i9xx_display_irq_enable_mask(struct intel_display *display); void i915_display_irq_postinstall(struct intel_display *display); void i965_display_irq_postinstall(struct intel_display *display); void vlv_display_irq_postinstall(struct intel_display *display); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 04de02fc08d9..f9fbb88b9e26 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -895,17 +895,9 @@ static void i915_irq_postinstall(struct drm_i915_private *dev_priv) gen2_error_init(uncore, GEN2_ERROR_REGS, ~i9xx_error_mask(dev_priv)); - enable_mask = - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + enable_mask = i9xx_display_irq_enable_mask(display) | I915_MASTER_ERROR_INTERRUPT; - if (DISPLAY_VER(display) >= 3) - enable_mask |= I915_ASLE_INTERRUPT; - - if (HAS_HOTPLUG(display)) - enable_mask |= I915_DISPLAY_PORT_INTERRUPT; - dev_priv->gen2_imr_mask = ~enable_mask; enable_mask |= I915_USER_INTERRUPT; @@ -1010,11 +1002,7 @@ static void i965_irq_postinstall(struct drm_i915_private *dev_priv) gen2_error_init(uncore, GEN2_ERROR_REGS, ~i965_error_mask(dev_priv)); - enable_mask = - I915_ASLE_INTERRUPT | - I915_DISPLAY_PORT_INTERRUPT | - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + enable_mask = i9xx_display_irq_enable_mask(display) | I915_MASTER_ERROR_INTERRUPT; dev_priv->gen2_imr_mask = ~enable_mask; -- cgit v1.2.3 From c39d3e2dd9dc97f15546e634934a47a81d95c44c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 23 Sep 2025 17:31:07 +0300 Subject: drm/i915/irq: move check for HAS_HOTPLUG() inside i9xx_hpd_irq_ack() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to avoid using the display dependent HAS_HOTPLUG() in generic irq code. Since the enabling of I915_DISPLAY_PORT_INTERRUPT depends on HAS_HOTPLUG() to begin with, we don't really expect to get the irqs for !HAS_HOTPLUG(). At least in theory, checking for HAS_HOTPLUG() inside i9xx_hpd_irq_ack() should not have any impact. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/2f97c077e67667bf420196c7381553d5286da958.1758637773.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_hotplug_irq.c | 3 +++ drivers/gpu/drm/i915/i915_irq.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c index 4f72f3fb9af5..9a4da818ad61 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c @@ -420,6 +420,9 @@ u32 i9xx_hpd_irq_ack(struct intel_display *display) u32 hotplug_status = 0, hotplug_status_mask; int i; + if (!HAS_HOTPLUG(display)) + return 0; + if (display->platform.g4x || display->platform.valleyview || display->platform.cherryview) hotplug_status_mask = HOTPLUG_INT_STATUS_G4X | diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f9fbb88b9e26..90174ce9195c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -931,8 +931,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) ret = IRQ_HANDLED; - if (HAS_HOTPLUG(display) && - iir & I915_DISPLAY_PORT_INTERRUPT) + if (iir & I915_DISPLAY_PORT_INTERRUPT) hotplug_status = i9xx_hpd_irq_ack(display); /* Call regardless, as some status bits might not be -- cgit v1.2.3 From c989cb4c64edca2516304c9d29011f1066ca471a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 23 Sep 2025 17:31:08 +0300 Subject: drm/i915/irq: split ILK display irq handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split out display irq handling on ilk. Since the master IRQ enable is in DEIIR, we'll need to do this in two parts. First, add ilk_display_irq_master_disable() to disable master and south interrupts, and second, add (repurposed) ilk_display_irq_handler() to finish display irq handling. It's not the prettiest thing you ever saw, but improves separation of display irq handling. And removes HAS_PCH_NOP() and DISPLAY_VER() checks from core irq code. v2: - Separate ilk_display_irq_master_enable() (Ville) - Use _fw mmio accessors (Ville) Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/e8ea7c985c3f3a80870f3333bde2e1bf30d653b0.1758637773.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display_irq.c | 51 +++++++++++++++++++++++- drivers/gpu/drm/i915/display/intel_display_irq.h | 5 ++- drivers/gpu/drm/i915/i915_irq.c | 31 +++----------- 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 4d51900123ea..e1a812f6159b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -872,7 +872,7 @@ static void ilk_gtt_fault_irq_handler(struct intel_display *display) } } -void ilk_display_irq_handler(struct intel_display *display, u32 de_iir) +static void _ilk_display_irq_handler(struct intel_display *display, u32 de_iir) { enum pipe pipe; u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG; @@ -923,7 +923,7 @@ void ilk_display_irq_handler(struct intel_display *display, u32 de_iir) ilk_display_rps_irq_handler(display); } -void ivb_display_irq_handler(struct intel_display *display, u32 de_iir) +static void _ivb_display_irq_handler(struct intel_display *display, u32 de_iir) { enum pipe pipe; u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB; @@ -972,6 +972,53 @@ void ivb_display_irq_handler(struct intel_display *display, u32 de_iir) } } +void ilk_display_irq_master_disable(struct intel_display *display, u32 *de_ier, u32 *sde_ier) +{ + /* disable master interrupt before clearing iir */ + *de_ier = intel_de_read_fw(display, DEIER); + intel_de_write_fw(display, DEIER, *de_ier & ~DE_MASTER_IRQ_CONTROL); + + /* + * Disable south interrupts. We'll only write to SDEIIR once, so further + * interrupts will be stored on its back queue, and then we'll be able + * to process them after we restore SDEIER (as soon as we restore it, + * we'll get an interrupt if SDEIIR still has something to process due + * to its back queue). + */ + if (!HAS_PCH_NOP(display)) { + *sde_ier = intel_de_read_fw(display, SDEIER); + intel_de_write_fw(display, SDEIER, 0); + } else { + *sde_ier = 0; + } +} + +void ilk_display_irq_master_enable(struct intel_display *display, u32 de_ier, u32 sde_ier) +{ + intel_de_write_fw(display, DEIER, de_ier); + + if (sde_ier) + intel_de_write_fw(display, SDEIER, sde_ier); +} + +bool ilk_display_irq_handler(struct intel_display *display) +{ + u32 de_iir; + bool handled = false; + + de_iir = intel_de_read_fw(display, DEIIR); + if (de_iir) { + intel_de_write_fw(display, DEIIR, de_iir); + if (DISPLAY_VER(display) >= 7) + _ivb_display_irq_handler(display, de_iir); + else + _ilk_display_irq_handler(display, de_iir); + handled = true; + } + + return handled; +} + static u32 gen8_de_port_aux_mask(struct intel_display *display) { u32 mask; diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.h b/drivers/gpu/drm/i915/display/intel_display_irq.h index e44d88e0d7e7..84acd31948cf 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.h +++ b/drivers/gpu/drm/i915/display/intel_display_irq.h @@ -47,8 +47,9 @@ void i965_disable_vblank(struct drm_crtc *crtc); void ilk_disable_vblank(struct drm_crtc *crtc); void bdw_disable_vblank(struct drm_crtc *crtc); -void ivb_display_irq_handler(struct intel_display *display, u32 de_iir); -void ilk_display_irq_handler(struct intel_display *display, u32 de_iir); +void ilk_display_irq_master_disable(struct intel_display *display, u32 *de_ier, u32 *sde_ier); +void ilk_display_irq_master_enable(struct intel_display *display, u32 de_ier, u32 sde_ier); +bool ilk_display_irq_handler(struct intel_display *display); void gen8_de_irq_handler(struct intel_display *display, u32 master_ctl); void gen11_display_irq_handler(struct intel_display *display); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 90174ce9195c..11a727b74849 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -414,7 +414,7 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) struct drm_i915_private *i915 = arg; struct intel_display *display = i915->display; void __iomem * const regs = intel_uncore_regs(&i915->uncore); - u32 de_iir, gt_iir, de_ier, sde_ier = 0; + u32 gt_iir, de_ier = 0, sde_ier = 0; irqreturn_t ret = IRQ_NONE; if (unlikely(!intel_irqs_enabled(i915))) @@ -423,19 +423,8 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) /* IRQs are synced during runtime_suspend, we don't require a wakeref */ disable_rpm_wakeref_asserts(&i915->runtime_pm); - /* disable master interrupt before clearing iir */ - de_ier = raw_reg_read(regs, DEIER); - raw_reg_write(regs, DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); - - /* Disable south interrupts. We'll only write to SDEIIR once, so further - * interrupts will will be stored on its back queue, and then we'll be - * able to process them after we restore SDEIER (as soon as we restore - * it, we'll get an interrupt if SDEIIR still has something to process - * due to its back queue). */ - if (!HAS_PCH_NOP(display)) { - sde_ier = raw_reg_read(regs, SDEIER); - raw_reg_write(regs, SDEIER, 0); - } + /* Disable master and south interrupts */ + ilk_display_irq_master_disable(display, &de_ier, &sde_ier); /* Find, clear, then process each source of interrupt */ @@ -449,15 +438,8 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) ret = IRQ_HANDLED; } - de_iir = raw_reg_read(regs, DEIIR); - if (de_iir) { - raw_reg_write(regs, DEIIR, de_iir); - if (DISPLAY_VER(display) >= 7) - ivb_display_irq_handler(display, de_iir); - else - ilk_display_irq_handler(display, de_iir); + if (ilk_display_irq_handler(display)) ret = IRQ_HANDLED; - } if (GRAPHICS_VER(i915) >= 6) { u32 pm_iir = raw_reg_read(regs, GEN6_PMIIR); @@ -468,9 +450,8 @@ static irqreturn_t ilk_irq_handler(int irq, void *arg) } } - raw_reg_write(regs, DEIER, de_ier); - if (sde_ier) - raw_reg_write(regs, SDEIER, sde_ier); + /* Re-enable master and south interrupts */ + ilk_display_irq_master_enable(display, de_ier, sde_ier); pmu_irq_stats(i915, ret); -- cgit v1.2.3 From d90c0a5ccdb48780a839b6ee4e3a569a445f4f2a Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Tue, 2 Sep 2025 17:58:50 +0530 Subject: drm/i915/vrr: Refactor VRR live status wait into common helper Add a helper to consolidate timeout handling and error logging when waiting for VRR live status to clear. Log an error message if the VRR live status bit fails to clear within the timeout. Signed-off-by: Ankit Nautiyal Reviewed-by: Mitul Golani Link: https://lore.kernel.org/r/20250902122850.3649828-1-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_vrr.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 9e007aab1452..98d28de2e451 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -644,6 +644,15 @@ void intel_vrr_enable(const struct intel_crtc_state *crtc_state) } } +static void intel_vrr_wait_for_live_status_clear(struct intel_display *display, + enum transcoder cpu_transcoder) +{ + if (intel_de_wait_for_clear(display, + TRANS_VRR_STATUS(display, cpu_transcoder), + VRR_STATUS_VRR_EN_LIVE, 1000)) + drm_err(display->drm, "Timed out waiting for VRR live status to clear\n"); +} + void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state) { struct intel_display *display = to_intel_display(old_crtc_state); @@ -655,9 +664,7 @@ void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state) if (!intel_vrr_always_use_vrr_tg(display)) { intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), trans_vrr_ctl(old_crtc_state)); - intel_de_wait_for_clear(display, - TRANS_VRR_STATUS(display, cpu_transcoder), - VRR_STATUS_VRR_EN_LIVE, 1000); + intel_vrr_wait_for_live_status_clear(display, cpu_transcoder); intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), 0); } @@ -703,8 +710,8 @@ void intel_vrr_transcoder_disable(const struct intel_crtc_state *crtc_state) intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), 0); - intel_de_wait_for_clear(display, TRANS_VRR_STATUS(display, cpu_transcoder), - VRR_STATUS_VRR_EN_LIVE, 1000); + intel_vrr_wait_for_live_status_clear(display, cpu_transcoder); + intel_de_write(display, TRANS_PUSH(display, cpu_transcoder), 0); } -- cgit v1.2.3 From c2e04017fb0b40f7b5ac1db4e9ab49e84b74f567 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 11:51:29 +0300 Subject: drm/i915/gem: add i915_gem_fence_wait_priority_display() helper Add i915_gem_fence_wait_priority_display() helper to wait with I915_PRIORITY_DISPLAY. This drops the intel_plane.c dependency on i915_scheduler_types.h, and allows us to remove the compat header from xe. Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20250924085129.146173-1-jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_plane.c | 5 +---- drivers/gpu/drm/i915/gem/i915_gem_object.h | 1 + drivers/gpu/drm/i915/gem/i915_gem_wait.c | 7 +++++++ .../gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h | 4 +--- .../gpu/drm/xe/compat-i915-headers/i915_scheduler_types.h | 13 ------------- 5 files changed, 10 insertions(+), 20 deletions(-) delete mode 100644 drivers/gpu/drm/xe/compat-i915-headers/i915_scheduler_types.h diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c index 2329f09d413d..19d4640c0e53 100644 --- a/drivers/gpu/drm/i915/display/intel_plane.c +++ b/drivers/gpu/drm/i915/display/intel_plane.c @@ -45,7 +45,6 @@ #include #include "gem/i915_gem_object.h" -#include "i915_scheduler_types.h" #include "i9xx_plane_regs.h" #include "intel_cdclk.h" #include "intel_cursor.h" @@ -1172,7 +1171,6 @@ static int intel_prepare_plane_fb(struct drm_plane *_plane, struct drm_plane_state *_new_plane_state) { - struct i915_sched_attr attr = { .priority = I915_PRIORITY_DISPLAY }; struct intel_plane *plane = to_intel_plane(_plane); struct intel_display *display = to_intel_display(plane); struct intel_plane_state *new_plane_state = @@ -1221,8 +1219,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane, goto unpin_fb; if (new_plane_state->uapi.fence) { - i915_gem_fence_wait_priority(new_plane_state->uapi.fence, - &attr); + i915_gem_fence_wait_priority_display(new_plane_state->uapi.fence); intel_display_rps_boost_after_vblank(new_plane_state->hw.crtc, new_plane_state->uapi.fence); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index 148034ef504d..8878539c10ed 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -802,6 +802,7 @@ static inline void __start_cpu_write(struct drm_i915_gem_object *obj) void i915_gem_fence_wait_priority(struct dma_fence *fence, const struct i915_sched_attr *attr); +void i915_gem_fence_wait_priority_display(struct dma_fence *fence); int i915_gem_object_wait(struct drm_i915_gem_object *obj, unsigned int flags, diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c b/drivers/gpu/drm/i915/gem/i915_gem_wait.c index 54829801d3f7..2893df65c359 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c @@ -138,6 +138,13 @@ void i915_gem_fence_wait_priority(struct dma_fence *fence, local_bh_enable(); /* kick the tasklets if queues were reprioritised */ } +void i915_gem_fence_wait_priority_display(struct dma_fence *fence) +{ + struct i915_sched_attr attr = { .priority = I915_PRIORITY_DISPLAY }; + + i915_gem_fence_wait_priority(fence, &attr); +} + int i915_gem_object_wait_priority(struct drm_i915_gem_object *obj, unsigned int flags, diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h index 8a048980ea38..0548b2e0316f 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h @@ -5,10 +5,8 @@ #define __I915_GEM_OBJECT_H__ struct dma_fence; -struct i915_sched_attr; -static inline void i915_gem_fence_wait_priority(struct dma_fence *fence, - const struct i915_sched_attr *attr) +static inline void i915_gem_fence_wait_priority_display(struct dma_fence *fence) { } diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_scheduler_types.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_scheduler_types.h deleted file mode 100644 index c11130440d31..000000000000 --- a/drivers/gpu/drm/xe/compat-i915-headers/i915_scheduler_types.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* Copyright © 2025 Intel Corporation */ - -#ifndef __I915_SCHEDULER_TYPES_H__ -#define __I915_SCHEDULER_TYPES_H__ - -#define I915_PRIORITY_DISPLAY 0 - -struct i915_sched_attr { - int priority; -}; - -#endif -- cgit v1.2.3 From 6131428a47537efd10d87ec77ee621deedb93763 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 24 Sep 2025 19:45:33 +0530 Subject: drm/i915/psr: s/intel_psr_min_vblank_delay/intel_psr_min_set_context_latency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename intel_psr_min_vblank_delay to intel_psr_min_set_context_latency to reflect that it provides the minimum value for 'Set context latency'(SCL or Window W2) for PSR/Panel Replay to work correctly across different platforms. Signed-off-by: Ankit Nautiyal Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/20250924141542.3122126-2-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_psr.c | 6 +++--- drivers/gpu/drm/i915/display/intel_psr.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 18b9baa96241..679c2a9baaee 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2369,7 +2369,7 @@ static int intel_crtc_vblank_delay(const struct intel_crtc_state *crtc_state) if (!HAS_DSB(display)) return 0; - vblank_delay = max(vblank_delay, intel_psr_min_vblank_delay(crtc_state)); + vblank_delay = max(vblank_delay, intel_psr_min_set_context_latency(crtc_state)); return vblank_delay; } diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 01bf304c705f..49ccd0864c55 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -2360,12 +2360,12 @@ void intel_psr_trigger_frame_change_event(struct intel_dsb *dsb, } /** - * intel_psr_min_vblank_delay - Minimum vblank delay needed by PSR + * intel_psr_min_set_context_latency - Minimum 'set context latency' lines needed by PSR * @crtc_state: the crtc state * - * Return minimum vblank delay needed by PSR. + * Return minimum SCL lines/delay needed by PSR. */ -int intel_psr_min_vblank_delay(const struct intel_crtc_state *crtc_state) +int intel_psr_min_set_context_latency(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 077751aa599f..9147996d6c9e 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -77,7 +77,7 @@ void intel_psr_unlock(const struct intel_crtc_state *crtc_state); void intel_psr_trigger_frame_change_event(struct intel_dsb *dsb, struct intel_atomic_state *state, struct intel_crtc *crtc); -int intel_psr_min_vblank_delay(const struct intel_crtc_state *crtc_state); +int intel_psr_min_set_context_latency(const struct intel_crtc_state *crtc_state); void intel_psr_connector_debugfs_add(struct intel_connector *connector); void intel_psr_debugfs_register(struct intel_display *display); bool intel_psr_needs_alpm(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state); -- cgit v1.2.3 From 419daf7d83b04c04c261cd729683cdbbd153bda3 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 24 Sep 2025 19:45:34 +0530 Subject: drm/i915/display: Add set_context_latency to crtc_state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'Set context latency' (SCL, Window W2) is defined as the number of lines before the double buffering point, which are required to complete programming of the registers, typically when DSB is used to program the display registers. Since we are not using this window for programming the registers, this is mostly set to 0, unless there is a requirement for few cases related to PSR/PR where the 'set context latency' should be at least 1. Currently we are using the 'set context latency' (if required) implicitly by moving the vblank start by the required amount and then measuring the delay i.e. the difference between undelayed vblank start and delayed vblank start. Since our guardband matches the vblank length, this was not a problem as the difference between the undelayed vblank and delayed vblank was at the most equal to the 'set context latency' lines. However, if we want to optimize the guardband, the difference between the undelayed and the delayed vblank will be large and we cannot use this difference as the 'set context latency' lines. To make way for this optimization of guardband, formally introduce the 'set context latency' or SCL and track it as a new member `set_context_latency` of the structure intel_crtc_state. Eventually, all references of vblank delay where we mean to use set context latency will be replaced by this new `set_context_latency` member. Note: for TGL the TRANS_SET_CONTEXT_LATENCY doesn't exist to account for the SCL. However, the VBLANK_START-VACTIVE difference plays an identical role here ie. it can be used to create the SCL window ahead of the undelayed vblank. While readback since there is no specific register to read out the SCL, use the difference between vblank start and vactive to populate the new member for TGL. v2: - Use u16 for set_context_latency. (Ville) - s/vblank_delay/set_context_latency. (Ville) - Meld the changes for TGL with this change. (Ville) v3: - Update comment to clarify the TGL case. (Ville) - Fix typo in commit message. Signed-off-by: Ankit Nautiyal Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/20250924141542.3122126-3-ankit.k.nautiyal@intel.com --- .../gpu/drm/i915/display/intel_crtc_state_dump.c | 5 +- drivers/gpu/drm/i915/display/intel_display.c | 56 +++++++++++++++------- drivers/gpu/drm/i915/display/intel_display_types.h | 3 ++ 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index 0c7f91046996..a14bcda4446c 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -289,10 +289,11 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, drm_printf(&p, "scanline offset: %d\n", intel_crtc_scanline_offset(pipe_config)); - drm_printf(&p, "vblank delay: %d, framestart delay: %d, MSA timing delay: %d\n", + drm_printf(&p, "vblank delay: %d, framestart delay: %d, MSA timing delay: %d set context latency: %d\n", pipe_config->hw.adjusted_mode.crtc_vblank_start - pipe_config->hw.adjusted_mode.crtc_vdisplay, - pipe_config->framestart_delay, pipe_config->msa_timing_delay); + pipe_config->framestart_delay, pipe_config->msa_timing_delay, + pipe_config->set_context_latency); drm_printf(&p, "vrr: %s, fixed rr: %s, vmin: %d, vmax: %d, flipline: %d, pipeline full: %d, guardband: %d vsync start: %d, vsync end: %d\n", str_yes_no(pipe_config->vrr.enable), diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 679c2a9baaee..050b6849dedc 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2361,39 +2361,44 @@ static int intel_crtc_compute_pipe_mode(struct intel_crtc_state *crtc_state) return 0; } -static int intel_crtc_vblank_delay(const struct intel_crtc_state *crtc_state) +static int intel_crtc_set_context_latency(struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - int vblank_delay = 0; + int set_context_latency = 0; if (!HAS_DSB(display)) return 0; - vblank_delay = max(vblank_delay, intel_psr_min_set_context_latency(crtc_state)); + set_context_latency = max(set_context_latency, + intel_psr_min_set_context_latency(crtc_state)); - return vblank_delay; + return set_context_latency; } -static int intel_crtc_compute_vblank_delay(struct intel_atomic_state *state, - struct intel_crtc *crtc) +static int intel_crtc_compute_set_context_latency(struct intel_atomic_state *state, + struct intel_crtc *crtc) { struct intel_display *display = to_intel_display(state); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; - int vblank_delay, max_vblank_delay; + int set_context_latency, max_vblank_delay; + + set_context_latency = intel_crtc_set_context_latency(crtc_state); - vblank_delay = intel_crtc_vblank_delay(crtc_state); max_vblank_delay = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start - 1; - if (vblank_delay > max_vblank_delay) { - drm_dbg_kms(display->drm, "[CRTC:%d:%s] vblank delay (%d) exceeds max (%d)\n", - crtc->base.base.id, crtc->base.name, vblank_delay, max_vblank_delay); + if (set_context_latency > max_vblank_delay) { + drm_dbg_kms(display->drm, "[CRTC:%d:%s] set context latency (%d) exceeds max (%d)\n", + crtc->base.base.id, crtc->base.name, + set_context_latency, + max_vblank_delay); return -EINVAL; } - adjusted_mode->crtc_vblank_start += vblank_delay; + crtc_state->set_context_latency = set_context_latency; + adjusted_mode->crtc_vblank_start += set_context_latency; return 0; } @@ -2405,7 +2410,7 @@ static int intel_crtc_compute_config(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); int ret; - ret = intel_crtc_compute_vblank_delay(state, crtc); + ret = intel_crtc_compute_set_context_latency(state, crtc); if (ret) return ret; @@ -2617,7 +2622,7 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta if (DISPLAY_VER(display) >= 13) { intel_de_write(display, TRANS_SET_CONTEXT_LATENCY(display, cpu_transcoder), - crtc_vblank_start - crtc_vdisplay); + crtc_state->set_context_latency); /* * VBLANK_START not used by hw, just clear it @@ -2707,7 +2712,7 @@ static void intel_set_transcoder_timings_lrr(const struct intel_crtc_state *crtc if (DISPLAY_VER(display) >= 13) { intel_de_write(display, TRANS_SET_CONTEXT_LATENCY(display, cpu_transcoder), - crtc_vblank_start - crtc_vdisplay); + crtc_state->set_context_latency); /* * VBLANK_START not used by hw, just clear it @@ -2820,11 +2825,24 @@ static void intel_get_transcoder_timings(struct intel_crtc *crtc, adjusted_mode->crtc_vblank_end += 1; } - if (DISPLAY_VER(display) >= 13 && !transcoder_is_dsi(cpu_transcoder)) - adjusted_mode->crtc_vblank_start = - adjusted_mode->crtc_vdisplay + + if (DISPLAY_VER(display) >= 13 && !transcoder_is_dsi(cpu_transcoder)) { + pipe_config->set_context_latency = intel_de_read(display, TRANS_SET_CONTEXT_LATENCY(display, cpu_transcoder)); + adjusted_mode->crtc_vblank_start = + adjusted_mode->crtc_vdisplay + + pipe_config->set_context_latency; + } else if (DISPLAY_VER(display) == 12) { + /* + * TGL doesn't have a dedicated register for SCL. + * Instead, the hardware derives SCL from the difference between + * TRANS_VBLANK.vblank_start and TRANS_VTOTAL.vactive. + * To reflect the HW behaviour, readout the value for SCL as + * Vblank start - Vactive. + */ + pipe_config->set_context_latency = + adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay; + } if (DISPLAY_VER(display) >= 30) pipe_config->min_hblank = intel_de_read(display, @@ -5387,6 +5405,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(vrr.guardband); } + PIPE_CONF_CHECK_I(set_context_latency); + #undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_LLI diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 358ab922d7a7..029c47743f8b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1341,6 +1341,9 @@ struct intel_crtc_state { /* LOBF flag */ bool has_lobf; + + /* W2 window or 'set context latency' lines */ + u16 set_context_latency; }; enum intel_pipe_crc_source { -- cgit v1.2.3 From 6441d9038fa9dbc2d737368ee31a3388d7e90859 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 24 Sep 2025 19:45:35 +0530 Subject: drm/i915/vrr: Use set_context_latency instead of intel_vrr_real_vblank_delay() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The helper intel_vrr_real_vblank_delay() was added to account for the SCL lines for TGL where we do not have the TRANS_SET_CONTEXT_LATENCY. Now, since we already are tracking the SCL with new member `set_context_latency` use it directly instead of the helper. Signed-off-by: Ankit Nautiyal Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/20250924141542.3122126-4-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_vrr.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 98d28de2e451..e188e5f07987 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -79,12 +79,6 @@ intel_vrr_check_modeset(struct intel_atomic_state *state) } } -static int intel_vrr_real_vblank_delay(const struct intel_crtc_state *crtc_state) -{ - return crtc_state->hw.adjusted_mode.crtc_vblank_start - - crtc_state->hw.adjusted_mode.crtc_vdisplay; -} - static int intel_vrr_extra_vblank_delay(struct intel_display *display) { /* @@ -102,7 +96,7 @@ int intel_vrr_vblank_delay(const struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); - return intel_vrr_real_vblank_delay(crtc_state) + + return crtc_state->set_context_latency + intel_vrr_extra_vblank_delay(display); } @@ -263,7 +257,7 @@ static int intel_vrr_hw_value(const struct intel_crtc_state *crtc_state, if (DISPLAY_VER(display) >= 13) return value; else - return value - intel_vrr_real_vblank_delay(crtc_state); + return value - crtc_state->set_context_latency; } /* @@ -768,9 +762,9 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) if (DISPLAY_VER(display) < 13) { /* undo what intel_vrr_hw_value() does when writing the values */ - crtc_state->vrr.flipline += intel_vrr_real_vblank_delay(crtc_state); - crtc_state->vrr.vmax += intel_vrr_real_vblank_delay(crtc_state); - crtc_state->vrr.vmin += intel_vrr_real_vblank_delay(crtc_state); + crtc_state->vrr.flipline += crtc_state->set_context_latency; + crtc_state->vrr.vmax += crtc_state->set_context_latency; + crtc_state->vrr.vmin += crtc_state->set_context_latency; crtc_state->vrr.vmin += intel_vrr_vmin_flipline_offset(display); } -- cgit v1.2.3 From b811a7635ac2a0a8ca44bc91986237a71cbbbb9a Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 24 Sep 2025 19:45:36 +0530 Subject: drm/i915/vrr: Use SCL for computing guardband MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For now guardband is equal to the vblank length so ideally it should be computed as difference between the vmin vtotal and vactive. However since we are having few lines as SCL, we need to account for this while computing the guardband. Since the vblank start is moved by SCL lines from the vactive, the delta between the vmin vtotal and new vblank start was used to account for this. Now that SCL is explicitly tracked using the `set_context_latency` member, use it directly in the guardband calculation. In the future, when the guardband is shortened or optimized, we may need to factor in both the change in the vblank start and SCL lines. For now, explicitly accounting for SCL is sufficient. v2: Fix typo: replace adjusted_mode->vdisplay with adjusted_mode->crtc_vdisplay. (Ville) Signed-off-by: Ankit Nautiyal Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/20250924141542.3122126-5-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_vrr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index e188e5f07987..e414fb53552f 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -418,7 +418,9 @@ void intel_vrr_compute_config_late(struct intel_crtc_state *crtc_state) return; crtc_state->vrr.guardband = - crtc_state->vrr.vmin - adjusted_mode->crtc_vblank_start - + crtc_state->vrr.vmin - + adjusted_mode->crtc_vdisplay - + crtc_state->set_context_latency - intel_vrr_extra_vblank_delay(display); if (DISPLAY_VER(display) < 13) { -- cgit v1.2.3 From 2a3831cd8081c9007661a0a0bf4b235dbf6ec01b Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 24 Sep 2025 19:45:37 +0530 Subject: drm/i915/dsb: s/intel_dsb_wait_vblank_delay/intel_dsb_wait_for_delayed_vblank MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The helper intel_dsb_wait_vblank_delay() is used in DSB to wait for the delayed vblank after the send push operation. Rename it to intel_dsb_wait_for_delayed_vblank() to align with the semantics. v2: Rename to intel_dsb_wait_vblank_delay instead of the proposed SCL semantics, as this will be ot only about SCL lines with different timing generator and different refresh rate modes. (Ville) Signed-off-by: Ankit Nautiyal Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/20250924141542.3122126-6-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_color.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_dsb.c | 4 ++-- drivers/gpu/drm/i915/display/intel_dsb.h | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 671db6926e4c..51db70d07fae 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -2013,7 +2013,7 @@ void intel_color_prepare_commit(struct intel_atomic_state *state, if (crtc_state->use_dsb && intel_color_uses_chained_dsb(crtc_state)) { intel_vrr_send_push(crtc_state->dsb_color, crtc_state); - intel_dsb_wait_vblank_delay(state, crtc_state->dsb_color); + intel_dsb_wait_for_delayed_vblank(state, crtc_state->dsb_color); intel_vrr_check_push_sent(crtc_state->dsb_color, crtc_state); intel_dsb_interrupt(crtc_state->dsb_color); } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 050b6849dedc..b57efd870774 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -7271,7 +7271,7 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state, intel_dsb_wait_vblanks(new_crtc_state->dsb_commit, 1); intel_vrr_send_push(new_crtc_state->dsb_commit, new_crtc_state); - intel_dsb_wait_vblank_delay(state, new_crtc_state->dsb_commit); + intel_dsb_wait_for_delayed_vblank(state, new_crtc_state->dsb_commit); intel_vrr_check_push_sent(new_crtc_state->dsb_commit, new_crtc_state); intel_dsb_interrupt(new_crtc_state->dsb_commit); diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index dee44d45b668..135d40852e4c 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -815,8 +815,8 @@ void intel_dsb_chain(struct intel_atomic_state *state, wait_for_vblank ? DSB_WAIT_FOR_VBLANK : 0); } -void intel_dsb_wait_vblank_delay(struct intel_atomic_state *state, - struct intel_dsb *dsb) +void intel_dsb_wait_for_delayed_vblank(struct intel_atomic_state *state, + struct intel_dsb *dsb) { struct intel_crtc *crtc = dsb->crtc; const struct intel_crtc_state *crtc_state = diff --git a/drivers/gpu/drm/i915/display/intel_dsb.h b/drivers/gpu/drm/i915/display/intel_dsb.h index c8f4499916eb..2f31f2c1d0c5 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.h +++ b/drivers/gpu/drm/i915/display/intel_dsb.h @@ -48,8 +48,8 @@ void intel_dsb_nonpost_end(struct intel_dsb *dsb); void intel_dsb_interrupt(struct intel_dsb *dsb); void intel_dsb_wait_usec(struct intel_dsb *dsb, int count); void intel_dsb_wait_vblanks(struct intel_dsb *dsb, int count); -void intel_dsb_wait_vblank_delay(struct intel_atomic_state *state, - struct intel_dsb *dsb); +void intel_dsb_wait_for_delayed_vblank(struct intel_atomic_state *state, + struct intel_dsb *dsb); void intel_dsb_wait_scanline_in(struct intel_atomic_state *state, struct intel_dsb *dsb, int lower, int upper); -- cgit v1.2.3 From 4e5c033cfe851625908b2121bf2c01eadabc4906 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 24 Sep 2025 19:45:38 +0530 Subject: drm/i915/display: Wait for scl start instead of dsb_wait_vblanks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until LNL, intel_dsb_wait_vblanks() used to wait for the undelayed vblank start. However, from PTL onwards, it waits for the start of the safe-window defined by the number of lines programmed in the register TRANS_SET_CONTEXT_LATENCY. This change was introduced to move the SCL window out of the vblank region, supporting modes with higher refresh rates and smaller vblanks. This change introduces a "safe window" a scanline range from (undelayed vblank - SCL) to (delayed vblank - SCL). As a result, on PTL+ platforms, the DSB wait for vblank completes exactly SCL lines earlier than the undelayed vblank start (safe window start). If the flip occurs in the active region and the push happens before the vmin decision boundary, the DSB wait fires early, and the push is sent inside this safe window. In such cases, the push bit is cleared at the delayed vblank, but our wait logic does not account for the early trigger, leading to DSB poll errors. To fix this, we add an explicit wait for the end of the safe window i.e., the scanline range from (undelayed vblank - SCL) to (delayed vblank - SCL). Once past this window, we are exactly SCL lines away from the delayed vblank, and our existing wait logic works as intended. This additional wait is only effective if the push occurs before the vmin decision boundary. If the push happens after the boundary, the hardware already guarantees we're SCL lines away from the delayed vblank, and the extra wait becomes a no-op. v2: - Use helpers for safe window start/end. (Ville) - Move the extra wait inside the helper to wait for delayed vblank. (Ville) - Update the commit message. v3: - Add more documentation for explanation for the wait. (Ville) - Rename intel_vrr_vmin_safe_window_start/end as this is vmin safe window. (Ville) - Minor refactoring to align with the code. (Ville) - Update the commit message for more clarity. v4: - Retain name for intel_vrr_safe_window_start as it doesn't change with vmin/vmax etc. (Ville) Signed-off-by: Ankit Nautiyal Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/20250924141542.3122126-7-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_dsb.c | 16 ++++++++++++++++ drivers/gpu/drm/i915/display/intel_vrr.c | 17 +++++++++++++++++ drivers/gpu/drm/i915/display/intel_vrr.h | 2 ++ 3 files changed, 35 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index 135d40852e4c..1d9379a3240b 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -824,6 +824,22 @@ void intel_dsb_wait_for_delayed_vblank(struct intel_atomic_state *state, int usecs = intel_scanlines_to_usecs(&crtc_state->hw.adjusted_mode, dsb_vblank_delay(state, crtc)); + /* + * If the push happened before the vmin decision boundary + * we don't know how far we are from the undelayed vblank. + * Wait until we're past the vmin safe window, at which + * point we're SCL lines away from the delayed vblank. + * + * If the push happened after the vmin decision boundary + * the hardware itself guarantees that we're SCL lines + * away from the delayed vblank, and we won't be inside + * the vmin safe window so this extra wait does nothing. + */ + if (pre_commit_is_vrr_active(state, crtc)) + intel_dsb_wait_scanline_out(state, dsb, + intel_vrr_safe_window_start(crtc_state), + intel_vrr_vmin_safe_window_end(crtc_state)); + intel_dsb_wait_usec(dsb, usecs); } diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index e414fb53552f..5f78b1af5fd5 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -807,3 +807,20 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) if (crtc_state->vrr.enable) crtc_state->mode_flags |= I915_MODE_FLAG_VRR; } + +int intel_vrr_safe_window_start(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + if (DISPLAY_VER(display) >= 30) + return crtc_state->hw.adjusted_mode.crtc_vdisplay - + crtc_state->set_context_latency; + else + return crtc_state->hw.adjusted_mode.crtc_vdisplay; +} + +int intel_vrr_vmin_safe_window_end(const struct intel_crtc_state *crtc_state) +{ + return intel_vrr_vmin_vblank_start(crtc_state) - + crtc_state->set_context_latency; +} diff --git a/drivers/gpu/drm/i915/display/intel_vrr.h b/drivers/gpu/drm/i915/display/intel_vrr.h index 38bf9996b883..32f8644fc369 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.h +++ b/drivers/gpu/drm/i915/display/intel_vrr.h @@ -41,5 +41,7 @@ void intel_vrr_transcoder_enable(const struct intel_crtc_state *crtc_state); void intel_vrr_transcoder_disable(const struct intel_crtc_state *crtc_state); void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state); bool intel_vrr_always_use_vrr_tg(struct intel_display *display); +int intel_vrr_safe_window_start(const struct intel_crtc_state *crtc_state); +int intel_vrr_vmin_safe_window_end(const struct intel_crtc_state *crtc_state); #endif /* __INTEL_VRR_H__ */ -- cgit v1.2.3 From 94da8e5eee9c2e33cc1d2d61029c9db0c6c5a55a Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 24 Sep 2025 19:45:39 +0530 Subject: drm/i915/reg_defs: Add REG_FIELD_MAX wrapper for FIELD_MAX() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce REG_FIELD_MAX macro as local wrapper around FIELD_MAX() to return the maximum value representable by a bit mask. The value is cast to u32 for consistency with other REG_* macros and assumes the bitfield fits within 32 bits. v2: Use __mask as macro argument aligning with other macros. (Ville) Signed-off-by: Ankit Nautiyal Reviewed-by: Ville Syrjälä Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20250924141542.3122126-8-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/i915_reg_defs.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg_defs.h b/drivers/gpu/drm/i915/i915_reg_defs.h index bfe98cb9a038..e81fac8ab51b 100644 --- a/drivers/gpu/drm/i915/i915_reg_defs.h +++ b/drivers/gpu/drm/i915/i915_reg_defs.h @@ -174,6 +174,16 @@ */ #define REG_FIELD_GET8(__mask, __val) ((u8)FIELD_GET(__mask, __val)) +/** + * REG_FIELD_MAX() - produce the maximum value representable by a field + * @__mask: shifted mask defining the field's length and position + * + * Local wrapper for FIELD_MAX() to return the maximum bit value that can + * be held in the field specified by @_mask, cast to u32 for consistency + * with other macros. + */ +#define REG_FIELD_MAX(__mask) ((u32)FIELD_MAX(__mask)) + typedef struct { u32 reg; } i915_reg_t; -- cgit v1.2.3 From 5f9172bf6f18da9c43f738b02de904d454459071 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 24 Sep 2025 19:45:40 +0530 Subject: drm/i915/vrr: Clamp guardband as per hardware and timing constraints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The maximum guardband value is constrained by two factors: - The actual vblank length minus set context latency (SCL) - The hardware register field width: - 8 bits for ICL/TGL (VRR_CTL_PIPELINE_FULL_MASK -> max 255) - 16 bits for ADL+ (XELPD_VRR_CTL_VRR_GUARDBAND_MASK -> max 65535) Remove the #FIXME and clamp the guardband to the maximum allowed value. v2: - Use REG_FIELD_MAX(). (Ville) - Separate out functions for intel_vrr_max_guardband(), intel_vrr_max_vblank_guardband(). (Ville) v3: - Fix Typo: Add the missing adjusted_mode->crtc_vdisplay in guardband computation. (Ville) - Refactor intel_vrr_max_hw_guardband() and use else for consistency. (Ville) v4: - Drop max_guardband from intel_vrr_max_hw_guardband(). (Ville) Signed-off-by: Ankit Nautiyal Reviewed-by: Ville Syrjälä (#v2) Link: https://lore.kernel.org/r/20250924141542.3122126-9-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_vrr.c | 47 ++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 5f78b1af5fd5..da073bbabc46 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -409,6 +409,38 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state, } } +static int +intel_vrr_max_hw_guardband(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + int max_pipeline_full = REG_FIELD_MAX(VRR_CTL_PIPELINE_FULL_MASK); + + if (DISPLAY_VER(display) >= 13) + return REG_FIELD_MAX(XELPD_VRR_CTL_VRR_GUARDBAND_MASK); + else + return intel_vrr_pipeline_full_to_guardband(crtc_state, + max_pipeline_full); +} + +static int +intel_vrr_max_vblank_guardband(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + + return crtc_state->vrr.vmin - + adjusted_mode->crtc_vdisplay - + crtc_state->set_context_latency - + intel_vrr_extra_vblank_delay(display); +} + +static int +intel_vrr_max_guardband(struct intel_crtc_state *crtc_state) +{ + return min(intel_vrr_max_hw_guardband(crtc_state), + intel_vrr_max_vblank_guardband(crtc_state)); +} + void intel_vrr_compute_config_late(struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); @@ -417,22 +449,13 @@ void intel_vrr_compute_config_late(struct intel_crtc_state *crtc_state) if (!intel_vrr_possible(crtc_state)) return; - crtc_state->vrr.guardband = - crtc_state->vrr.vmin - - adjusted_mode->crtc_vdisplay - - crtc_state->set_context_latency - - intel_vrr_extra_vblank_delay(display); - - if (DISPLAY_VER(display) < 13) { - /* FIXME handle the limit in a proper way */ - crtc_state->vrr.guardband = - min(crtc_state->vrr.guardband, - intel_vrr_pipeline_full_to_guardband(crtc_state, 255)); + crtc_state->vrr.guardband = min(crtc_state->vrr.vmin - adjusted_mode->crtc_vdisplay, + intel_vrr_max_guardband(crtc_state)); + if (DISPLAY_VER(display) < 13) crtc_state->vrr.pipeline_full = intel_vrr_guardband_to_pipeline_full(crtc_state, crtc_state->vrr.guardband); - } } static u32 trans_vrr_ctl(const struct intel_crtc_state *crtc_state) -- cgit v1.2.3 From 68f1d1764d50cf65f466cac0e6286f40c8ff93e9 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Wed, 24 Sep 2025 19:45:41 +0530 Subject: drm/i915/display: Drop intel_vrr_vblank_delay and use set_context_latency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The helper intel_vrr_vblank_delay() was used to keep track of the SCL lines + the extra vblank delay required for ICL/TGL. This was used to wait for sufficient lines for: -push send bit to clear for VRR case -evasion to delay the commit. For first case we are using safe window scanline wait and with that we just need to wait for SCL lines, we do not need to wait for the extra vblank delay required for ICL/TGL. For the second case, we actually do not need to wait for extra lines before the undelayed vblank, if we are already in the safe window. To sum up, SCL lines is sufficient for both cases. So drop the helper intel_vrr_vblank_delay and just use crtc_state->set_context_latency instead. Signed-off-by: Ankit Nautiyal Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/20250924141542.3122126-10-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_dsb.c | 4 ++-- drivers/gpu/drm/i915/display/intel_vblank.c | 2 +- drivers/gpu/drm/i915/display/intel_vrr.c | 8 -------- drivers/gpu/drm/i915/display/intel_vrr.h | 1 - 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index 1d9379a3240b..ae8574880ef2 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -128,7 +128,7 @@ static int dsb_vblank_delay(struct intel_atomic_state *state, * scanline until the delayed vblank occurs after * TRANS_PUSH has been written. */ - return intel_vrr_vblank_delay(crtc_state) + 1; + return crtc_state->set_context_latency + 1; else return intel_mode_vblank_delay(&crtc_state->hw.adjusted_mode); } @@ -723,7 +723,7 @@ void intel_dsb_vblank_evade(struct intel_atomic_state *state, intel_dsb_emit_wait_dsl(dsb, DSB_OPCODE_WAIT_DSL_OUT, 0, 0); if (pre_commit_is_vrr_active(state, crtc)) { - int vblank_delay = intel_vrr_vblank_delay(crtc_state); + int vblank_delay = crtc_state->set_context_latency; end = intel_vrr_vmin_vblank_start(crtc_state); start = end - vblank_delay - latency; diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c index c15234c1d96e..0b7fcc05e64c 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.c +++ b/drivers/gpu/drm/i915/display/intel_vblank.c @@ -681,7 +681,7 @@ void intel_vblank_evade_init(const struct intel_crtc_state *old_crtc_state, else evade->vblank_start = intel_vrr_vmax_vblank_start(crtc_state); - vblank_delay = intel_vrr_vblank_delay(crtc_state); + vblank_delay = crtc_state->set_context_latency; } else { evade->vblank_start = intel_mode_vblank_start(adjusted_mode); diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index da073bbabc46..190c51be5cbc 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -92,14 +92,6 @@ static int intel_vrr_extra_vblank_delay(struct intel_display *display) return DISPLAY_VER(display) < 13 ? 1 : 0; } -int intel_vrr_vblank_delay(const struct intel_crtc_state *crtc_state) -{ - struct intel_display *display = to_intel_display(crtc_state); - - return crtc_state->set_context_latency + - intel_vrr_extra_vblank_delay(display); -} - static int intel_vrr_vmin_flipline_offset(struct intel_display *display) { /* diff --git a/drivers/gpu/drm/i915/display/intel_vrr.h b/drivers/gpu/drm/i915/display/intel_vrr.h index 32f8644fc369..7317f8730089 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.h +++ b/drivers/gpu/drm/i915/display/intel_vrr.h @@ -35,7 +35,6 @@ int intel_vrr_vmax_vtotal(const struct intel_crtc_state *crtc_state); int intel_vrr_vmin_vtotal(const struct intel_crtc_state *crtc_state); int intel_vrr_vmax_vblank_start(const struct intel_crtc_state *crtc_state); int intel_vrr_vmin_vblank_start(const struct intel_crtc_state *crtc_state); -int intel_vrr_vblank_delay(const struct intel_crtc_state *crtc_state); bool intel_vrr_is_fixed_rr(const struct intel_crtc_state *crtc_state); void intel_vrr_transcoder_enable(const struct intel_crtc_state *crtc_state); void intel_vrr_transcoder_disable(const struct intel_crtc_state *crtc_state); -- cgit v1.2.3 From fe3c035330f545712919f9fe0a6613f4abc8ad56 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Thu, 25 Sep 2025 07:53:52 +0530 Subject: drm/i915/dsb: Inline dsb_vblank_delay() into intel_dsb_wait_for_delayed_vblank() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the now single-use dsb_vblank_delay() helper and inline its logic directly into intel_dsb_wait_for_delayed_vblank(). This will help to keep all VRR related wait stuff in one place. v2: Use intel_scanlines_to_usecs() in intel_dsb_wait_usec(). (Ville) Signed-off-by: Ankit Nautiyal Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/20250925022352.3129859-1-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_dsb.c | 59 ++++++++++++++------------------ 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index ae8574880ef2..4ad4efbf9253 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -115,24 +115,6 @@ static bool pre_commit_is_vrr_active(struct intel_atomic_state *state, return old_crtc_state->vrr.enable && !intel_crtc_vrr_disabling(state, crtc); } -static int dsb_vblank_delay(struct intel_atomic_state *state, - struct intel_crtc *crtc) -{ - const struct intel_crtc_state *crtc_state = - intel_pre_commit_crtc_state(state, crtc); - - if (pre_commit_is_vrr_active(state, crtc)) - /* - * When the push is sent during vblank it will trigger - * on the next scanline, hence we have up to one extra - * scanline until the delayed vblank occurs after - * TRANS_PUSH has been written. - */ - return crtc_state->set_context_latency + 1; - else - return intel_mode_vblank_delay(&crtc_state->hw.adjusted_mode); -} - static int dsb_vtotal(struct intel_atomic_state *state, struct intel_crtc *crtc) { @@ -821,26 +803,37 @@ void intel_dsb_wait_for_delayed_vblank(struct intel_atomic_state *state, struct intel_crtc *crtc = dsb->crtc; const struct intel_crtc_state *crtc_state = intel_pre_commit_crtc_state(state, crtc); - int usecs = intel_scanlines_to_usecs(&crtc_state->hw.adjusted_mode, - dsb_vblank_delay(state, crtc)); + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + int wait_scanlines; - /* - * If the push happened before the vmin decision boundary - * we don't know how far we are from the undelayed vblank. - * Wait until we're past the vmin safe window, at which - * point we're SCL lines away from the delayed vblank. - * - * If the push happened after the vmin decision boundary - * the hardware itself guarantees that we're SCL lines - * away from the delayed vblank, and we won't be inside - * the vmin safe window so this extra wait does nothing. - */ - if (pre_commit_is_vrr_active(state, crtc)) + if (pre_commit_is_vrr_active(state, crtc)) { + /* + * If the push happened before the vmin decision boundary + * we don't know how far we are from the undelayed vblank. + * Wait until we're past the vmin safe window, at which + * point we're SCL lines away from the delayed vblank. + * + * If the push happened after the vmin decision boundary + * the hardware itself guarantees that we're SCL lines + * away from the delayed vblank, and we won't be inside + * the vmin safe window so this extra wait does nothing. + */ intel_dsb_wait_scanline_out(state, dsb, intel_vrr_safe_window_start(crtc_state), intel_vrr_vmin_safe_window_end(crtc_state)); + /* + * When the push is sent during vblank it will trigger + * on the next scanline, hence we have up to one extra + * scanline until the delayed vblank occurs after + * TRANS_PUSH has been written. + */ + wait_scanlines = crtc_state->set_context_latency + 1; + } else { + wait_scanlines = intel_mode_vblank_delay(adjusted_mode); + } - intel_dsb_wait_usec(dsb, usecs); + intel_dsb_wait_usec(dsb, intel_scanlines_to_usecs(adjusted_mode, wait_scanlines)); } /** -- cgit v1.2.3 From 69b4d367fff6d311da6e3ce1b8b34b3e37b59b5a Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Thu, 18 Sep 2025 21:45:16 +0000 Subject: drm/i915/gvt: Simplify case switch in intel_vgpu_ioctl We do not need a case switch to check cap_type_id in intel_vgpu_ioctl for various reasons (it's impossible to hit the default case in the current code, there's only one valid case to check, the error handling code overlaps in both cases, etc.). Simplify the case switch into a single if statement. This has the additional effect of simplifying the error handling code. Note that it is still currently impossible for 'if (cap_type_id == VFIO_REGION_INFO_CAP_SPARSE_MMAP)' to fail, but we should still guard against the possibility of this changing in the future. Signed-off-by: Jonathan Cavitt Cc: Andi Shyti Reviewed-by: Zhenyu Wang Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250918214515.66926-2-jonathan.cavitt@intel.com --- drivers/gpu/drm/i915/gvt/kvmgt.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 69830a5c49d3..70af86d46fe8 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -1279,20 +1279,15 @@ static long intel_vgpu_ioctl(struct vfio_device *vfio_dev, unsigned int cmd, } if ((info.flags & VFIO_REGION_INFO_FLAG_CAPS) && sparse) { - switch (cap_type_id) { - case VFIO_REGION_INFO_CAP_SPARSE_MMAP: + ret = -EINVAL; + if (cap_type_id == VFIO_REGION_INFO_CAP_SPARSE_MMAP) ret = vfio_info_add_capability(&caps, &sparse->header, struct_size(sparse, areas, sparse->nr_areas)); - if (ret) { - kfree(sparse); - return ret; - } - break; - default: + if (ret) { kfree(sparse); - return -EINVAL; + return ret; } } -- cgit v1.2.3 From 22a2f2e35f9c08c8572003d1e6d3f0e9ab968837 Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Tue, 23 Sep 2025 21:23:33 +0000 Subject: drm/i915/gvt: Improve intel_vgpu_ioctl hdr error handling Add error handling for the following VFIO_DEVICE_SET_IRQS cases with respect to the hdr struct: - More than one VFIO_IRQ_DATA_TYPE_MASK flag is set in hdr.flags - More than one VFIO_IRQ_ACTION_TYPE_MASK flag is set in hdr.flags - hdr.count is not specified Note that since hdr.count != 0, data_size != 0 is guaranteed unless vfio_set_irqs_validate_and_prepare fails and returns an error. So, we no longer need to check data_size before running memdup_user because checking the return value of the function is sufficient. v2: Use correct name for mask v3: Use is_power_of_2 over hweight32 as it's more efficient (Andi) Signed-off-by: Jonathan Cavitt Cc: Andi Shyti Reviewed-by: Zhenyu Wang Reviewed-by: Krzysztof Karas Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250923212332.112137-2-jonathan.cavitt@intel.com --- drivers/gpu/drm/i915/gvt/kvmgt.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 70af86d46fe8..183128b84630 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -1356,21 +1356,27 @@ static long intel_vgpu_ioctl(struct vfio_device *vfio_dev, unsigned int cmd, if (copy_from_user(&hdr, (void __user *)arg, minsz)) return -EFAULT; + if (!is_power_of_2(hdr.flags & VFIO_IRQ_SET_DATA_TYPE_MASK) || + !is_power_of_2(hdr.flags & VFIO_IRQ_SET_ACTION_TYPE_MASK)) + return -EINVAL; + if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) { int max = intel_vgpu_get_irq_count(vgpu, hdr.index); + if (!hdr.count) + return -EINVAL; + ret = vfio_set_irqs_validate_and_prepare(&hdr, max, VFIO_PCI_NUM_IRQS, &data_size); if (ret) { gvt_vgpu_err("intel:vfio_set_irqs_validate_and_prepare failed\n"); return -EINVAL; } - if (data_size) { - data = memdup_user((void __user *)(arg + minsz), - data_size); - if (IS_ERR(data)) - return PTR_ERR(data); - } + + data = memdup_user((void __user *)(arg + minsz), + data_size); + if (IS_ERR(data)) + return PTR_ERR(data); } ret = intel_vgpu_set_irqs(vgpu, hdr.flags, hdr.index, -- cgit v1.2.3 From 40ac9b3eb09085dd729032ac5e1ea213068f34cc Mon Sep 17 00:00:00 2001 From: Madhur Kumar Date: Wed, 24 Sep 2025 01:20:51 +0530 Subject: drm/i915: i915_pmu: Use sysfs_emit() instead of sprintf() Follow the advice in Documentation/filesystems/sysfs.rst: show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. Signed-off-by: Madhur Kumar Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20250923195051.1277855-1-madhurkumar004@gmail.com --- drivers/gpu/drm/i915/i915_pmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 5bc696bfbb0f..d8f69bba79a9 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -895,7 +895,7 @@ static ssize_t i915_pmu_format_show(struct device *dev, struct i915_str_attribute *eattr; eattr = container_of(attr, struct i915_str_attribute, attr); - return sprintf(buf, "%s\n", eattr->str); + return sysfs_emit(buf, "%s\n", eattr->str); } #define I915_PMU_FORMAT_ATTR(_name, _config) \ @@ -925,7 +925,7 @@ static ssize_t i915_pmu_event_show(struct device *dev, struct i915_ext_attribute *eattr; eattr = container_of(attr, struct i915_ext_attribute, attr); - return sprintf(buf, "config=0x%lx\n", eattr->val); + return sysfs_emit(buf, "config=0x%lx\n", eattr->val); } #define __event(__counter, __name, __unit) \ -- cgit v1.2.3 From 924adb0bbdd8fef25fd229c76e3f602c3e8752ee Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Mon, 22 Sep 2025 13:27:25 +0300 Subject: drm/i915/psr: Deactivate PSR only on LNL and when selective fetch enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using intel_psr_exit in frontbuffer flush on older platforms seems to be causing problems. Sending single full frame update using intel_psr_force_update is anyways more optimal compared to psr deactivate/activate -> move back to this approach on PSR1, PSR HW tracking and Panel Replay full frame update and use deactivate/activate only on LunarLake and only when selective fetch is enabled. Tested-by: Lemen Tested-by: Koos Vriezen Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14946 Signed-off-by: Jouni Högander Reviewed-by: Mika Kahola Link: https://lore.kernel.org/r/20250922102725.2752742-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 49ccd0864c55..f7115969b4c5 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -3402,6 +3402,7 @@ static void _psr_flush_handle(struct intel_dp *intel_dp) struct intel_display *display = to_intel_display(intel_dp); if (DISPLAY_VER(display) < 20 && intel_dp->psr.psr2_sel_fetch_enabled) { + /* Selective fetch prior LNL */ if (intel_dp->psr.psr2_sel_fetch_cff_enabled) { /* can we turn CFF off? */ if (intel_dp->psr.busy_frontbuffer_bits == 0) @@ -3420,12 +3421,19 @@ static void _psr_flush_handle(struct intel_dp *intel_dp) intel_psr_configure_full_frame_update(intel_dp); intel_psr_force_update(intel_dp); + } else if (!intel_dp->psr.psr2_sel_fetch_enabled) { + /* + * PSR1 on all platforms + * PSR2 HW tracking + * Panel Replay Full frame update + */ + intel_psr_force_update(intel_dp); } else { + /* Selective update LNL onwards */ intel_psr_exit(intel_dp); } - if ((!intel_dp->psr.psr2_sel_fetch_enabled || DISPLAY_VER(display) >= 20) && - !intel_dp->psr.busy_frontbuffer_bits) + if (!intel_dp->psr.active && !intel_dp->psr.busy_frontbuffer_bits) queue_work(display->wq.unordered, &intel_dp->psr.work); } -- cgit v1.2.3 From 3198609ecc951b31b7e824e77c9c6460d711a55e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 19:43:30 +0300 Subject: drm/{i915, xe}/stolen: rename i915_stolen_fb to intel_stolen_node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a more generic name than one that refers to "i915" and "fb". Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/925fd07d3f2a6115c71984f5a40a06c9eb46a539.1758732183.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbc.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_stolen.h | 2 +- drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 0d380c825791..6a7357fa89db 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -102,7 +102,7 @@ struct intel_fbc { struct mutex lock; unsigned int busy_bits; - struct i915_stolen_fb compressed_fb, compressed_llb; + struct intel_stolen_node compressed_fb, compressed_llb; enum intel_fbc_id id; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h index dfe0db8bb1b9..c2f9c994e0ae 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h @@ -12,7 +12,7 @@ struct drm_i915_private; struct drm_mm_node; struct drm_i915_gem_object; -#define i915_stolen_fb drm_mm_node +#define intel_stolen_node drm_mm_node int i915_gem_stolen_insert_node(struct drm_i915_private *i915, struct drm_mm_node *node, u64 size, diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h index f097fc6d5127..62389b290907 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h @@ -12,12 +12,12 @@ struct xe_bo; -struct i915_stolen_fb { +struct intel_stolen_node { struct xe_bo *bo; }; static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, - struct i915_stolen_fb *fb, + struct intel_stolen_node *fb, u32 size, u32 align, u32 start, u32 end) { @@ -47,7 +47,7 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, } static inline int i915_gem_stolen_insert_node(struct xe_device *xe, - struct i915_stolen_fb *fb, + struct intel_stolen_node *fb, u32 size, u32 align) { /* Not used on xe */ @@ -56,7 +56,7 @@ static inline int i915_gem_stolen_insert_node(struct xe_device *xe, } static inline void i915_gem_stolen_remove_node(struct xe_device *xe, - struct i915_stolen_fb *fb) + struct intel_stolen_node *fb) { xe_bo_unpin_map_no_vm(fb->bo); fb->bo = NULL; @@ -65,7 +65,7 @@ static inline void i915_gem_stolen_remove_node(struct xe_device *xe, #define i915_gem_stolen_initialized(xe) (!!ttm_manager_type(&(xe)->ttm, XE_PL_STOLEN)) #define i915_gem_stolen_node_allocated(fb) (!!((fb)->bo)) -static inline u32 i915_gem_stolen_node_offset(struct i915_stolen_fb *fb) +static inline u32 i915_gem_stolen_node_offset(struct intel_stolen_node *fb) { struct xe_res_cursor res; -- cgit v1.2.3 From 511d2d70dfc96ccc37eef7203b345a7dbe55e254 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 19:43:31 +0300 Subject: drm/xe/stolen: rename fb to node in stolen compat header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's more about node than fb, and this makes more sense now that the struct is also named intel_stolen_node. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/71a7872e47da5f3fbe61cc21723bfcf8ff6518b8.1758732183.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- .../xe/compat-i915-headers/gem/i915_gem_stolen.h | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h index 62389b290907..b45575b15322 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h @@ -17,7 +17,7 @@ struct intel_stolen_node { }; static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, - struct intel_stolen_node *fb, + struct intel_stolen_node *node, u32 size, u32 align, u32 start, u32 end) { @@ -41,13 +41,13 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, return err; } - fb->bo = bo; + node->bo = bo; return err; } static inline int i915_gem_stolen_insert_node(struct xe_device *xe, - struct intel_stolen_node *fb, + struct intel_stolen_node *node, u32 size, u32 align) { /* Not used on xe */ @@ -56,20 +56,20 @@ static inline int i915_gem_stolen_insert_node(struct xe_device *xe, } static inline void i915_gem_stolen_remove_node(struct xe_device *xe, - struct intel_stolen_node *fb) + struct intel_stolen_node *node) { - xe_bo_unpin_map_no_vm(fb->bo); - fb->bo = NULL; + xe_bo_unpin_map_no_vm(node->bo); + node->bo = NULL; } #define i915_gem_stolen_initialized(xe) (!!ttm_manager_type(&(xe)->ttm, XE_PL_STOLEN)) -#define i915_gem_stolen_node_allocated(fb) (!!((fb)->bo)) +#define i915_gem_stolen_node_allocated(node) (!!((node)->bo)) -static inline u32 i915_gem_stolen_node_offset(struct intel_stolen_node *fb) +static inline u32 i915_gem_stolen_node_offset(struct intel_stolen_node *node) { struct xe_res_cursor res; - xe_res_first(fb->bo->ttm.resource, 0, 4096, &res); + xe_res_first(node->bo->ttm.resource, 0, 4096, &res); return res.start; } @@ -78,8 +78,8 @@ static inline u32 i915_gem_stolen_node_offset(struct intel_stolen_node *fb) /* Used for gen9 specific WA. Gen9 is not supported by Xe */ #define i915_gem_stolen_area_size(xe) (!WARN_ON(1)) -#define i915_gem_stolen_node_address(xe, fb) (xe_ttm_stolen_gpu_offset(xe) + \ - i915_gem_stolen_node_offset(fb)) -#define i915_gem_stolen_node_size(fb) ((u64)((fb)->bo->ttm.base.size)) +#define i915_gem_stolen_node_address(xe, node) (xe_ttm_stolen_gpu_offset(xe) + \ + i915_gem_stolen_node_offset(node)) +#define i915_gem_stolen_node_size(node) ((u64)((node)->bo->ttm.base.size)) #endif -- cgit v1.2.3 From b6500640acbcc93a371be3a253a558db81132e6b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 19:43:32 +0300 Subject: drm/xe/stolen: convert compat stolen macros to inline functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve type safety. Allows getting rid of a __maybe_unused annotation too. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/1ec1fa59e0e54da49a1ec4fd1d535288066db502.1758732183.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbc.c | 2 +- .../xe/compat-i915-headers/gem/i915_gem_stolen.h | 39 ++++++++++++++++++---- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 6a7357fa89db..cc67de6c06cf 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -797,7 +797,7 @@ static u64 intel_fbc_cfb_base_max(struct intel_display *display) static u64 intel_fbc_stolen_end(struct intel_display *display) { - struct drm_i915_private __maybe_unused *i915 = to_i915(display->drm); + struct drm_i915_private *i915 = to_i915(display->drm); u64 end; /* The FBC hardware for BDW/SKL doesn't have access to the stolen diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h index b45575b15322..2c77457837e4 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h @@ -62,8 +62,15 @@ static inline void i915_gem_stolen_remove_node(struct xe_device *xe, node->bo = NULL; } -#define i915_gem_stolen_initialized(xe) (!!ttm_manager_type(&(xe)->ttm, XE_PL_STOLEN)) -#define i915_gem_stolen_node_allocated(node) (!!((node)->bo)) +static inline bool i915_gem_stolen_initialized(struct xe_device *xe) +{ + return ttm_manager_type(&xe->ttm, XE_PL_STOLEN); +} + +static inline bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node) +{ + return node->bo; +} static inline u32 i915_gem_stolen_node_offset(struct intel_stolen_node *node) { @@ -74,12 +81,30 @@ static inline u32 i915_gem_stolen_node_offset(struct intel_stolen_node *node) } /* Used for < gen4. These are not supported by Xe */ -#define i915_gem_stolen_area_address(xe) (!WARN_ON(1)) +static inline u64 i915_gem_stolen_area_address(const struct xe_device *xe) +{ + WARN_ON(1); + + return 0; +} + /* Used for gen9 specific WA. Gen9 is not supported by Xe */ -#define i915_gem_stolen_area_size(xe) (!WARN_ON(1)) +static inline u64 i915_gem_stolen_area_size(const struct xe_device *xe) +{ + WARN_ON(1); + + return 0; +} -#define i915_gem_stolen_node_address(xe, node) (xe_ttm_stolen_gpu_offset(xe) + \ - i915_gem_stolen_node_offset(node)) -#define i915_gem_stolen_node_size(node) ((u64)((node)->bo->ttm.base.size)) +static inline u64 i915_gem_stolen_node_address(struct xe_device *xe, + struct intel_stolen_node *node) +{ + return xe_ttm_stolen_gpu_offset(xe) + i915_gem_stolen_node_offset(node); +} + +static inline u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node) +{ + return node->bo->ttm.base.size; +} #endif -- cgit v1.2.3 From 9f697958bb6e8baec08569210dc0545b8447dd4d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 19:43:33 +0300 Subject: drm/xe/stolen: switch from BUG_ON() to WARN_ON() in compat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're pretty much never supposed to be using BUG_ON(). Switch to WARN_ON(). Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/d14c693a3387a5d89bb88e81349639b5ec5663fb.1758732183.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h index 2c77457837e4..be249f51231d 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h @@ -51,7 +51,8 @@ static inline int i915_gem_stolen_insert_node(struct xe_device *xe, u32 size, u32 align) { /* Not used on xe */ - BUG_ON(1); + WARN_ON(1); + return -ENODEV; } -- cgit v1.2.3 From 59998644b79ace2abb73379cb1940c3f5ac09376 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 19:43:34 +0300 Subject: drm/i915/stolen: convert intel_stolen_node into a real struct of its own MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i915_gem_stolen.h simply defines intel_stolen_node as drm_mm_node. Make struct intel_stolen_node an actual struct of its own right, and embed struct drm_mm_node inside. This allow better unification between i915 and xe. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/36762f611566d81427e702369f4e8207ead5f26c.1758732183.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 66 ++++++++++++++++++++---------- drivers/gpu/drm/i915/gem/i915_gem_stolen.h | 22 +++++----- 2 files changed, 56 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 3380151edfc1..70ee34303e36 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -36,9 +36,9 @@ * for is a boon. */ -int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915, - struct drm_mm_node *node, u64 size, - unsigned alignment, u64 start, u64 end) +static int __i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915, + struct drm_mm_node *node, u64 size, + unsigned int alignment, u64 start, u64 end) { int ret; @@ -58,24 +58,46 @@ int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915, return ret; } +int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915, + struct intel_stolen_node *node, u64 size, + unsigned int alignment, u64 start, u64 end) +{ + return __i915_gem_stolen_insert_node_in_range(i915, &node->node, + size, alignment, + start, end); +} + +static int __i915_gem_stolen_insert_node(struct drm_i915_private *i915, + struct drm_mm_node *node, u64 size, + unsigned int alignment) +{ + return __i915_gem_stolen_insert_node_in_range(i915, node, + size, alignment, + I915_GEM_STOLEN_BIAS, + U64_MAX); +} + int i915_gem_stolen_insert_node(struct drm_i915_private *i915, - struct drm_mm_node *node, u64 size, - unsigned alignment) + struct intel_stolen_node *node, u64 size, + unsigned int alignment) { - return i915_gem_stolen_insert_node_in_range(i915, node, - size, alignment, - I915_GEM_STOLEN_BIAS, - U64_MAX); + return __i915_gem_stolen_insert_node(i915, &node->node, size, alignment); } -void i915_gem_stolen_remove_node(struct drm_i915_private *i915, - struct drm_mm_node *node) +static void __i915_gem_stolen_remove_node(struct drm_i915_private *i915, + struct drm_mm_node *node) { mutex_lock(&i915->mm.stolen_lock); drm_mm_remove_node(node); mutex_unlock(&i915->mm.stolen_lock); } +void i915_gem_stolen_remove_node(struct drm_i915_private *i915, + struct intel_stolen_node *node) +{ + __i915_gem_stolen_remove_node(i915, &node->node); +} + static bool valid_stolen_size(struct drm_i915_private *i915, struct resource *dsm) { return (dsm->start != 0 || HAS_LMEMBAR_SMEM_STOLEN(i915)) && dsm->end > dsm->start; @@ -683,7 +705,7 @@ i915_gem_object_release_stolen(struct drm_i915_gem_object *obj) struct drm_mm_node *stolen = fetch_and_zero(&obj->stolen); GEM_BUG_ON(!stolen); - i915_gem_stolen_remove_node(i915, stolen); + __i915_gem_stolen_remove_node(i915, stolen); kfree(stolen); i915_gem_object_release_memory_region(obj); @@ -772,8 +794,8 @@ static int _i915_gem_object_stolen_init(struct intel_memory_region *mem, ret = drm_mm_reserve_node(&i915->mm.stolen, stolen); mutex_unlock(&i915->mm.stolen_lock); } else { - ret = i915_gem_stolen_insert_node(i915, stolen, size, - mem->min_page_size); + ret = __i915_gem_stolen_insert_node(i915, stolen, size, + mem->min_page_size); } if (ret) goto err_free; @@ -785,7 +807,7 @@ static int _i915_gem_object_stolen_init(struct intel_memory_region *mem, return 0; err_remove: - i915_gem_stolen_remove_node(i915, stolen); + __i915_gem_stolen_remove_node(i915, stolen); err_free: kfree(stolen); return ret; @@ -1016,22 +1038,22 @@ u64 i915_gem_stolen_area_size(const struct drm_i915_private *i915) } u64 i915_gem_stolen_node_address(const struct drm_i915_private *i915, - const struct drm_mm_node *node) + const struct intel_stolen_node *node) { return i915->dsm.stolen.start + i915_gem_stolen_node_offset(node); } -bool i915_gem_stolen_node_allocated(const struct drm_mm_node *node) +bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node) { - return drm_mm_node_allocated(node); + return drm_mm_node_allocated(&node->node); } -u64 i915_gem_stolen_node_offset(const struct drm_mm_node *node) +u64 i915_gem_stolen_node_offset(const struct intel_stolen_node *node) { - return node->start; + return node->node.start; } -u64 i915_gem_stolen_node_size(const struct drm_mm_node *node) +u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node) { - return node->size; + return node->node.size; } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h index c2f9c994e0ae..9e42d5a4cf13 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h @@ -7,22 +7,24 @@ #define __I915_GEM_STOLEN_H__ #include +#include -struct drm_i915_private; -struct drm_mm_node; struct drm_i915_gem_object; +struct drm_i915_private; -#define intel_stolen_node drm_mm_node +struct intel_stolen_node { + struct drm_mm_node node; +}; int i915_gem_stolen_insert_node(struct drm_i915_private *i915, - struct drm_mm_node *node, u64 size, + struct intel_stolen_node *node, u64 size, unsigned alignment); int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915, - struct drm_mm_node *node, u64 size, + struct intel_stolen_node *node, u64 size, unsigned alignment, u64 start, u64 end); void i915_gem_stolen_remove_node(struct drm_i915_private *i915, - struct drm_mm_node *node); + struct intel_stolen_node *node); struct intel_memory_region * i915_gem_stolen_smem_setup(struct drm_i915_private *i915, u16 type, u16 instance); @@ -43,10 +45,10 @@ u64 i915_gem_stolen_area_address(const struct drm_i915_private *i915); u64 i915_gem_stolen_area_size(const struct drm_i915_private *i915); u64 i915_gem_stolen_node_address(const struct drm_i915_private *i915, - const struct drm_mm_node *node); + const struct intel_stolen_node *node); -bool i915_gem_stolen_node_allocated(const struct drm_mm_node *node); -u64 i915_gem_stolen_node_offset(const struct drm_mm_node *node); -u64 i915_gem_stolen_node_size(const struct drm_mm_node *node); +bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node); +u64 i915_gem_stolen_node_offset(const struct intel_stolen_node *node); +u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node); #endif /* __I915_GEM_STOLEN_H__ */ -- cgit v1.2.3 From 33c8d948bc87658e8d9ed1dfd05dfbbb417d3e75 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 19:43:35 +0300 Subject: drm/xe/stolen: convert compat static inlines to proper functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add display/xe_stolen.c as the implementation for the stolen interface exposed to display. This allows hiding the implementation details that shouldn't be exposed to display. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/8e807c6aafc6151b18df08dda20053516813e001.1758732183.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/Makefile | 1 + .../xe/compat-i915-headers/gem/i915_gem_stolen.h | 104 ++++----------------- drivers/gpu/drm/xe/display/xe_stolen.c | 99 ++++++++++++++++++++ 3 files changed, 119 insertions(+), 85 deletions(-) create mode 100644 drivers/gpu/drm/xe/display/xe_stolen.c diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index d9c6cf0f189e..ac65722e5d38 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -214,6 +214,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ display/xe_hdcp_gsc.o \ display/xe_panic.o \ display/xe_plane_initial.o \ + display/xe_stolen.o \ display/xe_tdf.o # SOC code shared with i915 diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h index be249f51231d..10f110b9bf77 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h @@ -6,106 +6,40 @@ #ifndef _I915_GEM_STOLEN_H_ #define _I915_GEM_STOLEN_H_ -#include "xe_ttm_stolen_mgr.h" -#include "xe_res_cursor.h" -#include "xe_validation.h" +#include struct xe_bo; +struct xe_device; struct intel_stolen_node { struct xe_bo *bo; }; -static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, - struct intel_stolen_node *node, - u32 size, u32 align, - u32 start, u32 end) -{ - struct xe_bo *bo; - int err = 0; - u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN; - - if (start < SZ_4K) - start = SZ_4K; - - if (align) { - size = ALIGN(size, align); - start = ALIGN(start, align); - } - - bo = xe_bo_create_pin_range_novm(xe, xe_device_get_root_tile(xe), - size, start, end, ttm_bo_type_kernel, flags); - if (IS_ERR(bo)) { - err = PTR_ERR(bo); - bo = NULL; - return err; - } - - node->bo = bo; - - return err; -} - -static inline int i915_gem_stolen_insert_node(struct xe_device *xe, - struct intel_stolen_node *node, - u32 size, u32 align) -{ - /* Not used on xe */ - WARN_ON(1); - - return -ENODEV; -} - -static inline void i915_gem_stolen_remove_node(struct xe_device *xe, - struct intel_stolen_node *node) -{ - xe_bo_unpin_map_no_vm(node->bo); - node->bo = NULL; -} - -static inline bool i915_gem_stolen_initialized(struct xe_device *xe) -{ - return ttm_manager_type(&xe->ttm, XE_PL_STOLEN); -} +int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, + struct intel_stolen_node *node, + u32 size, u32 align, + u32 start, u32 end); -static inline bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node) -{ - return node->bo; -} +int i915_gem_stolen_insert_node(struct xe_device *xe, + struct intel_stolen_node *node, + u32 size, u32 align); -static inline u32 i915_gem_stolen_node_offset(struct intel_stolen_node *node) -{ - struct xe_res_cursor res; +void i915_gem_stolen_remove_node(struct xe_device *xe, + struct intel_stolen_node *node); - xe_res_first(node->bo->ttm.resource, 0, 4096, &res); - return res.start; -} +bool i915_gem_stolen_initialized(struct xe_device *xe); -/* Used for < gen4. These are not supported by Xe */ -static inline u64 i915_gem_stolen_area_address(const struct xe_device *xe) -{ - WARN_ON(1); +bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node); - return 0; -} +u32 i915_gem_stolen_node_offset(struct intel_stolen_node *node); -/* Used for gen9 specific WA. Gen9 is not supported by Xe */ -static inline u64 i915_gem_stolen_area_size(const struct xe_device *xe) -{ - WARN_ON(1); +u64 i915_gem_stolen_area_address(const struct xe_device *xe); - return 0; -} +u64 i915_gem_stolen_area_size(const struct xe_device *xe); -static inline u64 i915_gem_stolen_node_address(struct xe_device *xe, - struct intel_stolen_node *node) -{ - return xe_ttm_stolen_gpu_offset(xe) + i915_gem_stolen_node_offset(node); -} +u64 i915_gem_stolen_node_address(struct xe_device *xe, + struct intel_stolen_node *node); -static inline u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node) -{ - return node->bo->ttm.base.size; -} +u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node); #endif diff --git a/drivers/gpu/drm/xe/display/xe_stolen.c b/drivers/gpu/drm/xe/display/xe_stolen.c new file mode 100644 index 000000000000..ab156a9f2c26 --- /dev/null +++ b/drivers/gpu/drm/xe/display/xe_stolen.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: MIT +/* Copyright © 2025 Intel Corporation */ + +#include "gem/i915_gem_stolen.h" +#include "xe_res_cursor.h" +#include "xe_ttm_stolen_mgr.h" +#include "xe_validation.h" + +int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, + struct intel_stolen_node *node, + u32 size, u32 align, + u32 start, u32 end) +{ + struct xe_bo *bo; + int err = 0; + u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN; + + if (start < SZ_4K) + start = SZ_4K; + + if (align) { + size = ALIGN(size, align); + start = ALIGN(start, align); + } + + bo = xe_bo_create_pin_range_novm(xe, xe_device_get_root_tile(xe), + size, start, end, ttm_bo_type_kernel, flags); + if (IS_ERR(bo)) { + err = PTR_ERR(bo); + bo = NULL; + return err; + } + + node->bo = bo; + + return err; +} + +int i915_gem_stolen_insert_node(struct xe_device *xe, + struct intel_stolen_node *node, + u32 size, u32 align) +{ + /* Not used on xe */ + WARN_ON(1); + + return -ENODEV; +} + +void i915_gem_stolen_remove_node(struct xe_device *xe, + struct intel_stolen_node *node) +{ + xe_bo_unpin_map_no_vm(node->bo); + node->bo = NULL; +} + +bool i915_gem_stolen_initialized(struct xe_device *xe) +{ + return ttm_manager_type(&xe->ttm, XE_PL_STOLEN); +} + +bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node) +{ + return node->bo; +} + +u32 i915_gem_stolen_node_offset(struct intel_stolen_node *node) +{ + struct xe_res_cursor res; + + xe_res_first(node->bo->ttm.resource, 0, 4096, &res); + return res.start; +} + +/* Used for < gen4. These are not supported by Xe */ +u64 i915_gem_stolen_area_address(const struct xe_device *xe) +{ + WARN_ON(1); + + return 0; +} + +/* Used for gen9 specific WA. Gen9 is not supported by Xe */ +u64 i915_gem_stolen_area_size(const struct xe_device *xe) +{ + WARN_ON(1); + + return 0; +} + +u64 i915_gem_stolen_node_address(struct xe_device *xe, + struct intel_stolen_node *node) +{ + return xe_ttm_stolen_gpu_offset(xe) + i915_gem_stolen_node_offset(node); +} + +u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node) +{ + return node->bo->ttm.base.size; +} -- cgit v1.2.3 From f74bab2d903e442a7bf68f08007edfe8859ef9a7 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 19:43:36 +0300 Subject: drm/{i915, xe}/stolen: make struct intel_stolen_node opaque MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add i915_gem_stolen_node_alloc() and i915_gem_stolen_node_free(), returning struct intel_stolen_node pointer. Make struct intel_stolen_node an opaque pointer, with different implementations in i915 and xe. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/3fe71bbb4c75ee86b4d129fafa3d4cd6526363f4.1758732183.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbc.c | 58 ++++++++++++++-------- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 20 ++++++++ drivers/gpu/drm/i915/gem/i915_gem_stolen.h | 10 ++-- .../xe/compat-i915-headers/gem/i915_gem_stolen.h | 11 ++-- drivers/gpu/drm/xe/display/xe_stolen.c | 20 ++++++++ 5 files changed, 89 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index cc67de6c06cf..05199434cb7c 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -102,7 +102,8 @@ struct intel_fbc { struct mutex lock; unsigned int busy_bits; - struct intel_stolen_node compressed_fb, compressed_llb; + struct intel_stolen_node *compressed_fb; + struct intel_stolen_node *compressed_llb; enum intel_fbc_id id; @@ -380,16 +381,16 @@ static void i8xx_fbc_program_cfb(struct intel_fbc *fbc) drm_WARN_ON(display->drm, range_end_overflows_t(u64, i915_gem_stolen_area_address(i915), - i915_gem_stolen_node_offset(&fbc->compressed_fb), + i915_gem_stolen_node_offset(fbc->compressed_fb), U32_MAX)); drm_WARN_ON(display->drm, range_end_overflows_t(u64, i915_gem_stolen_area_address(i915), - i915_gem_stolen_node_offset(&fbc->compressed_llb), + i915_gem_stolen_node_offset(fbc->compressed_llb), U32_MAX)); intel_de_write(display, FBC_CFB_BASE, - i915_gem_stolen_node_address(i915, &fbc->compressed_fb)); + i915_gem_stolen_node_address(i915, fbc->compressed_fb)); intel_de_write(display, FBC_LL_BASE, - i915_gem_stolen_node_address(i915, &fbc->compressed_llb)); + i915_gem_stolen_node_address(i915, fbc->compressed_llb)); } static const struct intel_fbc_funcs i8xx_fbc_funcs = { @@ -497,7 +498,7 @@ static void g4x_fbc_program_cfb(struct intel_fbc *fbc) struct intel_display *display = fbc->display; intel_de_write(display, DPFC_CB_BASE, - i915_gem_stolen_node_offset(&fbc->compressed_fb)); + i915_gem_stolen_node_offset(fbc->compressed_fb)); } static const struct intel_fbc_funcs g4x_fbc_funcs = { @@ -566,7 +567,7 @@ static void ilk_fbc_program_cfb(struct intel_fbc *fbc) struct intel_display *display = fbc->display; intel_de_write(display, ILK_DPFC_CB_BASE(fbc->id), - i915_gem_stolen_node_offset(&fbc->compressed_fb)); + i915_gem_stolen_node_offset(fbc->compressed_fb)); } static const struct intel_fbc_funcs ilk_fbc_funcs = { @@ -842,13 +843,13 @@ static int find_compression_limit(struct intel_fbc *fbc, size /= limit; /* Try to over-allocate to reduce reallocations and fragmentation. */ - ret = i915_gem_stolen_insert_node_in_range(i915, &fbc->compressed_fb, + ret = i915_gem_stolen_insert_node_in_range(i915, fbc->compressed_fb, size <<= 1, 4096, 0, end); if (ret == 0) return limit; for (; limit <= intel_fbc_max_limit(display); limit <<= 1) { - ret = i915_gem_stolen_insert_node_in_range(i915, &fbc->compressed_fb, + ret = i915_gem_stolen_insert_node_in_range(i915, fbc->compressed_fb, size >>= 1, 4096, 0, end); if (ret == 0) return limit; @@ -865,12 +866,12 @@ static int intel_fbc_alloc_cfb(struct intel_fbc *fbc, int ret; drm_WARN_ON(display->drm, - i915_gem_stolen_node_allocated(&fbc->compressed_fb)); + i915_gem_stolen_node_allocated(fbc->compressed_fb)); drm_WARN_ON(display->drm, - i915_gem_stolen_node_allocated(&fbc->compressed_llb)); + i915_gem_stolen_node_allocated(fbc->compressed_llb)); if (DISPLAY_VER(display) < 5 && !display->platform.g4x) { - ret = i915_gem_stolen_insert_node(i915, &fbc->compressed_llb, + ret = i915_gem_stolen_insert_node(i915, fbc->compressed_llb, 4096, 4096); if (ret) goto err; @@ -887,12 +888,12 @@ static int intel_fbc_alloc_cfb(struct intel_fbc *fbc, drm_dbg_kms(display->drm, "reserved %llu bytes of contiguous stolen space for FBC, limit: %d\n", - i915_gem_stolen_node_size(&fbc->compressed_fb), fbc->limit); + i915_gem_stolen_node_size(fbc->compressed_fb), fbc->limit); return 0; err_llb: - if (i915_gem_stolen_node_allocated(&fbc->compressed_llb)) - i915_gem_stolen_remove_node(i915, &fbc->compressed_llb); + if (i915_gem_stolen_node_allocated(fbc->compressed_llb)) + i915_gem_stolen_remove_node(i915, fbc->compressed_llb); err: if (i915_gem_stolen_initialized(i915)) drm_info_once(display->drm, @@ -951,10 +952,10 @@ static void __intel_fbc_cleanup_cfb(struct intel_fbc *fbc) if (WARN_ON(intel_fbc_hw_is_active(fbc))) return; - if (i915_gem_stolen_node_allocated(&fbc->compressed_llb)) - i915_gem_stolen_remove_node(i915, &fbc->compressed_llb); - if (i915_gem_stolen_node_allocated(&fbc->compressed_fb)) - i915_gem_stolen_remove_node(i915, &fbc->compressed_fb); + if (i915_gem_stolen_node_allocated(fbc->compressed_llb)) + i915_gem_stolen_remove_node(i915, fbc->compressed_llb); + if (i915_gem_stolen_node_allocated(fbc->compressed_fb)) + i915_gem_stolen_remove_node(i915, fbc->compressed_fb); } void intel_fbc_cleanup(struct intel_display *display) @@ -967,6 +968,9 @@ void intel_fbc_cleanup(struct intel_display *display) __intel_fbc_cleanup_cfb(fbc); mutex_unlock(&fbc->lock); + i915_gem_stolen_node_free(fbc->compressed_fb); + i915_gem_stolen_node_free(fbc->compressed_llb); + kfree(fbc); } } @@ -1355,7 +1359,7 @@ static bool intel_fbc_is_cfb_ok(const struct intel_plane_state *plane_state) return intel_fbc_min_limit(plane_state) <= fbc->limit && intel_fbc_cfb_size(plane_state) <= fbc->limit * - i915_gem_stolen_node_size(&fbc->compressed_fb); + i915_gem_stolen_node_size(fbc->compressed_fb); } static bool intel_fbc_is_ok(const struct intel_plane_state *plane_state) @@ -2083,6 +2087,13 @@ static struct intel_fbc *intel_fbc_create(struct intel_display *display, if (!fbc) return NULL; + fbc->compressed_fb = i915_gem_stolen_node_alloc(display->drm); + if (!fbc->compressed_fb) + goto err; + fbc->compressed_llb = i915_gem_stolen_node_alloc(display->drm); + if (!fbc->compressed_llb) + goto err; + fbc->id = fbc_id; fbc->display = display; INIT_WORK(&fbc->underrun_work, intel_fbc_underrun_work_fn); @@ -2102,6 +2113,13 @@ static struct intel_fbc *intel_fbc_create(struct intel_display *display, fbc->funcs = &i8xx_fbc_funcs; return fbc; + +err: + i915_gem_stolen_node_free(fbc->compressed_llb); + i915_gem_stolen_node_free(fbc->compressed_fb); + kfree(fbc); + + return NULL; } /** diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 70ee34303e36..5991ccd3f328 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -24,6 +24,10 @@ #include "intel_mchbar_regs.h" #include "intel_pci_config.h" +struct intel_stolen_node { + struct drm_mm_node node; +}; + /* * The BIOS typically reserves some of the system's memory for the exclusive * use of the integrated graphics. This memory is no longer available for @@ -1057,3 +1061,19 @@ u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node) { return node->node.size; } + +struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm) +{ + struct intel_stolen_node *node; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return NULL; + + return node; +} + +void i915_gem_stolen_node_free(const struct intel_stolen_node *node) +{ + kfree(node); +} diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h index 9e42d5a4cf13..25ec8325fb29 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h @@ -7,14 +7,11 @@ #define __I915_GEM_STOLEN_H__ #include -#include +struct drm_device; struct drm_i915_gem_object; struct drm_i915_private; - -struct intel_stolen_node { - struct drm_mm_node node; -}; +struct intel_stolen_node; int i915_gem_stolen_insert_node(struct drm_i915_private *i915, struct intel_stolen_node *node, u64 size, @@ -51,4 +48,7 @@ bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node); u64 i915_gem_stolen_node_offset(const struct intel_stolen_node *node); u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node); +struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm); +void i915_gem_stolen_node_free(const struct intel_stolen_node *node); + #endif /* __I915_GEM_STOLEN_H__ */ diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h index 10f110b9bf77..b0bc3efcaf6c 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h @@ -8,13 +8,10 @@ #include -struct xe_bo; +struct drm_device; +struct intel_stolen_node; struct xe_device; -struct intel_stolen_node { - struct xe_bo *bo; -}; - int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, struct intel_stolen_node *node, u32 size, u32 align, @@ -42,4 +39,8 @@ u64 i915_gem_stolen_node_address(struct xe_device *xe, u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node); +struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm); + +void i915_gem_stolen_node_free(const struct intel_stolen_node *node); + #endif diff --git a/drivers/gpu/drm/xe/display/xe_stolen.c b/drivers/gpu/drm/xe/display/xe_stolen.c index ab156a9f2c26..b218df40324a 100644 --- a/drivers/gpu/drm/xe/display/xe_stolen.c +++ b/drivers/gpu/drm/xe/display/xe_stolen.c @@ -6,6 +6,10 @@ #include "xe_ttm_stolen_mgr.h" #include "xe_validation.h" +struct intel_stolen_node { + struct xe_bo *bo; +}; + int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, struct intel_stolen_node *node, u32 size, u32 align, @@ -97,3 +101,19 @@ u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node) { return node->bo->ttm.base.size; } + +struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm) +{ + struct intel_stolen_node *node; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return NULL; + + return node; +} + +void i915_gem_stolen_node_free(const struct intel_stolen_node *node) +{ + kfree(node); +} -- cgit v1.2.3 From e8848d3d37490157e31ef583cb7098e368644254 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 19:43:37 +0300 Subject: drm/{i915, xe}/stolen: add device pointer to struct intel_stolen_node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add backpointers to i915/xe to allow simplifying some interfaces in follow-up. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/321354d47f9e530159caefef510d5394f4177470.1758732183.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 4 ++++ drivers/gpu/drm/xe/display/xe_stolen.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 5991ccd3f328..8bc71fb2a765 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -25,6 +25,7 @@ #include "intel_pci_config.h" struct intel_stolen_node { + struct drm_i915_private *i915; struct drm_mm_node node; }; @@ -1064,12 +1065,15 @@ u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node) struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm) { + struct drm_i915_private *i915 = to_i915(drm); struct intel_stolen_node *node; node = kzalloc(sizeof(*node), GFP_KERNEL); if (!node) return NULL; + node->i915 = i915; + return node; } diff --git a/drivers/gpu/drm/xe/display/xe_stolen.c b/drivers/gpu/drm/xe/display/xe_stolen.c index b218df40324a..eea182b569a1 100644 --- a/drivers/gpu/drm/xe/display/xe_stolen.c +++ b/drivers/gpu/drm/xe/display/xe_stolen.c @@ -7,6 +7,7 @@ #include "xe_validation.h" struct intel_stolen_node { + struct xe_device *xe; struct xe_bo *bo; }; @@ -104,12 +105,15 @@ u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node) struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm) { + struct xe_device *xe = to_xe_device(drm); struct intel_stolen_node *node; node = kzalloc(sizeof(*node), GFP_KERNEL); if (!node) return NULL; + node->xe = xe; + return node; } -- cgit v1.2.3 From 994c74ea5e07ec93a8616602caaca95a70efdb21 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 19:43:38 +0300 Subject: drm/{i915, xe}/stolen: use the stored i915/xe device pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we store the i915/xe device pointer in struct intel_stolen_node, we can reduce parameter passing in a number of functions. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/6f31114c8113ce2254d422ca53992088b673fb2f.1758732183.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbc.c | 21 ++++++++------------- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 20 +++++++++----------- drivers/gpu/drm/i915/gem/i915_gem_stolen.h | 12 ++++-------- .../xe/compat-i915-headers/gem/i915_gem_stolen.h | 13 ++++--------- drivers/gpu/drm/xe/display/xe_stolen.c | 17 ++++++++--------- 5 files changed, 33 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 05199434cb7c..0d837527aaab 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -388,9 +388,9 @@ static void i8xx_fbc_program_cfb(struct intel_fbc *fbc) i915_gem_stolen_node_offset(fbc->compressed_llb), U32_MAX)); intel_de_write(display, FBC_CFB_BASE, - i915_gem_stolen_node_address(i915, fbc->compressed_fb)); + i915_gem_stolen_node_address(fbc->compressed_fb)); intel_de_write(display, FBC_LL_BASE, - i915_gem_stolen_node_address(i915, fbc->compressed_llb)); + i915_gem_stolen_node_address(fbc->compressed_llb)); } static const struct intel_fbc_funcs i8xx_fbc_funcs = { @@ -836,20 +836,19 @@ static int find_compression_limit(struct intel_fbc *fbc, unsigned int size, int min_limit) { struct intel_display *display = fbc->display; - struct drm_i915_private *i915 = to_i915(display->drm); u64 end = intel_fbc_stolen_end(display); int ret, limit = min_limit; size /= limit; /* Try to over-allocate to reduce reallocations and fragmentation. */ - ret = i915_gem_stolen_insert_node_in_range(i915, fbc->compressed_fb, + ret = i915_gem_stolen_insert_node_in_range(fbc->compressed_fb, size <<= 1, 4096, 0, end); if (ret == 0) return limit; for (; limit <= intel_fbc_max_limit(display); limit <<= 1) { - ret = i915_gem_stolen_insert_node_in_range(i915, fbc->compressed_fb, + ret = i915_gem_stolen_insert_node_in_range(fbc->compressed_fb, size >>= 1, 4096, 0, end); if (ret == 0) return limit; @@ -871,8 +870,7 @@ static int intel_fbc_alloc_cfb(struct intel_fbc *fbc, i915_gem_stolen_node_allocated(fbc->compressed_llb)); if (DISPLAY_VER(display) < 5 && !display->platform.g4x) { - ret = i915_gem_stolen_insert_node(i915, fbc->compressed_llb, - 4096, 4096); + ret = i915_gem_stolen_insert_node(fbc->compressed_llb, 4096, 4096); if (ret) goto err; } @@ -893,7 +891,7 @@ static int intel_fbc_alloc_cfb(struct intel_fbc *fbc, err_llb: if (i915_gem_stolen_node_allocated(fbc->compressed_llb)) - i915_gem_stolen_remove_node(i915, fbc->compressed_llb); + i915_gem_stolen_remove_node(fbc->compressed_llb); err: if (i915_gem_stolen_initialized(i915)) drm_info_once(display->drm, @@ -946,16 +944,13 @@ static void intel_fbc_program_workarounds(struct intel_fbc *fbc) static void __intel_fbc_cleanup_cfb(struct intel_fbc *fbc) { - struct intel_display *display = fbc->display; - struct drm_i915_private *i915 = to_i915(display->drm); - if (WARN_ON(intel_fbc_hw_is_active(fbc))) return; if (i915_gem_stolen_node_allocated(fbc->compressed_llb)) - i915_gem_stolen_remove_node(i915, fbc->compressed_llb); + i915_gem_stolen_remove_node(fbc->compressed_llb); if (i915_gem_stolen_node_allocated(fbc->compressed_fb)) - i915_gem_stolen_remove_node(i915, fbc->compressed_fb); + i915_gem_stolen_remove_node(fbc->compressed_fb); } void intel_fbc_cleanup(struct intel_display *display) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 8bc71fb2a765..b2812ec79d19 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -63,11 +63,10 @@ static int __i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915, return ret; } -int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915, - struct intel_stolen_node *node, u64 size, +int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size, unsigned int alignment, u64 start, u64 end) { - return __i915_gem_stolen_insert_node_in_range(i915, &node->node, + return __i915_gem_stolen_insert_node_in_range(node->i915, &node->node, size, alignment, start, end); } @@ -82,11 +81,10 @@ static int __i915_gem_stolen_insert_node(struct drm_i915_private *i915, U64_MAX); } -int i915_gem_stolen_insert_node(struct drm_i915_private *i915, - struct intel_stolen_node *node, u64 size, +int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u64 size, unsigned int alignment) { - return __i915_gem_stolen_insert_node(i915, &node->node, size, alignment); + return __i915_gem_stolen_insert_node(node->i915, &node->node, size, alignment); } static void __i915_gem_stolen_remove_node(struct drm_i915_private *i915, @@ -97,10 +95,9 @@ static void __i915_gem_stolen_remove_node(struct drm_i915_private *i915, mutex_unlock(&i915->mm.stolen_lock); } -void i915_gem_stolen_remove_node(struct drm_i915_private *i915, - struct intel_stolen_node *node) +void i915_gem_stolen_remove_node(struct intel_stolen_node *node) { - __i915_gem_stolen_remove_node(i915, &node->node); + __i915_gem_stolen_remove_node(node->i915, &node->node); } static bool valid_stolen_size(struct drm_i915_private *i915, struct resource *dsm) @@ -1042,9 +1039,10 @@ u64 i915_gem_stolen_area_size(const struct drm_i915_private *i915) return resource_size(&i915->dsm.stolen); } -u64 i915_gem_stolen_node_address(const struct drm_i915_private *i915, - const struct intel_stolen_node *node) +u64 i915_gem_stolen_node_address(const struct intel_stolen_node *node) { + struct drm_i915_private *i915 = node->i915; + return i915->dsm.stolen.start + i915_gem_stolen_node_offset(node); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h index 25ec8325fb29..c670736f09e1 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h @@ -13,15 +13,12 @@ struct drm_i915_gem_object; struct drm_i915_private; struct intel_stolen_node; -int i915_gem_stolen_insert_node(struct drm_i915_private *i915, - struct intel_stolen_node *node, u64 size, +int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u64 size, unsigned alignment); -int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915, - struct intel_stolen_node *node, u64 size, +int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size, unsigned alignment, u64 start, u64 end); -void i915_gem_stolen_remove_node(struct drm_i915_private *i915, - struct intel_stolen_node *node); +void i915_gem_stolen_remove_node(struct intel_stolen_node *node); struct intel_memory_region * i915_gem_stolen_smem_setup(struct drm_i915_private *i915, u16 type, u16 instance); @@ -41,8 +38,7 @@ bool i915_gem_stolen_initialized(const struct drm_i915_private *i915); u64 i915_gem_stolen_area_address(const struct drm_i915_private *i915); u64 i915_gem_stolen_area_size(const struct drm_i915_private *i915); -u64 i915_gem_stolen_node_address(const struct drm_i915_private *i915, - const struct intel_stolen_node *node); +u64 i915_gem_stolen_node_address(const struct intel_stolen_node *node); bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node); u64 i915_gem_stolen_node_offset(const struct intel_stolen_node *node); diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h index b0bc3efcaf6c..7bdf73fad8bf 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h @@ -12,17 +12,13 @@ struct drm_device; struct intel_stolen_node; struct xe_device; -int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, - struct intel_stolen_node *node, +int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u32 size, u32 align, u32 start, u32 end); -int i915_gem_stolen_insert_node(struct xe_device *xe, - struct intel_stolen_node *node, - u32 size, u32 align); +int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u32 size, u32 align); -void i915_gem_stolen_remove_node(struct xe_device *xe, - struct intel_stolen_node *node); +void i915_gem_stolen_remove_node(struct intel_stolen_node *node); bool i915_gem_stolen_initialized(struct xe_device *xe); @@ -34,8 +30,7 @@ u64 i915_gem_stolen_area_address(const struct xe_device *xe); u64 i915_gem_stolen_area_size(const struct xe_device *xe); -u64 i915_gem_stolen_node_address(struct xe_device *xe, - struct intel_stolen_node *node); +u64 i915_gem_stolen_node_address(struct intel_stolen_node *node); u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node); diff --git a/drivers/gpu/drm/xe/display/xe_stolen.c b/drivers/gpu/drm/xe/display/xe_stolen.c index eea182b569a1..c1afe70454d1 100644 --- a/drivers/gpu/drm/xe/display/xe_stolen.c +++ b/drivers/gpu/drm/xe/display/xe_stolen.c @@ -11,11 +11,12 @@ struct intel_stolen_node { struct xe_bo *bo; }; -int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, - struct intel_stolen_node *node, +int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u32 size, u32 align, u32 start, u32 end) { + struct xe_device *xe = node->xe; + struct xe_bo *bo; int err = 0; u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN; @@ -41,9 +42,7 @@ int i915_gem_stolen_insert_node_in_range(struct xe_device *xe, return err; } -int i915_gem_stolen_insert_node(struct xe_device *xe, - struct intel_stolen_node *node, - u32 size, u32 align) +int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u32 size, u32 align) { /* Not used on xe */ WARN_ON(1); @@ -51,8 +50,7 @@ int i915_gem_stolen_insert_node(struct xe_device *xe, return -ENODEV; } -void i915_gem_stolen_remove_node(struct xe_device *xe, - struct intel_stolen_node *node) +void i915_gem_stolen_remove_node(struct intel_stolen_node *node) { xe_bo_unpin_map_no_vm(node->bo); node->bo = NULL; @@ -92,9 +90,10 @@ u64 i915_gem_stolen_area_size(const struct xe_device *xe) return 0; } -u64 i915_gem_stolen_node_address(struct xe_device *xe, - struct intel_stolen_node *node) +u64 i915_gem_stolen_node_address(struct intel_stolen_node *node) { + struct xe_device *xe = node->xe; + return xe_ttm_stolen_gpu_offset(xe) + i915_gem_stolen_node_offset(node); } -- cgit v1.2.3 From d3741f2c861c754ad39f8f35d03bd26ee04c74ca Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 19:43:39 +0300 Subject: drm/{i915, xe}/stolen: convert stolen interface to struct drm_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the stolen interface agnostic to i915/xe, and pass struct drm_device instead. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/bbfc2aeaeee3156e92d49c73983be05b6feeede2.1758732183.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_fbc.c | 13 +++++-------- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 12 +++++++++--- drivers/gpu/drm/i915/gem/i915_gem_stolen.h | 6 +++--- .../gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h | 7 +++---- drivers/gpu/drm/xe/display/xe_stolen.c | 8 +++++--- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 0d837527aaab..4edb4342833e 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -377,14 +377,13 @@ static void i8xx_fbc_nuke(struct intel_fbc *fbc) static void i8xx_fbc_program_cfb(struct intel_fbc *fbc) { struct intel_display *display = fbc->display; - struct drm_i915_private *i915 = to_i915(display->drm); drm_WARN_ON(display->drm, - range_end_overflows_t(u64, i915_gem_stolen_area_address(i915), + range_end_overflows_t(u64, i915_gem_stolen_area_address(display->drm), i915_gem_stolen_node_offset(fbc->compressed_fb), U32_MAX)); drm_WARN_ON(display->drm, - range_end_overflows_t(u64, i915_gem_stolen_area_address(i915), + range_end_overflows_t(u64, i915_gem_stolen_area_address(display->drm), i915_gem_stolen_node_offset(fbc->compressed_llb), U32_MAX)); intel_de_write(display, FBC_CFB_BASE, @@ -798,7 +797,6 @@ static u64 intel_fbc_cfb_base_max(struct intel_display *display) static u64 intel_fbc_stolen_end(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); u64 end; /* The FBC hardware for BDW/SKL doesn't have access to the stolen @@ -807,7 +805,7 @@ static u64 intel_fbc_stolen_end(struct intel_display *display) * underruns, even if that range is not reserved by the BIOS. */ if (display->platform.broadwell || (DISPLAY_VER(display) == 9 && !display->platform.broxton)) - end = i915_gem_stolen_area_size(i915) - 8 * 1024 * 1024; + end = i915_gem_stolen_area_size(display->drm) - 8 * 1024 * 1024; else end = U64_MAX; @@ -861,7 +859,6 @@ static int intel_fbc_alloc_cfb(struct intel_fbc *fbc, unsigned int size, int min_limit) { struct intel_display *display = fbc->display; - struct drm_i915_private *i915 = to_i915(display->drm); int ret; drm_WARN_ON(display->drm, @@ -893,7 +890,7 @@ err_llb: if (i915_gem_stolen_node_allocated(fbc->compressed_llb)) i915_gem_stolen_remove_node(fbc->compressed_llb); err: - if (i915_gem_stolen_initialized(i915)) + if (i915_gem_stolen_initialized(display->drm)) drm_info_once(display->drm, "not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size); return -ENOSPC; @@ -1435,7 +1432,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, if (!fbc) return 0; - if (!i915_gem_stolen_initialized(i915)) { + if (!i915_gem_stolen_initialized(display->drm)) { plane_state->no_fbc_reason = "stolen memory not initialised"; return 0; } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index b2812ec79d19..e73b369c3347 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -1024,18 +1024,24 @@ bool i915_gem_object_is_stolen(const struct drm_i915_gem_object *obj) return obj->ops == &i915_gem_object_stolen_ops; } -bool i915_gem_stolen_initialized(const struct drm_i915_private *i915) +bool i915_gem_stolen_initialized(struct drm_device *drm) { + struct drm_i915_private *i915 = to_i915(drm); + return drm_mm_initialized(&i915->mm.stolen); } -u64 i915_gem_stolen_area_address(const struct drm_i915_private *i915) +u64 i915_gem_stolen_area_address(struct drm_device *drm) { + struct drm_i915_private *i915 = to_i915(drm); + return i915->dsm.stolen.start; } -u64 i915_gem_stolen_area_size(const struct drm_i915_private *i915) +u64 i915_gem_stolen_area_size(struct drm_device *drm) { + struct drm_i915_private *i915 = to_i915(drm); + return resource_size(&i915->dsm.stolen); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h index c670736f09e1..7b0386002ed4 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.h @@ -34,9 +34,9 @@ bool i915_gem_object_is_stolen(const struct drm_i915_gem_object *obj); #define I915_GEM_STOLEN_BIAS SZ_128K -bool i915_gem_stolen_initialized(const struct drm_i915_private *i915); -u64 i915_gem_stolen_area_address(const struct drm_i915_private *i915); -u64 i915_gem_stolen_area_size(const struct drm_i915_private *i915); +bool i915_gem_stolen_initialized(struct drm_device *drm); +u64 i915_gem_stolen_area_address(struct drm_device *drm); +u64 i915_gem_stolen_area_size(struct drm_device *drm); u64 i915_gem_stolen_node_address(const struct intel_stolen_node *node); diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h index 7bdf73fad8bf..42927326e567 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h @@ -10,7 +10,6 @@ struct drm_device; struct intel_stolen_node; -struct xe_device; int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u32 size, u32 align, @@ -20,15 +19,15 @@ int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u32 size, u32 al void i915_gem_stolen_remove_node(struct intel_stolen_node *node); -bool i915_gem_stolen_initialized(struct xe_device *xe); +bool i915_gem_stolen_initialized(struct drm_device *drm); bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node); u32 i915_gem_stolen_node_offset(struct intel_stolen_node *node); -u64 i915_gem_stolen_area_address(const struct xe_device *xe); +u64 i915_gem_stolen_area_address(struct drm_device *drm); -u64 i915_gem_stolen_area_size(const struct xe_device *xe); +u64 i915_gem_stolen_area_size(struct drm_device *drm); u64 i915_gem_stolen_node_address(struct intel_stolen_node *node); diff --git a/drivers/gpu/drm/xe/display/xe_stolen.c b/drivers/gpu/drm/xe/display/xe_stolen.c index c1afe70454d1..d7af731d9c90 100644 --- a/drivers/gpu/drm/xe/display/xe_stolen.c +++ b/drivers/gpu/drm/xe/display/xe_stolen.c @@ -56,8 +56,10 @@ void i915_gem_stolen_remove_node(struct intel_stolen_node *node) node->bo = NULL; } -bool i915_gem_stolen_initialized(struct xe_device *xe) +bool i915_gem_stolen_initialized(struct drm_device *drm) { + struct xe_device *xe = to_xe_device(drm); + return ttm_manager_type(&xe->ttm, XE_PL_STOLEN); } @@ -75,7 +77,7 @@ u32 i915_gem_stolen_node_offset(struct intel_stolen_node *node) } /* Used for < gen4. These are not supported by Xe */ -u64 i915_gem_stolen_area_address(const struct xe_device *xe) +u64 i915_gem_stolen_area_address(struct drm_device *drm) { WARN_ON(1); @@ -83,7 +85,7 @@ u64 i915_gem_stolen_area_address(const struct xe_device *xe) } /* Used for gen9 specific WA. Gen9 is not supported by Xe */ -u64 i915_gem_stolen_area_size(const struct xe_device *xe) +u64 i915_gem_stolen_area_size(struct drm_device *drm) { WARN_ON(1); -- cgit v1.2.3 From d630a1bdd66090d49b51521019b905f37ae7a6b2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Sep 2025 19:43:40 +0300 Subject: drm/xe/stolen: use the same types as i915 interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify the i915 and xe interfaces by switching to the same types as i915. Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/f15d41bc232dfa957841f16d9a069c777af40194.1758732183.git.jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h | 8 ++++---- drivers/gpu/drm/xe/display/xe_stolen.c | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h index 42927326e567..48e3256ba37e 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h @@ -11,11 +11,11 @@ struct drm_device; struct intel_stolen_node; -int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, - u32 size, u32 align, - u32 start, u32 end); +int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size, + unsigned int align, u64 start, u64 end); -int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u32 size, u32 align); +int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u64 size, + unsigned int align); void i915_gem_stolen_remove_node(struct intel_stolen_node *node); diff --git a/drivers/gpu/drm/xe/display/xe_stolen.c b/drivers/gpu/drm/xe/display/xe_stolen.c index d7af731d9c90..9f04ba36e930 100644 --- a/drivers/gpu/drm/xe/display/xe_stolen.c +++ b/drivers/gpu/drm/xe/display/xe_stolen.c @@ -11,9 +11,8 @@ struct intel_stolen_node { struct xe_bo *bo; }; -int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, - u32 size, u32 align, - u32 start, u32 end) +int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size, + unsigned int align, u64 start, u64 end) { struct xe_device *xe = node->xe; @@ -42,7 +41,7 @@ int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, return err; } -int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u32 size, u32 align) +int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u64 size, unsigned int align) { /* Not used on xe */ WARN_ON(1); -- cgit v1.2.3 From 97825e1c6de7315cba9acb6c1371f1a87dedd904 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 26 Sep 2025 14:10:32 +0300 Subject: drm/{i915,xe}: driver agnostic drm to display pointer chase The display driver needs to get from the struct drm_device pointer to the struct intel_display pointer. Currently, this depends on knowledge of the struct drm_i915_private and struct xe_device definitions, but we'd like to hide those definitions from display. Require the struct drm_device and struct intel_display * members within struct drm_i915_private and struct xe_device to be placed next to each other, to be able to figure out the display pointer without knowledge of the structures. Use a generic dummy device structure to define the relative offsets of the drm and display members, and add static assertions to ensure this holds for both i915 and xe. Use the dummy structure to do the pointer chase from struct drm_device * to struct intel_display *. This requires moving the display member in struct xe_device after the drm member. Cc: Lucas De Marchi Cc: Rodrigo Vivi Cc: Ville Syrjala Suggested-by: Simona Vetter Reviewed-by: Lucas De Marchi Link: https://lore.kernel.org/r/20250926111032.1188876-1-jani.nikula@intel.com Signed-off-by: Jani Nikula --- .../drm/i915/display/intel_display_conversion.c | 20 +++++++---- drivers/gpu/drm/i915/i915_driver.c | 4 +++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/xe/display/xe_display.c | 4 +++ drivers/gpu/drm/xe/xe_device_types.h | 7 ++-- include/drm/intel/display_member.h | 42 ++++++++++++++++++++++ 6 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 include/drm/intel/display_member.h diff --git a/drivers/gpu/drm/i915/display/intel_display_conversion.c b/drivers/gpu/drm/i915/display/intel_display_conversion.c index d56065f22655..9a47aa38cf82 100644 --- a/drivers/gpu/drm/i915/display/intel_display_conversion.c +++ b/drivers/gpu/drm/i915/display/intel_display_conversion.c @@ -1,15 +1,21 @@ // SPDX-License-Identifier: MIT /* Copyright © 2024 Intel Corporation */ -#include "i915_drv.h" -#include "intel_display_conversion.h" +#include -static struct intel_display *__i915_to_display(struct drm_i915_private *i915) -{ - return i915->display; -} +#include "intel_display_conversion.h" struct intel_display *__drm_to_display(struct drm_device *drm) { - return __i915_to_display(to_i915(drm)); + /* + * Note: This relies on both struct drm_i915_private and struct + * xe_device having the struct drm_device and struct intel_display * + * members at the same relative offsets, as defined by struct + * __intel_generic_device. + * + * See also INTEL_DISPLAY_MEMBER_STATIC_ASSERT(). + */ + struct __intel_generic_device *d = container_of(drm, struct __intel_generic_device, drm); + + return d->display; } diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 95165e45de74..b46cb54ef5dc 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "display/i9xx_display_sr.h" #include "display/intel_bw.h" @@ -737,6 +738,9 @@ static void i915_welcome_messages(struct drm_i915_private *dev_priv) "DRM_I915_DEBUG_RUNTIME_PM enabled\n"); } +/* Ensure drm and display members are placed properly. */ +INTEL_DISPLAY_MEMBER_STATIC_ASSERT(struct drm_i915_private, drm, display); + static struct drm_i915_private * i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent) { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 03e497d2081e..6e159bb8ad2f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -174,6 +174,7 @@ struct i915_selftest_stash { struct drm_i915_private { struct drm_device drm; + /* display device data, must be placed after drm device member */ struct intel_display *display; /* FIXME: Device release actions should all be moved to drmm_ */ diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c index 19e691fccf8c..5f4044e63185 100644 --- a/drivers/gpu/drm/xe/display/xe_display.c +++ b/drivers/gpu/drm/xe/display/xe_display.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "soc/intel_dram.h" @@ -35,6 +36,9 @@ #include "skl_watermark.h" #include "xe_module.h" +/* Ensure drm and display members are placed properly. */ +INTEL_DISPLAY_MEMBER_STATIC_ASSERT(struct xe_device, drm, display); + /* Xe device functions */ /** diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index a6c361db11d9..53264b2bb832 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -217,6 +217,11 @@ struct xe_device { /** @drm: drm device */ struct drm_device drm; +#if IS_ENABLED(CONFIG_DRM_XE_DISPLAY) + /** @display: display device data, must be placed after drm device member */ + struct intel_display *display; +#endif + /** @devcoredump: device coredump */ struct xe_devcoredump devcoredump; @@ -617,8 +622,6 @@ struct xe_device { * drm_i915_private during build. After cleanup these should go away, * migrating to the right sub-structs */ - struct intel_display *display; - const struct dram_info *dram_info; /* diff --git a/include/drm/intel/display_member.h b/include/drm/intel/display_member.h new file mode 100644 index 000000000000..0319ea560b60 --- /dev/null +++ b/include/drm/intel/display_member.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2025 Intel Corporation */ + +#ifndef __DRM_INTEL_DISPLAY_H__ +#define __DRM_INTEL_DISPLAY_H__ + +#include +#include +#include + +#include + +struct intel_display; + +/* + * A dummy device struct to define the relative offsets of drm and display + * members. With the members identically placed in struct drm_i915_private and + * struct xe_device, this allows figuring out the struct intel_display pointer + * without the definition of either driver specific structure. + */ +struct __intel_generic_device { + struct drm_device drm; + struct intel_display *display; +}; + +/** + * INTEL_DISPLAY_MEMBER_STATIC_ASSERT() - ensure correct placing of drm and display members + * @type: The struct to check + * @drm_member: Name of the struct drm_device member + * @display_member: Name of the struct intel_display * member. + * + * Use this static assert macro to ensure the struct drm_i915_private and struct + * xe_device struct drm_device and struct intel_display * members are at the + * same relative offsets. + */ +#define INTEL_DISPLAY_MEMBER_STATIC_ASSERT(type, drm_member, display_member) \ + static_assert( \ + offsetof(struct __intel_generic_device, display) - offsetof(struct __intel_generic_device, drm) == \ + offsetof(type, display_member) - offsetof(type, drm_member), \ + __stringify(type) " " __stringify(drm_member) " and " __stringify(display_member) " members at invalid offsets") + +#endif -- cgit v1.2.3 From cc7e1a9b596c9d9dc3324c056cf8162e9fca2765 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 29 Sep 2025 16:34:18 +0300 Subject: drm/i915/irq: duplicate HAS_FBC() for irq error mask usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error irq handling needs to mask page table errors on gen 2/3 with FBC. See commit e7e12f6ec8bf ("drm/i915: Mask page table errors on gen2/3 with FBC") for details. We want to avoid using display feature checks in i915 core code. Since FBC can't be fused off on gen 2/3, just list the platforms that support FBC. Add a macro purely for making the code self-documenting. With this, we can drop the intel_display_core.h include, and make struct intel_display opaque inside i915_irq.c. Suggested-by: Ville Syrjälä Reviewed-by: Ville Syrjälä Link: https://lore.kernel.org/r/20250929133418.2033006-1-jani.nikula@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_irq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 11a727b74849..e0a0bd687f1b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -33,7 +33,6 @@ #include -#include "display/intel_display_core.h" #include "display/intel_display_irq.h" #include "display/intel_hotplug.h" #include "display/intel_hotplug_irq.h" @@ -794,9 +793,10 @@ static void cherryview_irq_postinstall(struct drm_i915_private *dev_priv) intel_uncore_posting_read(&dev_priv->uncore, GEN8_MASTER_IRQ); } +#define I9XX_HAS_FBC(i915) (IS_I85X(i915) || IS_I865G(i915) || IS_I915GM(i915) || IS_I945GM(i915)) + static u32 i9xx_error_mask(struct drm_i915_private *i915) { - struct intel_display *display = i915->display; /* * On gen2/3 FBC generates (seemingly spurious) * display INVALID_GTT/INVALID_GTT_PTE table errors. @@ -809,7 +809,7 @@ static u32 i9xx_error_mask(struct drm_i915_private *i915) * Unfortunately we can't mask off individual PGTBL_ER bits, * so we just have to mask off all page table errors via EMR. */ - if (HAS_FBC(display)) + if (I9XX_HAS_FBC(i915)) return I915_ERROR_MEMORY_REFRESH; else return I915_ERROR_PAGE_TABLE | -- cgit v1.2.3 From a5e07980e62deeb849e59c9f14299ea3f291969e Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Wed, 1 Oct 2025 16:23:36 +0200 Subject: drm/i915/gvt: Propagate vfio_set_irqs_validate_and_prepare() error Return the actual error code from vfio_set_irqs_validate_and_prepare() instead of always collapsing to -EINVAL. While the helper currently returns -EINVAL in most cases, passing through the real error code is more future-proof. While at it, drop the stray 'intel:' prefix from the error message. Signed-off-by: Andi Shyti Reviewed-by: Zhenyu Wang Link: https://lore.kernel.org/r/20251001142336.82089-1-andi.shyti@linux.intel.com --- drivers/gpu/drm/i915/gvt/kvmgt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 183128b84630..c43b47687838 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -1369,8 +1369,8 @@ static long intel_vgpu_ioctl(struct vfio_device *vfio_dev, unsigned int cmd, ret = vfio_set_irqs_validate_and_prepare(&hdr, max, VFIO_PCI_NUM_IRQS, &data_size); if (ret) { - gvt_vgpu_err("intel:vfio_set_irqs_validate_and_prepare failed\n"); - return -EINVAL; + gvt_vgpu_err("vfio_set_irqs_validate_and_prepare failed\n"); + return ret; } data = memdup_user((void __user *)(arg + minsz), -- cgit v1.2.3 From fcf6bddebfe03574041d7bb5f7e3f18e6b46a426 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Sep 2025 21:24:45 +0300 Subject: drm/dp: Add quirk for Synaptics DSC throughput link-bpp limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some Synaptics MST branch devices have a problem decompressing a stream with a compressed link-bpp higher than 12, if the pixel clock is higher than ~50 % of the maximum throughput capability reported by the branch device. The screen remains blank, or for some - mostly black content - gets enabled, but may stil have jitter artifacts. At least the following docking stations are affected, based on testing both with any Intel devices or the UCD-500 reference device as a source: - DELL WD19DCS, DELL WD19TB3, DELL WD22TB4 - ThinkPad 40AN - HP G2 At least the following docking stations are free from this problem, based on tests with a source/sink/mode etc. configuration matching the test cases used above: - DELL Dual Charge HD22Q, DELL WD25TB5 - ThinkPad 40B0 - Anker 565 All the affected devices have an older version of the Synaptics MST branch device (Panamera), whereas all the non-affected docking stations have a newer branch device (at least Synaptics Panamera with a higher HW revision number and Synaptics Cayenne models). Add the required quirk entries accordingly. The quirk will be handled by the i915/xe drivers in a follow-up change. The latest firmware version of the Synaptics branch device for all the affected devices tested above is 5.7 (as reported at DPCD address 0x50a/0x50b). For the DELL devices this corresponds to the latest 01.00.14.01.A03 firmware package version of the docking station. v2: - Document the DP_DPCD_QUIRK_DSC_THROUGHPUT_BPP_LIMIT enum. - Describe the quirk in more detail in the dpcd_quirk_list. v3: - s/Panarema/Panamera in the commit log. Cc: dri-devel@lists.freedesktop.org Reported-by: Vidya Srinivas Reported-and-tested-by: Swati Sharma Reviewed-by: Ville Syrjälä Acked-by: Maarten Lankhorst Signed-off-by: Imre Deak Link: https://lore.kernel.org/r/20250930182450.563016-2-imre.deak@intel.com --- drivers/gpu/drm/display/drm_dp_helper.c | 4 ++++ include/drm/display/drm_dp_helper.h | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index 4aaeae4fa03c..4cbcb685f562 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -2543,6 +2543,10 @@ static const struct dpcd_quirk dpcd_quirk_list[] = { { OUI(0x00, 0x0C, 0xE7), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC) }, /* Apple MacBookPro 2017 15 inch eDP Retina panel reports too low DP_MAX_LINK_RATE */ { OUI(0x00, 0x10, 0xfa), DEVICE_ID(101, 68, 21, 101, 98, 97), false, BIT(DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS) }, + /* Synaptics Panamera supports only a compressed bpp of 12 above 50% of its max DSC pixel throughput */ + { OUI(0x90, 0xCC, 0x24), DEVICE_ID('S', 'Y', 'N', 'A', 0x53, 0x22), true, BIT(DP_DPCD_QUIRK_DSC_THROUGHPUT_BPP_LIMIT) }, + { OUI(0x90, 0xCC, 0x24), DEVICE_ID('S', 'Y', 'N', 'A', 0x53, 0x31), true, BIT(DP_DPCD_QUIRK_DSC_THROUGHPUT_BPP_LIMIT) }, + { OUI(0x90, 0xCC, 0x24), DEVICE_ID('S', 'Y', 'N', 'A', 0x53, 0x33), true, BIT(DP_DPCD_QUIRK_DSC_THROUGHPUT_BPP_LIMIT) }, }; #undef OUI diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 87caa4f1fdb8..558f5ce924ac 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -820,6 +820,15 @@ enum drm_dp_quirk { * requires enabling DSC. */ DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC, + /** + * @DP_DPCD_QUIRK_DSC_THROUGHPUT_BPP_LIMIT: + * + * The device doesn't support DSC decompression at the maximum DSC + * pixel throughput and compressed bpp it indicates via its DPCD DSC + * capabilities. The compressed bpp must be limited above a device + * specific DSC pixel throughput. + */ + DP_DPCD_QUIRK_DSC_THROUGHPUT_BPP_LIMIT, }; /** -- cgit v1.2.3 From 1f95871207db4439a3116e9a86f5b5658a5157c4 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Sep 2025 21:24:46 +0300 Subject: drm/dp: Add helpers to query the branch DSC max throughput/line-width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helpers to query the DP DSC sink device's per-slice throughput as well as a DSC branch device's overall throughput and line-width capabilities. v2 (Ville): - Rename pixel_clock to peak_pixel_rate, document what the value means in case of MST tiled displays. - Fix name of drm_dp_dsc_branch_max_slice_throughput() to drm_dp_dsc_sink_max_slice_throughput(). v3: - Fix the DSC branch device minimum valid line width value from 2560 to 5120 pixels. - Fix drm_dp_dsc_sink_max_slice_throughput()'s pixel_clock parameter name to peak_pixel_rate in header file. - Add handling for throughput mode 0 granular delta, defined by DP Standard v2.1a. v4: - Remove the default switch case in drm_dp_dsc_sink_max_slice_throughput(), which is unreachable in the current code. (Ville) Cc: dri-devel@lists.freedesktop.org Suggested-by: Ville Syrjälä Reported-and-tested-by: Swati Sharma Reviewed-by: Ville Syrjälä Reviewed-by: Dmitry Baryshkov Acked-by: Maarten Lankhorst Signed-off-by: Imre Deak Link: https://lore.kernel.org/r/20250930182450.563016-3-imre.deak@intel.com --- drivers/gpu/drm/display/drm_dp_helper.c | 152 ++++++++++++++++++++++++++++++++ include/drm/display/drm_dp.h | 3 + include/drm/display/drm_dp_helper.h | 5 ++ 3 files changed, 160 insertions(+) diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index 4cbcb685f562..1ebed7c41b0d 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -2836,6 +2836,158 @@ int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_S } EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs); +/* + * See DP Standard v2.1a 2.8.4 Minimum Slices/Display, Table 2-159 and + * Appendix L.1 Derivation of Slice Count Requirements. + */ +static int dsc_sink_min_slice_throughput(int peak_pixel_rate) +{ + if (peak_pixel_rate >= 4800000) + return 600000; + else if (peak_pixel_rate >= 2700000) + return 400000; + else + return 340000; +} + +/** + * drm_dp_dsc_sink_max_slice_throughput() - Get a DSC sink's maximum pixel throughput per slice + * @dsc_dpcd: DSC sink's capabilities from DPCD + * @peak_pixel_rate: Cumulative peak pixel rate in kHz + * @is_rgb_yuv444: The mode is either RGB or YUV444 + * + * Return the DSC sink device's maximum pixel throughput per slice, based on + * the device's @dsc_dpcd capabilities, the @peak_pixel_rate of the transferred + * stream(s) and whether the output format @is_rgb_yuv444 or yuv422/yuv420. + * + * Note that @peak_pixel_rate is the total pixel rate transferred to the same + * DSC/display sink. For instance to calculate a tile's slice count of an MST + * multi-tiled display sink (not considering here the required + * rounding/alignment of slice count):: + * + * @peak_pixel_rate = tile_pixel_rate * tile_count + * total_slice_count = @peak_pixel_rate / drm_dp_dsc_sink_max_slice_throughput(@peak_pixel_rate) + * tile_slice_count = total_slice_count / tile_count + * + * Returns: + * The maximum pixel throughput per slice supported by the DSC sink device + * in kPixels/sec. + */ +int drm_dp_dsc_sink_max_slice_throughput(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], + int peak_pixel_rate, bool is_rgb_yuv444) +{ + int throughput; + int delta = 0; + int base; + + throughput = dsc_dpcd[DP_DSC_PEAK_THROUGHPUT - DP_DSC_SUPPORT]; + + if (is_rgb_yuv444) { + throughput = (throughput & DP_DSC_THROUGHPUT_MODE_0_MASK) >> + DP_DSC_THROUGHPUT_MODE_0_SHIFT; + + delta = ((dsc_dpcd[DP_DSC_RC_BUF_BLK_SIZE - DP_DSC_SUPPORT]) & + DP_DSC_THROUGHPUT_MODE_0_DELTA_MASK) >> + DP_DSC_THROUGHPUT_MODE_0_DELTA_SHIFT; /* in units of 2 MPixels/sec */ + delta *= 2000; + } else { + throughput = (throughput & DP_DSC_THROUGHPUT_MODE_1_MASK) >> + DP_DSC_THROUGHPUT_MODE_1_SHIFT; + } + + switch (throughput) { + case 0: + return dsc_sink_min_slice_throughput(peak_pixel_rate); + case 1: + base = 340000; + break; + case 2 ... 14: + base = 400000 + 50000 * (throughput - 2); + break; + case 15: + base = 170000; + break; + } + + return base + delta; +} +EXPORT_SYMBOL(drm_dp_dsc_sink_max_slice_throughput); + +static u8 dsc_branch_dpcd_cap(const u8 dpcd[DP_DSC_BRANCH_CAP_SIZE], int reg) +{ + return dpcd[reg - DP_DSC_BRANCH_OVERALL_THROUGHPUT_0]; +} + +/** + * drm_dp_dsc_branch_max_overall_throughput() - Branch device's max overall DSC pixel throughput + * @dsc_branch_dpcd: DSC branch capabilities from DPCD + * @is_rgb_yuv444: The mode is either RGB or YUV444 + * + * Return the branch device's maximum overall DSC pixel throughput, based on + * the device's DPCD DSC branch capabilities, and whether the output + * format @is_rgb_yuv444 or yuv422/yuv420. + * + * Returns: + * - 0: The maximum overall throughput capability is not indicated by + * the device separately and it must be determined from the per-slice + * max throughput (see @drm_dp_dsc_branch_slice_max_throughput()) + * and the maximum slice count supported by the device. + * - > 0: The maximum overall DSC pixel throughput supported by the branch + * device in kPixels/sec. + */ +int drm_dp_dsc_branch_max_overall_throughput(const u8 dsc_branch_dpcd[DP_DSC_BRANCH_CAP_SIZE], + bool is_rgb_yuv444) +{ + int throughput; + + if (is_rgb_yuv444) + throughput = dsc_branch_dpcd_cap(dsc_branch_dpcd, + DP_DSC_BRANCH_OVERALL_THROUGHPUT_0); + else + throughput = dsc_branch_dpcd_cap(dsc_branch_dpcd, + DP_DSC_BRANCH_OVERALL_THROUGHPUT_1); + + switch (throughput) { + case 0: + return 0; + case 1: + return 680000; + default: + return 600000 + 50000 * throughput; + } +} +EXPORT_SYMBOL(drm_dp_dsc_branch_max_overall_throughput); + +/** + * drm_dp_dsc_branch_max_line_width() - Branch device's max DSC line width + * @dsc_branch_dpcd: DSC branch capabilities from DPCD + * + * Return the branch device's maximum overall DSC line width, based on + * the device's @dsc_branch_dpcd capabilities. + * + * Returns: + * - 0: The maximum line width is not indicated by the device + * separately and it must be determined from the maximum + * slice count and slice-width supported by the device. + * - %-EINVAL: The device indicates an invalid maximum line width + * (< 5120 pixels). + * - >= 5120: The maximum line width in pixels. + */ +int drm_dp_dsc_branch_max_line_width(const u8 dsc_branch_dpcd[DP_DSC_BRANCH_CAP_SIZE]) +{ + int line_width = dsc_branch_dpcd_cap(dsc_branch_dpcd, DP_DSC_BRANCH_MAX_LINE_WIDTH); + + switch (line_width) { + case 0: + return 0; + case 1 ... 15: + return -EINVAL; + default: + return line_width * 320; + } +} +EXPORT_SYMBOL(drm_dp_dsc_branch_max_line_width); + static int drm_dp_read_lttpr_regs(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE], int address, u8 *buf, int buf_size) diff --git a/include/drm/display/drm_dp.h b/include/drm/display/drm_dp.h index 811e9238a77c..600bca40249b 100644 --- a/include/drm/display/drm_dp.h +++ b/include/drm/display/drm_dp.h @@ -257,6 +257,8 @@ # define DP_DSC_RC_BUF_BLK_SIZE_4 0x1 # define DP_DSC_RC_BUF_BLK_SIZE_16 0x2 # define DP_DSC_RC_BUF_BLK_SIZE_64 0x3 +# define DP_DSC_THROUGHPUT_MODE_0_DELTA_SHIFT 3 /* DP 2.1a, in units of 2 MPixels/sec */ +# define DP_DSC_THROUGHPUT_MODE_0_DELTA_MASK (0x1f << DP_DSC_THROUGHPUT_MODE_0_DELTA_SHIFT) #define DP_DSC_RC_BUF_SIZE 0x063 @@ -1683,6 +1685,7 @@ enum drm_dp_phy { #define DP_BRANCH_OUI_HEADER_SIZE 0xc #define DP_RECEIVER_CAP_SIZE 0xf #define DP_DSC_RECEIVER_CAP_SIZE 0x10 /* DSC Capabilities 0x60 through 0x6F */ +#define DP_DSC_BRANCH_CAP_SIZE 3 #define EDP_PSR_RECEIVER_CAP_SIZE 2 #define EDP_DISPLAY_CTL_CAP_SIZE 5 #define DP_LTTPR_COMMON_CAP_SIZE 8 diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 558f5ce924ac..fc02eb888be8 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -203,6 +203,11 @@ u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]); int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpc[DP_DSC_RECEIVER_CAP_SIZE], u8 dsc_bpc[3]); +int drm_dp_dsc_sink_max_slice_throughput(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], + int peak_pixel_rate, bool is_rgb_yuv444); +int drm_dp_dsc_branch_max_overall_throughput(const u8 dsc_branch_dpcd[DP_DSC_BRANCH_CAP_SIZE], + bool is_rgb_yuv444); +int drm_dp_dsc_branch_max_line_width(const u8 dsc_branch_dpcd[DP_DSC_BRANCH_CAP_SIZE]); static inline bool drm_dp_sink_supports_dsc(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) -- cgit v1.2.3 From b3797460fd3024f4c0458027f453f52926853e3f Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Sep 2025 21:24:47 +0300 Subject: drm/i915/dp: Calculate DSC slice count based on per-slice peak throughput MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the DSC sink device's actual per-slice peak throughput to calculate the minimum number of required DSC slices, falling back to the hard-coded throughput values (as suggested by the DP Standard) if the device's reported throughput value is 0. For now use the minimum of the two throughput values, which is ok, potentially resulting in a higher than required minimum slice count. This doesn't change the current way of using the same minimum throughput value regardless of the RGB/YUV output format used. While at it add a TODO comment for MST tiled displays to calculate the slice count for these based on the total pixel rate of all the tiles. v2: Use drm helpers to query the throughput caps. (Ville) v3: Add TODO comment to account for MST tiled displays. (Ville) Cc: Ville Syrjälä Reported-and-tested-by: Swati Sharma Reviewed-by: Ville Syrjälä Signed-off-by: Imre Deak Link: https://lore.kernel.org/r/20250930182450.563016-4-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2eab591a8ef5..491a804c1f6a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -96,11 +96,6 @@ #include "intel_vdsc.h" #include "intel_vrr.h" -/* DP DSC throughput values used for slice count calculations KPixels/s */ -#define DP_DSC_PEAK_PIXEL_RATE 2720000 -#define DP_DSC_MAX_ENC_THROUGHPUT_0 340000 -#define DP_DSC_MAX_ENC_THROUGHPUT_1 400000 - /* Max DSC line buffer depth supported by HW. */ #define INTEL_DP_DSC_MAX_LINE_BUF_DEPTH 13 @@ -1018,13 +1013,29 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, struct intel_display *display = to_intel_display(connector); u8 min_slice_count, i; int max_slice_width; + int tp_rgb_yuv444; + int tp_yuv422_420; - if (mode_clock <= DP_DSC_PEAK_PIXEL_RATE) - min_slice_count = DIV_ROUND_UP(mode_clock, - DP_DSC_MAX_ENC_THROUGHPUT_0); - else - min_slice_count = DIV_ROUND_UP(mode_clock, - DP_DSC_MAX_ENC_THROUGHPUT_1); + /* + * TODO: Pass the total pixel rate of all the streams transferred to + * an MST tiled display, calculate the total slice count for all tiles + * from this and the per-tile slice count from the total slice count. + */ + tp_rgb_yuv444 = drm_dp_dsc_sink_max_slice_throughput(connector->dp.dsc_dpcd, + mode_clock, true); + tp_yuv422_420 = drm_dp_dsc_sink_max_slice_throughput(connector->dp.dsc_dpcd, + mode_clock, false); + + /* + * TODO: Use the throughput value specific to the actual RGB/YUV + * format of the output. + * For now use the smaller of these, which is ok, potentially + * resulting in a higher than required minimum slice count. + * The RGB/YUV444 throughput value should be always either equal + * or smaller than the YUV422/420 value, but let's not depend on + * this assumption. + */ + min_slice_count = DIV_ROUND_UP(mode_clock, min(tp_rgb_yuv444, tp_yuv422_420)); /* * Due to some DSC engine BW limitations, we need to enable second -- cgit v1.2.3 From 8e696c8d2c9d626278c124009492481d7787480f Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Sep 2025 21:24:48 +0300 Subject: drm/i915/dp: Pass DPCD device descriptor to intel_dp_get_dsc_sink_cap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass the DPCD sink/branch device descriptor along with the is_branch/sink flag to intel_dp_get_dsc_sink_cap(). These will be used by a follow up change to read out the branch device's DSC overall throughput/line width capabilities and to detect a throughput/link-bpp quirk. Reported-and-tested-by: Swati Sharma Reviewed-by: Ville Syrjälä Signed-off-by: Imre Deak Link: https://lore.kernel.org/r/20250930182450.563016-5-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 5 ++++- drivers/gpu/drm/i915/display/intel_dp.h | 5 ++++- drivers/gpu/drm/i915/display/intel_dp_mst.c | 9 ++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 491a804c1f6a..2dcc20bcfa0b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4180,7 +4180,9 @@ static void intel_dp_read_dsc_dpcd(struct drm_dp_aux *aux, dsc_dpcd); } -void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, struct intel_connector *connector) +void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, + const struct drm_dp_desc *desc, bool is_branch, + struct intel_connector *connector) { struct intel_display *display = to_intel_display(connector); @@ -4231,6 +4233,7 @@ intel_dp_detect_dsc_caps(struct intel_dp *intel_dp, struct intel_connector *conn connector); else intel_dp_get_dsc_sink_cap(intel_dp->dpcd[DP_DPCD_REV], + &intel_dp->desc, drm_dp_is_branch(intel_dp->dpcd), connector); } diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index f90cfd1dbbd0..b379443e0211 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -12,6 +12,7 @@ enum intel_output_format; enum pipe; enum port; struct drm_connector_state; +struct drm_dp_desc; struct drm_dp_vsc_sdp; struct drm_encoder; struct drm_modeset_acquire_ctx; @@ -199,7 +200,9 @@ bool intel_dp_compute_config_limits(struct intel_dp *intel_dp, bool dsc, struct link_config_limits *limits); -void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, struct intel_connector *connector); +void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, + const struct drm_dp_desc *desc, bool is_branch, + struct intel_connector *connector); bool intel_dp_has_gamut_metadata_dip(struct intel_encoder *encoder); bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 352f7ef29c28..f2266b265304 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1658,6 +1658,7 @@ intel_dp_mst_read_decompression_port_dsc_caps(struct intel_dp *intel_dp, struct intel_connector *connector) { u8 dpcd_caps[DP_RECEIVER_CAP_SIZE]; + struct drm_dp_desc desc; if (!connector->dp.dsc_decompression_aux) return; @@ -1665,7 +1666,13 @@ intel_dp_mst_read_decompression_port_dsc_caps(struct intel_dp *intel_dp, if (drm_dp_read_dpcd_caps(connector->dp.dsc_decompression_aux, dpcd_caps) < 0) return; - intel_dp_get_dsc_sink_cap(dpcd_caps[DP_DPCD_REV], connector); + if (drm_dp_read_desc(connector->dp.dsc_decompression_aux, &desc, + drm_dp_is_branch(dpcd_caps)) < 0) + return; + + intel_dp_get_dsc_sink_cap(dpcd_caps[DP_DPCD_REV], + &desc, drm_dp_is_branch(dpcd_caps), + connector); } static bool detect_dsc_hblank_expansion_quirk(const struct intel_connector *connector) -- cgit v1.2.3 From a086950670af7336e73c658567bc7f745c552c91 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Sep 2025 21:24:49 +0300 Subject: drm/i915/dp: Verify branch devices' overall pixel throughput/line width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read out the branch devices' maximum overall DSC pixel throughput and line width and verify the mode's corresponding pixel clock and hactive period against these. v2: Use drm helpers to query the throughput/line-width caps. (Ville) Cc: Ville Syrjälä Reported-and-tested-by: Swati Sharma Reviewed-by: Ville Syrjälä Signed-off-by: Imre Deak Link: https://lore.kernel.org/r/20250930182450.563016-6-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display_types.h | 8 ++++ drivers/gpu/drm/i915/display/intel_dp.c | 51 ++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 029c47743f8b..99d2c3123692 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -552,6 +552,14 @@ struct intel_connector { u8 dsc_hblank_expansion_quirk:1; u8 dsc_decompression_enabled:1; + + struct { + struct { + int rgb_yuv444; + int yuv422_420; + } overall_throughput; + int max_line_width; + } dsc_branch_caps; } dp; struct { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2dcc20bcfa0b..9de9356302f9 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1016,6 +1016,20 @@ u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, int tp_rgb_yuv444; int tp_yuv422_420; + /* + * TODO: Use the throughput value specific to the actual RGB/YUV + * format of the output. + * The RGB/YUV444 throughput value should be always either equal + * or smaller than the YUV422/420 value, but let's not depend on + * this assumption. + */ + if (mode_clock > max(connector->dp.dsc_branch_caps.overall_throughput.rgb_yuv444, + connector->dp.dsc_branch_caps.overall_throughput.yuv422_420)) + return 0; + + if (mode_hdisplay > connector->dp.dsc_branch_caps.max_line_width) + return 0; + /* * TODO: Pass the total pixel rate of all the streams transferred to * an MST tiled display, calculate the total slice count for all tiles @@ -4180,6 +4194,33 @@ static void intel_dp_read_dsc_dpcd(struct drm_dp_aux *aux, dsc_dpcd); } +static void init_dsc_overall_throughput_limits(struct intel_connector *connector, bool is_branch) +{ + u8 branch_caps[DP_DSC_BRANCH_CAP_SIZE]; + int line_width; + + connector->dp.dsc_branch_caps.overall_throughput.rgb_yuv444 = INT_MAX; + connector->dp.dsc_branch_caps.overall_throughput.yuv422_420 = INT_MAX; + connector->dp.dsc_branch_caps.max_line_width = INT_MAX; + + if (!is_branch) + return; + + if (drm_dp_dpcd_read_data(connector->dp.dsc_decompression_aux, + DP_DSC_BRANCH_OVERALL_THROUGHPUT_0, branch_caps, + sizeof(branch_caps)) != 0) + return; + + connector->dp.dsc_branch_caps.overall_throughput.rgb_yuv444 = + drm_dp_dsc_branch_max_overall_throughput(branch_caps, true) ? : INT_MAX; + + connector->dp.dsc_branch_caps.overall_throughput.yuv422_420 = + drm_dp_dsc_branch_max_overall_throughput(branch_caps, false) ? : INT_MAX; + + line_width = drm_dp_dsc_branch_max_line_width(branch_caps); + connector->dp.dsc_branch_caps.max_line_width = line_width > 0 ? line_width : INT_MAX; +} + void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, const struct drm_dp_desc *desc, bool is_branch, struct intel_connector *connector) @@ -4195,6 +4236,8 @@ void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, /* Clear fec_capable to avoid using stale values */ connector->dp.fec_capability = 0; + memset(&connector->dp.dsc_branch_caps, 0, sizeof(connector->dp.dsc_branch_caps)); + if (dpcd_rev < DP_DPCD_REV_14) return; @@ -4209,6 +4252,11 @@ void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, drm_dbg_kms(display->drm, "FEC CAPABILITY: %x\n", connector->dp.fec_capability); + + if (!(connector->dp.dsc_dpcd[0] & DP_DSC_DECOMPRESSION_IS_SUPPORTED)) + return; + + init_dsc_overall_throughput_limits(connector, is_branch); } static void intel_edp_get_dsc_sink_cap(u8 edp_dpcd_rev, struct intel_connector *connector) @@ -4217,6 +4265,9 @@ static void intel_edp_get_dsc_sink_cap(u8 edp_dpcd_rev, struct intel_connector * return; intel_dp_read_dsc_dpcd(connector->dp.dsc_decompression_aux, connector->dp.dsc_dpcd); + + if (connector->dp.dsc_dpcd[0] & DP_DSC_DECOMPRESSION_IS_SUPPORTED) + init_dsc_overall_throughput_limits(connector, false); } static void -- cgit v1.2.3 From 8d677285a363556db4cfb8b7ed54cff0bbc11d6a Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Sep 2025 21:24:50 +0300 Subject: drm/i915/dp: Handle Synaptics DSC throughput link-bpp quirk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle the DSC pixel throughput quirk, limiting the compressed link-bpp value for Synaptics Panamera branch devices, working around a blank/unstable output issue observed on docking stations containing these branch devices, when using a mode with a high pixel clock and a high compressed link-bpp value. For now use the same mode clock limit for RGB/YUV444 and YUV422/420 output modes. This may result in limiting the link-bpp value for a YUV422/420 output mode already at a lower than required mode clock. v2: Apply the quirk only when DSC is enabled. v3 (Ville): - Move adjustment of link-bpp within the already existing is_dsc if branch. - Add TODO comment to move the HW revision check as well to the DRM core quirk table. v4: - Fix incorrect fxp_q4_from_int(INT_MAX) vs. INT_MAX return value from dsc_throughput_quirk_max_bpp_x16(). Cc: Ville Syrjälä Reported-by: Vidya Srinivas Reported-and-tested-by: Swati Sharma Reviewed-by: Ville Syrjälä Signed-off-by: Imre Deak Link: https://lore.kernel.org/r/20250930182450.563016-7-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 57 ++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 99d2c3123692..ca5a87772e93 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -551,6 +551,7 @@ struct intel_connector { u8 fec_capability; u8 dsc_hblank_expansion_quirk:1; + u8 dsc_throughput_quirk:1; u8 dsc_decompression_enabled:1; struct { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 9de9356302f9..8a2fc1fcb5d0 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2485,6 +2485,40 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, return 0; } +static int +dsc_throughput_quirk_max_bpp_x16(const struct intel_connector *connector, + const struct intel_crtc_state *crtc_state) +{ + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + + if (!connector->dp.dsc_throughput_quirk) + return INT_MAX; + + /* + * Synaptics Panamera branch devices have a problem decompressing a + * stream with a compressed link-bpp higher than 12, if the pixel + * clock is higher than ~50 % of the maximum overall throughput + * reported by the branch device. Work around this by limiting the + * maximum link bpp for such pixel clocks. + * + * TODO: Use the throughput value specific to the actual RGB/YUV + * format of the output, after determining the pixel clock limit for + * YUV modes. For now use the smaller of the throughput values, which + * may result in limiting the link-bpp value already at a lower than + * required mode clock in case of native YUV422/420 output formats. + * The RGB/YUV444 throughput value should be always either equal or + * smaller than the YUV422/420 value, but let's not depend on this + * assumption. + */ + if (adjusted_mode->crtc_clock < + min(connector->dp.dsc_branch_caps.overall_throughput.rgb_yuv444, + connector->dp.dsc_branch_caps.overall_throughput.yuv422_420) / 2) + return INT_MAX; + + return fxp_q4_from_int(12); +} + /* * Calculate the output link min, max bpp values in limits based on the pipe bpp * range, crtc_state and dsc mode. Return true on success. @@ -2516,6 +2550,7 @@ intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp, } else { int dsc_src_min_bpp, dsc_sink_min_bpp, dsc_min_bpp; int dsc_src_max_bpp, dsc_sink_max_bpp, dsc_max_bpp; + int throughput_max_bpp_x16; dsc_src_min_bpp = intel_dp_dsc_min_src_compressed_bpp(); dsc_sink_min_bpp = intel_dp_dsc_sink_min_compressed_bpp(crtc_state); @@ -2530,6 +2565,19 @@ intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp, min(dsc_sink_max_bpp, dsc_src_max_bpp) : dsc_src_max_bpp; max_link_bpp_x16 = min(max_link_bpp_x16, fxp_q4_from_int(dsc_max_bpp)); + + throughput_max_bpp_x16 = dsc_throughput_quirk_max_bpp_x16(connector, crtc_state); + throughput_max_bpp_x16 = clamp(throughput_max_bpp_x16, + limits->link.min_bpp_x16, max_link_bpp_x16); + if (throughput_max_bpp_x16 < max_link_bpp_x16) { + max_link_bpp_x16 = throughput_max_bpp_x16; + + drm_dbg_kms(display->drm, + "[CRTC:%d:%s][CONNECTOR:%d:%s] Decreasing link max bpp to " FXP_Q4_FMT " due to DSC throughput quirk\n", + crtc->base.base.id, crtc->base.name, + connector->base.base.id, connector->base.name, + FXP_Q4_ARGS(max_link_bpp_x16)); + } } limits->link.max_bpp_x16 = max_link_bpp_x16; @@ -4237,6 +4285,7 @@ void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, connector->dp.fec_capability = 0; memset(&connector->dp.dsc_branch_caps, 0, sizeof(connector->dp.dsc_branch_caps)); + connector->dp.dsc_throughput_quirk = false; if (dpcd_rev < DP_DPCD_REV_14) return; @@ -4257,6 +4306,14 @@ void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, return; init_dsc_overall_throughput_limits(connector, is_branch); + + /* + * TODO: Move the HW rev check as well to the DRM core quirk table if + * that's required after clarifying the list of affected devices. + */ + if (drm_dp_has_quirk(desc, DP_DPCD_QUIRK_DSC_THROUGHPUT_BPP_LIMIT) && + desc->ident.hw_rev == 0x10) + connector->dp.dsc_throughput_quirk = true; } static void intel_edp_get_dsc_sink_cap(u8 edp_dpcd_rev, struct intel_connector *connector) -- cgit v1.2.3 From defa5d7548e8569c4c06e7037a2d4110d0a71ac1 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Wed, 1 Oct 2025 13:04:48 -0300 Subject: drm/i915/display: Extract separate AUX PW descriptors In an upcoming change, we will fix an ordering issue between PICA and AUX power wells for Xe2_LPD and later, making sure that the driver acquires PICA power before AUX. As a preparation for that, let's extract separate descriptors for AUX power wells. Suggested-by: Imre Deak Reviewed-by: Imre Deak Link: https://lore.kernel.org/r/20251001-pica-power-before-aux-v2-1-6308df4de5a8@intel.com Signed-off-by: Gustavo Sousa --- .../gpu/drm/i915/display/intel_display_power_map.c | 26 ++++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power_map.c b/drivers/gpu/drm/i915/display/intel_display_power_map.c index 39b71fffa2cd..e89f18b7037f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_map.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_map.c @@ -1516,7 +1516,11 @@ static const struct i915_power_well_desc xelpdp_power_wells_main[] = { .ops = &hsw_power_well_ops, .irq_pipe_mask = BIT(PIPE_D), .has_fuses = true, - }, { + }, +}; + +static const struct i915_power_well_desc xelpdp_power_wells_aux[] = { + { .instances = &I915_PW_INSTANCES( I915_PW("AUX_A", &icl_pwdoms_aux_a, .xelpdp.aux_ch = AUX_CH_A), I915_PW("AUX_B", &icl_pwdoms_aux_b, .xelpdp.aux_ch = AUX_CH_B), @@ -1534,6 +1538,7 @@ static const struct i915_power_well_desc_list xelpdp_power_wells[] = { I915_PW_DESCRIPTORS(icl_power_wells_pw_1), I915_PW_DESCRIPTORS(xelpd_power_wells_dc_off), I915_PW_DESCRIPTORS(xelpdp_power_wells_main), + I915_PW_DESCRIPTORS(xelpdp_power_wells_aux), }; I915_DECL_PW_DOMAINS(xe2lpd_pwdoms_pica_tc, @@ -1583,6 +1588,7 @@ static const struct i915_power_well_desc_list xe2lpd_power_wells[] = { I915_PW_DESCRIPTORS(icl_power_wells_pw_1), I915_PW_DESCRIPTORS(xe2lpd_power_wells_dcoff), I915_PW_DESCRIPTORS(xelpdp_power_wells_main), + I915_PW_DESCRIPTORS(xelpdp_power_wells_aux), I915_PW_DESCRIPTORS(xe2lpd_power_wells_pica), }; @@ -1677,16 +1683,6 @@ static const struct i915_power_well_desc xe3lpd_power_wells_main[] = { .ops = &hsw_power_well_ops, .irq_pipe_mask = BIT(PIPE_D), .has_fuses = true, - }, { - .instances = &I915_PW_INSTANCES( - I915_PW("AUX_A", &icl_pwdoms_aux_a, .xelpdp.aux_ch = AUX_CH_A), - I915_PW("AUX_B", &icl_pwdoms_aux_b, .xelpdp.aux_ch = AUX_CH_B), - I915_PW("AUX_TC1", &xelpdp_pwdoms_aux_tc1, .xelpdp.aux_ch = AUX_CH_USBC1), - I915_PW("AUX_TC2", &xelpdp_pwdoms_aux_tc2, .xelpdp.aux_ch = AUX_CH_USBC2), - I915_PW("AUX_TC3", &xelpdp_pwdoms_aux_tc3, .xelpdp.aux_ch = AUX_CH_USBC3), - I915_PW("AUX_TC4", &xelpdp_pwdoms_aux_tc4, .xelpdp.aux_ch = AUX_CH_USBC4), - ), - .ops = &xelpdp_aux_power_well_ops, }, }; @@ -1714,6 +1710,7 @@ static const struct i915_power_well_desc_list xe3lpd_power_wells[] = { I915_PW_DESCRIPTORS(icl_power_wells_pw_1), I915_PW_DESCRIPTORS(xe3lpd_power_wells_dcoff), I915_PW_DESCRIPTORS(xe3lpd_power_wells_main), + I915_PW_DESCRIPTORS(xelpdp_power_wells_aux), I915_PW_DESCRIPTORS(xe2lpd_power_wells_pica), }; @@ -1751,7 +1748,11 @@ static const struct i915_power_well_desc wcl_power_wells_main[] = { .ops = &hsw_power_well_ops, .irq_pipe_mask = BIT(PIPE_C), .has_fuses = true, - }, { + }, +}; + +static const struct i915_power_well_desc wcl_power_wells_aux[] = { + { .instances = &I915_PW_INSTANCES( I915_PW("AUX_A", &icl_pwdoms_aux_a, .xelpdp.aux_ch = AUX_CH_A), I915_PW("AUX_B", &icl_pwdoms_aux_b, .xelpdp.aux_ch = AUX_CH_B), @@ -1767,6 +1768,7 @@ static const struct i915_power_well_desc_list wcl_power_wells[] = { I915_PW_DESCRIPTORS(icl_power_wells_pw_1), I915_PW_DESCRIPTORS(xe3lpd_power_wells_dcoff), I915_PW_DESCRIPTORS(wcl_power_wells_main), + I915_PW_DESCRIPTORS(wcl_power_wells_aux), I915_PW_DESCRIPTORS(xe2lpd_power_wells_pica), }; -- cgit v1.2.3 From df66786e6999e59e822498ec8cdf0bbf691019b7 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Wed, 1 Oct 2025 13:04:49 -0300 Subject: drm/i915/display: Enable PICA power before AUX According to Bspec, before enabling AUX power, we need to have the "power well containing Aux logic powered up". Starting with Xe2_LPD, such power well is the "PICA" power well, which is managed by the driver on demand. While we did add the mapping of AUX power domains to the PICA power well, we ended up placing its power well descriptor after the descriptor for AUX power. As a result, when enabling power wells for one of the aux power domains, the driver will enable AUX power before PICA power, going against the order specified in Bspec. It appears that issue did not become apparent to us mainly because, luckily, AUX power is brought up after we assert PICA power, even if done in the wrong order; and in enough time for the first AUX transaction to succeed. Furthermore, I have also realized that, in some cases, like driver initialization, PICA power is already up when we need to acquire AUX power. One case where we can observe the incorrect ordering is when the driver is resuming from runtime PM suspend. Here is an excerpt of a dmesg with some extra debug logs extracted from a LNL machine to illustrate the issue: [ +0.000156] xe 0000:00:02.0: [drm:intel_power_well_enable [xe]] enabling AUX_TC1 [ +0.001312] xe 0000:00:02.0: [drm:xelpdp_aux_power_well_enable [xe]] DBG: AUX_CH_USBC1 power status: 0 [ +0.000127] xe 0000:00:02.0: [drm:intel_power_well_enable [xe]] enabling PICA_TC [ +0.001072] xe 0000:00:02.0: [drm:xe2lpd_pica_power_well_enable [xe]] DBG: AUX_CH_USBC1 power status: 1 [ +0.000102] xe 0000:00:02.0: [drm:xe2lpd_pica_power_well_enable [xe]] DBG: AUX_CH_USBC2 power status: 0 [ +0.000090] xe 0000:00:02.0: [drm:xe2lpd_pica_power_well_enable [xe]] DBG: AUX_CH_USBC3 power status: 0 [ +0.000092] xe 0000:00:02.0: [drm:xe2lpd_pica_power_well_enable [xe]] DBG: AUX_CH_USBC4 power status: 0 The first "DBG: ..." line shows that AUX power for TC1 is off after we assert and wait. The remaining lines show that AUX power for TC1 was on after we enabled PICA power and waited for AUX power. It is important that we stay compliant with the spec, so let's fix this by listing the power wells in an order that matches the requirements from Bspec. (As a side note, it would be nice if we could define those dependencies explicitly.) After this change, we have: [ +0.000146] xe 0000:00:02.0: [drm:intel_power_well_enable [xe]] enabling PICA_TC [ +0.001417] xe 0000:00:02.0: [drm:xe2lpd_pica_power_well_enable [xe]] DBG: AUX_CH_USBC1 power status: 0 [ +0.000116] xe 0000:00:02.0: [drm:xe2lpd_pica_power_well_enable [xe]] DBG: AUX_CH_USBC2 power status: 0 [ +0.000096] xe 0000:00:02.0: [drm:xe2lpd_pica_power_well_enable [xe]] DBG: AUX_CH_USBC3 power status: 0 [ +0.000094] xe 0000:00:02.0: [drm:xe2lpd_pica_power_well_enable [xe]] DBG: AUX_CH_USBC4 power status: 0 [ +0.000095] xe 0000:00:02.0: [drm:intel_power_well_enable [xe]] enabling AUX_TC1 [ +0.000915] xe 0000:00:02.0: [drm:xelpdp_aux_power_well_enable [xe]] DBG: AUX_CH_USBC1 power status: 1 Bspec: 68967, 68886, 72519 Reviewed-by: Imre Deak Link: https://lore.kernel.org/r/20251001-pica-power-before-aux-v2-2-6308df4de5a8@intel.com Signed-off-by: Gustavo Sousa --- drivers/gpu/drm/i915/display/intel_display_power_map.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power_map.c b/drivers/gpu/drm/i915/display/intel_display_power_map.c index e89f18b7037f..9b49952994ce 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_map.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_map.c @@ -1588,8 +1588,8 @@ static const struct i915_power_well_desc_list xe2lpd_power_wells[] = { I915_PW_DESCRIPTORS(icl_power_wells_pw_1), I915_PW_DESCRIPTORS(xe2lpd_power_wells_dcoff), I915_PW_DESCRIPTORS(xelpdp_power_wells_main), - I915_PW_DESCRIPTORS(xelpdp_power_wells_aux), I915_PW_DESCRIPTORS(xe2lpd_power_wells_pica), + I915_PW_DESCRIPTORS(xelpdp_power_wells_aux), }; /* @@ -1710,8 +1710,8 @@ static const struct i915_power_well_desc_list xe3lpd_power_wells[] = { I915_PW_DESCRIPTORS(icl_power_wells_pw_1), I915_PW_DESCRIPTORS(xe3lpd_power_wells_dcoff), I915_PW_DESCRIPTORS(xe3lpd_power_wells_main), - I915_PW_DESCRIPTORS(xelpdp_power_wells_aux), I915_PW_DESCRIPTORS(xe2lpd_power_wells_pica), + I915_PW_DESCRIPTORS(xelpdp_power_wells_aux), }; static const struct i915_power_well_desc wcl_power_wells_main[] = { @@ -1768,8 +1768,8 @@ static const struct i915_power_well_desc_list wcl_power_wells[] = { I915_PW_DESCRIPTORS(icl_power_wells_pw_1), I915_PW_DESCRIPTORS(xe3lpd_power_wells_dcoff), I915_PW_DESCRIPTORS(wcl_power_wells_main), - I915_PW_DESCRIPTORS(wcl_power_wells_aux), I915_PW_DESCRIPTORS(xe2lpd_power_wells_pica), + I915_PW_DESCRIPTORS(wcl_power_wells_aux), }; static void init_power_well_domains(const struct i915_power_well_instance *inst, -- cgit v1.2.3 From ea1a866a30153c743e4b933d2788277bec0016e0 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 21:08:36 +0300 Subject: drm/i915: Use the the correct pixel rate to compute wm line time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The line time used for the watermark calculations is supposed to based on the plane's adjusted pixel rate, not the pipe's adjusted pixel rate. The current code will give incorrect answers if plane downscaling is used. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919180838.10498-2-ville.syrjala@linux.intel.com Reviewed-by: Vinod Govindapillai --- drivers/gpu/drm/i915/display/skl_watermark.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 9eb28d935757..f73d1d24a488 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1637,18 +1637,16 @@ skl_wm_method2(u32 pixel_rate, u32 pipe_htotal, u32 latency, } static uint_fixed_16_16_t -intel_get_linetime_us(const struct intel_crtc_state *crtc_state) +intel_get_linetime_us(const struct intel_crtc_state *crtc_state, + int pixel_rate) { struct intel_display *display = to_intel_display(crtc_state); - u32 pixel_rate; u32 crtc_htotal; uint_fixed_16_16_t linetime_us; if (!crtc_state->hw.active) return u32_to_fixed16(0); - pixel_rate = crtc_state->pixel_rate; - if (drm_WARN_ON(display->drm, pixel_rate == 0)) return u32_to_fixed16(0); @@ -1743,7 +1741,8 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, wp->y_tile_minimum = mul_u32_fixed16(wp->y_min_scanlines, wp->plane_blocks_per_line); - wp->linetime_us = fixed16_to_u32_round_up(intel_get_linetime_us(crtc_state)); + wp->linetime_us = fixed16_to_u32_round_up(intel_get_linetime_us(crtc_state, + plane_pixel_rate)); return 0; } -- cgit v1.2.3 From 09f21bee91b2d47c57e8f3ee31632c51b1799806 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 21:08:37 +0300 Subject: drm/i915: Deobfuscate wm linetime calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_get_linetime_us() is a mess. Rewrite it in a straightforward manner. Also the checks for the !active and pixel_rate==0 are completely pointless here since we know that the plane is visible. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919180838.10498-3-ville.syrjala@linux.intel.com Reviewed-by: Vinod Govindapillai --- drivers/gpu/drm/i915/display/skl_watermark.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index f73d1d24a488..93cad11e0b31 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1636,24 +1636,12 @@ skl_wm_method2(u32 pixel_rate, u32 pipe_htotal, u32 latency, return ret; } -static uint_fixed_16_16_t +static int intel_get_linetime_us(const struct intel_crtc_state *crtc_state, int pixel_rate) { - struct intel_display *display = to_intel_display(crtc_state); - u32 crtc_htotal; - uint_fixed_16_16_t linetime_us; - - if (!crtc_state->hw.active) - return u32_to_fixed16(0); - - if (drm_WARN_ON(display->drm, pixel_rate == 0)) - return u32_to_fixed16(0); - - crtc_htotal = crtc_state->hw.pipe_mode.crtc_htotal; - linetime_us = div_fixed16(crtc_htotal * 1000, pixel_rate); - - return linetime_us; + return DIV_ROUND_UP(crtc_state->hw.pipe_mode.crtc_htotal * 1000, + pixel_rate); } static int @@ -1741,8 +1729,7 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, wp->y_tile_minimum = mul_u32_fixed16(wp->y_min_scanlines, wp->plane_blocks_per_line); - wp->linetime_us = fixed16_to_u32_round_up(intel_get_linetime_us(crtc_state, - plane_pixel_rate)); + wp->linetime_us = intel_get_linetime_us(crtc_state, plane_pixel_rate); return 0; } -- cgit v1.2.3 From 32fdf8f418d74da3e22a2c1319285010192edc73 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Sep 2025 21:08:38 +0300 Subject: drm/i915: s/intel_get_linetime_us()/skl_wm_linetime_us()/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename intel_get_linetime_us() to skl_wm_linetime_us() to better reflect that it's not meant to be used for anything apart from the watermark calculations. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250919180838.10498-4-ville.syrjala@linux.intel.com Reviewed-by: Vinod Govindapillai --- drivers/gpu/drm/i915/display/skl_watermark.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 93cad11e0b31..9df9ee137bf9 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1636,9 +1636,8 @@ skl_wm_method2(u32 pixel_rate, u32 pipe_htotal, u32 latency, return ret; } -static int -intel_get_linetime_us(const struct intel_crtc_state *crtc_state, - int pixel_rate) +static int skl_wm_linetime_us(const struct intel_crtc_state *crtc_state, + int pixel_rate) { return DIV_ROUND_UP(crtc_state->hw.pipe_mode.crtc_htotal * 1000, pixel_rate); @@ -1729,7 +1728,7 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, wp->y_tile_minimum = mul_u32_fixed16(wp->y_min_scanlines, wp->plane_blocks_per_line); - wp->linetime_us = intel_get_linetime_us(crtc_state, plane_pixel_rate); + wp->linetime_us = skl_wm_linetime_us(crtc_state, plane_pixel_rate); return 0; } -- cgit v1.2.3