On Tue, Feb 18, 2025 at 12:00:19PM +0200, Mika Kahola wrote:
> The dedicated display PHYs reset to a power state that blocks S0ix,
> increasing idle system power. After a system reset (cold boot,
> S3/4/5, warm reset) if a dedicated PHY is not being brought up
> shortly, use these steps to move the PHY to the lowest power state
> to save power.
> 
> 1. Follow the PLL Enable Sequence, using any valid frequency such
>    as DP 1.62 GHz. This brings lanes out of reset and enables the
>    PLL to allow powerdown to be moved to the Disable state.
> 2. Follow PLL Disable Sequence. This moves powerdown to the Disable
>    state and disables the PLL.
> 
> v2: Rename WA function to more descriptive (Jani)
>     For PTL, only port A needs this wa
>     Add helpers to check presence of C10 phy and pll enabling (Imre)
> v3: Rename wa function (Imre)
>     Check return value of C10 pll tables readout (Imre)
>     Use PLL request to check pll enabling (Imre)
> v4: Move intel_cx0_pll_is_enabled() right after
>     intel_cx0_pll_disable() (Imre)
>     Add drm_WARN_ON() if C10 state cannot be calculated from
>     the tables (Imre)
> v5: Add debug message on PLL enabling (Imre)
>     Add check for intel_encoder_is_dig_port() (Imre)
> 
> Signed-off-by: Mika Kahola <mika.kah...@intel.com>

Reviewed-by: Imre Deak <imre.d...@intel.com>

> ---
>  drivers/gpu/drm/i915/display/intel_cx0_phy.c  | 61 +++++++++++++++++++
>  drivers/gpu/drm/i915/display/intel_cx0_phy.h  |  1 +
>  .../drm/i915/display/intel_display_reset.c    |  2 +
>  drivers/gpu/drm/i915/display/intel_dpll_mgr.c |  3 +
>  4 files changed, 67 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c 
> b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
> index 8d6fd3f1ac13..22595766eac5 100644
> --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c
> +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
> @@ -3294,6 +3294,16 @@ static void intel_cx0pll_disable(struct intel_encoder 
> *encoder)
>       intel_cx0_phy_transaction_end(encoder, wakeref);
>  }
>  
> +static bool intel_cx0_pll_is_enabled(struct intel_encoder *encoder)
> +{
> +     struct intel_display *display = to_intel_display(encoder);
> +     struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> +     u8 lane = dig_port->lane_reversal ? INTEL_CX0_LANE1 : INTEL_CX0_LANE0;
> +
> +     return intel_de_read(display, XELPDP_PORT_CLOCK_CTL(display, 
> encoder->port)) &
> +                          intel_cx0_get_pclk_pll_request(lane);
> +}
> +
>  static void intel_mtl_tbt_pll_disable(struct intel_encoder *encoder)
>  {
>       struct intel_display *display = to_intel_display(encoder);
> @@ -3555,3 +3565,54 @@ void intel_cx0pll_state_verify(struct 
> intel_atomic_state *state,
>       else
>               intel_c20pll_state_verify(new_crtc_state, crtc, encoder, 
> &mpll_hw_state.c20);
>  }
> +
> +/*
> + * WA 14022081154
> + * The dedicated display PHYs reset to a power state that blocks S0ix, 
> increasing idle
> + * system power. After a system reset (cold boot, S3/4/5, warm reset) if a 
> dedicated
> + * PHY is not being brought up shortly, use these steps to move the PHY to 
> the lowest
> + * power state to save power. For PTL the workaround is needed only for port 
> A. Port B
> + * is not connected.
> + *
> + * 1. Follow the PLL Enable Sequence, using any valid frequency such as DP 
> 1.62 GHz.
> + *    This brings lanes out of reset and enables the PLL to allow powerdown 
> to be moved
> + *    to the Disable state.
> + * 2. Follow PLL Disable Sequence. This moves powerdown to the Disable state 
> and disables the PLL.
> + */
> +void intel_cx0_pll_power_save_wa(struct intel_display *display)
> +{
> +     struct intel_encoder *encoder;
> +
> +     if (DISPLAY_VER(display) != 30)
> +             return;
> +
> +     for_each_intel_encoder(display->drm, encoder) {
> +             struct intel_cx0pll_state pll_state = {};
> +             int port_clock = 162000;
> +
> +             if (!intel_encoder_is_dig_port(encoder))
> +                     continue;
> +
> +             if (!intel_encoder_is_c10phy(encoder))
> +                     continue;
> +
> +             if (intel_cx0_pll_is_enabled(encoder))
> +                     continue;
> +
> +             if (intel_c10pll_calc_state_from_table(encoder,
> +                                                    mtl_c10_edp_tables,
> +                                                    true, port_clock,
> +                                                    &pll_state) < 0) {
> +                     drm_WARN_ON(display->drm,
> +                                 "Unable to calc C10 state from the 
> tables\n");
> +                     continue;
> +             }
> +
> +             drm_dbg_kms(display->drm,
> +                         "[ENCODER:%d:%s] Applying power saving workaround 
> on disabled PLL\n",
> +                         encoder->base.base.id, encoder->base.name);
> +
> +             __intel_cx0pll_enable(encoder, &pll_state, true, port_clock, 4);
> +             intel_cx0pll_disable(encoder);
> +     }
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h 
> b/drivers/gpu/drm/i915/display/intel_cx0_phy.h
> index 573fa7d3e88f..a8f811ca5e7b 100644
> --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h
> +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h
> @@ -42,5 +42,6 @@ bool intel_cx0pll_compare_hw_state(const struct 
> intel_cx0pll_state *a,
>  void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder,
>                                    const struct intel_crtc_state *crtc_state);
>  int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder);
> +void intel_cx0_pll_power_save_wa(struct intel_display *display);
>  
>  #endif /* __INTEL_CX0_PHY_H__ */
> diff --git a/drivers/gpu/drm/i915/display/intel_display_reset.c 
> b/drivers/gpu/drm/i915/display/intel_display_reset.c
> index 093b386c95e8..a690968885bf 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_reset.c
> +++ b/drivers/gpu/drm/i915/display/intel_display_reset.c
> @@ -7,6 +7,7 @@
>  
>  #include "i915_drv.h"
>  #include "intel_clock_gating.h"
> +#include "intel_cx0_phy.h"
>  #include "intel_display_driver.h"
>  #include "intel_display_reset.h"
>  #include "intel_display_types.h"
> @@ -116,6 +117,7 @@ void intel_display_reset_finish(struct drm_i915_private 
> *i915)
>               intel_pps_unlock_regs_wa(display);
>               intel_display_driver_init_hw(display);
>               intel_clock_gating_init(i915);
> +             intel_cx0_pll_power_save_wa(display);
>               intel_hpd_init(i915);
>  
>               ret = __intel_display_driver_resume(display, state, ctx);
> diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c 
> b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
> index eb3df25a308c..c825a507b905 100644
> --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
> +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
> @@ -27,6 +27,7 @@
>  #include "bxt_dpio_phy_regs.h"
>  #include "i915_drv.h"
>  #include "i915_reg.h"
> +#include "intel_cx0_phy.h"
>  #include "intel_de.h"
>  #include "intel_display_types.h"
>  #include "intel_dkl_phy.h"
> @@ -4571,6 +4572,8 @@ void intel_dpll_sanitize_state(struct intel_display 
> *display)
>       struct intel_shared_dpll *pll;
>       int i;
>  
> +     intel_cx0_pll_power_save_wa(display);
> +
>       for_each_shared_dpll(display, pll, i)
>               sanitize_dpll_state(display, pll);
>  }
> -- 
> 2.43.0
> 

Reply via email to