From: Suketu Shah <suketu.j.s...@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)

Issue: VIZ-2819
Signed-off-by: A.Sunil Kamath <sunil.kam...@intel.com>
Signed-off-by: Suketu Shah <suketu.j.s...@intel.com>
Signed-off-by: Damien Lespiau <damien.lesp...@intel.com>
Signed-off-by: Imre Deak <imre.d...@intel.com>
Signed-off-by: Animesh Manna <animesh.ma...@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h         |  2 ++
 drivers/gpu/drm/i915/intel_csr.c        | 50 ++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_drv.h        |  2 ++
 drivers/gpu/drm/i915/intel_runtime_pm.c | 31 ++++++++++++++++++++
 4 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index dd572a0..3320fb4 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -669,6 +669,8 @@ struct intel_uncore {
 struct intel_csr {
        int csr_size;
        u8 *csr_buf;
+       bool loaded;
+       bool failed;
        const char *fw_path;
 };
 
diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
index f44f1cd..87d393a 100644
--- a/drivers/gpu/drm/i915/intel_csr.c
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -60,6 +60,25 @@ 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.loaded;
+       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.loaded = 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;
@@ -91,6 +110,8 @@ void intel_csr_load_program(struct drm_device *dev)
                I915_WRITE(dev_priv->dmc_info.mmioaddr[i],
                        dev_priv->dmc_info.mmiodata[i]);
        }
+
+       dev_priv->csr.loaded = true;
        mutex_unlock(&dev_priv->csr_lock);
 }
 
@@ -110,11 +131,13 @@ static void finish_csr_load(const struct firmware *fw, 
void *context)
 
        if (!fw) {
                i915_firmware_load_error_print(csr->fw_path, 0);
+               csr->failed = true;
                goto out;
        }
 
        if ((stepping == -ENODATA) || (substepping == -ENODATA)) {
                DRM_ERROR("Unknown stepping info, firmware loading failed\n");
+               csr->failed = true;
                goto out;
        }
 
@@ -131,6 +154,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));
+               csr->failed = true;
                goto out;
        }
        readcount += sizeof(struct intel_css_header);
@@ -142,6 +166,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));
+               csr->failed = true;
                goto out;
        }
        readcount += sizeof(struct intel_package_header);
@@ -162,6 +187,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);
+               csr->failed = true;
                goto out;
        }
        readcount += dmc_offset;
@@ -171,6 +197,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));
+               csr->failed = true;
                goto out;
        }
        readcount += sizeof(struct intel_dmc_header);
@@ -179,6 +206,7 @@ static void finish_csr_load(const struct firmware *fw, void 
*context)
        if (dmc_header->mmio_count > CSR_MAX_MMIO_COUNT) {
                DRM_ERROR("Firmware has wrong mmio count %u\n",
                                                dmc_header->mmio_count);
+               csr->failed = true;
                goto out;
        }
        dev_priv->dmc_info.mmio_count = dmc_header->mmio_count;
@@ -187,6 +215,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]);
+                       csr->failed = true;
                        goto out;
                }
                dev_priv->dmc_info.mmioaddr[i] = dmc_header->mmioaddr[i];
@@ -197,11 +226,13 @@ 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);
+               csr->failed = true;
                goto out;
        }
        dev_priv->dmc_info.dmc_payload = kmalloc(nbytes, GFP_KERNEL);
        if (!dev_priv->dmc_info.dmc_payload) {
                DRM_ERROR("Memory allocation failed for dmc payload\n");
+               csr->failed = true;
                goto out;
        }
 
@@ -218,7 +249,14 @@ 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);
+
        kfree(csr->csr_buf);
        csr->csr_buf = NULL;
 }
@@ -236,16 +274,25 @@ int 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");
+               csr->failed = true;
                return 0;
        }
 
+       /*
+        * 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);
+               csr->failed = true;
+       }
 
        return ret;
 }
@@ -257,6 +304,7 @@ void intel_csr_ucode_fini(struct drm_device *dev)
        if (!HAS_CSR(dev))
                return;
 
+       intel_csr_load_status_set(dev_priv, false);
        kfree(dev_priv->dmc_info.dmc_payload);
        memset(&dev_priv->dmc_info, 0, sizeof(struct intel_dmc_info));
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index cd20b6a..39cb2dc 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1061,6 +1061,8 @@ unsigned long intel_plane_obj_offset(struct intel_plane 
*intel_plane,
 
 /* intel_csr.c */
 int 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..8b917e2 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,27 @@ 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.failed) {
+                                       /*
+                                       * 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

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to