[PATCH 12/21] drm/i915: support Haswell-style force waking

Eugeni Dodonov
2012-06-28T18:54:35Z

On Haswell, there is a different register for reading force wake ACKs, and
all the writes should go into the multi-threaded register, even for the
legacy force wake.

Also, we have a theorical possibility for the force wake sequence to
awaken the GT, but return while it hasn't finished bringing up the queue.
So we properly check those bits as well, to ensure we won't end up in
half-woken situation.

Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
---
drivers/gpu/drm/i915/i915_drv.c | 36 +++++++++++++++++++++++++++++++++++-
drivers/gpu/drm/i915/i915_drv.h | 3 +++
drivers/gpu/drm/i915/i915_reg.h | 1 +
drivers/gpu/drm/i915/intel_pm.c | 4 +++-
4 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 79be879..73fd38a 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -536,6 +536,39 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
return ret;
}

+static inline void __hsw_wait_gt_awake(struct drm_i915_private *dev_priv)
+{
+ int count = 0;
+
+ while (count++ < 50) {
+ u32 tmp = I915_READ_NOTRACE(FORCEWAKE_ACK_HSW);
+ if ((tmp & 1) && !(tmp & _MASKED_BIT_ENABLE(~7)))
+ break;
+ udelay(10);
+ }
+}
+
+
+void hsw_gt_force_wake_get(struct drm_i915_private *dev_priv)
+{
+ __hsw_wait_gt_awake(dev_priv);
+
+ I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(1));
+ POSTING_READ(FORCEWAKE_MT);
+
+ __hsw_wait_gt_awake(dev_priv);
+}
+
+void hsw_gt_force_wake_put(struct drm_i915_private *dev_priv)
+{
+ I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(1));
+
+ __hsw_wait_gt_awake(dev_priv);
+
+ /* The below doubles as a POSTING_READ */
+ gen6_gt_check_fifodbg(dev_priv);
+}
+
void vlv_force_wake_get(struct drm_i915_private *dev_priv)
{
int count;
@@ -1161,7 +1194,8 @@ MODULE_LICENSE("GPL and additional rights");
#define NEEDS_FORCE_WAKE(dev_priv, reg) \
((HAS_FORCE_WAKE((dev_priv)->dev)) && \
((reg) < 0x40000) && \
- ((reg) != FORCEWAKE))
+ ((reg) != FORCEWAKE) && \
+ ((reg) != FORCEWAKE_MT))

static bool IS_DISPLAYREG(u32 reg)
{
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a0c15ab..e4916a0 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1525,6 +1525,9 @@ extern void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv);
extern void vlv_force_wake_get(struct drm_i915_private *dev_priv);
extern void vlv_force_wake_put(struct drm_i915_private *dev_priv);

+extern void hsw_gt_force_wake_get(struct drm_i915_private *dev_priv);
+extern void hsw_gt_force_wake_put(struct drm_i915_private *dev_priv);
+
/* overlay */
#ifdef CONFIG_DEBUG_FS
extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 284965b..2c4be2e 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -4070,6 +4070,7 @@
#define FORCEWAKE 0xA18C
#define FORCEWAKE_VLV 0x1300b0
#define FORCEWAKE_ACK_VLV 0x1300b4
+#define FORCEWAKE_ACK_HSW 0x130044
#define FORCEWAKE_ACK 0x130090
#define FORCEWAKE_MT 0xa188 /* multi-threaded */
#define FORCEWAKE_MT_ACK 0x130040
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 99bc1f3..0334e42 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3769,7 +3769,7 @@ void intel_init_pm(struct drm_device *dev)
dev_priv->display.force_wake_put = __gen6_gt_force_wake_put;

/* IVB configs may use multi-threaded forcewake */
- if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
+ if (IS_IVYBRIDGE(dev)) {
u32 ecobus;

/* A small trick here - if the bios hasn't configured MT forcewake,
@@ -3842,6 +3842,8 @@ void intel_init_pm(struct drm_device *dev)
}
dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
dev_priv->display.sanitize_pm = gen6_sanitize_pm;
+ dev_priv->display.force_wake_get = hsw_gt_force_wake_get;
+ dev_priv->display.force_wake_put = hsw_gt_force_wake_put;
} else
dev_priv->display.update_wm = NULL;
} else if (IS_VALLEYVIEW(dev)) {
--
1.7.11.1