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

Commit 8fd26859 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915: Enable RC6 autodownclocking on Sandybridge

parent eb43f4af
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -283,6 +283,7 @@
#define RING_CTL(base)		((base)+0x3c)
#define RING_SYNC_0(base)	((base)+0x40)
#define RING_SYNC_1(base)	((base)+0x44)
#define RING_MAX_IDLE(base)	((base)+0x54)
#define RING_HWS_PGA(base)	((base)+0x80)
#define RING_HWS_PGA_GEN6(base)	((base)+0x2080)
#define RING_ACTHD(base)	((base)+0x74)
@@ -3116,4 +3117,62 @@

#define  FORCEWAKE				0xA18C
#define  FORCEWAKE_ACK				0x130090

#define GEN6_RC_NORMAL_FREQ			0xA008
#define   GEN6_TURBO_DISABLE			(1<<31)
#define   GEN6_FREQUENCY(x)			((x)<<25)
#define   GEN6_OFFSET(x)			((x)<<19)
#define   GEN6_AGGRESSIVE_TURBO			(0<<15)
#define GEN6_RC_VIDEO_FREQ			0xA00C
#define GEN6_RC_CONTROL				0xA090
#define   GEN6_RC_CTL_RC6pp_ENABLE		(1<<16)
#define   GEN6_RC_CTL_RC6p_ENABLE		(1<<17)
#define   GEN6_RC_CTL_RC6_ENABLE		(1<<18)
#define   GEN6_RC_CTL_RC1e_ENABLE		(1<<20)
#define   GEN6_RC_CTL_RC7_ENABLE		(1<<22)
#define   GEN6_RC_CTL_EI_MODE(x)		((x)<<27)
#define   GEN6_RC_CTL_HW_ENABLE			(1<<31)
#define GEN6_RP_DOWN_TIMEOUT			0xA010
#define GEN6_RP_INTERRUPT_LIMITS		0xA014
#define GEN6_RP_CONTROL				0xA024
#define   GEN6_RP_MEDIA_TURBO			(1<<11)
#define   GEN6_RP_USE_NORMAL_FREQ		(1<<9)
#define   GEN6_RP_MEDIA_IS_GFX			(1<<8)
#define   GEN6_RP_ENABLE			(1<<7)
#define   GEN6_RP_UP_BUSY_MAX			(0x2<<3)
#define   GEN6_RP_DOWN_BUSY_MIN			(0x2<<0)
#define GEN6_RP_UP_THRESHOLD			0xA02C
#define GEN6_RP_DOWN_THRESHOLD			0xA030
#define GEN6_RP_UP_EI				0xA068
#define GEN6_RP_DOWN_EI				0xA06C
#define GEN6_RP_IDLE_HYSTERSIS			0xA070
#define GEN6_RC_STATE				0xA094
#define GEN6_RC1_WAKE_RATE_LIMIT		0xA098
#define GEN6_RC6_WAKE_RATE_LIMIT		0xA09C
#define GEN6_RC6pp_WAKE_RATE_LIMIT		0xA0A0
#define GEN6_RC_EVALUATION_INTERVAL		0xA0A8
#define GEN6_RC_IDLE_HYSTERSIS			0xA0AC
#define GEN6_RC_SLEEP				0xA0B0
#define GEN6_RC1e_THRESHOLD			0xA0B4
#define GEN6_RC6_THRESHOLD			0xA0B8
#define GEN6_RC6p_THRESHOLD			0xA0BC
#define GEN6_RC6pp_THRESHOLD			0xA0C0

#define GEN6_PMISR				0x44020
#define GEN6_PMIMR				0x44024
#define GEN6_PMIIR				0x44028
#define GEN6_PMIER				0x4402C
#define  GEN6_PM_MBOX_EVENT			(1<<25)
#define  GEN6_PM_THERMAL_EVENT			(1<<24)
#define  GEN6_PM_RP_DOWN_TIMEOUT		(1<<6)
#define  GEN6_PM_RP_UP_THRESHOLD		(1<<5)
#define  GEN6_PM_RP_DOWN_THRESHOLD		(1<<4)
#define  GEN6_PM_RP_UP_EI_EXPIRED		(1<<2)
#define  GEN6_PM_RP_DOWN_EI_EXPIRED		(1<<1)

#define GEN6_PCODE_MAILBOX			0x138124
#define   GEN6_PCODE_READY			(1<<31)
#define   GEN6_PCODE_WRITE_MIN_FREQ_TABLE	0x9
#define GEN6_PCODE_DATA				0x138128

#endif /* _I915_REG_H_ */
+89 −0
Original line number Diff line number Diff line
@@ -5842,6 +5842,91 @@ void intel_init_emon(struct drm_device *dev)
	dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
}

static void gen6_enable_rc6(struct drm_i915_private *dev_priv)
{
	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);
	__gen6_force_wake_get(dev_priv);

	/* disable the counters and set determistic 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 */

	I915_WRITE(GEN6_RC_CONTROL,
		   GEN6_RC_CTL_RC6p_ENABLE |
		   GEN6_RC_CTL_RC6_ENABLE |
		   GEN6_RC_CTL_HW_ENABLE);

	I915_WRITE(GEN6_RC_NORMAL_FREQ,
		   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, 90000);
	I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 100000);
	I915_WRITE(GEN6_RP_UP_EI, 100000);
	I915_WRITE(GEN6_RP_DOWN_EI, 300000);
	I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
	I915_WRITE(GEN6_RP_CONTROL,
		   GEN6_RP_MEDIA_TURBO |
		   GEN6_RP_USE_NORMAL_FREQ |
		   GEN6_RP_MEDIA_IS_GFX |
		   GEN6_RP_ENABLE |
		   GEN6_RP_UP_BUSY_MAX |
		   GEN6_RP_DOWN_BUSY_MIN);

	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");

	/* 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);

	__gen6_force_wake_put(dev_priv);
}

void intel_enable_clock_gating(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5924,6 +6009,7 @@ void intel_enable_clock_gating(struct drm_device *dev)
				   _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
				   _3D_CHICKEN2_WM_READ_PIPELINED);
		}

	} else if (IS_G4X(dev)) {
		uint32_t dspclk_gate;
		I915_WRITE(RENCLK_GATE_D1, 0);
@@ -5997,6 +6083,9 @@ void intel_enable_clock_gating(struct drm_device *dev)
				   I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT);
		}
	}

	if (IS_GEN6(dev))
		gen6_enable_rc6(dev_priv);
}

void intel_disable_clock_gating(struct drm_device *dev)