diff mbox

[v4,2/8] drm/i915/skl: Add DC5 Trigger Sequence.

Message ID 1429174334-12089-3-git-send-email-animesh.manna@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Manna, Animesh April 16, 2015, 8:52 a.m. UTC
From: Suketu Shah <suketu.j.shah@intel.com>

Add triggers as per expectations mentioned in gen9_enable_dc5
and gen9_disable_dc5 patch.

Also call POSTING_READ for every write to a register to ensure that
its written immediately.

v1: Remove POSTING_READ calls as they've already been added in previous patches.

v2: Rebase to move all runtime pm specific changes to intel_runtime_pm.c file.

Modified as per review comments from Imre:
1] Change variable name 'dc5_allowed' to 'dc5_enabled' to correspond to relevant
   functions.
2] Move the check dc5_enabled in skl_set_power_well() to disable DC5 into
   gen9_disable_DC5 which is a more appropriate place.
3] Convert checks for 'pm.dc5_enabled' and 'pm.suspended' in skl_set_power_well()
   to warnings. However, removing them for now as they'll be included in a future patch
   asserting DC-state entry/exit criteria.
4] Enable DC5, only when CSR firmware is verified to be loaded. Create new structure
   to track 'enabled' and 'deferred' status of DC5.
5] Ensure runtime PM reference is obtained, if CSR is not loaded, to avoid entering
   runtime-suspend and release it when it's loaded.
6] Protect necessary CSR-related code with locks.
7] Move CSR-loading call to runtime PM initialization, as power domains needed to be
   accessed during deferred DC5-enabling, are not initialized earlier.

v3: Rebase to latest.

Modified as per review comments from Imre:
1] Use blocking wait for CSR-loading to finish to enable DC5  for simplicity, instead of
   deferring enabling DC5 until CSR is loaded.
2] Obtain runtime PM reference during CSR-loading initialization itself as deferred DC5-
   enabling is removed and release it at the end of CSR-loading functionality.
3] Revert calling CSR-loading functionality to the beginning of i915 driver-load
   functionality to avoid any delay in loading.
4] Define another variable to track whether CSR-loading failed and use it to avoid enabling
   DC5 if it's true.
5] Define CSR-load-status accessor functions for use later.

v4:
1] Disable DC5 before enabling PG2 instead of after it.
2] DC5 was being mistaken enabled even when CSR-loading timed-out. Fix that.
3] Enable DC5-related functionality using a macro.
4] Remove dc5_enabled tracking variable and its use as it's not needed now.

v5:
1] Mark CSR failed to load where necessary in finish_csr_load function.
2] Use mutex-protected accessor function to check if CSR loaded instead of directly
   accessing the variable.
3] Prefix csr_load_status_get/set function names with intel_.

v6: rebase to latest.
v7: Rebase on top of nightly (Damien)
v8: Squashed the patch from Imre - added csr helper pointers to simplify the code. (Imre)
v9: After adding dmc ver 1.0 support rebased on top of nightly. (Animesh)
v10: Added a enum for different csr states, suggested by Imre. (Animesh)

v11: Based on review comments from Imre, Damien and Daniel following changes done
- enum name chnaged to csr_state (singular form).
- FW_UNINITIALIZED used as zeroth element in enum csr_state.
- Prototype changed for helper function(set/get csr status), using enum csr_state instead of bool.

Issue: VIZ-2819
Signed-off-by: A.Sunil Kamath <sunil.kamath@intel.com>
Signed-off-by: Suketu Shah <suketu.j.shah@intel.com>
Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Animesh Manna <animesh.manna@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h         |  7 +++++
 drivers/gpu/drm/i915/intel_csr.c        | 49 +++++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_drv.h        |  3 ++
 drivers/gpu/drm/i915/intel_runtime_pm.c | 33 ++++++++++++++++++++++
 4 files changed, 90 insertions(+), 2 deletions(-)

Comments

Imre Deak April 16, 2015, 9:25 a.m. UTC | #1
On to, 2015-04-16 at 14:22 +0530, Animesh Manna wrote:
> From: Suketu Shah <suketu.j.shah@intel.com>
> 
> Add triggers as per expectations mentioned in gen9_enable_dc5
> and gen9_disable_dc5 patch.
> 
> Also call POSTING_READ for every write to a register to ensure that
> its written immediately.
> 
> v1: Remove POSTING_READ calls as they've already been added in previous patches.
> 
> v2: Rebase to move all runtime pm specific changes to intel_runtime_pm.c file.
> 
> Modified as per review comments from Imre:
> 1] Change variable name 'dc5_allowed' to 'dc5_enabled' to correspond to relevant
>    functions.
> 2] Move the check dc5_enabled in skl_set_power_well() to disable DC5 into
>    gen9_disable_DC5 which is a more appropriate place.
> 3] Convert checks for 'pm.dc5_enabled' and 'pm.suspended' in skl_set_power_well()
>    to warnings. However, removing them for now as they'll be included in a future patch
>    asserting DC-state entry/exit criteria.
> 4] Enable DC5, only when CSR firmware is verified to be loaded. Create new structure
>    to track 'enabled' and 'deferred' status of DC5.
> 5] Ensure runtime PM reference is obtained, if CSR is not loaded, to avoid entering
>    runtime-suspend and release it when it's loaded.
> 6] Protect necessary CSR-related code with locks.
> 7] Move CSR-loading call to runtime PM initialization, as power domains needed to be
>    accessed during deferred DC5-enabling, are not initialized earlier.
> 
> v3: Rebase to latest.
> 
> Modified as per review comments from Imre:
> 1] Use blocking wait for CSR-loading to finish to enable DC5  for simplicity, instead of
>    deferring enabling DC5 until CSR is loaded.
> 2] Obtain runtime PM reference during CSR-loading initialization itself as deferred DC5-
>    enabling is removed and release it at the end of CSR-loading functionality.
> 3] Revert calling CSR-loading functionality to the beginning of i915 driver-load
>    functionality to avoid any delay in loading.
> 4] Define another variable to track whether CSR-loading failed and use it to avoid enabling
>    DC5 if it's true.
> 5] Define CSR-load-status accessor functions for use later.
> 
> v4:
> 1] Disable DC5 before enabling PG2 instead of after it.
> 2] DC5 was being mistaken enabled even when CSR-loading timed-out. Fix that.
> 3] Enable DC5-related functionality using a macro.
> 4] Remove dc5_enabled tracking variable and its use as it's not needed now.
> 
> v5:
> 1] Mark CSR failed to load where necessary in finish_csr_load function.
> 2] Use mutex-protected accessor function to check if CSR loaded instead of directly
>    accessing the variable.
> 3] Prefix csr_load_status_get/set function names with intel_.
> 
> v6: rebase to latest.
> v7: Rebase on top of nightly (Damien)
> v8: Squashed the patch from Imre - added csr helper pointers to simplify the code. (Imre)
> v9: After adding dmc ver 1.0 support rebased on top of nightly. (Animesh)
> v10: Added a enum for different csr states, suggested by Imre. (Animesh)
> 
> v11: Based on review comments from Imre, Damien and Daniel following changes done
> - enum name chnaged to csr_state (singular form).
> - FW_UNINITIALIZED used as zeroth element in enum csr_state.
> - Prototype changed for helper function(set/get csr status), using enum csr_state instead of bool.
> 
> Issue: VIZ-2819
> Signed-off-by: A.Sunil Kamath <sunil.kamath@intel.com>
> Signed-off-by: Suketu Shah <suketu.j.shah@intel.com>
> Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> Signed-off-by: Animesh Manna <animesh.manna@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h         |  7 +++++
>  drivers/gpu/drm/i915/intel_csr.c        | 49 +++++++++++++++++++++++++++++++--
>  drivers/gpu/drm/i915/intel_drv.h        |  3 ++
>  drivers/gpu/drm/i915/intel_runtime_pm.c | 33 ++++++++++++++++++++++
>  4 files changed, 90 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 90e47a9..670e407 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -667,6 +667,12 @@ struct intel_uncore {
>  #define for_each_fw_domain(domain__, dev_priv__, i__) \
>  	for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__)
>  
> +enum csr_state {
> +	FW_UNINITIALIZED = 0,
> +	FW_LOADED,
> +	FW_FAILED
> +};
> +
>  struct intel_csr {
>  	const char *fw_path;
>  	__be32 *dmc_payload;
> @@ -674,6 +680,7 @@ struct intel_csr {
>  	uint32_t mmio_count;
>  	uint32_t mmioaddr[8];
>  	uint32_t mmiodata[8];
> +	enum csr_state state;
>  };
>  
>  #define DEV_INFO_FOR_EACH_FLAG(func, sep) \
> diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
> index f5fa574..fe6789f 100644
> --- a/drivers/gpu/drm/i915/intel_csr.c
> +++ b/drivers/gpu/drm/i915/intel_csr.c
> @@ -183,6 +183,25 @@ static char intel_get_substepping(struct drm_device *dev)
>  		return -ENODATA;
>  }
>  
> +enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv)
> +{
> +	enum csr_state state;
> +
> +	mutex_lock(&dev_priv->csr_lock);
> +	state = dev_priv->csr.state;
> +	mutex_unlock(&dev_priv->csr_lock);
> +
> +	return state;
> +}
> +
> +void intel_csr_load_status_set(struct drm_i915_private *dev_priv,
> +			enum csr_state state)
> +{
> +	mutex_lock(&dev_priv->csr_lock);
> +	dev_priv->csr.state = state;
> +	mutex_unlock(&dev_priv->csr_lock);
> +}
> +
>  void intel_csr_load_program(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -204,6 +223,8 @@ void intel_csr_load_program(struct drm_device *dev)
>  		I915_WRITE(dev_priv->csr.mmioaddr[i],
>  			dev_priv->csr.mmiodata[i]);
>  	}
> +
> +	dev_priv->csr.state = FW_LOADED;
>  	mutex_unlock(&dev_priv->csr_lock);
>  }
>  
> @@ -223,11 +244,13 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>  
>  	if (!fw) {
>  		i915_firmware_load_error_print(csr->fw_path, 0);
> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>  		goto out;
>  	}
>  
>  	if ((stepping == -ENODATA) || (substepping == -ENODATA)) {
>  		DRM_ERROR("Unknown stepping info, firmware loading failed\n");
> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>  		goto out;
>  	}
>  
> @@ -237,6 +260,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>  		(css_header->header_len * 4)) {
>  		DRM_ERROR("Firmware has wrong CSS header length %u bytes\n",
>  			(css_header->header_len * 4));
> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>  		goto out;
>  	}
>  	readcount += sizeof(struct intel_css_header);
> @@ -248,6 +272,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>  		(package_header->header_len * 4)) {
>  		DRM_ERROR("Firmware has wrong package header length %u bytes\n",
>  			(package_header->header_len * 4));
> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>  		goto out;
>  	}
>  	readcount += sizeof(struct intel_package_header);
> @@ -268,6 +293,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>  	}
>  	if (dmc_offset == CSR_DEFAULT_FW_OFFSET) {
>  		DRM_ERROR("Firmware not supported for %c stepping\n", stepping);
> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>  		goto out;
>  	}
>  	readcount += dmc_offset;
> @@ -277,6 +303,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>  	if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) {
>  		DRM_ERROR("Firmware has wrong dmc header length %u bytes\n",
>  				(dmc_header->header_len));
> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>  		goto out;
>  	}
>  	readcount += sizeof(struct intel_dmc_header);
> @@ -285,6 +312,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>  	if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) {
>  		DRM_ERROR("Firmware has wrong mmio count %u\n",
>  						dmc_header->mmio_count);
> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>  		goto out;
>  	}
>  	csr->mmio_count = dmc_header->mmio_count;
> @@ -293,6 +321,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>  			dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) {
>  			DRM_ERROR(" Firmware has wrong mmio address 0x%x\n",
>  						dmc_header->mmioaddr[i]);
> +			intel_csr_load_status_set(dev_priv, FW_FAILED);
>  			goto out;
>  		}
>  		csr->mmioaddr[i] = dmc_header->mmioaddr[i];
> @@ -303,6 +332,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>  	nbytes = dmc_header->fw_size * 4;
>  	if (nbytes > CSR_MAX_FW_SIZE) {
>  		DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes);
> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>  		goto out;
>  	}
>  	csr->dmc_fw_size = dmc_header->fw_size;
> @@ -310,6 +340,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>  	csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL);
>  	if (!csr->dmc_payload) {
>  		DRM_ERROR("Memory allocation failed for dmc payload\n");
> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>  		goto out;
>  	}
>  
> @@ -327,6 +358,11 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>  	/* load csr program during system boot, as needed for DC states */
>  	intel_csr_load_program(dev);
>  out:
> +	/*
> +	 * Release the runtime pm reference obtained when
> +	 * CSR wasn't loaded.
> +	 */
> +	intel_runtime_pm_put(dev_priv);

I'm not sure if runtime PM would work correctly without DC5/6, so let's
not enable RPM if the firmware fails to load. This is also inconsistent
with the error handling in intel_csr_ucode_init().

>  	release_firmware(fw);
>  }
>  
> @@ -343,17 +379,25 @@ void intel_csr_ucode_init(struct drm_device *dev)
>  		csr->fw_path = I915_CSR_SKL;
>  	else {
>  		DRM_ERROR("Unexpected: no known CSR firmware for platform\n");
> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>  		return;
>  	}
>  
> +	/*
> +	 * Obtain a runtime pm reference, until CSR is loaded,
> +	 * to avoid entering runtime-suspend.
> +	 */
> +	intel_runtime_pm_get(dev_priv);
> +
>  	/* CSR supported for platform, load firmware */
>  	ret = request_firmware_nowait(THIS_MODULE, true, csr->fw_path,
>  				&dev_priv->dev->pdev->dev,
>  				GFP_KERNEL, dev_priv,
>  				finish_csr_load);
> -	if (ret)
> +	if (ret) {
>  		i915_firmware_load_error_print(csr->fw_path, ret);
> -
> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> +	}
>  }
>  
>  void intel_csr_ucode_fini(struct drm_device *dev)
> @@ -363,5 +407,6 @@ void intel_csr_ucode_fini(struct drm_device *dev)
>  	if (!HAS_CSR(dev))
>  		return;
>  
> +	intel_csr_load_status_set(dev_priv, FW_FAILED);
>  	kfree(dev_priv->csr.dmc_payload);
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index f3a2d88..25d7956 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1064,6 +1064,9 @@ unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
>  
>  /* intel_csr.c */
>  void intel_csr_ucode_init(struct drm_device *dev);
> +enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv);
> +void intel_csr_load_status_set(struct drm_i915_private *dev_priv,
> +					enum csr_state state);
>  void intel_csr_load_program(struct drm_device *dev);
>  void intel_csr_ucode_fini(struct drm_device *dev);
>  
> diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
> index ce00e69..23f02a8 100644
> --- a/drivers/gpu/drm/i915/intel_runtime_pm.c
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
> @@ -49,6 +49,8 @@
>   * present for a given platform.
>   */
>  
> +#define GEN9_ENABLE_DC5(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 &&			\
> @@ -319,9 +321,20 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
>  	SKL_DISPLAY_MISC_IO_POWER_DOMAINS)) |		\
>  	BIT(POWER_DOMAIN_INIT))
>  
> +static void gen9_enable_dc5(struct drm_i915_private *dev_priv)
> +{
> +	/* TODO: Implementation to be done. */
> +}
> +
> +static void gen9_disable_dc5(struct drm_i915_private *dev_priv)
> +{
> +	/* TODO: Implementation to be done. */
> +}
> +
>  static void skl_set_power_well(struct drm_i915_private *dev_priv,
>  			struct i915_power_well *power_well, bool enable)
>  {
> +	struct drm_device *dev = dev_priv->dev;
>  	uint32_t tmp, fuse_status;
>  	uint32_t req_mask, state_mask;
>  	bool is_enabled, enable_requested, check_fuse_status = false;
> @@ -361,6 +374,13 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
>  
>  	if (enable) {
>  		if (!enable_requested) {
> +			WARN((tmp & state_mask) &&
> +				!I915_READ(HSW_PWR_WELL_BIOS),
> +				"Invalid for power well status to be enabled, unless done by the BIOS, \
> +				when request is to disable!\n");
> +			if (GEN9_ENABLE_DC5(dev) &&
> +				power_well->data == SKL_DISP_PW_2)
> +				gen9_disable_dc5(dev_priv);
>  			I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask);
>  		}
>  
> @@ -377,6 +397,19 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
>  			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) {
> +				enum csr_state state;
> +
> +				wait_for((state = intel_csr_load_status_get(dev_priv)) !=
> +						FW_UNINITIALIZED, 1000);
> +				if (state != FW_LOADED)
> +					DRM_ERROR("CSR firmware not ready (%d)\n",
> +							state);
> +				else
> +					gen9_enable_dc5(dev_priv);
> +			}
>  		}
>  	}
>
Imre Deak April 16, 2015, 9:48 a.m. UTC | #2
On to, 2015-04-16 at 12:25 +0300, Imre Deak wrote:
> On to, 2015-04-16 at 14:22 +0530, Animesh Manna wrote:
> >  [...]
> > @@ -223,11 +244,13 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >  
> >  	if (!fw) {
> >  		i915_firmware_load_error_print(csr->fw_path, 0);
> > +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >  		goto out;
> >  	}
> >  
> >  	if ((stepping == -ENODATA) || (substepping == -ENODATA)) {
> >  		DRM_ERROR("Unknown stepping info, firmware loading failed\n");
> > +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >  		goto out;
> >  	}
> >  
> > @@ -237,6 +260,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >  		(css_header->header_len * 4)) {
> >  		DRM_ERROR("Firmware has wrong CSS header length %u bytes\n",
> >  			(css_header->header_len * 4));
> > +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >  		goto out;
> >  	}
> >  	readcount += sizeof(struct intel_css_header);
> > @@ -248,6 +272,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >  		(package_header->header_len * 4)) {
> >  		DRM_ERROR("Firmware has wrong package header length %u bytes\n",
> >  			(package_header->header_len * 4));
> > +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >  		goto out;
> >  	}
> >  	readcount += sizeof(struct intel_package_header);
> > @@ -268,6 +293,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >  	}
> >  	if (dmc_offset == CSR_DEFAULT_FW_OFFSET) {
> >  		DRM_ERROR("Firmware not supported for %c stepping\n", stepping);
> > +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >  		goto out;
> >  	}
> >  	readcount += dmc_offset;
> > @@ -277,6 +303,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >  	if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) {
> >  		DRM_ERROR("Firmware has wrong dmc header length %u bytes\n",
> >  				(dmc_header->header_len));
> > +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >  		goto out;
> >  	}
> >  	readcount += sizeof(struct intel_dmc_header);
> > @@ -285,6 +312,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >  	if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) {
> >  		DRM_ERROR("Firmware has wrong mmio count %u\n",
> >  						dmc_header->mmio_count);
> > +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >  		goto out;
> >  	}
> >  	csr->mmio_count = dmc_header->mmio_count;
> > @@ -293,6 +321,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >  			dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) {
> >  			DRM_ERROR(" Firmware has wrong mmio address 0x%x\n",
> >  						dmc_header->mmioaddr[i]);
> > +			intel_csr_load_status_set(dev_priv, FW_FAILED);
> >  			goto out;
> >  		}
> >  		csr->mmioaddr[i] = dmc_header->mmioaddr[i];
> > @@ -303,6 +332,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >  	nbytes = dmc_header->fw_size * 4;
> >  	if (nbytes > CSR_MAX_FW_SIZE) {
> >  		DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes);
> > +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >  		goto out;
> >  	}
> >  	csr->dmc_fw_size = dmc_header->fw_size;
> > @@ -310,6 +340,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >  	csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL);
> >  	if (!csr->dmc_payload) {
> >  		DRM_ERROR("Memory allocation failed for dmc payload\n");
> > +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >  		goto out;
> >  	}
> >  
> > @@ -327,6 +358,11 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >  	/* load csr program during system boot, as needed for DC states */
> >  	intel_csr_load_program(dev);
> >  out:

Also, since you have to anyway change the patch: could you replace all
the above intel_csr_load_status_set(dev_priv, FW_FAILED); with one here
using a fw_loaded bool that you set after intel_csr_load_program?

> > +	/*
> > +	 * Release the runtime pm reference obtained when
> > +	 * CSR wasn't loaded.
> > +	 */
> > +	intel_runtime_pm_put(dev_priv);
Manna, Animesh April 17, 2015, 5:59 a.m. UTC | #3
On 4/16/2015 3:18 PM, Imre Deak wrote:
> On to, 2015-04-16 at 12:25 +0300, Imre Deak wrote:
>> On to, 2015-04-16 at 14:22 +0530, Animesh Manna wrote:
>>>   [...]
>>> @@ -223,11 +244,13 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>>>   
>>>   	if (!fw) {
>>>   		i915_firmware_load_error_print(csr->fw_path, 0);
>>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>>>   		goto out;
>>>   	}
>>>   
>>>   	if ((stepping == -ENODATA) || (substepping == -ENODATA)) {
>>>   		DRM_ERROR("Unknown stepping info, firmware loading failed\n");
>>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>>>   		goto out;
>>>   	}
>>>   
>>> @@ -237,6 +260,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>>>   		(css_header->header_len * 4)) {
>>>   		DRM_ERROR("Firmware has wrong CSS header length %u bytes\n",
>>>   			(css_header->header_len * 4));
>>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>>>   		goto out;
>>>   	}
>>>   	readcount += sizeof(struct intel_css_header);
>>> @@ -248,6 +272,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>>>   		(package_header->header_len * 4)) {
>>>   		DRM_ERROR("Firmware has wrong package header length %u bytes\n",
>>>   			(package_header->header_len * 4));
>>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>>>   		goto out;
>>>   	}
>>>   	readcount += sizeof(struct intel_package_header);
>>> @@ -268,6 +293,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>>>   	}
>>>   	if (dmc_offset == CSR_DEFAULT_FW_OFFSET) {
>>>   		DRM_ERROR("Firmware not supported for %c stepping\n", stepping);
>>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>>>   		goto out;
>>>   	}
>>>   	readcount += dmc_offset;
>>> @@ -277,6 +303,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>>>   	if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) {
>>>   		DRM_ERROR("Firmware has wrong dmc header length %u bytes\n",
>>>   				(dmc_header->header_len));
>>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>>>   		goto out;
>>>   	}
>>>   	readcount += sizeof(struct intel_dmc_header);
>>> @@ -285,6 +312,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>>>   	if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) {
>>>   		DRM_ERROR("Firmware has wrong mmio count %u\n",
>>>   						dmc_header->mmio_count);
>>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>>>   		goto out;
>>>   	}
>>>   	csr->mmio_count = dmc_header->mmio_count;
>>> @@ -293,6 +321,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>>>   			dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) {
>>>   			DRM_ERROR(" Firmware has wrong mmio address 0x%x\n",
>>>   						dmc_header->mmioaddr[i]);
>>> +			intel_csr_load_status_set(dev_priv, FW_FAILED);
>>>   			goto out;
>>>   		}
>>>   		csr->mmioaddr[i] = dmc_header->mmioaddr[i];
>>> @@ -303,6 +332,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>>>   	nbytes = dmc_header->fw_size * 4;
>>>   	if (nbytes > CSR_MAX_FW_SIZE) {
>>>   		DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes);
>>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>>>   		goto out;
>>>   	}
>>>   	csr->dmc_fw_size = dmc_header->fw_size;
>>> @@ -310,6 +340,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>>>   	csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL);
>>>   	if (!csr->dmc_payload) {
>>>   		DRM_ERROR("Memory allocation failed for dmc payload\n");
>>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
>>>   		goto out;
>>>   	}
>>>   
>>> @@ -327,6 +358,11 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>>>   	/* load csr program during system boot, as needed for DC states */
>>>   	intel_csr_load_program(dev);
>>>   out:
> Also, since you have to anyway change the patch: could you replace all
> the above intel_csr_load_status_set(dev_priv, FW_FAILED); with one here
> using a fw_loaded bool that you set after intel_csr_load_program?

Now we do not have fw_loaded bool in current patch, enum csr_state is used to capture the current state.
Want me to add fw_loaded bool and call intel_csr_load_status_set(dev_priv, FW_FAILED) based on that?

Regards,
Animesh

>
>>> +	/*
>>> +	 * Release the runtime pm reference obtained when
>>> +	 * CSR wasn't loaded.
>>> +	 */
>>> +	intel_runtime_pm_put(dev_priv);
>
Imre Deak April 17, 2015, 7:15 a.m. UTC | #4
On Fri, 2015-04-17 at 11:29 +0530, Animesh Manna wrote:
> 
> On 4/16/2015 3:18 PM, Imre Deak wrote:
> > On to, 2015-04-16 at 12:25 +0300, Imre Deak wrote:
> >> On to, 2015-04-16 at 14:22 +0530, Animesh Manna wrote:
> >>>   [...]
> >>> @@ -223,11 +244,13 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >>>   

To clarify, I meant to add at the top of this function:
bool fw_loaded = false;

> >>>   	if (!fw) {
> >>>   		i915_firmware_load_error_print(csr->fw_path, 0);
> >>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);

... remove all the intel_csr_load_status_set(FW_FAILED) calls added in
this function

> >>>   		goto out;
> >>>   	}
> >>>   
> >>>   	if ((stepping == -ENODATA) || (substepping == -ENODATA)) {
> >>>   		DRM_ERROR("Unknown stepping info, firmware loading failed\n");
> >>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >>>   		goto out;
> >>>   	}
> >>>   
> >>> @@ -237,6 +260,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >>>   		(css_header->header_len * 4)) {
> >>>   		DRM_ERROR("Firmware has wrong CSS header length %u bytes\n",
> >>>   			(css_header->header_len * 4));
> >>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >>>   		goto out;
> >>>   	}
> >>>   	readcount += sizeof(struct intel_css_header);
> >>> @@ -248,6 +272,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >>>   		(package_header->header_len * 4)) {
> >>>   		DRM_ERROR("Firmware has wrong package header length %u bytes\n",
> >>>   			(package_header->header_len * 4));
> >>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >>>   		goto out;
> >>>   	}
> >>>   	readcount += sizeof(struct intel_package_header);
> >>> @@ -268,6 +293,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >>>   	}
> >>>   	if (dmc_offset == CSR_DEFAULT_FW_OFFSET) {
> >>>   		DRM_ERROR("Firmware not supported for %c stepping\n", stepping);
> >>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >>>   		goto out;
> >>>   	}
> >>>   	readcount += dmc_offset;
> >>> @@ -277,6 +303,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >>>   	if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) {
> >>>   		DRM_ERROR("Firmware has wrong dmc header length %u bytes\n",
> >>>   				(dmc_header->header_len));
> >>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >>>   		goto out;
> >>>   	}
> >>>   	readcount += sizeof(struct intel_dmc_header);
> >>> @@ -285,6 +312,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >>>   	if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) {
> >>>   		DRM_ERROR("Firmware has wrong mmio count %u\n",
> >>>   						dmc_header->mmio_count);
> >>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >>>   		goto out;
> >>>   	}
> >>>   	csr->mmio_count = dmc_header->mmio_count;
> >>> @@ -293,6 +321,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >>>   			dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) {
> >>>   			DRM_ERROR(" Firmware has wrong mmio address 0x%x\n",
> >>>   						dmc_header->mmioaddr[i]);
> >>> +			intel_csr_load_status_set(dev_priv, FW_FAILED);
> >>>   			goto out;
> >>>   		}
> >>>   		csr->mmioaddr[i] = dmc_header->mmioaddr[i];
> >>> @@ -303,6 +332,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >>>   	nbytes = dmc_header->fw_size * 4;
> >>>   	if (nbytes > CSR_MAX_FW_SIZE) {
> >>>   		DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes);
> >>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >>>   		goto out;
> >>>   	}
> >>>   	csr->dmc_fw_size = dmc_header->fw_size;
> >>> @@ -310,6 +340,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >>>   	csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL);
> >>>   	if (!csr->dmc_payload) {
> >>>   		DRM_ERROR("Memory allocation failed for dmc payload\n");
> >>> +		intel_csr_load_status_set(dev_priv, FW_FAILED);
> >>>   		goto out;
> >>>   	}
> >>>   
> >>> @@ -327,6 +358,11 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> >>>   	/* load csr program during system boot, as needed for DC states */
> >>>   	intel_csr_load_program(dev);

... set fw_loaded = true; here

> >>>   out:
> > Also, since you have to anyway change the patch: could you replace all
> > the above intel_csr_load_status_set(dev_priv, FW_FAILED); with one here
> > using a fw_loaded bool that you set after intel_csr_load_program?
>
> Now we do not have fw_loaded bool in current patch, enum csr_state is
> used to capture the current state. Want me to add fw_loaded bool and
> call intel_csr_load_status_set(dev_priv, FW_FAILED) based on that?

... and add here
if (!fw_loaded)
	intel_csr_load_status_set(dev_priv, FW_FAILED);

to remove some duplication in the code.

--Imre
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 90e47a9..670e407 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -667,6 +667,12 @@  struct intel_uncore {
 #define for_each_fw_domain(domain__, dev_priv__, i__) \
 	for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__)
 
+enum csr_state {
+	FW_UNINITIALIZED = 0,
+	FW_LOADED,
+	FW_FAILED
+};
+
 struct intel_csr {
 	const char *fw_path;
 	__be32 *dmc_payload;
@@ -674,6 +680,7 @@  struct intel_csr {
 	uint32_t mmio_count;
 	uint32_t mmioaddr[8];
 	uint32_t mmiodata[8];
+	enum csr_state state;
 };
 
 #define DEV_INFO_FOR_EACH_FLAG(func, sep) \
diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
index f5fa574..fe6789f 100644
--- a/drivers/gpu/drm/i915/intel_csr.c
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -183,6 +183,25 @@  static char intel_get_substepping(struct drm_device *dev)
 		return -ENODATA;
 }
 
+enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv)
+{
+	enum csr_state state;
+
+	mutex_lock(&dev_priv->csr_lock);
+	state = dev_priv->csr.state;
+	mutex_unlock(&dev_priv->csr_lock);
+
+	return state;
+}
+
+void intel_csr_load_status_set(struct drm_i915_private *dev_priv,
+			enum csr_state state)
+{
+	mutex_lock(&dev_priv->csr_lock);
+	dev_priv->csr.state = state;
+	mutex_unlock(&dev_priv->csr_lock);
+}
+
 void intel_csr_load_program(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -204,6 +223,8 @@  void intel_csr_load_program(struct drm_device *dev)
 		I915_WRITE(dev_priv->csr.mmioaddr[i],
 			dev_priv->csr.mmiodata[i]);
 	}
+
+	dev_priv->csr.state = FW_LOADED;
 	mutex_unlock(&dev_priv->csr_lock);
 }
 
@@ -223,11 +244,13 @@  static void finish_csr_load(const struct firmware *fw, void *context)
 
 	if (!fw) {
 		i915_firmware_load_error_print(csr->fw_path, 0);
+		intel_csr_load_status_set(dev_priv, FW_FAILED);
 		goto out;
 	}
 
 	if ((stepping == -ENODATA) || (substepping == -ENODATA)) {
 		DRM_ERROR("Unknown stepping info, firmware loading failed\n");
+		intel_csr_load_status_set(dev_priv, FW_FAILED);
 		goto out;
 	}
 
@@ -237,6 +260,7 @@  static void finish_csr_load(const struct firmware *fw, void *context)
 		(css_header->header_len * 4)) {
 		DRM_ERROR("Firmware has wrong CSS header length %u bytes\n",
 			(css_header->header_len * 4));
+		intel_csr_load_status_set(dev_priv, FW_FAILED);
 		goto out;
 	}
 	readcount += sizeof(struct intel_css_header);
@@ -248,6 +272,7 @@  static void finish_csr_load(const struct firmware *fw, void *context)
 		(package_header->header_len * 4)) {
 		DRM_ERROR("Firmware has wrong package header length %u bytes\n",
 			(package_header->header_len * 4));
+		intel_csr_load_status_set(dev_priv, FW_FAILED);
 		goto out;
 	}
 	readcount += sizeof(struct intel_package_header);
@@ -268,6 +293,7 @@  static void finish_csr_load(const struct firmware *fw, void *context)
 	}
 	if (dmc_offset == CSR_DEFAULT_FW_OFFSET) {
 		DRM_ERROR("Firmware not supported for %c stepping\n", stepping);
+		intel_csr_load_status_set(dev_priv, FW_FAILED);
 		goto out;
 	}
 	readcount += dmc_offset;
@@ -277,6 +303,7 @@  static void finish_csr_load(const struct firmware *fw, void *context)
 	if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) {
 		DRM_ERROR("Firmware has wrong dmc header length %u bytes\n",
 				(dmc_header->header_len));
+		intel_csr_load_status_set(dev_priv, FW_FAILED);
 		goto out;
 	}
 	readcount += sizeof(struct intel_dmc_header);
@@ -285,6 +312,7 @@  static void finish_csr_load(const struct firmware *fw, void *context)
 	if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) {
 		DRM_ERROR("Firmware has wrong mmio count %u\n",
 						dmc_header->mmio_count);
+		intel_csr_load_status_set(dev_priv, FW_FAILED);
 		goto out;
 	}
 	csr->mmio_count = dmc_header->mmio_count;
@@ -293,6 +321,7 @@  static void finish_csr_load(const struct firmware *fw, void *context)
 			dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) {
 			DRM_ERROR(" Firmware has wrong mmio address 0x%x\n",
 						dmc_header->mmioaddr[i]);
+			intel_csr_load_status_set(dev_priv, FW_FAILED);
 			goto out;
 		}
 		csr->mmioaddr[i] = dmc_header->mmioaddr[i];
@@ -303,6 +332,7 @@  static void finish_csr_load(const struct firmware *fw, void *context)
 	nbytes = dmc_header->fw_size * 4;
 	if (nbytes > CSR_MAX_FW_SIZE) {
 		DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes);
+		intel_csr_load_status_set(dev_priv, FW_FAILED);
 		goto out;
 	}
 	csr->dmc_fw_size = dmc_header->fw_size;
@@ -310,6 +340,7 @@  static void finish_csr_load(const struct firmware *fw, void *context)
 	csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL);
 	if (!csr->dmc_payload) {
 		DRM_ERROR("Memory allocation failed for dmc payload\n");
+		intel_csr_load_status_set(dev_priv, FW_FAILED);
 		goto out;
 	}
 
@@ -327,6 +358,11 @@  static void finish_csr_load(const struct firmware *fw, void *context)
 	/* load csr program during system boot, as needed for DC states */
 	intel_csr_load_program(dev);
 out:
+	/*
+	 * Release the runtime pm reference obtained when
+	 * CSR wasn't loaded.
+	 */
+	intel_runtime_pm_put(dev_priv);
 	release_firmware(fw);
 }
 
@@ -343,17 +379,25 @@  void intel_csr_ucode_init(struct drm_device *dev)
 		csr->fw_path = I915_CSR_SKL;
 	else {
 		DRM_ERROR("Unexpected: no known CSR firmware for platform\n");
+		intel_csr_load_status_set(dev_priv, FW_FAILED);
 		return;
 	}
 
+	/*
+	 * Obtain a runtime pm reference, until CSR is loaded,
+	 * to avoid entering runtime-suspend.
+	 */
+	intel_runtime_pm_get(dev_priv);
+
 	/* CSR supported for platform, load firmware */
 	ret = request_firmware_nowait(THIS_MODULE, true, csr->fw_path,
 				&dev_priv->dev->pdev->dev,
 				GFP_KERNEL, dev_priv,
 				finish_csr_load);
-	if (ret)
+	if (ret) {
 		i915_firmware_load_error_print(csr->fw_path, ret);
-
+		intel_csr_load_status_set(dev_priv, FW_FAILED);
+	}
 }
 
 void intel_csr_ucode_fini(struct drm_device *dev)
@@ -363,5 +407,6 @@  void intel_csr_ucode_fini(struct drm_device *dev)
 	if (!HAS_CSR(dev))
 		return;
 
+	intel_csr_load_status_set(dev_priv, FW_FAILED);
 	kfree(dev_priv->csr.dmc_payload);
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index f3a2d88..25d7956 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1064,6 +1064,9 @@  unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
 
 /* intel_csr.c */
 void intel_csr_ucode_init(struct drm_device *dev);
+enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv);
+void intel_csr_load_status_set(struct drm_i915_private *dev_priv,
+					enum csr_state state);
 void intel_csr_load_program(struct drm_device *dev);
 void intel_csr_ucode_fini(struct drm_device *dev);
 
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index ce00e69..23f02a8 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -49,6 +49,8 @@ 
  * present for a given platform.
  */
 
+#define GEN9_ENABLE_DC5(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 &&			\
@@ -319,9 +321,20 @@  static void hsw_set_power_well(struct drm_i915_private *dev_priv,
 	SKL_DISPLAY_MISC_IO_POWER_DOMAINS)) |		\
 	BIT(POWER_DOMAIN_INIT))
 
+static void gen9_enable_dc5(struct drm_i915_private *dev_priv)
+{
+	/* TODO: Implementation to be done. */
+}
+
+static void gen9_disable_dc5(struct drm_i915_private *dev_priv)
+{
+	/* TODO: Implementation to be done. */
+}
+
 static void skl_set_power_well(struct drm_i915_private *dev_priv,
 			struct i915_power_well *power_well, bool enable)
 {
+	struct drm_device *dev = dev_priv->dev;
 	uint32_t tmp, fuse_status;
 	uint32_t req_mask, state_mask;
 	bool is_enabled, enable_requested, check_fuse_status = false;
@@ -361,6 +374,13 @@  static void skl_set_power_well(struct drm_i915_private *dev_priv,
 
 	if (enable) {
 		if (!enable_requested) {
+			WARN((tmp & state_mask) &&
+				!I915_READ(HSW_PWR_WELL_BIOS),
+				"Invalid for power well status to be enabled, unless done by the BIOS, \
+				when request is to disable!\n");
+			if (GEN9_ENABLE_DC5(dev) &&
+				power_well->data == SKL_DISP_PW_2)
+				gen9_disable_dc5(dev_priv);
 			I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask);
 		}
 
@@ -377,6 +397,19 @@  static void skl_set_power_well(struct drm_i915_private *dev_priv,
 			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) {
+				enum csr_state state;
+
+				wait_for((state = intel_csr_load_status_get(dev_priv)) !=
+						FW_UNINITIALIZED, 1000);
+				if (state != FW_LOADED)
+					DRM_ERROR("CSR firmware not ready (%d)\n",
+							state);
+				else
+					gen9_enable_dc5(dev_priv);
+			}
 		}
 	}