#include <drm/drm_print.h>
#include "i915_reg.h"
+#include "i915_utils.h"
#include "intel_cx0_phy.h"
#include "intel_cx0_phy_regs.h"
#include "intel_de.h"
#include "intel_hdmi.h"
#include "intel_lt_phy.h"
#include "intel_lt_phy_regs.h"
+#include "intel_psr.h"
#include "intel_tc.h"
#define INTEL_LT_PHY_LANE0 BIT(0)
#define INTEL_LT_PHY_LANE1 BIT(1)
#define INTEL_LT_PHY_BOTH_LANES (INTEL_LT_PHY_LANE1 |\
INTEL_LT_PHY_LANE0)
+#define MODE_DP 3
static u8 intel_lt_phy_get_owned_lane_mask(struct intel_encoder *encoder)
{
? INTEL_LT_PHY_BOTH_LANES : INTEL_LT_PHY_LANE0;
}
+static u8 intel_lt_phy_read(struct intel_encoder *encoder, u8 lane_mask, u16 addr)
+{
+ return intel_cx0_read(encoder, lane_mask, addr);
+}
+
static void
intel_lt_phy_setup_powerdown(struct intel_encoder *encoder, u8 lane_count)
{
XELPDP_SSC_ENABLE_PLLB, val);
}
+static u32 intel_lt_phy_get_dp_clock(u8 rate)
+{
+ switch (rate) {
+ case 0:
+ return 162000;
+ case 1:
+ return 270000;
+ case 2:
+ return 540000;
+ case 3:
+ return 810000;
+ case 4:
+ return 216000;
+ case 5:
+ return 243000;
+ case 6:
+ return 324000;
+ case 7:
+ return 432000;
+ case 8:
+ return 1000000;
+ case 9:
+ return 1350000;
+ case 10:
+ return 2000000;
+ case 11:
+ return 675000;
+ default:
+ MISSING_CASE(rate);
+ return 0;
+ }
+}
+
+static bool
+intel_lt_phy_config_changed(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ u8 val, rate;
+ u32 clock;
+
+ val = intel_lt_phy_read(encoder, INTEL_LT_PHY_LANE0,
+ LT_PHY_VDR_0_CONFIG);
+ rate = REG_FIELD_GET8(LT_PHY_VDR_RATE_ENCODING_MASK, val);
+
+ /*
+ * The only time we do not reconfigure the PLL is when we are
+ * using 1.62 Gbps clock since PHY PLL defaults to that
+ * otherwise we always need to reconfigure it.
+ */
+ if (intel_crtc_has_dp_encoder(crtc_state)) {
+ clock = intel_lt_phy_get_dp_clock(rate);
+ if (crtc_state->port_clock == 1620000 && crtc_state->port_clock == clock)
+ return false;
+ }
+
+ return true;
+}
+
+static intel_wakeref_t intel_lt_phy_transaction_begin(struct intel_encoder *encoder)
+{
+ struct intel_display *display = to_intel_display(encoder);
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ intel_wakeref_t wakeref;
+
+ intel_psr_pause(intel_dp);
+ wakeref = intel_display_power_get(display, POWER_DOMAIN_DC_OFF);
+
+ return wakeref;
+}
+
+static void intel_lt_phy_transaction_end(struct intel_encoder *encoder, intel_wakeref_t wakeref)
+{
+ struct intel_display *display = to_intel_display(encoder);
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+ intel_psr_resume(intel_dp);
+ intel_display_power_put(display, POWER_DOMAIN_DC_OFF, wakeref);
+}
+
void intel_lt_phy_pll_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
+ struct intel_display *display = to_intel_display(encoder);
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
bool lane_reversal = dig_port->lane_reversal;
u8 owned_lane_mask = intel_lt_phy_get_owned_lane_mask(encoder);
+ intel_wakeref_t wakeref = 0;
+
+ wakeref = intel_lt_phy_transaction_begin(encoder);
/* 1. Enable MacCLK at default 162 MHz frequency. */
intel_lt_phy_lane_reset(encoder, crtc_state->lane_count);
* 4. Read the PHY message bus VDR register PHY_VDR_0_Config check enabled PLL type,
* encoded rate and encoded mode.
*/
- /*
- * 5. Program the PHY internal PLL registers over PHY message bus for the desired
- * frequency and protocol type
- */
- /* 6. Use the P2P transaction flow */
- /*
- * 6.1. Set the PHY VDR register 0xCC4[Rate Control VDR Update] = 1 over PHY message
- * bus for Owned PHY Lanes.
- */
- /*
- * 6.2. Poll for P2P Transaction Ready = "1" and read the MAC message bus VDR register
- * at offset 0xC00 for Owned PHY Lanes.
- */
- /* 6.3. Clear P2P transaction Ready bit. */
- /* 7. Program PORT_CLOCK_CTL[PCLK PLL Request LN0] = 0. */
- /* 8. Poll for PORT_CLOCK_CTL[PCLK PLL Ack LN0]= 0. */
- /*
- * 9. Follow the Display Voltage Frequency Switching - Sequence Before Frequency Change.
- * We handle this step in bxt_set_cdclk()
- */
- /* 10. Program DDI_CLK_VALFREQ to match intended DDI clock frequency. */
- /* 11. Program PORT_CLOCK_CTL[PCLK PLL Request LN0] = 1. */
- /* 12. Poll for PORT_CLOCK_CTL[PCLK PLL Ack LN0]= 1. */
+ if (intel_lt_phy_config_changed(encoder, crtc_state)) {
+ /*
+ * 5. Program the PHY internal PLL registers over PHY message bus for the desired
+ * frequency and protocol type
+ */
+ /* 6. Use the P2P transaction flow */
+ /*
+ * 6.1. Set the PHY VDR register 0xCC4[Rate Control VDR Update] = 1 over PHY message
+ * bus for Owned PHY Lanes.
+ */
+ /*
+ * 6.2. Poll for P2P Transaction Ready = "1" and read the MAC message bus VDR
+ * register at offset 0xC00 for Owned PHY Lanes*.
+ */
+ /* 6.3. Clear P2P transaction Ready bit. */
+ /* 7. Program PORT_CLOCK_CTL[PCLK PLL Request LN0] = 0. */
+ /* 8. Poll for PORT_CLOCK_CTL[PCLK PLL Ack LN0]= 0. */
+ /*
+ * 9. Follow the Display Voltage Frequency Switching - Sequence Before Frequency
+ * Change. We handle this step in bxt_set_cdclk().
+ */
+ /* 10. Program DDI_CLK_VALFREQ to match intended DDI clock frequency. */
+ /* 11. Program PORT_CLOCK_CTL[PCLK PLL Request LN0] = 1. */
+ /* 12. Poll for PORT_CLOCK_CTL[PCLK PLL Ack LN0]= 1. */
+ } else {
+ intel_de_write(display, DDI_CLK_VALFREQ(encoder->port), crtc_state->port_clock);
+ }
+
/* 13. Ungate the forward clock by setting PORT_CLOCK_CTL[Forward Clock Ungate] = 1. */
/* 14. SW clears PORT_BUF_CTL2 [PHY Pulse Status]. */
/*
* We handle this step in bxt_set_cdclk()
*/
/* 19. Move the PHY powerdown state to Active and program to enable/disable transmitters */
+
+ intel_lt_phy_transaction_end(encoder, wakeref);
}