[Intel-gfx] [PATCH 09/15] drm/i915/glk: Implement Geminilake DDI init sequence
Rodrigo Vivi
rodrigo.vivi at gmail.com
Fri Nov 11 01:27:14 UTC 2016
Reviewed-by: Rodrigo Vivi <rodrigo.vivi at intel.com>
On Thu, Nov 10, 2016 at 05:23:14PM +0200, Ander Conselvan de Oliveira wrote:
> 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 at intel.com>
> ---
> drivers/gpu/drm/i915/i915_drv.h | 5 +-
> drivers/gpu/drm/i915/i915_reg.h | 17 +++--
> drivers/gpu/drm/i915/intel_dpio_phy.c | 114 +++++++++++++++++++++++++++-----
> drivers/gpu/drm/i915/intel_dpll_mgr.c | 4 +-
> drivers/gpu/drm/i915/intel_runtime_pm.c | 39 +++++++++++
> 5 files changed, 155 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 4bb745a..f497396 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -207,7 +207,8 @@ enum dpio_channel {
>
> enum dpio_phy {
> DPIO_PHY0,
> - DPIO_PHY1
> + DPIO_PHY1,
> + DPIO_PHY2,
> };
>
> enum intel_display_power_domain {
> @@ -3888,7 +3889,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,
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 78a3347..d78a3e6 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -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)) \
> @@ -726,6 +729,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))
> @@ -1194,8 +1198,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))
> @@ -1207,7 +1213,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
> @@ -1220,9 +1225,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
> diff --git a/drivers/gpu/drm/i915/intel_dpio_phy.c b/drivers/gpu/drm/i915/intel_dpio_phy.c
> index 7a8e82d..4ff601d 100644
> --- a/drivers/gpu/drm/i915/intel_dpio_phy.c
> +++ b/drivers/gpu/drm/i915/intel_dpio_phy.c
> @@ -131,6 +131,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.
> */
> struct {
> @@ -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;
> +
> + phys = bxt_get_phy_list(dev_priv, &count);
>
> - for (i = 0; i < ARRAY_SIZE(bxt_ddi_phy_info); i++) {
> - phy_info = &bxt_ddi_phy_info[i];
> + 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)
> @@ -326,7 +401,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);
>
> /*
> @@ -384,6 +459,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);
> @@ -395,20 +473,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;
>
> @@ -461,10 +543,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__)
> @@ -540,7 +624,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));
> @@ -568,7 +652,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++) {
> diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> index 8205c1c..0311fd4 100644
> --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> @@ -1374,7 +1374,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));
> @@ -1492,7 +1492,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;
> diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
> index 683c15b..30d5112 100644
> --- a/drivers/gpu/drm/i915/intel_runtime_pm.c
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
> @@ -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,
> @@ -2219,6 +2237,27 @@ static struct i915_power_well glk_power_wells[] = {
> .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,
> .ops = &skl_power_well_ops,
> --
> 2.5.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
More information about the Intel-gfx
mailing list