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,
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to