Skip to content

Commit bf85319

Browse files
committed
drm/i915/display: Allow display PHYs to reset power state
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.kahola@intel.com> Reviewed-by: Imre Deak <imre.deak@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20250218100019.740556-3-mika.kahola@intel.com
1 parent a4ed5f3 commit bf85319

File tree

4 files changed

+67
-0
lines changed

4 files changed

+67
-0
lines changed

drivers/gpu/drm/i915/display/intel_cx0_phy.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3294,6 +3294,16 @@ static void intel_cx0pll_disable(struct intel_encoder *encoder)
32943294
intel_cx0_phy_transaction_end(encoder, wakeref);
32953295
}
32963296

3297+
static bool intel_cx0_pll_is_enabled(struct intel_encoder *encoder)
3298+
{
3299+
struct intel_display *display = to_intel_display(encoder);
3300+
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
3301+
u8 lane = dig_port->lane_reversal ? INTEL_CX0_LANE1 : INTEL_CX0_LANE0;
3302+
3303+
return intel_de_read(display, XELPDP_PORT_CLOCK_CTL(display, encoder->port)) &
3304+
intel_cx0_get_pclk_pll_request(lane);
3305+
}
3306+
32973307
static void intel_mtl_tbt_pll_disable(struct intel_encoder *encoder)
32983308
{
32993309
struct intel_display *display = to_intel_display(encoder);
@@ -3555,3 +3565,54 @@ void intel_cx0pll_state_verify(struct intel_atomic_state *state,
35553565
else
35563566
intel_c20pll_state_verify(new_crtc_state, crtc, encoder, &mpll_hw_state.c20);
35573567
}
3568+
3569+
/*
3570+
* WA 14022081154
3571+
* The dedicated display PHYs reset to a power state that blocks S0ix, increasing idle
3572+
* system power. After a system reset (cold boot, S3/4/5, warm reset) if a dedicated
3573+
* PHY is not being brought up shortly, use these steps to move the PHY to the lowest
3574+
* power state to save power. For PTL the workaround is needed only for port A. Port B
3575+
* is not connected.
3576+
*
3577+
* 1. Follow the PLL Enable Sequence, using any valid frequency such as DP 1.62 GHz.
3578+
* This brings lanes out of reset and enables the PLL to allow powerdown to be moved
3579+
* to the Disable state.
3580+
* 2. Follow PLL Disable Sequence. This moves powerdown to the Disable state and disables the PLL.
3581+
*/
3582+
void intel_cx0_pll_power_save_wa(struct intel_display *display)
3583+
{
3584+
struct intel_encoder *encoder;
3585+
3586+
if (DISPLAY_VER(display) != 30)
3587+
return;
3588+
3589+
for_each_intel_encoder(display->drm, encoder) {
3590+
struct intel_cx0pll_state pll_state = {};
3591+
int port_clock = 162000;
3592+
3593+
if (!intel_encoder_is_dig_port(encoder))
3594+
continue;
3595+
3596+
if (!intel_encoder_is_c10phy(encoder))
3597+
continue;
3598+
3599+
if (intel_cx0_pll_is_enabled(encoder))
3600+
continue;
3601+
3602+
if (intel_c10pll_calc_state_from_table(encoder,
3603+
mtl_c10_edp_tables,
3604+
true, port_clock,
3605+
&pll_state) < 0) {
3606+
drm_WARN_ON(display->drm,
3607+
"Unable to calc C10 state from the tables\n");
3608+
continue;
3609+
}
3610+
3611+
drm_dbg_kms(display->drm,
3612+
"[ENCODER:%d:%s] Applying power saving workaround on disabled PLL\n",
3613+
encoder->base.base.id, encoder->base.name);
3614+
3615+
__intel_cx0pll_enable(encoder, &pll_state, true, port_clock, 4);
3616+
intel_cx0pll_disable(encoder);
3617+
}
3618+
}

drivers/gpu/drm/i915/display/intel_cx0_phy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,6 @@ bool intel_cx0pll_compare_hw_state(const struct intel_cx0pll_state *a,
4242
void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder,
4343
const struct intel_crtc_state *crtc_state);
4444
int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder);
45+
void intel_cx0_pll_power_save_wa(struct intel_display *display);
4546

4647
#endif /* __INTEL_CX0_PHY_H__ */

drivers/gpu/drm/i915/display/intel_display_reset.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "i915_drv.h"
99
#include "intel_clock_gating.h"
10+
#include "intel_cx0_phy.h"
1011
#include "intel_display_driver.h"
1112
#include "intel_display_reset.h"
1213
#include "intel_display_types.h"
@@ -116,6 +117,7 @@ void intel_display_reset_finish(struct drm_i915_private *i915)
116117
intel_pps_unlock_regs_wa(display);
117118
intel_display_driver_init_hw(display);
118119
intel_clock_gating_init(i915);
120+
intel_cx0_pll_power_save_wa(display);
119121
intel_hpd_init(i915);
120122

121123
ret = __intel_display_driver_resume(display, state, ctx);

drivers/gpu/drm/i915/display/intel_dpll_mgr.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "bxt_dpio_phy_regs.h"
2828
#include "i915_drv.h"
2929
#include "i915_reg.h"
30+
#include "intel_cx0_phy.h"
3031
#include "intel_de.h"
3132
#include "intel_display_types.h"
3233
#include "intel_dkl_phy.h"
@@ -4571,6 +4572,8 @@ void intel_dpll_sanitize_state(struct intel_display *display)
45714572
struct intel_shared_dpll *pll;
45724573
int i;
45734574

4575+
intel_cx0_pll_power_save_wa(display);
4576+
45744577
for_each_shared_dpll(display, pll, i)
45754578
sanitize_dpll_state(display, pll);
45764579
}

0 commit comments

Comments
 (0)