These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / i915 / intel_ddi.c
index 3eb0efc..7e6158b 100644 (file)
@@ -31,6 +31,7 @@
 struct ddi_buf_trans {
        u32 trans1;     /* balance leg enable, de-emph level */
        u32 trans2;     /* vref sel, vswing */
+       u8 i_boost;     /* SKL: I_boost; valid: 0x0, 0x1, 0x3, 0x7 */
 };
 
 /* HDMI/DVI modes ignore everything but the last 2 items. So we share
@@ -38,148 +39,384 @@ struct ddi_buf_trans {
  * automatically adapt to HDMI connections as well
  */
 static const struct ddi_buf_trans hsw_ddi_translations_dp[] = {
-       { 0x00FFFFFF, 0x0006000E },
-       { 0x00D75FFF, 0x0005000A },
-       { 0x00C30FFF, 0x00040006 },
-       { 0x80AAAFFF, 0x000B0000 },
-       { 0x00FFFFFF, 0x0005000A },
-       { 0x00D75FFF, 0x000C0004 },
-       { 0x80C30FFF, 0x000B0000 },
-       { 0x00FFFFFF, 0x00040006 },
-       { 0x80D75FFF, 0x000B0000 },
+       { 0x00FFFFFF, 0x0006000E, 0x0 },
+       { 0x00D75FFF, 0x0005000A, 0x0 },
+       { 0x00C30FFF, 0x00040006, 0x0 },
+       { 0x80AAAFFF, 0x000B0000, 0x0 },
+       { 0x00FFFFFF, 0x0005000A, 0x0 },
+       { 0x00D75FFF, 0x000C0004, 0x0 },
+       { 0x80C30FFF, 0x000B0000, 0x0 },
+       { 0x00FFFFFF, 0x00040006, 0x0 },
+       { 0x80D75FFF, 0x000B0000, 0x0 },
 };
 
 static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = {
-       { 0x00FFFFFF, 0x0007000E },
-       { 0x00D75FFF, 0x000F000A },
-       { 0x00C30FFF, 0x00060006 },
-       { 0x00AAAFFF, 0x001E0000 },
-       { 0x00FFFFFF, 0x000F000A },
-       { 0x00D75FFF, 0x00160004 },
-       { 0x00C30FFF, 0x001E0000 },
-       { 0x00FFFFFF, 0x00060006 },
-       { 0x00D75FFF, 0x001E0000 },
+       { 0x00FFFFFF, 0x0007000E, 0x0 },
+       { 0x00D75FFF, 0x000F000A, 0x0 },
+       { 0x00C30FFF, 0x00060006, 0x0 },
+       { 0x00AAAFFF, 0x001E0000, 0x0 },
+       { 0x00FFFFFF, 0x000F000A, 0x0 },
+       { 0x00D75FFF, 0x00160004, 0x0 },
+       { 0x00C30FFF, 0x001E0000, 0x0 },
+       { 0x00FFFFFF, 0x00060006, 0x0 },
+       { 0x00D75FFF, 0x001E0000, 0x0 },
 };
 
 static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = {
                                        /* Idx  NT mV d T mV d  db      */
-       { 0x00FFFFFF, 0x0006000E },     /* 0:   400     400     0       */
-       { 0x00E79FFF, 0x000E000C },     /* 1:   400     500     2       */
-       { 0x00D75FFF, 0x0005000A },     /* 2:   400     600     3.5     */
-       { 0x00FFFFFF, 0x0005000A },     /* 3:   600     600     0       */
-       { 0x00E79FFF, 0x001D0007 },     /* 4:   600     750     2       */
-       { 0x00D75FFF, 0x000C0004 },     /* 5:   600     900     3.5     */
-       { 0x00FFFFFF, 0x00040006 },     /* 6:   800     800     0       */
-       { 0x80E79FFF, 0x00030002 },     /* 7:   800     1000    2       */
-       { 0x00FFFFFF, 0x00140005 },     /* 8:   850     850     0       */
-       { 0x00FFFFFF, 0x000C0004 },     /* 9:   900     900     0       */
-       { 0x00FFFFFF, 0x001C0003 },     /* 10:  950     950     0       */
-       { 0x80FFFFFF, 0x00030002 },     /* 11:  1000    1000    0       */
+       { 0x00FFFFFF, 0x0006000E, 0x0 },/* 0:   400     400     0       */
+       { 0x00E79FFF, 0x000E000C, 0x0 },/* 1:   400     500     2       */
+       { 0x00D75FFF, 0x0005000A, 0x0 },/* 2:   400     600     3.5     */
+       { 0x00FFFFFF, 0x0005000A, 0x0 },/* 3:   600     600     0       */
+       { 0x00E79FFF, 0x001D0007, 0x0 },/* 4:   600     750     2       */
+       { 0x00D75FFF, 0x000C0004, 0x0 },/* 5:   600     900     3.5     */
+       { 0x00FFFFFF, 0x00040006, 0x0 },/* 6:   800     800     0       */
+       { 0x80E79FFF, 0x00030002, 0x0 },/* 7:   800     1000    2       */
+       { 0x00FFFFFF, 0x00140005, 0x0 },/* 8:   850     850     0       */
+       { 0x00FFFFFF, 0x000C0004, 0x0 },/* 9:   900     900     0       */
+       { 0x00FFFFFF, 0x001C0003, 0x0 },/* 10:  950     950     0       */
+       { 0x80FFFFFF, 0x00030002, 0x0 },/* 11:  1000    1000    0       */
 };
 
 static const struct ddi_buf_trans bdw_ddi_translations_edp[] = {
-       { 0x00FFFFFF, 0x00000012 },
-       { 0x00EBAFFF, 0x00020011 },
-       { 0x00C71FFF, 0x0006000F },
-       { 0x00AAAFFF, 0x000E000A },
-       { 0x00FFFFFF, 0x00020011 },
-       { 0x00DB6FFF, 0x0005000F },
-       { 0x00BEEFFF, 0x000A000C },
-       { 0x00FFFFFF, 0x0005000F },
-       { 0x00DB6FFF, 0x000A000C },
+       { 0x00FFFFFF, 0x00000012, 0x0 },
+       { 0x00EBAFFF, 0x00020011, 0x0 },
+       { 0x00C71FFF, 0x0006000F, 0x0 },
+       { 0x00AAAFFF, 0x000E000A, 0x0 },
+       { 0x00FFFFFF, 0x00020011, 0x0 },
+       { 0x00DB6FFF, 0x0005000F, 0x0 },
+       { 0x00BEEFFF, 0x000A000C, 0x0 },
+       { 0x00FFFFFF, 0x0005000F, 0x0 },
+       { 0x00DB6FFF, 0x000A000C, 0x0 },
 };
 
 static const struct ddi_buf_trans bdw_ddi_translations_dp[] = {
-       { 0x00FFFFFF, 0x0007000E },
-       { 0x00D75FFF, 0x000E000A },
-       { 0x00BEFFFF, 0x00140006 },
-       { 0x80B2CFFF, 0x001B0002 },
-       { 0x00FFFFFF, 0x000E000A },
-       { 0x00DB6FFF, 0x00160005 },
-       { 0x80C71FFF, 0x001A0002 },
-       { 0x00F7DFFF, 0x00180004 },
-       { 0x80D75FFF, 0x001B0002 },
+       { 0x00FFFFFF, 0x0007000E, 0x0 },
+       { 0x00D75FFF, 0x000E000A, 0x0 },
+       { 0x00BEFFFF, 0x00140006, 0x0 },
+       { 0x80B2CFFF, 0x001B0002, 0x0 },
+       { 0x00FFFFFF, 0x000E000A, 0x0 },
+       { 0x00DB6FFF, 0x00160005, 0x0 },
+       { 0x80C71FFF, 0x001A0002, 0x0 },
+       { 0x00F7DFFF, 0x00180004, 0x0 },
+       { 0x80D75FFF, 0x001B0002, 0x0 },
 };
 
 static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = {
-       { 0x00FFFFFF, 0x0001000E },
-       { 0x00D75FFF, 0x0004000A },
-       { 0x00C30FFF, 0x00070006 },
-       { 0x00AAAFFF, 0x000C0000 },
-       { 0x00FFFFFF, 0x0004000A },
-       { 0x00D75FFF, 0x00090004 },
-       { 0x00C30FFF, 0x000C0000 },
-       { 0x00FFFFFF, 0x00070006 },
-       { 0x00D75FFF, 0x000C0000 },
+       { 0x00FFFFFF, 0x0001000E, 0x0 },
+       { 0x00D75FFF, 0x0004000A, 0x0 },
+       { 0x00C30FFF, 0x00070006, 0x0 },
+       { 0x00AAAFFF, 0x000C0000, 0x0 },
+       { 0x00FFFFFF, 0x0004000A, 0x0 },
+       { 0x00D75FFF, 0x00090004, 0x0 },
+       { 0x00C30FFF, 0x000C0000, 0x0 },
+       { 0x00FFFFFF, 0x00070006, 0x0 },
+       { 0x00D75FFF, 0x000C0000, 0x0 },
 };
 
 static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = {
                                        /* Idx  NT mV d T mV df db      */
-       { 0x00FFFFFF, 0x0007000E },     /* 0:   400     400     0       */
-       { 0x00D75FFF, 0x000E000A },     /* 1:   400     600     3.5     */
-       { 0x00BEFFFF, 0x00140006 },     /* 2:   400     800     6       */
-       { 0x00FFFFFF, 0x0009000D },     /* 3:   450     450     0       */
-       { 0x00FFFFFF, 0x000E000A },     /* 4:   600     600     0       */
-       { 0x00D7FFFF, 0x00140006 },     /* 5:   600     800     2.5     */
-       { 0x80CB2FFF, 0x001B0002 },     /* 6:   600     1000    4.5     */
-       { 0x00FFFFFF, 0x00140006 },     /* 7:   800     800     0       */
-       { 0x80E79FFF, 0x001B0002 },     /* 8:   800     1000    2       */
-       { 0x80FFFFFF, 0x001B0002 },     /* 9:   1000    1000    0       */
+       { 0x00FFFFFF, 0x0007000E, 0x0 },/* 0:   400     400     0       */
+       { 0x00D75FFF, 0x000E000A, 0x0 },/* 1:   400     600     3.5     */
+       { 0x00BEFFFF, 0x00140006, 0x0 },/* 2:   400     800     6       */
+       { 0x00FFFFFF, 0x0009000D, 0x0 },/* 3:   450     450     0       */
+       { 0x00FFFFFF, 0x000E000A, 0x0 },/* 4:   600     600     0       */
+       { 0x00D7FFFF, 0x00140006, 0x0 },/* 5:   600     800     2.5     */
+       { 0x80CB2FFF, 0x001B0002, 0x0 },/* 6:   600     1000    4.5     */
+       { 0x00FFFFFF, 0x00140006, 0x0 },/* 7:   800     800     0       */
+       { 0x80E79FFF, 0x001B0002, 0x0 },/* 8:   800     1000    2       */
+       { 0x80FFFFFF, 0x001B0002, 0x0 },/* 9:   1000    1000    0       */
 };
 
+/* Skylake H and S */
 static const struct ddi_buf_trans skl_ddi_translations_dp[] = {
-       { 0x00000018, 0x000000a2 },
-       { 0x00004014, 0x0000009B },
-       { 0x00006012, 0x00000088 },
-       { 0x00008010, 0x00000087 },
-       { 0x00000018, 0x0000009B },
-       { 0x00004014, 0x00000088 },
-       { 0x00006012, 0x00000087 },
-       { 0x00000018, 0x00000088 },
-       { 0x00004014, 0x00000087 },
+       { 0x00002016, 0x000000A0, 0x0 },
+       { 0x00005012, 0x0000009B, 0x0 },
+       { 0x00007011, 0x00000088, 0x0 },
+       { 0x00009010, 0x000000C7, 0x0 },
+       { 0x00002016, 0x0000009B, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x00007011, 0x000000C7, 0x0 },
+       { 0x00002016, 0x000000DF, 0x0 },
+       { 0x00005012, 0x000000C7, 0x0 },
 };
 
-/* eDP 1.4 low vswing translation parameters */
+/* Skylake U */
+static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = {
+       { 0x0000201B, 0x000000A2, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x00007011, 0x00000087, 0x0 },
+       { 0x80009010, 0x000000C7, 0x1 },        /* Uses I_boost level 0x1 */
+       { 0x0000201B, 0x0000009D, 0x0 },
+       { 0x00005012, 0x000000C7, 0x0 },
+       { 0x00007011, 0x000000C7, 0x0 },
+       { 0x00002016, 0x00000088, 0x0 },
+       { 0x00005012, 0x000000C7, 0x0 },
+};
+
+/* Skylake Y */
+static const struct ddi_buf_trans skl_y_ddi_translations_dp[] = {
+       { 0x00000018, 0x000000A2, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x00007011, 0x00000087, 0x0 },
+       { 0x80009010, 0x000000C7, 0x3 },        /* Uses I_boost level 0x3 */
+       { 0x00000018, 0x0000009D, 0x0 },
+       { 0x00005012, 0x000000C7, 0x0 },
+       { 0x00007011, 0x000000C7, 0x0 },
+       { 0x00000018, 0x00000088, 0x0 },
+       { 0x00005012, 0x000000C7, 0x0 },
+};
+
+/*
+ * Skylake H and S
+ * eDP 1.4 low vswing translation parameters
+ */
 static const struct ddi_buf_trans skl_ddi_translations_edp[] = {
-       { 0x00000018, 0x000000a8 },
-       { 0x00002016, 0x000000ab },
-       { 0x00006012, 0x000000a2 },
-       { 0x00008010, 0x00000088 },
-       { 0x00000018, 0x000000ab },
-       { 0x00004014, 0x000000a2 },
-       { 0x00006012, 0x000000a6 },
-       { 0x00000018, 0x000000a2 },
-       { 0x00005013, 0x0000009c },
-       { 0x00000018, 0x00000088 },
+       { 0x00000018, 0x000000A8, 0x0 },
+       { 0x00004013, 0x000000A9, 0x0 },
+       { 0x00007011, 0x000000A2, 0x0 },
+       { 0x00009010, 0x0000009C, 0x0 },
+       { 0x00000018, 0x000000A9, 0x0 },
+       { 0x00006013, 0x000000A2, 0x0 },
+       { 0x00007011, 0x000000A6, 0x0 },
+       { 0x00000018, 0x000000AB, 0x0 },
+       { 0x00007013, 0x0000009F, 0x0 },
+       { 0x00000018, 0x000000DF, 0x0 },
+};
+
+/*
+ * Skylake U
+ * eDP 1.4 low vswing translation parameters
+ */
+static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = {
+       { 0x00000018, 0x000000A8, 0x0 },
+       { 0x00004013, 0x000000A9, 0x0 },
+       { 0x00007011, 0x000000A2, 0x0 },
+       { 0x00009010, 0x0000009C, 0x0 },
+       { 0x00000018, 0x000000A9, 0x0 },
+       { 0x00006013, 0x000000A2, 0x0 },
+       { 0x00007011, 0x000000A6, 0x0 },
+       { 0x00002016, 0x000000AB, 0x0 },
+       { 0x00005013, 0x0000009F, 0x0 },
+       { 0x00000018, 0x000000DF, 0x0 },
 };
 
+/*
+ * Skylake Y
+ * eDP 1.4 low vswing translation parameters
+ */
+static const struct ddi_buf_trans skl_y_ddi_translations_edp[] = {
+       { 0x00000018, 0x000000A8, 0x0 },
+       { 0x00004013, 0x000000AB, 0x0 },
+       { 0x00007011, 0x000000A4, 0x0 },
+       { 0x00009010, 0x000000DF, 0x0 },
+       { 0x00000018, 0x000000AA, 0x0 },
+       { 0x00006013, 0x000000A4, 0x0 },
+       { 0x00007011, 0x0000009D, 0x0 },
+       { 0x00000018, 0x000000A0, 0x0 },
+       { 0x00006012, 0x000000DF, 0x0 },
+       { 0x00000018, 0x0000008A, 0x0 },
+};
 
+/* Skylake U, H and S */
 static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
-                                       /* Idx  NT mV   T mV    db  */
-       { 0x00004014, 0x00000087 },     /* 0:   800     1000    2   */
+       { 0x00000018, 0x000000AC, 0x0 },
+       { 0x00005012, 0x0000009D, 0x0 },
+       { 0x00007011, 0x00000088, 0x0 },
+       { 0x00000018, 0x000000A1, 0x0 },
+       { 0x00000018, 0x00000098, 0x0 },
+       { 0x00004013, 0x00000088, 0x0 },
+       { 0x00006012, 0x00000087, 0x0 },
+       { 0x00000018, 0x000000DF, 0x0 },
+       { 0x00003015, 0x00000087, 0x0 },        /* Default */
+       { 0x00003015, 0x000000C7, 0x0 },
+       { 0x00000018, 0x000000C7, 0x0 },
 };
 
-enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
+/* Skylake Y */
+static const struct ddi_buf_trans skl_y_ddi_translations_hdmi[] = {
+       { 0x00000018, 0x000000A1, 0x0 },
+       { 0x00005012, 0x000000DF, 0x0 },
+       { 0x00007011, 0x00000084, 0x0 },
+       { 0x00000018, 0x000000A4, 0x0 },
+       { 0x00000018, 0x0000009D, 0x0 },
+       { 0x00004013, 0x00000080, 0x0 },
+       { 0x00006013, 0x000000C7, 0x0 },
+       { 0x00000018, 0x0000008A, 0x0 },
+       { 0x00003015, 0x000000C7, 0x0 },        /* Default */
+       { 0x80003015, 0x000000C7, 0x7 },        /* Uses I_boost level 0x7 */
+       { 0x00000018, 0x000000C7, 0x0 },
+};
+
+struct bxt_ddi_buf_trans {
+       u32 margin;     /* swing value */
+       u32 scale;      /* scale value */
+       u32 enable;     /* scale enable */
+       u32 deemphasis;
+       bool default_index; /* true if the entry represents default value */
+};
+
+static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = {
+                                       /* Idx  NT mV diff      db  */
+       { 52,  0x9A, 0, 128, true  },   /* 0:   400             0   */
+       { 78,  0x9A, 0, 85,  false },   /* 1:   400             3.5 */
+       { 104, 0x9A, 0, 64,  false },   /* 2:   400             6   */
+       { 154, 0x9A, 0, 43,  false },   /* 3:   400             9.5 */
+       { 77,  0x9A, 0, 128, false },   /* 4:   600             0   */
+       { 116, 0x9A, 0, 85,  false },   /* 5:   600             3.5 */
+       { 154, 0x9A, 0, 64,  false },   /* 6:   600             6   */
+       { 102, 0x9A, 0, 128, false },   /* 7:   800             0   */
+       { 154, 0x9A, 0, 85,  false },   /* 8:   800             3.5 */
+       { 154, 0x9A, 1, 128, false },   /* 9:   1200            0   */
+};
+
+static const struct bxt_ddi_buf_trans bxt_ddi_translations_edp[] = {
+                                       /* Idx  NT mV diff      db  */
+       { 26, 0, 0, 128, false },       /* 0:   200             0   */
+       { 38, 0, 0, 112, false },       /* 1:   200             1.5 */
+       { 48, 0, 0, 96,  false },       /* 2:   200             4   */
+       { 54, 0, 0, 69,  false },       /* 3:   200             6   */
+       { 32, 0, 0, 128, false },       /* 4:   250             0   */
+       { 48, 0, 0, 104, false },       /* 5:   250             1.5 */
+       { 54, 0, 0, 85,  false },       /* 6:   250             4   */
+       { 43, 0, 0, 128, false },       /* 7:   300             0   */
+       { 54, 0, 0, 101, false },       /* 8:   300             1.5 */
+       { 48, 0, 0, 128, false },       /* 9:   300             0   */
+};
+
+/* BSpec has 2 recommended values - entries 0 and 8.
+ * Using the entry with higher vswing.
+ */
+static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = {
+                                       /* Idx  NT mV diff      db  */
+       { 52,  0x9A, 0, 128, false },   /* 0:   400             0   */
+       { 52,  0x9A, 0, 85,  false },   /* 1:   400             3.5 */
+       { 52,  0x9A, 0, 64,  false },   /* 2:   400             6   */
+       { 42,  0x9A, 0, 43,  false },   /* 3:   400             9.5 */
+       { 77,  0x9A, 0, 128, false },   /* 4:   600             0   */
+       { 77,  0x9A, 0, 85,  false },   /* 5:   600             3.5 */
+       { 77,  0x9A, 0, 64,  false },   /* 6:   600             6   */
+       { 102, 0x9A, 0, 128, false },   /* 7:   800             0   */
+       { 102, 0x9A, 0, 85,  false },   /* 8:   800             3.5 */
+       { 154, 0x9A, 1, 128, true },    /* 9:   1200            0   */
+};
+
+static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
+                                   enum port port, int type);
+
+static void ddi_get_encoder_port(struct intel_encoder *intel_encoder,
+                                struct intel_digital_port **dig_port,
+                                enum port *port)
 {
        struct drm_encoder *encoder = &intel_encoder->base;
-       int type = intel_encoder->type;
 
-       if (type == INTEL_OUTPUT_DP_MST) {
-               struct intel_digital_port *intel_dig_port = enc_to_mst(encoder)->primary;
-               return intel_dig_port->port;
-       } else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP ||
-           type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) {
-               struct intel_digital_port *intel_dig_port =
-                       enc_to_dig_port(encoder);
-               return intel_dig_port->port;
+       switch (intel_encoder->type) {
+       case INTEL_OUTPUT_DP_MST:
+               *dig_port = enc_to_mst(encoder)->primary;
+               *port = (*dig_port)->port;
+               break;
+       case INTEL_OUTPUT_DISPLAYPORT:
+       case INTEL_OUTPUT_EDP:
+       case INTEL_OUTPUT_HDMI:
+       case INTEL_OUTPUT_UNKNOWN:
+               *dig_port = enc_to_dig_port(encoder);
+               *port = (*dig_port)->port;
+               break;
+       case INTEL_OUTPUT_ANALOG:
+               *dig_port = NULL;
+               *port = PORT_E;
+               break;
+       default:
+               WARN(1, "Invalid DDI encoder type %d\n", intel_encoder->type);
+               break;
+       }
+}
 
-       } else if (type == INTEL_OUTPUT_ANALOG) {
-               return PORT_E;
+enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
+{
+       struct intel_digital_port *dig_port;
+       enum port port;
 
+       ddi_get_encoder_port(intel_encoder, &dig_port, &port);
+
+       return port;
+}
+
+static bool
+intel_dig_port_supports_hdmi(const struct intel_digital_port *intel_dig_port)
+{
+       return intel_dig_port->hdmi.hdmi_reg;
+}
+
+static const struct ddi_buf_trans *skl_get_buf_trans_dp(struct drm_device *dev,
+                                                       int *n_entries)
+{
+       const struct ddi_buf_trans *ddi_translations;
+
+       if (IS_SKL_ULX(dev)) {
+               ddi_translations = skl_y_ddi_translations_dp;
+               *n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp);
+       } else if (IS_SKL_ULT(dev)) {
+               ddi_translations = skl_u_ddi_translations_dp;
+               *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp);
        } else {
-               DRM_ERROR("Invalid DDI encoder type %d\n", type);
-               BUG();
+               ddi_translations = skl_ddi_translations_dp;
+               *n_entries = ARRAY_SIZE(skl_ddi_translations_dp);
        }
+
+       return ddi_translations;
+}
+
+static const struct ddi_buf_trans *skl_get_buf_trans_edp(struct drm_device *dev,
+                                                        int *n_entries)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       const struct ddi_buf_trans *ddi_translations;
+
+       if (IS_SKL_ULX(dev)) {
+               if (dev_priv->edp_low_vswing) {
+                       ddi_translations = skl_y_ddi_translations_edp;
+                       *n_entries = ARRAY_SIZE(skl_y_ddi_translations_edp);
+               } else {
+                       ddi_translations = skl_y_ddi_translations_dp;
+                       *n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp);
+               }
+       } else if (IS_SKL_ULT(dev)) {
+               if (dev_priv->edp_low_vswing) {
+                       ddi_translations = skl_u_ddi_translations_edp;
+                       *n_entries = ARRAY_SIZE(skl_u_ddi_translations_edp);
+               } else {
+                       ddi_translations = skl_u_ddi_translations_dp;
+                       *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp);
+               }
+       } else {
+               if (dev_priv->edp_low_vswing) {
+                       ddi_translations = skl_ddi_translations_edp;
+                       *n_entries = ARRAY_SIZE(skl_ddi_translations_edp);
+               } else {
+                       ddi_translations = skl_ddi_translations_dp;
+                       *n_entries = ARRAY_SIZE(skl_ddi_translations_dp);
+               }
+       }
+
+       return ddi_translations;
+}
+
+static const struct ddi_buf_trans *
+skl_get_buf_trans_hdmi(struct drm_device *dev,
+                      int *n_entries)
+{
+       const struct ddi_buf_trans *ddi_translations;
+
+       if (IS_SKL_ULX(dev)) {
+               ddi_translations = skl_y_ddi_translations_hdmi;
+               *n_entries = ARRAY_SIZE(skl_y_ddi_translations_hdmi);
+       } else {
+               ddi_translations = skl_ddi_translations_hdmi;
+               *n_entries = ARRAY_SIZE(skl_ddi_translations_hdmi);
+       }
+
+       return ddi_translations;
 }
 
 /*
@@ -189,10 +426,11 @@ enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
  * in either FDI or DP modes only, as HDMI connections will work with both
  * of those
  */
-static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
+static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
+                                     bool supports_hdmi)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 reg;
+       u32 iboost_bit = 0;
        int i, n_hdmi_entries, n_dp_entries, n_edp_entries, hdmi_default_entry,
            size;
        int hdmi_level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift;
@@ -202,28 +440,27 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
        const struct ddi_buf_trans *ddi_translations_hdmi;
        const struct ddi_buf_trans *ddi_translations;
 
-       if (IS_SKYLAKE(dev)) {
-               ddi_translations_fdi = NULL;
-               ddi_translations_dp = skl_ddi_translations_dp;
-               n_dp_entries = ARRAY_SIZE(skl_ddi_translations_dp);
-               if (dev_priv->vbt.edp_low_vswing) {
-                       ddi_translations_edp = skl_ddi_translations_edp;
-                       n_edp_entries = ARRAY_SIZE(skl_ddi_translations_edp);
-               } else {
-                       ddi_translations_edp = skl_ddi_translations_dp;
-                       n_edp_entries = ARRAY_SIZE(skl_ddi_translations_dp);
-               }
+       if (IS_BROXTON(dev)) {
+               if (!supports_hdmi)
+                       return;
 
-               /*
-                * On SKL, the recommendation from the hw team is to always use
-                * a certain type of level shifter (and thus the corresponding
-                * 800mV+2dB entry). Given that's the only validated entry, we
-                * override what is in the VBT, at least until further notice.
-                */
-               hdmi_level = 0;
-               ddi_translations_hdmi = skl_ddi_translations_hdmi;
-               n_hdmi_entries = ARRAY_SIZE(skl_ddi_translations_hdmi);
-               hdmi_default_entry = 0;
+               /* Vswing programming for HDMI */
+               bxt_ddi_vswing_sequence(dev, hdmi_level, port,
+                                       INTEL_OUTPUT_HDMI);
+               return;
+       } else if (IS_SKYLAKE(dev)) {
+               ddi_translations_fdi = NULL;
+               ddi_translations_dp =
+                               skl_get_buf_trans_dp(dev, &n_dp_entries);
+               ddi_translations_edp =
+                               skl_get_buf_trans_edp(dev, &n_edp_entries);
+               ddi_translations_hdmi =
+                               skl_get_buf_trans_hdmi(dev, &n_hdmi_entries);
+               hdmi_default_entry = 8;
+               /* If we're boosting the current, set bit 31 of trans1 */
+               if (dev_priv->vbt.ddi_port_info[port].hdmi_boost_level ||
+                   dev_priv->vbt.ddi_port_info[port].dp_boost_level)
+                       iboost_bit = 1<<31;
        } else if (IS_BROADWELL(dev)) {
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
@@ -283,23 +520,26 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
                BUG();
        }
 
-       for (i = 0, reg = DDI_BUF_TRANS(port); i < size; i++) {
-               I915_WRITE(reg, ddi_translations[i].trans1);
-               reg += 4;
-               I915_WRITE(reg, ddi_translations[i].trans2);
-               reg += 4;
+       for (i = 0; i < size; i++) {
+               I915_WRITE(DDI_BUF_TRANS_LO(port, i),
+                          ddi_translations[i].trans1 | iboost_bit);
+               I915_WRITE(DDI_BUF_TRANS_HI(port, i),
+                          ddi_translations[i].trans2);
        }
 
+       if (!supports_hdmi)
+               return;
+
        /* Choose a good default if VBT is badly populated */
        if (hdmi_level == HDMI_LEVEL_SHIFT_UNKNOWN ||
            hdmi_level >= n_hdmi_entries)
                hdmi_level = hdmi_default_entry;
 
        /* Entry 9 is for HDMI: */
-       I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans1);
-       reg += 4;
-       I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans2);
-       reg += 4;
+       I915_WRITE(DDI_BUF_TRANS_LO(port, i),
+                  ddi_translations_hdmi[hdmi_level].trans1 | iboost_bit);
+       I915_WRITE(DDI_BUF_TRANS_HI(port, i),
+                  ddi_translations_hdmi[hdmi_level].trans2);
 }
 
 /* Program DDI buffers translations for DP. By default, program ports A-D in DP
@@ -307,13 +547,30 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
  */
 void intel_prepare_ddi(struct drm_device *dev)
 {
-       int port;
+       struct intel_encoder *intel_encoder;
+       bool visited[I915_MAX_PORTS] = { 0, };
 
        if (!HAS_DDI(dev))
                return;
 
-       for (port = PORT_A; port <= PORT_E; port++)
-               intel_prepare_ddi_buffers(dev, port);
+       for_each_intel_encoder(dev, intel_encoder) {
+               struct intel_digital_port *intel_dig_port;
+               enum port port;
+               bool supports_hdmi;
+
+               if (intel_encoder->type == INTEL_OUTPUT_DSI)
+                       continue;
+
+               ddi_get_encoder_port(intel_encoder, &intel_dig_port, &port);
+               if (visited[port])
+                       continue;
+
+               supports_hdmi = intel_dig_port &&
+                               intel_dig_port_supports_hdmi(intel_dig_port);
+
+               intel_prepare_ddi_buffers(dev, port, supports_hdmi);
+               visited[port] = true;
+       }
 }
 
 static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
@@ -322,7 +579,7 @@ static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
        uint32_t reg = DDI_BUF_CTL(port);
        int i;
 
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < 16; i++) {
                udelay(1);
                if (I915_READ(reg) & DDI_BUF_IS_IDLE)
                        return;
@@ -353,7 +610,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
         *
         * WaFDIAutoLinkSetTimingOverrride:hsw
         */
-       I915_WRITE(_FDI_RXA_MISC, FDI_RX_PWRDN_LANE1_VAL(2) |
+       I915_WRITE(FDI_RX_MISC(PIPE_A), FDI_RX_PWRDN_LANE1_VAL(2) |
                                  FDI_RX_PWRDN_LANE0_VAL(2) |
                                  FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
 
@@ -361,13 +618,13 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
        rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE |
                     FDI_RX_PLL_ENABLE |
                     FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
-       I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
-       POSTING_READ(_FDI_RXA_CTL);
+       I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
+       POSTING_READ(FDI_RX_CTL(PIPE_A));
        udelay(220);
 
        /* Switch from Rawclk to PCDclk */
        rx_ctl_val |= FDI_PCDCLK;
-       I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
+       I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
 
        /* Configure Port Clock Select */
        I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config->ddi_pll_sel);
@@ -396,21 +653,21 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
                udelay(600);
 
                /* Program PCH FDI Receiver TU */
-               I915_WRITE(_FDI_RXA_TUSIZE1, TU_SIZE(64));
+               I915_WRITE(FDI_RX_TUSIZE1(PIPE_A), TU_SIZE(64));
 
                /* Enable PCH FDI Receiver with auto-training */
                rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO;
-               I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
-               POSTING_READ(_FDI_RXA_CTL);
+               I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
+               POSTING_READ(FDI_RX_CTL(PIPE_A));
 
                /* Wait for FDI receiver lane calibration */
                udelay(30);
 
                /* Unset FDI_RX_MISC pwrdn lanes */
-               temp = I915_READ(_FDI_RXA_MISC);
+               temp = I915_READ(FDI_RX_MISC(PIPE_A));
                temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
-               I915_WRITE(_FDI_RXA_MISC, temp);
-               POSTING_READ(_FDI_RXA_MISC);
+               I915_WRITE(FDI_RX_MISC(PIPE_A), temp);
+               POSTING_READ(FDI_RX_MISC(PIPE_A));
 
                /* Wait for FDI auto training time */
                udelay(5);
@@ -444,15 +701,15 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
                intel_wait_ddi_buf_idle(dev_priv, PORT_E);
 
                rx_ctl_val &= ~FDI_RX_ENABLE;
-               I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
-               POSTING_READ(_FDI_RXA_CTL);
+               I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
+               POSTING_READ(FDI_RX_CTL(PIPE_A));
 
                /* Reset FDI_RX_MISC pwrdn lanes */
-               temp = I915_READ(_FDI_RXA_MISC);
+               temp = I915_READ(FDI_RX_MISC(PIPE_A));
                temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
                temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
-               I915_WRITE(_FDI_RXA_MISC, temp);
-               POSTING_READ(_FDI_RXA_MISC);
+               I915_WRITE(FDI_RX_MISC(PIPE_A), temp);
+               POSTING_READ(FDI_RX_MISC(PIPE_A));
        }
 
        DRM_ERROR("FDI link training failed!\n");
@@ -467,7 +724,6 @@ void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder)
        intel_dp->DP = intel_dig_port->saved_port_bits |
                DDI_BUF_CTL_ENABLE | DDI_BUF_TRANS_SELECT(0);
        intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
-
 }
 
 static struct intel_encoder *
@@ -491,23 +747,24 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc)
        return ret;
 }
 
-static struct intel_encoder *
+struct intel_encoder *
 intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state)
 {
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
        struct intel_encoder *ret = NULL;
        struct drm_atomic_state *state;
+       struct drm_connector *connector;
+       struct drm_connector_state *connector_state;
        int num_encoders = 0;
        int i;
 
        state = crtc_state->base.state;
 
-       for (i = 0; i < state->num_connector; i++) {
-               if (!state->connectors[i] ||
-                   state->connector_states[i]->crtc != crtc_state->base.crtc)
+       for_each_connector_in_state(state, connector, connector_state, i) {
+               if (connector_state->crtc != crtc_state->base.crtc)
                        continue;
 
-               ret = to_intel_encoder(state->connector_states[i]->best_encoder);
+               ret = to_intel_encoder(connector_state->best_encoder);
                num_encoders++;
        }
 
@@ -537,11 +794,11 @@ intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state)
        (void) (&__a == &__b);                  \
        __a > __b ? (__a - __b) : (__b - __a); })
 
-struct wrpll_rnp {
+struct hsw_wrpll_rnp {
        unsigned p, n2, r2;
 };
 
-static unsigned wrpll_get_budget_for_freq(int clock)
+static unsigned hsw_wrpll_get_budget_for_freq(int clock)
 {
        unsigned budget;
 
@@ -615,9 +872,9 @@ static unsigned wrpll_get_budget_for_freq(int clock)
        return budget;
 }
 
-static void wrpll_update_rnp(uint64_t freq2k, unsigned budget,
-                            unsigned r2, unsigned n2, unsigned p,
-                            struct wrpll_rnp *best)
+static void hsw_wrpll_update_rnp(uint64_t freq2k, unsigned budget,
+                                unsigned r2, unsigned n2, unsigned p,
+                                struct hsw_wrpll_rnp *best)
 {
        uint64_t a, b, c, d, diff, diff_best;
 
@@ -674,8 +931,7 @@ static void wrpll_update_rnp(uint64_t freq2k, unsigned budget,
        /* Otherwise a < c && b >= d, do nothing */
 }
 
-static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
-                                    int reg)
+static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, int reg)
 {
        int refclk = LC_FREQ;
        int n, p, r;
@@ -715,8 +971,8 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv,
        uint32_t cfgcr1_val, cfgcr2_val;
        uint32_t p0, p1, p2, dco_freq;
 
-       cfgcr1_reg = GET_CFG_CR1_REG(dpll);
-       cfgcr2_reg = GET_CFG_CR2_REG(dpll);
+       cfgcr1_reg = DPLL_CFGCR1(dpll);
+       cfgcr2_reg = DPLL_CFGCR2(dpll);
 
        cfgcr1_val = I915_READ(cfgcr1_reg);
        cfgcr2_val = I915_READ(cfgcr2_reg);
@@ -768,6 +1024,26 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv,
        return dco_freq / (p0 * p1 * p2 * 5);
 }
 
+static void ddi_dotclock_get(struct intel_crtc_state *pipe_config)
+{
+       int dotclock;
+
+       if (pipe_config->has_pch_encoder)
+               dotclock = intel_dotclock_calculate(pipe_config->port_clock,
+                                                   &pipe_config->fdi_m_n);
+       else if (pipe_config->has_dp_encoder)
+               dotclock = intel_dotclock_calculate(pipe_config->port_clock,
+                                                   &pipe_config->dp_m_n);
+       else if (pipe_config->has_hdmi_sink && pipe_config->pipe_bpp == 36)
+               dotclock = pipe_config->port_clock * 2 / 3;
+       else
+               dotclock = pipe_config->port_clock;
+
+       if (pipe_config->pixel_multiplier)
+               dotclock /= pipe_config->pixel_multiplier;
+
+       pipe_config->base.adjusted_mode.crtc_clock = dotclock;
+}
 
 static void skl_ddi_clock_get(struct intel_encoder *encoder,
                                struct intel_crtc_state *pipe_config)
@@ -783,26 +1059,26 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder,
        if (dpll_ctl1 & DPLL_CTRL1_HDMI_MODE(dpll)) {
                link_clock = skl_calc_wrpll_link(dev_priv, dpll);
        } else {
-               link_clock = dpll_ctl1 & DPLL_CRTL1_LINK_RATE_MASK(dpll);
-               link_clock >>= DPLL_CRTL1_LINK_RATE_SHIFT(dpll);
+               link_clock = dpll_ctl1 & DPLL_CTRL1_LINK_RATE_MASK(dpll);
+               link_clock >>= DPLL_CTRL1_LINK_RATE_SHIFT(dpll);
 
                switch (link_clock) {
-               case DPLL_CRTL1_LINK_RATE_810:
+               case DPLL_CTRL1_LINK_RATE_810:
                        link_clock = 81000;
                        break;
-               case DPLL_CRTL1_LINK_RATE_1080:
+               case DPLL_CTRL1_LINK_RATE_1080:
                        link_clock = 108000;
                        break;
-               case DPLL_CRTL1_LINK_RATE_1350:
+               case DPLL_CTRL1_LINK_RATE_1350:
                        link_clock = 135000;
                        break;
-               case DPLL_CRTL1_LINK_RATE_1620:
+               case DPLL_CTRL1_LINK_RATE_1620:
                        link_clock = 162000;
                        break;
-               case DPLL_CRTL1_LINK_RATE_2160:
+               case DPLL_CTRL1_LINK_RATE_2160:
                        link_clock = 216000;
                        break;
-               case DPLL_CRTL1_LINK_RATE_2700:
+               case DPLL_CTRL1_LINK_RATE_2700:
                        link_clock = 270000;
                        break;
                default:
@@ -814,12 +1090,7 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder,
 
        pipe_config->port_clock = link_clock;
 
-       if (pipe_config->has_dp_encoder)
-               pipe_config->base.adjusted_mode.crtc_clock =
-                       intel_dotclock_calculate(pipe_config->port_clock,
-                                                &pipe_config->dp_m_n);
-       else
-               pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
+       ddi_dotclock_get(pipe_config);
 }
 
 static void hsw_ddi_clock_get(struct intel_encoder *encoder,
@@ -841,10 +1112,10 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder,
                link_clock = 270000;
                break;
        case PORT_CLK_SEL_WRPLL1:
-               link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1);
+               link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1);
                break;
        case PORT_CLK_SEL_WRPLL2:
-               link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2);
+               link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2);
                break;
        case PORT_CLK_SEL_SPLL:
                pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK;
@@ -866,16 +1137,44 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder,
 
        pipe_config->port_clock = link_clock * 2;
 
-       if (pipe_config->has_pch_encoder)
-               pipe_config->base.adjusted_mode.crtc_clock =
-                       intel_dotclock_calculate(pipe_config->port_clock,
-                                                &pipe_config->fdi_m_n);
-       else if (pipe_config->has_dp_encoder)
-               pipe_config->base.adjusted_mode.crtc_clock =
-                       intel_dotclock_calculate(pipe_config->port_clock,
-                                                &pipe_config->dp_m_n);
-       else
-               pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
+       ddi_dotclock_get(pipe_config);
+}
+
+static int bxt_calc_pll_link(struct drm_i915_private *dev_priv,
+                               enum intel_dpll_id dpll)
+{
+       struct intel_shared_dpll *pll;
+       struct intel_dpll_hw_state *state;
+       intel_clock_t clock;
+
+       /* For DDI ports we always use a shared PLL. */
+       if (WARN_ON(dpll == DPLL_ID_PRIVATE))
+               return 0;
+
+       pll = &dev_priv->shared_dplls[dpll];
+       state = &pll->config.hw_state;
+
+       clock.m1 = 2;
+       clock.m2 = (state->pll0 & PORT_PLL_M2_MASK) << 22;
+       if (state->pll3 & PORT_PLL_M2_FRAC_ENABLE)
+               clock.m2 |= state->pll2 & PORT_PLL_M2_FRAC_MASK;
+       clock.n = (state->pll1 & PORT_PLL_N_MASK) >> PORT_PLL_N_SHIFT;
+       clock.p1 = (state->ebb0 & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT;
+       clock.p2 = (state->ebb0 & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT;
+
+       return chv_calc_dpll_params(100000, &clock);
+}
+
+static void bxt_ddi_clock_get(struct intel_encoder *encoder,
+                               struct intel_crtc_state *pipe_config)
+{
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       enum port port = intel_ddi_get_encoder_port(encoder);
+       uint32_t dpll = port;
+
+       pipe_config->port_clock = bxt_calc_pll_link(dev_priv, dpll);
+
+       ddi_dotclock_get(pipe_config);
 }
 
 void intel_ddi_clock_get(struct intel_encoder *encoder,
@@ -885,8 +1184,10 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 
        if (INTEL_INFO(dev)->gen <= 8)
                hsw_ddi_clock_get(encoder, pipe_config);
-       else
+       else if (IS_SKYLAKE(dev))
                skl_ddi_clock_get(encoder, pipe_config);
+       else if (IS_BROXTON(dev))
+               bxt_ddi_clock_get(encoder, pipe_config);
 }
 
 static void
@@ -895,12 +1196,12 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */,
 {
        uint64_t freq2k;
        unsigned p, n2, r2;
-       struct wrpll_rnp best = { 0, 0, 0 };
+       struct hsw_wrpll_rnp best = { 0, 0, 0 };
        unsigned budget;
 
        freq2k = clock / 100;
 
-       budget = wrpll_get_budget_for_freq(clock);
+       budget = hsw_wrpll_get_budget_for_freq(clock);
 
        /* Special case handling for 540 pixel clock: bypass WR PLL entirely
         * and directly pass the LC PLL to it. */
@@ -944,8 +1245,8 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */,
                     n2++) {
 
                        for (p = P_MIN; p <= P_MAX; p += P_INC)
-                               wrpll_update_rnp(freq2k, budget,
-                                                r2, n2, p, &best);
+                               hsw_wrpll_update_rnp(freq2k, budget,
+                                                    r2, n2, p, &best);
                }
        }
 
@@ -957,9 +1258,10 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */,
 static bool
 hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
                   struct intel_crtc_state *crtc_state,
-                  struct intel_encoder *intel_encoder,
-                  int clock)
+                  struct intel_encoder *intel_encoder)
 {
+       int clock = crtc_state->port_clock;
+
        if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
                struct intel_shared_dpll *pll;
                uint32_t val;
@@ -971,6 +1273,9 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
                      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
                      WRPLL_DIVIDER_POST(p);
 
+               memset(&crtc_state->dpll_hw_state, 0,
+                      sizeof(crtc_state->dpll_hw_state));
+
                crtc_state->dpll_hw_state.wrpll = val;
 
                pll = intel_get_shared_dpll(intel_crtc, crtc_state);
@@ -981,11 +1286,119 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
                }
 
                crtc_state->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id);
+       } else if (crtc_state->ddi_pll_sel == PORT_CLK_SEL_SPLL) {
+               struct drm_atomic_state *state = crtc_state->base.state;
+               struct intel_shared_dpll_config *spll =
+                       &intel_atomic_get_shared_dpll_state(state)[DPLL_ID_SPLL];
+
+               if (spll->crtc_mask &&
+                   WARN_ON(spll->hw_state.spll != crtc_state->dpll_hw_state.spll))
+                       return false;
+
+               crtc_state->shared_dpll = DPLL_ID_SPLL;
+               spll->hw_state.spll = crtc_state->dpll_hw_state.spll;
+               spll->crtc_mask |= 1 << intel_crtc->pipe;
        }
 
        return true;
 }
 
+struct skl_wrpll_context {
+       uint64_t min_deviation;         /* current minimal deviation */
+       uint64_t central_freq;          /* chosen central freq */
+       uint64_t dco_freq;              /* chosen dco freq */
+       unsigned int p;                 /* chosen divider */
+};
+
+static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
+{
+       memset(ctx, 0, sizeof(*ctx));
+
+       ctx->min_deviation = U64_MAX;
+}
+
+/* DCO freq must be within +1%/-6%  of the DCO central freq */
+#define SKL_DCO_MAX_PDEVIATION 100
+#define SKL_DCO_MAX_NDEVIATION 600
+
+static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
+                                 uint64_t central_freq,
+                                 uint64_t dco_freq,
+                                 unsigned int divider)
+{
+       uint64_t deviation;
+
+       deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
+                             central_freq);
+
+       /* positive deviation */
+       if (dco_freq >= central_freq) {
+               if (deviation < SKL_DCO_MAX_PDEVIATION &&
+                   deviation < ctx->min_deviation) {
+                       ctx->min_deviation = deviation;
+                       ctx->central_freq = central_freq;
+                       ctx->dco_freq = dco_freq;
+                       ctx->p = divider;
+               }
+       /* negative deviation */
+       } else if (deviation < SKL_DCO_MAX_NDEVIATION &&
+                  deviation < ctx->min_deviation) {
+               ctx->min_deviation = deviation;
+               ctx->central_freq = central_freq;
+               ctx->dco_freq = dco_freq;
+               ctx->p = divider;
+       }
+}
+
+static void skl_wrpll_get_multipliers(unsigned int p,
+                                     unsigned int *p0 /* out */,
+                                     unsigned int *p1 /* out */,
+                                     unsigned int *p2 /* out */)
+{
+       /* even dividers */
+       if (p % 2 == 0) {
+               unsigned int half = p / 2;
+
+               if (half == 1 || half == 2 || half == 3 || half == 5) {
+                       *p0 = 2;
+                       *p1 = 1;
+                       *p2 = half;
+               } else if (half % 2 == 0) {
+                       *p0 = 2;
+                       *p1 = half / 2;
+                       *p2 = 2;
+               } else if (half % 3 == 0) {
+                       *p0 = 3;
+                       *p1 = half / 3;
+                       *p2 = 2;
+               } else if (half % 7 == 0) {
+                       *p0 = 7;
+                       *p1 = half / 7;
+                       *p2 = 2;
+               }
+       } else if (p == 3 || p == 9) {  /* 3, 5, 7, 9, 15, 21, 35 */
+               *p0 = 3;
+               *p1 = 1;
+               *p2 = p / 3;
+       } else if (p == 5 || p == 7) {
+               *p0 = p;
+               *p1 = 1;
+               *p2 = 1;
+       } else if (p == 15) {
+               *p0 = 3;
+               *p1 = 1;
+               *p2 = 5;
+       } else if (p == 21) {
+               *p0 = 7;
+               *p1 = 1;
+               *p2 = 3;
+       } else if (p == 35) {
+               *p0 = 7;
+               *p1 = 1;
+               *p2 = 5;
+       }
+}
+
 struct skl_wrpll_params {
        uint32_t        dco_fraction;
        uint32_t        dco_integer;
@@ -996,159 +1409,154 @@ struct skl_wrpll_params {
        uint32_t        central_freq;
 };
 
-static void
-skl_ddi_calculate_wrpll(int clock /* in Hz */,
-                       struct skl_wrpll_params *wrpll_params)
+static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
+                                     uint64_t afe_clock,
+                                     uint64_t central_freq,
+                                     uint32_t p0, uint32_t p1, uint32_t p2)
 {
-       uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
-       uint64_t dco_central_freq[3] = {8400000000ULL,
-                                       9000000000ULL,
-                                       9600000000ULL};
-       uint32_t min_dco_deviation = 400;
-       uint32_t min_dco_index = 3;
-       uint32_t P0[4] = {1, 2, 3, 7};
-       uint32_t P2[4] = {1, 2, 3, 5};
-       bool found = false;
-       uint32_t candidate_p = 0;
-       uint32_t candidate_p0[3] = {0}, candidate_p1[3] = {0};
-       uint32_t candidate_p2[3] = {0};
-       uint32_t dco_central_freq_deviation[3];
-       uint32_t i, P1, k, dco_count;
-       bool retry_with_odd = false;
        uint64_t dco_freq;
 
-       /* Determine P0, P1 or P2 */
-       for (dco_count = 0; dco_count < 3; dco_count++) {
-               found = false;
-               candidate_p =
-                       div64_u64(dco_central_freq[dco_count], afe_clock);
-               if (retry_with_odd == false)
-                       candidate_p = (candidate_p % 2 == 0 ?
-                               candidate_p : candidate_p + 1);
-
-               for (P1 = 1; P1 < candidate_p; P1++) {
-                       for (i = 0; i < 4; i++) {
-                               if (!(P0[i] != 1 || P1 == 1))
-                                       continue;
-
-                               for (k = 0; k < 4; k++) {
-                                       if (P1 != 1 && P2[k] != 2)
-                                               continue;
-
-                                       if (candidate_p == P0[i] * P1 * P2[k]) {
-                                               /* Found possible P0, P1, P2 */
-                                               found = true;
-                                               candidate_p0[dco_count] = P0[i];
-                                               candidate_p1[dco_count] = P1;
-                                               candidate_p2[dco_count] = P2[k];
-                                               goto found;
-                                       }
-
-                               }
-                       }
-               }
-
-found:
-               if (found) {
-                       dco_central_freq_deviation[dco_count] =
-                               div64_u64(10000 *
-                                         abs_diff((candidate_p * afe_clock),
-                                                  dco_central_freq[dco_count]),
-                                         dco_central_freq[dco_count]);
-
-                       if (dco_central_freq_deviation[dco_count] <
-                               min_dco_deviation) {
-                               min_dco_deviation =
-                                       dco_central_freq_deviation[dco_count];
-                               min_dco_index = dco_count;
-                       }
-               }
+       switch (central_freq) {
+       case 9600000000ULL:
+               params->central_freq = 0;
+               break;
+       case 9000000000ULL:
+               params->central_freq = 1;
+               break;
+       case 8400000000ULL:
+               params->central_freq = 3;
+       }
 
-               if (min_dco_index > 2 && dco_count == 2) {
-                       retry_with_odd = true;
-                       dco_count = 0;
-               }
+       switch (p0) {
+       case 1:
+               params->pdiv = 0;
+               break;
+       case 2:
+               params->pdiv = 1;
+               break;
+       case 3:
+               params->pdiv = 2;
+               break;
+       case 7:
+               params->pdiv = 4;
+               break;
+       default:
+               WARN(1, "Incorrect PDiv\n");
        }
 
-       if (min_dco_index > 2) {
-               WARN(1, "No valid values found for the given pixel clock\n");
-       } else {
-                wrpll_params->central_freq = dco_central_freq[min_dco_index];
+       switch (p2) {
+       case 5:
+               params->kdiv = 0;
+               break;
+       case 2:
+               params->kdiv = 1;
+               break;
+       case 3:
+               params->kdiv = 2;
+               break;
+       case 1:
+               params->kdiv = 3;
+               break;
+       default:
+               WARN(1, "Incorrect KDiv\n");
+       }
 
-                switch (dco_central_freq[min_dco_index]) {
-                case 9600000000ULL:
-                       wrpll_params->central_freq = 0;
-                       break;
-                case 9000000000ULL:
-                       wrpll_params->central_freq = 1;
-                       break;
-                case 8400000000ULL:
-                       wrpll_params->central_freq = 3;
-                }
+       params->qdiv_ratio = p1;
+       params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
 
-                switch (candidate_p0[min_dco_index]) {
-                case 1:
-                       wrpll_params->pdiv = 0;
-                       break;
-                case 2:
-                       wrpll_params->pdiv = 1;
-                       break;
-                case 3:
-                       wrpll_params->pdiv = 2;
-                       break;
-                case 7:
-                       wrpll_params->pdiv = 4;
-                       break;
-                default:
-                       WARN(1, "Incorrect PDiv\n");
-                }
+       dco_freq = p0 * p1 * p2 * afe_clock;
 
-                switch (candidate_p2[min_dco_index]) {
-                case 5:
-                       wrpll_params->kdiv = 0;
-                       break;
-                case 2:
-                       wrpll_params->kdiv = 1;
-                       break;
-                case 3:
-                       wrpll_params->kdiv = 2;
-                       break;
-                case 1:
-                       wrpll_params->kdiv = 3;
-                       break;
-                default:
-                       WARN(1, "Incorrect KDiv\n");
-                }
-
-                wrpll_params->qdiv_ratio = candidate_p1[min_dco_index];
-                wrpll_params->qdiv_mode =
-                       (wrpll_params->qdiv_ratio == 1) ? 0 : 1;
+       /*
+        * Intermediate values are in Hz.
+        * Divide by MHz to match bsepc
+        */
+       params->dco_integer = div_u64(dco_freq, 24 * MHz(1));
+       params->dco_fraction =
+               div_u64((div_u64(dco_freq, 24) -
+                        params->dco_integer * MHz(1)) * 0x8000, MHz(1));
+}
 
-                dco_freq = candidate_p0[min_dco_index] *
-                        candidate_p1[min_dco_index] *
-                        candidate_p2[min_dco_index] * afe_clock;
+static bool
+skl_ddi_calculate_wrpll(int clock /* in Hz */,
+                       struct skl_wrpll_params *wrpll_params)
+{
+       uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
+       uint64_t dco_central_freq[3] = {8400000000ULL,
+                                       9000000000ULL,
+                                       9600000000ULL};
+       static const int even_dividers[] = {  4,  6,  8, 10, 12, 14, 16, 18, 20,
+                                            24, 28, 30, 32, 36, 40, 42, 44,
+                                            48, 52, 54, 56, 60, 64, 66, 68,
+                                            70, 72, 76, 78, 80, 84, 88, 90,
+                                            92, 96, 98 };
+       static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
+       static const struct {
+               const int *list;
+               int n_dividers;
+       } dividers[] = {
+               { even_dividers, ARRAY_SIZE(even_dividers) },
+               { odd_dividers, ARRAY_SIZE(odd_dividers) },
+       };
+       struct skl_wrpll_context ctx;
+       unsigned int dco, d, i;
+       unsigned int p0, p1, p2;
+
+       skl_wrpll_context_init(&ctx);
+
+       for (d = 0; d < ARRAY_SIZE(dividers); d++) {
+               for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
+                       for (i = 0; i < dividers[d].n_dividers; i++) {
+                               unsigned int p = dividers[d].list[i];
+                               uint64_t dco_freq = p * afe_clock;
+
+                               skl_wrpll_try_divider(&ctx,
+                                                     dco_central_freq[dco],
+                                                     dco_freq,
+                                                     p);
+                               /*
+                                * Skip the remaining dividers if we're sure to
+                                * have found the definitive divider, we can't
+                                * improve a 0 deviation.
+                                */
+                               if (ctx.min_deviation == 0)
+                                       goto skip_remaining_dividers;
+                       }
+               }
 
+skip_remaining_dividers:
                /*
-               * Intermediate values are in Hz.
-               * Divide by MHz to match bsepc
-               */
-                wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1)));
-                wrpll_params->dco_fraction =
-                        div_u64(((div_u64(dco_freq, 24) -
-                                  wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1));
+                * If a solution is found with an even divider, prefer
+                * this one.
+                */
+               if (d == 0 && ctx.p)
+                       break;
+       }
 
+       if (!ctx.p) {
+               DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock);
+               return false;
        }
-}
 
+       /*
+        * gcc incorrectly analyses that these can be used without being
+        * initialized. To be fair, it's hard to guess.
+        */
+       p0 = p1 = p2 = 0;
+       skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2);
+       skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq,
+                                 p0, p1, p2);
+
+       return true;
+}
 
 static bool
 skl_ddi_pll_select(struct intel_crtc *intel_crtc,
                   struct intel_crtc_state *crtc_state,
-                  struct intel_encoder *intel_encoder,
-                  int clock)
+                  struct intel_encoder *intel_encoder)
 {
        struct intel_shared_dpll *pll;
        uint32_t ctrl1, cfgcr1, cfgcr2;
+       int clock = crtc_state->port_clock;
 
        /*
         * See comment in intel_dpll_hw_state to understand why we always use 0
@@ -1162,7 +1570,8 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
 
                ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
 
-               skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params);
+               if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
+                       return false;
 
                cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
                         DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
@@ -1173,19 +1582,17 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
                         DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
                         DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
                         wrpll_params.central_freq;
-       } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
-               struct drm_encoder *encoder = &intel_encoder->base;
-               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-
-               switch (intel_dp->link_bw) {
-               case DP_LINK_BW_1_62:
-                       ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_810, 0);
+       } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+                  intel_encoder->type == INTEL_OUTPUT_DP_MST) {
+               switch (crtc_state->port_clock / 2) {
+               case 81000:
+                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
                        break;
-               case DP_LINK_BW_2_7:
-                       ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1350, 0);
+               case 135000:
+                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
                        break;
-               case DP_LINK_BW_5_4:
-                       ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_2700, 0);
+               case 270000:
+                       ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
                        break;
                }
 
@@ -1193,6 +1600,9 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
        } else /* eDP */
                return true;
 
+       memset(&crtc_state->dpll_hw_state, 0,
+              sizeof(crtc_state->dpll_hw_state));
+
        crtc_state->dpll_hw_state.ctrl1 = ctrl1;
        crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
        crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
@@ -1210,6 +1620,153 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
        return true;
 }
 
+/* bxt clock parameters */
+struct bxt_clk_div {
+       int clock;
+       uint32_t p1;
+       uint32_t p2;
+       uint32_t m2_int;
+       uint32_t m2_frac;
+       bool m2_frac_en;
+       uint32_t n;
+};
+
+/* pre-calculated values for DP linkrates */
+static const struct bxt_clk_div bxt_dp_clk_val[] = {
+       {162000, 4, 2, 32, 1677722, 1, 1},
+       {270000, 4, 1, 27,       0, 0, 1},
+       {540000, 2, 1, 27,       0, 0, 1},
+       {216000, 3, 2, 32, 1677722, 1, 1},
+       {243000, 4, 1, 24, 1258291, 1, 1},
+       {324000, 4, 1, 32, 1677722, 1, 1},
+       {432000, 3, 1, 32, 1677722, 1, 1}
+};
+
+static bool
+bxt_ddi_pll_select(struct intel_crtc *intel_crtc,
+                  struct intel_crtc_state *crtc_state,
+                  struct intel_encoder *intel_encoder)
+{
+       struct intel_shared_dpll *pll;
+       struct bxt_clk_div clk_div = {0};
+       int vco = 0;
+       uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
+       uint32_t lanestagger;
+       int clock = crtc_state->port_clock;
+
+       if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
+               intel_clock_t best_clock;
+
+               /* Calculate HDMI div */
+               /*
+                * FIXME: tie the following calculation into
+                * i9xx_crtc_compute_clock
+                */
+               if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
+                       DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
+                                        clock, pipe_name(intel_crtc->pipe));
+                       return false;
+               }
+
+               clk_div.p1 = best_clock.p1;
+               clk_div.p2 = best_clock.p2;
+               WARN_ON(best_clock.m1 != 2);
+               clk_div.n = best_clock.n;
+               clk_div.m2_int = best_clock.m2 >> 22;
+               clk_div.m2_frac = best_clock.m2 & ((1 << 22) - 1);
+               clk_div.m2_frac_en = clk_div.m2_frac != 0;
+
+               vco = best_clock.vco;
+       } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+                       intel_encoder->type == INTEL_OUTPUT_EDP) {
+               int i;
+
+               clk_div = bxt_dp_clk_val[0];
+               for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
+                       if (bxt_dp_clk_val[i].clock == clock) {
+                               clk_div = bxt_dp_clk_val[i];
+                               break;
+                       }
+               }
+               vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2;
+       }
+
+       if (vco >= 6200000 && vco <= 6700000) {
+               prop_coef = 4;
+               int_coef = 9;
+               gain_ctl = 3;
+               targ_cnt = 8;
+       } else if ((vco > 5400000 && vco < 6200000) ||
+                       (vco >= 4800000 && vco < 5400000)) {
+               prop_coef = 5;
+               int_coef = 11;
+               gain_ctl = 3;
+               targ_cnt = 9;
+       } else if (vco == 5400000) {
+               prop_coef = 3;
+               int_coef = 8;
+               gain_ctl = 1;
+               targ_cnt = 9;
+       } else {
+               DRM_ERROR("Invalid VCO\n");
+               return false;
+       }
+
+       memset(&crtc_state->dpll_hw_state, 0,
+              sizeof(crtc_state->dpll_hw_state));
+
+       if (clock > 270000)
+               lanestagger = 0x18;
+       else if (clock > 135000)
+               lanestagger = 0x0d;
+       else if (clock > 67000)
+               lanestagger = 0x07;
+       else if (clock > 33000)
+               lanestagger = 0x04;
+       else
+               lanestagger = 0x02;
+
+       crtc_state->dpll_hw_state.ebb0 =
+               PORT_PLL_P1(clk_div.p1) | PORT_PLL_P2(clk_div.p2);
+       crtc_state->dpll_hw_state.pll0 = clk_div.m2_int;
+       crtc_state->dpll_hw_state.pll1 = PORT_PLL_N(clk_div.n);
+       crtc_state->dpll_hw_state.pll2 = clk_div.m2_frac;
+
+       if (clk_div.m2_frac_en)
+               crtc_state->dpll_hw_state.pll3 =
+                       PORT_PLL_M2_FRAC_ENABLE;
+
+       crtc_state->dpll_hw_state.pll6 =
+               prop_coef | PORT_PLL_INT_COEFF(int_coef);
+       crtc_state->dpll_hw_state.pll6 |=
+               PORT_PLL_GAIN_CTL(gain_ctl);
+
+       crtc_state->dpll_hw_state.pll8 = targ_cnt;
+
+       crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
+
+       crtc_state->dpll_hw_state.pll10 =
+               PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
+               | PORT_PLL_DCO_AMP_OVR_EN_H;
+
+       crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
+
+       crtc_state->dpll_hw_state.pcsdw12 =
+               LANESTAGGER_STRAP_OVRD | lanestagger;
+
+       pll = intel_get_shared_dpll(intel_crtc, crtc_state);
+       if (pll == NULL) {
+               DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
+                       pipe_name(intel_crtc->pipe));
+               return false;
+       }
+
+       /* shared DPLL id 0 is DPLL A */
+       crtc_state->ddi_pll_sel = pll->id;
+
+       return true;
+}
+
 /*
  * Tries to find a *shared* PLL for the CRTC and store it in
  * intel_crtc->ddi_pll_sel.
@@ -1223,14 +1780,16 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc,
        struct drm_device *dev = intel_crtc->base.dev;
        struct intel_encoder *intel_encoder =
                intel_ddi_get_crtc_new_encoder(crtc_state);
-       int clock = crtc_state->port_clock;
 
        if (IS_SKYLAKE(dev))
                return skl_ddi_pll_select(intel_crtc, crtc_state,
-                                         intel_encoder, clock);
+                                         intel_encoder);
+       else if (IS_BROXTON(dev))
+               return bxt_ddi_pll_select(intel_crtc, crtc_state,
+                                         intel_encoder);
        else
                return hsw_ddi_pll_select(intel_crtc, crtc_state,
-                                         intel_encoder, clock);
+                                         intel_encoder);
 }
 
 void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
@@ -1363,7 +1922,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
                } else
                        temp |= TRANS_DDI_MODE_SELECT_DP_SST;
 
-               temp |= DDI_PORT_WIDTH(intel_dp->lane_count);
+               temp |= DDI_PORT_WIDTH(intel_crtc->config->lane_count);
        } else if (type == INTEL_OUTPUT_DP_MST) {
                struct intel_dp *intel_dp = &enc_to_mst(encoder)->primary->dp;
 
@@ -1372,7 +1931,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
                } else
                        temp |= TRANS_DDI_MODE_SELECT_DP_SST;
 
-               temp |= DDI_PORT_WIDTH(intel_dp->lane_count);
+               temp |= DDI_PORT_WIDTH(intel_crtc->config->lane_count);
        } else {
                WARN(1, "Invalid encoder type %d for pipe %c\n",
                     intel_encoder->type, pipe_name(pipe));
@@ -1499,7 +2058,8 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
 void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
 {
        struct drm_crtc *crtc = &intel_crtc->base;
-       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
        enum port port = intel_ddi_get_encoder_port(intel_encoder);
        enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
@@ -1519,6 +2079,199 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc)
                           TRANS_CLK_SEL_DISABLED);
 }
 
+static void skl_ddi_set_iboost(struct drm_device *dev, u32 level,
+                              enum port port, int type)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       const struct ddi_buf_trans *ddi_translations;
+       uint8_t iboost;
+       uint8_t dp_iboost, hdmi_iboost;
+       int n_entries;
+       u32 reg;
+
+       /* VBT may override standard boost values */
+       dp_iboost = dev_priv->vbt.ddi_port_info[port].dp_boost_level;
+       hdmi_iboost = dev_priv->vbt.ddi_port_info[port].hdmi_boost_level;
+
+       if (type == INTEL_OUTPUT_DISPLAYPORT) {
+               if (dp_iboost) {
+                       iboost = dp_iboost;
+               } else {
+                       ddi_translations = skl_get_buf_trans_dp(dev, &n_entries);
+                       iboost = ddi_translations[port].i_boost;
+               }
+       } else if (type == INTEL_OUTPUT_EDP) {
+               if (dp_iboost) {
+                       iboost = dp_iboost;
+               } else {
+                       ddi_translations = skl_get_buf_trans_edp(dev, &n_entries);
+                       iboost = ddi_translations[port].i_boost;
+               }
+       } else if (type == INTEL_OUTPUT_HDMI) {
+               if (hdmi_iboost) {
+                       iboost = hdmi_iboost;
+               } else {
+                       ddi_translations = skl_get_buf_trans_hdmi(dev, &n_entries);
+                       iboost = ddi_translations[port].i_boost;
+               }
+       } else {
+               return;
+       }
+
+       /* Make sure that the requested I_boost is valid */
+       if (iboost && iboost != 0x1 && iboost != 0x3 && iboost != 0x7) {
+               DRM_ERROR("Invalid I_boost value %u\n", iboost);
+               return;
+       }
+
+       reg = I915_READ(DISPIO_CR_TX_BMU_CR0);
+       reg &= ~BALANCE_LEG_MASK(port);
+       reg &= ~(1 << (BALANCE_LEG_DISABLE_SHIFT + port));
+
+       if (iboost)
+               reg |= iboost << BALANCE_LEG_SHIFT(port);
+       else
+               reg |= 1 << (BALANCE_LEG_DISABLE_SHIFT + port);
+
+       I915_WRITE(DISPIO_CR_TX_BMU_CR0, reg);
+}
+
+static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
+                                   enum port port, int type)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       const struct bxt_ddi_buf_trans *ddi_translations;
+       u32 n_entries, i;
+       uint32_t val;
+
+       if (type == INTEL_OUTPUT_EDP && dev_priv->edp_low_vswing) {
+               n_entries = ARRAY_SIZE(bxt_ddi_translations_edp);
+               ddi_translations = bxt_ddi_translations_edp;
+       } else if (type == INTEL_OUTPUT_DISPLAYPORT
+                       || type == INTEL_OUTPUT_EDP) {
+               n_entries = ARRAY_SIZE(bxt_ddi_translations_dp);
+               ddi_translations = bxt_ddi_translations_dp;
+       } else if (type == INTEL_OUTPUT_HDMI) {
+               n_entries = ARRAY_SIZE(bxt_ddi_translations_hdmi);
+               ddi_translations = bxt_ddi_translations_hdmi;
+       } else {
+               DRM_DEBUG_KMS("Vswing programming not done for encoder %d\n",
+                               type);
+               return;
+       }
+
+       /* Check if default value has to be used */
+       if (level >= n_entries ||
+           (type == INTEL_OUTPUT_HDMI && level == HDMI_LEVEL_SHIFT_UNKNOWN)) {
+               for (i = 0; i < n_entries; i++) {
+                       if (ddi_translations[i].default_index) {
+                               level = i;
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * 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);
+}
+
+static uint32_t translate_signal_level(int signal_levels)
+{
+       uint32_t level;
+
+       switch (signal_levels) {
+       default:
+               DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level: 0x%x\n",
+                             signal_levels);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               level = 0;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               level = 1;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+               level = 2;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3:
+               level = 3;
+               break;
+
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               level = 4;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               level = 5;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+               level = 6;
+               break;
+
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               level = 7;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               level = 8;
+               break;
+
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               level = 9;
+               break;
+       }
+
+       return level;
+}
+
+uint32_t ddi_signal_levels(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = dport->base.base.dev;
+       struct intel_encoder *encoder = &dport->base;
+       uint8_t train_set = intel_dp->train_set[0];
+       int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
+                                        DP_TRAIN_PRE_EMPHASIS_MASK);
+       enum port port = dport->port;
+       uint32_t level;
+
+       level = translate_signal_level(signal_levels);
+
+       if (IS_SKYLAKE(dev))
+               skl_ddi_set_iboost(dev, level, port, encoder->type);
+       else if (IS_BROXTON(dev))
+               bxt_ddi_vswing_sequence(dev, level, port, encoder->type);
+
+       return DDI_BUF_TRANS_SELECT(level);
+}
+
 static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 {
        struct drm_encoder *encoder = &intel_encoder->base;
@@ -1527,6 +2280,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
        struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
        enum port port = intel_ddi_get_encoder_port(intel_encoder);
        int type = intel_encoder->type;
+       int hdmi_level;
 
        if (type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -1548,7 +2302,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 
                        val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) |
                                 DPLL_CTRL1_SSC(dpll) |
-                                DPLL_CRTL1_LINK_RATE_MASK(dpll));
+                                DPLL_CTRL1_LINK_RATE_MASK(dpll));
                        val |= crtc->config->dpll_hw_state.ctrl1 << (dpll * 6);
 
                        I915_WRITE(DPLL_CTRL1, val);
@@ -1565,7 +2319,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 
                I915_WRITE(DPLL_CTRL2, val);
 
-       } else {
+       } else if (INTEL_INFO(dev)->gen < 9) {
                WARN_ON(crtc->config->ddi_pll_sel == PORT_CLK_SEL_NONE);
                I915_WRITE(PORT_CLK_SEL(port), crtc->config->ddi_pll_sel);
        }
@@ -1573,16 +2327,23 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
        if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
+               intel_dp_set_link_params(intel_dp, crtc->config);
+
                intel_ddi_init_dp_buf_reg(intel_encoder);
 
                intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
                intel_dp_start_link_train(intel_dp);
-               intel_dp_complete_link_train(intel_dp);
                if (port != PORT_A || INTEL_INFO(dev)->gen >= 9)
                        intel_dp_stop_link_train(intel_dp);
        } else if (type == INTEL_OUTPUT_HDMI) {
                struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 
+               if (IS_BROXTON(dev)) {
+                       hdmi_level = dev_priv->vbt.
+                               ddi_port_info[port].hdmi_level_shift;
+                       bxt_ddi_vswing_sequence(dev, hdmi_level, port,
+                                       INTEL_OUTPUT_HDMI);
+               }
                intel_hdmi->set_infoframes(encoder,
                                           crtc->config->has_hdmi_sink,
                                           &crtc->config->base.adjusted_mode);
@@ -1624,7 +2385,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
        if (IS_SKYLAKE(dev))
                I915_WRITE(DPLL_CTRL2, (I915_READ(DPLL_CTRL2) |
                                        DPLL_CTRL2_DDI_CLK_OFF(port)));
-       else
+       else if (INTEL_INFO(dev)->gen < 9)
                I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE);
 }
 
@@ -1689,157 +2450,101 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
        }
 }
 
-static int skl_get_cdclk_freq(struct drm_i915_private *dev_priv)
+static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
+                              struct intel_shared_dpll *pll)
 {
-       uint32_t lcpll1 = I915_READ(LCPLL1_CTL);
-       uint32_t cdctl = I915_READ(CDCLK_CTL);
-       uint32_t linkrate;
-
-       if (!(lcpll1 & LCPLL_PLL_ENABLE)) {
-               WARN(1, "LCPLL1 not enabled\n");
-               return 24000; /* 24MHz is the cd freq with NSSC ref */
-       }
-
-       if ((cdctl & CDCLK_FREQ_SEL_MASK) == CDCLK_FREQ_540)
-               return 540000;
-
-       linkrate = (I915_READ(DPLL_CTRL1) &
-                   DPLL_CRTL1_LINK_RATE_MASK(SKL_DPLL0)) >> 1;
-
-       if (linkrate == DPLL_CRTL1_LINK_RATE_2160 ||
-           linkrate == DPLL_CRTL1_LINK_RATE_1080) {
-               /* vco 8640 */
-               switch (cdctl & CDCLK_FREQ_SEL_MASK) {
-               case CDCLK_FREQ_450_432:
-                       return 432000;
-               case CDCLK_FREQ_337_308:
-                       return 308570;
-               case CDCLK_FREQ_675_617:
-                       return 617140;
-               default:
-                       WARN(1, "Unknown cd freq selection\n");
-               }
-       } else {
-               /* vco 8100 */
-               switch (cdctl & CDCLK_FREQ_SEL_MASK) {
-               case CDCLK_FREQ_450_432:
-                       return 450000;
-               case CDCLK_FREQ_337_308:
-                       return 337500;
-               case CDCLK_FREQ_675_617:
-                       return 675000;
-               default:
-                       WARN(1, "Unknown cd freq selection\n");
-               }
-       }
-
-       /* error case, do as if DPLL0 isn't enabled */
-       return 24000;
+       I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll);
+       POSTING_READ(WRPLL_CTL(pll->id));
+       udelay(20);
 }
 
-static int bdw_get_cdclk_freq(struct drm_i915_private *dev_priv)
+static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
+                               struct intel_shared_dpll *pll)
 {
-       uint32_t lcpll = I915_READ(LCPLL_CTL);
-       uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
-
-       if (lcpll & LCPLL_CD_SOURCE_FCLK)
-               return 800000;
-       else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
-               return 450000;
-       else if (freq == LCPLL_CLK_FREQ_450)
-               return 450000;
-       else if (freq == LCPLL_CLK_FREQ_54O_BDW)
-               return 540000;
-       else if (freq == LCPLL_CLK_FREQ_337_5_BDW)
-               return 337500;
-       else
-               return 675000;
+       I915_WRITE(SPLL_CTL, pll->config.hw_state.spll);
+       POSTING_READ(SPLL_CTL);
+       udelay(20);
 }
 
-static int hsw_get_cdclk_freq(struct drm_i915_private *dev_priv)
+static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
+                                 struct intel_shared_dpll *pll)
 {
-       struct drm_device *dev = dev_priv->dev;
-       uint32_t lcpll = I915_READ(LCPLL_CTL);
-       uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
+       uint32_t val;
 
-       if (lcpll & LCPLL_CD_SOURCE_FCLK)
-               return 800000;
-       else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
-               return 450000;
-       else if (freq == LCPLL_CLK_FREQ_450)
-               return 450000;
-       else if (IS_HSW_ULT(dev))
-               return 337500;
-       else
-               return 540000;
+       val = I915_READ(WRPLL_CTL(pll->id));
+       I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE);
+       POSTING_READ(WRPLL_CTL(pll->id));
 }
 
-int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv)
+static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
+                                struct intel_shared_dpll *pll)
 {
-       struct drm_device *dev = dev_priv->dev;
-
-       if (IS_SKYLAKE(dev))
-               return skl_get_cdclk_freq(dev_priv);
-
-       if (IS_BROADWELL(dev))
-               return bdw_get_cdclk_freq(dev_priv);
-
-       /* Haswell */
-       return hsw_get_cdclk_freq(dev_priv);
-}
+       uint32_t val;
 
-static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv,
-                              struct intel_shared_dpll *pll)
-{
-       I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll);
-       POSTING_READ(WRPLL_CTL(pll->id));
-       udelay(20);
+       val = I915_READ(SPLL_CTL);
+       I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
+       POSTING_READ(SPLL_CTL);
 }
 
-static void hsw_ddi_pll_disable(struct drm_i915_private *dev_priv,
-                               struct intel_shared_dpll *pll)
+static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
+                                      struct intel_shared_dpll *pll,
+                                      struct intel_dpll_hw_state *hw_state)
 {
        uint32_t val;
 
+       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+               return false;
+
        val = I915_READ(WRPLL_CTL(pll->id));
-       I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE);
-       POSTING_READ(WRPLL_CTL(pll->id));
+       hw_state->wrpll = val;
+
+       return val & WRPLL_PLL_ENABLE;
 }
 
-static bool hsw_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
-                                    struct intel_shared_dpll *pll,
-                                    struct intel_dpll_hw_state *hw_state)
+static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
+                                     struct intel_shared_dpll *pll,
+                                     struct intel_dpll_hw_state *hw_state)
 {
        uint32_t val;
 
        if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
                return false;
 
-       val = I915_READ(WRPLL_CTL(pll->id));
-       hw_state->wrpll = val;
+       val = I915_READ(SPLL_CTL);
+       hw_state->spll = val;
 
-       return val & WRPLL_PLL_ENABLE;
+       return val & SPLL_PLL_ENABLE;
 }
 
+
 static const char * const hsw_ddi_pll_names[] = {
        "WRPLL 1",
        "WRPLL 2",
+       "SPLL"
 };
 
 static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv)
 {
        int i;
 
-       dev_priv->num_shared_dpll = 2;
+       dev_priv->num_shared_dpll = 3;
 
-       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+       for (i = 0; i < 2; i++) {
                dev_priv->shared_dplls[i].id = i;
                dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
-               dev_priv->shared_dplls[i].disable = hsw_ddi_pll_disable;
-               dev_priv->shared_dplls[i].enable = hsw_ddi_pll_enable;
+               dev_priv->shared_dplls[i].disable = hsw_ddi_wrpll_disable;
+               dev_priv->shared_dplls[i].enable = hsw_ddi_wrpll_enable;
                dev_priv->shared_dplls[i].get_hw_state =
-                       hsw_ddi_pll_get_hw_state;
+                       hsw_ddi_wrpll_get_hw_state;
        }
+
+       /* SPLL is special, but needs to be initialized anyway.. */
+       dev_priv->shared_dplls[i].id = i;
+       dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
+       dev_priv->shared_dplls[i].disable = hsw_ddi_spll_disable;
+       dev_priv->shared_dplls[i].enable = hsw_ddi_spll_enable;
+       dev_priv->shared_dplls[i].get_hw_state = hsw_ddi_spll_get_hw_state;
+
 }
 
 static const char * const skl_ddi_pll_names[] = {
@@ -1857,20 +2562,20 @@ static const struct skl_dpll_regs skl_dpll_regs[3] = {
        {
                /* DPLL 1 */
                .ctl = LCPLL2_CTL,
-               .cfgcr1 = DPLL1_CFGCR1,
-               .cfgcr2 = DPLL1_CFGCR2,
+               .cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
+               .cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
        },
        {
                /* DPLL 2 */
                .ctl = WRPLL_CTL1,
-               .cfgcr1 = DPLL2_CFGCR1,
-               .cfgcr2 = DPLL2_CFGCR2,
+               .cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
+               .cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
        },
        {
                /* DPLL 3 */
                .ctl = WRPLL_CTL2,
-               .cfgcr1 = DPLL3_CFGCR1,
-               .cfgcr2 = DPLL3_CFGCR2,
+               .cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
+               .cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
        },
 };
 
@@ -1887,7 +2592,7 @@ static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
        val = I915_READ(DPLL_CTRL1);
 
        val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) |
-                DPLL_CRTL1_LINK_RATE_MASK(dpll));
+                DPLL_CTRL1_LINK_RATE_MASK(dpll));
        val |= pll->config.hw_state.ctrl1 << (dpll * 6);
 
        I915_WRITE(DPLL_CTRL1, val);
@@ -1963,6 +2668,326 @@ static void skl_shared_dplls_init(struct drm_i915_private *dev_priv)
        }
 }
 
+static void broxton_phy_init(struct drm_i915_private *dev_priv,
+                            enum dpio_phy phy)
+{
+       enum port port;
+       uint32_t 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);
+
+       /* Considering 10ms timeout until BSpec is updated */
+       if (wait_for(I915_READ(BXT_PORT_CL1CM_DW0(phy)) & PHY_POWER_GOOD, 10))
+               DRM_ERROR("timeout during PHY%d power on\n", phy);
+
+       for (port =  (phy == DPIO_PHY0 ? PORT_B : PORT_A);
+            port <= (phy == DPIO_PHY0 ? PORT_C : PORT_A); port++) {
+               int lane;
+
+               for (lane = 0; lane < 4; lane++) {
+                       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 (lane != 1)
+                               val |= LATENCY_OPTIM;
+
+                       I915_WRITE(BXT_PORT_TX_DW14_LN(port, lane), val);
+               }
+       }
+
+       /* 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.
+        */
+       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.
+                */
+               if (wait_for(I915_READ(BXT_PORT_REF_DW3(DPIO_PHY1)) & GRC_DONE,
+                            10))
+                       DRM_ERROR("timeout waiting for PHY1 GRC\n");
+
+               val = I915_READ(BXT_PORT_REF_DW6(DPIO_PHY1));
+               val = (val & GRC_CODE_MASK) >> GRC_CODE_SHIFT;
+               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);
+}
+
+void broxton_ddi_phy_init(struct drm_device *dev)
+{
+       /* Enable PHY1 first since it provides Rcomp for PHY0 */
+       broxton_phy_init(dev->dev_private, DPIO_PHY1);
+       broxton_phy_init(dev->dev_private, DPIO_PHY0);
+}
+
+static void broxton_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);
+}
+
+void broxton_ddi_phy_uninit(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       broxton_phy_uninit(dev_priv, DPIO_PHY1);
+       broxton_phy_uninit(dev_priv, DPIO_PHY0);
+
+       /* FIXME: do this in broxton_phy_uninit per phy */
+       I915_WRITE(BXT_P_CR_GT_DISP_PWRON, 0);
+}
+
+static const char * const bxt_ddi_pll_names[] = {
+       "PORT PLL A",
+       "PORT PLL B",
+       "PORT PLL C",
+};
+
+static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
+                               struct intel_shared_dpll *pll)
+{
+       uint32_t temp;
+       enum port port = (enum port)pll->id;    /* 1:1 port->PLL mapping */
+
+       temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
+       temp &= ~PORT_PLL_REF_SEL;
+       /* Non-SSC reference */
+       I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
+
+       /* Disable 10 bit clock */
+       temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
+       temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
+       I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
+
+       /* Write P1 & P2 */
+       temp = I915_READ(BXT_PORT_PLL_EBB_0(port));
+       temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK);
+       temp |= pll->config.hw_state.ebb0;
+       I915_WRITE(BXT_PORT_PLL_EBB_0(port), temp);
+
+       /* Write M2 integer */
+       temp = I915_READ(BXT_PORT_PLL(port, 0));
+       temp &= ~PORT_PLL_M2_MASK;
+       temp |= pll->config.hw_state.pll0;
+       I915_WRITE(BXT_PORT_PLL(port, 0), temp);
+
+       /* Write N */
+       temp = I915_READ(BXT_PORT_PLL(port, 1));
+       temp &= ~PORT_PLL_N_MASK;
+       temp |= pll->config.hw_state.pll1;
+       I915_WRITE(BXT_PORT_PLL(port, 1), temp);
+
+       /* Write M2 fraction */
+       temp = I915_READ(BXT_PORT_PLL(port, 2));
+       temp &= ~PORT_PLL_M2_FRAC_MASK;
+       temp |= pll->config.hw_state.pll2;
+       I915_WRITE(BXT_PORT_PLL(port, 2), temp);
+
+       /* Write M2 fraction enable */
+       temp = I915_READ(BXT_PORT_PLL(port, 3));
+       temp &= ~PORT_PLL_M2_FRAC_ENABLE;
+       temp |= pll->config.hw_state.pll3;
+       I915_WRITE(BXT_PORT_PLL(port, 3), temp);
+
+       /* Write coeff */
+       temp = I915_READ(BXT_PORT_PLL(port, 6));
+       temp &= ~PORT_PLL_PROP_COEFF_MASK;
+       temp &= ~PORT_PLL_INT_COEFF_MASK;
+       temp &= ~PORT_PLL_GAIN_CTL_MASK;
+       temp |= pll->config.hw_state.pll6;
+       I915_WRITE(BXT_PORT_PLL(port, 6), temp);
+
+       /* Write calibration val */
+       temp = I915_READ(BXT_PORT_PLL(port, 8));
+       temp &= ~PORT_PLL_TARGET_CNT_MASK;
+       temp |= pll->config.hw_state.pll8;
+       I915_WRITE(BXT_PORT_PLL(port, 8), temp);
+
+       temp = I915_READ(BXT_PORT_PLL(port, 9));
+       temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK;
+       temp |= pll->config.hw_state.pll9;
+       I915_WRITE(BXT_PORT_PLL(port, 9), temp);
+
+       temp = I915_READ(BXT_PORT_PLL(port, 10));
+       temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H;
+       temp &= ~PORT_PLL_DCO_AMP_MASK;
+       temp |= pll->config.hw_state.pll10;
+       I915_WRITE(BXT_PORT_PLL(port, 10), temp);
+
+       /* Recalibrate with new settings */
+       temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
+       temp |= PORT_PLL_RECALIBRATE;
+       I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
+       temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
+       temp |= pll->config.hw_state.ebb4;
+       I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
+
+       /* Enable PLL */
+       temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
+       temp |= PORT_PLL_ENABLE;
+       I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
+       POSTING_READ(BXT_PORT_PLL_ENABLE(port));
+
+       if (wait_for_atomic_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) &
+                       PORT_PLL_LOCK), 200))
+               DRM_ERROR("PLL %d not locked\n", port);
+
+       /*
+        * 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.
+        */
+       temp = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
+       temp &= ~LANE_STAGGER_MASK;
+       temp &= ~LANESTAGGER_STRAP_OVRD;
+       temp |= pll->config.hw_state.pcsdw12;
+       I915_WRITE(BXT_PORT_PCS_DW12_GRP(port), temp);
+}
+
+static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv,
+                                       struct intel_shared_dpll *pll)
+{
+       enum port port = (enum port)pll->id;    /* 1:1 port->PLL mapping */
+       uint32_t temp;
+
+       temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
+       temp &= ~PORT_PLL_ENABLE;
+       I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
+       POSTING_READ(BXT_PORT_PLL_ENABLE(port));
+}
+
+static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
+                                       struct intel_shared_dpll *pll,
+                                       struct intel_dpll_hw_state *hw_state)
+{
+       enum port port = (enum port)pll->id;    /* 1:1 port->PLL mapping */
+       uint32_t val;
+
+       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+               return false;
+
+       val = I915_READ(BXT_PORT_PLL_ENABLE(port));
+       if (!(val & PORT_PLL_ENABLE))
+               return false;
+
+       hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
+       hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
+
+       hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(port));
+       hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
+
+       hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0));
+       hw_state->pll0 &= PORT_PLL_M2_MASK;
+
+       hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1));
+       hw_state->pll1 &= PORT_PLL_N_MASK;
+
+       hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2));
+       hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK;
+
+       hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3));
+       hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE;
+
+       hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6));
+       hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK |
+                         PORT_PLL_INT_COEFF_MASK |
+                         PORT_PLL_GAIN_CTL_MASK;
+
+       hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8));
+       hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK;
+
+       hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9));
+       hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK;
+
+       hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10));
+       hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H |
+                          PORT_PLL_DCO_AMP_MASK;
+
+       /*
+        * While we write to the group register to program all lanes at once we
+        * can read only lane registers. We configure all lanes the same way, so
+        * here just read out lanes 0/1 and output a note if lanes 2/3 differ.
+        */
+       hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
+       if (I915_READ(BXT_PORT_PCS_DW12_LN23(port)) != hw_state->pcsdw12)
+               DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n",
+                                hw_state->pcsdw12,
+                                I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
+       hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
+
+       return true;
+}
+
+static void bxt_shared_dplls_init(struct drm_i915_private *dev_priv)
+{
+       int i;
+
+       dev_priv->num_shared_dpll = 3;
+
+       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+               dev_priv->shared_dplls[i].id = i;
+               dev_priv->shared_dplls[i].name = bxt_ddi_pll_names[i];
+               dev_priv->shared_dplls[i].disable = bxt_ddi_pll_disable;
+               dev_priv->shared_dplls[i].enable = bxt_ddi_pll_enable;
+               dev_priv->shared_dplls[i].get_hw_state =
+                       bxt_ddi_pll_get_hw_state;
+       }
+}
+
 void intel_ddi_pll_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1970,15 +2995,23 @@ void intel_ddi_pll_init(struct drm_device *dev)
 
        if (IS_SKYLAKE(dev))
                skl_shared_dplls_init(dev_priv);
+       else if (IS_BROXTON(dev))
+               bxt_shared_dplls_init(dev_priv);
        else
                hsw_shared_dplls_init(dev_priv);
 
-       DRM_DEBUG_KMS("CDCLK running at %dKHz\n",
-                     intel_ddi_get_cdclk_freq(dev_priv));
-
        if (IS_SKYLAKE(dev)) {
+               int cdclk_freq;
+
+               cdclk_freq = dev_priv->display.get_display_clock_speed(dev);
+               dev_priv->skl_boot_cdclk = cdclk_freq;
                if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE))
                        DRM_ERROR("LCPLL1 is disabled\n");
+               else
+                       intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
+       } else if (IS_BROXTON(dev)) {
+               broxton_init_cdclk(dev);
+               broxton_ddi_phy_init(dev);
        } else {
                /*
                 * The LCPLL register should be turned on by the BIOS. For now
@@ -2048,36 +3081,22 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc)
 
        intel_ddi_post_disable(intel_encoder);
 
-       val = I915_READ(_FDI_RXA_CTL);
+       val = I915_READ(FDI_RX_CTL(PIPE_A));
        val &= ~FDI_RX_ENABLE;
-       I915_WRITE(_FDI_RXA_CTL, val);
+       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
 
-       val = I915_READ(_FDI_RXA_MISC);
+       val = I915_READ(FDI_RX_MISC(PIPE_A));
        val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
        val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
-       I915_WRITE(_FDI_RXA_MISC, val);
+       I915_WRITE(FDI_RX_MISC(PIPE_A), val);
 
-       val = I915_READ(_FDI_RXA_CTL);
+       val = I915_READ(FDI_RX_CTL(PIPE_A));
        val &= ~FDI_PCDCLK;
-       I915_WRITE(_FDI_RXA_CTL, val);
+       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
 
-       val = I915_READ(_FDI_RXA_CTL);
+       val = I915_READ(FDI_RX_CTL(PIPE_A));
        val &= ~FDI_RX_PLL_ENABLE;
-       I915_WRITE(_FDI_RXA_CTL, val);
-}
-
-static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder)
-{
-       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&intel_encoder->base);
-       int type = intel_dig_port->base.type;
-
-       if (type != INTEL_OUTPUT_DISPLAYPORT &&
-           type != INTEL_OUTPUT_EDP &&
-           type != INTEL_OUTPUT_UNKNOWN) {
-               return;
-       }
-
-       intel_dp_hot_plug(intel_encoder);
+       I915_WRITE(FDI_RX_CTL(PIPE_A), val);
 }
 
 void intel_ddi_get_config(struct intel_encoder *encoder,
@@ -2132,6 +3151,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
        case TRANS_DDI_MODE_SELECT_DP_SST:
        case TRANS_DDI_MODE_SELECT_DP_MST:
                pipe_config->has_dp_encoder = true;
+               pipe_config->lane_count =
+                       ((temp & DDI_PORT_WIDTH_MASK) >> DDI_PORT_WIDTH_SHIFT) + 1;
                intel_dp_get_m_n(intel_crtc, pipe_config);
                break;
        default:
@@ -2241,10 +3262,9 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
                     dev_priv->vbt.ddi_port_info[port].supports_hdmi);
        init_dp = dev_priv->vbt.ddi_port_info[port].supports_dp;
        if (!init_dp && !init_hdmi) {
-               DRM_DEBUG_KMS("VBT says port %c is not DVI/HDMI/DP compatible, assuming it is\n",
+               DRM_DEBUG_KMS("VBT says port %c is not DVI/HDMI/DP compatible, respect it\n",
                              port_name(port));
-               init_hdmi = true;
-               init_dp = true;
+               return;
        }
 
        intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
@@ -2273,14 +3293,21 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
        intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
        intel_encoder->cloneable = 0;
-       intel_encoder->hot_plug = intel_ddi_hot_plug;
 
        if (init_dp) {
                if (!intel_ddi_init_dp_connector(intel_dig_port))
                        goto err;
 
                intel_dig_port->hpd_pulse = intel_dp_hpd_pulse;
-               dev_priv->hpd_irq_port[port] = intel_dig_port;
+               /*
+                * On BXT A0/A1, sw needs to activate DDIA HPD logic and
+                * interrupts to check the external panel connection.
+                */
+               if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0)
+                                        && port == PORT_B)
+                       dev_priv->hotplug.irq_port[PORT_A] = intel_dig_port;
+               else
+                       dev_priv->hotplug.irq_port[port] = intel_dig_port;
        }
 
        /* In theory we don't need the encoder->type check, but leave it just in