* [PATCH 1/5] drm/i915: fix line breaks in intel_pm
2012-04-18 14:51 [PATCH 0/5] rebased intel_pm series Eugeni Dodonov
@ 2012-04-18 14:51 ` Eugeni Dodonov
2012-04-18 14:51 ` [PATCH 2/5] drm/i915: move drps, rps and rc6-related functions to intel_pm Eugeni Dodonov
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Eugeni Dodonov @ 2012-04-18 14:51 UTC (permalink / raw)
To: intel-gfx; +Cc: Eugeni Dodonov
The previous patch had way too long lines, this fixes them to fit into a
reasonable screen space.
Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
---
drivers/gpu/drm/i915/intel_pm.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index b208165..c5bc4c4 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -28,11 +28,15 @@
#include "i915_drv.h"
#include "intel_drv.h"
-/* FBC, or Frame Buffer Compression, is a technique employed to compress the framebuffer contents in-memory, aiming at reducing the required bandwidth during in-memory transfers and, therefore, reduce the power packet.
+/* FBC, or Frame Buffer Compression, is a technique employed to compress the
+ * framebuffer contents in-memory, aiming at reducing the required bandwidth
+ * during in-memory transfers and, therefore, reduce the power packet.
*
- * The benefits of FBC are mostly visible with solid backgrounds and variation-less patterns.
+ * The benefits of FBC are mostly visible with solid backgrounds and
+ * variation-less patterns.
*
- * FBC-related functionality can be enabled by the means of the i915.i915_enable_fbc parameter
+ * FBC-related functionality can be enabled by the means of the
+ * i915.i915_enable_fbc parameter
*/
void i8xx_disable_fbc(struct drm_device *dev)
--
1.7.10
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/5] drm/i915: move drps, rps and rc6-related functions to intel_pm
2012-04-18 14:51 [PATCH 0/5] rebased intel_pm series Eugeni Dodonov
2012-04-18 14:51 ` [PATCH 1/5] drm/i915: fix line breaks in intel_pm Eugeni Dodonov
@ 2012-04-18 14:51 ` Eugeni Dodonov
2012-04-18 15:04 ` Daniel Vetter
2012-04-18 14:51 ` [PATCH 3/5] drm/i915: move emon functionality into intel_pm module Eugeni Dodonov
` (2 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Eugeni Dodonov @ 2012-04-18 14:51 UTC (permalink / raw)
To: intel-gfx; +Cc: Eugeni Dodonov
This moves DRPS, RPS and RC6-related functionality into intel_pm module.
It also removes the linux/cpufreq.h include from intel_display, as its
only user was the GPU turbo-related functionality in Gen6+ code path.
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Acked-by: Ben Widawsky <benjamin.widawsky@intel.com>
Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
---
drivers/gpu/drm/i915/intel_display.c | 513 ----------------------------------
drivers/gpu/drm/i915/intel_drv.h | 1 +
drivers/gpu/drm/i915/intel_pm.c | 509 +++++++++++++++++++++++++++++++++
3 files changed, 510 insertions(+), 513 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 03c015c..d3982e9 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -25,7 +25,6 @@
*/
#include <linux/dmi.h>
-#include <linux/cpufreq.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/i2c.h>
@@ -6352,177 +6351,6 @@ static const struct drm_mode_config_funcs intel_mode_funcs = {
.output_poll_changed = intel_fb_output_poll_changed,
};
-static struct drm_i915_gem_object *
-intel_alloc_context_page(struct drm_device *dev)
-{
- struct drm_i915_gem_object *ctx;
- int ret;
-
- WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
- ctx = i915_gem_alloc_object(dev, 4096);
- if (!ctx) {
- DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
- return NULL;
- }
-
- ret = i915_gem_object_pin(ctx, 4096, true);
- if (ret) {
- DRM_ERROR("failed to pin power context: %d\n", ret);
- goto err_unref;
- }
-
- ret = i915_gem_object_set_to_gtt_domain(ctx, 1);
- if (ret) {
- DRM_ERROR("failed to set-domain on power context: %d\n", ret);
- goto err_unpin;
- }
-
- return ctx;
-
-err_unpin:
- i915_gem_object_unpin(ctx);
-err_unref:
- drm_gem_object_unreference(&ctx->base);
- mutex_unlock(&dev->struct_mutex);
- return NULL;
-}
-
-bool ironlake_set_drps(struct drm_device *dev, u8 val)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u16 rgvswctl;
-
- rgvswctl = I915_READ16(MEMSWCTL);
- if (rgvswctl & MEMCTL_CMD_STS) {
- DRM_DEBUG("gpu busy, RCS change rejected\n");
- return false; /* still busy with another command */
- }
-
- rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
- (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
- I915_WRITE16(MEMSWCTL, rgvswctl);
- POSTING_READ16(MEMSWCTL);
-
- rgvswctl |= MEMCTL_CMD_STS;
- I915_WRITE16(MEMSWCTL, rgvswctl);
-
- return true;
-}
-
-void ironlake_enable_drps(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 rgvmodectl = I915_READ(MEMMODECTL);
- u8 fmax, fmin, fstart, vstart;
-
- /* Enable temp reporting */
- I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
- I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
-
- /* 100ms RC evaluation intervals */
- I915_WRITE(RCUPEI, 100000);
- I915_WRITE(RCDNEI, 100000);
-
- /* Set max/min thresholds to 90ms and 80ms respectively */
- I915_WRITE(RCBMAXAVG, 90000);
- I915_WRITE(RCBMINAVG, 80000);
-
- I915_WRITE(MEMIHYST, 1);
-
- /* Set up min, max, and cur for interrupt handling */
- fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
- fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
- fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
- MEMMODE_FSTART_SHIFT;
-
- vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
- PXVFREQ_PX_SHIFT;
-
- dev_priv->fmax = fmax; /* IPS callback will increase this */
- dev_priv->fstart = fstart;
-
- dev_priv->max_delay = fstart;
- dev_priv->min_delay = fmin;
- dev_priv->cur_delay = fstart;
-
- DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
- fmax, fmin, fstart);
-
- I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
-
- /*
- * Interrupts will be enabled in ironlake_irq_postinstall
- */
-
- I915_WRITE(VIDSTART, vstart);
- POSTING_READ(VIDSTART);
-
- rgvmodectl |= MEMMODE_SWMODE_EN;
- I915_WRITE(MEMMODECTL, rgvmodectl);
-
- if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
- DRM_ERROR("stuck trying to change perf mode\n");
- msleep(1);
-
- ironlake_set_drps(dev, fstart);
-
- dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
- I915_READ(0x112e0);
- dev_priv->last_time1 = jiffies_to_msecs(jiffies);
- dev_priv->last_count2 = I915_READ(0x112f4);
- getrawmonotonic(&dev_priv->last_time2);
-}
-
-void ironlake_disable_drps(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u16 rgvswctl = I915_READ16(MEMSWCTL);
-
- /* Ack interrupts, disable EFC interrupt */
- I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
- I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
- I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
- I915_WRITE(DEIIR, DE_PCU_EVENT);
- I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
-
- /* Go back to the starting frequency */
- ironlake_set_drps(dev, dev_priv->fstart);
- msleep(1);
- rgvswctl |= MEMCTL_CMD_STS;
- I915_WRITE(MEMSWCTL, rgvswctl);
- msleep(1);
-
-}
-
-void gen6_set_rps(struct drm_device *dev, u8 val)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 swreq;
-
- swreq = (val & 0x3ff) << 25;
- I915_WRITE(GEN6_RPNSWREQ, swreq);
-}
-
-void gen6_disable_rps(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
- I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
- I915_WRITE(GEN6_PMIER, 0);
- /* Complete PM interrupt masking here doesn't race with the rps work
- * item again unmasking PM interrupts because that is using a different
- * register (PMIMR) to mask PM interrupts. The only risk is in leaving
- * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
-
- spin_lock_irq(&dev_priv->rps_lock);
- dev_priv->pm_iir = 0;
- spin_unlock_irq(&dev_priv->rps_lock);
-
- I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
-}
-
static unsigned long intel_pxfreq(u32 vidfreq)
{
unsigned long freq;
@@ -6609,232 +6437,6 @@ void intel_init_emon(struct drm_device *dev)
dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
}
-int intel_enable_rc6(const struct drm_device *dev)
-{
- /*
- * Respect the kernel parameter if it is set
- */
- if (i915_enable_rc6 >= 0)
- return i915_enable_rc6;
-
- /*
- * Disable RC6 on Ironlake
- */
- if (INTEL_INFO(dev)->gen == 5)
- return 0;
-
- /* Sorry Haswell, no RC6 for you for now. */
- if (IS_HASWELL(dev))
- return 0;
-
- /*
- * Disable rc6 on Sandybridge
- */
- if (INTEL_INFO(dev)->gen == 6) {
- DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
- return INTEL_RC6_ENABLE;
- }
- DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n");
- return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
-}
-
-void gen6_enable_rps(struct drm_i915_private *dev_priv)
-{
- u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
- u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
- u32 pcu_mbox, rc6_mask = 0;
- u32 gtfifodbg;
- int cur_freq, min_freq, max_freq;
- int rc6_mode;
- int i;
-
- /* Here begins a magic sequence of register writes to enable
- * auto-downclocking.
- *
- * Perhaps there might be some value in exposing these to
- * userspace...
- */
- I915_WRITE(GEN6_RC_STATE, 0);
- mutex_lock(&dev_priv->dev->struct_mutex);
-
- /* Clear the DBG now so we don't confuse earlier errors */
- if ((gtfifodbg = I915_READ(GTFIFODBG))) {
- DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
- I915_WRITE(GTFIFODBG, gtfifodbg);
- }
-
- gen6_gt_force_wake_get(dev_priv);
-
- /* disable the counters and set deterministic thresholds */
- I915_WRITE(GEN6_RC_CONTROL, 0);
-
- I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16);
- I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30);
- I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30);
- I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
- I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
-
- for (i = 0; i < I915_NUM_RINGS; i++)
- I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10);
-
- I915_WRITE(GEN6_RC_SLEEP, 0);
- I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
- I915_WRITE(GEN6_RC6_THRESHOLD, 50000);
- I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
- I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
-
- rc6_mode = intel_enable_rc6(dev_priv->dev);
- if (rc6_mode & INTEL_RC6_ENABLE)
- rc6_mask |= GEN6_RC_CTL_RC6_ENABLE;
-
- if (rc6_mode & INTEL_RC6p_ENABLE)
- rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE;
-
- if (rc6_mode & INTEL_RC6pp_ENABLE)
- rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE;
-
- DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
- (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off",
- (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off",
- (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off");
-
- I915_WRITE(GEN6_RC_CONTROL,
- rc6_mask |
- GEN6_RC_CTL_EI_MODE(1) |
- GEN6_RC_CTL_HW_ENABLE);
-
- I915_WRITE(GEN6_RPNSWREQ,
- GEN6_FREQUENCY(10) |
- GEN6_OFFSET(0) |
- GEN6_AGGRESSIVE_TURBO);
- I915_WRITE(GEN6_RC_VIDEO_FREQ,
- GEN6_FREQUENCY(12));
-
- I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
- I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
- 18 << 24 |
- 6 << 16);
- I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000);
- I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000);
- I915_WRITE(GEN6_RP_UP_EI, 100000);
- I915_WRITE(GEN6_RP_DOWN_EI, 5000000);
- I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
- I915_WRITE(GEN6_RP_CONTROL,
- GEN6_RP_MEDIA_TURBO |
- GEN6_RP_MEDIA_HW_MODE |
- GEN6_RP_MEDIA_IS_GFX |
- GEN6_RP_ENABLE |
- GEN6_RP_UP_BUSY_AVG |
- GEN6_RP_DOWN_IDLE_CONT);
-
- if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
- 500))
- DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
-
- I915_WRITE(GEN6_PCODE_DATA, 0);
- I915_WRITE(GEN6_PCODE_MAILBOX,
- GEN6_PCODE_READY |
- GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
- if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
- 500))
- DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
-
- min_freq = (rp_state_cap & 0xff0000) >> 16;
- max_freq = rp_state_cap & 0xff;
- cur_freq = (gt_perf_status & 0xff00) >> 8;
-
- /* Check for overclock support */
- if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
- 500))
- DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
- I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS);
- pcu_mbox = I915_READ(GEN6_PCODE_DATA);
- if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
- 500))
- DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
- if (pcu_mbox & (1<<31)) { /* OC supported */
- max_freq = pcu_mbox & 0xff;
- DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
- }
-
- /* In units of 100MHz */
- dev_priv->max_delay = max_freq;
- dev_priv->min_delay = min_freq;
- dev_priv->cur_delay = cur_freq;
-
- /* requires MSI enabled */
- I915_WRITE(GEN6_PMIER,
- GEN6_PM_MBOX_EVENT |
- GEN6_PM_THERMAL_EVENT |
- GEN6_PM_RP_DOWN_TIMEOUT |
- GEN6_PM_RP_UP_THRESHOLD |
- GEN6_PM_RP_DOWN_THRESHOLD |
- GEN6_PM_RP_UP_EI_EXPIRED |
- GEN6_PM_RP_DOWN_EI_EXPIRED);
- spin_lock_irq(&dev_priv->rps_lock);
- WARN_ON(dev_priv->pm_iir != 0);
- I915_WRITE(GEN6_PMIMR, 0);
- spin_unlock_irq(&dev_priv->rps_lock);
- /* enable all PM interrupts */
- I915_WRITE(GEN6_PMINTRMSK, 0);
-
- gen6_gt_force_wake_put(dev_priv);
- mutex_unlock(&dev_priv->dev->struct_mutex);
-}
-
-void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
-{
- int min_freq = 15;
- int gpu_freq, ia_freq, max_ia_freq;
- int scaling_factor = 180;
-
- max_ia_freq = cpufreq_quick_get_max(0);
- /*
- * Default to measured freq if none found, PCU will ensure we don't go
- * over
- */
- if (!max_ia_freq)
- max_ia_freq = tsc_khz;
-
- /* Convert from kHz to MHz */
- max_ia_freq /= 1000;
-
- mutex_lock(&dev_priv->dev->struct_mutex);
-
- /*
- * For each potential GPU frequency, load a ring frequency we'd like
- * to use for memory access. We do this by specifying the IA frequency
- * the PCU should use as a reference to determine the ring frequency.
- */
- for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay;
- gpu_freq--) {
- int diff = dev_priv->max_delay - gpu_freq;
-
- /*
- * For GPU frequencies less than 750MHz, just use the lowest
- * ring freq.
- */
- if (gpu_freq < min_freq)
- ia_freq = 800;
- else
- ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
- ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
-
- I915_WRITE(GEN6_PCODE_DATA,
- (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) |
- gpu_freq);
- I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
- GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
- if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
- GEN6_PCODE_READY) == 0, 10)) {
- DRM_ERROR("pcode write of freq table timed out\n");
- continue;
- }
- }
-
- mutex_unlock(&dev_priv->dev->struct_mutex);
-}
-
static void ironlake_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7178,121 +6780,6 @@ static void cpt_init_clock_gating(struct drm_device *dev)
I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS);
}
-static void ironlake_teardown_rc6(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (dev_priv->renderctx) {
- i915_gem_object_unpin(dev_priv->renderctx);
- drm_gem_object_unreference(&dev_priv->renderctx->base);
- dev_priv->renderctx = NULL;
- }
-
- if (dev_priv->pwrctx) {
- i915_gem_object_unpin(dev_priv->pwrctx);
- drm_gem_object_unreference(&dev_priv->pwrctx->base);
- dev_priv->pwrctx = NULL;
- }
-}
-
-static void ironlake_disable_rc6(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (I915_READ(PWRCTXA)) {
- /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
- I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
- wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
- 50);
-
- I915_WRITE(PWRCTXA, 0);
- POSTING_READ(PWRCTXA);
-
- I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
- POSTING_READ(RSTDBYCTL);
- }
-
- ironlake_teardown_rc6(dev);
-}
-
-static int ironlake_setup_rc6(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (dev_priv->renderctx == NULL)
- dev_priv->renderctx = intel_alloc_context_page(dev);
- if (!dev_priv->renderctx)
- return -ENOMEM;
-
- if (dev_priv->pwrctx == NULL)
- dev_priv->pwrctx = intel_alloc_context_page(dev);
- if (!dev_priv->pwrctx) {
- ironlake_teardown_rc6(dev);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void ironlake_enable_rc6(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int ret;
-
- /* rc6 disabled by default due to repeated reports of hanging during
- * boot and resume.
- */
- if (!intel_enable_rc6(dev))
- return;
-
- mutex_lock(&dev->struct_mutex);
- ret = ironlake_setup_rc6(dev);
- if (ret) {
- mutex_unlock(&dev->struct_mutex);
- return;
- }
-
- /*
- * GPU can automatically power down the render unit if given a page
- * to save state.
- */
- ret = BEGIN_LP_RING(6);
- if (ret) {
- ironlake_teardown_rc6(dev);
- mutex_unlock(&dev->struct_mutex);
- return;
- }
-
- OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
- OUT_RING(MI_SET_CONTEXT);
- OUT_RING(dev_priv->renderctx->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();
-
- /*
- * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
- * does an implicit flush, combined with MI_FLUSH above, it should be
- * safe to assume that renderctx is valid
- */
- ret = intel_wait_ring_idle(LP_RING(dev_priv));
- if (ret) {
- DRM_ERROR("failed to enable ironlake power power savings\n");
- ironlake_teardown_rc6(dev);
- mutex_unlock(&dev->struct_mutex);
- return;
- }
-
- I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
- I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
- mutex_unlock(&dev->struct_mutex);
-}
-
void intel_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index f1e27ce..c87f29a 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -396,6 +396,7 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, int regno);
extern void intel_enable_clock_gating(struct drm_device *dev);
+extern void ironlake_disable_rc6(struct drm_device *dev);
extern void ironlake_enable_drps(struct drm_device *dev);
extern void ironlake_disable_drps(struct drm_device *dev);
extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index c5bc4c4..58b26df0 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -25,6 +25,7 @@
*
*/
+#include <linux/cpufreq.h>
#include "i915_drv.h"
#include "intel_drv.h"
@@ -1979,3 +1980,511 @@ void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
pixel_size);
}
+static struct drm_i915_gem_object *
+intel_alloc_context_page(struct drm_device *dev)
+{
+ struct drm_i915_gem_object *ctx;
+ int ret;
+
+ WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+ ctx = i915_gem_alloc_object(dev, 4096);
+ if (!ctx) {
+ DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
+ return NULL;
+ }
+
+ ret = i915_gem_object_pin(ctx, 4096, true);
+ if (ret) {
+ DRM_ERROR("failed to pin power context: %d\n", ret);
+ goto err_unref;
+ }
+
+ ret = i915_gem_object_set_to_gtt_domain(ctx, 1);
+ if (ret) {
+ DRM_ERROR("failed to set-domain on power context: %d\n", ret);
+ goto err_unpin;
+ }
+
+ return ctx;
+
+err_unpin:
+ i915_gem_object_unpin(ctx);
+err_unref:
+ drm_gem_object_unreference(&ctx->base);
+ mutex_unlock(&dev->struct_mutex);
+ return NULL;
+}
+
+bool ironlake_set_drps(struct drm_device *dev, u8 val)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u16 rgvswctl;
+
+ rgvswctl = I915_READ16(MEMSWCTL);
+ if (rgvswctl & MEMCTL_CMD_STS) {
+ DRM_DEBUG("gpu busy, RCS change rejected\n");
+ return false; /* still busy with another command */
+ }
+
+ rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
+ (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
+ I915_WRITE16(MEMSWCTL, rgvswctl);
+ POSTING_READ16(MEMSWCTL);
+
+ rgvswctl |= MEMCTL_CMD_STS;
+ I915_WRITE16(MEMSWCTL, rgvswctl);
+
+ return true;
+}
+
+void ironlake_enable_drps(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 rgvmodectl = I915_READ(MEMMODECTL);
+ u8 fmax, fmin, fstart, vstart;
+
+ /* Enable temp reporting */
+ I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
+ I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
+
+ /* 100ms RC evaluation intervals */
+ I915_WRITE(RCUPEI, 100000);
+ I915_WRITE(RCDNEI, 100000);
+
+ /* Set max/min thresholds to 90ms and 80ms respectively */
+ I915_WRITE(RCBMAXAVG, 90000);
+ I915_WRITE(RCBMINAVG, 80000);
+
+ I915_WRITE(MEMIHYST, 1);
+
+ /* Set up min, max, and cur for interrupt handling */
+ fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
+ fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
+ fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
+ MEMMODE_FSTART_SHIFT;
+
+ vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
+ PXVFREQ_PX_SHIFT;
+
+ dev_priv->fmax = fmax; /* IPS callback will increase this */
+ dev_priv->fstart = fstart;
+
+ dev_priv->max_delay = fstart;
+ dev_priv->min_delay = fmin;
+ dev_priv->cur_delay = fstart;
+
+ DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
+ fmax, fmin, fstart);
+
+ I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
+
+ /*
+ * Interrupts will be enabled in ironlake_irq_postinstall
+ */
+
+ I915_WRITE(VIDSTART, vstart);
+ POSTING_READ(VIDSTART);
+
+ rgvmodectl |= MEMMODE_SWMODE_EN;
+ I915_WRITE(MEMMODECTL, rgvmodectl);
+
+ if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
+ DRM_ERROR("stuck trying to change perf mode\n");
+ msleep(1);
+
+ ironlake_set_drps(dev, fstart);
+
+ dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
+ I915_READ(0x112e0);
+ dev_priv->last_time1 = jiffies_to_msecs(jiffies);
+ dev_priv->last_count2 = I915_READ(0x112f4);
+ getrawmonotonic(&dev_priv->last_time2);
+}
+
+void ironlake_disable_drps(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u16 rgvswctl = I915_READ16(MEMSWCTL);
+
+ /* Ack interrupts, disable EFC interrupt */
+ I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
+ I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
+ I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
+ I915_WRITE(DEIIR, DE_PCU_EVENT);
+ I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
+
+ /* Go back to the starting frequency */
+ ironlake_set_drps(dev, dev_priv->fstart);
+ msleep(1);
+ rgvswctl |= MEMCTL_CMD_STS;
+ I915_WRITE(MEMSWCTL, rgvswctl);
+ msleep(1);
+
+}
+
+void gen6_set_rps(struct drm_device *dev, u8 val)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 swreq;
+
+ swreq = (val & 0x3ff) << 25;
+ I915_WRITE(GEN6_RPNSWREQ, swreq);
+}
+
+void gen6_disable_rps(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
+ I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
+ I915_WRITE(GEN6_PMIER, 0);
+ /* Complete PM interrupt masking here doesn't race with the rps work
+ * item again unmasking PM interrupts because that is using a different
+ * register (PMIMR) to mask PM interrupts. The only risk is in leaving
+ * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
+
+ spin_lock_irq(&dev_priv->rps_lock);
+ dev_priv->pm_iir = 0;
+ spin_unlock_irq(&dev_priv->rps_lock);
+
+ I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+}
+
+int intel_enable_rc6(const struct drm_device *dev)
+{
+ /*
+ * Respect the kernel parameter if it is set
+ */
+ if (i915_enable_rc6 >= 0)
+ return i915_enable_rc6;
+
+ /*
+ * Disable RC6 on Ironlake
+ */
+ if (INTEL_INFO(dev)->gen == 5)
+ return 0;
+
+ /*
+ * Disable rc6 on Sandybridge
+ */
+ if (INTEL_INFO(dev)->gen == 6) {
+ DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
+ return INTEL_RC6_ENABLE;
+ }
+ DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n");
+ return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
+}
+
+void gen6_enable_rps(struct drm_i915_private *dev_priv)
+{
+ u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+ u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
+ u32 pcu_mbox, rc6_mask = 0;
+ u32 gtfifodbg;
+ int cur_freq, min_freq, max_freq;
+ int rc6_mode;
+ int i;
+
+ /* Here begins a magic sequence of register writes to enable
+ * auto-downclocking.
+ *
+ * Perhaps there might be some value in exposing these to
+ * userspace...
+ */
+ I915_WRITE(GEN6_RC_STATE, 0);
+ mutex_lock(&dev_priv->dev->struct_mutex);
+
+ /* Clear the DBG now so we don't confuse earlier errors */
+ if ((gtfifodbg = I915_READ(GTFIFODBG))) {
+ DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
+ I915_WRITE(GTFIFODBG, gtfifodbg);
+ }
+
+ gen6_gt_force_wake_get(dev_priv);
+
+ /* disable the counters and set deterministic thresholds */
+ I915_WRITE(GEN6_RC_CONTROL, 0);
+
+ I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16);
+ I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30);
+ I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30);
+ I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
+ I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
+
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10);
+
+ I915_WRITE(GEN6_RC_SLEEP, 0);
+ I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
+ I915_WRITE(GEN6_RC6_THRESHOLD, 50000);
+ I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
+ I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
+
+ rc6_mode = intel_enable_rc6(dev_priv->dev);
+ if (rc6_mode & INTEL_RC6_ENABLE)
+ rc6_mask |= GEN6_RC_CTL_RC6_ENABLE;
+
+ if (rc6_mode & INTEL_RC6p_ENABLE)
+ rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE;
+
+ if (rc6_mode & INTEL_RC6pp_ENABLE)
+ rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE;
+
+ DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
+ (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off",
+ (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off",
+ (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off");
+
+ I915_WRITE(GEN6_RC_CONTROL,
+ rc6_mask |
+ GEN6_RC_CTL_EI_MODE(1) |
+ GEN6_RC_CTL_HW_ENABLE);
+
+ I915_WRITE(GEN6_RPNSWREQ,
+ GEN6_FREQUENCY(10) |
+ GEN6_OFFSET(0) |
+ GEN6_AGGRESSIVE_TURBO);
+ I915_WRITE(GEN6_RC_VIDEO_FREQ,
+ GEN6_FREQUENCY(12));
+
+ I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
+ I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
+ 18 << 24 |
+ 6 << 16);
+ I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000);
+ I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000);
+ I915_WRITE(GEN6_RP_UP_EI, 100000);
+ I915_WRITE(GEN6_RP_DOWN_EI, 5000000);
+ I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
+ I915_WRITE(GEN6_RP_CONTROL,
+ GEN6_RP_MEDIA_TURBO |
+ GEN6_RP_MEDIA_HW_MODE |
+ GEN6_RP_MEDIA_IS_GFX |
+ GEN6_RP_ENABLE |
+ GEN6_RP_UP_BUSY_AVG |
+ GEN6_RP_DOWN_IDLE_CONT);
+
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
+
+ I915_WRITE(GEN6_PCODE_DATA, 0);
+ I915_WRITE(GEN6_PCODE_MAILBOX,
+ GEN6_PCODE_READY |
+ GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
+
+ min_freq = (rp_state_cap & 0xff0000) >> 16;
+ max_freq = rp_state_cap & 0xff;
+ cur_freq = (gt_perf_status & 0xff00) >> 8;
+
+ /* Check for overclock support */
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
+ I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS);
+ pcu_mbox = I915_READ(GEN6_PCODE_DATA);
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
+ if (pcu_mbox & (1<<31)) { /* OC supported */
+ max_freq = pcu_mbox & 0xff;
+ DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
+ }
+
+ /* In units of 100MHz */
+ dev_priv->max_delay = max_freq;
+ dev_priv->min_delay = min_freq;
+ dev_priv->cur_delay = cur_freq;
+
+ /* requires MSI enabled */
+ I915_WRITE(GEN6_PMIER,
+ GEN6_PM_MBOX_EVENT |
+ GEN6_PM_THERMAL_EVENT |
+ GEN6_PM_RP_DOWN_TIMEOUT |
+ GEN6_PM_RP_UP_THRESHOLD |
+ GEN6_PM_RP_DOWN_THRESHOLD |
+ GEN6_PM_RP_UP_EI_EXPIRED |
+ GEN6_PM_RP_DOWN_EI_EXPIRED);
+ spin_lock_irq(&dev_priv->rps_lock);
+ WARN_ON(dev_priv->pm_iir != 0);
+ I915_WRITE(GEN6_PMIMR, 0);
+ spin_unlock_irq(&dev_priv->rps_lock);
+ /* enable all PM interrupts */
+ I915_WRITE(GEN6_PMINTRMSK, 0);
+
+ gen6_gt_force_wake_put(dev_priv);
+ mutex_unlock(&dev_priv->dev->struct_mutex);
+}
+
+void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
+{
+ int min_freq = 15;
+ int gpu_freq, ia_freq, max_ia_freq;
+ int scaling_factor = 180;
+
+ max_ia_freq = cpufreq_quick_get_max(0);
+ /*
+ * Default to measured freq if none found, PCU will ensure we don't go
+ * over
+ */
+ if (!max_ia_freq)
+ max_ia_freq = tsc_khz;
+
+ /* Convert from kHz to MHz */
+ max_ia_freq /= 1000;
+
+ mutex_lock(&dev_priv->dev->struct_mutex);
+
+ /*
+ * For each potential GPU frequency, load a ring frequency we'd like
+ * to use for memory access. We do this by specifying the IA frequency
+ * the PCU should use as a reference to determine the ring frequency.
+ */
+ for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay;
+ gpu_freq--) {
+ int diff = dev_priv->max_delay - gpu_freq;
+
+ /*
+ * For GPU frequencies less than 750MHz, just use the lowest
+ * ring freq.
+ */
+ if (gpu_freq < min_freq)
+ ia_freq = 800;
+ else
+ ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
+ ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
+
+ I915_WRITE(GEN6_PCODE_DATA,
+ (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) |
+ gpu_freq);
+ I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
+ GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
+ GEN6_PCODE_READY) == 0, 10)) {
+ DRM_ERROR("pcode write of freq table timed out\n");
+ continue;
+ }
+ }
+
+ mutex_unlock(&dev_priv->dev->struct_mutex);
+}
+
+static void ironlake_teardown_rc6(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->renderctx) {
+ i915_gem_object_unpin(dev_priv->renderctx);
+ drm_gem_object_unreference(&dev_priv->renderctx->base);
+ dev_priv->renderctx = NULL;
+ }
+
+ if (dev_priv->pwrctx) {
+ i915_gem_object_unpin(dev_priv->pwrctx);
+ drm_gem_object_unreference(&dev_priv->pwrctx->base);
+ dev_priv->pwrctx = NULL;
+ }
+}
+
+void ironlake_disable_rc6(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (I915_READ(PWRCTXA)) {
+ /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
+ I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
+ wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
+ 50);
+
+ I915_WRITE(PWRCTXA, 0);
+ POSTING_READ(PWRCTXA);
+
+ I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
+ POSTING_READ(RSTDBYCTL);
+ }
+
+ ironlake_teardown_rc6(dev);
+}
+
+static int ironlake_setup_rc6(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->renderctx == NULL)
+ dev_priv->renderctx = intel_alloc_context_page(dev);
+ if (!dev_priv->renderctx)
+ return -ENOMEM;
+
+ if (dev_priv->pwrctx == NULL)
+ dev_priv->pwrctx = intel_alloc_context_page(dev);
+ if (!dev_priv->pwrctx) {
+ ironlake_teardown_rc6(dev);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void ironlake_enable_rc6(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
+
+ /* rc6 disabled by default due to repeated reports of hanging during
+ * boot and resume.
+ */
+ if (!intel_enable_rc6(dev))
+ return;
+
+ mutex_lock(&dev->struct_mutex);
+ ret = ironlake_setup_rc6(dev);
+ if (ret) {
+ mutex_unlock(&dev->struct_mutex);
+ return;
+ }
+
+ /*
+ * GPU can automatically power down the render unit if given a page
+ * to save state.
+ */
+ ret = BEGIN_LP_RING(6);
+ if (ret) {
+ ironlake_teardown_rc6(dev);
+ mutex_unlock(&dev->struct_mutex);
+ return;
+ }
+
+ OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
+ OUT_RING(MI_SET_CONTEXT);
+ OUT_RING(dev_priv->renderctx->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();
+
+ /*
+ * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
+ * does an implicit flush, combined with MI_FLUSH above, it should be
+ * safe to assume that renderctx is valid
+ */
+ ret = intel_wait_ring_idle(LP_RING(dev_priv));
+ if (ret) {
+ DRM_ERROR("failed to enable ironlake power power savings\n");
+ ironlake_teardown_rc6(dev);
+ mutex_unlock(&dev->struct_mutex);
+ return;
+ }
+
+ I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
+ I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
+ mutex_unlock(&dev->struct_mutex);
+}
+
--
1.7.10
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH 2/5] drm/i915: move drps, rps and rc6-related functions to intel_pm
2012-04-18 14:51 ` [PATCH 2/5] drm/i915: move drps, rps and rc6-related functions to intel_pm Eugeni Dodonov
@ 2012-04-18 15:04 ` Daniel Vetter
0 siblings, 0 replies; 7+ messages in thread
From: Daniel Vetter @ 2012-04-18 15:04 UTC (permalink / raw)
To: Eugeni Dodonov; +Cc: intel-gfx
On Wed, Apr 18, 2012 at 11:51:15AM -0300, Eugeni Dodonov wrote:
> This moves DRPS, RPS and RC6-related functionality into intel_pm module.
>
> It also removes the linux/cpufreq.h include from intel_display, as its
> only user was the GPU turbo-related functionality in Gen6+ code path.
>
> Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
> Acked-by: Ben Widawsky <benjamin.widawsky@intel.com>
> Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
> @@ -6609,232 +6437,6 @@ void intel_init_emon(struct drm_device *dev)
> dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
> }
>
> -int intel_enable_rc6(const struct drm_device *dev)
> -{
> - /*
> - * Respect the kernel parameter if it is set
> - */
> - if (i915_enable_rc6 >= 0)
> - return i915_enable_rc6;
> -
> - /*
> - * Disable RC6 on Ironlake
> - */
> - if (INTEL_INFO(dev)->gen == 5)
> - return 0;
> -
> - /* Sorry Haswell, no RC6 for you for now. */
> - if (IS_HASWELL(dev))
> - return 0;
You remove this line but don't readd it. Not good.
-Daniel
> -
> - /*
> - * Disable rc6 on Sandybridge
> - */
> - if (INTEL_INFO(dev)->gen == 6) {
> - DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
> - return INTEL_RC6_ENABLE;
> - }
> - DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n");
> - return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
> -}
> -
> -void gen6_enable_rps(struct drm_i915_private *dev_priv)
> -{
> - u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
> - u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
> - u32 pcu_mbox, rc6_mask = 0;
> - u32 gtfifodbg;
> - int cur_freq, min_freq, max_freq;
> - int rc6_mode;
> - int i;
> -
> - /* Here begins a magic sequence of register writes to enable
> - * auto-downclocking.
> - *
> - * Perhaps there might be some value in exposing these to
> - * userspace...
> - */
> - I915_WRITE(GEN6_RC_STATE, 0);
> - mutex_lock(&dev_priv->dev->struct_mutex);
> -
> - /* Clear the DBG now so we don't confuse earlier errors */
> - if ((gtfifodbg = I915_READ(GTFIFODBG))) {
> - DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
> - I915_WRITE(GTFIFODBG, gtfifodbg);
> - }
> -
> - gen6_gt_force_wake_get(dev_priv);
> -
> - /* disable the counters and set deterministic thresholds */
> - I915_WRITE(GEN6_RC_CONTROL, 0);
> -
> - I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16);
> - I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30);
> - I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30);
> - I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
> - I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
> -
> - for (i = 0; i < I915_NUM_RINGS; i++)
> - I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10);
> -
> - I915_WRITE(GEN6_RC_SLEEP, 0);
> - I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
> - I915_WRITE(GEN6_RC6_THRESHOLD, 50000);
> - I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
> - I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
> -
> - rc6_mode = intel_enable_rc6(dev_priv->dev);
> - if (rc6_mode & INTEL_RC6_ENABLE)
> - rc6_mask |= GEN6_RC_CTL_RC6_ENABLE;
> -
> - if (rc6_mode & INTEL_RC6p_ENABLE)
> - rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE;
> -
> - if (rc6_mode & INTEL_RC6pp_ENABLE)
> - rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE;
> -
> - DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
> - (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off",
> - (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off",
> - (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off");
> -
> - I915_WRITE(GEN6_RC_CONTROL,
> - rc6_mask |
> - GEN6_RC_CTL_EI_MODE(1) |
> - GEN6_RC_CTL_HW_ENABLE);
> -
> - I915_WRITE(GEN6_RPNSWREQ,
> - GEN6_FREQUENCY(10) |
> - GEN6_OFFSET(0) |
> - GEN6_AGGRESSIVE_TURBO);
> - I915_WRITE(GEN6_RC_VIDEO_FREQ,
> - GEN6_FREQUENCY(12));
> -
> - I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
> - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
> - 18 << 24 |
> - 6 << 16);
> - I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000);
> - I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000);
> - I915_WRITE(GEN6_RP_UP_EI, 100000);
> - I915_WRITE(GEN6_RP_DOWN_EI, 5000000);
> - I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
> - I915_WRITE(GEN6_RP_CONTROL,
> - GEN6_RP_MEDIA_TURBO |
> - GEN6_RP_MEDIA_HW_MODE |
> - GEN6_RP_MEDIA_IS_GFX |
> - GEN6_RP_ENABLE |
> - GEN6_RP_UP_BUSY_AVG |
> - GEN6_RP_DOWN_IDLE_CONT);
> -
> - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> - 500))
> - DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
> -
> - I915_WRITE(GEN6_PCODE_DATA, 0);
> - I915_WRITE(GEN6_PCODE_MAILBOX,
> - GEN6_PCODE_READY |
> - GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
> - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> - 500))
> - DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
> -
> - min_freq = (rp_state_cap & 0xff0000) >> 16;
> - max_freq = rp_state_cap & 0xff;
> - cur_freq = (gt_perf_status & 0xff00) >> 8;
> -
> - /* Check for overclock support */
> - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> - 500))
> - DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
> - I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS);
> - pcu_mbox = I915_READ(GEN6_PCODE_DATA);
> - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> - 500))
> - DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
> - if (pcu_mbox & (1<<31)) { /* OC supported */
> - max_freq = pcu_mbox & 0xff;
> - DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
> - }
> -
> - /* In units of 100MHz */
> - dev_priv->max_delay = max_freq;
> - dev_priv->min_delay = min_freq;
> - dev_priv->cur_delay = cur_freq;
> -
> - /* requires MSI enabled */
> - I915_WRITE(GEN6_PMIER,
> - GEN6_PM_MBOX_EVENT |
> - GEN6_PM_THERMAL_EVENT |
> - GEN6_PM_RP_DOWN_TIMEOUT |
> - GEN6_PM_RP_UP_THRESHOLD |
> - GEN6_PM_RP_DOWN_THRESHOLD |
> - GEN6_PM_RP_UP_EI_EXPIRED |
> - GEN6_PM_RP_DOWN_EI_EXPIRED);
> - spin_lock_irq(&dev_priv->rps_lock);
> - WARN_ON(dev_priv->pm_iir != 0);
> - I915_WRITE(GEN6_PMIMR, 0);
> - spin_unlock_irq(&dev_priv->rps_lock);
> - /* enable all PM interrupts */
> - I915_WRITE(GEN6_PMINTRMSK, 0);
> -
> - gen6_gt_force_wake_put(dev_priv);
> - mutex_unlock(&dev_priv->dev->struct_mutex);
> -}
> -
> -void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
> -{
> - int min_freq = 15;
> - int gpu_freq, ia_freq, max_ia_freq;
> - int scaling_factor = 180;
> -
> - max_ia_freq = cpufreq_quick_get_max(0);
> - /*
> - * Default to measured freq if none found, PCU will ensure we don't go
> - * over
> - */
> - if (!max_ia_freq)
> - max_ia_freq = tsc_khz;
> -
> - /* Convert from kHz to MHz */
> - max_ia_freq /= 1000;
> -
> - mutex_lock(&dev_priv->dev->struct_mutex);
> -
> - /*
> - * For each potential GPU frequency, load a ring frequency we'd like
> - * to use for memory access. We do this by specifying the IA frequency
> - * the PCU should use as a reference to determine the ring frequency.
> - */
> - for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay;
> - gpu_freq--) {
> - int diff = dev_priv->max_delay - gpu_freq;
> -
> - /*
> - * For GPU frequencies less than 750MHz, just use the lowest
> - * ring freq.
> - */
> - if (gpu_freq < min_freq)
> - ia_freq = 800;
> - else
> - ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
> - ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
> -
> - I915_WRITE(GEN6_PCODE_DATA,
> - (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) |
> - gpu_freq);
> - I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
> - GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
> - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
> - GEN6_PCODE_READY) == 0, 10)) {
> - DRM_ERROR("pcode write of freq table timed out\n");
> - continue;
> - }
> - }
> -
> - mutex_unlock(&dev_priv->dev->struct_mutex);
> -}
> -
> static void ironlake_init_clock_gating(struct drm_device *dev)
> {
> struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -7178,121 +6780,6 @@ static void cpt_init_clock_gating(struct drm_device *dev)
> I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS);
> }
>
> -static void ironlake_teardown_rc6(struct drm_device *dev)
> -{
> - struct drm_i915_private *dev_priv = dev->dev_private;
> -
> - if (dev_priv->renderctx) {
> - i915_gem_object_unpin(dev_priv->renderctx);
> - drm_gem_object_unreference(&dev_priv->renderctx->base);
> - dev_priv->renderctx = NULL;
> - }
> -
> - if (dev_priv->pwrctx) {
> - i915_gem_object_unpin(dev_priv->pwrctx);
> - drm_gem_object_unreference(&dev_priv->pwrctx->base);
> - dev_priv->pwrctx = NULL;
> - }
> -}
> -
> -static void ironlake_disable_rc6(struct drm_device *dev)
> -{
> - struct drm_i915_private *dev_priv = dev->dev_private;
> -
> - if (I915_READ(PWRCTXA)) {
> - /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
> - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
> - wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
> - 50);
> -
> - I915_WRITE(PWRCTXA, 0);
> - POSTING_READ(PWRCTXA);
> -
> - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
> - POSTING_READ(RSTDBYCTL);
> - }
> -
> - ironlake_teardown_rc6(dev);
> -}
> -
> -static int ironlake_setup_rc6(struct drm_device *dev)
> -{
> - struct drm_i915_private *dev_priv = dev->dev_private;
> -
> - if (dev_priv->renderctx == NULL)
> - dev_priv->renderctx = intel_alloc_context_page(dev);
> - if (!dev_priv->renderctx)
> - return -ENOMEM;
> -
> - if (dev_priv->pwrctx == NULL)
> - dev_priv->pwrctx = intel_alloc_context_page(dev);
> - if (!dev_priv->pwrctx) {
> - ironlake_teardown_rc6(dev);
> - return -ENOMEM;
> - }
> -
> - return 0;
> -}
> -
> -void ironlake_enable_rc6(struct drm_device *dev)
> -{
> - struct drm_i915_private *dev_priv = dev->dev_private;
> - int ret;
> -
> - /* rc6 disabled by default due to repeated reports of hanging during
> - * boot and resume.
> - */
> - if (!intel_enable_rc6(dev))
> - return;
> -
> - mutex_lock(&dev->struct_mutex);
> - ret = ironlake_setup_rc6(dev);
> - if (ret) {
> - mutex_unlock(&dev->struct_mutex);
> - return;
> - }
> -
> - /*
> - * GPU can automatically power down the render unit if given a page
> - * to save state.
> - */
> - ret = BEGIN_LP_RING(6);
> - if (ret) {
> - ironlake_teardown_rc6(dev);
> - mutex_unlock(&dev->struct_mutex);
> - return;
> - }
> -
> - OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
> - OUT_RING(MI_SET_CONTEXT);
> - OUT_RING(dev_priv->renderctx->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();
> -
> - /*
> - * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
> - * does an implicit flush, combined with MI_FLUSH above, it should be
> - * safe to assume that renderctx is valid
> - */
> - ret = intel_wait_ring_idle(LP_RING(dev_priv));
> - if (ret) {
> - DRM_ERROR("failed to enable ironlake power power savings\n");
> - ironlake_teardown_rc6(dev);
> - mutex_unlock(&dev->struct_mutex);
> - return;
> - }
> -
> - I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
> - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
> - mutex_unlock(&dev->struct_mutex);
> -}
> -
> void intel_init_clock_gating(struct drm_device *dev)
> {
> struct drm_i915_private *dev_priv = dev->dev_private;
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index f1e27ce..c87f29a 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -396,6 +396,7 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
> extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
> u16 *blue, int regno);
> extern void intel_enable_clock_gating(struct drm_device *dev);
> +extern void ironlake_disable_rc6(struct drm_device *dev);
> extern void ironlake_enable_drps(struct drm_device *dev);
> extern void ironlake_disable_drps(struct drm_device *dev);
> extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index c5bc4c4..58b26df0 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -25,6 +25,7 @@
> *
> */
>
> +#include <linux/cpufreq.h>
> #include "i915_drv.h"
> #include "intel_drv.h"
>
> @@ -1979,3 +1980,511 @@ void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
> pixel_size);
> }
>
> +static struct drm_i915_gem_object *
> +intel_alloc_context_page(struct drm_device *dev)
> +{
> + struct drm_i915_gem_object *ctx;
> + int ret;
> +
> + WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> +
> + ctx = i915_gem_alloc_object(dev, 4096);
> + if (!ctx) {
> + DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
> + return NULL;
> + }
> +
> + ret = i915_gem_object_pin(ctx, 4096, true);
> + if (ret) {
> + DRM_ERROR("failed to pin power context: %d\n", ret);
> + goto err_unref;
> + }
> +
> + ret = i915_gem_object_set_to_gtt_domain(ctx, 1);
> + if (ret) {
> + DRM_ERROR("failed to set-domain on power context: %d\n", ret);
> + goto err_unpin;
> + }
> +
> + return ctx;
> +
> +err_unpin:
> + i915_gem_object_unpin(ctx);
> +err_unref:
> + drm_gem_object_unreference(&ctx->base);
> + mutex_unlock(&dev->struct_mutex);
> + return NULL;
> +}
> +
> +bool ironlake_set_drps(struct drm_device *dev, u8 val)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + u16 rgvswctl;
> +
> + rgvswctl = I915_READ16(MEMSWCTL);
> + if (rgvswctl & MEMCTL_CMD_STS) {
> + DRM_DEBUG("gpu busy, RCS change rejected\n");
> + return false; /* still busy with another command */
> + }
> +
> + rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
> + (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
> + I915_WRITE16(MEMSWCTL, rgvswctl);
> + POSTING_READ16(MEMSWCTL);
> +
> + rgvswctl |= MEMCTL_CMD_STS;
> + I915_WRITE16(MEMSWCTL, rgvswctl);
> +
> + return true;
> +}
> +
> +void ironlake_enable_drps(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + u32 rgvmodectl = I915_READ(MEMMODECTL);
> + u8 fmax, fmin, fstart, vstart;
> +
> + /* Enable temp reporting */
> + I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
> + I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
> +
> + /* 100ms RC evaluation intervals */
> + I915_WRITE(RCUPEI, 100000);
> + I915_WRITE(RCDNEI, 100000);
> +
> + /* Set max/min thresholds to 90ms and 80ms respectively */
> + I915_WRITE(RCBMAXAVG, 90000);
> + I915_WRITE(RCBMINAVG, 80000);
> +
> + I915_WRITE(MEMIHYST, 1);
> +
> + /* Set up min, max, and cur for interrupt handling */
> + fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
> + fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
> + fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
> + MEMMODE_FSTART_SHIFT;
> +
> + vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
> + PXVFREQ_PX_SHIFT;
> +
> + dev_priv->fmax = fmax; /* IPS callback will increase this */
> + dev_priv->fstart = fstart;
> +
> + dev_priv->max_delay = fstart;
> + dev_priv->min_delay = fmin;
> + dev_priv->cur_delay = fstart;
> +
> + DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
> + fmax, fmin, fstart);
> +
> + I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
> +
> + /*
> + * Interrupts will be enabled in ironlake_irq_postinstall
> + */
> +
> + I915_WRITE(VIDSTART, vstart);
> + POSTING_READ(VIDSTART);
> +
> + rgvmodectl |= MEMMODE_SWMODE_EN;
> + I915_WRITE(MEMMODECTL, rgvmodectl);
> +
> + if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
> + DRM_ERROR("stuck trying to change perf mode\n");
> + msleep(1);
> +
> + ironlake_set_drps(dev, fstart);
> +
> + dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
> + I915_READ(0x112e0);
> + dev_priv->last_time1 = jiffies_to_msecs(jiffies);
> + dev_priv->last_count2 = I915_READ(0x112f4);
> + getrawmonotonic(&dev_priv->last_time2);
> +}
> +
> +void ironlake_disable_drps(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + u16 rgvswctl = I915_READ16(MEMSWCTL);
> +
> + /* Ack interrupts, disable EFC interrupt */
> + I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
> + I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
> + I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
> + I915_WRITE(DEIIR, DE_PCU_EVENT);
> + I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
> +
> + /* Go back to the starting frequency */
> + ironlake_set_drps(dev, dev_priv->fstart);
> + msleep(1);
> + rgvswctl |= MEMCTL_CMD_STS;
> + I915_WRITE(MEMSWCTL, rgvswctl);
> + msleep(1);
> +
> +}
> +
> +void gen6_set_rps(struct drm_device *dev, u8 val)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + u32 swreq;
> +
> + swreq = (val & 0x3ff) << 25;
> + I915_WRITE(GEN6_RPNSWREQ, swreq);
> +}
> +
> +void gen6_disable_rps(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> +
> + I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
> + I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
> + I915_WRITE(GEN6_PMIER, 0);
> + /* Complete PM interrupt masking here doesn't race with the rps work
> + * item again unmasking PM interrupts because that is using a different
> + * register (PMIMR) to mask PM interrupts. The only risk is in leaving
> + * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
> +
> + spin_lock_irq(&dev_priv->rps_lock);
> + dev_priv->pm_iir = 0;
> + spin_unlock_irq(&dev_priv->rps_lock);
> +
> + I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
> +}
> +
> +int intel_enable_rc6(const struct drm_device *dev)
> +{
> + /*
> + * Respect the kernel parameter if it is set
> + */
> + if (i915_enable_rc6 >= 0)
> + return i915_enable_rc6;
> +
> + /*
> + * Disable RC6 on Ironlake
> + */
> + if (INTEL_INFO(dev)->gen == 5)
> + return 0;
> +
> + /*
> + * Disable rc6 on Sandybridge
> + */
> + if (INTEL_INFO(dev)->gen == 6) {
> + DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
> + return INTEL_RC6_ENABLE;
> + }
> + DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n");
> + return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
> +}
> +
> +void gen6_enable_rps(struct drm_i915_private *dev_priv)
> +{
> + u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
> + u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
> + u32 pcu_mbox, rc6_mask = 0;
> + u32 gtfifodbg;
> + int cur_freq, min_freq, max_freq;
> + int rc6_mode;
> + int i;
> +
> + /* Here begins a magic sequence of register writes to enable
> + * auto-downclocking.
> + *
> + * Perhaps there might be some value in exposing these to
> + * userspace...
> + */
> + I915_WRITE(GEN6_RC_STATE, 0);
> + mutex_lock(&dev_priv->dev->struct_mutex);
> +
> + /* Clear the DBG now so we don't confuse earlier errors */
> + if ((gtfifodbg = I915_READ(GTFIFODBG))) {
> + DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
> + I915_WRITE(GTFIFODBG, gtfifodbg);
> + }
> +
> + gen6_gt_force_wake_get(dev_priv);
> +
> + /* disable the counters and set deterministic thresholds */
> + I915_WRITE(GEN6_RC_CONTROL, 0);
> +
> + I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16);
> + I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30);
> + I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30);
> + I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
> + I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
> +
> + for (i = 0; i < I915_NUM_RINGS; i++)
> + I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10);
> +
> + I915_WRITE(GEN6_RC_SLEEP, 0);
> + I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
> + I915_WRITE(GEN6_RC6_THRESHOLD, 50000);
> + I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
> + I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
> +
> + rc6_mode = intel_enable_rc6(dev_priv->dev);
> + if (rc6_mode & INTEL_RC6_ENABLE)
> + rc6_mask |= GEN6_RC_CTL_RC6_ENABLE;
> +
> + if (rc6_mode & INTEL_RC6p_ENABLE)
> + rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE;
> +
> + if (rc6_mode & INTEL_RC6pp_ENABLE)
> + rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE;
> +
> + DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
> + (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off",
> + (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off",
> + (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off");
> +
> + I915_WRITE(GEN6_RC_CONTROL,
> + rc6_mask |
> + GEN6_RC_CTL_EI_MODE(1) |
> + GEN6_RC_CTL_HW_ENABLE);
> +
> + I915_WRITE(GEN6_RPNSWREQ,
> + GEN6_FREQUENCY(10) |
> + GEN6_OFFSET(0) |
> + GEN6_AGGRESSIVE_TURBO);
> + I915_WRITE(GEN6_RC_VIDEO_FREQ,
> + GEN6_FREQUENCY(12));
> +
> + I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
> + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
> + 18 << 24 |
> + 6 << 16);
> + I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000);
> + I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000);
> + I915_WRITE(GEN6_RP_UP_EI, 100000);
> + I915_WRITE(GEN6_RP_DOWN_EI, 5000000);
> + I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
> + I915_WRITE(GEN6_RP_CONTROL,
> + GEN6_RP_MEDIA_TURBO |
> + GEN6_RP_MEDIA_HW_MODE |
> + GEN6_RP_MEDIA_IS_GFX |
> + GEN6_RP_ENABLE |
> + GEN6_RP_UP_BUSY_AVG |
> + GEN6_RP_DOWN_IDLE_CONT);
> +
> + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> + 500))
> + DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
> +
> + I915_WRITE(GEN6_PCODE_DATA, 0);
> + I915_WRITE(GEN6_PCODE_MAILBOX,
> + GEN6_PCODE_READY |
> + GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
> + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> + 500))
> + DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
> +
> + min_freq = (rp_state_cap & 0xff0000) >> 16;
> + max_freq = rp_state_cap & 0xff;
> + cur_freq = (gt_perf_status & 0xff00) >> 8;
> +
> + /* Check for overclock support */
> + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> + 500))
> + DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
> + I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS);
> + pcu_mbox = I915_READ(GEN6_PCODE_DATA);
> + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> + 500))
> + DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
> + if (pcu_mbox & (1<<31)) { /* OC supported */
> + max_freq = pcu_mbox & 0xff;
> + DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
> + }
> +
> + /* In units of 100MHz */
> + dev_priv->max_delay = max_freq;
> + dev_priv->min_delay = min_freq;
> + dev_priv->cur_delay = cur_freq;
> +
> + /* requires MSI enabled */
> + I915_WRITE(GEN6_PMIER,
> + GEN6_PM_MBOX_EVENT |
> + GEN6_PM_THERMAL_EVENT |
> + GEN6_PM_RP_DOWN_TIMEOUT |
> + GEN6_PM_RP_UP_THRESHOLD |
> + GEN6_PM_RP_DOWN_THRESHOLD |
> + GEN6_PM_RP_UP_EI_EXPIRED |
> + GEN6_PM_RP_DOWN_EI_EXPIRED);
> + spin_lock_irq(&dev_priv->rps_lock);
> + WARN_ON(dev_priv->pm_iir != 0);
> + I915_WRITE(GEN6_PMIMR, 0);
> + spin_unlock_irq(&dev_priv->rps_lock);
> + /* enable all PM interrupts */
> + I915_WRITE(GEN6_PMINTRMSK, 0);
> +
> + gen6_gt_force_wake_put(dev_priv);
> + mutex_unlock(&dev_priv->dev->struct_mutex);
> +}
> +
> +void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
> +{
> + int min_freq = 15;
> + int gpu_freq, ia_freq, max_ia_freq;
> + int scaling_factor = 180;
> +
> + max_ia_freq = cpufreq_quick_get_max(0);
> + /*
> + * Default to measured freq if none found, PCU will ensure we don't go
> + * over
> + */
> + if (!max_ia_freq)
> + max_ia_freq = tsc_khz;
> +
> + /* Convert from kHz to MHz */
> + max_ia_freq /= 1000;
> +
> + mutex_lock(&dev_priv->dev->struct_mutex);
> +
> + /*
> + * For each potential GPU frequency, load a ring frequency we'd like
> + * to use for memory access. We do this by specifying the IA frequency
> + * the PCU should use as a reference to determine the ring frequency.
> + */
> + for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay;
> + gpu_freq--) {
> + int diff = dev_priv->max_delay - gpu_freq;
> +
> + /*
> + * For GPU frequencies less than 750MHz, just use the lowest
> + * ring freq.
> + */
> + if (gpu_freq < min_freq)
> + ia_freq = 800;
> + else
> + ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
> + ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
> +
> + I915_WRITE(GEN6_PCODE_DATA,
> + (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) |
> + gpu_freq);
> + I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
> + GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
> + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
> + GEN6_PCODE_READY) == 0, 10)) {
> + DRM_ERROR("pcode write of freq table timed out\n");
> + continue;
> + }
> + }
> +
> + mutex_unlock(&dev_priv->dev->struct_mutex);
> +}
> +
> +static void ironlake_teardown_rc6(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> +
> + if (dev_priv->renderctx) {
> + i915_gem_object_unpin(dev_priv->renderctx);
> + drm_gem_object_unreference(&dev_priv->renderctx->base);
> + dev_priv->renderctx = NULL;
> + }
> +
> + if (dev_priv->pwrctx) {
> + i915_gem_object_unpin(dev_priv->pwrctx);
> + drm_gem_object_unreference(&dev_priv->pwrctx->base);
> + dev_priv->pwrctx = NULL;
> + }
> +}
> +
> +void ironlake_disable_rc6(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> +
> + if (I915_READ(PWRCTXA)) {
> + /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
> + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
> + wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
> + 50);
> +
> + I915_WRITE(PWRCTXA, 0);
> + POSTING_READ(PWRCTXA);
> +
> + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
> + POSTING_READ(RSTDBYCTL);
> + }
> +
> + ironlake_teardown_rc6(dev);
> +}
> +
> +static int ironlake_setup_rc6(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> +
> + if (dev_priv->renderctx == NULL)
> + dev_priv->renderctx = intel_alloc_context_page(dev);
> + if (!dev_priv->renderctx)
> + return -ENOMEM;
> +
> + if (dev_priv->pwrctx == NULL)
> + dev_priv->pwrctx = intel_alloc_context_page(dev);
> + if (!dev_priv->pwrctx) {
> + ironlake_teardown_rc6(dev);
> + return -ENOMEM;
> + }
> +
> + return 0;
> +}
> +
> +void ironlake_enable_rc6(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + int ret;
> +
> + /* rc6 disabled by default due to repeated reports of hanging during
> + * boot and resume.
> + */
> + if (!intel_enable_rc6(dev))
> + return;
> +
> + mutex_lock(&dev->struct_mutex);
> + ret = ironlake_setup_rc6(dev);
> + if (ret) {
> + mutex_unlock(&dev->struct_mutex);
> + return;
> + }
> +
> + /*
> + * GPU can automatically power down the render unit if given a page
> + * to save state.
> + */
> + ret = BEGIN_LP_RING(6);
> + if (ret) {
> + ironlake_teardown_rc6(dev);
> + mutex_unlock(&dev->struct_mutex);
> + return;
> + }
> +
> + OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
> + OUT_RING(MI_SET_CONTEXT);
> + OUT_RING(dev_priv->renderctx->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();
> +
> + /*
> + * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
> + * does an implicit flush, combined with MI_FLUSH above, it should be
> + * safe to assume that renderctx is valid
> + */
> + ret = intel_wait_ring_idle(LP_RING(dev_priv));
> + if (ret) {
> + DRM_ERROR("failed to enable ironlake power power savings\n");
> + ironlake_teardown_rc6(dev);
> + mutex_unlock(&dev->struct_mutex);
> + return;
> + }
> +
> + I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
> + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
> + mutex_unlock(&dev->struct_mutex);
> +}
> +
> --
> 1.7.10
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
--
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 3/5] drm/i915: move emon functionality into intel_pm module
2012-04-18 14:51 [PATCH 0/5] rebased intel_pm series Eugeni Dodonov
2012-04-18 14:51 ` [PATCH 1/5] drm/i915: fix line breaks in intel_pm Eugeni Dodonov
2012-04-18 14:51 ` [PATCH 2/5] drm/i915: move drps, rps and rc6-related functions to intel_pm Eugeni Dodonov
@ 2012-04-18 14:51 ` Eugeni Dodonov
2012-04-18 14:51 ` [PATCH 4/5] drm/i915: move clock gating " Eugeni Dodonov
2012-04-18 14:51 ` [PATCH 5/5] drm/i915: add generic power management initialization Eugeni Dodonov
4 siblings, 0 replies; 7+ messages in thread
From: Eugeni Dodonov @ 2012-04-18 14:51 UTC (permalink / raw)
To: intel-gfx; +Cc: Eugeni Dodonov
This moves the Ironlake energy monitoring functionality into intel_pm
module.
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Acked-by: Ben Widawsky <benjamin.widawsky@intel.com>
Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
---
drivers/gpu/drm/i915/intel_display.c | 86 ----------------------------------
drivers/gpu/drm/i915/intel_pm.c | 86 ++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+), 86 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d3982e9..4fb1982 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6351,92 +6351,6 @@ static const struct drm_mode_config_funcs intel_mode_funcs = {
.output_poll_changed = intel_fb_output_poll_changed,
};
-static unsigned long intel_pxfreq(u32 vidfreq)
-{
- unsigned long freq;
- int div = (vidfreq & 0x3f0000) >> 16;
- int post = (vidfreq & 0x3000) >> 12;
- int pre = (vidfreq & 0x7);
-
- if (!pre)
- return 0;
-
- freq = ((div * 133333) / ((1<<post) * pre));
-
- return freq;
-}
-
-void intel_init_emon(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 lcfuse;
- u8 pxw[16];
- int i;
-
- /* Disable to program */
- I915_WRITE(ECR, 0);
- POSTING_READ(ECR);
-
- /* Program energy weights for various events */
- I915_WRITE(SDEW, 0x15040d00);
- I915_WRITE(CSIEW0, 0x007f0000);
- I915_WRITE(CSIEW1, 0x1e220004);
- I915_WRITE(CSIEW2, 0x04000004);
-
- for (i = 0; i < 5; i++)
- I915_WRITE(PEW + (i * 4), 0);
- for (i = 0; i < 3; i++)
- I915_WRITE(DEW + (i * 4), 0);
-
- /* Program P-state weights to account for frequency power adjustment */
- for (i = 0; i < 16; i++) {
- u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4));
- unsigned long freq = intel_pxfreq(pxvidfreq);
- unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >>
- PXVFREQ_PX_SHIFT;
- unsigned long val;
-
- val = vid * vid;
- val *= (freq / 1000);
- val *= 255;
- val /= (127*127*900);
- if (val > 0xff)
- DRM_ERROR("bad pxval: %ld\n", val);
- pxw[i] = val;
- }
- /* Render standby states get 0 weight */
- pxw[14] = 0;
- pxw[15] = 0;
-
- for (i = 0; i < 4; i++) {
- u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) |
- (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]);
- I915_WRITE(PXW + (i * 4), val);
- }
-
- /* Adjust magic regs to magic values (more experimental results) */
- I915_WRITE(OGW0, 0);
- I915_WRITE(OGW1, 0);
- I915_WRITE(EG0, 0x00007f00);
- I915_WRITE(EG1, 0x0000000e);
- I915_WRITE(EG2, 0x000e0000);
- I915_WRITE(EG3, 0x68000300);
- I915_WRITE(EG4, 0x42000000);
- I915_WRITE(EG5, 0x00140031);
- I915_WRITE(EG6, 0);
- I915_WRITE(EG7, 0);
-
- for (i = 0; i < 8; i++)
- I915_WRITE(PXWL + (i * 4), 0);
-
- /* Enable PMON + select events */
- I915_WRITE(ECR, 0x80000019);
-
- lcfuse = I915_READ(LCFUSE02);
-
- dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
-}
-
static void ironlake_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 58b26df0..280d66d 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2488,3 +2488,89 @@ void ironlake_enable_rc6(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
}
+static unsigned long intel_pxfreq(u32 vidfreq)
+{
+ unsigned long freq;
+ int div = (vidfreq & 0x3f0000) >> 16;
+ int post = (vidfreq & 0x3000) >> 12;
+ int pre = (vidfreq & 0x7);
+
+ if (!pre)
+ return 0;
+
+ freq = ((div * 133333) / ((1<<post) * pre));
+
+ return freq;
+}
+
+void intel_init_emon(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 lcfuse;
+ u8 pxw[16];
+ int i;
+
+ /* Disable to program */
+ I915_WRITE(ECR, 0);
+ POSTING_READ(ECR);
+
+ /* Program energy weights for various events */
+ I915_WRITE(SDEW, 0x15040d00);
+ I915_WRITE(CSIEW0, 0x007f0000);
+ I915_WRITE(CSIEW1, 0x1e220004);
+ I915_WRITE(CSIEW2, 0x04000004);
+
+ for (i = 0; i < 5; i++)
+ I915_WRITE(PEW + (i * 4), 0);
+ for (i = 0; i < 3; i++)
+ I915_WRITE(DEW + (i * 4), 0);
+
+ /* Program P-state weights to account for frequency power adjustment */
+ for (i = 0; i < 16; i++) {
+ u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4));
+ unsigned long freq = intel_pxfreq(pxvidfreq);
+ unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >>
+ PXVFREQ_PX_SHIFT;
+ unsigned long val;
+
+ val = vid * vid;
+ val *= (freq / 1000);
+ val *= 255;
+ val /= (127*127*900);
+ if (val > 0xff)
+ DRM_ERROR("bad pxval: %ld\n", val);
+ pxw[i] = val;
+ }
+ /* Render standby states get 0 weight */
+ pxw[14] = 0;
+ pxw[15] = 0;
+
+ for (i = 0; i < 4; i++) {
+ u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) |
+ (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]);
+ I915_WRITE(PXW + (i * 4), val);
+ }
+
+ /* Adjust magic regs to magic values (more experimental results) */
+ I915_WRITE(OGW0, 0);
+ I915_WRITE(OGW1, 0);
+ I915_WRITE(EG0, 0x00007f00);
+ I915_WRITE(EG1, 0x0000000e);
+ I915_WRITE(EG2, 0x000e0000);
+ I915_WRITE(EG3, 0x68000300);
+ I915_WRITE(EG4, 0x42000000);
+ I915_WRITE(EG5, 0x00140031);
+ I915_WRITE(EG6, 0);
+ I915_WRITE(EG7, 0);
+
+ for (i = 0; i < 8; i++)
+ I915_WRITE(PXWL + (i * 4), 0);
+
+ /* Enable PMON + select events */
+ I915_WRITE(ECR, 0x80000019);
+
+ lcfuse = I915_READ(LCFUSE02);
+
+ dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
+}
+
--
1.7.10
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 4/5] drm/i915: move clock gating functionality into intel_pm module
2012-04-18 14:51 [PATCH 0/5] rebased intel_pm series Eugeni Dodonov
` (2 preceding siblings ...)
2012-04-18 14:51 ` [PATCH 3/5] drm/i915: move emon functionality into intel_pm module Eugeni Dodonov
@ 2012-04-18 14:51 ` Eugeni Dodonov
2012-04-18 14:51 ` [PATCH 5/5] drm/i915: add generic power management initialization Eugeni Dodonov
4 siblings, 0 replies; 7+ messages in thread
From: Eugeni Dodonov @ 2012-04-18 14:51 UTC (permalink / raw)
To: intel-gfx; +Cc: Eugeni Dodonov
This moves the clock gating-related functions into intel_pm module.
v2: also move the gen7_setup_fixed_func_scheduler function, introduced
after the original patches, into intel_pm as well.
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Acked-by: Ben Widawsky <benjamin.widawsky@intel.com>
Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
---
drivers/gpu/drm/i915/intel_display.c | 355 +---------------------------------
drivers/gpu/drm/i915/intel_drv.h | 16 ++
drivers/gpu/drm/i915/intel_pm.c | 340 ++++++++++++++++++++++++++++++++
3 files changed, 357 insertions(+), 354 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 4fb1982..dec67aa 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1515,7 +1515,7 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
* Plane regs are double buffered, going from enabled->disabled needs a
* trigger in order to latch. The display address reg provides this.
*/
-static void intel_flush_display_plane(struct drm_i915_private *dev_priv,
+void intel_flush_display_plane(struct drm_i915_private *dev_priv,
enum plane plane)
{
I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane)));
@@ -6351,359 +6351,6 @@ static const struct drm_mode_config_funcs intel_mode_funcs = {
.output_poll_changed = intel_fb_output_poll_changed,
};
-static void ironlake_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
-
- /* Required for FBC */
- dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
- DPFCRUNIT_CLOCK_GATE_DISABLE |
- DPFDUNIT_CLOCK_GATE_DISABLE;
- /* Required for CxSR */
- dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
-
- I915_WRITE(PCH_3DCGDIS0,
- MARIUNIT_CLOCK_GATE_DISABLE |
- SVSMUNIT_CLOCK_GATE_DISABLE);
- I915_WRITE(PCH_3DCGDIS1,
- VFMUNIT_CLOCK_GATE_DISABLE);
-
- I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
-
- /*
- * According to the spec the following bits should be set in
- * order to enable memory self-refresh
- * The bit 22/21 of 0x42004
- * The bit 5 of 0x42020
- * The bit 15 of 0x45000
- */
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- (I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_DPARB_GATE | ILK_VSDPFD_FULL));
- I915_WRITE(ILK_DSPCLK_GATE,
- (I915_READ(ILK_DSPCLK_GATE) |
- ILK_DPARB_CLK_GATE));
- I915_WRITE(DISP_ARB_CTL,
- (I915_READ(DISP_ARB_CTL) |
- DISP_FBC_WM_DIS));
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
-
- /*
- * Based on the document from hardware guys the following bits
- * should be set unconditionally in order to enable FBC.
- * The bit 22 of 0x42000
- * The bit 22 of 0x42004
- * The bit 7,8,9 of 0x42020.
- */
- if (IS_IRONLAKE_M(dev)) {
- I915_WRITE(ILK_DISPLAY_CHICKEN1,
- I915_READ(ILK_DISPLAY_CHICKEN1) |
- ILK_FBCQ_DIS);
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_DPARB_GATE);
- I915_WRITE(ILK_DSPCLK_GATE,
- I915_READ(ILK_DSPCLK_GATE) |
- ILK_DPFC_DIS1 |
- ILK_DPFC_DIS2 |
- ILK_CLK_FBC);
- }
-
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_ELPIN_409_SELECT);
- I915_WRITE(_3D_CHICKEN2,
- _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
- _3D_CHICKEN2_WM_READ_PIPELINED);
-}
-
-static void gen6_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe;
- uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
-
- I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
-
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_ELPIN_409_SELECT);
-
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
-
- /* clear masked bit */
- I915_WRITE(CACHE_MODE_0,
- CM0_STC_EVICT_DISABLE_LRA_SNB << CM0_MASK_SHIFT);
-
- I915_WRITE(GEN6_UCGCTL1,
- I915_READ(GEN6_UCGCTL1) |
- GEN6_BLBUNIT_CLOCK_GATE_DISABLE |
- GEN6_CSUNIT_CLOCK_GATE_DISABLE);
-
- /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
- * gating disable must be set. Failure to set it results in
- * flickering pixels due to Z write ordering failures after
- * some amount of runtime in the Mesa "fire" demo, and Unigine
- * Sanctuary and Tropics, and apparently anything else with
- * alpha test or pixel discard.
- *
- * According to the spec, bit 11 (RCCUNIT) must also be set,
- * but we didn't debug actual testcases to find it out.
- */
- I915_WRITE(GEN6_UCGCTL2,
- GEN6_RCPBUNIT_CLOCK_GATE_DISABLE |
- GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
-
- /* Bspec says we need to always set all mask bits. */
- I915_WRITE(_3D_CHICKEN, (0xFFFF << 16) |
- _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL);
-
- /*
- * According to the spec the following bits should be
- * set in order to enable memory self-refresh and fbc:
- * The bit21 and bit22 of 0x42000
- * The bit21 and bit22 of 0x42004
- * The bit5 and bit7 of 0x42020
- * The bit14 of 0x70180
- * The bit14 of 0x71180
- */
- I915_WRITE(ILK_DISPLAY_CHICKEN1,
- I915_READ(ILK_DISPLAY_CHICKEN1) |
- ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_DPARB_GATE | ILK_VSDPFD_FULL);
- I915_WRITE(ILK_DSPCLK_GATE,
- I915_READ(ILK_DSPCLK_GATE) |
- ILK_DPARB_CLK_GATE |
- ILK_DPFD_CLK_GATE);
-
- for_each_pipe(pipe) {
- I915_WRITE(DSPCNTR(pipe),
- I915_READ(DSPCNTR(pipe)) |
- DISPPLANE_TRICKLE_FEED_DISABLE);
- intel_flush_display_plane(dev_priv, pipe);
- }
-}
-
-static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv)
-{
- uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE);
-
- reg &= ~GEN7_FF_SCHED_MASK;
- reg |= GEN7_FF_TS_SCHED_HW;
- reg |= GEN7_FF_VS_SCHED_HW;
- reg |= GEN7_FF_DS_SCHED_HW;
-
- I915_WRITE(GEN7_FF_THREAD_MODE, reg);
-}
-
-static void ivybridge_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe;
- uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
-
- I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
-
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
-
- /* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
- * This implements the WaDisableRCZUnitClockGating workaround.
- */
- I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
-
- I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
-
- I915_WRITE(IVB_CHICKEN3,
- CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
- CHICKEN3_DGMG_DONE_FIX_DISABLE);
-
- /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
- I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
- GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
-
- /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
- I915_WRITE(GEN7_L3CNTLREG1,
- GEN7_WA_FOR_GEN7_L3_CONTROL);
- I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER,
- GEN7_WA_L3_CHICKEN_MODE);
-
- /* This is required by WaCatErrorRejectionIssue */
- I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
- I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
- GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
-
- for_each_pipe(pipe) {
- I915_WRITE(DSPCNTR(pipe),
- I915_READ(DSPCNTR(pipe)) |
- DISPPLANE_TRICKLE_FEED_DISABLE);
- intel_flush_display_plane(dev_priv, pipe);
- }
-
- gen7_setup_fixed_func_scheduler(dev_priv);
-}
-
-static void valleyview_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe;
- uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
-
- I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
-
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
-
- /* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
- * This implements the WaDisableRCZUnitClockGating workaround.
- */
- I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
-
- I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
-
- I915_WRITE(IVB_CHICKEN3,
- CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
- CHICKEN3_DGMG_DONE_FIX_DISABLE);
-
- /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
- I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
- GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
-
- /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
- I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL);
- I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE);
-
- /* This is required by WaCatErrorRejectionIssue */
- I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
- I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
- GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
-
- for_each_pipe(pipe) {
- I915_WRITE(DSPCNTR(pipe),
- I915_READ(DSPCNTR(pipe)) |
- DISPPLANE_TRICKLE_FEED_DISABLE);
- intel_flush_display_plane(dev_priv, pipe);
- }
-
- I915_WRITE(CACHE_MODE_1, I915_READ(CACHE_MODE_1) |
- (PIXEL_SUBSPAN_COLLECT_OPT_DISABLE << 16) |
- PIXEL_SUBSPAN_COLLECT_OPT_DISABLE);
-}
-
-static void g4x_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dspclk_gate;
-
- I915_WRITE(RENCLK_GATE_D1, 0);
- I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
- GS_UNIT_CLOCK_GATE_DISABLE |
- CL_UNIT_CLOCK_GATE_DISABLE);
- I915_WRITE(RAMCLK_GATE_D, 0);
- dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
- OVRUNIT_CLOCK_GATE_DISABLE |
- OVCUNIT_CLOCK_GATE_DISABLE;
- if (IS_GM45(dev))
- dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
- I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
-}
-
-static void crestline_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
- I915_WRITE(RENCLK_GATE_D2, 0);
- I915_WRITE(DSPCLK_GATE_D, 0);
- I915_WRITE(RAMCLK_GATE_D, 0);
- I915_WRITE16(DEUC, 0);
-}
-
-static void broadwater_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
- I965_RCC_CLOCK_GATE_DISABLE |
- I965_RCPB_CLOCK_GATE_DISABLE |
- I965_ISC_CLOCK_GATE_DISABLE |
- I965_FBC_CLOCK_GATE_DISABLE);
- I915_WRITE(RENCLK_GATE_D2, 0);
-}
-
-static void gen3_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 dstate = I915_READ(D_STATE);
-
- dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
- DSTATE_DOT_CLOCK_GATING;
- I915_WRITE(D_STATE, dstate);
-}
-
-static void i85x_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
-}
-
-static void i830_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
-}
-
-static void ibx_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- /*
- * On Ibex Peak and Cougar Point, we need to disable clock
- * gating for the panel power sequencer or it will fail to
- * start up when no ports are active.
- */
- I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
-}
-
-static void cpt_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe;
-
- /*
- * On Ibex Peak and Cougar Point, we need to disable clock
- * gating for the panel power sequencer or it will fail to
- * start up when no ports are active.
- */
- I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
- I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
- DPLS_EDP_PPS_FIX_DIS);
- /* Without this, mode sets may fail silently on FDI */
- for_each_pipe(pipe)
- I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS);
-}
-
-void intel_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- dev_priv->display.init_clock_gating(dev);
-
- if (dev_priv->display.init_pch_clock_gating)
- dev_priv->display.init_pch_clock_gating(dev);
-}
-
/* Set up chip specific display functions */
static void intel_init_display(struct drm_device *dev)
{
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index c87f29a..771075c 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -339,6 +339,8 @@ extern bool intel_dpd_is_edp(struct drm_device *dev);
extern void intel_edp_link_config(struct intel_encoder *, int *, int *);
extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
extern int intel_plane_init(struct drm_device *dev, enum pipe pipe);
+extern void intel_flush_display_plane(struct drm_i915_private *dev_priv,
+ enum plane plane);
/* intel_panel.c */
extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
@@ -490,4 +492,18 @@ extern int i85x_get_fifo_size(struct drm_device *dev, int plane);
extern int i845_get_fifo_size(struct drm_device *dev, int plane);
extern int i830_get_fifo_size(struct drm_device *dev, int plane);
+/* Clock gating */
+extern void ironlake_init_clock_gating(struct drm_device *dev);
+extern void gen6_init_clock_gating(struct drm_device *dev);
+extern void ivybridge_init_clock_gating(struct drm_device *dev);
+extern void valleyview_init_clock_gating(struct drm_device *dev);
+extern void g4x_init_clock_gating(struct drm_device *dev);
+extern void crestline_init_clock_gating(struct drm_device *dev);
+extern void broadwater_init_clock_gating(struct drm_device *dev);
+extern void gen3_init_clock_gating(struct drm_device *dev);
+extern void i85x_init_clock_gating(struct drm_device *dev);
+extern void i830_init_clock_gating(struct drm_device *dev);
+extern void ibx_init_clock_gating(struct drm_device *dev);
+extern void cpt_init_clock_gating(struct drm_device *dev);
+
#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 280d66d..b39867f 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2574,3 +2574,343 @@ void intel_init_emon(struct drm_device *dev)
dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
}
+void ironlake_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+ /* Required for FBC */
+ dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
+ DPFCRUNIT_CLOCK_GATE_DISABLE |
+ DPFDUNIT_CLOCK_GATE_DISABLE;
+ /* Required for CxSR */
+ dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
+
+ I915_WRITE(PCH_3DCGDIS0,
+ MARIUNIT_CLOCK_GATE_DISABLE |
+ SVSMUNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(PCH_3DCGDIS1,
+ VFMUNIT_CLOCK_GATE_DISABLE);
+
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+ /*
+ * According to the spec the following bits should be set in
+ * order to enable memory self-refresh
+ * The bit 22/21 of 0x42004
+ * The bit 5 of 0x42020
+ * The bit 15 of 0x45000
+ */
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ (I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_DPARB_GATE | ILK_VSDPFD_FULL));
+ I915_WRITE(ILK_DSPCLK_GATE,
+ (I915_READ(ILK_DSPCLK_GATE) |
+ ILK_DPARB_CLK_GATE));
+ I915_WRITE(DISP_ARB_CTL,
+ (I915_READ(DISP_ARB_CTL) |
+ DISP_FBC_WM_DIS));
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ /*
+ * Based on the document from hardware guys the following bits
+ * should be set unconditionally in order to enable FBC.
+ * The bit 22 of 0x42000
+ * The bit 22 of 0x42004
+ * The bit 7,8,9 of 0x42020.
+ */
+ if (IS_IRONLAKE_M(dev)) {
+ I915_WRITE(ILK_DISPLAY_CHICKEN1,
+ I915_READ(ILK_DISPLAY_CHICKEN1) |
+ ILK_FBCQ_DIS);
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_DPARB_GATE);
+ I915_WRITE(ILK_DSPCLK_GATE,
+ I915_READ(ILK_DSPCLK_GATE) |
+ ILK_DPFC_DIS1 |
+ ILK_DPFC_DIS2 |
+ ILK_CLK_FBC);
+ }
+
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_ELPIN_409_SELECT);
+ I915_WRITE(_3D_CHICKEN2,
+ _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
+ _3D_CHICKEN2_WM_READ_PIPELINED);
+}
+
+void gen6_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe;
+ uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_ELPIN_409_SELECT);
+
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
+ * gating disable must be set. Failure to set it results in
+ * flickering pixels due to Z write ordering failures after
+ * some amount of runtime in the Mesa "fire" demo, and Unigine
+ * Sanctuary and Tropics, and apparently anything else with
+ * alpha test or pixel discard.
+ *
+ * According to the spec, bit 11 (RCCUNIT) must also be set,
+ * but we didn't debug actual testcases to find it out.
+ */
+ I915_WRITE(GEN6_UCGCTL2,
+ GEN6_RCPBUNIT_CLOCK_GATE_DISABLE |
+ GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
+
+ /*
+ * According to the spec the following bits should be
+ * set in order to enable memory self-refresh and fbc:
+ * The bit21 and bit22 of 0x42000
+ * The bit21 and bit22 of 0x42004
+ * The bit5 and bit7 of 0x42020
+ * The bit14 of 0x70180
+ * The bit14 of 0x71180
+ */
+ I915_WRITE(ILK_DISPLAY_CHICKEN1,
+ I915_READ(ILK_DISPLAY_CHICKEN1) |
+ ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_DPARB_GATE | ILK_VSDPFD_FULL);
+ I915_WRITE(ILK_DSPCLK_GATE,
+ I915_READ(ILK_DSPCLK_GATE) |
+ ILK_DPARB_CLK_GATE |
+ ILK_DPFD_CLK_GATE);
+
+ for_each_pipe(pipe) {
+ I915_WRITE(DSPCNTR(pipe),
+ I915_READ(DSPCNTR(pipe)) |
+ DISPPLANE_TRICKLE_FEED_DISABLE);
+ intel_flush_display_plane(dev_priv, pipe);
+ }
+}
+
+static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv)
+{
+ uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE);
+
+ reg &= ~GEN7_FF_SCHED_MASK;
+ reg |= GEN7_FF_TS_SCHED_HW;
+ reg |= GEN7_FF_VS_SCHED_HW;
+ reg |= GEN7_FF_DS_SCHED_HW;
+
+ I915_WRITE(GEN7_FF_THREAD_MODE, reg);
+}
+
+void ivybridge_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe;
+ uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ /* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
+ * This implements the WaDisableRCZUnitClockGating workaround.
+ */
+ I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
+
+ I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
+
+ I915_WRITE(IVB_CHICKEN3,
+ CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
+ CHICKEN3_DGMG_DONE_FIX_DISABLE);
+
+ /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
+ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
+ GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
+
+ /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
+ I915_WRITE(GEN7_L3CNTLREG1,
+ GEN7_WA_FOR_GEN7_L3_CONTROL);
+ I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER,
+ GEN7_WA_L3_CHICKEN_MODE);
+
+ /* This is required by WaCatErrorRejectionIssue */
+ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
+ I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
+ GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
+
+ for_each_pipe(pipe) {
+ I915_WRITE(DSPCNTR(pipe),
+ I915_READ(DSPCNTR(pipe)) |
+ DISPPLANE_TRICKLE_FEED_DISABLE);
+ intel_flush_display_plane(dev_priv, pipe);
+ }
+
+ gen7_setup_fixed_func_scheduler(dev_priv);
+}
+
+void valleyview_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe;
+ uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ /* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
+ * This implements the WaDisableRCZUnitClockGating workaround.
+ */
+ I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
+
+ I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
+
+ I915_WRITE(IVB_CHICKEN3,
+ CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
+ CHICKEN3_DGMG_DONE_FIX_DISABLE);
+
+ /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
+ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
+ GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
+
+ /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
+ I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL);
+ I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE);
+
+ /* This is required by WaCatErrorRejectionIssue */
+ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
+ I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
+ GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
+
+ for_each_pipe(pipe) {
+ I915_WRITE(DSPCNTR(pipe),
+ I915_READ(DSPCNTR(pipe)) |
+ DISPPLANE_TRICKLE_FEED_DISABLE);
+ intel_flush_display_plane(dev_priv, pipe);
+ }
+
+ I915_WRITE(CACHE_MODE_1, I915_READ(CACHE_MODE_1) |
+ (PIXEL_SUBSPAN_COLLECT_OPT_DISABLE << 16) |
+ PIXEL_SUBSPAN_COLLECT_OPT_DISABLE);
+}
+
+void g4x_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dspclk_gate;
+
+ I915_WRITE(RENCLK_GATE_D1, 0);
+ I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
+ GS_UNIT_CLOCK_GATE_DISABLE |
+ CL_UNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(RAMCLK_GATE_D, 0);
+ dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
+ OVRUNIT_CLOCK_GATE_DISABLE |
+ OVCUNIT_CLOCK_GATE_DISABLE;
+ if (IS_GM45(dev))
+ dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
+ I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
+}
+
+void crestline_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
+ I915_WRITE(RENCLK_GATE_D2, 0);
+ I915_WRITE(DSPCLK_GATE_D, 0);
+ I915_WRITE(RAMCLK_GATE_D, 0);
+ I915_WRITE16(DEUC, 0);
+}
+
+void broadwater_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
+ I965_RCC_CLOCK_GATE_DISABLE |
+ I965_RCPB_CLOCK_GATE_DISABLE |
+ I965_ISC_CLOCK_GATE_DISABLE |
+ I965_FBC_CLOCK_GATE_DISABLE);
+ I915_WRITE(RENCLK_GATE_D2, 0);
+}
+
+void gen3_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 dstate = I915_READ(D_STATE);
+
+ dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
+ DSTATE_DOT_CLOCK_GATING;
+ I915_WRITE(D_STATE, dstate);
+}
+
+void i85x_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
+}
+
+void i830_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
+}
+
+void ibx_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /*
+ * On Ibex Peak and Cougar Point, we need to disable clock
+ * gating for the panel power sequencer or it will fail to
+ * start up when no ports are active.
+ */
+ I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+}
+
+void cpt_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe;
+
+ /*
+ * On Ibex Peak and Cougar Point, we need to disable clock
+ * gating for the panel power sequencer or it will fail to
+ * start up when no ports are active.
+ */
+ I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
+ DPLS_EDP_PPS_FIX_DIS);
+ /* Without this, mode sets may fail silently on FDI */
+ for_each_pipe(pipe)
+ I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS);
+}
+
+void intel_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ dev_priv->display.init_clock_gating(dev);
+
+ if (dev_priv->display.init_pch_clock_gating)
+ dev_priv->display.init_pch_clock_gating(dev);
+}
+
--
1.7.10
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 5/5] drm/i915: add generic power management initialization
2012-04-18 14:51 [PATCH 0/5] rebased intel_pm series Eugeni Dodonov
` (3 preceding siblings ...)
2012-04-18 14:51 ` [PATCH 4/5] drm/i915: move clock gating " Eugeni Dodonov
@ 2012-04-18 14:51 ` Eugeni Dodonov
4 siblings, 0 replies; 7+ messages in thread
From: Eugeni Dodonov @ 2012-04-18 14:51 UTC (permalink / raw)
To: intel-gfx; +Cc: Eugeni Dodonov
This adds intel_pm routine for generic power-related infrastructure
initialization.
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Acked-by: Ben Widawsky <benjamin.widawsky@intel.com>
Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
---
drivers/gpu/drm/i915/intel_display.c | 125 +-----------------------------
drivers/gpu/drm/i915/intel_drv.h | 45 +----------
drivers/gpu/drm/i915/intel_pm.c | 142 ++++++++++++++++++++++++++++++++++
3 files changed, 145 insertions(+), 167 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index dec67aa..aa647c6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6367,23 +6367,6 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.update_plane = i9xx_update_plane;
}
- if (I915_HAS_FBC(dev)) {
- if (HAS_PCH_SPLIT(dev)) {
- dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
- dev_priv->display.enable_fbc = ironlake_enable_fbc;
- dev_priv->display.disable_fbc = ironlake_disable_fbc;
- } else if (IS_GM45(dev)) {
- dev_priv->display.fbc_enabled = g4x_fbc_enabled;
- dev_priv->display.enable_fbc = g4x_enable_fbc;
- dev_priv->display.disable_fbc = g4x_disable_fbc;
- } else if (IS_CRESTLINE(dev)) {
- dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
- dev_priv->display.enable_fbc = i8xx_enable_fbc;
- dev_priv->display.disable_fbc = i8xx_disable_fbc;
- }
- /* 855GM needs testing */
- }
-
/* Returns the core display clock speed */
if (IS_VALLEYVIEW(dev))
dev_priv->display.get_display_clock_speed =
@@ -6410,130 +6393,24 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.get_display_clock_speed =
i830_get_display_clock_speed;
- /* For FIFO watermark updates */
if (HAS_PCH_SPLIT(dev)) {
- dev_priv->display.force_wake_get = __gen6_gt_force_wake_get;
- dev_priv->display.force_wake_put = __gen6_gt_force_wake_put;
-
- /* IVB configs may use multi-threaded forcewake */
- if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
- u32 ecobus;
-
- /* A small trick here - if the bios hasn't configured MT forcewake,
- * and if the device is in RC6, then force_wake_mt_get will not wake
- * the device and the ECOBUS read will return zero. Which will be
- * (correctly) interpreted by the test below as MT forcewake being
- * disabled.
- */
- mutex_lock(&dev->struct_mutex);
- __gen6_gt_force_wake_mt_get(dev_priv);
- ecobus = I915_READ_NOTRACE(ECOBUS);
- __gen6_gt_force_wake_mt_put(dev_priv);
- mutex_unlock(&dev->struct_mutex);
-
- if (ecobus & FORCEWAKE_MT_ENABLE) {
- DRM_DEBUG_KMS("Using MT version of forcewake\n");
- dev_priv->display.force_wake_get =
- __gen6_gt_force_wake_mt_get;
- dev_priv->display.force_wake_put =
- __gen6_gt_force_wake_mt_put;
- }
- }
-
- if (HAS_PCH_IBX(dev))
- dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating;
- else if (HAS_PCH_CPT(dev))
- dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating;
-
if (IS_GEN5(dev)) {
- if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
- dev_priv->display.update_wm = ironlake_update_wm;
- else {
- DRM_DEBUG_KMS("Failed to get proper latency. "
- "Disable CxSR\n");
- dev_priv->display.update_wm = NULL;
- }
dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
- dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
dev_priv->display.write_eld = ironlake_write_eld;
} else if (IS_GEN6(dev)) {
- if (SNB_READ_WM0_LATENCY()) {
- dev_priv->display.update_wm = sandybridge_update_wm;
- dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
- } else {
- DRM_DEBUG_KMS("Failed to read display plane latency. "
- "Disable CxSR\n");
- dev_priv->display.update_wm = NULL;
- }
dev_priv->display.fdi_link_train = gen6_fdi_link_train;
- dev_priv->display.init_clock_gating = gen6_init_clock_gating;
dev_priv->display.write_eld = ironlake_write_eld;
} else if (IS_IVYBRIDGE(dev)) {
/* FIXME: detect B0+ stepping and use auto training */
dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
- if (SNB_READ_WM0_LATENCY()) {
- dev_priv->display.update_wm = sandybridge_update_wm;
- dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
- } else {
- DRM_DEBUG_KMS("Failed to read display plane latency. "
- "Disable CxSR\n");
- dev_priv->display.update_wm = NULL;
- }
- dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
dev_priv->display.write_eld = ironlake_write_eld;
} else
dev_priv->display.update_wm = NULL;
} else if (IS_VALLEYVIEW(dev)) {
- dev_priv->display.update_wm = valleyview_update_wm;
- dev_priv->display.init_clock_gating =
- valleyview_init_clock_gating;
dev_priv->display.force_wake_get = vlv_force_wake_get;
dev_priv->display.force_wake_put = vlv_force_wake_put;
- } else if (IS_PINEVIEW(dev)) {
- if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
- dev_priv->is_ddr3,
- dev_priv->fsb_freq,
- dev_priv->mem_freq)) {
- DRM_INFO("failed to find known CxSR latency "
- "(found ddr%s fsb freq %d, mem freq %d), "
- "disabling CxSR\n",
- (dev_priv->is_ddr3 == 1) ? "3" : "2",
- dev_priv->fsb_freq, dev_priv->mem_freq);
- /* Disable CxSR and never update its watermark again */
- pineview_disable_cxsr(dev);
- dev_priv->display.update_wm = NULL;
- } else
- dev_priv->display.update_wm = pineview_update_wm;
- dev_priv->display.init_clock_gating = gen3_init_clock_gating;
} else if (IS_G4X(dev)) {
dev_priv->display.write_eld = g4x_write_eld;
- dev_priv->display.update_wm = g4x_update_wm;
- dev_priv->display.init_clock_gating = g4x_init_clock_gating;
- } else if (IS_GEN4(dev)) {
- dev_priv->display.update_wm = i965_update_wm;
- if (IS_CRESTLINE(dev))
- dev_priv->display.init_clock_gating = crestline_init_clock_gating;
- else if (IS_BROADWATER(dev))
- dev_priv->display.init_clock_gating = broadwater_init_clock_gating;
- } else if (IS_GEN3(dev)) {
- dev_priv->display.update_wm = i9xx_update_wm;
- dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
- dev_priv->display.init_clock_gating = gen3_init_clock_gating;
- } else if (IS_I865G(dev)) {
- dev_priv->display.update_wm = i830_update_wm;
- dev_priv->display.init_clock_gating = i85x_init_clock_gating;
- dev_priv->display.get_fifo_size = i830_get_fifo_size;
- } else if (IS_I85X(dev)) {
- dev_priv->display.update_wm = i9xx_update_wm;
- dev_priv->display.get_fifo_size = i85x_get_fifo_size;
- dev_priv->display.init_clock_gating = i85x_init_clock_gating;
- } else {
- dev_priv->display.update_wm = i830_update_wm;
- dev_priv->display.init_clock_gating = i830_init_clock_gating;
- if (IS_845G(dev))
- dev_priv->display.get_fifo_size = i845_get_fifo_size;
- else
- dev_priv->display.get_fifo_size = i830_get_fifo_size;
}
/* Default just returns -ENODEV to indicate unsupported */
@@ -6723,6 +6600,8 @@ void intel_modeset_init(struct drm_device *dev)
intel_init_quirks(dev);
+ intel_init_pm(dev);
+
intel_init_display(dev);
if (IS_GEN2(dev)) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 771075c..c5bf8be 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -457,53 +457,10 @@ extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
extern u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg);
/* Power-related functions, located in intel_pm.c */
+extern void intel_init_pm(struct drm_device *dev);
/* FBC */
-extern void i8xx_disable_fbc(struct drm_device *dev);
-extern void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
-extern bool i8xx_fbc_enabled(struct drm_device *dev);
-extern void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
-extern void g4x_disable_fbc(struct drm_device *dev);
-extern bool g4x_fbc_enabled(struct drm_device *dev);
-extern void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
-extern void ironlake_disable_fbc(struct drm_device *dev);
-extern bool ironlake_fbc_enabled(struct drm_device *dev);
extern bool intel_fbc_enabled(struct drm_device *dev);
extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
extern void intel_update_fbc(struct drm_device *dev);
-/* Watermarks */
-extern void pineview_update_wm(struct drm_device *dev);
-extern void valleyview_update_wm(struct drm_device *dev);
-extern void g4x_update_wm(struct drm_device *dev);
-extern void i965_update_wm(struct drm_device *dev);
-extern void i9xx_update_wm(struct drm_device *dev);
-extern void i830_update_wm(struct drm_device *dev);
-extern void ironlake_update_wm(struct drm_device *dev);
-extern void sandybridge_update_wm(struct drm_device *dev);
-extern void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
- uint32_t sprite_width, int pixel_size);
-extern const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop,
- int is_ddr3,
- int fsb,
- int mem);
-extern void pineview_disable_cxsr(struct drm_device *dev);
-extern int i9xx_get_fifo_size(struct drm_device *dev, int plane);
-extern int i85x_get_fifo_size(struct drm_device *dev, int plane);
-extern int i845_get_fifo_size(struct drm_device *dev, int plane);
-extern int i830_get_fifo_size(struct drm_device *dev, int plane);
-
-/* Clock gating */
-extern void ironlake_init_clock_gating(struct drm_device *dev);
-extern void gen6_init_clock_gating(struct drm_device *dev);
-extern void ivybridge_init_clock_gating(struct drm_device *dev);
-extern void valleyview_init_clock_gating(struct drm_device *dev);
-extern void g4x_init_clock_gating(struct drm_device *dev);
-extern void crestline_init_clock_gating(struct drm_device *dev);
-extern void broadwater_init_clock_gating(struct drm_device *dev);
-extern void gen3_init_clock_gating(struct drm_device *dev);
-extern void i85x_init_clock_gating(struct drm_device *dev);
-extern void i830_init_clock_gating(struct drm_device *dev);
-extern void ibx_init_clock_gating(struct drm_device *dev);
-extern void cpt_init_clock_gating(struct drm_device *dev);
-
#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index b39867f..deb1aae 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2914,3 +2914,145 @@ void intel_init_clock_gating(struct drm_device *dev)
dev_priv->display.init_pch_clock_gating(dev);
}
+/* Set up chip specific power management-related functions */
+void intel_init_pm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (I915_HAS_FBC(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
+ dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
+ dev_priv->display.enable_fbc = ironlake_enable_fbc;
+ dev_priv->display.disable_fbc = ironlake_disable_fbc;
+ } else if (IS_GM45(dev)) {
+ dev_priv->display.fbc_enabled = g4x_fbc_enabled;
+ dev_priv->display.enable_fbc = g4x_enable_fbc;
+ dev_priv->display.disable_fbc = g4x_disable_fbc;
+ } else if (IS_CRESTLINE(dev)) {
+ dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
+ dev_priv->display.enable_fbc = i8xx_enable_fbc;
+ dev_priv->display.disable_fbc = i8xx_disable_fbc;
+ }
+ /* 855GM needs testing */
+ }
+
+ /* For FIFO watermark updates */
+ if (HAS_PCH_SPLIT(dev)) {
+ dev_priv->display.force_wake_get = __gen6_gt_force_wake_get;
+ dev_priv->display.force_wake_put = __gen6_gt_force_wake_put;
+
+ /* IVB configs may use multi-threaded forcewake */
+ if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
+ u32 ecobus;
+
+ /* A small trick here - if the bios hasn't configured MT forcewake,
+ * and if the device is in RC6, then force_wake_mt_get will not wake
+ * the device and the ECOBUS read will return zero. Which will be
+ * (correctly) interpreted by the test below as MT forcewake being
+ * disabled.
+ */
+ mutex_lock(&dev->struct_mutex);
+ __gen6_gt_force_wake_mt_get(dev_priv);
+ ecobus = I915_READ_NOTRACE(ECOBUS);
+ __gen6_gt_force_wake_mt_put(dev_priv);
+ mutex_unlock(&dev->struct_mutex);
+
+ if (ecobus & FORCEWAKE_MT_ENABLE) {
+ DRM_DEBUG_KMS("Using MT version of forcewake\n");
+ dev_priv->display.force_wake_get =
+ __gen6_gt_force_wake_mt_get;
+ dev_priv->display.force_wake_put =
+ __gen6_gt_force_wake_mt_put;
+ }
+ }
+
+ if (HAS_PCH_IBX(dev))
+ dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating;
+ else if (HAS_PCH_CPT(dev))
+ dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating;
+
+ if (IS_GEN5(dev)) {
+ if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
+ dev_priv->display.update_wm = ironlake_update_wm;
+ else {
+ DRM_DEBUG_KMS("Failed to get proper latency. "
+ "Disable CxSR\n");
+ dev_priv->display.update_wm = NULL;
+ }
+ dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
+ } else if (IS_GEN6(dev)) {
+ if (SNB_READ_WM0_LATENCY()) {
+ dev_priv->display.update_wm = sandybridge_update_wm;
+ dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
+ } else {
+ DRM_DEBUG_KMS("Failed to read display plane latency. "
+ "Disable CxSR\n");
+ dev_priv->display.update_wm = NULL;
+ }
+ dev_priv->display.init_clock_gating = gen6_init_clock_gating;
+ } else if (IS_IVYBRIDGE(dev)) {
+ /* FIXME: detect B0+ stepping and use auto training */
+ if (SNB_READ_WM0_LATENCY()) {
+ dev_priv->display.update_wm = sandybridge_update_wm;
+ dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
+ } else {
+ DRM_DEBUG_KMS("Failed to read display plane latency. "
+ "Disable CxSR\n");
+ dev_priv->display.update_wm = NULL;
+ }
+ dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
+ } else
+ dev_priv->display.update_wm = NULL;
+ } else if (IS_VALLEYVIEW(dev)) {
+ dev_priv->display.update_wm = valleyview_update_wm;
+ dev_priv->display.init_clock_gating =
+ valleyview_init_clock_gating;
+ dev_priv->display.force_wake_get = vlv_force_wake_get;
+ dev_priv->display.force_wake_put = vlv_force_wake_put;
+ } else if (IS_PINEVIEW(dev)) {
+ if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
+ dev_priv->is_ddr3,
+ dev_priv->fsb_freq,
+ dev_priv->mem_freq)) {
+ DRM_INFO("failed to find known CxSR latency "
+ "(found ddr%s fsb freq %d, mem freq %d), "
+ "disabling CxSR\n",
+ (dev_priv->is_ddr3 == 1) ? "3" : "2",
+ dev_priv->fsb_freq, dev_priv->mem_freq);
+ /* Disable CxSR and never update its watermark again */
+ pineview_disable_cxsr(dev);
+ dev_priv->display.update_wm = NULL;
+ } else
+ dev_priv->display.update_wm = pineview_update_wm;
+ dev_priv->display.init_clock_gating = gen3_init_clock_gating;
+ } else if (IS_G4X(dev)) {
+ dev_priv->display.update_wm = g4x_update_wm;
+ dev_priv->display.init_clock_gating = g4x_init_clock_gating;
+ } else if (IS_GEN4(dev)) {
+ dev_priv->display.update_wm = i965_update_wm;
+ if (IS_CRESTLINE(dev))
+ dev_priv->display.init_clock_gating = crestline_init_clock_gating;
+ else if (IS_BROADWATER(dev))
+ dev_priv->display.init_clock_gating = broadwater_init_clock_gating;
+ } else if (IS_GEN3(dev)) {
+ dev_priv->display.update_wm = i9xx_update_wm;
+ dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
+ dev_priv->display.init_clock_gating = gen3_init_clock_gating;
+ } else if (IS_I865G(dev)) {
+ dev_priv->display.update_wm = i830_update_wm;
+ dev_priv->display.init_clock_gating = i85x_init_clock_gating;
+ dev_priv->display.get_fifo_size = i830_get_fifo_size;
+ } else if (IS_I85X(dev)) {
+ dev_priv->display.update_wm = i9xx_update_wm;
+ dev_priv->display.get_fifo_size = i85x_get_fifo_size;
+ dev_priv->display.init_clock_gating = i85x_init_clock_gating;
+ } else {
+ dev_priv->display.update_wm = i830_update_wm;
+ dev_priv->display.init_clock_gating = i830_init_clock_gating;
+ if (IS_845G(dev))
+ dev_priv->display.get_fifo_size = i845_get_fifo_size;
+ else
+ dev_priv->display.get_fifo_size = i830_get_fifo_size;
+ }
+}
+
--
1.7.10
^ permalink raw reply related [flat|nested] 7+ messages in thread