Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97f5ab66 authored by Jesse Barnes's avatar Jesse Barnes Committed by Eric Anholt
Browse files

drm/i915: add render standby support



Render standy allows the GPU to power down the render unit when idle.
In order for this to work, it needs a page of graphics memory to save
state.  This patch allocates that page and enables the feature on
supported chipsets.

Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent d8a2d0e0
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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;

@@ -280,6 +281,7 @@ typedef struct drm_i915_private {
	u32 saveDSPBCNTR;
	u32 saveDSPARB;
	u32 saveRENDERSTANDBY;
	u32 savePWRCTXA;
	u32 saveHWS;
	u32 savePIPEACONF;
	u32 savePIPEBCONF;
@@ -1019,6 +1021,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
			   (IS_I9XX(dev) || IS_GM45(dev)) && \
			   !IS_IGD(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)

+4 −1
Original line number Diff line number Diff line
@@ -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,7 +771,8 @@

/** GM965 GM45 render standby register */
#define MCHBAR_RENDER_STANDBY	0x111B8

#define   RCX_SW_EXIT		(1<<23)
#define   RSX_STATUS_MASK	0x00700000
#define PEG_BAND_GAP_DATA	0x14d68

/*
+6 −2
Original line number Diff line number Diff line
@@ -699,8 +699,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 (I915_HAS_RC6(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);
@@ -762,8 +764,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 (I915_HAS_RC6(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);
+41 −0
Original line number Diff line number Diff line
@@ -4296,6 +4296,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, 4096);
		if (ret) {
			DRM_ERROR("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 */
@@ -4450,6 +4486,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);
}