drm/i915: re-enable rc6 support for Ironlake+
authorJesse Barnes <jbarnes@virtuousgeek.org>
Wed, 5 Jan 2011 20:01:24 +0000 (12:01 -0800)
committerChris Wilson <chris@chris-wilson.co.uk>
Tue, 11 Jan 2011 20:43:58 +0000 (20:43 +0000)
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>
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_display.c

index 7243d64..9c4cdc1 100644 (file)
@@ -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;
 }
index b0ab424..33ddf31 100644 (file)
 #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)
 #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 */
 #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 */
index 4107724..af53063 100644 (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_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);
index 043825c..f3c0525 100644 (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
         * 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) {
-                               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_NOOP);
-                               OUT_RING(MI_FLUSH);
-                               ADVANCE_LP_RING();
+                       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);
                }
        }
 }