> -----Original Message----- > From: Jani Nikula <jani.nikula@xxxxxxxxxxxxxxx> > Sent: Friday, September 30, 2022 12:32 PM > To: Kahola, Mika <mika.kahola@xxxxxxxxx>; intel-gfx@xxxxxxxxxxxxxxxxxxxxx > Subject: Re: [PATCH 3/5] drm/i915/mtl: Add support for C10 phy > programming > > On Thu, 29 Sep 2022, Mika Kahola <mika.kahola@xxxxxxxxx> wrote: > > From: Radhakrishna Sripada <radhakrishna.sripada@xxxxxxxxx> > > > > Add sequences for C10 phy enable/disable phy lane reset, powerdown > > change sequence and phy lane programming. > > > > Bspec: 64539, 67636, 65451, 65450, 64568 > > > > Cc: Imre Deak <imre.deak@xxxxxxxxx> > > Cc: Mika Kahola <mika.kahola@xxxxxxxxx> > > Cc: Uma Shankar <uma.shankar@xxxxxxxxx> > > Signed-off-by: Radhakrishna Sripada <radhakrishna.sripada@xxxxxxxxx> > > Signed-off-by: Mika Kahola <mika.kahola@xxxxxxxxx> (v9) > > --- > > drivers/gpu/drm/i915/Makefile | 1 + > > drivers/gpu/drm/i915/display/intel_cx0_phy.c | 352 > > ++++++++++++++++++- drivers/gpu/drm/i915/display/intel_cx0_phy.h | 17 + > > drivers/gpu/drm/i915/display/intel_ddi.c | 2 + > > drivers/gpu/drm/i915/display/intel_dp.c | 15 +- > > drivers/gpu/drm/i915/display/intel_dpll.c | 2 + > > drivers/gpu/drm/i915/i915_reg.h | 141 ++++++++ > > 7 files changed, 526 insertions(+), 4 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/Makefile > > b/drivers/gpu/drm/i915/Makefile index a26edcdadc21..994f87a12782 > > 100644 > > --- a/drivers/gpu/drm/i915/Makefile > > +++ b/drivers/gpu/drm/i915/Makefile > > @@ -279,6 +279,7 @@ i915-y += \ > > display/icl_dsi.o \ > > display/intel_backlight.o \ > > display/intel_crt.o \ > > + display/intel_cx0_phy.o \ > > This belongs where intel_cx0_phy.c is added. > > > display/intel_ddi.o \ > > display/intel_ddi_buf_trans.o \ > > display/intel_display_trace.o \ > > diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c > > b/drivers/gpu/drm/i915/display/intel_cx0_phy.c > > index 2f401116d1d0..6ba11cd7cd75 100644 > > --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c > > +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c > > @@ -526,9 +526,9 @@ void intel_c10mpllb_readout_hw_state(struct > intel_encoder *encoder, > > tx0, cmn, phy_name(phy)); > > } > > > > -__maybe_unused static void intel_c10_pll_program(struct drm_i915_private > *i915, > > - const struct intel_crtc_state > *crtc_state, > > - struct intel_encoder > *encoder) > > +static void intel_c10_pll_program(struct drm_i915_private *i915, > > + const struct intel_crtc_state *crtc_state, > > + struct intel_encoder *encoder) > > { > > const struct intel_c10mpllb_state *pll_state = &crtc_state- > >c10mpllb_state; > > struct intel_digital_port *dig_port = enc_to_dig_port(encoder); @@ > > -633,6 +633,352 @@ int intel_c10mpllb_calc_port_clock(struct intel_encoder > *encoder, > > 10 << (tx_clk_div + 16)); > > } > > > > +#define PHY_LANES_VAL_ARG(FIELD, lanes, arg) ({u32 __val; > switch(lanes) {\ > > + case > INTEL_CX0_BOTH_LANES: \ > > + __val = > ((XELPDP_LANE0_##FIELD(arg)) |\ > > + > (XELPDP_LANE1_##FIELD(arg))); \ > > + break; > \ > > + case INTEL_CX0_LANE0: > \ > > + __val = > (XELPDP_LANE0_##FIELD(arg));\ > > + break; > \ > > + case INTEL_CX0_LANE1: > \ > > + __val = > (XELPDP_LANE1_##FIELD(arg));\ > > + break; \ > > + }; __val; }) > > + > > +#define PHY_LANES_VAL(FIELD, lanes) ({u32 __val; switch(lanes) {\ > > + case > INTEL_CX0_BOTH_LANES: \ > > + __val = > (XELPDP_LANE0_##FIELD | \ > > + > XELPDP_LANE1_##FIELD); \ > > + break; > \ > > + case INTEL_CX0_LANE0: > \ > > + __val = > (XELPDP_LANE0_##FIELD); \ > > + break; > \ > > + case INTEL_CX0_LANE1: > \ > > + __val = > (XELPDP_LANE1_##FIELD);\ > > + break; \ > > + }; __val; }) > > Ugh that's ugly. I'll try to look the other way. > > > + > > +static void intel_program_port_clock_ctl(struct intel_encoder *encoder, > > + const struct intel_crtc_state > *crtc_state, > > + bool lane_reversal) > > +{ > > + struct drm_i915_private *i915 = to_i915(encoder->base.dev); > > + struct intel_dp *intel_dp; > > + bool ssc_enabled; > > + u32 val = 0; > > + > > + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL1(encoder->port), > XELPDP_PORT_REVERSAL, > > + lane_reversal ? XELPDP_PORT_REVERSAL : 0); > > + > > + if (lane_reversal) > > + val |= XELPDP_LANE1_PHY_CLOCK_SELECT; > > + > > + val |= XELPDP_FORWARD_CLOCK_UNGATE; > > + val |= > XELPDP_DDI_CLOCK_SELECT(XELPDP_DDI_CLOCK_SELECT_MAXPCLK); > > + > > + if (intel_crtc_has_dp_encoder(crtc_state)) { > > + intel_dp = enc_to_intel_dp(encoder); > > + ssc_enabled = intel_dp->dpcd[DP_MAX_DOWNSPREAD] & > > + DP_MAX_DOWNSPREAD_0_5; > > It is almost certainly the wrong thing to do to look at sink DPCD register values > at the low level PHY code. Smells like something that should be added to crtc > state. > > > + > > + /* TODO: DP2.0 10G and 20G rates enable MPLLA*/ > > + val |= ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0; > > + } > > + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), > > + XELPDP_LANE1_PHY_CLOCK_SELECT | > > + XELPDP_FORWARD_CLOCK_UNGATE | > > + XELPDP_DDI_CLOCK_SELECT_MASK | > > + XELPDP_SSC_ENABLE_PLLB, val); > > +} > > + > > +static void intel_cx0_powerdown_change_sequence(struct drm_i915_private > *i915, > > + enum port port, > > + enum intel_cx0_lanes lane, u8 > state) { > > + enum phy phy = intel_port_to_phy(i915, port); > > + > > + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), > > + PHY_LANES_VAL(POWERDOWN_NEW_STATE_MASK, lane), > > + PHY_LANES_VAL_ARG(POWERDOWN_NEW_STATE, lane, > state)); > > + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), > > + PHY_LANES_VAL(POWERDOWN_UPDATE, lane), > > + PHY_LANES_VAL(POWERDOWN_UPDATE, lane)); > > + > > + /* Update Timeout Value */ > > + if (__intel_wait_for_register(&i915->uncore, > XELPDP_PORT_BUF_CTL2(port), > > + PHY_LANES_VAL(POWERDOWN_UPDATE, > lane), 0, > > + > XELPDP_PORT_RESET_START_TIMEOUT_US, 0, NULL)) > > + drm_warn(&i915->drm, "PHY %c failed to bring out of Lane > reset after %dus.\n", > > + phy_name(phy), > XELPDP_PORT_RESET_START_TIMEOUT_US); > > +} > > + > > +static void intel_cx0_setup_powerdown(struct drm_i915_private *i915, > > +enum port port) { > > + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), > > + XELPDP_POWER_STATE_READY_MASK, > > + XELPDP_POWER_STATE_READY(CX0_P2_STATE_READY)); > > + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL3(port), > > + XELPDP_POWER_STATE_ACTIVE_MASK | > > + XELPDP_PLL_LANE_STAGGERING_DELAY_MASK, > > + XELPDP_POWER_STATE_ACTIVE(CX0_P0_STATE_ACTIVE) | > > + XELPDP_PLL_LANE_STAGGERING_DELAY(0)); > > +} > > + > > +/* FIXME: Some Type-C cases need not reset both the lanes. Handle > > +those cases. */ static void intel_cx0_phy_lane_reset(struct drm_i915_private > *i915, enum port port, > > + bool lane_reversal) > > +{ > > + enum phy phy = intel_port_to_phy(i915, port); > > + enum intel_cx0_lanes lane = lane_reversal ? INTEL_CX0_LANE1 : > > + INTEL_CX0_LANE0; > > + > > + if (__intel_wait_for_register(&i915->uncore, > XELPDP_PORT_BUF_CTL1(port), > > + XELPDP_PORT_BUF_SOC_PHY_READY, > > + XELPDP_PORT_BUF_SOC_PHY_READY, > > + > XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US, 0, NULL)) > > + drm_warn(&i915->drm, "PHY %c failed to bring out of SOC reset > after %dus.\n", > > + phy_name(phy), > XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US); > > + > > + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), > > + PHY_LANES_VAL(PIPE_RESET, INTEL_CX0_BOTH_LANES), > > + PHY_LANES_VAL(PIPE_RESET, INTEL_CX0_BOTH_LANES)); > > + > > + if (__intel_wait_for_register(&i915->uncore, > XELPDP_PORT_BUF_CTL2(port), > > + PHY_LANES_VAL(PHY_CURRENT_STATUS, > INTEL_CX0_BOTH_LANES), > > + PHY_LANES_VAL(PHY_CURRENT_STATUS, > INTEL_CX0_BOTH_LANES), > > + > XELPDP_PORT_RESET_START_TIMEOUT_US, 0, NULL)) > > + drm_warn(&i915->drm, "PHY %c failed to bring out of Lane > reset after %dus.\n", > > + phy_name(phy), > XELPDP_PORT_RESET_START_TIMEOUT_US); > > + > > + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(port), > > + PHY_LANES_VAL(PCLK_REFCLK_REQUEST, lane), > > + PHY_LANES_VAL(PCLK_REFCLK_REQUEST, lane)); > > + > > + if (__intel_wait_for_register(&i915->uncore, > XELPDP_PORT_CLOCK_CTL(port), > > + PHY_LANES_VAL(PCLK_REFCLK_ACK, lane), > > + PHY_LANES_VAL(PCLK_REFCLK_ACK, lane), > > + XELPDP_REFCLK_ENABLE_TIMEOUT_US, 0, > NULL)) > > + drm_warn(&i915->drm, "PHY %c failed to request refclk after > %dus.\n", > > + phy_name(phy), > XELPDP_REFCLK_ENABLE_TIMEOUT_US); > > + > > + intel_cx0_powerdown_change_sequence(i915, port, > INTEL_CX0_BOTH_LANES, > > + CX0_P2_STATE_RESET); > > + intel_cx0_setup_powerdown(i915, port); > > + > > + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), > > + PHY_LANES_VAL(PIPE_RESET, INTEL_CX0_BOTH_LANES), 0); > > + > > + if (intel_de_wait_for_clear(i915, XELPDP_PORT_BUF_CTL2(port), > > + PHY_LANES_VAL(PHY_CURRENT_STATUS, > > + INTEL_CX0_BOTH_LANES), > > + XELPDP_PORT_RESET_END_TIMEOUT)) > > + drm_warn(&i915->drm, "PHY %c failed to bring out of Lane > reset after %dms.\n", > > + phy_name(phy), > XELPDP_PORT_RESET_END_TIMEOUT); } > > + > > +static void intel_c10_program_phy_lane(struct drm_i915_private *i915, > > + enum port port, int lane_count, > > + bool lane_reversal) > > +{ > > + u8 l0t1, l0t2, l1t1, l1t2; > > + > > + intel_cx0_rmw(i915, port, INTEL_CX0_BOTH_LANES, > PHY_C10_VDR_CONTROL(1), > > + C10_VDR_CTRL_MSGBUS_ACCESS, > C10_VDR_CTRL_MSGBUS_ACCESS, > > + MB_WRITE_COMMITTED); > > + > > + l0t1 = intel_cx0_read(i915, port, 0, PHY_CX0_TX_CONTROL(1, 2)); > > + l0t2 = intel_cx0_read(i915, port, 0, PHY_CX0_TX_CONTROL(2, 2)); > > + l1t1 = intel_cx0_read(i915, port, 1, PHY_CX0_TX_CONTROL(1, 2)); > > + l1t2 = intel_cx0_read(i915, port, 1, PHY_CX0_TX_CONTROL(2, 2)); > > + > > + if (lane_reversal) { > > + switch (lane_count) { > > + case 1: > > + /* Disable MLs 1(lane0), 2(lane0), 3(lane1) */ > > + intel_cx0_write(i915, port, 1, > PHY_CX0_TX_CONTROL(1, 2), > > + l1t1 | > CONTROL2_DISABLE_SINGLE_TX, > > + MB_WRITE_COMMITTED); > > + fallthrough; > > + case 2: > > + /* Disable MLs 1(lane0), 2(lane0) */ > > + intel_cx0_write(i915, port, 0, > PHY_CX0_TX_CONTROL(2, 2), > > + l0t2 | > CONTROL2_DISABLE_SINGLE_TX, > > + MB_WRITE_COMMITTED); > > + fallthrough; > > + case 3: > > + /* Disable MLs 1(lane0) */ > > + intel_cx0_write(i915, port, 0, > PHY_CX0_TX_CONTROL(1, 2), > > + l0t1 | > CONTROL2_DISABLE_SINGLE_TX, > > + MB_WRITE_COMMITTED); > > + break; > > + } > > + } else { > > + switch (lane_count) { > > + case 1: > > + /* Disable MLs 2(lane0), 3(lane1), 4(lane1) */ > > + intel_cx0_write(i915, port, 0, > PHY_CX0_TX_CONTROL(2, 2), > > + l0t2 | > CONTROL2_DISABLE_SINGLE_TX, > > + MB_WRITE_COMMITTED); > > + fallthrough; > > + case 2: > > + /* Disable MLs 3(lane1), 4(lane1) */ > > + intel_cx0_write(i915, port, 1, > PHY_CX0_TX_CONTROL(1, 2), > > + l1t1 | > CONTROL2_DISABLE_SINGLE_TX, > > + MB_WRITE_COMMITTED); > > + fallthrough; > > + case 3: > > + /* Disable MLs 4(lane1) */ > > + intel_cx0_write(i915, port, 1, > PHY_CX0_TX_CONTROL(2, 2), > > + l1t2 | > CONTROL2_DISABLE_SINGLE_TX, > > + MB_WRITE_COMMITTED); > > + break; > > + } > > + } > > + > > + intel_cx0_rmw(i915, port, INTEL_CX0_BOTH_LANES, > PHY_C10_VDR_CONTROL(1), > > + C10_VDR_CTRL_UPDATE_CFG, > C10_VDR_CTRL_UPDATE_CFG, > > +MB_WRITE_COMMITTED); } > > + > > +static void intel_c10pll_enable(struct intel_encoder *encoder, > > + const struct intel_crtc_state *crtc_state) { > > + struct drm_i915_private *i915 = to_i915(encoder->base.dev); > > + enum phy phy = intel_port_to_phy(i915, encoder->port); > > + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); > > + bool lane_reversal = dig_port->saved_port_bits & > DDI_BUF_PORT_REVERSAL; > > + enum intel_cx0_lanes maxpclk_lane = lane_reversal ? > INTEL_CX0_LANE1 : > > + INTEL_CX0_LANE0; > > + > > + /* > > + * 1. Program PORT_CLOCK_CTL REGISTER to configure > > + * clock muxes, gating and SSC > > + */ > > + intel_program_port_clock_ctl(encoder, crtc_state, lane_reversal); > > + > > + /* 2. Bring PHY out of reset. */ > > + intel_cx0_phy_lane_reset(i915, encoder->port, lane_reversal); > > + > > + /* > > + * 3. Change Phy power state to Ready. > > + * TODO: For DP alt mode use only one lane. > > + */ > > + intel_cx0_powerdown_change_sequence(i915, encoder->port, > INTEL_CX0_BOTH_LANES, > > + CX0_P2_STATE_READY); > > + > > + /* 4. Program PHY internal PLL internal registers. */ > > + intel_c10_pll_program(i915, crtc_state, encoder); > > + > > + /* > > + * 5. Program the enabled and disabled owned PHY lane > > + * transmitters over message bus > > + */ > > + intel_c10_program_phy_lane(i915, encoder->port, > > +crtc_state->lane_count, lane_reversal); > > + > > + /* > > + * 6. Follow the Display Voltage Frequency Switching - Sequence > > + * Before Frequency Change. We handle this step in bxt_set_cdclk(). > > + */ > > + > > + /* > > + * 7. Program DDI_CLK_VALFREQ to match intended DDI > > + * clock frequency. > > + */ > > + intel_de_write(i915, DDI_CLK_VALFREQ(encoder->port), > > + crtc_state->port_clock); > > + /* > > + * 8. Set PORT_CLOCK_CTL register PCLK PLL Request > > + * LN<Lane for maxPCLK> to "1" to enable PLL. > > + */ > > + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), 0, > > + PHY_LANES_VAL(PCLK_PLL_REQUEST, maxpclk_lane)); > > + > > + /* 9. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN<Lane for maxPCLK> == > "1". */ > > + if (__intel_wait_for_register(&i915->uncore, > XELPDP_PORT_CLOCK_CTL(encoder->port), > > + PHY_LANES_VAL(PCLK_PLL_ACK, > maxpclk_lane), > > + PHY_LANES_VAL(PCLK_PLL_ACK, > maxpclk_lane), > > + XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US, > 0, NULL)) > > + drm_warn(&i915->drm, "Port %c PLL not locked after %dus.\n", > > + phy_name(phy), > XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US); > > + > > + /* > > + * 10. Follow the Display Voltage Frequency Switching Sequence After > > + * Frequency Change. We handle this step in bxt_set_cdclk(). > > + */ > > +} > > + > > +void intel_cx0pll_enable(struct intel_encoder *encoder, > > + const struct intel_crtc_state *crtc_state) { > > + struct drm_i915_private *i915 = to_i915(encoder->base.dev); > > + enum phy phy = intel_port_to_phy(i915, encoder->port); > > + > > + drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); > > + intel_c10pll_enable(encoder, crtc_state); } > > + > > +static void intel_c10pll_disable(struct intel_encoder *encoder) { > > + struct drm_i915_private *i915 = to_i915(encoder->base.dev); > > + enum phy phy = intel_port_to_phy(i915, encoder->port); > > + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); > > + bool lane_reversal = dig_port->saved_port_bits & > DDI_BUF_PORT_REVERSAL; > > + enum intel_cx0_lanes lane = lane_reversal ? INTEL_CX0_LANE1 : > > + INTEL_CX0_LANE0; > > + > > + /* 1. Change owned PHY lane power to Disable state. */ > > + intel_cx0_powerdown_change_sequence(i915, encoder->port, > INTEL_CX0_BOTH_LANES, > > + CX0_P2PG_STATE_DISABLE); > > + > > + /* > > + * 2. Follow the Display Voltage Frequency Switching Sequence Before > > + * Frequency Change. We handle this step in bxt_set_cdclk(). > > + */ > > + > > + /* > > + * 3. Set PORT_CLOCK_CTL register PCLK PLL Request LN<Lane for > maxPCLK> > > + * to "0" to disable PLL. > > + */ > > + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), > > + PHY_LANES_VAL(PCLK_PLL_REQUEST, > INTEL_CX0_BOTH_LANES) | > > + PHY_LANES_VAL(PCLK_REFCLK_REQUEST, > INTEL_CX0_BOTH_LANES), 0); > > + > > + /* 4. Program DDI_CLK_VALFREQ to 0. */ > > + intel_de_write(i915, DDI_CLK_VALFREQ(encoder->port), 0); > > + > > + /* > > + * 5. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN<Lane for maxPCLK**> > == "0". > > + */ > > + if (__intel_wait_for_register(&i915->uncore, > XELPDP_PORT_CLOCK_CTL(encoder->port), > > + PHY_LANES_VAL(PCLK_PLL_ACK, lane) | > > + PHY_LANES_VAL(PCLK_REFCLK_ACK, lane), > 0, > > + XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US, > 0, NULL)) > > + drm_warn(&i915->drm, "Port %c PLL not unlocked after > %dus.\n", > > + phy_name(phy), > XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US); > > + > > + /* > > + * 6. Follow the Display Voltage Frequency Switching Sequence After > > + * Frequency Change. We handle this step in bxt_set_cdclk(). > > + */ > > + > > + /* 7. Program PORT_CLOCK_CTL register to disable and gate clocks. */ > > + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), > > + XELPDP_DDI_CLOCK_SELECT_MASK | > > + XELPDP_FORWARD_CLOCK_UNGATE, 0); } > > + > > +void intel_cx0pll_disable(struct intel_encoder *encoder) { > > + struct drm_i915_private *i915 = to_i915(encoder->base.dev); > > + enum phy phy = intel_port_to_phy(i915, encoder->port); > > + > > + drm_WARN_ON(&i915->drm, !intel_is_c10phy(i915, phy)); > > + intel_c10pll_disable(encoder); > > +} > > + > > +#undef PHY_LANES_VAL_ARG > > +#undef PHY_LANES_VAL > > + > > void intel_c10mpllb_state_verify(struct intel_atomic_state *state, > > struct intel_crtc_state *new_crtc_state) { diff > --git > > a/drivers/gpu/drm/i915/display/intel_cx0_phy.h > > b/drivers/gpu/drm/i915/display/intel_cx0_phy.h > > index cf1f300b6a7b..d12d2e2f02ee 100644 > > --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h > > +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h > > @@ -106,6 +106,19 @@ enum intel_cx0_lanes { > > #define C10_VDR_CTRL_UPDATE_CFG REG_BIT8(0) > > #define PHY_C10_VDR_CUSTOM_WIDTH 0xD02 > > > > +#define CX0_P0_STATE_ACTIVE 0x0 > > +#define CX0_P2_STATE_READY 0x2 > > +#define CX0_P2PG_STATE_DISABLE 0x9 > > +#define CX0_P4PG_STATE_DISABLE 0xC > > +#define CX0_P2_STATE_RESET 0x2 > > + > > +/* PHY_C10_VDR_PLL0 */ > > +#define PLL_C10_MPLL_SSC_EN REG_BIT8(0) > > + > > +/* PIPE SPEC Defined Registers */ > > +#define PHY_CX0_TX_CONTROL(tx, control) (0x400 + ((tx) - 1) * 0x200 + > (control)) > > +#define CONTROL2_DISABLE_SINGLE_TX REG_BIT(6) > > + > > Again, register definitions don't belong here. Yes, I will move these to a separate file. > > > static inline bool intel_is_c10phy(struct drm_i915_private *dev_priv, > > enum phy phy) { > > if (!IS_METEORLAKE(dev_priv)) > > @@ -114,6 +127,10 @@ static inline bool intel_is_c10phy(struct > drm_i915_private *dev_priv, enum phy p > > return (phy < PHY_C); > > } > > > > +void intel_cx0pll_enable(struct intel_encoder *encoder, > > + const struct intel_crtc_state *crtc_state); void > > +intel_cx0pll_disable(struct intel_encoder *encoder); > > + > > void intel_c10mpllb_readout_hw_state(struct intel_encoder *encoder, > > struct intel_c10mpllb_state *pll_state); int > > intel_cx0mpllb_calc_state(struct intel_crtc_state *crtc_state, diff > > --git a/drivers/gpu/drm/i915/display/intel_ddi.c > > b/drivers/gpu/drm/i915/display/intel_ddi.c > > index aaa8846c3b18..639ec604babf 100644 > > --- a/drivers/gpu/drm/i915/display/intel_ddi.c > > +++ b/drivers/gpu/drm/i915/display/intel_ddi.c > > @@ -4384,6 +4384,8 @@ void intel_ddi_init(struct drm_i915_private > *dev_priv, enum port port) > > encoder->pipe_mask = ~0; > > > > if (DISPLAY_VER(dev_priv) >= 14) { > > + encoder->enable_clock = intel_cx0pll_enable; > > + encoder->disable_clock = intel_cx0pll_disable; > > encoder->get_config = mtl_ddi_get_config; > > } else if (IS_DG2(dev_priv)) { > > encoder->enable_clock = intel_mpllb_enable; diff --git > > a/drivers/gpu/drm/i915/display/intel_dp.c > > b/drivers/gpu/drm/i915/display/intel_dp.c > > index 70b06806ec0d..db32799b5f46 100644 > > --- a/drivers/gpu/drm/i915/display/intel_dp.c > > +++ b/drivers/gpu/drm/i915/display/intel_dp.c > > @@ -420,6 +420,11 @@ static int ehl_max_source_rate(struct intel_dp > *intel_dp) > > return 810000; > > } > > > > +static int mtl_max_source_rate(struct intel_dp *intel_dp) { > > + return intel_dp_is_edp(intel_dp) ? 675000 : 810000; } > > + > > static int vbt_max_link_rate(struct intel_dp *intel_dp) { > > struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; @@ > > -444,6 +449,10 @@ static void intel_dp_set_source_rates(struct > > intel_dp *intel_dp) { > > /* The values must be in increasing order */ > > + static const int mtl_rates[] = { > > + 162000, 216000, 243000, 270000, 324000, 432000, 540000, > 675000, > > + 810000, > > + }; > > static const int icl_rates[] = { > > 162000, 216000, 270000, 324000, 432000, 540000, 648000, > 810000, > > 1000000, 1350000, > > @@ -469,7 +478,11 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) > > drm_WARN_ON(&dev_priv->drm, > > intel_dp->source_rates || intel_dp->num_source_rates); > > > > - if (DISPLAY_VER(dev_priv) >= 11) { > > + if (DISPLAY_VER(dev_priv) >= 14) { > > + source_rates = mtl_rates; > > + size = ARRAY_SIZE(mtl_rates); > > + max_rate = mtl_max_source_rate(intel_dp); > > + } else if (DISPLAY_VER(dev_priv) >= 11) { > > source_rates = icl_rates; > > size = ARRAY_SIZE(icl_rates); > > if (IS_DG2(dev_priv)) > > All of the changes to intel_dp.c should be a separate patch. Ok. I will split this patch so this one is separated from this patch > > > diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c > > b/drivers/gpu/drm/i915/display/intel_dpll.c > > index 73f541050913..d6fcdf4eba0e 100644 > > --- a/drivers/gpu/drm/i915/display/intel_dpll.c > > +++ b/drivers/gpu/drm/i915/display/intel_dpll.c > > @@ -1533,6 +1533,8 @@ intel_dpll_init_clock_hook(struct > > drm_i915_private *dev_priv) { > > if (DISPLAY_VER(dev_priv) >= 14) > > dev_priv->display.funcs.dpll = &mtl_dpll_funcs; > > + else if (DISPLAY_VER(dev_priv) >= 14) > > + dev_priv->display.funcs.dpll = &mtl_dpll_funcs; > > else if (IS_DG2(dev_priv)) > > dev_priv->display.funcs.dpll = &dg2_dpll_funcs; > > else if (DISPLAY_VER(dev_priv) >= 9 || HAS_DDI(dev_priv)) diff --git > > a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > > index 5003a5ffbc6a..5e6ff9f2aa10 100644 > > --- a/drivers/gpu/drm/i915/i915_reg.h > > +++ b/drivers/gpu/drm/i915/i915_reg.h > > @@ -2121,6 +2121,11 @@ > > #define TRANS_PUSH_EN REG_BIT(31) > > #define TRANS_PUSH_SEND REG_BIT(30) > > > > +/* DDI Buffer Control */ > > +#define _DDI_CLK_VALFREQ_A 0x64030 > > +#define _DDI_CLK_VALFREQ_B 0x64130 > > +#define DDI_CLK_VALFREQ(port) _MMIO_PORT(port, > _DDI_CLK_VALFREQ_A, _DDI_CLK_VALFREQ_B) > > + > > /* > > * HSW+ eDP PSR registers > > * > > @@ -8375,4 +8380,140 @@ enum skl_power_gate { > > > > #define MTL_MEDIA_GSI_BASE 0x380000 > > > > +#define PUNIT_MMIO_CR_POC_STRAPS _MMIO(0x281078) > > +#define NUM_TILES_MASK REG_GENMASK(1, 0) > > +#define CD_ALIVE REG_BIT(2) > > +#define SOCKET_ID_MASK REG_GENMASK(7, 3) > > + > > +/* Define the BAR and offset for the accelerator fabric CSRs */ > > +#define CD_BASE_OFFSET 0x291000 #define CD_BAR_SIZE (256 * 1024) > > + > > +/* > > + * In general, the i915 should not touch the IAF registers. The > > +registers > > + * will be passed as an IO resource via the MFD interface. However, > > +it > > + * is necessary to put the IRQ bits in a known state, before the MFD > > +cell > > + * is registered. > > + * > > + * So define these registers for i915 usage. > > These should probably be split to a separate _regs file, like we've been doing for > other registers. Especially because "In general, the i915 should not touch the IAF > registers." Maybe these could be moved into intel_cx0_reg_defs.h file? > > > + */ > > +#define CPORT_MBDB_CSRS (CD_BASE_OFFSET + 0x6000) #define > > +CPORT_MBDB_CSRS_END (CPORT_MBDB_CSRS + 0x1000) #define > > +CPORT_MBDB_INT_ENABLE_MASK _MMIO(CPORT_MBDB_CSRS + 0x8) > > + > > +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A 0x64040 > > +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B 0x64140 > > +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1 > 0x16F240 > > +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2 > 0x16F440 > > +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC3 > 0x16F640 > > +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC4 > 0x16F840 > > +#define _XELPDP_PORT_M2P_MSGBUS_CTL(port, lane) > (_PICK(port, \ > > + [PORT_A] = > _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A, \ > > + [PORT_B] = > _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B, \ > > + [PORT_TC1] = > _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1, \ > > + [PORT_TC2] = > _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2, \ > > + [PORT_TC3] = > _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC3, \ > > + [PORT_TC4] = > _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC4) + ((lane) > > +* 4)) > > + > > +#define XELPDP_PORT_M2P_MSGBUS_CTL(port, lane) > _MMIO(_XELPDP_PORT_M2P_MSGBUS_CTL(port, lane)) > > +#define XELPDP_PORT_M2P_TRANSACTION_PENDING > REG_BIT(31) > > +#define XELPDP_PORT_M2P_COMMAND_TYPE_MASK > REG_GENMASK(30, 27) > > +#define XELPDP_PORT_M2P_COMMAND_WRITE_UNCOMMITTED > REG_FIELD_PREP(XELPDP_PORT_M2P_COMMAND_TYPE_MASK, 0x1) > > +#define XELPDP_PORT_M2P_COMMAND_WRITE_COMMITTED > REG_FIELD_PREP(XELPDP_PORT_M2P_COMMAND_TYPE_MASK, 0x2) > > +#define XELPDP_PORT_M2P_COMMAND_READ > REG_FIELD_PREP(XELPDP_PORT_M2P_COMMAND_TYPE_MASK, 0x3) > > +#define XELPDP_PORT_M2P_DATA_MASK > REG_GENMASK(23, 16) > > +#define XELPDP_PORT_M2P_DATA(val) > REG_FIELD_PREP(XELPDP_PORT_M2P_DATA_MASK, val) > > +#define XELPDP_PORT_M2P_TRANSACTION_RESET REG_BIT(15) > > +#define XELPDP_PORT_M2P_ADDRESS_MASK > REG_GENMASK(11, 0) > > +#define XELPDP_PORT_M2P_ADDRESS(val) > REG_FIELD_PREP(XELPDP_PORT_M2P_ADDRESS_MASK, val) > > + > > +#define XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane) > _MMIO(_XELPDP_PORT_M2P_MSGBUS_CTL(port, lane) + 8) > > +#define XELPDP_PORT_P2M_RESPONSE_READY > REG_BIT(31) > > +#define XELPDP_PORT_P2M_COMMAND_TYPE_MASK > REG_GENMASK(30, 27) > > +#define XELPDP_PORT_P2M_COMMAND_READ_ACK 0x4 > > +#define XELPDP_PORT_P2M_COMMAND_WRITE_ACK 0x5 > > +#define XELPDP_PORT_P2M_DATA_MASK > REG_GENMASK(23, 16) > > +#define XELPDP_PORT_P2M_DATA(val) > REG_FIELD_PREP(XELPDP_PORT_P2M_DATA_MASK, val) > > +#define XELPDP_PORT_P2M_ERROR_SET REG_BIT(15) > > + > > +#define XELPDP_MSGBUS_TIMEOUT_SLOW 1 > > +#define XELPDP_MSGBUS_TIMEOUT_FAST_US 2 > > +#define XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US 3200 > > +#define XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US 20 > > +#define XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US 100 > > +#define XELPDP_PORT_RESET_START_TIMEOUT_US 5 > > +#define XELPDP_PORT_RESET_END_TIMEOUT 15 > > +#define XELPDP_REFCLK_ENABLE_TIMEOUT_US 1 > > + > > +#define _XELPDP_PORT_BUF_CTL1_LN0_A 0x64004 > > +#define _XELPDP_PORT_BUF_CTL1_LN0_B 0x64104 > > +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC1 > 0x16F200 > > +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC2 > 0x16F400 > > +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC3 > 0x16F600 > > +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC4 > 0x16F800 > > +#define _XELPDP_PORT_BUF_CTL1(port) (_PICK(port, \ > > + [PORT_A] = > _XELPDP_PORT_BUF_CTL1_LN0_A, \ > > + [PORT_B] = > _XELPDP_PORT_BUF_CTL1_LN0_B, \ > > + [PORT_TC1] = > _XELPDP_PORT_BUF_CTL1_LN0_USBC1, \ > > + [PORT_TC2] = > _XELPDP_PORT_BUF_CTL1_LN0_USBC2, \ > > + [PORT_TC3] = > _XELPDP_PORT_BUF_CTL1_LN0_USBC3, \ > > + [PORT_TC4] = > _XELPDP_PORT_BUF_CTL1_LN0_USBC4)) > > + > > +#define XELPDP_PORT_BUF_CTL1(port) > _MMIO(_XELPDP_PORT_BUF_CTL1(port)) > > +#define XELPDP_PORT_BUF_SOC_PHY_READY > REG_BIT(24) > > +#define XELPDP_PORT_REVERSAL REG_BIT(16) > > +#define XELPDP_PORT_WIDTH_MASK > REG_GENMASK(3, 1) > > +#define XELPDP_PORT_WIDTH(val) > REG_FIELD_PREP(XELPDP_PORT_WIDTH_MASK, val) > > + > > +#define XELPDP_PORT_BUF_CTL2(port) > _MMIO(_XELPDP_PORT_BUF_CTL1(port) + 4) > > +#define XELPDP_LANE0_PIPE_RESET REG_BIT(31) > > +#define XELPDP_LANE1_PIPE_RESET REG_BIT(30) > > +#define XELPDP_LANE0_PHY_CURRENT_STATUS REG_BIT(29) > > +#define XELPDP_LANE1_PHY_CURRENT_STATUS REG_BIT(28) > > +#define XELPDP_LANE0_POWERDOWN_UPDATE > REG_BIT(25) > > +#define XELPDP_LANE1_POWERDOWN_UPDATE > REG_BIT(24) > > +#define XELPDP_LANE0_POWERDOWN_NEW_STATE_MASK > REG_GENMASK(23, 20) > > +#define XELPDP_LANE0_POWERDOWN_NEW_STATE(val) > REG_FIELD_PREP(XELPDP_LANE0_POWERDOWN_NEW_STATE_MASK, > val) > > +#define XELPDP_LANE1_POWERDOWN_NEW_STATE_MASK > REG_GENMASK(19, 16) > > +#define XELPDP_LANE1_POWERDOWN_NEW_STATE(val) > REG_FIELD_PREP(XELPDP_LANE1_POWERDOWN_NEW_STATE_MASK, > val) > > +#define XELPDP_POWER_STATE_READY_MASK > REG_GENMASK(7, 4) > > +#define XELPDP_POWER_STATE_READY(val) > REG_FIELD_PREP(XELPDP_POWER_STATE_READY_MASK, val) > > + > > +#define XELPDP_PORT_BUF_CTL3(port) > _MMIO(_XELPDP_PORT_BUF_CTL1(port) + 8) > > +#define XELPDP_PLL_LANE_STAGGERING_DELAY_MASK > REG_GENMASK(15, 8) > > +#define XELPDP_PLL_LANE_STAGGERING_DELAY(val) > REG_FIELD_PREP(XELPDP_PLL_LANE_STAGGERING_DELAY_MASK, val) > > +#define XELPDP_POWER_STATE_ACTIVE_MASK > REG_GENMASK(3, 0) > > +#define XELPDP_POWER_STATE_ACTIVE(val) > REG_FIELD_PREP(XELPDP_POWER_STATE_ACTIVE_MASK, val) > > + > > +#define _XELPDP_PORT_CLOCK_CTL_A 0x640E0 > > +#define _XELPDP_PORT_CLOCK_CTL_B 0x641E0 > > +#define _XELPDP_PORT_CLOCK_CTL_USBC1 0x16F260 > > +#define _XELPDP_PORT_CLOCK_CTL_USBC2 0x16F460 > > +#define _XELPDP_PORT_CLOCK_CTL_USBC3 0x16F660 > > +#define _XELPDP_PORT_CLOCK_CTL_USBC4 0x16F860 > > +#define XELPDP_PORT_CLOCK_CTL(port) > _MMIO(_PICK(port, \ > > + [PORT_A] = > _XELPDP_PORT_CLOCK_CTL_A, \ > > + [PORT_B] = > _XELPDP_PORT_CLOCK_CTL_B, \ > > + [PORT_TC1] = > _XELPDP_PORT_CLOCK_CTL_USBC1, \ > > + [PORT_TC2] = > _XELPDP_PORT_CLOCK_CTL_USBC2, \ > > + [PORT_TC3] = > _XELPDP_PORT_CLOCK_CTL_USBC3, \ > > + [PORT_TC4] = > _XELPDP_PORT_CLOCK_CTL_USBC4)) > > + > > +#define XELPDP_LANE0_PCLK_PLL_REQUEST REG_BIT(31) > > +#define XELPDP_LANE0_PCLK_PLL_ACK REG_BIT(30) > > +#define XELPDP_LANE0_PCLK_REFCLK_REQUEST REG_BIT(29) > > +#define XELPDP_LANE0_PCLK_REFCLK_ACK REG_BIT(28) > > +#define XELPDP_LANE1_PCLK_PLL_REQUEST REG_BIT(27) > > +#define XELPDP_LANE1_PCLK_PLL_ACK REG_BIT(26) > > +#define XELPDP_LANE1_PCLK_REFCLK_REQUEST REG_BIT(25) > > +#define XELPDP_LANE1_PCLK_REFCLK_ACK REG_BIT(24) > > +#define XELPDP_DDI_CLOCK_SELECT_MASK > REG_GENMASK(15, 12) > > +#define XELPDP_DDI_CLOCK_SELECT(val) > REG_FIELD_PREP(XELPDP_DDI_CLOCK_SELECT_MASK, val) > > +#define XELPDP_DDI_CLOCK_SELECT_NONE 0x0 > > +#define XELPDP_DDI_CLOCK_SELECT_MAXPCLK 0x8 > > +#define XELPDP_FORWARD_CLOCK_UNGATE REG_BIT(10) > > +#define XELPDP_LANE1_PHY_CLOCK_SELECT REG_BIT(8) > > +#define XELPDP_SSC_ENABLE_PLLA REG_BIT(1) > > +#define XELPDP_SSC_ENABLE_PLLB REG_BIT(0) > > + > > #endif /* _I915_REG_H_ */ > > -- > Jani Nikula, Intel Open Source Graphics Center