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: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Jesse Barnes 2011-01-05 12:01:24 -08:00 committed by Chris Wilson
parent 0dc79fb2a3
commit 88271da3f3
4 changed files with 91 additions and 21 deletions

View File

@ -896,7 +896,7 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
struct drm_device *dev = node->minor->dev; struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
u32 rgvmodectl = I915_READ(MEMMODECTL); u32 rgvmodectl = I915_READ(MEMMODECTL);
u32 rstdbyctl = I915_READ(MCHBAR_RENDER_STANDBY); u32 rstdbyctl = I915_READ(RSTDBYCTL);
u16 crstandvid = I915_READ16(CRSTANDVID); u16 crstandvid = I915_READ16(CRSTANDVID);
seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ? 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, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f));
seq_printf(m, "Render standby enabled: %s\n", seq_printf(m, "Render standby enabled: %s\n",
(rstdbyctl & RCX_SW_EXIT) ? "no" : "yes"); (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; return 0;
} }

View File

@ -145,6 +145,8 @@
#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ #define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */
#define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */ #define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */
#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) #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_REPORT_HEAD MI_INSTR(0x07, 0)
#define MI_OVERLAY_FLIP MI_INSTR(0x11,0) #define MI_OVERLAY_FLIP MI_INSTR(0x11,0)
#define MI_OVERLAY_CONTINUE (0x0<<21) #define MI_OVERLAY_CONTINUE (0x0<<21)
@ -159,6 +161,7 @@
#define MI_MM_SPACE_PHYSICAL (0<<8) #define MI_MM_SPACE_PHYSICAL (0<<8)
#define MI_SAVE_EXT_STATE_EN (1<<3) #define MI_SAVE_EXT_STATE_EN (1<<3)
#define MI_RESTORE_EXT_STATE_EN (1<<2) #define MI_RESTORE_EXT_STATE_EN (1<<2)
#define MI_FORCE_RESTORE (1<<1)
#define MI_RESTORE_INHIBIT (1<<0) #define MI_RESTORE_INHIBIT (1<<0)
#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) #define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1)
#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ #define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */
@ -1131,9 +1134,50 @@
#define RCBMINAVG 0x111a0 #define RCBMINAVG 0x111a0
#define RCUPEI 0x111b0 #define RCUPEI 0x111b0
#define RCDNEI 0x111b4 #define RCDNEI 0x111b4
#define MCHBAR_RENDER_STANDBY 0x111b8 #define RSTDBYCTL 0x111b8
#define RCX_SW_EXIT (1<<23) #define RS1EN (1<<31)
#define RSX_STATUS_MASK 0x00700000 #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 VIDCTL 0x111c0
#define VIDSTS 0x111c8 #define VIDSTS 0x111c8
#define VIDSTART 0x111cc /* 8 bits */ #define VIDSTART 0x111cc /* 8 bits */

View File

@ -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_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR); I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR);
I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL); I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL);
I915_WRITE(MCHBAR_RENDER_STANDBY, I915_WRITE(RSTDBYCTL,
dev_priv->saveMCHBAR_RENDER_STANDBY); dev_priv->saveMCHBAR_RENDER_STANDBY);
} else { } else {
I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); 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_RXA_IMR = I915_READ(FDI_RXA_IMR);
dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR); dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR);
dev_priv->saveMCHBAR_RENDER_STANDBY = dev_priv->saveMCHBAR_RENDER_STANDBY =
I915_READ(MCHBAR_RENDER_STANDBY); I915_READ(RSTDBYCTL);
} else { } else {
dev_priv->saveIER = I915_READ(IER); dev_priv->saveIER = I915_READ(IER);
dev_priv->saveIMR = I915_READ(IMR); dev_priv->saveIMR = I915_READ(IMR);

View File

@ -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 * GPU can automatically power down the render unit if given a page
* to save state. * 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) if (dev_priv->renderctx == NULL)
dev_priv->renderctx = intel_alloc_context_page(dev); dev_priv->renderctx = intel_alloc_context_page(dev);
if (dev_priv->renderctx) { if (dev_priv->renderctx) {
struct drm_i915_gem_object *obj = dev_priv->renderctx; struct drm_i915_gem_object *obj = dev_priv->renderctx;
if (BEGIN_LP_RING(4) == 0) { if (BEGIN_LP_RING(6) != 0) {
OUT_RING(MI_SET_CONTEXT); i915_gem_object_unpin(obj);
OUT_RING(obj->gtt_offset | drm_gem_object_unreference(&obj->base);
MI_MM_SPACE_GTT | dev_priv->renderctx = NULL;
MI_SAVE_EXT_STATE_EN | return;
MI_RESTORE_EXT_STATE_EN |
MI_RESTORE_INHIBIT);
OUT_RING(MI_NOOP);
OUT_RING(MI_FLUSH);
ADVANCE_LP_RING();
} }
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 } else
DRM_DEBUG_KMS("Failed to allocate render context." DRM_DEBUG_KMS("Failed to allocate render context."
"Disable RC6\n"); "Disable RC6\n");
}
if (IS_GEN4(dev) && IS_MOBILE(dev)) {
if (dev_priv->pwrctx == NULL) if (dev_priv->pwrctx == NULL)
dev_priv->pwrctx = intel_alloc_context_page(dev); dev_priv->pwrctx = intel_alloc_context_page(dev);
if (dev_priv->pwrctx) { if (dev_priv->pwrctx) {
struct drm_i915_gem_object *obj = dev_priv->pwrctx; struct drm_i915_gem_object *obj = dev_priv->pwrctx;
I915_WRITE(PWRCTXA, obj->gtt_offset | PWRCTX_EN); I915_WRITE(PWRCTXA, obj->gtt_offset | PWRCTX_EN);
I915_WRITE(MCHBAR_RENDER_STANDBY,
I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT);
} }
} }
} }