[Intel-gfx] [PATCH 6/8] drm/i915/skl: Turn DC handling into a power well

Imre Deak imre.deak at intel.com
Wed Nov 4 11:15:51 PST 2015


On ti, 2015-11-03 at 13:31 +0100, Patrik Jakobsson wrote:
> Handle DC off as a power well where enabling the power well will prevent
> the DMC to enter selected DC states (required around modesets and Aux
> A). Disabling the power well will allow DC states again. For now the
> highest DC state is DC6 but will be configurable in a later patch.
> 
> Signed-off-by: Patrik Jakobsson <patrik.jakobsson at linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.c         |   6 --
>  drivers/gpu/drm/i915/intel_display.c    |   6 ++
>  drivers/gpu/drm/i915/intel_runtime_pm.c | 107 +++++++++++++++++++++-----------
>  3 files changed, 78 insertions(+), 41 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 37319b0..e190237 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -1069,9 +1069,6 @@ static int skl_suspend_complete(struct drm_i915_private *dev_priv)
>  {
>  	skl_uninit_cdclk(dev_priv);
>  
> -	if (dev_priv->csr.dmc_payload)
> -		skl_enable_dc6(dev_priv);
> -
>  	return 0;
>  }
>  
> @@ -1116,9 +1113,6 @@ static int bxt_resume_prepare(struct drm_i915_private *dev_priv)
>  
>  static int skl_resume_prepare(struct drm_i915_private *dev_priv)
>  {
> -	if (dev_priv->csr.dmc_payload)
> -		skl_disable_dc6(dev_priv);
> -
>  	skl_init_cdclk(dev_priv);
>  	intel_csr_load_program(dev_priv);
>  
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index c6d60b8..e401871 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -13296,6 +13296,9 @@ static int intel_atomic_commit(struct drm_device *dev,
>  			to_intel_crtc_state(crtc->state)->update_pipe;
>  		unsigned long put_domains = 0;
>  
> +		if (modeset)
> +			intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
> +
>  		if (modeset && crtc->state->active) {
>  			update_scanline_offset(to_intel_crtc(crtc));
>  			dev_priv->display.crtc_enable(crtc);
> @@ -13319,6 +13322,9 @@ static int intel_atomic_commit(struct drm_device *dev,
>  			modeset_put_power_domains(dev_priv, put_domains);
>  
>  		intel_post_plane_update(intel_crtc);
> +
> +		if (modeset)
> +			intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
>  	}
>  
>  	/* FIXME: add subpixel order */
> diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
> index c901b19..042d92f 100644
> --- a/drivers/gpu/drm/i915/intel_runtime_pm.c
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
> @@ -49,9 +49,6 @@
>   * present for a given platform.
>   */
>  
> -#define GEN9_ENABLE_DC5(dev) 0
> -#define SKL_ENABLE_DC6(dev) IS_SKYLAKE(dev)
> -
>  #define for_each_power_well(i, power_well, domain_mask, power_domains)	\
>  	for (i = 0;							\
>  	     i < (power_domains)->power_well_count &&			\
> @@ -336,10 +333,15 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
>  	SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS |		\
>  	BIT(POWER_DOMAIN_PLLS) |			\
>  	BIT(POWER_DOMAIN_INIT))
> +#define SKL_DISPLAY_DC_OFF_POWER_DOMAINS (		\
> +	BIT(POWER_DOMAIN_MODESET) |			\
> +	BIT(POWER_DOMAIN_AUX_A) |			\
> +	BIT(POWER_DOMAIN_INIT))
>  #define SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS (		\
>  	(POWER_DOMAIN_MASK & ~(SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS |	\
>  	SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS |		\
> -	SKL_DISPLAY_MISC_IO_POWER_DOMAINS)) |		\
> +	SKL_DISPLAY_MISC_IO_POWER_DOMAINS |		\
> +	SKL_DISPLAY_DC_OFF_POWER_DOMAINS)) |		\
>  	BIT(POWER_DOMAIN_INIT))
>  
>  #define BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS (		\
> @@ -511,20 +513,6 @@ static void gen9_enable_dc5(struct drm_i915_private *dev_priv)
>  	POSTING_READ(DC_STATE_EN);
>  }
>  
> -static void gen9_disable_dc5(struct drm_i915_private *dev_priv)
> -{
> -	uint32_t val;
> -
> -	assert_can_disable_dc5(dev_priv);
> -
> -	DRM_DEBUG_KMS("Disabling DC5\n");
> -
> -	val = I915_READ(DC_STATE_EN);
> -	val &= ~DC_STATE_EN_UPTO_DC5;
> -	I915_WRITE(DC_STATE_EN, val);
> -	POSTING_READ(DC_STATE_EN);
> -}
> -
>  static void assert_can_enable_dc6(struct drm_i915_private *dev_priv)
>  {
>  	struct drm_device *dev = dev_priv->dev;
> @@ -553,6 +541,21 @@ static void assert_can_disable_dc6(struct drm_i915_private *dev_priv)
>  		  "DC6 already programmed to be disabled.\n");
>  }
>  
> +static void gen9_disable_dc5_dc6(struct drm_i915_private *dev_priv)
> +{
> +	uint32_t val;
> +
> +	assert_can_disable_dc5(dev_priv);
> +	assert_can_disable_dc6(dev_priv);
> +
> +	DRM_DEBUG_KMS("Disabling DC5 and DC6\n");
> +
> +	val = I915_READ(DC_STATE_EN);
> +	val &= ~DC_STATE_EN_UPTO_DC5_DC6_MASK;
> +	I915_WRITE(DC_STATE_EN, val);
> +	POSTING_READ(DC_STATE_EN);
> +}
> +
>  void skl_enable_dc6(struct drm_i915_private *dev_priv)
>  {
>  	uint32_t val;
> @@ -632,17 +635,13 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
>  				"Invalid for power well status to be enabled, unless done by the BIOS, \
>  				when request is to disable!\n");
>  			if (power_well->data == SKL_DISP_PW_2) {
> -				if (GEN9_ENABLE_DC5(dev))
> -					gen9_disable_dc5(dev_priv);
> -				if (SKL_ENABLE_DC6(dev)) {
> -					/*
> -					 * DDI buffer programming unnecessary during driver-load/resume
> -					 * as it's already done during modeset initialization then.
> -					 * It's also invalid here as encoder list is still uninitialized.
> -					 */
> -					if (!dev_priv->power_domains.initializing)
> -						intel_prepare_ddi(dev);
> -				}
> +				/*
> +				 * DDI buffer programming unnecessary during driver-load/resume
> +				 * as it's already done during modeset initialization then.
> +				 * It's also invalid here as encoder list is still uninitialized.
> +				 */
> +				if (!dev_priv->power_domains.initializing)
> +					intel_prepare_ddi(dev);
>  			}
>  			I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask);
>  		}
> @@ -658,17 +657,13 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
>  	} else {
>  		if (enable_requested) {
>  			if (IS_SKYLAKE(dev) &&
> -				(power_well->data == SKL_DISP_PW_1))
> +				(power_well->data == SKL_DISP_PW_1)) {
>  				DRM_DEBUG_KMS("Not Disabling PW1, dmc will handle\n");
> -			else {
> +			} else {
>  				I915_WRITE(HSW_PWR_WELL_DRIVER,	tmp & ~req_mask);
>  				POSTING_READ(HSW_PWR_WELL_DRIVER);
>  				DRM_DEBUG_KMS("Disabling %s\n", power_well->name);
>  			}
> -
> -			if (GEN9_ENABLE_DC5(dev) &&
> -				power_well->data == SKL_DISP_PW_2)
> -					gen9_enable_dc5(dev_priv);
>  		}
>  	}
>  
> @@ -743,6 +738,36 @@ static void skl_power_well_disable(struct drm_i915_private *dev_priv,
>  	skl_set_power_well(dev_priv, power_well, false);
>  }
>  
> +static bool skl_dc_off_power_well_enabled(struct drm_i915_private *dev_priv,
> +					  struct i915_power_well *power_well)
> +{
> +	return !(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6);
> +}
> +
> +static void skl_dc_off_power_well_enable(struct drm_i915_private *dev_priv,
> +					 struct i915_power_well *power_well)
> +{
> +	gen9_disable_dc5_dc6(dev_priv);
> +}
> +
> +static void skl_dc_off_power_well_disable(struct drm_i915_private *dev_priv,
> +					  struct i915_power_well *power_well)
> +{
> +	if (IS_SKYLAKE(dev_priv))
> +		skl_enable_dc6(dev_priv);
> +	else
> +		gen9_enable_dc5(dev_priv);
> +}
> +
> +static void skl_dc_off_power_well_sync_hw(struct drm_i915_private *dev_priv,
> +					  struct i915_power_well *power_well)
> +{
> +	if (power_well->count > 0)
> +		skl_dc_off_power_well_enable(dev_priv, power_well);
> +	else
> +		skl_dc_off_power_well_disable(dev_priv, power_well);
> +}
> +
>  static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv,
>  					   struct i915_power_well *power_well)
>  {
> @@ -1574,6 +1599,13 @@ static const struct i915_power_well_ops skl_power_well_ops = {
>  	.is_enabled = skl_power_well_enabled,
>  };
>  
> +static const struct i915_power_well_ops skl_dc_off_power_well_ops = {
> +	.sync_hw = skl_dc_off_power_well_sync_hw,
> +	.enable = skl_dc_off_power_well_enable,
> +	.disable = skl_dc_off_power_well_disable,
> +	.is_enabled = skl_dc_off_power_well_enabled,
> +};
> +
>  static struct i915_power_well hsw_power_wells[] = {
>  	{
>  		.name = "always-on",
> @@ -1738,6 +1770,11 @@ static struct i915_power_well skl_power_wells[] = {
>  		.data = SKL_DISP_PW_1,
>  	},
>  	{
> +		.name = "DC off",
> +		.domains = SKL_DISPLAY_DC_OFF_POWER_DOMAINS,
> +		.ops = &skl_dc_off_power_well_ops,

We need to set a unique ID in .data, since we use it to look up power
wells. I have a patch to fix up the other places missing an ID, but you
could fix this one up already now.

> +	},
> +	{
>  		.name = "MISC IO power well",
>  		.domains = SKL_DISPLAY_MISC_IO_POWER_DOMAINS,
>  		.ops = &skl_power_well_ops,




More information about the Intel-gfx mailing list