From 97f5ab6651a996ecefed73e41684422f3b29d9a8 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 8 Oct 2009 10:16:48 -0700 Subject: [PATCH] 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: Jesse Barnes Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.h | 3 ++ drivers/gpu/drm/i915/i915_reg.h | 5 +++- drivers/gpu/drm/i915/i915_suspend.c | 8 ++++-- drivers/gpu/drm/i915/intel_display.c | 41 ++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 57204e298975..95391191316a 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; @@ -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) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1687edf68795..51fd152f47f3 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,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 /* diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 992d5617e798..cd10d9b8181f 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -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); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 099f420de57a..8945656dc1dc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -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); }