Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3b8d8d91 authored by Jesse Barnes's avatar Jesse Barnes Committed by Chris Wilson
Browse files

drm/i915: dynamic render p-state support for Sandy Bridge



Add an interrupt handler for switching graphics frequencies and handling
PM interrupts.  This should allow for increased performance when busy
and lower power consumption when idle.

Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent 9c3d2f7f
Loading
Loading
Loading
Loading
+45 −9
Original line number Diff line number Diff line
@@ -797,6 +797,8 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
	struct drm_info_node *node = (struct drm_info_node *) m->private;
	struct drm_device *dev = node->minor->dev;
	drm_i915_private_t *dev_priv = dev->dev_private;

	if (IS_GEN5(dev)) {
		u16 rgvswctl = I915_READ16(MEMSWCTL);
		u16 rgvstat = I915_READ16(MEMSTAT_ILK);

@@ -806,6 +808,40 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
			   MEMSTAT_VID_SHIFT);
		seq_printf(m, "Current P-state: %d\n",
			   (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
	} else if (IS_GEN6(dev)) {
		u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
		u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
		u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
		int max_freq;

		/* RPSTAT1 is in the GT power well */
		__gen6_force_wake_get(dev_priv);

		seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
		seq_printf(m, "RPSTAT1: 0x%08x\n", I915_READ(GEN6_RPSTAT1));
		seq_printf(m, "Render p-state ratio: %d\n",
			   (gt_perf_status & 0xff00) >> 8);
		seq_printf(m, "Render p-state VID: %d\n",
			   gt_perf_status & 0xff);
		seq_printf(m, "Render p-state limit: %d\n",
			   rp_state_limits & 0xff);

		max_freq = (rp_state_cap & 0xff0000) >> 16;
		seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
			   max_freq * 100);

		max_freq = (rp_state_cap & 0xff00) >> 8;
		seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
			   max_freq * 100);

		max_freq = rp_state_cap & 0xff;
		seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
			   max_freq * 100);

		__gen6_force_wake_put(dev_priv);
	} else {
		seq_printf(m, "no P-state info available\n");
	}

	return 0;
}
+1 −0
Original line number Diff line number Diff line
@@ -1264,6 +1264,7 @@ extern void intel_disable_fbc(struct drm_device *dev);
extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
extern bool intel_fbc_enabled(struct drm_device *dev);
extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
extern void gen6_set_rps(struct drm_device *dev, u8 val);
extern void intel_detect_pch (struct drm_device *dev);
extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);

+45 −2
Original line number Diff line number Diff line
@@ -397,11 +397,49 @@ static void notify_ring(struct drm_device *dev,
		  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
}

static void gen6_pm_irq_handler(struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	u8 new_delay = dev_priv->cur_delay;
	u32 pm_iir;

	pm_iir = I915_READ(GEN6_PMIIR);
	if (!pm_iir)
		return;

	if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
		if (dev_priv->cur_delay != dev_priv->max_delay)
			new_delay = dev_priv->cur_delay + 1;
		if (new_delay > dev_priv->max_delay)
			new_delay = dev_priv->max_delay;
	} else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) {
		if (dev_priv->cur_delay != dev_priv->min_delay)
			new_delay = dev_priv->cur_delay - 1;
		if (new_delay < dev_priv->min_delay) {
			new_delay = dev_priv->min_delay;
			I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
				   I915_READ(GEN6_RP_INTERRUPT_LIMITS) |
				   ((new_delay << 16) & 0x3f0000));
		} else {
			/* Make sure we continue to get down interrupts
			 * until we hit the minimum frequency */
			I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
				   I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000);
		}

	}

	gen6_set_rps(dev, new_delay);
	dev_priv->cur_delay = new_delay;

	I915_WRITE(GEN6_PMIIR, pm_iir);
}

static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	int ret = IRQ_NONE;
	u32 de_iir, gt_iir, de_ier, pch_iir;
	u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
	u32 hotplug_mask;
	struct drm_i915_master_private *master_priv;
	u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
@@ -417,8 +455,10 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
	de_iir = I915_READ(DEIIR);
	gt_iir = I915_READ(GTIIR);
	pch_iir = I915_READ(SDEIIR);
	pm_iir = I915_READ(GEN6_PMIIR);

	if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
	if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 &&
	    (!IS_GEN6(dev) || pm_iir == 0))
		goto done;

	if (HAS_PCH_CPT(dev))
@@ -470,6 +510,9 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
		i915_handle_rps_change(dev);
	}

	if (IS_GEN6(dev))
		gen6_pm_irq_handler(dev);

	/* should clear PCH hotplug event before clear CPU irq */
	I915_WRITE(SDEIIR, pch_iir);
	I915_WRITE(GTIIR, gt_iir);
+7 −1
Original line number Diff line number Diff line
@@ -1188,6 +1188,10 @@
#define DDRMPLL1		0X12c20
#define PEG_BAND_GAP_DATA	0x14d68

#define GEN6_GT_PERF_STATUS	0x145948
#define GEN6_RP_STATE_LIMITS	0x145994
#define GEN6_RP_STATE_CAP	0x145998

/*
 * Logical Context regs
 */
@@ -3169,7 +3173,7 @@
#define  FORCEWAKE				0xA18C
#define  FORCEWAKE_ACK				0x130090

#define GEN6_RC_NORMAL_FREQ			0xA008
#define GEN6_RPNSWREQ				0xA008
#define   GEN6_TURBO_DISABLE			(1<<31)
#define   GEN6_FREQUENCY(x)			((x)<<25)
#define   GEN6_OFFSET(x)			((x)<<19)
@@ -3185,6 +3189,7 @@
#define   GEN6_RC_CTL_HW_ENABLE			(1<<31)
#define GEN6_RP_DOWN_TIMEOUT			0xA010
#define GEN6_RP_INTERRUPT_LIMITS		0xA014
#define GEN6_RPSTAT1				0xA01C
#define GEN6_RP_CONTROL				0xA024
#define   GEN6_RP_MEDIA_TURBO			(1<<11)
#define   GEN6_RP_USE_NORMAL_FREQ		(1<<9)
@@ -3208,6 +3213,7 @@
#define GEN6_RC6_THRESHOLD			0xA0B8
#define GEN6_RC6p_THRESHOLD			0xA0BC
#define GEN6_RC6pp_THRESHOLD			0xA0C0
#define GEN6_PMINTRMSK				0xA168

#define GEN6_PMISR				0x44020
#define GEN6_PMIMR				0x44024
+7 −2
Original line number Diff line number Diff line
@@ -817,8 +817,10 @@ int i915_save_state(struct drm_device *dev)
		dev_priv->saveIMR = I915_READ(IMR);
	}

	if (HAS_PCH_SPLIT(dev))
	if (IS_IRONLAKE_M(dev))
		ironlake_disable_drps(dev);
	if (IS_GEN6(dev))
		gen6_disable_rps(dev);

	intel_disable_clock_gating(dev);

@@ -867,11 +869,14 @@ int i915_restore_state(struct drm_device *dev)
	/* Clock gating state */
	intel_enable_clock_gating(dev);

	if (HAS_PCH_SPLIT(dev)) {
	if (IS_IRONLAKE_M(dev)) {
		ironlake_enable_drps(dev);
		intel_init_emon(dev);
	}

	if (IS_GEN6(dev))
		gen6_enable_rps(dev_priv);

	/* Cache mode state */
	I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);

Loading