[PATCH 16/26] drm/i915: turbo & RC6 support for VLV

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Sat, 2 Mar 2013, Jesse Barnes wrote:

> From: Ben Widawsky <ben at bwidawsk.net>
>
> Uses slightly different interfaces than other platforms.
>
> Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
> ---
> drivers/gpu/drm/i915/intel_pm.c |  148 +++++++++++++++++++++++++++++++++++++--
> 1 file changed, 144 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index e3947cb..d16f4f40 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2477,6 +2477,47 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
> 	trace_intel_gpu_freq_change(val * 50);
> }
>
> +void valleyview_set_rps(struct drm_device *dev, u8 val)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	unsigned long timeout = jiffies + msecs_to_jiffies(100);
> +	u32 limits = gen6_rps_limits(dev_priv, &val);
> +	u32 pval;
> +
> +	WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
> +	WARN_ON(val > dev_priv->rps.max_delay);
> +	WARN_ON(val < dev_priv->rps.min_delay);
> +
> +	if (val == dev_priv->rps.cur_delay)
> +		return;
> +
> +	valleyview_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
> +
> +	do {
> +		valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval);
> +		if (time_after(jiffies, timeout)) {
> +			DRM_DEBUG_DRIVER("timed out waiting for Punit\n");
> +			break;
> +		}
> +		udelay(10);
> +	} while (pval & 1);
> +
> +	valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval);
> +	if ((pval >> 8) != val)
> +		DRM_DEBUG_DRIVER("punit overrode freq: %d requested, but got %d\n",
> +			  val, pval >> 8);
> +
> +	/* Make sure we continue to get interrupts
> +	 * until we hit the minimum or maximum frequencies.
> +	 */
> +	I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits);
> +
> +	dev_priv->rps.cur_delay = val;

Shouldn't we store pval >> 8 instead of val in cur_delay in order to
reclaim the rps state? If we store val here, the requested frequency will
eventually exceed max_delay if punit overrides with a lower frequency.

> +
> +	trace_intel_gpu_freq_change(val * 50);
> +}
> +
> +
> static void gen6_disable_rps(struct drm_device *dev)
> {
> 	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -2714,6 +2755,100 @@ static void gen6_update_ring_freq(struct drm_device *dev)
> 	}
> }
>
> +static void valleyview_enable_rps(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_ring_buffer *ring;
> +	u32 gtfifodbg, val;
> +	int i;
> +
> +	WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
> +
> +	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);
> +
> +	I915_WRITE(GEN6_RC_SLEEP, 0);
> +
> +	I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 0x00280000);
> +	I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
> +	I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 0x19);
> +
> +	for_each_ring(ring, dev_priv, i)
> +		I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
> +
> +	I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
> +	I915_WRITE(GEN6_RC6_THRESHOLD, 0xc350);
> +
> +	I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
> +	I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
> +	I915_WRITE(GEN6_RP_UP_EI, 66000);
> +	I915_WRITE(GEN6_RP_DOWN_EI, 350000);
> +
> +	I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
> +
> +	I915_WRITE(GEN6_RP_CONTROL,
> +		   GEN6_RP_MEDIA_TURBO |
> +		   GEN6_RP_MEDIA_HW_NORMAL_MODE |
> +		   GEN6_RP_MEDIA_IS_GFX |
> +		   GEN6_RP_ENABLE |
> +		   GEN6_RP_UP_BUSY_AVG |
> +		   GEN6_RP_DOWN_IDLE_CONT);
> +
> +	/* allows RC6 residency counter to work */
> +	I915_WRITE(0x138104, 0xffff00ff);
> +	I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE);
> +
> +	valleyview_punit_read(dev_priv, PUNIT_FUSE_BUS1, &val);
> +	DRM_DEBUG_DRIVER("max GPU freq: %d\n", val);
> +	dev_priv->rps.max_delay = val;
> +
> +	valleyview_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val);
> +	DRM_DEBUG_DRIVER("min GPU freq: %d\n", val);
> +	dev_priv->rps.min_delay = val;
> +
> +	valleyview_punit_read(dev_priv, PUNIT_FUSE_BUS2, &val);
> +	DRM_DEBUG_DRIVER("max GPLL freq: %d\n", val);
> +
> +	valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &val);
> +	DRM_DEBUG_DRIVER("DDR speed: ");
> +	if (((val >> 6) & 3) == 0) {
> +		dev_priv->mem_freq = 800;
> +		printk("800 MHz\n");
> +	} else if (((val >> 6) & 3) == 1) {
> +		printk("1066 MHz\n");
> +		dev_priv->mem_freq = 1066;
> +	} else if (((val >> 6) & 3) == 2) {
> +		printk("1333 MHz\n");
> +		dev_priv->mem_freq = 1333;
> +	} else if (((val >> 6) & 3) == 3)
> +		printk("invalid\n");
> +	DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 8 ? "yes" : "no");
> +	DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val);
> +
> +	DRM_DEBUG_DRIVER("current GPU freq: %x\n", (val >> 8) & 0xff);
> +	dev_priv->rps.cur_delay = (val >> 8) & 0xff;
> +
> +	val = 0xd500;
> +	DRM_DEBUG_DRIVER("setting GPU freq to %d\n", (val >> 8) & 0xff);
> +
> +	valleyview_set_rps(dev_priv->dev, (val >> 8) & 0xff);
> +
> +	/* requires MSI enabled */
> +	I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS);
> +	spin_lock_irq(&dev_priv->rps.lock);
> +	WARN_ON(dev_priv->rps.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);
> +}
> +
> void ironlake_teardown_rc6(struct drm_device *dev)
> {
> 	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -3440,7 +3575,7 @@ void intel_disable_gt_powersave(struct drm_device *dev)
> 	if (IS_IRONLAKE_M(dev)) {
> 		ironlake_disable_drps(dev);
> 		ironlake_disable_rc6(dev);
> -	} else if (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) {
> +	} else if (INTEL_INFO(dev)->gen >= 6) {
> 		cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
> 		mutex_lock(&dev_priv->rps.hw_lock);
> 		gen6_disable_rps(dev);
> @@ -3456,8 +3591,13 @@ static void intel_gen6_powersave_work(struct work_struct *work)
> 	struct drm_device *dev = dev_priv->dev;
>
> 	mutex_lock(&dev_priv->rps.hw_lock);
> -	gen6_enable_rps(dev);
> -	gen6_update_ring_freq(dev);
> +
> +	if (IS_VALLEYVIEW(dev)) {
> +		valleyview_enable_rps(dev);
> +	} else {
> +		gen6_enable_rps(dev);
> +		gen6_update_ring_freq(dev);
> +	}
> 	mutex_unlock(&dev_priv->rps.hw_lock);
> }
>
> @@ -3469,7 +3609,7 @@ void intel_enable_gt_powersave(struct drm_device *dev)
> 		ironlake_enable_drps(dev);
> 		ironlake_enable_rc6(dev);
> 		intel_init_emon(dev);
> -	} else if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) {
> +	} else if (IS_GEN6(dev) || IS_GEN7(dev)) {
> 		/*
> 		 * PCU communication is slow and this doesn't need to be
> 		 * done at any specific time, so do this out of our fast path
> -- 
> 1.7.9.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>


[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux