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,
next 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.