diff mbox

drm/i915: add render standby support

Message ID 20091007144155.57b84ad6@jbarnes-g45 (mailing list archive)
State Rejected
Headers show

Commit Message

Jesse Barnes Oct. 7, 2009, 9:41 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d378a1a..6c1ae48 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -187,6 +187,7 @@  typedef struct drm_i915_private {
 	unsigned int status_gfx_addr;
 	drm_local_map_t hws_map;
 	struct drm_gem_object *hws_obj;
+	struct drm_gem_object *pwrctx;
 
 	struct resource mch_res;
 
@@ -279,6 +280,7 @@  typedef struct drm_i915_private {
 	u32 saveDSPBCNTR;
 	u32 saveDSPARB;
 	u32 saveRENDERSTANDBY;
+	u32 savePWRCTXA;
 	u32 saveHWS;
 	u32 savePIPEACONF;
 	u32 savePIPEBCONF;
@@ -979,8 +981,9 @@  extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 
 #define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IGDNG(dev))
 #define HAS_PIPE_CXSR(dev) (IS_G4X(dev) || IS_IGDNG(dev))
-#define I915_HAS_FBC(dev) (IS_MOBILE(dev) && (IS_I9XX(dev) || IS_I965G(dev) || IS_GM45(dev)) \
-			   && !IS_IGDNG(dev))
+#define I915_HAS_FBC(dev) (IS_MOBILE(dev) && (IS_I9XX(dev) || IS_I965G(dev) || \
+					      IS_GM45(dev)) && !IS_IGDNG(dev))
+#define I915_HAS_RC6(dev) (IS_I965GM(dev) || IS_GM45(dev) || IS_IGDNG_M(dev))
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index efcfe64..76b74c6 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -260,6 +260,8 @@ 
 #define HWS_PGA		0x02080
 #define HWS_ADDRESS_MASK	0xfffff000
 #define HWS_START_ADDRESS_SHIFT	4
+#define PWRCTXA		0x2088 /* 965GM+ only */
+#define   PWRCTX_EN	(1<<0)
 #define IPEIR		0x02088
 #define IPEHR		0x0208c
 #define INSTDONE	0x02090
@@ -769,6 +771,8 @@ 
 
 /** GM965 GM45 render standby register */
 #define MCHBAR_RENDER_STANDBY	0x111B8
+#define   RCX_SW_EXIT		(1<<23)
+#define   RSX_STATUS_MASK	0x00700000
 #define MCHBAR_GFXEC		0x112f4 /* Energy counter */
 #define PEG_BAND_GAP_DATA	0x14d68
 
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index bd6d8d9..d561fd9 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -534,8 +534,10 @@  int i915_save_state(struct drm_device *dev)
 	pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
 
 	/* Render Standby */
-	if (IS_I965G(dev) && IS_MOBILE(dev))
+	if (IS_I965G(dev) && IS_MOBILE(dev)) {
 		dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY);
+		dev_priv->savePWRCTXA = I915_READ(PWRCTXA);
+	}
 
 	/* Hardware status page */
 	dev_priv->saveHWS = I915_READ(HWS_PGA);
@@ -588,8 +590,10 @@  int i915_restore_state(struct drm_device *dev)
 	pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
 
 	/* Render Standby */
-	if (IS_I965G(dev) && IS_MOBILE(dev))
+	if (IS_I965G(dev) && IS_MOBILE(dev)) {
 		I915_WRITE(MCHBAR_RENDER_STANDBY, dev_priv->saveRENDERSTANDBY);
+		I915_WRITE(PWRCTXA, dev_priv->savePWRCTXA);
+	}
 
 	/* Hardware status page */
 	I915_WRITE(HWS_PGA, dev_priv->saveHWS);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 12514ca..a87c1fd 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4159,6 +4159,42 @@  void intel_init_clock_gating(struct drm_device *dev)
 	} else if (IS_I830(dev)) {
 		I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
 	}
+
+	/*
+	 * GPU can automatically power down the render unit if given a page
+	 * to save state.
+	 */
+	if (I915_HAS_RC6(dev)) {
+		struct drm_gem_object *pwrctx;
+		struct drm_i915_gem_object *obj_priv;
+		int ret;
+
+		pwrctx = drm_gem_object_alloc(dev, 4096);
+		if (!pwrctx) {
+			DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
+			goto out;
+		}
+
+		ret = i915_gem_object_pin(pwrctx, PAGE_SIZE);
+		if (ret) {
+			DRM_DEBUG("failed to pin power context: %d\n", ret);
+			drm_gem_object_unreference(pwrctx);
+			goto out;
+		}
+
+		i915_gem_object_set_to_gtt_domain(pwrctx, 1);
+
+		obj_priv = pwrctx->driver_private;
+
+		I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN);
+		I915_WRITE(MCHBAR_RENDER_STANDBY,
+			   I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT);
+
+		dev_priv->pwrctx = pwrctx;
+	}
+
+out:
+	return;
 }
 
 /* Set up chip specific display functions */
@@ -4313,6 +4349,11 @@  void intel_modeset_cleanup(struct drm_device *dev)
 	if (dev_priv->display.disable_fbc)
 		dev_priv->display.disable_fbc(dev);
 
+	if (dev_priv->pwrctx) {
+		i915_gem_object_unpin(dev_priv->pwrctx);
+		drm_gem_object_unreference(dev_priv->pwrctx);
+	}
+
 	drm_mode_config_cleanup(dev);
 }