aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2010-12-17 17:19:02 -0500
committerChris Wilson <chris@chris-wilson.co.uk>2010-12-18 06:07:02 -0500
commit3b8d8d91d51c7d15cda51052624169edf7b6dbc6 (patch)
treef4b4f830d3d882f0d1673e21c15932843005a745 /drivers/gpu
parent9c3d2f7ffac34c62fea0b73e607707168a6f09b1 (diff)
drm/i915: dynamic render p-state support for Sandy Bridge
Add an interrupt handler for switching graphics frequencies and handling PM interrupts. This should allow for increased performance when busy and lower power consumption when idle. Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c54
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h1
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c47
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h8
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c9
-rw-r--r--drivers/gpu/drm/i915/intel_display.c36
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
7 files changed, 137 insertions, 20 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 864e75d762e6..92f75782c332 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -797,15 +797,51 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
797 struct drm_info_node *node = (struct drm_info_node *) m->private; 797 struct drm_info_node *node = (struct drm_info_node *) m->private;
798 struct drm_device *dev = node->minor->dev; 798 struct drm_device *dev = node->minor->dev;
799 drm_i915_private_t *dev_priv = dev->dev_private; 799 drm_i915_private_t *dev_priv = dev->dev_private;
800 u16 rgvswctl = I915_READ16(MEMSWCTL); 800
801 u16 rgvstat = I915_READ16(MEMSTAT_ILK); 801 if (IS_GEN5(dev)) {
802 802 u16 rgvswctl = I915_READ16(MEMSWCTL);
803 seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); 803 u16 rgvstat = I915_READ16(MEMSTAT_ILK);
804 seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f); 804
805 seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> 805 seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf);
806 MEMSTAT_VID_SHIFT); 806 seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f);
807 seq_printf(m, "Current P-state: %d\n", 807 seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >>
808 (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); 808 MEMSTAT_VID_SHIFT);
809 seq_printf(m, "Current P-state: %d\n",
810 (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
811 } else if (IS_GEN6(dev)) {
812 u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
813 u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
814 u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
815 int max_freq;
816
817 /* RPSTAT1 is in the GT power well */
818 __gen6_force_wake_get(dev_priv);
819
820 seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
821 seq_printf(m, "RPSTAT1: 0x%08x\n", I915_READ(GEN6_RPSTAT1));
822 seq_printf(m, "Render p-state ratio: %d\n",
823 (gt_perf_status & 0xff00) >> 8);
824 seq_printf(m, "Render p-state VID: %d\n",
825 gt_perf_status & 0xff);
826 seq_printf(m, "Render p-state limit: %d\n",
827 rp_state_limits & 0xff);
828
829 max_freq = (rp_state_cap & 0xff0000) >> 16;
830 seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
831 max_freq * 100);
832
833 max_freq = (rp_state_cap & 0xff00) >> 8;
834 seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
835 max_freq * 100);
836
837 max_freq = rp_state_cap & 0xff;
838 seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
839 max_freq * 100);
840
841 __gen6_force_wake_put(dev_priv);
842 } else {
843 seq_printf(m, "no P-state info available\n");
844 }
809 845
810 return 0; 846 return 0;
811} 847}
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 53dfc8398a96..2a653cc80395 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1264,6 +1264,7 @@ extern void intel_disable_fbc(struct drm_device *dev);
1264extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); 1264extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
1265extern bool intel_fbc_enabled(struct drm_device *dev); 1265extern bool intel_fbc_enabled(struct drm_device *dev);
1266extern bool ironlake_set_drps(struct drm_device *dev, u8 val); 1266extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
1267extern void gen6_set_rps(struct drm_device *dev, u8 val);
1267extern void intel_detect_pch (struct drm_device *dev); 1268extern void intel_detect_pch (struct drm_device *dev);
1268extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); 1269extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
1269 1270
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index adf983f01dda..0dadc025b77b 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -397,11 +397,49 @@ static void notify_ring(struct drm_device *dev,
397 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); 397 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
398} 398}
399 399
400static void gen6_pm_irq_handler(struct drm_device *dev)
401{
402 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
403 u8 new_delay = dev_priv->cur_delay;
404 u32 pm_iir;
405
406 pm_iir = I915_READ(GEN6_PMIIR);
407 if (!pm_iir)
408 return;
409
410 if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
411 if (dev_priv->cur_delay != dev_priv->max_delay)
412 new_delay = dev_priv->cur_delay + 1;
413 if (new_delay > dev_priv->max_delay)
414 new_delay = dev_priv->max_delay;
415 } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) {
416 if (dev_priv->cur_delay != dev_priv->min_delay)
417 new_delay = dev_priv->cur_delay - 1;
418 if (new_delay < dev_priv->min_delay) {
419 new_delay = dev_priv->min_delay;
420 I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
421 I915_READ(GEN6_RP_INTERRUPT_LIMITS) |
422 ((new_delay << 16) & 0x3f0000));
423 } else {
424 /* Make sure we continue to get down interrupts
425 * until we hit the minimum frequency */
426 I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
427 I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000);
428 }
429
430 }
431
432 gen6_set_rps(dev, new_delay);
433 dev_priv->cur_delay = new_delay;
434
435 I915_WRITE(GEN6_PMIIR, pm_iir);
436}
437
400static irqreturn_t ironlake_irq_handler(struct drm_device *dev) 438static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
401{ 439{
402 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 440 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
403 int ret = IRQ_NONE; 441 int ret = IRQ_NONE;
404 u32 de_iir, gt_iir, de_ier, pch_iir; 442 u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
405 u32 hotplug_mask; 443 u32 hotplug_mask;
406 struct drm_i915_master_private *master_priv; 444 struct drm_i915_master_private *master_priv;
407 u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT; 445 u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
@@ -417,8 +455,10 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
417 de_iir = I915_READ(DEIIR); 455 de_iir = I915_READ(DEIIR);
418 gt_iir = I915_READ(GTIIR); 456 gt_iir = I915_READ(GTIIR);
419 pch_iir = I915_READ(SDEIIR); 457 pch_iir = I915_READ(SDEIIR);
458 pm_iir = I915_READ(GEN6_PMIIR);
420 459
421 if (de_iir == 0 && gt_iir == 0 && pch_iir == 0) 460 if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 &&
461 (!IS_GEN6(dev) || pm_iir == 0))
422 goto done; 462 goto done;
423 463
424 if (HAS_PCH_CPT(dev)) 464 if (HAS_PCH_CPT(dev))
@@ -470,6 +510,9 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
470 i915_handle_rps_change(dev); 510 i915_handle_rps_change(dev);
471 } 511 }
472 512
513 if (IS_GEN6(dev))
514 gen6_pm_irq_handler(dev);
515
473 /* should clear PCH hotplug event before clear CPU irq */ 516 /* should clear PCH hotplug event before clear CPU irq */
474 I915_WRITE(SDEIIR, pch_iir); 517 I915_WRITE(SDEIIR, pch_iir);
475 I915_WRITE(GTIIR, gt_iir); 518 I915_WRITE(GTIIR, gt_iir);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index c2231f7d2d97..d60860ec8cf4 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1188,6 +1188,10 @@
1188#define DDRMPLL1 0X12c20 1188#define DDRMPLL1 0X12c20
1189#define PEG_BAND_GAP_DATA 0x14d68 1189#define PEG_BAND_GAP_DATA 0x14d68
1190 1190
1191#define GEN6_GT_PERF_STATUS 0x145948
1192#define GEN6_RP_STATE_LIMITS 0x145994
1193#define GEN6_RP_STATE_CAP 0x145998
1194
1191/* 1195/*
1192 * Logical Context regs 1196 * Logical Context regs
1193 */ 1197 */
@@ -3169,7 +3173,7 @@
3169#define FORCEWAKE 0xA18C 3173#define FORCEWAKE 0xA18C
3170#define FORCEWAKE_ACK 0x130090 3174#define FORCEWAKE_ACK 0x130090
3171 3175
3172#define GEN6_RC_NORMAL_FREQ 0xA008 3176#define GEN6_RPNSWREQ 0xA008
3173#define GEN6_TURBO_DISABLE (1<<31) 3177#define GEN6_TURBO_DISABLE (1<<31)
3174#define GEN6_FREQUENCY(x) ((x)<<25) 3178#define GEN6_FREQUENCY(x) ((x)<<25)
3175#define GEN6_OFFSET(x) ((x)<<19) 3179#define GEN6_OFFSET(x) ((x)<<19)
@@ -3185,6 +3189,7 @@
3185#define GEN6_RC_CTL_HW_ENABLE (1<<31) 3189#define GEN6_RC_CTL_HW_ENABLE (1<<31)
3186#define GEN6_RP_DOWN_TIMEOUT 0xA010 3190#define GEN6_RP_DOWN_TIMEOUT 0xA010
3187#define GEN6_RP_INTERRUPT_LIMITS 0xA014 3191#define GEN6_RP_INTERRUPT_LIMITS 0xA014
3192#define GEN6_RPSTAT1 0xA01C
3188#define GEN6_RP_CONTROL 0xA024 3193#define GEN6_RP_CONTROL 0xA024
3189#define GEN6_RP_MEDIA_TURBO (1<<11) 3194#define GEN6_RP_MEDIA_TURBO (1<<11)
3190#define GEN6_RP_USE_NORMAL_FREQ (1<<9) 3195#define GEN6_RP_USE_NORMAL_FREQ (1<<9)
@@ -3208,6 +3213,7 @@
3208#define GEN6_RC6_THRESHOLD 0xA0B8 3213#define GEN6_RC6_THRESHOLD 0xA0B8
3209#define GEN6_RC6p_THRESHOLD 0xA0BC 3214#define GEN6_RC6p_THRESHOLD 0xA0BC
3210#define GEN6_RC6pp_THRESHOLD 0xA0C0 3215#define GEN6_RC6pp_THRESHOLD 0xA0C0
3216#define GEN6_PMINTRMSK 0xA168
3211 3217
3212#define GEN6_PMISR 0x44020 3218#define GEN6_PMISR 0x44020
3213#define GEN6_PMIMR 0x44024 3219#define GEN6_PMIMR 0x44024
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index a311809f3c80..f623efdb1151 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -817,8 +817,10 @@ int i915_save_state(struct drm_device *dev)
817 dev_priv->saveIMR = I915_READ(IMR); 817 dev_priv->saveIMR = I915_READ(IMR);
818 } 818 }
819 819
820 if (HAS_PCH_SPLIT(dev)) 820 if (IS_IRONLAKE_M(dev))
821 ironlake_disable_drps(dev); 821 ironlake_disable_drps(dev);
822 if (IS_GEN6(dev))
823 gen6_disable_rps(dev);
822 824
823 intel_disable_clock_gating(dev); 825 intel_disable_clock_gating(dev);
824 826
@@ -867,11 +869,14 @@ int i915_restore_state(struct drm_device *dev)
867 /* Clock gating state */ 869 /* Clock gating state */
868 intel_enable_clock_gating(dev); 870 intel_enable_clock_gating(dev);
869 871
870 if (HAS_PCH_SPLIT(dev)) { 872 if (IS_IRONLAKE_M(dev)) {
871 ironlake_enable_drps(dev); 873 ironlake_enable_drps(dev);
872 intel_init_emon(dev); 874 intel_init_emon(dev);
873 } 875 }
874 876
877 if (IS_GEN6(dev))
878 gen6_enable_rps(dev_priv);
879
875 /* Cache mode state */ 880 /* Cache mode state */
876 I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); 881 I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
877 882
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index c79bee4b4d56..880659680d0a 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6021,6 +6021,25 @@ void ironlake_disable_drps(struct drm_device *dev)
6021 6021
6022} 6022}
6023 6023
6024void gen6_set_rps(struct drm_device *dev, u8 val)
6025{
6026 struct drm_i915_private *dev_priv = dev->dev_private;
6027 u32 swreq;
6028
6029 swreq = (val & 0x3ff) << 25;
6030 I915_WRITE(GEN6_RPNSWREQ, swreq);
6031}
6032
6033void gen6_disable_rps(struct drm_device *dev)
6034{
6035 struct drm_i915_private *dev_priv = dev->dev_private;
6036
6037 I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
6038 I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
6039 I915_WRITE(GEN6_PMIER, 0);
6040 I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
6041}
6042
6024static unsigned long intel_pxfreq(u32 vidfreq) 6043static unsigned long intel_pxfreq(u32 vidfreq)
6025{ 6044{
6026 unsigned long freq; 6045 unsigned long freq;
@@ -6107,7 +6126,7 @@ void intel_init_emon(struct drm_device *dev)
6107 dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); 6126 dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
6108} 6127}
6109 6128
6110static void gen6_enable_rc6(struct drm_i915_private *dev_priv) 6129void gen6_enable_rps(struct drm_i915_private *dev_priv)
6111{ 6130{
6112 int i; 6131 int i;
6113 6132
@@ -6120,7 +6139,7 @@ static void gen6_enable_rc6(struct drm_i915_private *dev_priv)
6120 I915_WRITE(GEN6_RC_STATE, 0); 6139 I915_WRITE(GEN6_RC_STATE, 0);
6121 __gen6_force_wake_get(dev_priv); 6140 __gen6_force_wake_get(dev_priv);
6122 6141
6123 /* disable the counters and set determistic thresholds */ 6142 /* disable the counters and set deterministic thresholds */
6124 I915_WRITE(GEN6_RC_CONTROL, 0); 6143 I915_WRITE(GEN6_RC_CONTROL, 0);
6125 6144
6126 I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16); 6145 I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16);
@@ -6144,7 +6163,7 @@ static void gen6_enable_rc6(struct drm_i915_private *dev_priv)
6144 GEN6_RC_CTL_EI_MODE(1) | 6163 GEN6_RC_CTL_EI_MODE(1) |
6145 GEN6_RC_CTL_HW_ENABLE); 6164 GEN6_RC_CTL_HW_ENABLE);
6146 6165
6147 I915_WRITE(GEN6_RC_NORMAL_FREQ, 6166 I915_WRITE(GEN6_RPNSWREQ,
6148 GEN6_FREQUENCY(10) | 6167 GEN6_FREQUENCY(10) |
6149 GEN6_OFFSET(0) | 6168 GEN6_OFFSET(0) |
6150 GEN6_AGGRESSIVE_TURBO); 6169 GEN6_AGGRESSIVE_TURBO);
@@ -6189,6 +6208,9 @@ static void gen6_enable_rc6(struct drm_i915_private *dev_priv)
6189 GEN6_PM_RP_DOWN_THRESHOLD | 6208 GEN6_PM_RP_DOWN_THRESHOLD |
6190 GEN6_PM_RP_UP_EI_EXPIRED | 6209 GEN6_PM_RP_UP_EI_EXPIRED |
6191 GEN6_PM_RP_DOWN_EI_EXPIRED); 6210 GEN6_PM_RP_DOWN_EI_EXPIRED);
6211 I915_WRITE(GEN6_PMIMR, 0);
6212 /* enable all PM interrupts */
6213 I915_WRITE(GEN6_PMINTRMSK, 0);
6192 6214
6193 __gen6_force_wake_put(dev_priv); 6215 __gen6_force_wake_put(dev_priv);
6194} 6216}
@@ -6381,9 +6403,6 @@ void intel_enable_clock_gating(struct drm_device *dev)
6381 I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT); 6403 I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT);
6382 } 6404 }
6383 } 6405 }
6384
6385 if (IS_GEN6(dev))
6386 gen6_enable_rc6(dev_priv);
6387} 6406}
6388 6407
6389void intel_disable_clock_gating(struct drm_device *dev) 6408void intel_disable_clock_gating(struct drm_device *dev)
@@ -6657,6 +6676,9 @@ void intel_modeset_init(struct drm_device *dev)
6657 intel_init_emon(dev); 6676 intel_init_emon(dev);
6658 } 6677 }
6659 6678
6679 if (IS_GEN6(dev))
6680 gen6_enable_rps(dev_priv);
6681
6660 INIT_WORK(&dev_priv->idle_work, intel_idle_update); 6682 INIT_WORK(&dev_priv->idle_work, intel_idle_update);
6661 setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, 6683 setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
6662 (unsigned long)dev); 6684 (unsigned long)dev);
@@ -6690,6 +6712,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
6690 6712
6691 if (IS_IRONLAKE_M(dev)) 6713 if (IS_IRONLAKE_M(dev))
6692 ironlake_disable_drps(dev); 6714 ironlake_disable_drps(dev);
6715 if (IS_GEN6(dev))
6716 gen6_disable_rps(dev);
6693 6717
6694 intel_disable_clock_gating(dev); 6718 intel_disable_clock_gating(dev);
6695 6719
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index acdea6549ec4..d782ad9fd6db 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -298,6 +298,8 @@ extern void intel_enable_clock_gating(struct drm_device *dev);
298extern void intel_disable_clock_gating(struct drm_device *dev); 298extern void intel_disable_clock_gating(struct drm_device *dev);
299extern void ironlake_enable_drps(struct drm_device *dev); 299extern void ironlake_enable_drps(struct drm_device *dev);
300extern void ironlake_disable_drps(struct drm_device *dev); 300extern void ironlake_disable_drps(struct drm_device *dev);
301extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
302extern void gen6_disable_rps(struct drm_device *dev);
301extern void intel_init_emon(struct drm_device *dev); 303extern void intel_init_emon(struct drm_device *dev);
302 304
303extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, 305extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,