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);
        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);
+       }
+}
 
 
 #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"
                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);