[Intel-gfx] [PATCH v3 3/8] drm/i915/skl: Add DC5 Trigger Sequence
Animesh Manna
animesh.manna at intel.com
Mon Apr 13 03:26:23 PDT 2015
From: Suketu Shah <suketu.j.shah at 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)
Issue: VIZ-2819
Signed-off-by: A.Sunil Kamath <sunil.kamath at intel.com>
Signed-off-by: Suketu Shah <suketu.j.shah at intel.com>
Signed-off-by: Damien Lespiau <damien.lespiau at intel.com>
Signed-off-by: Imre Deak <imre.deak at intel.com>
Signed-off-by: Animesh Manna <animesh.manna at intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 7 +++++
drivers/gpu/drm/i915/intel_csr.c | 51 +++++++++++++++++++++++++++++++--
drivers/gpu/drm/i915/intel_drv.h | 2 ++
drivers/gpu/drm/i915/intel_runtime_pm.c | 29 +++++++++++++++++++
4 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 90e47a9..8d6deaa 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_states {
+ FW_LOADED = 0,
+ FW_LOADING,
+ 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_states states;
};
#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 ab9b16b..6d08a41 100644
--- a/drivers/gpu/drm/i915/intel_csr.c
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -49,6 +49,25 @@ static char intel_get_substepping(struct drm_device *dev)
else
return -ENODATA;
}
+
+bool intel_csr_load_status_get(struct drm_i915_private *dev_priv)
+{
+ bool val = false;
+
+ mutex_lock(&dev_priv->csr_lock);
+ val = dev_priv->csr.states;
+ mutex_unlock(&dev_priv->csr_lock);
+
+ return val;
+}
+
+void intel_csr_load_status_set(struct drm_i915_private *dev_priv, bool val)
+{
+ mutex_lock(&dev_priv->csr_lock);
+ dev_priv->csr.states = val;
+ mutex_unlock(&dev_priv->csr_lock);
+}
+
void intel_csr_load_program(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -71,6 +90,8 @@ void intel_csr_load_program(struct drm_device *dev)
I915_WRITE(dev_priv->csr.mmioaddr[i],
dev_priv->csr.mmiodata[i]);
}
+
+ intel_csr_load_status_set(dev_priv, FW_LOADED);
mutex_unlock(&dev_priv->csr_lock);
}
@@ -90,11 +111,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;
}
@@ -104,6 +127,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);
@@ -115,6 +139,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);
@@ -135,6 +160,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;
@@ -144,6 +170,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);
@@ -152,6 +179,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;
@@ -160,6 +188,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];
@@ -170,6 +199,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;
@@ -177,6 +207,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;
}
@@ -194,6 +225,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);
}
@@ -210,17 +246,27 @@ 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);
+
+ intel_csr_load_status_set(dev_priv, FW_LOADING);
+
/* 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)
@@ -230,5 +276,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..3fc2473 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1064,6 +1064,8 @@ unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
/* intel_csr.c */
void intel_csr_ucode_init(struct drm_device *dev);
+bool intel_csr_load_status_get(struct drm_i915_private *dev_priv);
+void intel_csr_load_status_set(struct drm_i915_private *dev_priv, bool val);
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 bc6cee9..0750191 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 && \
@@ -369,6 +371,7 @@ static void gen9_disable_dc5(struct drm_i915_private *dev_priv)
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;
@@ -408,6 +411,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);
}
@@ -424,6 +434,25 @@ 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) {
+ if (dev_priv->csr.states <= FW_LOADING) {
+ /*
+ * TODO: wait for a completion event or
+ * similar here instead of busy
+ * waiting using wait_for function.
+ */
+ if (wait_for(
+ intel_csr_load_status_get(
+ dev_priv), 1000))
+ DRM_ERROR("Timed out waiting for CSR to be loaded!");
+ else
+ gen9_enable_dc5(dev_priv);
+ } else {
+ DRM_ERROR("Cannot enable DC5 as CSR failed to load!");
+ }
+ }
}
}
--
2.0.2
More information about the Intel-gfx
mailing list