drm/i915/glk: Implement Geminilake DDI init sequence
Implement the DDI initsequence and add information about the different phys in GLK. v2: Rebase on the move of phys to be power wells. v3: Rebase on addition of struct bxt_ddi_phy_info. Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1480667037-11215-4-git-send-email-ander.conselvan.de.oliveira@intel.com
This commit is contained in:
Родитель
0d03926de5
Коммит
0a116ce895
|
@ -234,7 +234,8 @@ enum dpio_channel {
|
|||
|
||||
enum dpio_phy {
|
||||
DPIO_PHY0,
|
||||
DPIO_PHY1
|
||||
DPIO_PHY1,
|
||||
DPIO_PHY2,
|
||||
};
|
||||
|
||||
enum intel_display_power_domain {
|
||||
|
@ -3619,7 +3620,7 @@ u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg);
|
|||
void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
|
||||
|
||||
/* intel_dpio_phy.c */
|
||||
void bxt_port_to_phy_channel(enum port port,
|
||||
void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port,
|
||||
enum dpio_phy *phy, enum dpio_channel *ch);
|
||||
void bxt_ddi_phy_set_signal_level(struct drm_i915_private *dev_priv,
|
||||
enum port port, u32 margin, u32 scale,
|
||||
|
|
|
@ -62,6 +62,9 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
|
|||
#define _PORT3(port, a, b, c) ((port) == PORT_A ? (a) : \
|
||||
(port) == PORT_B ? (b) : (c))
|
||||
#define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PORT3(pipe, a, b, c))
|
||||
#define _PHY3(phy, a, b, c) ((phy) == DPIO_PHY0 ? (a) : \
|
||||
(phy) == DPIO_PHY1 ? (b) : (c))
|
||||
#define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c))
|
||||
|
||||
#define _MASKED_FIELD(mask, value) ({ \
|
||||
if (__builtin_constant_p(mask)) \
|
||||
|
@ -1062,6 +1065,7 @@ enum skl_disp_power_wells {
|
|||
|
||||
BXT_DPIO_CMN_A,
|
||||
BXT_DPIO_CMN_BC,
|
||||
GLK_DPIO_CMN_C,
|
||||
};
|
||||
|
||||
#define SKL_POWER_WELL_STATE(pw) (1 << ((pw) * 2))
|
||||
|
@ -1530,8 +1534,10 @@ enum skl_disp_power_wells {
|
|||
/* BXT PHY registers */
|
||||
#define _BXT_PHY0_BASE 0x6C000
|
||||
#define _BXT_PHY1_BASE 0x162000
|
||||
#define BXT_PHY_BASE(phy) _PIPE((phy), _BXT_PHY0_BASE, \
|
||||
_BXT_PHY1_BASE)
|
||||
#define _BXT_PHY2_BASE 0x163000
|
||||
#define BXT_PHY_BASE(phy) _PHY3((phy), _BXT_PHY0_BASE, \
|
||||
_BXT_PHY1_BASE, \
|
||||
_BXT_PHY2_BASE)
|
||||
|
||||
#define _BXT_PHY(phy, reg) \
|
||||
_MMIO(BXT_PHY_BASE(phy) - _BXT_PHY0_BASE + (reg))
|
||||
|
@ -1543,7 +1549,6 @@ enum skl_disp_power_wells {
|
|||
_MMIO(_BXT_PHY_CH(phy, ch, reg_ch0, reg_ch1))
|
||||
|
||||
#define BXT_P_CR_GT_DISP_PWRON _MMIO(0x138090)
|
||||
#define GT_DISPLAY_POWER_ON(phy) (1 << (phy))
|
||||
|
||||
#define _BXT_PHY_CTL_DDI_A 0x64C00
|
||||
#define _BXT_PHY_CTL_DDI_B 0x64C10
|
||||
|
@ -1556,9 +1561,11 @@ enum skl_disp_power_wells {
|
|||
|
||||
#define _PHY_CTL_FAMILY_EDP 0x64C80
|
||||
#define _PHY_CTL_FAMILY_DDI 0x64C90
|
||||
#define _PHY_CTL_FAMILY_DDI_C 0x64CA0
|
||||
#define COMMON_RESET_DIS (1 << 31)
|
||||
#define BXT_PHY_CTL_FAMILY(phy) _MMIO_PIPE((phy), _PHY_CTL_FAMILY_DDI, \
|
||||
_PHY_CTL_FAMILY_EDP)
|
||||
#define BXT_PHY_CTL_FAMILY(phy) _MMIO_PHY3((phy), _PHY_CTL_FAMILY_DDI, \
|
||||
_PHY_CTL_FAMILY_EDP, \
|
||||
_PHY_CTL_FAMILY_DDI_C)
|
||||
|
||||
/* BXT PHY PLL registers */
|
||||
#define _PORT_PLL_A 0x46074
|
||||
|
|
|
@ -130,6 +130,18 @@ struct bxt_ddi_phy_info {
|
|||
*/
|
||||
enum dpio_phy rcomp_phy;
|
||||
|
||||
/**
|
||||
* @reset_delay: delay in us to wait before setting the common reset
|
||||
* bit in BXT_PHY_CTL_FAMILY, which effectively enables the phy.
|
||||
*/
|
||||
int reset_delay;
|
||||
|
||||
/**
|
||||
* @pwron_mask: Mask with the appropriate bit set that would cause the
|
||||
* punit to power this phy if written to BXT_P_CR_GT_DISP_PWRON.
|
||||
*/
|
||||
u32 pwron_mask;
|
||||
|
||||
/**
|
||||
* @channel: struct containing per channel information.
|
||||
*/
|
||||
|
@ -145,6 +157,7 @@ static const struct bxt_ddi_phy_info bxt_ddi_phy_info[] = {
|
|||
[DPIO_PHY0] = {
|
||||
.dual_channel = true,
|
||||
.rcomp_phy = DPIO_PHY1,
|
||||
.pwron_mask = BIT(0),
|
||||
|
||||
.channel = {
|
||||
[DPIO_CH0] = { .port = PORT_B },
|
||||
|
@ -154,6 +167,7 @@ static const struct bxt_ddi_phy_info bxt_ddi_phy_info[] = {
|
|||
[DPIO_PHY1] = {
|
||||
.dual_channel = false,
|
||||
.rcomp_phy = -1,
|
||||
.pwron_mask = BIT(1),
|
||||
|
||||
.channel = {
|
||||
[DPIO_CH0] = { .port = PORT_A },
|
||||
|
@ -161,20 +175,77 @@ static const struct bxt_ddi_phy_info bxt_ddi_phy_info[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct bxt_ddi_phy_info glk_ddi_phy_info[] = {
|
||||
[DPIO_PHY0] = {
|
||||
.dual_channel = false,
|
||||
.rcomp_phy = DPIO_PHY1,
|
||||
.pwron_mask = BIT(0),
|
||||
.reset_delay = 20,
|
||||
|
||||
.channel = {
|
||||
[DPIO_CH0] = { .port = PORT_B },
|
||||
}
|
||||
},
|
||||
[DPIO_PHY1] = {
|
||||
.dual_channel = false,
|
||||
.rcomp_phy = -1,
|
||||
.pwron_mask = BIT(3),
|
||||
.reset_delay = 20,
|
||||
|
||||
.channel = {
|
||||
[DPIO_CH0] = { .port = PORT_A },
|
||||
}
|
||||
},
|
||||
[DPIO_PHY2] = {
|
||||
.dual_channel = false,
|
||||
.rcomp_phy = DPIO_PHY1,
|
||||
.pwron_mask = BIT(1),
|
||||
.reset_delay = 20,
|
||||
|
||||
.channel = {
|
||||
[DPIO_CH0] = { .port = PORT_C },
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
static u32 bxt_phy_port_mask(const struct bxt_ddi_phy_info *phy_info)
|
||||
{
|
||||
return (phy_info->dual_channel * BIT(phy_info->channel[DPIO_CH1].port)) |
|
||||
BIT(phy_info->channel[DPIO_CH0].port);
|
||||
}
|
||||
|
||||
void bxt_port_to_phy_channel(enum port port,
|
||||
static const struct bxt_ddi_phy_info *
|
||||
bxt_get_phy_list(struct drm_i915_private *dev_priv, int *count)
|
||||
{
|
||||
if (IS_GEMINILAKE(dev_priv)) {
|
||||
*count = ARRAY_SIZE(glk_ddi_phy_info);
|
||||
return glk_ddi_phy_info;
|
||||
} else {
|
||||
*count = ARRAY_SIZE(bxt_ddi_phy_info);
|
||||
return bxt_ddi_phy_info;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct bxt_ddi_phy_info *
|
||||
bxt_get_phy_info(struct drm_i915_private *dev_priv, enum dpio_phy phy)
|
||||
{
|
||||
int count;
|
||||
const struct bxt_ddi_phy_info *phy_list =
|
||||
bxt_get_phy_list(dev_priv, &count);
|
||||
|
||||
return &phy_list[phy];
|
||||
}
|
||||
|
||||
void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port,
|
||||
enum dpio_phy *phy, enum dpio_channel *ch)
|
||||
{
|
||||
const struct bxt_ddi_phy_info *phy_info;
|
||||
int i;
|
||||
const struct bxt_ddi_phy_info *phy_info, *phys;
|
||||
int i, count;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bxt_ddi_phy_info); i++) {
|
||||
phy_info = &bxt_ddi_phy_info[i];
|
||||
phys = bxt_get_phy_list(dev_priv, &count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
phy_info = &phys[i];
|
||||
|
||||
if (port == phy_info->channel[DPIO_CH0].port) {
|
||||
*phy = i;
|
||||
|
@ -203,7 +274,7 @@ void bxt_ddi_phy_set_signal_level(struct drm_i915_private *dev_priv,
|
|||
enum dpio_phy phy;
|
||||
enum dpio_channel ch;
|
||||
|
||||
bxt_port_to_phy_channel(port, &phy, &ch);
|
||||
bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
|
||||
|
||||
/*
|
||||
* While we write to the group register to program all lanes at once we
|
||||
|
@ -241,10 +312,12 @@ void bxt_ddi_phy_set_signal_level(struct drm_i915_private *dev_priv,
|
|||
bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy)
|
||||
{
|
||||
const struct bxt_ddi_phy_info *phy_info = &bxt_ddi_phy_info[phy];
|
||||
const struct bxt_ddi_phy_info *phy_info;
|
||||
enum port port;
|
||||
|
||||
if (!(I915_READ(BXT_P_CR_GT_DISP_PWRON) & GT_DISPLAY_POWER_ON(phy)))
|
||||
phy_info = bxt_get_phy_info(dev_priv, phy);
|
||||
|
||||
if (!(I915_READ(BXT_P_CR_GT_DISP_PWRON) & phy_info->pwron_mask))
|
||||
return false;
|
||||
|
||||
if ((I915_READ(BXT_PORT_CL1CM_DW0(phy)) &
|
||||
|
@ -306,9 +379,11 @@ static void bxt_phy_wait_grc_done(struct drm_i915_private *dev_priv,
|
|||
static void _bxt_ddi_phy_init(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy)
|
||||
{
|
||||
const struct bxt_ddi_phy_info *phy_info = &bxt_ddi_phy_info[phy];
|
||||
const struct bxt_ddi_phy_info *phy_info;
|
||||
u32 val;
|
||||
|
||||
phy_info = bxt_get_phy_info(dev_priv, phy);
|
||||
|
||||
if (bxt_ddi_phy_is_enabled(dev_priv, phy)) {
|
||||
/* Still read out the GRC value for state verification */
|
||||
if (phy_info->rcomp_phy != -1)
|
||||
|
@ -325,7 +400,7 @@ static void _bxt_ddi_phy_init(struct drm_i915_private *dev_priv,
|
|||
}
|
||||
|
||||
val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
|
||||
val |= GT_DISPLAY_POWER_ON(phy);
|
||||
val |= phy_info->pwron_mask;
|
||||
I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val);
|
||||
|
||||
/*
|
||||
|
@ -383,6 +458,9 @@ static void _bxt_ddi_phy_init(struct drm_i915_private *dev_priv,
|
|||
I915_WRITE(BXT_PORT_REF_DW8(phy), val);
|
||||
}
|
||||
|
||||
if (phy_info->reset_delay)
|
||||
udelay(phy_info->reset_delay);
|
||||
|
||||
val = I915_READ(BXT_PHY_CTL_FAMILY(phy));
|
||||
val |= COMMON_RESET_DIS;
|
||||
I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val);
|
||||
|
@ -394,20 +472,24 @@ static void _bxt_ddi_phy_init(struct drm_i915_private *dev_priv,
|
|||
|
||||
void bxt_ddi_phy_uninit(struct drm_i915_private *dev_priv, enum dpio_phy phy)
|
||||
{
|
||||
const struct bxt_ddi_phy_info *phy_info;
|
||||
uint32_t val;
|
||||
|
||||
phy_info = bxt_get_phy_info(dev_priv, phy);
|
||||
|
||||
val = I915_READ(BXT_PHY_CTL_FAMILY(phy));
|
||||
val &= ~COMMON_RESET_DIS;
|
||||
I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val);
|
||||
|
||||
val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
|
||||
val &= ~GT_DISPLAY_POWER_ON(phy);
|
||||
val &= ~phy_info->pwron_mask;
|
||||
I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val);
|
||||
}
|
||||
|
||||
void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy)
|
||||
{
|
||||
const struct bxt_ddi_phy_info *phy_info = &bxt_ddi_phy_info[phy];
|
||||
const struct bxt_ddi_phy_info *phy_info =
|
||||
bxt_get_phy_info(dev_priv, phy);
|
||||
enum dpio_phy rcomp_phy = phy_info->rcomp_phy;
|
||||
bool was_enabled;
|
||||
|
||||
|
@ -460,10 +542,12 @@ __phy_reg_verify_state(struct drm_i915_private *dev_priv, enum dpio_phy phy,
|
|||
bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy)
|
||||
{
|
||||
const struct bxt_ddi_phy_info *phy_info = &bxt_ddi_phy_info[phy];
|
||||
const struct bxt_ddi_phy_info *phy_info;
|
||||
uint32_t mask;
|
||||
bool ok;
|
||||
|
||||
phy_info = bxt_get_phy_info(dev_priv, phy);
|
||||
|
||||
#define _CHK(reg, mask, exp, fmt, ...) \
|
||||
__phy_reg_verify_state(dev_priv, phy, reg, mask, exp, fmt, \
|
||||
## __VA_ARGS__)
|
||||
|
@ -539,7 +623,7 @@ void bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder *encoder,
|
|||
enum dpio_channel ch;
|
||||
int lane;
|
||||
|
||||
bxt_port_to_phy_channel(port, &phy, &ch);
|
||||
bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
|
||||
|
||||
for (lane = 0; lane < 4; lane++) {
|
||||
u32 val = I915_READ(BXT_PORT_TX_DW14_LN(phy, ch, lane));
|
||||
|
@ -567,7 +651,7 @@ bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder)
|
|||
int lane;
|
||||
uint8_t mask;
|
||||
|
||||
bxt_port_to_phy_channel(port, &phy, &ch);
|
||||
bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
|
||||
|
||||
mask = 0;
|
||||
for (lane = 0; lane < 4; lane++) {
|
||||
|
|
|
@ -1373,7 +1373,7 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
|
|||
enum dpio_phy phy;
|
||||
enum dpio_channel ch;
|
||||
|
||||
bxt_port_to_phy_channel(port, &phy, &ch);
|
||||
bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
|
||||
|
||||
/* Non-SSC reference */
|
||||
temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
|
||||
|
@ -1491,7 +1491,7 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
|
|||
enum dpio_phy phy;
|
||||
enum dpio_channel ch;
|
||||
|
||||
bxt_port_to_phy_channel(port, &phy, &ch);
|
||||
bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
|
||||
|
||||
if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
|
||||
return false;
|
||||
|
|
|
@ -477,6 +477,18 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
|
|||
#define GLK_DISPLAY_DDI_C_POWER_DOMAINS ( \
|
||||
BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \
|
||||
BIT(POWER_DOMAIN_INIT))
|
||||
#define GLK_DPIO_CMN_A_POWER_DOMAINS ( \
|
||||
BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \
|
||||
BIT(POWER_DOMAIN_AUX_A) | \
|
||||
BIT(POWER_DOMAIN_INIT))
|
||||
#define GLK_DPIO_CMN_B_POWER_DOMAINS ( \
|
||||
BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \
|
||||
BIT(POWER_DOMAIN_AUX_B) | \
|
||||
BIT(POWER_DOMAIN_INIT))
|
||||
#define GLK_DPIO_CMN_C_POWER_DOMAINS ( \
|
||||
BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \
|
||||
BIT(POWER_DOMAIN_AUX_C) | \
|
||||
BIT(POWER_DOMAIN_INIT))
|
||||
#define GLK_DISPLAY_AUX_A_POWER_DOMAINS ( \
|
||||
BIT(POWER_DOMAIN_AUX_A) | \
|
||||
BIT(POWER_DOMAIN_INIT))
|
||||
|
@ -926,6 +938,12 @@ static void bxt_verify_ddi_phy_power_wells(struct drm_i915_private *dev_priv)
|
|||
power_well = lookup_power_well(dev_priv, BXT_DPIO_CMN_BC);
|
||||
if (power_well->count > 0)
|
||||
bxt_ddi_phy_verify_state(dev_priv, power_well->data);
|
||||
|
||||
if (IS_GEMINILAKE(dev_priv)) {
|
||||
power_well = lookup_power_well(dev_priv, GLK_DPIO_CMN_C);
|
||||
if (power_well->count > 0)
|
||||
bxt_ddi_phy_verify_state(dev_priv, power_well->data);
|
||||
}
|
||||
}
|
||||
|
||||
static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv,
|
||||
|
@ -2218,6 +2236,27 @@ static struct i915_power_well glk_power_wells[] = {
|
|||
.ops = &skl_power_well_ops,
|
||||
.id = SKL_DISP_PW_2,
|
||||
},
|
||||
{
|
||||
.name = "dpio-common-a",
|
||||
.domains = GLK_DPIO_CMN_A_POWER_DOMAINS,
|
||||
.ops = &bxt_dpio_cmn_power_well_ops,
|
||||
.id = BXT_DPIO_CMN_A,
|
||||
.data = DPIO_PHY1,
|
||||
},
|
||||
{
|
||||
.name = "dpio-common-b",
|
||||
.domains = GLK_DPIO_CMN_B_POWER_DOMAINS,
|
||||
.ops = &bxt_dpio_cmn_power_well_ops,
|
||||
.id = BXT_DPIO_CMN_BC,
|
||||
.data = DPIO_PHY0,
|
||||
},
|
||||
{
|
||||
.name = "dpio-common-c",
|
||||
.domains = GLK_DPIO_CMN_C_POWER_DOMAINS,
|
||||
.ops = &bxt_dpio_cmn_power_well_ops,
|
||||
.id = GLK_DPIO_CMN_C,
|
||||
.data = DPIO_PHY2,
|
||||
},
|
||||
{
|
||||
.name = "AUX A",
|
||||
.domains = GLK_DISPLAY_AUX_A_POWER_DOMAINS,
|
||||
|
|
Загрузка…
Ссылка в новой задаче