Commit f8896f5d authored by David Weinehall's avatar David Weinehall Committed by Daniel Vetter

drm/i915/skl: Buffer translation improvements

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: default avatarDavid Weinehall <david.weinehall@linux.intel.com>
Reviewed-by: default avatarAntti Koskipää <antti.koskipaa@linux.intel.com>
[danvet: Apply style polish checkpatch suggested.]
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 2cb389b7
...@@ -2436,6 +2436,14 @@ struct drm_i915_cmd_table { ...@@ -2436,6 +2436,14 @@ struct drm_i915_cmd_table {
/* ULX machines are also considered ULT. */ /* ULX machines are also considered ULT. */
#define IS_HSW_ULX(dev) (INTEL_DEVID(dev) == 0x0A0E || \ #define IS_HSW_ULX(dev) (INTEL_DEVID(dev) == 0x0A0E || \
INTEL_DEVID(dev) == 0x0A1E) 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 IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary)
#define SKL_REVID_A0 (0x0) #define SKL_REVID_A0 (0x0)
......
...@@ -1384,6 +1384,18 @@ enum skl_disp_power_wells { ...@@ -1384,6 +1384,18 @@ enum skl_disp_power_wells {
_PORT_TX_DW14_LN0_C) + \ _PORT_TX_DW14_LN0_C) + \
_BXT_LANE_OFFSET(lane)) _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 * Fence registers
*/ */
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
struct ddi_buf_trans { struct ddi_buf_trans {
u32 trans1; /* balance leg enable, de-emph level */ u32 trans1; /* balance leg enable, de-emph level */
u32 trans2; /* vref sel, vswing */ 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 /* HDMI/DVI modes ignore everything but the last 2 items. So we share
...@@ -38,134 +39,213 @@ struct ddi_buf_trans { ...@@ -38,134 +39,213 @@ struct ddi_buf_trans {
* automatically adapt to HDMI connections as well * automatically adapt to HDMI connections as well
*/ */
static const struct ddi_buf_trans hsw_ddi_translations_dp[] = { static const struct ddi_buf_trans hsw_ddi_translations_dp[] = {
{ 0x00FFFFFF, 0x0006000E }, { 0x00FFFFFF, 0x0006000E, 0x0 },
{ 0x00D75FFF, 0x0005000A }, { 0x00D75FFF, 0x0005000A, 0x0 },
{ 0x00C30FFF, 0x00040006 }, { 0x00C30FFF, 0x00040006, 0x0 },
{ 0x80AAAFFF, 0x000B0000 }, { 0x80AAAFFF, 0x000B0000, 0x0 },
{ 0x00FFFFFF, 0x0005000A }, { 0x00FFFFFF, 0x0005000A, 0x0 },
{ 0x00D75FFF, 0x000C0004 }, { 0x00D75FFF, 0x000C0004, 0x0 },
{ 0x80C30FFF, 0x000B0000 }, { 0x80C30FFF, 0x000B0000, 0x0 },
{ 0x00FFFFFF, 0x00040006 }, { 0x00FFFFFF, 0x00040006, 0x0 },
{ 0x80D75FFF, 0x000B0000 }, { 0x80D75FFF, 0x000B0000, 0x0 },
}; };
static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = { static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = {
{ 0x00FFFFFF, 0x0007000E }, { 0x00FFFFFF, 0x0007000E, 0x0 },
{ 0x00D75FFF, 0x000F000A }, { 0x00D75FFF, 0x000F000A, 0x0 },
{ 0x00C30FFF, 0x00060006 }, { 0x00C30FFF, 0x00060006, 0x0 },
{ 0x00AAAFFF, 0x001E0000 }, { 0x00AAAFFF, 0x001E0000, 0x0 },
{ 0x00FFFFFF, 0x000F000A }, { 0x00FFFFFF, 0x000F000A, 0x0 },
{ 0x00D75FFF, 0x00160004 }, { 0x00D75FFF, 0x00160004, 0x0 },
{ 0x00C30FFF, 0x001E0000 }, { 0x00C30FFF, 0x001E0000, 0x0 },
{ 0x00FFFFFF, 0x00060006 }, { 0x00FFFFFF, 0x00060006, 0x0 },
{ 0x00D75FFF, 0x001E0000 }, { 0x00D75FFF, 0x001E0000, 0x0 },
}; };
static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = { static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = {
/* Idx NT mV d T mV d db */ /* Idx NT mV d T mV d db */
{ 0x00FFFFFF, 0x0006000E }, /* 0: 400 400 0 */ { 0x00FFFFFF, 0x0006000E, 0x0 },/* 0: 400 400 0 */
{ 0x00E79FFF, 0x000E000C }, /* 1: 400 500 2 */ { 0x00E79FFF, 0x000E000C, 0x0 },/* 1: 400 500 2 */
{ 0x00D75FFF, 0x0005000A }, /* 2: 400 600 3.5 */ { 0x00D75FFF, 0x0005000A, 0x0 },/* 2: 400 600 3.5 */
{ 0x00FFFFFF, 0x0005000A }, /* 3: 600 600 0 */ { 0x00FFFFFF, 0x0005000A, 0x0 },/* 3: 600 600 0 */
{ 0x00E79FFF, 0x001D0007 }, /* 4: 600 750 2 */ { 0x00E79FFF, 0x001D0007, 0x0 },/* 4: 600 750 2 */
{ 0x00D75FFF, 0x000C0004 }, /* 5: 600 900 3.5 */ { 0x00D75FFF, 0x000C0004, 0x0 },/* 5: 600 900 3.5 */
{ 0x00FFFFFF, 0x00040006 }, /* 6: 800 800 0 */ { 0x00FFFFFF, 0x00040006, 0x0 },/* 6: 800 800 0 */
{ 0x80E79FFF, 0x00030002 }, /* 7: 800 1000 2 */ { 0x80E79FFF, 0x00030002, 0x0 },/* 7: 800 1000 2 */
{ 0x00FFFFFF, 0x00140005 }, /* 8: 850 850 0 */ { 0x00FFFFFF, 0x00140005, 0x0 },/* 8: 850 850 0 */
{ 0x00FFFFFF, 0x000C0004 }, /* 9: 900 900 0 */ { 0x00FFFFFF, 0x000C0004, 0x0 },/* 9: 900 900 0 */
{ 0x00FFFFFF, 0x001C0003 }, /* 10: 950 950 0 */ { 0x00FFFFFF, 0x001C0003, 0x0 },/* 10: 950 950 0 */
{ 0x80FFFFFF, 0x00030002 }, /* 11: 1000 1000 0 */ { 0x80FFFFFF, 0x00030002, 0x0 },/* 11: 1000 1000 0 */
}; };
static const struct ddi_buf_trans bdw_ddi_translations_edp[] = { static const struct ddi_buf_trans bdw_ddi_translations_edp[] = {
{ 0x00FFFFFF, 0x00000012 }, { 0x00FFFFFF, 0x00000012, 0x0 },
{ 0x00EBAFFF, 0x00020011 }, { 0x00EBAFFF, 0x00020011, 0x0 },
{ 0x00C71FFF, 0x0006000F }, { 0x00C71FFF, 0x0006000F, 0x0 },
{ 0x00AAAFFF, 0x000E000A }, { 0x00AAAFFF, 0x000E000A, 0x0 },
{ 0x00FFFFFF, 0x00020011 }, { 0x00FFFFFF, 0x00020011, 0x0 },
{ 0x00DB6FFF, 0x0005000F }, { 0x00DB6FFF, 0x0005000F, 0x0 },
{ 0x00BEEFFF, 0x000A000C }, { 0x00BEEFFF, 0x000A000C, 0x0 },
{ 0x00FFFFFF, 0x0005000F }, { 0x00FFFFFF, 0x0005000F, 0x0 },
{ 0x00DB6FFF, 0x000A000C }, { 0x00DB6FFF, 0x000A000C, 0x0 },
}; };
static const struct ddi_buf_trans bdw_ddi_translations_dp[] = { static const struct ddi_buf_trans bdw_ddi_translations_dp[] = {
{ 0x00FFFFFF, 0x0007000E }, { 0x00FFFFFF, 0x0007000E, 0x0 },
{ 0x00D75FFF, 0x000E000A }, { 0x00D75FFF, 0x000E000A, 0x0 },
{ 0x00BEFFFF, 0x00140006 }, { 0x00BEFFFF, 0x00140006, 0x0 },
{ 0x80B2CFFF, 0x001B0002 }, { 0x80B2CFFF, 0x001B0002, 0x0 },
{ 0x00FFFFFF, 0x000E000A }, { 0x00FFFFFF, 0x000E000A, 0x0 },
{ 0x00DB6FFF, 0x00160005 }, { 0x00DB6FFF, 0x00160005, 0x0 },
{ 0x80C71FFF, 0x001A0002 }, { 0x80C71FFF, 0x001A0002, 0x0 },
{ 0x00F7DFFF, 0x00180004 }, { 0x00F7DFFF, 0x00180004, 0x0 },
{ 0x80D75FFF, 0x001B0002 }, { 0x80D75FFF, 0x001B0002, 0x0 },
}; };
static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = { static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = {
{ 0x00FFFFFF, 0x0001000E }, { 0x00FFFFFF, 0x0001000E, 0x0 },
{ 0x00D75FFF, 0x0004000A }, { 0x00D75FFF, 0x0004000A, 0x0 },
{ 0x00C30FFF, 0x00070006 }, { 0x00C30FFF, 0x00070006, 0x0 },
{ 0x00AAAFFF, 0x000C0000 }, { 0x00AAAFFF, 0x000C0000, 0x0 },
{ 0x00FFFFFF, 0x0004000A }, { 0x00FFFFFF, 0x0004000A, 0x0 },
{ 0x00D75FFF, 0x00090004 }, { 0x00D75FFF, 0x00090004, 0x0 },
{ 0x00C30FFF, 0x000C0000 }, { 0x00C30FFF, 0x000C0000, 0x0 },
{ 0x00FFFFFF, 0x00070006 }, { 0x00FFFFFF, 0x00070006, 0x0 },
{ 0x00D75FFF, 0x000C0000 }, { 0x00D75FFF, 0x000C0000, 0x0 },
}; };
static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = { static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = {
/* Idx NT mV d T mV df db */ /* Idx NT mV d T mV df db */
{ 0x00FFFFFF, 0x0007000E }, /* 0: 400 400 0 */ { 0x00FFFFFF, 0x0007000E, 0x0 },/* 0: 400 400 0 */
{ 0x00D75FFF, 0x000E000A }, /* 1: 400 600 3.5 */ { 0x00D75FFF, 0x000E000A, 0x0 },/* 1: 400 600 3.5 */
{ 0x00BEFFFF, 0x00140006 }, /* 2: 400 800 6 */ { 0x00BEFFFF, 0x00140006, 0x0 },/* 2: 400 800 6 */
{ 0x00FFFFFF, 0x0009000D }, /* 3: 450 450 0 */ { 0x00FFFFFF, 0x0009000D, 0x0 },/* 3: 450 450 0 */
{ 0x00FFFFFF, 0x000E000A }, /* 4: 600 600 0 */ { 0x00FFFFFF, 0x000E000A, 0x0 },/* 4: 600 600 0 */
{ 0x00D7FFFF, 0x00140006 }, /* 5: 600 800 2.5 */ { 0x00D7FFFF, 0x00140006, 0x0 },/* 5: 600 800 2.5 */
{ 0x80CB2FFF, 0x001B0002 }, /* 6: 600 1000 4.5 */ { 0x80CB2FFF, 0x001B0002, 0x0 },/* 6: 600 1000 4.5 */
{ 0x00FFFFFF, 0x00140006 }, /* 7: 800 800 0 */ { 0x00FFFFFF, 0x00140006, 0x0 },/* 7: 800 800 0 */
{ 0x80E79FFF, 0x001B0002 }, /* 8: 800 1000 2 */ { 0x80E79FFF, 0x001B0002, 0x0 },/* 8: 800 1000 2 */
{ 0x80FFFFFF, 0x001B0002 }, /* 9: 1000 1000 0 */ { 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[] = { static const struct ddi_buf_trans skl_ddi_translations_dp[] = {
{ 0x00000018, 0x000000a2 }, { 0x00002016, 0x000000A0, 0x0 },
{ 0x00004014, 0x0000009B }, { 0x00005012, 0x0000009B, 0x0 },
{ 0x00006012, 0x00000088 }, { 0x00007011, 0x00000088, 0x0 },
{ 0x00008010, 0x00000087 }, { 0x00009010, 0x000000C7, 0x0 },
{ 0x00000018, 0x0000009B }, { 0x00002016, 0x0000009B, 0x0 },
{ 0x00004014, 0x00000088 }, { 0x00005012, 0x00000088, 0x0 },
{ 0x00006012, 0x00000087 }, { 0x00007011, 0x000000C7, 0x0 },
{ 0x00000018, 0x00000088 }, { 0x00002016, 0x000000DF, 0x0 },
{ 0x00004014, 0x00000087 }, { 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[] = { static const struct ddi_buf_trans skl_ddi_translations_edp[] = {
{ 0x00000018, 0x000000a8 }, { 0x00000018, 0x000000A8, 0x0 },
{ 0x00002016, 0x000000ab }, { 0x00004013, 0x000000A9, 0x0 },
{ 0x00006012, 0x000000a2 }, { 0x00007011, 0x000000A2, 0x0 },
{ 0x00008010, 0x00000088 }, { 0x00009010, 0x0000009C, 0x0 },
{ 0x00000018, 0x000000ab }, { 0x00000018, 0x000000A9, 0x0 },
{ 0x00004014, 0x000000a2 }, { 0x00006013, 0x000000A2, 0x0 },
{ 0x00006012, 0x000000a6 }, { 0x00007011, 0x000000A6, 0x0 },
{ 0x00000018, 0x000000a2 }, { 0x00000018, 0x000000AB, 0x0 },
{ 0x00005013, 0x0000009c }, { 0x00007013, 0x0000009F, 0x0 },
{ 0x00000018, 0x00000088 }, { 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[] = { static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
{ 0x00000018, 0x000000ac }, { 0x00000018, 0x000000AC, 0x0 },
{ 0x00005012, 0x0000009d }, { 0x00005012, 0x0000009D, 0x0 },
{ 0x00007011, 0x00000088 }, { 0x00007011, 0x00000088, 0x0 },
{ 0x00000018, 0x000000a1 }, { 0x00000018, 0x000000A1, 0x0 },
{ 0x00000018, 0x00000098 }, { 0x00000018, 0x00000098, 0x0 },
{ 0x00004013, 0x00000088 }, { 0x00004013, 0x00000088, 0x0 },
{ 0x00006012, 0x00000087 }, { 0x00006012, 0x00000087, 0x0 },
{ 0x00000018, 0x000000df }, { 0x00000018, 0x000000DF, 0x0 },
{ 0x00003015, 0x00000087 }, { 0x00003015, 0x00000087, 0x0 }, /* Default */
{ 0x00003015, 0x000000c7 }, { 0x00003015, 0x000000C7, 0x0 },
{ 0x00000018, 0x000000c7 }, { 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 { struct bxt_ddi_buf_trans {
...@@ -190,7 +270,7 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { ...@@ -190,7 +270,7 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = {
{ 154, 0x9A, 0, 64, false }, /* 6: 600 6 */ { 154, 0x9A, 0, 64, false }, /* 6: 600 6 */
{ 102, 0x9A, 0, 128, false }, /* 7: 800 0 */ { 102, 0x9A, 0, 128, false }, /* 7: 800 0 */
{ 154, 0x9A, 0, 85, false }, /* 8: 800 3.5 */ { 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. /* BSpec has 2 recommended values - entries 0 and 8.
...@@ -210,6 +290,9 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = { ...@@ -210,6 +290,9 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = {
{ 154, 0x9A, 1, 128, true }, /* 9: 1200 0 */ { 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, static void ddi_get_encoder_port(struct intel_encoder *intel_encoder,
struct intel_digital_port **dig_port, struct intel_digital_port **dig_port,
enum port *port) enum port *port)
...@@ -249,6 +332,102 @@ intel_dig_port_supports_hdmi(const struct intel_digital_port *intel_dig_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; 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 * Starting with Haswell, DDI port buffers must be programmed with correct
* values in advance. The buffer values are different for FDI and DP modes, * 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, ...@@ -279,20 +458,13 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
INTEL_OUTPUT_HDMI); INTEL_OUTPUT_HDMI);
return; return;
} else if (IS_SKYLAKE(dev)) { } else if (IS_SKYLAKE(dev)) {
ddi_translations_fdi = NULL; ddi_translations_dp =
ddi_translations_dp = skl_ddi_translations_dp; skl_get_buf_trans_dp(dev, &n_dp_entries);
n_dp_entries = ARRAY_SIZE(skl_ddi_translations_dp); ddi_translations_edp =
if (dev_priv->edp_low_vswing) { skl_get_buf_trans_edp(dev, &n_edp_entries);
ddi_translations_edp = skl_ddi_translations_edp; ddi_translations_hdmi =
n_edp_entries = ARRAY_SIZE(skl_ddi_translations_edp); skl_get_buf_trans_hdmi(dev, &n_hdmi_entries);
} else { hdmi_default_entry = 8;
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;
} else if (IS_BROADWELL(dev)) { } else if (IS_BROADWELL(dev)) {
ddi_translations_fdi = bdw_ddi_translations_fdi; ddi_translations_fdi = bdw_ddi_translations_fdi;
ddi_translations_dp = bdw_ddi_translations_dp; ddi_translations_dp = bdw_ddi_translations_dp;
...@@ -1883,8 +2055,48 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) ...@@ -1883,8 +2055,48 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc)
TRANS_CLK_SEL_DISABLED); TRANS_CLK_SEL_DISABLED);
} }
void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, static void skl_ddi_set_iboost(struct drm_device *dev, u32 level,
enum port port, int type) 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; struct drm_i915_private *dev_priv = dev->dev_private;
const struct bxt_ddi_buf_trans *ddi_translations; const struct bxt_ddi_buf_trans *ddi_translations;
...@@ -1944,6 +2156,73 @@ void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, ...@@ -1944,6 +2156,73 @@ void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
I915_WRITE(BXT_PORT_PCS_DW10_GRP(port), val); 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) static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
{ {
struct drm_encoder *encoder = &intel_encoder->base; struct drm_encoder *encoder = &intel_encoder->base;
......
...@@ -3424,92 +3424,6 @@ gen7_edp_signal_levels(uint8_t train_set) ...@@ -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. */ /* Properly updates "DP" with the correct signal levels. */
static void static void
intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) 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) ...@@ -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); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
enum port port = intel_dig_port->port; enum port port = intel_dig_port->port;
struct drm_device *dev = intel_dig_port->base.base.dev; 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]; uint8_t train_set = intel_dp->train_set[0];
if (IS_BROXTON(dev)) { if (HAS_DDI(dev)) {
signal_levels = 0; signal_levels = ddi_signal_levels(intel_dp);
bxt_signal_levels(intel_dp);
mask = 0; if (IS_BROXTON(dev))
} else if (HAS_DDI(dev)) { signal_levels = 0;
signal_levels = hsw_signal_levels(train_set); else
mask = DDI_BUF_EMP_MASK; mask = DDI_BUF_EMP_MASK;
} else if (IS_CHERRYVIEW(dev)) { } else if (IS_CHERRYVIEW(dev)) {
signal_levels = chv_signal_levels(intel_dp); signal_levels = chv_signal_levels(intel_dp);
mask = 0;
} else if (IS_VALLEYVIEW(dev)) { } else if (IS_VALLEYVIEW(dev)) {
signal_levels = vlv_signal_levels(intel_dp); signal_levels = vlv_signal_levels(intel_dp);
mask = 0;
} else if (IS_GEN7(dev) && port == PORT_A) { } else if (IS_GEN7(dev) && port == PORT_A) {
signal_levels = gen7_edp_signal_levels(train_set); signal_levels = gen7_edp_signal_levels(train_set);
mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB; mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB;
......
...@@ -968,8 +968,7 @@ void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder); ...@@ -968,8 +968,7 @@ void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder);
void intel_ddi_clock_get(struct intel_encoder *encoder, void intel_ddi_clock_get(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config); struct intel_crtc_state *pipe_config);
void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state); void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
enum port port, int type);
/* intel_frontbuffer.c */ /* intel_frontbuffer.c */
void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment