From: Imre Deak Date: Mon, 13 Jun 2016 13:44:34 +0000 (+0300) Subject: drm/i915/bxt: Move DDI PHY enabling/disabling to the power well code X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=9c8d0b8e53b902daeb3622c722b9337a78db724a;p=linux-beck.git drm/i915/bxt: Move DDI PHY enabling/disabling to the power well code So far we depended on the HW to dynamically power down unused PHYs and so we enabled them manually once during driver loading/resuming. There are indications however that we can achieve better power savings by manual powering toggling. So make the PHY enabling/disabling to happen on-demand whenever we need either the corresponding AUX or port functionality. CHV does this already by enabling the PHY along the corresponding PHY common lane power wells there, do the same on BXT by adding virtual power wells for the same purpose. Also sanity check the common lane power down ack signal from the PHY. Do this only when the PHY is enabled, since it's not clear at what point the HW power/clock gates things. While at it rename broxton_ prefix to bxt_ in related function names to better align with the SKL code. Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä --- diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4657aed5d7b0..c8fd8b94deaf 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -716,6 +716,9 @@ enum skl_disp_power_wells { /* Not actual bit groups. Used as IDs for lookup_power_well() */ SKL_DISP_PW_ALWAYS_ON, SKL_DISP_PW_DC_OFF, + + BXT_DPIO_CMN_A, + BXT_DPIO_CMN_BC, }; #define SKL_POWER_WELL_STATE(pw) (1 << ((pw) * 2)) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b10c7b569bd6..dee6dd0f9f37 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1742,8 +1742,8 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder) } } -static bool broxton_phy_is_enabled(struct drm_i915_private *dev_priv, - enum dpio_phy phy) +bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv, + enum dpio_phy phy) { if (!(I915_READ(BXT_P_CR_GT_DISP_PWRON) & GT_DISPLAY_POWER_ON(phy))) return false; @@ -1787,21 +1787,17 @@ static void broxton_phy_wait_grc_done(struct drm_i915_private *dev_priv, DRM_ERROR("timeout waiting for PHY%d GRC\n", phy); } -static bool broxton_phy_verify_state(struct drm_i915_private *dev_priv, - enum dpio_phy phy); - -static void broxton_phy_init(struct drm_i915_private *dev_priv, - enum dpio_phy phy) +void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy) { enum port port; u32 ports, val; - if (broxton_phy_is_enabled(dev_priv, phy)) { + if (bxt_ddi_phy_is_enabled(dev_priv, phy)) { /* Still read out the GRC value for state verification */ if (phy == DPIO_PHY0) dev_priv->bxt_phy_grc = broxton_get_grc(dev_priv, phy); - if (broxton_phy_verify_state(dev_priv, phy)) { + if (bxt_ddi_phy_verify_state(dev_priv, phy)) { DRM_DEBUG_DRIVER("DDI PHY %d already enabled, " "won't reprogram it\n", phy); @@ -1810,8 +1806,6 @@ static void broxton_phy_init(struct drm_i915_private *dev_priv, DRM_DEBUG_DRIVER("DDI PHY %d enabled with invalid state, " "force reprogramming it\n", phy); - } else { - DRM_DEBUG_DRIVER("DDI PHY %d not enabled, enabling it\n", phy); } val = I915_READ(BXT_P_CR_GT_DISP_PWRON); @@ -1919,15 +1913,7 @@ static void broxton_phy_init(struct drm_i915_private *dev_priv, broxton_phy_wait_grc_done(dev_priv, DPIO_PHY1); } -void broxton_ddi_phy_init(struct drm_i915_private *dev_priv) -{ - /* Enable PHY1 first since it provides Rcomp for PHY0 */ - broxton_phy_init(dev_priv, DPIO_PHY1); - broxton_phy_init(dev_priv, DPIO_PHY0); -} - -static void broxton_phy_uninit(struct drm_i915_private *dev_priv, - enum dpio_phy phy) +void bxt_ddi_phy_uninit(struct drm_i915_private *dev_priv, enum dpio_phy phy) { uint32_t val; @@ -1940,12 +1926,6 @@ static void broxton_phy_uninit(struct drm_i915_private *dev_priv, I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val); } -void broxton_ddi_phy_uninit(struct drm_i915_private *dev_priv) -{ - broxton_phy_uninit(dev_priv, DPIO_PHY1); - broxton_phy_uninit(dev_priv, DPIO_PHY0); -} - static bool __printf(6, 7) __phy_reg_verify_state(struct drm_i915_private *dev_priv, enum dpio_phy phy, i915_reg_t reg, u32 mask, u32 expected, @@ -1973,8 +1953,8 @@ __phy_reg_verify_state(struct drm_i915_private *dev_priv, enum dpio_phy phy, return false; } -static bool broxton_phy_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) { enum port port; u32 ports; @@ -1985,8 +1965,7 @@ static bool broxton_phy_verify_state(struct drm_i915_private *dev_priv, __phy_reg_verify_state(dev_priv, phy, reg, mask, exp, fmt, \ ## __VA_ARGS__) - /* We expect the PHY to be always enabled */ - if (!broxton_phy_is_enabled(dev_priv, phy)) + if (!bxt_ddi_phy_is_enabled(dev_priv, phy)) return false; ok = true; @@ -2049,13 +2028,6 @@ static bool broxton_phy_verify_state(struct drm_i915_private *dev_priv, #undef _CHK } -void broxton_ddi_phy_verify_state(struct drm_i915_private *dev_priv) -{ - if (!broxton_phy_verify_state(dev_priv, DPIO_PHY0) || - !broxton_phy_verify_state(dev_priv, DPIO_PHY1)) - i915_report_error(dev_priv, "DDI PHY state mismatch\n"); -} - void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ebe7b3427e2e..17445d7b2810 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1263,9 +1263,12 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv); void hsw_disable_pc8(struct drm_i915_private *dev_priv); void broxton_init_cdclk(struct drm_i915_private *dev_priv); void broxton_uninit_cdclk(struct drm_i915_private *dev_priv); -void broxton_ddi_phy_init(struct drm_i915_private *dev_priv); -void broxton_ddi_phy_uninit(struct drm_i915_private *dev_priv); -void broxton_ddi_phy_verify_state(struct drm_i915_private *dev_priv); +void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy); +void bxt_ddi_phy_uninit(struct drm_i915_private *dev_priv, enum dpio_phy phy); +bool bxt_ddi_phy_is_enabled(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); void gen9_sanitize_dc_state(struct drm_i915_private *dev_priv); void bxt_enable_dc9(struct drm_i915_private *dev_priv); void bxt_disable_dc9(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 10978cb87700..7e91881726a8 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -65,6 +65,9 @@ bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, int power_well_id); +static struct i915_power_well * +lookup_power_well(struct drm_i915_private *dev_priv, int power_well_id); + const char * intel_display_power_domain_str(enum intel_display_power_domain domain) { @@ -436,6 +439,16 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_MODESET) | \ BIT(POWER_DOMAIN_AUX_A) | \ BIT(POWER_DOMAIN_INIT)) +#define BXT_DPIO_CMN_A_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \ + BIT(POWER_DOMAIN_AUX_A) | \ + BIT(POWER_DOMAIN_INIT)) +#define BXT_DPIO_CMN_BC_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ + BIT(POWER_DOMAIN_AUX_B) | \ + BIT(POWER_DOMAIN_AUX_C) | \ + BIT(POWER_DOMAIN_INIT)) static void assert_can_enable_dc9(struct drm_i915_private *dev_priv) { @@ -817,6 +830,72 @@ static void skl_power_well_disable(struct drm_i915_private *dev_priv, skl_set_power_well(dev_priv, power_well, false); } +static enum dpio_phy bxt_power_well_to_phy(struct i915_power_well *power_well) +{ + enum skl_disp_power_wells power_well_id = power_well->data; + + return power_well_id == BXT_DPIO_CMN_A ? DPIO_PHY1 : DPIO_PHY0; +} + +static void bxt_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + enum skl_disp_power_wells power_well_id = power_well->data; + struct i915_power_well *cmn_a_well; + + if (power_well_id == BXT_DPIO_CMN_BC) { + /* + * We need to copy the GRC calibration value from the eDP PHY, + * so make sure it's powered up. + */ + cmn_a_well = lookup_power_well(dev_priv, BXT_DPIO_CMN_A); + intel_power_well_get(dev_priv, cmn_a_well); + } + + bxt_ddi_phy_init(dev_priv, bxt_power_well_to_phy(power_well)); + + if (power_well_id == BXT_DPIO_CMN_BC) + intel_power_well_put(dev_priv, cmn_a_well); +} + +static void bxt_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + bxt_ddi_phy_uninit(dev_priv, bxt_power_well_to_phy(power_well)); +} + +static bool bxt_dpio_cmn_power_well_enabled(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + return bxt_ddi_phy_is_enabled(dev_priv, + bxt_power_well_to_phy(power_well)); +} + +static void bxt_dpio_cmn_power_well_sync_hw(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + if (power_well->count > 0) + bxt_dpio_cmn_power_well_enable(dev_priv, power_well); + else + bxt_dpio_cmn_power_well_disable(dev_priv, power_well); +} + + +static void bxt_verify_ddi_phy_power_wells(struct drm_i915_private *dev_priv) +{ + struct i915_power_well *power_well; + + power_well = lookup_power_well(dev_priv, BXT_DPIO_CMN_A); + if (power_well->count > 0) + bxt_ddi_phy_verify_state(dev_priv, + bxt_power_well_to_phy(power_well)); + + power_well = lookup_power_well(dev_priv, BXT_DPIO_CMN_BC); + if (power_well->count > 0) + bxt_ddi_phy_verify_state(dev_priv, + bxt_power_well_to_phy(power_well)); +} + static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { @@ -843,7 +922,7 @@ static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv, gen9_assert_dbuf_enabled(dev_priv); if (IS_BROXTON(dev_priv)) - broxton_ddi_phy_verify_state(dev_priv); + bxt_verify_ddi_phy_power_wells(dev_priv); } static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv, @@ -1802,6 +1881,13 @@ static const struct i915_power_well_ops gen9_dc_off_power_well_ops = { .is_enabled = gen9_dc_off_power_well_enabled, }; +static const struct i915_power_well_ops bxt_dpio_cmn_power_well_ops = { + .sync_hw = bxt_dpio_cmn_power_well_sync_hw, + .enable = bxt_dpio_cmn_power_well_enable, + .disable = bxt_dpio_cmn_power_well_disable, + .is_enabled = bxt_dpio_cmn_power_well_enabled, +}; + static struct i915_power_well hsw_power_wells[] = { { .name = "always-on", @@ -2038,6 +2124,18 @@ static struct i915_power_well bxt_power_wells[] = { .ops = &skl_power_well_ops, .data = SKL_DISP_PW_2, }, + { + .name = "dpio-common-a", + .domains = BXT_DPIO_CMN_A_POWER_DOMAINS, + .ops = &bxt_dpio_cmn_power_well_ops, + .data = BXT_DPIO_CMN_A, + }, + { + .name = "dpio-common-bc", + .domains = BXT_DPIO_CMN_BC_POWER_DOMAINS, + .ops = &bxt_dpio_cmn_power_well_ops, + .data = BXT_DPIO_CMN_BC, + }, }; static int @@ -2307,10 +2405,6 @@ void bxt_display_core_init(struct drm_i915_private *dev_priv, gen9_dbuf_enable(dev_priv); - broxton_ddi_phy_init(dev_priv); - - broxton_ddi_phy_verify_state(dev_priv); - if (resume && dev_priv->csr.dmc_payload) intel_csr_load_program(dev_priv); } @@ -2322,8 +2416,6 @@ void bxt_display_core_uninit(struct drm_i915_private *dev_priv) gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); - broxton_ddi_phy_uninit(dev_priv); - gen9_dbuf_disable(dev_priv); broxton_uninit_cdclk(dev_priv);