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

Commit 88271da3 authored by Jesse Barnes's avatar Jesse Barnes Committed by Chris Wilson
Browse files

drm/i915: re-enable rc6 support for Ironlake+



Re-enable rc6 support on Ironlake for power savings.  Adds a debugfs
file to check current RC state, adds a missing workaround for Ironlake
MI_SET_CONTEXT instructions, and renames MCHBAR_RENDER_STANDBY to
RSTDBYCTL to match the docs.

Keep RC6 and the power context disabled on pre-ILK.  It only seems to
hang and doesn't save any power.

Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent 0dc79fb2
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -896,7 +896,7 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
	struct drm_device *dev = node->minor->dev;
	drm_i915_private_t *dev_priv = dev->dev_private;
	u32 rgvmodectl = I915_READ(MEMMODECTL);
	u32 rstdbyctl = I915_READ(MCHBAR_RENDER_STANDBY);
	u32 rstdbyctl = I915_READ(RSTDBYCTL);
	u16 crstandvid = I915_READ16(CRSTANDVID);

	seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ?
@@ -919,6 +919,30 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
	seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f));
	seq_printf(m, "Render standby enabled: %s\n",
		   (rstdbyctl & RCX_SW_EXIT) ? "no" : "yes");
	seq_printf(m, "Current RS state: ");
	switch (rstdbyctl & RSX_STATUS_MASK) {
	case RSX_STATUS_ON:
		seq_printf(m, "on\n");
		break;
	case RSX_STATUS_RC1:
		seq_printf(m, "RC1\n");
		break;
	case RSX_STATUS_RC1E:
		seq_printf(m, "RC1E\n");
		break;
	case RSX_STATUS_RS1:
		seq_printf(m, "RS1\n");
		break;
	case RSX_STATUS_RS2:
		seq_printf(m, "RS2 (RC6)\n");
		break;
	case RSX_STATUS_RS3:
		seq_printf(m, "RC3 (RC6+)\n");
		break;
	default:
		seq_printf(m, "unknown\n");
		break;
	}

	return 0;
}
+47 −3
Original line number Diff line number Diff line
@@ -145,6 +145,8 @@
#define   MI_END_SCENE		(1 << 4) /* flush binner and incr scene count */
#define   MI_INVALIDATE_ISP	(1 << 5) /* invalidate indirect state pointers */
#define MI_BATCH_BUFFER_END	MI_INSTR(0x0a, 0)
#define MI_SUSPEND_FLUSH	MI_INSTR(0x0b, 0)
#define   MI_SUSPEND_FLUSH_EN	(1<<0)
#define MI_REPORT_HEAD		MI_INSTR(0x07, 0)
#define MI_OVERLAY_FLIP		MI_INSTR(0x11,0)
#define   MI_OVERLAY_CONTINUE	(0x0<<21)
@@ -159,6 +161,7 @@
#define   MI_MM_SPACE_PHYSICAL		(0<<8)
#define   MI_SAVE_EXT_STATE_EN		(1<<3)
#define   MI_RESTORE_EXT_STATE_EN	(1<<2)
#define   MI_FORCE_RESTORE		(1<<1)
#define   MI_RESTORE_INHIBIT		(1<<0)
#define MI_STORE_DWORD_IMM	MI_INSTR(0x20, 1)
#define   MI_MEM_VIRTUAL	(1 << 22) /* 965+ only */
@@ -1131,9 +1134,50 @@
#define RCBMINAVG		0x111a0
#define RCUPEI			0x111b0
#define RCDNEI			0x111b4
#define MCHBAR_RENDER_STANDBY		0x111b8
#define   RCX_SW_EXIT		(1<<23)
#define   RSX_STATUS_MASK	0x00700000
#define RSTDBYCTL		0x111b8
#define   RS1EN			(1<<31)
#define   RS2EN			(1<<30)
#define   RS3EN			(1<<29)
#define   D3RS3EN		(1<<28) /* Display D3 imlies RS3 */
#define   SWPROMORSX		(1<<27) /* RSx promotion timers ignored */
#define   RCWAKERW		(1<<26) /* Resetwarn from PCH causes wakeup */
#define   DPRSLPVREN		(1<<25) /* Fast voltage ramp enable */
#define   GFXTGHYST		(1<<24) /* Hysteresis to allow trunk gating */
#define   RCX_SW_EXIT		(1<<23) /* Leave RSx and prevent re-entry */
#define   RSX_STATUS_MASK	(7<<20)
#define   RSX_STATUS_ON		(0<<20)
#define   RSX_STATUS_RC1	(1<<20)
#define   RSX_STATUS_RC1E	(2<<20)
#define   RSX_STATUS_RS1	(3<<20)
#define   RSX_STATUS_RS2	(4<<20) /* aka rc6 */
#define   RSX_STATUS_RSVD	(5<<20) /* deep rc6 unsupported on ilk */
#define   RSX_STATUS_RS3	(6<<20) /* rs3 unsupported on ilk */
#define   RSX_STATUS_RSVD2	(7<<20)
#define   UWRCRSXE		(1<<19) /* wake counter limit prevents rsx */
#define   RSCRP			(1<<18) /* rs requests control on rs1/2 reqs */
#define   JRSC			(1<<17) /* rsx coupled to cpu c-state */
#define   RS2INC0		(1<<16) /* allow rs2 in cpu c0 */
#define   RS1CONTSAV_MASK	(3<<14)
#define   RS1CONTSAV_NO_RS1	(0<<14) /* rs1 doesn't save/restore context */
#define   RS1CONTSAV_RSVD	(1<<14)
#define   RS1CONTSAV_SAVE_RS1	(2<<14) /* rs1 saves context */
#define   RS1CONTSAV_FULL_RS1	(3<<14) /* rs1 saves and restores context */
#define   NORMSLEXLAT_MASK	(3<<12)
#define   SLOW_RS123		(0<<12)
#define   SLOW_RS23		(1<<12)
#define   SLOW_RS3		(2<<12)
#define   NORMAL_RS123		(3<<12)
#define   RCMODE_TIMEOUT	(1<<11) /* 0 is eval interval method */
#define   IMPROMOEN		(1<<10) /* promo is immediate or delayed until next idle interval (only for timeout method above) */
#define   RCENTSYNC		(1<<9) /* rs coupled to cpu c-state (3/6/7) */
#define   STATELOCK		(1<<7) /* locked to rs_cstate if 0 */
#define   RS_CSTATE_MASK	(3<<4)
#define   RS_CSTATE_C367_RS1	(0<<4)
#define   RS_CSTATE_C36_RS1_C7_RS2 (1<<4)
#define   RS_CSTATE_RSVD	(2<<4)
#define   RS_CSTATE_C367_RS2	(3<<4)
#define   REDSAVES		(1<<3) /* no context save if was idle during rs0 */
#define   REDRESTORES		(1<<2) /* no restore if was idle during rs0 */
#define VIDCTL			0x111c0
#define VIDSTS			0x111c8
#define VIDSTART		0x111cc /* 8 bits */
+2 −2
Original line number Diff line number Diff line
@@ -740,7 +740,7 @@ void i915_restore_display(struct drm_device *dev)
		I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
		I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR);
		I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL);
		I915_WRITE(MCHBAR_RENDER_STANDBY,
		I915_WRITE(RSTDBYCTL,
			   dev_priv->saveMCHBAR_RENDER_STANDBY);
	} else {
		I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
@@ -811,7 +811,7 @@ int i915_save_state(struct drm_device *dev)
		dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR);
		dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR);
		dev_priv->saveMCHBAR_RENDER_STANDBY =
			I915_READ(MCHBAR_RENDER_STANDBY);
			I915_READ(RSTDBYCTL);
	} else {
		dev_priv->saveIER = I915_READ(IER);
		dev_priv->saveIMR = I915_READ(IMR);
+17 −15
Original line number Diff line number Diff line
@@ -6420,35 +6420,37 @@ void intel_enable_clock_gating(struct drm_device *dev)
	 * GPU can automatically power down the render unit if given a page
	 * to save state.
	 */
	if (IS_IRONLAKE_M(dev) && 0) { /* XXX causes a failure during suspend */
	if (IS_IRONLAKE_M(dev)) {
		if (dev_priv->renderctx == NULL)
			dev_priv->renderctx = intel_alloc_context_page(dev);
		if (dev_priv->renderctx) {
			struct drm_i915_gem_object *obj = dev_priv->renderctx;
			if (BEGIN_LP_RING(4) == 0) {
			if (BEGIN_LP_RING(6) != 0) {
				i915_gem_object_unpin(obj);
				drm_gem_object_unreference(&obj->base);
				dev_priv->renderctx = NULL;
				return;
			}
			OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
			OUT_RING(MI_SET_CONTEXT);
			OUT_RING(obj->gtt_offset |
				 MI_MM_SPACE_GTT |
				 MI_SAVE_EXT_STATE_EN |
				 MI_RESTORE_EXT_STATE_EN |
				 MI_RESTORE_INHIBIT);
			OUT_RING(MI_SUSPEND_FLUSH);
			OUT_RING(MI_NOOP);
			OUT_RING(MI_FLUSH);
			ADVANCE_LP_RING();
			}
		} else
			DRM_DEBUG_KMS("Failed to allocate render context."
				       "Disable RC6\n");
	}

	if (IS_GEN4(dev) && IS_MOBILE(dev)) {
		if (dev_priv->pwrctx == NULL)
			dev_priv->pwrctx = intel_alloc_context_page(dev);
		if (dev_priv->pwrctx) {
			struct drm_i915_gem_object *obj = dev_priv->pwrctx;
			I915_WRITE(PWRCTXA, obj->gtt_offset | PWRCTX_EN);
			I915_WRITE(MCHBAR_RENDER_STANDBY,
				   I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT);
		}
	}
}