diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_cx0_phy.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_cx0_phy.c | 61 |
1 files changed, 61 insertions, 0 deletions
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); + } +} |
