drm/i915/icl: toggle PHY clock gating around link training
authorPaulo Zanoni <paulo.r.zanoni@intel.com>
Wed, 25 Jul 2018 00:28:13 +0000 (17:28 -0700)
committerPaulo Zanoni <paulo.r.zanoni@intel.com>
Wed, 25 Jul 2018 20:45:26 +0000 (13:45 -0700)
The Gen11 TypeC PHY DDI Buffer chapter, PHY Clock Gating Programming
section says that PHY clock gating should be disabled before starting
voltage swing programming, then enabled after any link training is
complete.

v2: Simple rebase.

Cc: Animesh Manna <animesh.manna@intel.com>
Cc: Manasi Navare <manasi.d.navare@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> (v1)
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180725002813.6938-6-paulo.r.zanoni@intel.com
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h

index cf1d2bbb0613a9b670361e97c71b91f2dde68b91..5530c470f30d41c482f5a2f8fff993659227c0ed 100644 (file)
@@ -2106,6 +2106,26 @@ enum i915_power_well_id {
                                 MG_DP_MODE_LN1_ACU_PORT1)
 #define   MG_DP_MODE_CFG_DP_X2_MODE                    (1 << 7)
 #define   MG_DP_MODE_CFG_DP_X1_MODE                    (1 << 6)
+#define   MG_DP_MODE_CFG_TR2PWR_GATING                 (1 << 5)
+#define   MG_DP_MODE_CFG_TRPWR_GATING                  (1 << 4)
+#define   MG_DP_MODE_CFG_CLNPWR_GATING                 (1 << 3)
+#define   MG_DP_MODE_CFG_DIGPWR_GATING                 (1 << 2)
+#define   MG_DP_MODE_CFG_GAONPWR_GATING                        (1 << 1)
+
+#define MG_MISC_SUS0_PORT1                             0x168814
+#define MG_MISC_SUS0_PORT2                             0x169814
+#define MG_MISC_SUS0_PORT3                             0x16A814
+#define MG_MISC_SUS0_PORT4                             0x16B814
+#define MG_MISC_SUS0(tc_port) \
+       _MMIO(_PORT(tc_port, MG_MISC_SUS0_PORT1, MG_MISC_SUS0_PORT2))
+#define   MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE_MASK     (3 << 14)
+#define   MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE(x)       ((x) << 14)
+#define   MG_MISC_SUS0_CFG_TR2PWR_GATING               (1 << 12)
+#define   MG_MISC_SUS0_CFG_CL2PWR_GATING               (1 << 11)
+#define   MG_MISC_SUS0_CFG_GAONPWR_GATING              (1 << 10)
+#define   MG_MISC_SUS0_CFG_TRPWR_GATING                        (1 << 7)
+#define   MG_MISC_SUS0_CFG_CL1PWR_GATING               (1 << 6)
+#define   MG_MISC_SUS0_CFG_DGPWR_GATING                        (1 << 5)
 
 /* The spec defines this only for BXT PHY0, but lets assume that this
  * would exist for PHY1 too if it had a second channel.
index 399c438bd2106e2853206142513f2259bb4cc33c..0adc043529f2dde704ed35544f59144f1027e3d6 100644 (file)
@@ -2810,6 +2810,7 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
        intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
 
        icl_program_mg_dp_mode(intel_dp);
+       icl_disable_phy_clock_gating(dig_port);
 
        if (IS_ICELAKE(dev_priv))
                icl_ddi_vswing_sequence(encoder, crtc_state->port_clock,
@@ -2828,6 +2829,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
        if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
                intel_dp_stop_link_train(intel_dp);
 
+       icl_enable_phy_clock_gating(dig_port);
+
        intel_ddi_enable_pipe_clock(crtc_state);
 }
 
index 28de73be4507f5923b061c31ce4aed559aadcebb..cc33d7c6ba19249982b288eb11bbad8e746a0158 100644 (file)
@@ -295,6 +295,72 @@ void icl_program_mg_dp_mode(struct intel_dp *intel_dp)
        I915_WRITE(MG_DP_MODE(port, 1), ln1);
 }
 
+void icl_enable_phy_clock_gating(struct intel_digital_port *dig_port)
+{
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+       enum port port = dig_port->base.port;
+       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+       i915_reg_t mg_regs[2] = { MG_DP_MODE(port, 0), MG_DP_MODE(port, 1) };
+       u32 val;
+       int i;
+
+       if (tc_port == PORT_TC_NONE)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(mg_regs); i++) {
+               val = I915_READ(mg_regs[i]);
+               val |= MG_DP_MODE_CFG_TR2PWR_GATING |
+                      MG_DP_MODE_CFG_TRPWR_GATING |
+                      MG_DP_MODE_CFG_CLNPWR_GATING |
+                      MG_DP_MODE_CFG_DIGPWR_GATING |
+                      MG_DP_MODE_CFG_GAONPWR_GATING;
+               I915_WRITE(mg_regs[i], val);
+       }
+
+       val = I915_READ(MG_MISC_SUS0(tc_port));
+       val |= MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE(3) |
+              MG_MISC_SUS0_CFG_TR2PWR_GATING |
+              MG_MISC_SUS0_CFG_CL2PWR_GATING |
+              MG_MISC_SUS0_CFG_GAONPWR_GATING |
+              MG_MISC_SUS0_CFG_TRPWR_GATING |
+              MG_MISC_SUS0_CFG_CL1PWR_GATING |
+              MG_MISC_SUS0_CFG_DGPWR_GATING;
+       I915_WRITE(MG_MISC_SUS0(tc_port), val);
+}
+
+void icl_disable_phy_clock_gating(struct intel_digital_port *dig_port)
+{
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+       enum port port = dig_port->base.port;
+       enum tc_port tc_port = intel_port_to_tc(dev_priv, port);
+       i915_reg_t mg_regs[2] = { MG_DP_MODE(port, 0), MG_DP_MODE(port, 1) };
+       u32 val;
+       int i;
+
+       if (tc_port == PORT_TC_NONE)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(mg_regs); i++) {
+               val = I915_READ(mg_regs[i]);
+               val &= ~(MG_DP_MODE_CFG_TR2PWR_GATING |
+                        MG_DP_MODE_CFG_TRPWR_GATING |
+                        MG_DP_MODE_CFG_CLNPWR_GATING |
+                        MG_DP_MODE_CFG_DIGPWR_GATING |
+                        MG_DP_MODE_CFG_GAONPWR_GATING);
+               I915_WRITE(mg_regs[i], val);
+       }
+
+       val = I915_READ(MG_MISC_SUS0(tc_port));
+       val &= ~(MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE_MASK |
+                MG_MISC_SUS0_CFG_TR2PWR_GATING |
+                MG_MISC_SUS0_CFG_CL2PWR_GATING |
+                MG_MISC_SUS0_CFG_GAONPWR_GATING |
+                MG_MISC_SUS0_CFG_TRPWR_GATING |
+                MG_MISC_SUS0_CFG_CL1PWR_GATING |
+                MG_MISC_SUS0_CFG_DGPWR_GATING);
+       I915_WRITE(MG_MISC_SUS0(tc_port), val);
+}
+
 int
 intel_dp_max_data_rate(int max_link_clock, int max_lanes)
 {
index 4e5b00052b5bd2490b5f4664b3a76789f28c5649..99a5f5be5b82bce22c7f16b7514977e980e6bf5f 100644 (file)
@@ -1715,6 +1715,8 @@ void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
 void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
                          unsigned int frontbuffer_bits);
 void icl_program_mg_dp_mode(struct intel_dp *intel_dp);
+void icl_enable_phy_clock_gating(struct intel_digital_port *dig_port);
+void icl_disable_phy_clock_gating(struct intel_digital_port *dig_port);
 
 void
 intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,