@@ -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;
}
@@ -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)
@@ -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);
@@ -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);
@@ -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
@@ -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);
@@ -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);
@@ -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,