On Mon, Jun 05, 2017 at 01:53:07PM -0700, Rodrigo Vivi wrote: > This is an important part of the DDI initalization as well as > for changing the voltage during DisplayPort link training. > > This new sequence for Cannonlake is more like Broxton style > but still with different registers, different table and > different steps. > > v2: Do not write to DW4_GRP to avoid overwrite individual loadgen. > Fix PORT_CL_DW5 SUS Clock Config set. > v3: As previous platforms use only eDP table if low voltage was > requested. > v4: fix Werror:maybe uninitialized (Paulo) > v5: Rebase on top of dw2_swing_sel changes > on previous patches. > v6: Using flexible SCALING_MODE_SEL(x). > > Cc: Manasi Navare <manasi.d.navare@xxxxxxxxx> > Cc: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > Signed-off-by: Rodrigo Vivi <rodrigo.vivi@xxxxxxxxx> Reviewed-by: Manasi Navare <manasi.d.navare@xxxxxxxxx> > --- > drivers/gpu/drm/i915/i915_reg.h | 1 + > drivers/gpu/drm/i915/intel_ddi.c | 176 ++++++++++++++++++++++++++++++++++++++- > drivers/gpu/drm/i915/intel_dp.c | 2 +- > 3 files changed, 177 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index 0d2063e..e61376f 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -1671,6 +1671,7 @@ enum skl_disp_power_wells { > > #define CNL_PORT_CL1CM_DW5 _MMIO(0x162014) > #define CL_POWER_DOWN_ENABLE (1 << 4) > +#define SUS_CLOCK_CONFIG (3 << 0) > > #define _PORT_CL1CM_DW9_A 0x162024 > #define _PORT_CL1CM_DW9_BC 0x6C024 > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c > index 9f34038..56b0a2c 100644 > --- a/drivers/gpu/drm/i915/intel_ddi.c > +++ b/drivers/gpu/drm/i915/intel_ddi.c > @@ -1720,6 +1720,173 @@ u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder) > DP_TRAIN_VOLTAGE_SWING_MASK; > } > > +static const struct cnl_ddi_buf_trans * > +cnl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, > + u32 voltage, int *n_entries) > +{ > + if (voltage == VOLTAGE_INFO_0_85V) { > + *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_85V); > + return cnl_ddi_translations_hdmi_0_85V; > + } else if (voltage == VOLTAGE_INFO_0_95V) { > + *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_95V); > + return cnl_ddi_translations_hdmi_0_95V; > + } else if (voltage == VOLTAGE_INFO_1_05V) { > + *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_1_05V); > + return cnl_ddi_translations_hdmi_1_05V; > + } > + return NULL; > +} > + > +static const struct cnl_ddi_buf_trans * > +cnl_get_buf_trans_dp(struct drm_i915_private *dev_priv, > + u32 voltage, int *n_entries) > +{ > + if (voltage == VOLTAGE_INFO_0_85V) { > + *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_85V); > + return cnl_ddi_translations_dp_0_85V; > + } else if (voltage == VOLTAGE_INFO_0_95V) { > + *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_95V); > + return cnl_ddi_translations_dp_0_95V; > + } else if (voltage == VOLTAGE_INFO_1_05V) { > + *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_1_05V); > + return cnl_ddi_translations_dp_1_05V; > + } > + return NULL; > +} > + > +static const struct cnl_ddi_buf_trans * > +cnl_get_buf_trans_edp(struct drm_i915_private *dev_priv, > + u32 voltage, int *n_entries) > +{ > + if (dev_priv->vbt.edp.low_vswing) { > + if (voltage == VOLTAGE_INFO_0_85V) { > + *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_85V); > + return cnl_ddi_translations_dp_0_85V; > + } else if (voltage == VOLTAGE_INFO_0_95V) { > + *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_95V); > + return cnl_ddi_translations_edp_0_95V; > + } else if (voltage == VOLTAGE_INFO_1_05V) { > + *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_1_05V); > + return cnl_ddi_translations_edp_1_05V; > + } > + return NULL; > + } else { > + return cnl_get_buf_trans_dp(dev_priv, voltage, n_entries); > + } > +} > + > +static void cnl_ddi_vswing_program(struct drm_i915_private *dev_priv, > + u32 level, enum port port, int type) > +{ > + const struct cnl_ddi_buf_trans *ddi_translations = NULL; > + u32 n_entries, val, voltage; > + int ln; > + > + /* > + * Values for each port type are listed in > + * voltage swing programming tables. > + * Vccio voltage found in PORT_COMP_DW3. > + */ > + voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; > + > + if (type == INTEL_OUTPUT_HDMI) { > + ddi_translations = cnl_get_buf_trans_hdmi(dev_priv, > + voltage, &n_entries); > + } else if (type == INTEL_OUTPUT_DP) { > + ddi_translations = cnl_get_buf_trans_dp(dev_priv, > + voltage, &n_entries); > + } else if (type == INTEL_OUTPUT_EDP) { > + ddi_translations = cnl_get_buf_trans_edp(dev_priv, > + voltage, &n_entries); > + } > + > + if (ddi_translations == NULL) { > + MISSING_CASE(voltage); > + return; > + } > + > + if (level >= n_entries) { > + DRM_DEBUG_KMS("DDI translation not found for level %d. Using %d instead.", level, n_entries - 1); > + level = n_entries - 1; > + } > + > + /* Set PORT_TX_DW5 Scaling Mode Sel to 010b. */ > + val = I915_READ(CNL_PORT_TX_DW5_LN0(port)); > + val |= SCALING_MODE_SEL(2); > + I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val); > + > + /* Program PORT_TX_DW2 */ > + val = I915_READ(CNL_PORT_TX_DW2_LN0(port)); > + val |= SWING_SEL_UPPER(ddi_translations[level].dw2_swing_sel); > + val |= SWING_SEL_LOWER(ddi_translations[level].dw2_swing_sel); > + /* Rcomp scalar is fixed as 0x98 for every table entry */ > + val |= RCOMP_SCALAR(0x98); > + I915_WRITE(CNL_PORT_TX_DW2_GRP(port), val); > + > + /* Program PORT_TX_DW4 */ > + /* We cannot write to GRP. It would overrite individual loadgen */ > + for (ln = 0; ln < 4; ln++) { > + val = I915_READ(CNL_PORT_TX_DW4_LN(port, ln)); > + val |= POST_CURSOR_1(ddi_translations[level].dw4_post_cursor_1); > + val |= POST_CURSOR_2(ddi_translations[level].dw4_post_cursor_2); > + val |= CURSOR_COEFF(ddi_translations[level].dw4_cursor_coeff); > + I915_WRITE(CNL_PORT_TX_DW4_LN(port, ln), val); > + } > + > + /* Program PORT_TX_DW5 */ > + /* All DW5 values are fixed for every table entry */ > + val = I915_READ(CNL_PORT_TX_DW5_LN0(port)); > + val |= RTERM_SELECT(6); > + val |= TAP3_DISABLE; > + I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val); > + > + /* Program PORT_TX_DW7 */ > + val = I915_READ(CNL_PORT_TX_DW7_LN0(port)); > + val |= N_SCALAR(ddi_translations[level].dw7_n_scalar); > + I915_WRITE(CNL_PORT_TX_DW7_GRP(port), val); > +} > + > +static void cnl_ddi_vswing_sequence(struct drm_i915_private *dev_priv, > + u32 level, enum port port, int type) > +{ > + u32 val; > + > + /* > + * 1. If port type is eDP or DP, > + * set PORT_PCS_DW1 cmnkeeper_enable to 1b, > + * else clear to 0b. > + */ > + val = I915_READ(CNL_PORT_PCS_DW1_LN0(port)); > + if (type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP) > + val |= COMMON_KEEPER_EN; > + else > + val &= ~COMMON_KEEPER_EN; > + I915_WRITE(CNL_PORT_PCS_DW1_GRP(port), val); > + > + /* 2. Program loadgen select */ > + /* > + * FIXME: Program PORT_TX_DW4_LN depending on Bit rate and used lanes > + */ > + > + /* 3. Set PORT_CL_DW5 SUS Clock Config to 11b */ > + val = I915_READ(CNL_PORT_CL1CM_DW5); > + val |= SUS_CLOCK_CONFIG; > + I915_WRITE(CNL_PORT_CL1CM_DW5, val); > + > + /* 4. Clear training enable to change swing values */ > + val = I915_READ(CNL_PORT_TX_DW5_LN0(port)); > + val &= ~TX_TRAINING_EN; > + I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val); > + > + /* 5. Program swing and de-emphasis */ > + cnl_ddi_vswing_program(dev_priv, level, port, type); > + > + /* 6. Set training enable to trigger update */ > + val = I915_READ(CNL_PORT_TX_DW5_LN0(port)); > + val |= TX_TRAINING_EN; > + I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val); > +} > + > static uint32_t translate_signal_level(int signal_levels) > { > int i; > @@ -1752,7 +1919,11 @@ uint32_t ddi_signal_levels(struct intel_dp *intel_dp) > skl_ddi_set_iboost(encoder, level); > else if (IS_GEN9_LP(dev_priv)) > bxt_ddi_vswing_sequence(dev_priv, level, port, encoder->type); > - > + else if (IS_CANNONLAKE(dev_priv)) { > + cnl_ddi_vswing_sequence(dev_priv, level, port, encoder->type); > + /* DDI_BUF_CTL bits 27:24 are reserved on CNL */ > + return 0; > + } > return DDI_BUF_TRANS_SELECT(level); > } > > @@ -1850,6 +2021,9 @@ static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder, > else if (IS_GEN9_LP(dev_priv)) > bxt_ddi_vswing_sequence(dev_priv, level, port, > INTEL_OUTPUT_HDMI); > + else if (IS_CANNONLAKE(dev_priv)) > + cnl_ddi_vswing_sequence(dev_priv, level, port, > + INTEL_OUTPUT_HDMI); > > intel_hdmi->set_infoframes(drm_encoder, > has_hdmi_sink, > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c > index 1a27c72..ecf9dfc 100644 > --- a/drivers/gpu/drm/i915/intel_dp.c > +++ b/drivers/gpu/drm/i915/intel_dp.c > @@ -3462,7 +3462,7 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp) > if (HAS_DDI(dev_priv)) { > signal_levels = ddi_signal_levels(intel_dp); > > - if (IS_GEN9_LP(dev_priv)) > + if (IS_GEN9_LP(dev_priv) || IS_CANNONLAKE(dev_priv)) > signal_levels = 0; > else > mask = DDI_BUF_EMP_MASK; > -- > 1.9.1 > _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx