All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jesse Barnes <jbarnes@virtuousgeek.org>
To: intel-gfx@lists.freedesktop.org
Subject: [PATCH] drm/i915: render p-state support for Sandybridge
Date: Thu, 9 Dec 2010 15:00:46 -0800	[thread overview]
Message-ID: <20101209150046.23bef984@jbarnes-desktop> (raw)

Note: this patch is just for comments/testing, it should not be
integrated at this time.

This seems to be enough to initialize render p-state support and get
up/down interrupts (though I've only confirmed down interrupts so
far).  There's code in there for requesting a frequency change, but it
seems to be ignored (at least according to GT_PERF_STATUS; the debugfs
file never indicates that a frequency change has occurred).

Still working with the hw guys on resolving that, but I thought I'd
post this for reference so that others with Sandybridge systems could
try it out and report their results.

Thanks,
-- 
Jesse Barnes, Intel Open Source Technology Center

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 1f4f3ce..f25e960 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -658,15 +658,42 @@ 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;
-	u16 rgvswctl = I915_READ16(MEMSWCTL);
-	u16 rgvstat = I915_READ16(MEMSTAT_ILK);
-
-	seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf);
-	seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f);
-	seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >>
-		   MEMSTAT_VID_SHIFT);
-	seq_printf(m, "Current P-state: %d\n",
-		   (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
+
+	if (IS_GEN5(dev)) {
+		u16 rgvswctl = I915_READ16(MEMSWCTL);
+		u16 rgvstat = I915_READ16(MEMSTAT_ILK);
+
+		seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf);
+		seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f);
+		seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >>
+			   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(0x145948);
+		u32 rp_state_limits = I915_READ(0x145994);
+		u32 rp_state_cap = I915_READ(0x145998);
+		int max_freq;
+
+		seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
+		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, "Max RPN frequency: %dMHz\n", max_freq * 100);
+
+		max_freq = (rp_state_cap & 0xff00) >> 8;
+		seq_printf(m, "Max RP1 frequency: %dMHz\n", max_freq * 100);
+
+		max_freq = rp_state_cap & 0xff;
+		seq_printf(m, "Max RP0 frequency: %dMHz\n", max_freq * 100);
+	} else {
+		seq_printf(m, "no P-state info available\n");
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 80745f8..d0eeaae 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -509,6 +509,7 @@ i915_pci_remove(struct pci_dev *pdev)
 	struct drm_device *dev = pci_get_drvdata(pdev);
 
 	drm_put_dev(dev);
+	pci_disable_device(pdev);
 }
 
 static int i915_pm_suspend(struct device *dev)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 90414ae..6c5a1c4 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -186,6 +186,7 @@ struct drm_i915_display_funcs {
 	void (*update_wm)(struct drm_device *dev, int planea_clock,
 			  int planeb_clock, int sr_hdisplay, int sr_htotal,
 			  int pixel_size);
+	void (*handle_rps_change)(struct drm_device *dev);
 	/* clock updates for mode set */
 	/* cursor updates */
 	/* render clock increase/decrease */
@@ -1161,6 +1162,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 sandybridge_set_drps(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);
 
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 62aa93a..9d828ef 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -306,6 +306,38 @@ static void notify_ring(struct drm_device *dev,
 		  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 }
 
+static void sandybridge_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(PMIIR);
+	if (!pm_iir)
+		return;
+
+	DRM_ERROR("received PM interrupt: 0x%08x\n", pm_iir);
+	DRM_ERROR("  ISR: 0x%08x, IMR: 0x%08x, IER: 0x%08x\n",
+		  I915_READ(PMISR), I915_READ(PMIMR), I915_READ(PMIER));
+
+	if (pm_iir & PM_RP_UP) {
+		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 & PM_RP_DOWN) {
+		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;
+	}
+
+	sandybridge_set_drps(dev, new_delay);
+	dev_priv->cur_delay = new_delay;
+
+	I915_WRITE(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;
@@ -379,6 +411,9 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
 		i915_handle_rps_change(dev);
 	}
 
+	if (IS_GEN6(dev))
+		sandybridge_pm_irq_handler(dev);
+
 	/* should clear PCH hotplug event before clear CPU irq */
 	I915_WRITE(SDEIIR, pch_iir);
 	I915_WRITE(GTIIR, gt_iir);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 8415950..6bc0c21 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -888,6 +888,48 @@
 #define PALETTE_A		0x0a000
 #define PALETTE_B		0x0a800
 
+/*
+ * Sandybridge PM regs
+ */
+#define RPNSWREQ		0x0a008
+#define RPVSWREQ		0x0a00c
+#define RPDNTIMOUT		0x0a010 /* in usec */
+#define RPINTLIM		0x0a014
+#define RPSTAT1			0x0a01c
+#define RPMODECTL1		0x0a024
+#define RPINCLIMIT		0x0a02c
+#define RPDECLIMIT		0x0a030
+#define RPCURUPEI		0x0a050
+#define RPCURUP			0x0a054
+#define RPPREVUP		0x0a058
+#define RPCURDNEI		0x0a05c
+#define RPCURDN			0x0a060
+#define RPPREVDN		0x0a064
+#define RPUPEI			0x0a068
+#define RPDNEI			0x0a06c
+#define GPMPIHYST		0x0a070
+#define RPDEUCSW		0x0a088
+#define RCCTL1			0x0a090
+#define RCCTL2			0x0a094
+#define RC1WRL			0x0a098
+#define RCxWRL			0x0a09c
+#define RCDPSTRC6WRL		0x0a0a0
+#define RCWC			0x0a0a4
+#define RCI			0x0a0a8
+#define RCIHYST			0x0a0ac
+#define RCUBMABDTMR		0x0a0b0
+#define RC1TIMER		0x0a0b4
+#define RC6TIMER		0x0a0b8
+#define RCDEEPRC6TIMER		0x0a0bc
+#define RCDEEPESTRC6TIMER	0x0a0c0
+#define PMINTRMSK		0x0a168
+#define  PMINTR_TOINTRMSK	(1<<6)
+#define  PMINTR_UPINTRMSK	(1<<5)
+#define  PMINTR_DOWNINTRMSK	(1<<4)
+#define  PMINTR_TEMPMSK		(1<<3)
+#define  PMINTR_EIUPINTRMSK	(1<<2)
+#define  PMINTR_EIDNINTRMSK	(1<<1)
+
 /* MCH MMIO space */
 
 /*
@@ -2433,6 +2475,14 @@
 # define VGA_2X_MODE				(1 << 30)
 # define VGA_PIPE_B_SELECT			(1 << 29)
 
+/* Sandybridge PM */
+#define PMISR		0x44020
+#define PMIMR		0x44024
+#define   PM_RP_UP	(1<<5)
+#define   PM_RP_DOWN	(1<<4)
+#define PMIIR		0x44028
+#define PMIER		0x4402c
+
 /* Ironlake */
 
 #define CPU_VGACNTRL	0x41000
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 454c064..39641fd 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -771,8 +771,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))
+		sandybridge_disable_drps(dev);
 
 	/* Cache mode state */
 	dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
@@ -862,11 +864,14 @@ int i915_restore_state(struct drm_device *dev)
 	/* Clock gating state */
 	intel_init_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))
+		sandybridge_enable_drps(dev);
+
 	/* Cache mode state */
 	I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 48d8fd6..0a6750a 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5654,6 +5654,92 @@ void ironlake_disable_drps(struct drm_device *dev)
 
 }
 
+void sandybridge_set_drps(struct drm_device *dev, u8 val)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 swreq;
+
+	DRM_ERROR("setting render p-state to %d\n", val);
+
+	swreq = (val & 0x3ff) << 25;
+	I915_WRITE(0xa18c, 1); /* force wake */
+	wait_for_atomic((I915_READ(0x130090) & 1) == 1, 100); /* wait for wake */
+	I915_WRITE(0xa008, swreq);
+	I915_WRITE(0xa18c, 0); /* clear force wake */
+	wait_for_atomic((I915_READ(0x130090) & 1) == 0, 100); /* wait for sleep */
+
+	DRM_ERROR("RPNSWREQ: 0x%08x\n", I915_READ(0xa008));
+}
+
+void sandybridge_enable_drps(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 gt_perf_status = I915_READ(0x145948);
+	u32 rp_state_cap = I915_READ(0x145998);
+	u64 perf_ctl;
+
+	rdmsrl(0x199, perf_ctl);
+	DRM_ERROR("IA32_PERF_CTL: 0x%016llx\n", (unsigned long long)perf_ctl);
+	DRM_ERROR("RPNSWREQ: 0x%08x\n", I915_READ(0xa008));
+
+	I915_WRITE(0xa094, 0); /* set rc0 */
+	I915_WRITE(0xa18c, 1); /* force wake */
+	wait_for((I915_READ(0x130090) & 1) == 1, 100); /* wait for wake */
+	I915_WRITE(0xa090, 0); /* disable hw rc */
+	I915_WRITE(0xa098, 0x3e80000); /* rc1e wake rate limit */
+	I915_WRITE(0xa09c, 0x28001e); /* rc6/6p wake rate limit */
+	I915_WRITE(0xa0a0, 0x1e); /* rc6pp wake rate limit */
+	I915_WRITE(0xa0ac, 0x64); /* idle hysteresis */
+	I915_WRITE(0x2054, 0xa); /* render idle max count */
+	I915_WRITE(0x12054, 0xa); /* video idle max count */
+	I915_WRITE(0x22054, 0xa); /* blitter idle max count */
+	I915_WRITE(0xa0b0, 0); /* unblock ack to busy */
+	I915_WRITE(0xa0b4, 0x3e8); /* rc1e threshold 1ms/EI */
+	I915_WRITE(0xa0b8, 0xc350); /* rc6 threshold 40% */
+	I915_WRITE(0xa0bc, 0x186a0); /* rc6p threshold */
+	I915_WRITE(0xa0c0, 0xfa00); /* rc6pp threshold */
+	I915_WRITE(0xa090, 0x88040000); /* enable rc etc */
+	I915_WRITE(0xa008, 0x14000000); /* enable turbo, request 1GHz .. */
+	I915_WRITE(0xa00c, 0x18000000); /* 1.2GHz video freq */
+	I915_WRITE(0xa010, 0xf4240); /* rp down timeout 1s */
+	I915_WRITE(0xa014, 0x12060000); /* interrupt limits */
+	I915_WRITE(0xa02c, 0x15f90); /* rp up threshold */
+	I915_WRITE(0xa030, 0x186a0); /* rp down threshold */
+	I915_WRITE(0xa068, 0x186a0); /* rp up ei 100ms */
+	I915_WRITE(0xa06c, 0x493e0); /* rp down ei 300ms */
+	I915_WRITE(0xa070, 0xa); /* idle hysteresis 0us */
+	I915_WRITE(0xa024, 0xb92); /* rp control */
+	wait_for((I915_READ(0x138124) & 0x80000000) == 0, 100);
+	I915_WRITE(0x138128, 0);
+	I915_WRITE(0x138124, 0x80000004);
+	wait_for((I915_READ(0x138124) & 0x80000000) == 0, 100);
+	I915_WRITE(0x4402c, 0x3000076); /* enable PM interrupts */
+	I915_WRITE(0xa18c, 0); /* clear force wake */
+	wait_for((I915_READ(0x130090) & 1) == 0, 100); /* wait for sleep */
+
+	dev_priv->max_delay = rp_state_cap & 0xff;
+	dev_priv->min_delay = 0;
+	dev_priv->cur_delay = (gt_perf_status & 0xff00) >> 8;
+
+	DRM_ERROR("DRPS initialized, max freq %dMHz, current %dMHz\n",
+		  dev_priv->max_delay * 100, dev_priv->cur_delay * 100);
+
+	/* Enable the interrupts */
+	I915_WRITE(PMIER, ~0);
+	I915_WRITE(PMIMR, 0);
+	I915_WRITE(PMINTRMSK, 0);
+//	I915_WRITE(PMINTRMSK, PMINTR_TOINTRMSK | PMINTR_UPINTRMSK |
+//		   PMINTR_DOWNINTRMSK | PMINTR_TEMPMSK | PMINTR_EIUPINTRMSK |
+//		   PMINTR_EIDNINTRMSK);
+}
+
+void sandybridge_disable_drps(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	I915_WRITE(0xa008, 1 << 31);
+}
+
 static unsigned long intel_pxfreq(u32 vidfreq)
 {
 	unsigned long freq;
@@ -6137,6 +6223,9 @@ void intel_modeset_init(struct drm_device *dev)
 		intel_init_emon(dev);
 	}
 
+	if (IS_GEN6(dev))
+		sandybridge_enable_drps(dev);
+
 	INIT_WORK(&dev_priv->idle_work, intel_idle_update);
 	setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
 		    (unsigned long)dev);
@@ -6190,6 +6279,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
 	if (IS_IRONLAKE_M(dev))
 		ironlake_disable_drps(dev);
+	if (IS_GEN6(dev))
+		sandybridge_disable_drps(dev);
 
 	mutex_unlock(&dev->struct_mutex);
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 21551fe..c7d86cb 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -296,6 +296,8 @@ extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
 extern void intel_init_clock_gating(struct drm_device *dev);
 extern void ironlake_enable_drps(struct drm_device *dev);
 extern void ironlake_disable_drps(struct drm_device *dev);
+extern void sandybridge_enable_drps(struct drm_device *dev);
+extern void sandybridge_disable_drps(struct drm_device *dev);
 extern void intel_init_emon(struct drm_device *dev);
 
 extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,

             reply	other threads:[~2010-12-09 23:00 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-12-09 23:00 Jesse Barnes [this message]
2010-12-10  9:37 ` [PATCH] drm/i915: render p-state support for Sandybridge Chris Wilson
2010-12-10 17:46   ` Jesse Barnes

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20101209150046.23bef984@jbarnes-desktop \
    --to=jbarnes@virtuousgeek.org \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.