drm/i915/skl: Buffer translation improvements
authorDavid Weinehall <david.weinehall@linux.intel.com>
Thu, 25 Jun 2015 08:11:03 +0000 (11:11 +0300)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 30 Jun 2015 10:35:30 +0000 (12:35 +0200)
This patch adds support for 0.85V VccIO on Skylake Y,
separate buffer translation tables for Skylake U,
and support for I_boost for the entries that needs this.

Changes in v2:
* Refactored the code a bit to move all DDI signal level setup to
  intel_ddi.c

Issue: VIZ-5677
Signed-off-by: David Weinehall <david.weinehall@linux.intel.com>
Reviewed-by: Antti Koskipää <antti.koskipaa@linux.intel.com>
[danvet: Apply style polish checkpatch suggested.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h

index 6acc6504863b62bb4680ba9192114de566cec808..64041e788a1c75d41716dcf9f6feef49088a9f73 100644 (file)
@@ -2436,6 +2436,14 @@ struct drm_i915_cmd_table {
 /* ULX machines are also considered ULT. */
 #define IS_HSW_ULX(dev)                (INTEL_DEVID(dev) == 0x0A0E || \
                                 INTEL_DEVID(dev) == 0x0A1E)
+#define IS_SKL_ULT(dev)                (INTEL_DEVID(dev) == 0x1906 || \
+                                INTEL_DEVID(dev) == 0x1913 || \
+                                INTEL_DEVID(dev) == 0x1916 || \
+                                INTEL_DEVID(dev) == 0x1921 || \
+                                INTEL_DEVID(dev) == 0x1926)
+#define IS_SKL_ULX(dev)                (INTEL_DEVID(dev) == 0x190E || \
+                                INTEL_DEVID(dev) == 0x1915 || \
+                                INTEL_DEVID(dev) == 0x191E)
 #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary)
 
 #define SKL_REVID_A0           (0x0)
index 50e6279d7d5626077ecc7bd3f6b46ce276912346..bdef9f7b629e06e00644631d9e699ae7d04be670 100644 (file)
@@ -1384,6 +1384,18 @@ enum skl_disp_power_wells {
                                                        _PORT_TX_DW14_LN0_C) + \
                                         _BXT_LANE_OFFSET(lane))
 
+/* UAIMI scratch pad register 1 */
+#define UAIMI_SPR1                     0x4F074
+/* SKL VccIO mask */
+#define SKL_VCCIO_MASK                 0x1
+/* SKL balance leg register */
+#define DISPIO_CR_TX_BMU_CR0           0x6C00C
+/* I_boost values */
+#define BALANCE_LEG_SHIFT(port)                (8+3*(port))
+#define BALANCE_LEG_MASK(port)         (7<<(8+3*(port)))
+/* Balance leg disable bits */
+#define BALANCE_LEG_DISABLE_SHIFT      23
+
 /*
  * Fence registers
  */
index 42c14870ef4393f54462784001615d41785b7233..b29d103bd706a839f2585fcd766650d61ad4988f 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,134 +39,213 @@ 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, S, and Skylake Y with 0.95V VccIO */
 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[] = {
+       { 0x00002016, 0x000000A2, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x00007011, 0x00000087, 0x0 },
+       { 0x80009010, 0x000000C7, 0x1 },        /* Uses I_boost */
+       { 0x00002016, 0x0000009D, 0x0 },
+       { 0x00005012, 0x000000C7, 0x0 },
+       { 0x00007011, 0x000000C7, 0x0 },
+       { 0x00002016, 0x00000088, 0x0 },
+       { 0x00005012, 0x000000C7, 0x0 },
+};
+
+/* Skylake Y with 0.85V VccIO */
+static const struct ddi_buf_trans skl_y_085v_ddi_translations_dp[] = {
+       { 0x00000018, 0x000000A2, 0x0 },
+       { 0x00005012, 0x00000088, 0x0 },
+       { 0x00007011, 0x00000087, 0x0 },
+       { 0x80009010, 0x000000C7, 0x1 },        /* Uses I_boost */
+       { 0x00000018, 0x0000009D, 0x0 },
+       { 0x00005012, 0x000000C7, 0x0 },
+       { 0x00007011, 0x000000C7, 0x0 },
+       { 0x00000018, 0x00000088, 0x0 },
+       { 0x00005012, 0x000000C7, 0x0 },
+};
+
+/*
+ * Skylake H and S, and Skylake Y with 0.95V VccIO
+ * 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 with 0.95V VccIO
+ * eDP 1.4 low vswing translation parameters
+ */
+static const struct ddi_buf_trans skl_y_085v_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 H, S and U, and Skylake Y with 0.95V VccIO */
 static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
-       { 0x00000018, 0x000000ac },
-       { 0x00005012, 0x0000009d },
-       { 0x00007011, 0x00000088 },
-       { 0x00000018, 0x000000a1 },
-       { 0x00000018, 0x00000098 },
-       { 0x00004013, 0x00000088 },
-       { 0x00006012, 0x00000087 },
-       { 0x00000018, 0x000000df },
-       { 0x00003015, 0x00000087 },
-       { 0x00003015, 0x000000c7 },
-       { 0x00000018, 0x000000c7 },
+       { 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 },
+};
+
+/* Skylake Y with 0.85V VccIO */
+static const struct ddi_buf_trans skl_y_085v_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 */
+       { 0x00000018, 0x000000C7, 0x0 },
 };
 
 struct bxt_ddi_buf_trans {
@@ -190,7 +270,7 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = {
        { 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   */
+       { 154, 0x9A, 1, 128, false },   /* 9:   1200            0   */
 };
 
 /* BSpec has 2 recommended values - entries 0 and 8.
@@ -210,6 +290,9 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = {
        { 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)
@@ -249,6 +332,102 @@ 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)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       const struct ddi_buf_trans *ddi_translations;
+       static int is_095v = -1;
+
+       if (is_095v == -1) {
+               u32 spr1 = I915_READ(UAIMI_SPR1);
+
+               is_095v = spr1 & SKL_VCCIO_MASK;
+       }
+
+       if (IS_SKL_ULX(dev) && !is_095v) {
+               ddi_translations = skl_y_085v_ddi_translations_dp;
+               *n_entries = ARRAY_SIZE(skl_y_085v_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 {
+               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;
+       static int is_095v = -1;
+
+       if (is_095v == -1) {
+               u32 spr1 = I915_READ(UAIMI_SPR1);
+
+               is_095v = spr1 & SKL_VCCIO_MASK;
+       }
+
+       if (IS_SKL_ULX(dev) && !is_095v) {
+               if (dev_priv->edp_low_vswing) {
+                       ddi_translations = skl_y_085v_ddi_translations_edp;
+                       *n_entries =
+                               ARRAY_SIZE(skl_y_085v_ddi_translations_edp);
+               } else {
+                       ddi_translations = skl_y_085v_ddi_translations_dp;
+                       *n_entries =
+                               ARRAY_SIZE(skl_y_085v_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)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       const struct ddi_buf_trans *ddi_translations;
+       static int is_095v = -1;
+
+       if (is_095v == -1) {
+               u32 spr1 = I915_READ(UAIMI_SPR1);
+
+               is_095v = spr1 & SKL_VCCIO_MASK;
+       }
+
+       if (IS_SKL_ULX(dev) && !is_095v) {
+               ddi_translations = skl_y_085v_ddi_translations_hdmi;
+               *n_entries = ARRAY_SIZE(skl_y_085v_ddi_translations_hdmi);
+       } else {
+               ddi_translations = skl_ddi_translations_hdmi;
+               *n_entries = ARRAY_SIZE(skl_ddi_translations_hdmi);
+       }
+
+       return ddi_translations;
+}
+
 /*
  * Starting with Haswell, DDI port buffers must be programmed with correct
  * values in advance. The buffer values are different for FDI and DP modes,
@@ -279,20 +458,13 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
                                        INTEL_OUTPUT_HDMI);
                return;
        } else 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->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);
-               }
-
-               ddi_translations_hdmi = skl_ddi_translations_hdmi;
-               n_hdmi_entries = ARRAY_SIZE(skl_ddi_translations_hdmi);
-               hdmi_default_entry = 7;
+               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;
        } else if (IS_BROADWELL(dev)) {
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
@@ -1883,8 +2055,48 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc)
                           TRANS_CLK_SEL_DISABLED);
 }
 
-void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
-                            enum port port, int type)
+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;
+       int n_entries;
+       u32 reg;
+
+       if (type == INTEL_OUTPUT_DISPLAYPORT) {
+               ddi_translations = skl_get_buf_trans_dp(dev, &n_entries);
+               iboost = ddi_translations[port].i_boost;
+       } else if (type == INTEL_OUTPUT_EDP) {
+               ddi_translations = skl_get_buf_trans_edp(dev, &n_entries);
+               iboost = ddi_translations[port].i_boost;
+       } else if (type == INTEL_OUTPUT_HDMI) {
+               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;
@@ -1944,6 +2156,73 @@ void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
        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;
index c43bff90c47a26e0de69933d00a229d1bee9f758..367f71224c96a20bc48f0f72f57a38969a9407e9 100644 (file)
@@ -3424,92 +3424,6 @@ gen7_edp_signal_levels(uint8_t train_set)
        }
 }
 
-/* Gen7.5's (HSW) DP voltage swing and pre-emphasis control */
-static uint32_t
-hsw_signal_levels(uint8_t train_set)
-{
-       int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
-                                        DP_TRAIN_PRE_EMPHASIS_MASK);
-       switch (signal_levels) {
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
-               return DDI_BUF_TRANS_SELECT(0);
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
-               return DDI_BUF_TRANS_SELECT(1);
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
-               return DDI_BUF_TRANS_SELECT(2);
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3:
-               return DDI_BUF_TRANS_SELECT(3);
-
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
-               return DDI_BUF_TRANS_SELECT(4);
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
-               return DDI_BUF_TRANS_SELECT(5);
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2:
-               return DDI_BUF_TRANS_SELECT(6);
-
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
-               return DDI_BUF_TRANS_SELECT(7);
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
-               return DDI_BUF_TRANS_SELECT(8);
-
-       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0:
-               return DDI_BUF_TRANS_SELECT(9);
-       default:
-               DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
-                             "0x%x\n", signal_levels);
-               return DDI_BUF_TRANS_SELECT(0);
-       }
-}
-
-static void bxt_signal_levels(struct intel_dp *intel_dp)
-{
-       struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
-       enum port port = dport->port;
-       struct drm_device *dev = dport->base.base.dev;
-       struct intel_encoder *encoder = &dport->base;
-       uint8_t train_set = intel_dp->train_set[0];
-       uint32_t level = 0;
-
-       int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
-                                        DP_TRAIN_PRE_EMPHASIS_MASK);
-       switch (signal_levels) {
-       default:
-               DRM_DEBUG_KMS("Unsupported voltage swing/pre-emph level\n");
-       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;
-       }
-
-       bxt_ddi_vswing_sequence(dev, level, port, encoder->type);
-}
-
 /* Properly updates "DP" with the correct signal levels. */
 static void
 intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
@@ -3517,22 +3431,20 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        enum port port = intel_dig_port->port;
        struct drm_device *dev = intel_dig_port->base.base.dev;
-       uint32_t signal_levels, mask;
+       uint32_t signal_levels, mask = 0;
        uint8_t train_set = intel_dp->train_set[0];
 
-       if (IS_BROXTON(dev)) {
-               signal_levels = 0;
-               bxt_signal_levels(intel_dp);
-               mask = 0;
-       } else if (HAS_DDI(dev)) {
-               signal_levels = hsw_signal_levels(train_set);
-               mask = DDI_BUF_EMP_MASK;
+       if (HAS_DDI(dev)) {
+               signal_levels = ddi_signal_levels(intel_dp);
+
+               if (IS_BROXTON(dev))
+                       signal_levels = 0;
+               else
+                       mask = DDI_BUF_EMP_MASK;
        } else if (IS_CHERRYVIEW(dev)) {
                signal_levels = chv_signal_levels(intel_dp);
-               mask = 0;
        } else if (IS_VALLEYVIEW(dev)) {
                signal_levels = vlv_signal_levels(intel_dp);
-               mask = 0;
        } else if (IS_GEN7(dev) && port == PORT_A) {
                signal_levels = gen7_edp_signal_levels(train_set);
                mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB;
index 7f2e204b9fb5ae5c4da2c76e663771c5ffeb2324..bb52620a3ce813dffde0f64707e622f6f06b9538 100644 (file)
@@ -968,8 +968,7 @@ void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder);
 void intel_ddi_clock_get(struct intel_encoder *encoder,
                         struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
-void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
-                               enum port port, int type);
+uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
 
 /* intel_frontbuffer.c */
 void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,