[v2] drm/i915/skl: Buffer translation improvements
diff mbox

Message ID 20150625081103.GO14570@boom
State New
Headers show

Commit Message

David Weinehall June 25, 2015, 8:11 a.m. UTC
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>
---
 drivers/gpu/drm/i915/i915_drv.h  |   8 +
 drivers/gpu/drm/i915/i915_reg.h  |  12 +
 drivers/gpu/drm/i915/intel_ddi.c | 507 ++++++++++++++++++++++++++++++---------
 drivers/gpu/drm/i915/intel_dp.c  | 104 +-------
 drivers/gpu/drm/i915/intel_drv.h |   3 +-
 5 files changed, 421 insertions(+), 213 deletions(-)

Comments

Antti Koskipää June 29, 2015, 10:35 a.m. UTC | #1
Looks fine to me.

Reviewed-by: Antti Koskipää <antti.koskipaa@linux.intel.com>


On 06/25/2015 11:11 AM, David Weinehall wrote:
> 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>
> ---
>  drivers/gpu/drm/i915/i915_drv.h  |   8 +
>  drivers/gpu/drm/i915/i915_reg.h  |  12 +
>  drivers/gpu/drm/i915/intel_ddi.c | 507 ++++++++++++++++++++++++++++++---------
>  drivers/gpu/drm/i915/intel_dp.c  | 104 +-------
>  drivers/gpu/drm/i915/intel_drv.h |   3 +-
>  5 files changed, 421 insertions(+), 213 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 491ef0cfcb0b..09a57a584f5f 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2415,6 +2415,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)
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 0b979ad16d41..fb63ead2b8eb 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -1382,6 +1382,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
>   */
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 31b29e8781ac..08f89299b572 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -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,99 @@ 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 +455,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;
> @@ -1806,8 +1975,49 @@ 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;
> @@ -1867,6 +2077,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;
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index f52eef138247..041e2d6dcc56 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -3417,92 +3417,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)
> @@ -3510,22 +3424,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;
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index bcafefcf048b..c6cbe8c602f9 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -950,8 +950,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,
>
Daniel Vetter June 29, 2015, 4:12 p.m. UTC | #2
On Mon, Jun 29, 2015 at 01:35:06PM +0300, Antti Koskipää wrote:
> Looks fine to me.
> 
> Reviewed-by: Antti Koskipää <antti.koskipaa@linux.intel.com>
> 
> 
> On 06/25/2015 11:11 AM, David Weinehall wrote:
> > 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

For next time around please split out refactoring from actual code
changes, makes it a pain to review. And if this blows up in a
regression that's really annoying. Also please head checkpatch's
suggestions a bit more, I fixed that up when applying.
-Daniel

> > 
> > Issue: VIZ-5677
> > Signed-off-by: David Weinehall <david.weinehall@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/i915_drv.h  |   8 +
> >  drivers/gpu/drm/i915/i915_reg.h  |  12 +
> >  drivers/gpu/drm/i915/intel_ddi.c | 507 ++++++++++++++++++++++++++++++---------
> >  drivers/gpu/drm/i915/intel_dp.c  | 104 +-------
> >  drivers/gpu/drm/i915/intel_drv.h |   3 +-
> >  5 files changed, 421 insertions(+), 213 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > index 491ef0cfcb0b..09a57a584f5f 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.h
> > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > @@ -2415,6 +2415,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)
> > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> > index 0b979ad16d41..fb63ead2b8eb 100644
> > --- a/drivers/gpu/drm/i915/i915_reg.h
> > +++ b/drivers/gpu/drm/i915/i915_reg.h
> > @@ -1382,6 +1382,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
> >   */
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> > index 31b29e8781ac..08f89299b572 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -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,99 @@ 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 +455,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;
> > @@ -1806,8 +1975,49 @@ 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;
> > @@ -1867,6 +2077,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;
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> > index f52eef138247..041e2d6dcc56 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -3417,92 +3417,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)
> > @@ -3510,22 +3424,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;
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index bcafefcf048b..c6cbe8c602f9 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -950,8 +950,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,
> > 
> 
> -- 
> - Antti
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
David Weinehall June 30, 2015, 10:27 a.m. UTC | #3
On Mon, Jun 29, 2015 at 06:12:54PM +0200, Daniel Vetter wrote:
> On Mon, Jun 29, 2015 at 01:35:06PM +0300, Antti Koskipää wrote:
> > Looks fine to me.
> > 
> > Reviewed-by: Antti Koskipää <antti.koskipaa@linux.intel.com>
> > 
> > 
> > On 06/25/2015 11:11 AM, David Weinehall wrote:
> > > 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
> 
> For next time around please split out refactoring from actual code
> changes, makes it a pain to review. And if this blows up in a
> regression that's really annoying. Also please head checkpatch's
> suggestions a bit more, I fixed that up when applying.

OK, noted.


Kind regards, David

Patch
diff mbox

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 491ef0cfcb0b..09a57a584f5f 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2415,6 +2415,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)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 0b979ad16d41..fb63ead2b8eb 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1382,6 +1382,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
  */
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 31b29e8781ac..08f89299b572 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -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,99 @@  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 +455,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;
@@ -1806,8 +1975,49 @@  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;
@@ -1867,6 +2077,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;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index f52eef138247..041e2d6dcc56 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -3417,92 +3417,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)
@@ -3510,22 +3424,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;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index bcafefcf048b..c6cbe8c602f9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -950,8 +950,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,