drm/i915: Pass atomic state to intel_audio_codec_enable, v2.
[linux-block.git] / drivers / gpu / drm / i915 / intel_ddi.c
index 07164e250adf059e8723e5ca50645b5aa46e5f11..0ad4e16a639fa004dfebfe94ef5e0bc55bc62009 100644 (file)
@@ -167,8 +167,47 @@ static const struct ddi_buf_trans skl_y_ddi_translations_dp[] = {
        { 0x80005012, 0x000000C0, 0x3 },
 };
 
+/* Kabylake H and S */
+static const struct ddi_buf_trans kbl_ddi_translations_dp[] = {
+       { 0x00002016, 0x000000A0, 0x0 },
+       { 0x00005012, 0x0000009B, 0x0 },
+       { 0x00007011, 0x00000088, 0x0 },
+       { 0x80009010, 0x000000C0, 0x1 },
+       { 0x00002016, 0x0000009B, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x80007011, 0x000000C0, 0x1 },
+       { 0x00002016, 0x00000097, 0x0 },
+       { 0x80005012, 0x000000C0, 0x1 },
+};
+
+/* Kabylake U */
+static const struct ddi_buf_trans kbl_u_ddi_translations_dp[] = {
+       { 0x0000201B, 0x000000A1, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x80007011, 0x000000CD, 0x3 },
+       { 0x80009010, 0x000000C0, 0x3 },
+       { 0x0000201B, 0x0000009D, 0x0 },
+       { 0x80005012, 0x000000C0, 0x3 },
+       { 0x80007011, 0x000000C0, 0x3 },
+       { 0x00002016, 0x0000004F, 0x0 },
+       { 0x80005012, 0x000000C0, 0x3 },
+};
+
+/* Kabylake Y */
+static const struct ddi_buf_trans kbl_y_ddi_translations_dp[] = {
+       { 0x00001017, 0x000000A1, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x80007011, 0x000000CD, 0x3 },
+       { 0x8000800F, 0x000000C0, 0x3 },
+       { 0x00001017, 0x0000009D, 0x0 },
+       { 0x80005012, 0x000000C0, 0x3 },
+       { 0x80007011, 0x000000C0, 0x3 },
+       { 0x00001017, 0x0000004C, 0x0 },
+       { 0x80005012, 0x000000C0, 0x3 },
+};
+
 /*
- * Skylake H and S
+ * Skylake/Kabylake H and S
  * eDP 1.4 low vswing translation parameters
  */
 static const struct ddi_buf_trans skl_ddi_translations_edp[] = {
@@ -185,7 +224,7 @@ static const struct ddi_buf_trans skl_ddi_translations_edp[] = {
 };
 
 /*
- * Skylake U
+ * Skylake/Kabylake U
  * eDP 1.4 low vswing translation parameters
  */
 static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = {
@@ -202,7 +241,7 @@ static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = {
 };
 
 /*
- * Skylake Y
+ * Skylake/Kabylake Y
  * eDP 1.4 low vswing translation parameters
  */
 static const struct ddi_buf_trans skl_y_ddi_translations_edp[] = {
@@ -218,7 +257,7 @@ static const struct ddi_buf_trans skl_y_ddi_translations_edp[] = {
        { 0x00000018, 0x0000008A, 0x0 },
 };
 
-/* Skylake U, H and S */
+/* Skylake/Kabylake U, H and S */
 static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
        { 0x00000018, 0x000000AC, 0x0 },
        { 0x00005012, 0x0000009D, 0x0 },
@@ -233,7 +272,7 @@ static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
        { 0x80000018, 0x000000C0, 0x1 },
 };
 
-/* Skylake Y */
+/* Skylake/Kabylake Y */
 static const struct ddi_buf_trans skl_y_ddi_translations_hdmi[] = {
        { 0x00000018, 0x000000A1, 0x0 },
        { 0x00005012, 0x000000DF, 0x0 },
@@ -334,10 +373,10 @@ bdw_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
 static const struct ddi_buf_trans *
 skl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
 {
-       if (IS_SKL_ULX(dev_priv) || IS_KBL_ULX(dev_priv)) {
+       if (IS_SKL_ULX(dev_priv)) {
                *n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp);
                return skl_y_ddi_translations_dp;
-       } else if (IS_SKL_ULT(dev_priv) || IS_KBL_ULT(dev_priv)) {
+       } else if (IS_SKL_ULT(dev_priv)) {
                *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp);
                return skl_u_ddi_translations_dp;
        } else {
@@ -346,6 +385,21 @@ skl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
        }
 }
 
+static const struct ddi_buf_trans *
+kbl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
+{
+       if (IS_KBL_ULX(dev_priv)) {
+               *n_entries = ARRAY_SIZE(kbl_y_ddi_translations_dp);
+               return kbl_y_ddi_translations_dp;
+       } else if (IS_KBL_ULT(dev_priv)) {
+               *n_entries = ARRAY_SIZE(kbl_u_ddi_translations_dp);
+               return kbl_u_ddi_translations_dp;
+       } else {
+               *n_entries = ARRAY_SIZE(kbl_ddi_translations_dp);
+               return kbl_ddi_translations_dp;
+       }
+}
+
 static const struct ddi_buf_trans *
 skl_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
 {
@@ -362,7 +416,10 @@ skl_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
                }
        }
 
-       return skl_get_buf_trans_dp(dev_priv, n_entries);
+       if (IS_KABYLAKE(dev_priv))
+               return kbl_get_buf_trans_dp(dev_priv, n_entries);
+       else
+               return skl_get_buf_trans_dp(dev_priv, n_entries);
 }
 
 static const struct ddi_buf_trans *
@@ -430,21 +487,18 @@ void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder)
        if (IS_BROXTON(dev_priv))
                return;
 
-       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+       if (IS_KABYLAKE(dev_priv)) {
+               ddi_translations_fdi = NULL;
+               ddi_translations_dp =
+                               kbl_get_buf_trans_dp(dev_priv, &n_dp_entries);
+               ddi_translations_edp =
+                               skl_get_buf_trans_edp(dev_priv, &n_edp_entries);
+       } else if (IS_SKYLAKE(dev_priv)) {
                ddi_translations_fdi = NULL;
                ddi_translations_dp =
                                skl_get_buf_trans_dp(dev_priv, &n_dp_entries);
                ddi_translations_edp =
                                skl_get_buf_trans_edp(dev_priv, &n_edp_entries);
-
-               /* If we're boosting the current, set bit 31 of trans1 */
-               if (dev_priv->vbt.ddi_port_info[port].dp_boost_level)
-                       iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE;
-
-               if (WARN_ON(encoder->type == INTEL_OUTPUT_EDP &&
-                           port != PORT_A && port != PORT_E &&
-                           n_edp_entries > 9))
-                       n_edp_entries = 9;
        } else if (IS_BROADWELL(dev_priv)) {
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
@@ -464,6 +518,17 @@ void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder)
                n_dp_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
        }
 
+       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+               /* If we're boosting the current, set bit 31 of trans1 */
+               if (dev_priv->vbt.ddi_port_info[port].dp_boost_level)
+                       iboost_bit = DDI_BUF_BALANCE_LEG_ENABLE;
+
+               if (WARN_ON(encoder->type == INTEL_OUTPUT_EDP &&
+                           port != PORT_A && port != PORT_E &&
+                           n_edp_entries > 9))
+                       n_edp_entries = 9;
+       }
+
        switch (encoder->type) {
        case INTEL_OUTPUT_EDP:
                ddi_translations = ddi_translations_edp;
@@ -1434,7 +1499,12 @@ static void skl_ddi_set_iboost(struct intel_encoder *encoder, u32 level)
                if (dp_iboost) {
                        iboost = dp_iboost;
                } else {
-                       ddi_translations = skl_get_buf_trans_dp(dev_priv, &n_entries);
+                       if (IS_KABYLAKE(dev_priv))
+                               ddi_translations = kbl_get_buf_trans_dp(dev_priv,
+                                                                       &n_entries);
+                       else
+                               ddi_translations = skl_get_buf_trans_dp(dev_priv,
+                                                                       &n_entries);
                        iboost = ddi_translations[level].i_boost;
                }
        } else if (type == INTEL_OUTPUT_EDP) {
@@ -1477,7 +1547,6 @@ static void bxt_ddi_vswing_sequence(struct drm_i915_private *dev_priv,
 {
        const struct bxt_ddi_buf_trans *ddi_translations;
        u32 n_entries, i;
-       uint32_t val;
 
        if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.low_vswing) {
                n_entries = ARRAY_SIZE(bxt_ddi_translations_edp);
@@ -1506,38 +1575,11 @@ static void bxt_ddi_vswing_sequence(struct drm_i915_private *dev_priv,
                }
        }
 
-       /*
-        * While we write to the group register to program all lanes at once we
-        * can read only lane registers and we pick lanes 0/1 for that.
-        */
-       val = I915_READ(BXT_PORT_PCS_DW10_LN01(port));
-       val &= ~(TX2_SWING_CALC_INIT | TX1_SWING_CALC_INIT);
-       I915_WRITE(BXT_PORT_PCS_DW10_GRP(port), val);
-
-       val = I915_READ(BXT_PORT_TX_DW2_LN0(port));
-       val &= ~(MARGIN_000 | UNIQ_TRANS_SCALE);
-       val |= ddi_translations[level].margin << MARGIN_000_SHIFT |
-              ddi_translations[level].scale << UNIQ_TRANS_SCALE_SHIFT;
-       I915_WRITE(BXT_PORT_TX_DW2_GRP(port), val);
-
-       val = I915_READ(BXT_PORT_TX_DW3_LN0(port));
-       val &= ~SCALE_DCOMP_METHOD;
-       if (ddi_translations[level].enable)
-               val |= SCALE_DCOMP_METHOD;
-
-       if ((val & UNIQUE_TRANGE_EN_METHOD) && !(val & SCALE_DCOMP_METHOD))
-               DRM_ERROR("Disabled scaling while ouniqetrangenmethod was set");
-
-       I915_WRITE(BXT_PORT_TX_DW3_GRP(port), val);
-
-       val = I915_READ(BXT_PORT_TX_DW4_LN0(port));
-       val &= ~DE_EMPHASIS;
-       val |= ddi_translations[level].deemphasis << DEEMPH_SHIFT;
-       I915_WRITE(BXT_PORT_TX_DW4_GRP(port), val);
-
-       val = I915_READ(BXT_PORT_PCS_DW10_LN01(port));
-       val |= TX2_SWING_CALC_INIT | TX1_SWING_CALC_INIT;
-       I915_WRITE(BXT_PORT_PCS_DW10_GRP(port), val);
+       bxt_ddi_phy_set_signal_level(dev_priv, port,
+                                    ddi_translations[level].margin,
+                                    ddi_translations[level].scale,
+                                    ddi_translations[level].enable,
+                                    ddi_translations[level].deemphasis);
 }
 
 static uint32_t translate_signal_level(int signal_levels)
@@ -1824,7 +1866,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder,
 
        if (intel_crtc->config->has_audio) {
                intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
-               intel_audio_codec_enable(intel_encoder);
+               intel_audio_codec_enable(intel_encoder, pipe_config, conn_state);
        }
 }
 
@@ -1853,332 +1895,14 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder,
        }
 }
 
-bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv,
-                           enum dpio_phy phy)
-{
-       enum port port;
-
-       if (!(I915_READ(BXT_P_CR_GT_DISP_PWRON) & GT_DISPLAY_POWER_ON(phy)))
-               return false;
-
-       if ((I915_READ(BXT_PORT_CL1CM_DW0(phy)) &
-            (PHY_POWER_GOOD | PHY_RESERVED)) != PHY_POWER_GOOD) {
-               DRM_DEBUG_DRIVER("DDI PHY %d powered, but power hasn't settled\n",
-                                phy);
-
-               return false;
-       }
-
-       if (phy == DPIO_PHY1 &&
-           !(I915_READ(BXT_PORT_REF_DW3(DPIO_PHY1)) & GRC_DONE)) {
-               DRM_DEBUG_DRIVER("DDI PHY 1 powered, but GRC isn't done\n");
-
-               return false;
-       }
-
-       if (!(I915_READ(BXT_PHY_CTL_FAMILY(phy)) & COMMON_RESET_DIS)) {
-               DRM_DEBUG_DRIVER("DDI PHY %d powered, but still in reset\n",
-                                phy);
-
-               return false;
-       }
-
-       for_each_port_masked(port,
-                            phy == DPIO_PHY0 ? BIT(PORT_B) | BIT(PORT_C) :
-                                               BIT(PORT_A)) {
-               u32 tmp = I915_READ(BXT_PHY_CTL(port));
-
-               if (tmp & BXT_PHY_CMNLANE_POWERDOWN_ACK) {
-                       DRM_DEBUG_DRIVER("DDI PHY %d powered, but common lane "
-                                        "for port %c powered down "
-                                        "(PHY_CTL %08x)\n",
-                                        phy, port_name(port), tmp);
-
-                       return false;
-               }
-       }
-
-       return true;
-}
-
-static u32 bxt_get_grc(struct drm_i915_private *dev_priv, enum dpio_phy phy)
-{
-       u32 val = I915_READ(BXT_PORT_REF_DW6(phy));
-
-       return (val & GRC_CODE_MASK) >> GRC_CODE_SHIFT;
-}
-
-static void bxt_phy_wait_grc_done(struct drm_i915_private *dev_priv,
-                                 enum dpio_phy phy)
-{
-       if (intel_wait_for_register(dev_priv,
-                                   BXT_PORT_REF_DW3(phy),
-                                   GRC_DONE, GRC_DONE,
-                                   10))
-               DRM_ERROR("timeout waiting for PHY%d GRC\n", phy);
-}
-
-void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy)
-{
-       u32 val;
-
-       if (bxt_ddi_phy_is_enabled(dev_priv, phy)) {
-               /* Still read out the GRC value for state verification */
-               if (phy == DPIO_PHY0)
-                       dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv, phy);
-
-               if (bxt_ddi_phy_verify_state(dev_priv, phy)) {
-                       DRM_DEBUG_DRIVER("DDI PHY %d already enabled, "
-                                        "won't reprogram it\n", phy);
-
-                       return;
-               }
-
-               DRM_DEBUG_DRIVER("DDI PHY %d enabled with invalid state, "
-                                "force reprogramming it\n", phy);
-       }
-
-       val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
-       val |= GT_DISPLAY_POWER_ON(phy);
-       I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val);
-
-       /*
-        * The PHY registers start out inaccessible and respond to reads with
-        * all 1s.  Eventually they become accessible as they power up, then
-        * the reserved bit will give the default 0.  Poll on the reserved bit
-        * becoming 0 to find when the PHY is accessible.
-        * HW team confirmed that the time to reach phypowergood status is
-        * anywhere between 50 us and 100us.
-        */
-       if (wait_for_us(((I915_READ(BXT_PORT_CL1CM_DW0(phy)) &
-               (PHY_RESERVED | PHY_POWER_GOOD)) == PHY_POWER_GOOD), 100)) {
-               DRM_ERROR("timeout during PHY%d power on\n", phy);
-       }
-
-       /* Program PLL Rcomp code offset */
-       val = I915_READ(BXT_PORT_CL1CM_DW9(phy));
-       val &= ~IREF0RC_OFFSET_MASK;
-       val |= 0xE4 << IREF0RC_OFFSET_SHIFT;
-       I915_WRITE(BXT_PORT_CL1CM_DW9(phy), val);
-
-       val = I915_READ(BXT_PORT_CL1CM_DW10(phy));
-       val &= ~IREF1RC_OFFSET_MASK;
-       val |= 0xE4 << IREF1RC_OFFSET_SHIFT;
-       I915_WRITE(BXT_PORT_CL1CM_DW10(phy), val);
-
-       /* Program power gating */
-       val = I915_READ(BXT_PORT_CL1CM_DW28(phy));
-       val |= OCL1_POWER_DOWN_EN | DW28_OLDO_DYN_PWR_DOWN_EN |
-               SUS_CLK_CONFIG;
-       I915_WRITE(BXT_PORT_CL1CM_DW28(phy), val);
-
-       if (phy == DPIO_PHY0) {
-               val = I915_READ(BXT_PORT_CL2CM_DW6_BC);
-               val |= DW6_OLDO_DYN_PWR_DOWN_EN;
-               I915_WRITE(BXT_PORT_CL2CM_DW6_BC, val);
-       }
-
-       val = I915_READ(BXT_PORT_CL1CM_DW30(phy));
-       val &= ~OCL2_LDOFUSE_PWR_DIS;
-       /*
-        * On PHY1 disable power on the second channel, since no port is
-        * connected there. On PHY0 both channels have a port, so leave it
-        * enabled.
-        * TODO: port C is only connected on BXT-P, so on BXT0/1 we should
-        * power down the second channel on PHY0 as well.
-        *
-        * FIXME: Clarify programming of the following, the register is
-        * read-only with bit 6 fixed at 0 at least in stepping A.
-        */
-       if (phy == DPIO_PHY1)
-               val |= OCL2_LDOFUSE_PWR_DIS;
-       I915_WRITE(BXT_PORT_CL1CM_DW30(phy), val);
-
-       if (phy == DPIO_PHY0) {
-               uint32_t grc_code;
-               /*
-                * PHY0 isn't connected to an RCOMP resistor so copy over
-                * the corresponding calibrated value from PHY1, and disable
-                * the automatic calibration on PHY0.
-                */
-               val = dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv, DPIO_PHY1);
-               grc_code = val << GRC_CODE_FAST_SHIFT |
-                          val << GRC_CODE_SLOW_SHIFT |
-                          val;
-               I915_WRITE(BXT_PORT_REF_DW6(DPIO_PHY0), grc_code);
-
-               val = I915_READ(BXT_PORT_REF_DW8(DPIO_PHY0));
-               val |= GRC_DIS | GRC_RDY_OVRD;
-               I915_WRITE(BXT_PORT_REF_DW8(DPIO_PHY0), val);
-       }
-
-       val = I915_READ(BXT_PHY_CTL_FAMILY(phy));
-       val |= COMMON_RESET_DIS;
-       I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val);
-
-       if (phy == DPIO_PHY1)
-               bxt_phy_wait_grc_done(dev_priv, DPIO_PHY1);
-}
-
-void bxt_ddi_phy_uninit(struct drm_i915_private *dev_priv, enum dpio_phy phy)
-{
-       uint32_t val;
-
-       val = I915_READ(BXT_PHY_CTL_FAMILY(phy));
-       val &= ~COMMON_RESET_DIS;
-       I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val);
-
-       val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
-       val &= ~GT_DISPLAY_POWER_ON(phy);
-       I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val);
-}
-
-static bool __printf(6, 7)
-__phy_reg_verify_state(struct drm_i915_private *dev_priv, enum dpio_phy phy,
-                      i915_reg_t reg, u32 mask, u32 expected,
-                      const char *reg_fmt, ...)
-{
-       struct va_format vaf;
-       va_list args;
-       u32 val;
-
-       val = I915_READ(reg);
-       if ((val & mask) == expected)
-               return true;
-
-       va_start(args, reg_fmt);
-       vaf.fmt = reg_fmt;
-       vaf.va = &args;
-
-       DRM_DEBUG_DRIVER("DDI PHY %d reg %pV [%08x] state mismatch: "
-                        "current %08x, expected %08x (mask %08x)\n",
-                        phy, &vaf, reg.reg, val, (val & ~mask) | expected,
-                        mask);
-
-       va_end(args);
-
-       return false;
-}
-
-bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv,
-                             enum dpio_phy phy)
-{
-       uint32_t mask;
-       bool ok;
-
-#define _CHK(reg, mask, exp, fmt, ...)                                 \
-       __phy_reg_verify_state(dev_priv, phy, reg, mask, exp, fmt,      \
-                              ## __VA_ARGS__)
-
-       if (!bxt_ddi_phy_is_enabled(dev_priv, phy))
-               return false;
-
-       ok = true;
-
-       /* PLL Rcomp code offset */
-       ok &= _CHK(BXT_PORT_CL1CM_DW9(phy),
-                   IREF0RC_OFFSET_MASK, 0xe4 << IREF0RC_OFFSET_SHIFT,
-                   "BXT_PORT_CL1CM_DW9(%d)", phy);
-       ok &= _CHK(BXT_PORT_CL1CM_DW10(phy),
-                   IREF1RC_OFFSET_MASK, 0xe4 << IREF1RC_OFFSET_SHIFT,
-                   "BXT_PORT_CL1CM_DW10(%d)", phy);
-
-       /* Power gating */
-       mask = OCL1_POWER_DOWN_EN | DW28_OLDO_DYN_PWR_DOWN_EN | SUS_CLK_CONFIG;
-       ok &= _CHK(BXT_PORT_CL1CM_DW28(phy), mask, mask,
-                   "BXT_PORT_CL1CM_DW28(%d)", phy);
-
-       if (phy == DPIO_PHY0)
-               ok &= _CHK(BXT_PORT_CL2CM_DW6_BC,
-                          DW6_OLDO_DYN_PWR_DOWN_EN, DW6_OLDO_DYN_PWR_DOWN_EN,
-                          "BXT_PORT_CL2CM_DW6_BC");
-
-       /*
-        * TODO: Verify BXT_PORT_CL1CM_DW30 bit OCL2_LDOFUSE_PWR_DIS,
-        * at least on stepping A this bit is read-only and fixed at 0.
-        */
-
-       if (phy == DPIO_PHY0) {
-               u32 grc_code = dev_priv->bxt_phy_grc;
-
-               grc_code = grc_code << GRC_CODE_FAST_SHIFT |
-                          grc_code << GRC_CODE_SLOW_SHIFT |
-                          grc_code;
-               mask = GRC_CODE_FAST_MASK | GRC_CODE_SLOW_MASK |
-                      GRC_CODE_NOM_MASK;
-               ok &= _CHK(BXT_PORT_REF_DW6(DPIO_PHY0), mask, grc_code,
-                           "BXT_PORT_REF_DW6(%d)", DPIO_PHY0);
-
-               mask = GRC_DIS | GRC_RDY_OVRD;
-               ok &= _CHK(BXT_PORT_REF_DW8(DPIO_PHY0), mask, mask,
-                           "BXT_PORT_REF_DW8(%d)", DPIO_PHY0);
-       }
-
-       return ok;
-#undef _CHK
-}
-
-static uint8_t
-bxt_ddi_phy_calc_lane_lat_optim_mask(struct intel_encoder *encoder,
-                                    struct intel_crtc_state *pipe_config)
-{
-       switch (pipe_config->lane_count) {
-       case 1:
-               return 0;
-       case 2:
-               return BIT(2) | BIT(0);
-       case 4:
-               return BIT(3) | BIT(2) | BIT(0);
-       default:
-               MISSING_CASE(pipe_config->lane_count);
-
-               return 0;
-       }
-}
-
 static void bxt_ddi_pre_pll_enable(struct intel_encoder *encoder,
                                   struct intel_crtc_state *pipe_config,
                                   struct drm_connector_state *conn_state)
 {
-       struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
-       enum port port = dport->port;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
-       int lane;
-
-       for (lane = 0; lane < 4; lane++) {
-               u32 val = I915_READ(BXT_PORT_TX_DW14_LN(port, lane));
-
-               /*
-                * Note that on CHV this flag is called UPAR, but has
-                * the same function.
-                */
-               val &= ~LATENCY_OPTIM;
-               if (intel_crtc->config->lane_lat_optim_mask & BIT(lane))
-                       val |= LATENCY_OPTIM;
+       uint8_t mask = intel_crtc->config->lane_lat_optim_mask;
 
-               I915_WRITE(BXT_PORT_TX_DW14_LN(port, lane), val);
-       }
-}
-
-static uint8_t
-bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder)
-{
-       struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
-       enum port port = dport->port;
-       int lane;
-       uint8_t mask;
-
-       mask = 0;
-       for (lane = 0; lane < 4; lane++) {
-               u32 val = I915_READ(BXT_PORT_TX_DW14_LN(port, lane));
-
-               if (val & LATENCY_OPTIM)
-                       mask |= BIT(lane);
-       }
-
-       return mask;
+       bxt_ddi_phy_set_lane_optim_mask(encoder, mask);
 }
 
 void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
@@ -2347,7 +2071,7 @@ static bool intel_ddi_compute_config(struct intel_encoder *encoder,
        if (IS_BROXTON(dev_priv) && ret)
                pipe_config->lane_lat_optim_mask =
                        bxt_ddi_phy_calc_lane_lat_optim_mask(encoder,
-                                                            pipe_config);
+                                                            pipe_config->lane_count);
 
        return ret;
 
@@ -2438,7 +2162,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
        struct intel_digital_port *intel_dig_port;
        struct intel_encoder *intel_encoder;
        struct drm_encoder *encoder;
-       bool init_hdmi, init_dp;
+       bool init_hdmi, init_dp, init_lspcon = false;
        int max_lanes;
 
        if (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES) {
@@ -2470,6 +2194,19 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
        init_hdmi = (dev_priv->vbt.ddi_port_info[port].supports_dvi ||
                     dev_priv->vbt.ddi_port_info[port].supports_hdmi);
        init_dp = dev_priv->vbt.ddi_port_info[port].supports_dp;
+
+       if (intel_bios_is_lspcon_present(dev_priv, port)) {
+               /*
+                * Lspcon device needs to be driven with DP connector
+                * with special detection sequence. So make sure DP
+                * is initialized before lspcon.
+                */
+               init_dp = true;
+               init_lspcon = true;
+               init_hdmi = false;
+               DRM_DEBUG_KMS("VBT says port %c has lspcon\n", port_name(port));
+       }
+
        if (!init_dp && !init_hdmi) {
                DRM_DEBUG_KMS("VBT says port %c is not DVI/HDMI/DP compatible, respect it\n",
                              port_name(port));
@@ -2509,7 +2246,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
         * configuration so that we use the proper lane count for our
         * calculations.
         */
-       if (IS_BROXTON(dev) && port == PORT_A) {
+       if (IS_BROXTON(dev_priv) && port == PORT_A) {
                if (!(intel_dig_port->saved_port_bits & DDI_A_4_LANES)) {
                        DRM_DEBUG_KMS("BXT BIOS forgot to set DDI_A_4_LANES for port A; fixing\n");
                        intel_dig_port->saved_port_bits |= DDI_A_4_LANES;
@@ -2533,7 +2270,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
                 * On BXT A0/A1, sw needs to activate DDIA HPD logic and
                 * interrupts to check the external panel connection.
                 */
-               if (IS_BXT_REVID(dev, 0, BXT_REVID_A1) && port == PORT_B)
+               if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1) && port == PORT_B)
                        dev_priv->hotplug.irq_port[PORT_A] = intel_dig_port;
                else
                        dev_priv->hotplug.irq_port[port] = intel_dig_port;
@@ -2546,6 +2283,20 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
                        goto err;
        }
 
+       if (init_lspcon) {
+               if (lspcon_init(intel_dig_port))
+                       /* TODO: handle hdmi info frame part */
+                       DRM_DEBUG_KMS("LSPCON init success on port %c\n",
+                               port_name(port));
+               else
+                       /*
+                        * LSPCON init faied, but DP init was success, so
+                        * lets try to drive as DP++ port.
+                        */
+                       DRM_ERROR("LSPCON init failed on port %c\n",
+                               port_name(port));
+       }
+
        return;
 
 err: