[Intel-gfx] [PATCH 1/5] drm/i915/vlv: power well support for VLV/BYT

Jesse Barnes jbarnes at virtuousgeek.org
Tue Oct 15 01:07:45 CEST 2013


Had to conditionalize some HSW bits and add virtual functions for
get/set on the power wells.

Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
---
 drivers/gpu/drm/i915/i915_drv.h     |  10 +-
 drivers/gpu/drm/i915/intel_drv.h    |   2 +
 drivers/gpu/drm/i915/intel_pm.c     | 128 +++-------------------
 drivers/gpu/drm/i915/intel_uncore.c | 211 ++++++++++++++++++++++++++++++++++++
 4 files changed, 238 insertions(+), 113 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index ca74ef2..4e97840 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -401,6 +401,14 @@ struct drm_i915_display_funcs {
 struct intel_uncore_funcs {
 	void (*force_wake_get)(struct drm_i915_private *dev_priv);
 	void (*force_wake_put)(struct drm_i915_private *dev_priv);
+	void (*set_display_power)(struct drm_i915_private *dev_priv,
+				  bool enable);
+	bool (*display_power_enabled)(struct drm_i915_private *dev_priv,
+				      enum intel_display_power_domain domain);
+	void (*display_power_get)(struct drm_i915_private *dev_priv,
+				  enum intel_display_power_domain domain);
+	void (*display_power_put)(struct drm_i915_private *dev_priv,
+				  enum intel_display_power_domain domain);
 };
 
 struct intel_uncore {
@@ -1702,7 +1710,7 @@ struct drm_i915_file_private {
 #define HAS_IPS(dev)		(IS_ULT(dev))
 
 #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
-#define HAS_POWER_WELL(dev)	(IS_HASWELL(dev))
+#define HAS_POWER_WELL(dev)	(IS_HASWELL(dev) || IS_VALLEYVIEW(dev))
 #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
 #define HAS_PSR(dev)		(IS_HASWELL(dev))
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 476d98b..9317383 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -798,6 +798,8 @@ void intel_display_power_get(struct drm_device *dev,
 			     enum intel_display_power_domain domain);
 void intel_display_power_put(struct drm_device *dev,
 			     enum intel_display_power_domain domain);
+void __intel_power_well_get(struct i915_power_well *power_well);
+void __intel_power_well_put(struct i915_power_well *power_well);
 void intel_init_power_well(struct drm_device *dev);
 void intel_set_power_well(struct drm_device *dev, bool enable);
 void intel_enable_gt_powersave(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 0b4de57..d1abc42 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -5367,146 +5367,48 @@ bool intel_display_power_enabled(struct drm_device *dev,
 	if (!HAS_POWER_WELL(dev))
 		return true;
 
-	switch (domain) {
-	case POWER_DOMAIN_PIPE_A:
-	case POWER_DOMAIN_TRANSCODER_EDP:
-		return true;
-	case POWER_DOMAIN_VGA:
-	case POWER_DOMAIN_PIPE_B:
-	case POWER_DOMAIN_PIPE_C:
-	case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
-	case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
-	case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
-	case POWER_DOMAIN_TRANSCODER_A:
-	case POWER_DOMAIN_TRANSCODER_B:
-	case POWER_DOMAIN_TRANSCODER_C:
-		return I915_READ(HSW_PWR_WELL_DRIVER) ==
-		     (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED);
-	default:
-		BUG();
-	}
+	return dev_priv->uncore.funcs.display_power_enabled(dev_priv, domain);
 }
 
-static void __intel_set_power_well(struct drm_device *dev, bool enable)
+void __intel_power_well_get(struct i915_power_well *power_well)
 {
+	struct drm_device *dev = power_well->device;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	bool is_enabled, enable_requested;
-	uint32_t tmp;
 
-	tmp = I915_READ(HSW_PWR_WELL_DRIVER);
-	is_enabled = tmp & HSW_PWR_WELL_STATE_ENABLED;
-	enable_requested = tmp & HSW_PWR_WELL_ENABLE_REQUEST;
-
-	if (enable) {
-		if (!enable_requested)
-			I915_WRITE(HSW_PWR_WELL_DRIVER,
-				   HSW_PWR_WELL_ENABLE_REQUEST);
-
-		if (!is_enabled) {
-			DRM_DEBUG_KMS("Enabling power well\n");
-			if (wait_for((I915_READ(HSW_PWR_WELL_DRIVER) &
-				      HSW_PWR_WELL_STATE_ENABLED), 20))
-				DRM_ERROR("Timeout enabling power well\n");
-		}
-	} else {
-		if (enable_requested) {
-			unsigned long irqflags;
-			enum pipe p;
-
-			I915_WRITE(HSW_PWR_WELL_DRIVER, 0);
-			POSTING_READ(HSW_PWR_WELL_DRIVER);
-			DRM_DEBUG_KMS("Requesting to disable the power well\n");
-
-			/*
-			 * After this, the registers on the pipes that are part
-			 * of the power well will become zero, so we have to
-			 * adjust our counters according to that.
-			 *
-			 * FIXME: Should we do this in general in
-			 * drm_vblank_post_modeset?
-			 */
-			spin_lock_irqsave(&dev->vbl_lock, irqflags);
-			for_each_pipe(p)
-				if (p != PIPE_A)
-					dev->last_vblank[p] = 0;
-			spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
-		}
-	}
-}
-
-static void __intel_power_well_get(struct i915_power_well *power_well)
-{
 	if (!power_well->count++)
-		__intel_set_power_well(power_well->device, true);
+		dev_priv->uncore.funcs.set_display_power(dev_priv, true);
 }
 
-static void __intel_power_well_put(struct i915_power_well *power_well)
+void __intel_power_well_put(struct i915_power_well *power_well)
 {
+	struct drm_device *dev = power_well->device;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
 	WARN_ON(!power_well->count);
 	if (!--power_well->count)
-		__intel_set_power_well(power_well->device, false);
+		dev_priv->uncore.funcs.set_display_power(dev_priv, false);
 }
 
 void intel_display_power_get(struct drm_device *dev,
 			     enum intel_display_power_domain domain)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct i915_power_well *power_well = &dev_priv->power_well;
 
 	if (!HAS_POWER_WELL(dev))
 		return;
 
-	switch (domain) {
-	case POWER_DOMAIN_PIPE_A:
-	case POWER_DOMAIN_TRANSCODER_EDP:
-		return;
-	case POWER_DOMAIN_VGA:
-	case POWER_DOMAIN_PIPE_B:
-	case POWER_DOMAIN_PIPE_C:
-	case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
-	case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
-	case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
-	case POWER_DOMAIN_TRANSCODER_A:
-	case POWER_DOMAIN_TRANSCODER_B:
-	case POWER_DOMAIN_TRANSCODER_C:
-		spin_lock_irq(&power_well->lock);
-		__intel_power_well_get(power_well);
-		spin_unlock_irq(&power_well->lock);
-		return;
-	default:
-		BUG();
-	}
+	dev_priv->uncore.funcs.display_power_get(dev_priv, domain);
 }
 
 void intel_display_power_put(struct drm_device *dev,
 			     enum intel_display_power_domain domain)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct i915_power_well *power_well = &dev_priv->power_well;
 
 	if (!HAS_POWER_WELL(dev))
 		return;
 
-	switch (domain) {
-	case POWER_DOMAIN_PIPE_A:
-	case POWER_DOMAIN_TRANSCODER_EDP:
-		return;
-	case POWER_DOMAIN_VGA:
-	case POWER_DOMAIN_PIPE_B:
-	case POWER_DOMAIN_PIPE_C:
-	case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
-	case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
-	case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
-	case POWER_DOMAIN_TRANSCODER_A:
-	case POWER_DOMAIN_TRANSCODER_B:
-	case POWER_DOMAIN_TRANSCODER_C:
-		spin_lock_irq(&power_well->lock);
-		__intel_power_well_put(power_well);
-		spin_unlock_irq(&power_well->lock);
-		return;
-	default:
-		BUG();
-	}
+	dev_priv->uncore.funcs.display_power_put(dev_priv, domain);
 }
 
 static struct i915_power_well *hsw_pwr;
@@ -5595,7 +5497,8 @@ static void intel_resume_power_well(struct drm_device *dev)
 		return;
 
 	spin_lock_irq(&power_well->lock);
-	__intel_set_power_well(dev, power_well->count > 0);
+	dev_priv->uncore.funcs.set_display_power(dev_priv,
+						 power_well->count > 0);
 	spin_unlock_irq(&power_well->lock);
 }
 
@@ -5618,8 +5521,9 @@ void intel_init_power_well(struct drm_device *dev)
 
 	/* We're taking over the BIOS, so clear any requests made by it since
 	 * the driver is in charge now. */
-	if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST)
-		I915_WRITE(HSW_PWR_WELL_BIOS, 0);
+	if (IS_HASWELL(dev))
+		if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST)
+			I915_WRITE(HSW_PWR_WELL_BIOS, 0);
 }
 
 /* Disables PC8 so we can use the GMBUS and DP AUX interrupts. */
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 288a3a6..ef5d7fd 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -216,6 +216,209 @@ static void gen6_force_wake_work(struct work_struct *work)
 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
+static void hsw_display_power_get(struct drm_i915_private *dev_priv,
+				  enum intel_display_power_domain domain)
+{
+	struct i915_power_well *power_well = &dev_priv->power_well;
+
+	switch (domain) {
+	case POWER_DOMAIN_PIPE_A:
+	case POWER_DOMAIN_TRANSCODER_EDP:
+		return;
+	case POWER_DOMAIN_VGA:
+	case POWER_DOMAIN_PIPE_B:
+	case POWER_DOMAIN_PIPE_C:
+	case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
+	case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
+	case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
+	case POWER_DOMAIN_TRANSCODER_A:
+	case POWER_DOMAIN_TRANSCODER_B:
+	case POWER_DOMAIN_TRANSCODER_C:
+		spin_lock_irq(&power_well->lock);
+		__intel_power_well_get(power_well);
+		spin_unlock_irq(&power_well->lock);
+		return;
+	default:
+		BUG();
+	}
+}
+
+static void hsw_display_power_put(struct drm_i915_private *dev_priv,
+				  enum intel_display_power_domain domain)
+{
+	struct i915_power_well *power_well = &dev_priv->power_well;
+	switch (domain) {
+	case POWER_DOMAIN_PIPE_A:
+	case POWER_DOMAIN_TRANSCODER_EDP:
+		return;
+	case POWER_DOMAIN_VGA:
+	case POWER_DOMAIN_PIPE_B:
+	case POWER_DOMAIN_PIPE_C:
+	case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
+	case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
+	case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
+	case POWER_DOMAIN_TRANSCODER_A:
+	case POWER_DOMAIN_TRANSCODER_B:
+	case POWER_DOMAIN_TRANSCODER_C:
+		spin_lock_irq(&power_well->lock);
+		__intel_power_well_put(power_well);
+		spin_unlock_irq(&power_well->lock);
+		return;
+	default:
+		BUG();
+	}
+}
+
+static void vlv_display_power_get(struct drm_i915_private *dev_priv,
+				  enum intel_display_power_domain domain)
+{
+	struct i915_power_well *power_well = &dev_priv->power_well;
+
+	spin_lock_irq(&power_well->lock);
+	__intel_power_well_get(power_well);
+	spin_unlock_irq(&power_well->lock);
+}
+
+static void vlv_display_power_put(struct drm_i915_private *dev_priv,
+				  enum intel_display_power_domain domain)
+{
+	struct i915_power_well *power_well = &dev_priv->power_well;
+
+	spin_lock_irq(&power_well->lock);
+	__intel_power_well_put(power_well);
+	spin_unlock_irq(&power_well->lock);
+}
+
+static bool hsw_display_power_enabled(struct drm_i915_private *dev_priv,
+				      enum intel_display_power_domain domain)
+{
+	switch (domain) {
+	case POWER_DOMAIN_PIPE_A:
+	case POWER_DOMAIN_TRANSCODER_EDP:
+		return true;
+	case POWER_DOMAIN_VGA:
+	case POWER_DOMAIN_PIPE_B:
+	case POWER_DOMAIN_PIPE_C:
+	case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
+	case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
+	case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
+	case POWER_DOMAIN_TRANSCODER_A:
+	case POWER_DOMAIN_TRANSCODER_B:
+	case POWER_DOMAIN_TRANSCODER_C:
+		return I915_READ(HSW_PWR_WELL_DRIVER) ==
+			(HSW_PWR_WELL_ENABLE_REQUEST |
+			 HSW_PWR_WELL_STATE_ENABLED);
+	default:
+		BUG();
+	}
+}
+
+static bool __vlv_get_power_well(struct drm_i915_private *dev_priv,
+				 u32 pwrgt_mask)
+{
+	u32 reg_val;
+
+	mutex_lock(&dev_priv->rps.hw_lock);
+	reg_val = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS);
+	mutex_unlock(&dev_priv->rps.hw_lock);
+
+	return !(reg_val & pwrgt_mask);
+}
+
+static bool vlv_display_power_enabled(struct drm_i915_private *dev_priv,
+				      enum intel_display_power_domain domain)
+{
+	return __vlv_get_power_well(dev_priv, DISP2D_PWRGT);
+}
+
+static void hsw_set_display_power(struct drm_i915_private *dev_priv,
+				  bool enable)
+{
+	struct drm_device *dev = dev_priv->dev;
+	bool is_enabled, enable_requested;
+	uint32_t tmp;
+
+	tmp = I915_READ(HSW_PWR_WELL_DRIVER);
+	is_enabled = tmp & HSW_PWR_WELL_STATE_ENABLED;
+	enable_requested = tmp & HSW_PWR_WELL_ENABLE_REQUEST;
+
+	if (enable) {
+		if (!enable_requested)
+			I915_WRITE(HSW_PWR_WELL_DRIVER,
+				   HSW_PWR_WELL_ENABLE_REQUEST);
+
+		if (!is_enabled) {
+			DRM_DEBUG_KMS("Enabling power well\n");
+			if (wait_for((I915_READ(HSW_PWR_WELL_DRIVER) &
+				      HSW_PWR_WELL_STATE_ENABLED), 20))
+				DRM_ERROR("Timeout enabling power well\n");
+		}
+	} else {
+		if (enable_requested) {
+			unsigned long irqflags;
+			enum pipe p;
+
+			I915_WRITE(HSW_PWR_WELL_DRIVER, 0);
+			POSTING_READ(HSW_PWR_WELL_DRIVER);
+			DRM_DEBUG_KMS("Requesting to disable the power well\n");
+
+			/*
+			 * After this, the registers on the pipes that are part
+			 * of the power well will become zero, so we have to
+			 * adjust our counters according to that.
+			 *
+			 * FIXME: Should we do this in general in
+			 * drm_vblank_post_modeset?
+			 */
+			spin_lock_irqsave(&dev->vbl_lock, irqflags);
+			for_each_pipe(p)
+				if (p != PIPE_A)
+					dev->last_vblank[p] = 0;
+			spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+		}
+	}
+}
+
+static void __vlv_set_power_well(struct drm_i915_private *dev_priv,
+				 u32 pwrgt_mask, bool enable)
+{
+	u32 reg_val;
+
+	mutex_lock(&dev_priv->rps.hw_lock);
+	reg_val = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS);
+	if (enable) {
+		if (reg_val & pwrgt_mask) {
+			reg_val &= ~pwrgt_mask;
+			vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL,
+					reg_val);
+			if (wait_for(!(vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & pwrgt_mask), 100))
+				DRM_ERROR("timed out waiting for power well enable\n");
+		}
+	} else {
+		reg_val |= pwrgt_mask;
+		vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, reg_val);
+		if (wait_for(vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & pwrgt_mask, 100))
+			DRM_ERROR("timed out waiting for power well disable\n");	}
+	reg_val = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS);
+	mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
+static void vlv_set_display_power(struct drm_i915_private *dev_priv,
+				  bool enable)
+{
+	__vlv_set_power_well(dev_priv, DISP2D_PWRGT, enable);
+}
+
+static void vlv_set_render_power(struct drm_i915_private *dev_priv, bool enable)
+{
+	__vlv_set_power_well(dev_priv, RENDER_PWRGT, enable);
+}
+
+static void vlv_set_media_power(struct drm_i915_private *dev_priv, bool enable)
+{
+	__vlv_set_power_well(dev_priv, MEDIA_PWRGT, enable);
+}
+
 void intel_uncore_early_sanitize(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -234,9 +437,17 @@ void intel_uncore_init(struct drm_device *dev)
 	if (IS_VALLEYVIEW(dev)) {
 		dev_priv->uncore.funcs.force_wake_get = vlv_force_wake_get;
 		dev_priv->uncore.funcs.force_wake_put = vlv_force_wake_put;
+		dev_priv->uncore.funcs.set_display_power = vlv_set_display_power;
+		dev_priv->uncore.funcs.display_power_enabled = vlv_display_power_enabled;
+		dev_priv->uncore.funcs.display_power_get = vlv_display_power_get;
+		dev_priv->uncore.funcs.display_power_put = vlv_display_power_put;
 	} else if (IS_HASWELL(dev)) {
 		dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get;
 		dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put;
+		dev_priv->uncore.funcs.set_display_power = hsw_set_display_power;
+		dev_priv->uncore.funcs.display_power_enabled = hsw_display_power_enabled;
+		dev_priv->uncore.funcs.display_power_get = hsw_display_power_get;
+		dev_priv->uncore.funcs.display_power_put = hsw_display_power_put;
 	} else if (IS_IVYBRIDGE(dev)) {
 		u32 ecobus;
 
-- 
1.8.3.1




More information about the Intel-gfx mailing list