@@ -3559,3 +3559,48 @@ void intel_cx0pll_state_verify(struct intel_atomic_state *state,
else
intel_c20pll_state_verify(new_crtc_state, crtc, encoder, &mpll_hw_state.c20);
}
+
+static bool intel_cx0_pll_is_enabled(struct intel_display *display, enum port port)
+{
+ u32 val = intel_de_read(display, XELPDP_PORT_CLOCK_CTL(display, port));
+
+ if (REG_FIELD_GET(XELPDP_DDI_CLOCK_SELECT_MASK, val) == XELPDP_DDI_CLOCK_SELECT_NONE)
+ return false;
+
+ return true;
+}
+/*
+ * 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 ptl_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_c10phy(encoder))
+ continue;
+
+ if (intel_cx0_pll_is_enabled(display, encoder->port))
+ continue;
+
+ intel_c10pll_calc_state_from_table(encoder, mtl_c10_edp_tables, port_clock, true, &pll_state);
+ __intel_cx0pll_enable(encoder, &pll_state, true, port_clock, 4);
+ intel_cx0pll_disable(encoder);
+ }
+}
@@ -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 ptl_power_save_wa(struct intel_display *display);
#endif /* __INTEL_CX0_PHY_H__ */
@@ -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);
+ ptl_power_save_wa(display);
intel_hpd_init(i915);
ret = __intel_display_driver_resume(display, state, ctx);
@@ -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"
@@ -4552,6 +4553,7 @@ static void sanitize_dpll_state(struct drm_i915_private *i915,
return;
adlp_cmtg_clock_gating_wa(i915, pll);
+ ptl_power_save_wa(&i915->display);
if (pll->active_mask)
return;
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) Signed-off-by: Mika Kahola <mika.kahola@intel.com> --- drivers/gpu/drm/i915/display/intel_cx0_phy.c | 45 +++++++++++++++++++ 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 | 2 + 4 files changed, 50 insertions(+)