drm/i915/glk: Implement Geminilake DDI init sequence
authorAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Fri, 2 Dec 2016 08:23:51 +0000 (10:23 +0200)
committerAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Fri, 2 Dec 2016 14:40:49 +0000 (16:40 +0200)
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
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_dpio_phy.c
drivers/gpu/drm/i915/intel_dpll_mgr.c
drivers/gpu/drm/i915/intel_runtime_pm.c

index 90ef5a0..035ac75 100644 (file)
@@ -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,
index 35f7820..d1f0720 100644 (file)
@@ -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
index 8c62dea..46e38a0 100644 (file)
@@ -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)
@@ -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++) {
index 976d390..8a82507 100644 (file)
@@ -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;
index 49043fc..4987a66 100644 (file)
@@ -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,