aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2010-01-29 14:27:07 -0500
committerEric Anholt <eric@anholt.net>2010-02-22 11:46:54 -0500
commitf97108d1d0facc7902134ebc453b226bbd4d1cdb (patch)
tree563d14cb7c65b80e16df9246da25cade22f22fdd /drivers/gpu/drm
parentee980b8003a25fbfed50c3367f2b426c870eaf90 (diff)
drm/i915: add dynamic performance control support for Ironlake
Ironlake (and 965GM, which this patch doesn't support) supports a hardware performance and power management feature that allows it to adjust to changes in GPU load over time with software help. The goal if this is to maximize performance/power for a given workload. This patch enables that feature, which is also a requirement for supporting Intelligent Power Sharing, a feature which allows for dynamic budgeting of power between the CPU and GPU in Arrandale platforms. Tested-by: ykzhao <yakui.zhao@intel.com> [anholt: Resolved against the irq handler loop removal] Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c96
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c5
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h6
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c63
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h141
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c8
-rw-r--r--drivers/gpu/drm/i915/intel_display.c100
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
8 files changed, 411 insertions, 10 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index a894ade03093..55340de618ea 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -386,6 +386,97 @@ out:
386 return 0; 386 return 0;
387} 387}
388 388
389static int i915_rstdby_delays(struct seq_file *m, void *unused)
390{
391 struct drm_info_node *node = (struct drm_info_node *) m->private;
392 struct drm_device *dev = node->minor->dev;
393 drm_i915_private_t *dev_priv = dev->dev_private;
394 u16 crstanddelay = I915_READ16(CRSTANDVID);
395
396 seq_printf(m, "w/ctx: %d, w/o ctx: %d\n", (crstanddelay >> 8) & 0x3f, (crstanddelay & 0x3f));
397
398 return 0;
399}
400
401static int i915_cur_delayinfo(struct seq_file *m, void *unused)
402{
403 struct drm_info_node *node = (struct drm_info_node *) m->private;
404 struct drm_device *dev = node->minor->dev;
405 drm_i915_private_t *dev_priv = dev->dev_private;
406 u16 rgvswctl = I915_READ16(MEMSWCTL);
407
408 seq_printf(m, "Last command: 0x%01x\n", (rgvswctl >> 13) & 0x3);
409 seq_printf(m, "Command status: %d\n", (rgvswctl >> 12) & 1);
410 seq_printf(m, "P%d DELAY 0x%02x\n", (rgvswctl >> 8) & 0xf,
411 rgvswctl & 0x3f);
412
413 return 0;
414}
415
416static int i915_delayfreq_table(struct seq_file *m, void *unused)
417{
418 struct drm_info_node *node = (struct drm_info_node *) m->private;
419 struct drm_device *dev = node->minor->dev;
420 drm_i915_private_t *dev_priv = dev->dev_private;
421 u32 delayfreq;
422 int i;
423
424 for (i = 0; i < 16; i++) {
425 delayfreq = I915_READ(PXVFREQ_BASE + i * 4);
426 seq_printf(m, "P%02dVIDFREQ: 0x%08x\n", i, delayfreq);
427 }
428
429 return 0;
430}
431
432static inline int MAP_TO_MV(int map)
433{
434 return 1250 - (map * 25);
435}
436
437static int i915_inttoext_table(struct seq_file *m, void *unused)
438{
439 struct drm_info_node *node = (struct drm_info_node *) m->private;
440 struct drm_device *dev = node->minor->dev;
441 drm_i915_private_t *dev_priv = dev->dev_private;
442 u32 inttoext;
443 int i;
444
445 for (i = 1; i <= 32; i++) {
446 inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4);
447 seq_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext);
448 }
449
450 return 0;
451}
452
453static int i915_drpc_info(struct seq_file *m, void *unused)
454{
455 struct drm_info_node *node = (struct drm_info_node *) m->private;
456 struct drm_device *dev = node->minor->dev;
457 drm_i915_private_t *dev_priv = dev->dev_private;
458 u32 rgvmodectl = I915_READ(MEMMODECTL);
459
460 seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ?
461 "yes" : "no");
462 seq_printf(m, "Boost freq: %d\n",
463 (rgvmodectl & MEMMODE_BOOST_FREQ_MASK) >>
464 MEMMODE_BOOST_FREQ_SHIFT);
465 seq_printf(m, "HW control enabled: %s\n",
466 rgvmodectl & MEMMODE_HWIDLE_EN ? "yes" : "no");
467 seq_printf(m, "SW control enabled: %s\n",
468 rgvmodectl & MEMMODE_SWMODE_EN ? "yes" : "no");
469 seq_printf(m, "Gated voltage change: %s\n",
470 rgvmodectl & MEMMODE_RCLK_GATE ? "yes" : "no");
471 seq_printf(m, "Starting frequency: P%d\n",
472 (rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT);
473 seq_printf(m, "Max frequency: P%d\n",
474 (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT);
475 seq_printf(m, "Min frequency: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK));
476
477 return 0;
478}
479
389static int 480static int
390i915_wedged_open(struct inode *inode, 481i915_wedged_open(struct inode *inode,
391 struct file *filp) 482 struct file *filp)
@@ -503,6 +594,11 @@ static struct drm_info_list i915_debugfs_list[] = {
503 {"i915_ringbuffer_info", i915_ringbuffer_info, 0}, 594 {"i915_ringbuffer_info", i915_ringbuffer_info, 0},
504 {"i915_batchbuffers", i915_batchbuffer_info, 0}, 595 {"i915_batchbuffers", i915_batchbuffer_info, 0},
505 {"i915_error_state", i915_error_state, 0}, 596 {"i915_error_state", i915_error_state, 0},
597 {"i915_rstdby_delays", i915_rstdby_delays, 0},
598 {"i915_cur_delayinfo", i915_cur_delayinfo, 0},
599 {"i915_delayfreq_table", i915_delayfreq_table, 0},
600 {"i915_inttoext_table", i915_inttoext_table, 0},
601 {"i915_drpc_info", i915_drpc_info, 0},
506}; 602};
507#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) 603#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
508 604
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 79beffcf5936..89f1cb86c32b 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -583,6 +583,11 @@ static int __init i915_init(void)
583 driver.driver_features &= ~DRIVER_MODESET; 583 driver.driver_features &= ~DRIVER_MODESET;
584#endif 584#endif
585 585
586 if (!(driver.driver_features & DRIVER_MODESET)) {
587 driver.suspend = i915_suspend;
588 driver.resume = i915_resume;
589 }
590
586 return drm_init(&driver); 591 return drm_init(&driver);
587} 592}
588 593
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f2742d6d3f54..2e493ec1042b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -452,6 +452,7 @@ typedef struct drm_i915_private {
452 u32 savePIPEB_DATA_N1; 452 u32 savePIPEB_DATA_N1;
453 u32 savePIPEB_LINK_M1; 453 u32 savePIPEB_LINK_M1;
454 u32 savePIPEB_LINK_N1; 454 u32 savePIPEB_LINK_N1;
455 u32 saveRSTDBYCTL;
455 456
456 struct { 457 struct {
457 struct drm_mm gtt_space; 458 struct drm_mm gtt_space;
@@ -590,7 +591,12 @@ typedef struct drm_i915_private {
590 int child_dev_num; 591 int child_dev_num;
591 struct child_device_config *child_dev; 592 struct child_device_config *child_dev;
592 struct drm_connector *int_lvds_connector; 593 struct drm_connector *int_lvds_connector;
594
593 bool mchbar_need_disable; 595 bool mchbar_need_disable;
596
597 u8 cur_delay;
598 u8 min_delay;
599 u8 max_delay;
594} drm_i915_private_t; 600} drm_i915_private_t;
595 601
596/** driver private structure attached to each drm_gem_object */ 602/** driver private structure attached to each drm_gem_object */
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index a17d6bdfe63e..8b35f5e1c511 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -269,6 +269,57 @@ static void i915_hotplug_work_func(struct work_struct *work)
269 drm_sysfs_hotplug_event(dev); 269 drm_sysfs_hotplug_event(dev);
270} 270}
271 271
272static void i915_handle_rps_change(struct drm_device *dev)
273{
274 drm_i915_private_t *dev_priv = dev->dev_private;
275 u32 slow_up, slow_down, max_avg, min_avg;
276 u16 rgvswctl;
277 u8 new_delay = dev_priv->cur_delay;
278
279 I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS) & ~MEMINT_EVAL_CHG);
280 slow_up = I915_READ(RCPREVBSYTUPAVG);
281 slow_down = I915_READ(RCPREVBSYTDNAVG);
282 max_avg = I915_READ(RCBMAXAVG);
283 min_avg = I915_READ(RCBMINAVG);
284
285 /* Handle RCS change request from hw */
286 if (slow_up > max_avg) {
287 if (dev_priv->cur_delay != dev_priv->max_delay)
288 new_delay = dev_priv->cur_delay - 1;
289 if (new_delay < dev_priv->max_delay)
290 new_delay = dev_priv->max_delay;
291 } else if (slow_down < min_avg) {
292 if (dev_priv->cur_delay != dev_priv->min_delay)
293 new_delay = dev_priv->cur_delay + 1;
294 if (new_delay > dev_priv->min_delay)
295 new_delay = dev_priv->min_delay;
296 }
297
298 DRM_DEBUG("rps change requested: %d -> %d\n",
299 dev_priv->cur_delay, new_delay);
300
301 rgvswctl = I915_READ(MEMSWCTL);
302 if (rgvswctl & MEMCTL_CMD_STS) {
303 DRM_ERROR("gpu slow, RCS change rejected\n");
304 return; /* still slow with another command */
305 }
306
307 /* Program the new state */
308 rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
309 (new_delay << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
310 I915_WRITE(MEMSWCTL, rgvswctl);
311 POSTING_READ(MEMSWCTL);
312
313 rgvswctl |= MEMCTL_CMD_STS;
314 I915_WRITE(MEMSWCTL, rgvswctl);
315
316 dev_priv->cur_delay = new_delay;
317
318 DRM_DEBUG("rps changed\n");
319
320 return;
321}
322
272irqreturn_t ironlake_irq_handler(struct drm_device *dev) 323irqreturn_t ironlake_irq_handler(struct drm_device *dev)
273{ 324{
274 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 325 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -331,6 +382,11 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
331 queue_work(dev_priv->wq, &dev_priv->hotplug_work); 382 queue_work(dev_priv->wq, &dev_priv->hotplug_work);
332 } 383 }
333 384
385 if (de_iir & DE_PCU_EVENT) {
386 I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS));
387 i915_handle_rps_change(dev);
388 }
389
334 /* should clear PCH hotplug event before clear CPU irq */ 390 /* should clear PCH hotplug event before clear CPU irq */
335 I915_WRITE(SDEIIR, pch_iir); 391 I915_WRITE(SDEIIR, pch_iir);
336 I915_WRITE(GTIIR, gt_iir); 392 I915_WRITE(GTIIR, gt_iir);
@@ -1064,6 +1120,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
1064 I915_WRITE(SDEIER, dev_priv->pch_irq_enable_reg); 1120 I915_WRITE(SDEIER, dev_priv->pch_irq_enable_reg);
1065 (void) I915_READ(SDEIER); 1121 (void) I915_READ(SDEIER);
1066 1122
1123 if (IS_IRONLAKE_M(dev)) {
1124 /* Clear & enable PCU event interrupts */
1125 I915_WRITE(DEIIR, DE_PCU_EVENT);
1126 I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
1127 ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
1128 }
1129
1067 return 0; 1130 return 0;
1068} 1131}
1069 1132
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 6defb7f47348..c3948ee37c13 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -61,6 +61,7 @@
61#define GC_CLOCK_100_200 (1 << 0) 61#define GC_CLOCK_100_200 (1 << 0)
62#define GC_CLOCK_100_133 (2 << 0) 62#define GC_CLOCK_100_133 (2 << 0)
63#define GC_CLOCK_166_250 (3 << 0) 63#define GC_CLOCK_166_250 (3 << 0)
64#define GCFGC2 0xda
64#define GCFGC 0xf0 /* 915+ only */ 65#define GCFGC 0xf0 /* 915+ only */
65#define GC_LOW_FREQUENCY_ENABLE (1 << 7) 66#define GC_LOW_FREQUENCY_ENABLE (1 << 7)
66#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4) 67#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
@@ -282,7 +283,7 @@
282#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) 283#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
283#define I915_DISPLAY_PORT_INTERRUPT (1<<17) 284#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
284#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) 285#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
285#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) 286#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */
286#define I915_HWB_OOM_INTERRUPT (1<<13) 287#define I915_HWB_OOM_INTERRUPT (1<<13)
287#define I915_SYNC_STATUS_INTERRUPT (1<<12) 288#define I915_SYNC_STATUS_INTERRUPT (1<<12)
288#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) 289#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11)
@@ -787,10 +788,144 @@
787#define CLKCFG_MEM_800 (3 << 4) 788#define CLKCFG_MEM_800 (3 << 4)
788#define CLKCFG_MEM_MASK (7 << 4) 789#define CLKCFG_MEM_MASK (7 << 4)
789 790
790/** GM965 GM45 render standby register */ 791#define CRSTANDVID 0x11100
791#define MCHBAR_RENDER_STANDBY 0x111B8 792#define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
793#define PXVFREQ_PX_MASK 0x7f000000
794#define PXVFREQ_PX_SHIFT 24
795#define VIDFREQ_BASE 0x11110
796#define VIDFREQ1 0x11110 /* VIDFREQ1-4 (0x1111c) (Cantiga) */
797#define VIDFREQ2 0x11114
798#define VIDFREQ3 0x11118
799#define VIDFREQ4 0x1111c
800#define VIDFREQ_P0_MASK 0x1f000000
801#define VIDFREQ_P0_SHIFT 24
802#define VIDFREQ_P0_CSCLK_MASK 0x00f00000
803#define VIDFREQ_P0_CSCLK_SHIFT 20
804#define VIDFREQ_P0_CRCLK_MASK 0x000f0000
805#define VIDFREQ_P0_CRCLK_SHIFT 16
806#define VIDFREQ_P1_MASK 0x00001f00
807#define VIDFREQ_P1_SHIFT 8
808#define VIDFREQ_P1_CSCLK_MASK 0x000000f0
809#define VIDFREQ_P1_CSCLK_SHIFT 4
810#define VIDFREQ_P1_CRCLK_MASK 0x0000000f
811#define INTTOEXT_BASE_ILK 0x11300
812#define INTTOEXT_BASE 0x11120 /* INTTOEXT1-8 (0x1113c) */
813#define INTTOEXT_MAP3_SHIFT 24
814#define INTTOEXT_MAP3_MASK (0x1f << INTTOEXT_MAP3_SHIFT)
815#define INTTOEXT_MAP2_SHIFT 16
816#define INTTOEXT_MAP2_MASK (0x1f << INTTOEXT_MAP2_SHIFT)
817#define INTTOEXT_MAP1_SHIFT 8
818#define INTTOEXT_MAP1_MASK (0x1f << INTTOEXT_MAP1_SHIFT)
819#define INTTOEXT_MAP0_SHIFT 0
820#define INTTOEXT_MAP0_MASK (0x1f << INTTOEXT_MAP0_SHIFT)
821#define MEMSWCTL 0x11170 /* Ironlake only */
822#define MEMCTL_CMD_MASK 0xe000
823#define MEMCTL_CMD_SHIFT 13
824#define MEMCTL_CMD_RCLK_OFF 0
825#define MEMCTL_CMD_RCLK_ON 1
826#define MEMCTL_CMD_CHFREQ 2
827#define MEMCTL_CMD_CHVID 3
828#define MEMCTL_CMD_VMMOFF 4
829#define MEMCTL_CMD_VMMON 5
830#define MEMCTL_CMD_STS (1<<12) /* write 1 triggers command, clears
831 when command complete */
832#define MEMCTL_FREQ_MASK 0x0f00 /* jitter, from 0-15 */
833#define MEMCTL_FREQ_SHIFT 8
834#define MEMCTL_SFCAVM (1<<7)
835#define MEMCTL_TGT_VID_MASK 0x007f
836#define MEMIHYST 0x1117c
837#define MEMINTREN 0x11180 /* 16 bits */
838#define MEMINT_RSEXIT_EN (1<<8)
839#define MEMINT_CX_SUPR_EN (1<<7)
840#define MEMINT_CONT_BUSY_EN (1<<6)
841#define MEMINT_AVG_BUSY_EN (1<<5)
842#define MEMINT_EVAL_CHG_EN (1<<4)
843#define MEMINT_MON_IDLE_EN (1<<3)
844#define MEMINT_UP_EVAL_EN (1<<2)
845#define MEMINT_DOWN_EVAL_EN (1<<1)
846#define MEMINT_SW_CMD_EN (1<<0)
847#define MEMINTRSTR 0x11182 /* 16 bits */
848#define MEM_RSEXIT_MASK 0xc000
849#define MEM_RSEXIT_SHIFT 14
850#define MEM_CONT_BUSY_MASK 0x3000
851#define MEM_CONT_BUSY_SHIFT 12
852#define MEM_AVG_BUSY_MASK 0x0c00
853#define MEM_AVG_BUSY_SHIFT 10
854#define MEM_EVAL_CHG_MASK 0x0300
855#define MEM_EVAL_BUSY_SHIFT 8
856#define MEM_MON_IDLE_MASK 0x00c0
857#define MEM_MON_IDLE_SHIFT 6
858#define MEM_UP_EVAL_MASK 0x0030
859#define MEM_UP_EVAL_SHIFT 4
860#define MEM_DOWN_EVAL_MASK 0x000c
861#define MEM_DOWN_EVAL_SHIFT 2
862#define MEM_SW_CMD_MASK 0x0003
863#define MEM_INT_STEER_GFX 0
864#define MEM_INT_STEER_CMR 1
865#define MEM_INT_STEER_SMI 2
866#define MEM_INT_STEER_SCI 3
867#define MEMINTRSTS 0x11184
868#define MEMINT_RSEXIT (1<<7)
869#define MEMINT_CONT_BUSY (1<<6)
870#define MEMINT_AVG_BUSY (1<<5)
871#define MEMINT_EVAL_CHG (1<<4)
872#define MEMINT_MON_IDLE (1<<3)
873#define MEMINT_UP_EVAL (1<<2)
874#define MEMINT_DOWN_EVAL (1<<1)
875#define MEMINT_SW_CMD (1<<0)
876#define MEMMODECTL 0x11190
877#define MEMMODE_BOOST_EN (1<<31)
878#define MEMMODE_BOOST_FREQ_MASK 0x0f000000 /* jitter for boost, 0-15 */
879#define MEMMODE_BOOST_FREQ_SHIFT 24
880#define MEMMODE_IDLE_MODE_MASK 0x00030000
881#define MEMMODE_IDLE_MODE_SHIFT 16
882#define MEMMODE_IDLE_MODE_EVAL 0
883#define MEMMODE_IDLE_MODE_CONT 1
884#define MEMMODE_HWIDLE_EN (1<<15)
885#define MEMMODE_SWMODE_EN (1<<14)
886#define MEMMODE_RCLK_GATE (1<<13)
887#define MEMMODE_HW_UPDATE (1<<12)
888#define MEMMODE_FSTART_MASK 0x00000f00 /* starting jitter, 0-15 */
889#define MEMMODE_FSTART_SHIFT 8
890#define MEMMODE_FMAX_MASK 0x000000f0 /* max jitter, 0-15 */
891#define MEMMODE_FMAX_SHIFT 4
892#define MEMMODE_FMIN_MASK 0x0000000f /* min jitter, 0-15 */
893#define RCBMAXAVG 0x1119c
894#define MEMSWCTL2 0x1119e /* Cantiga only */
895#define SWMEMCMD_RENDER_OFF (0 << 13)
896#define SWMEMCMD_RENDER_ON (1 << 13)
897#define SWMEMCMD_SWFREQ (2 << 13)
898#define SWMEMCMD_TARVID (3 << 13)
899#define SWMEMCMD_VRM_OFF (4 << 13)
900#define SWMEMCMD_VRM_ON (5 << 13)
901#define CMDSTS (1<<12)
902#define SFCAVM (1<<11)
903#define SWFREQ_MASK 0x0380 /* P0-7 */
904#define SWFREQ_SHIFT 7
905#define TARVID_MASK 0x001f
906#define MEMSTAT_CTG 0x111a0
907#define RCBMINAVG 0x111a0
908#define RCUPEI 0x111b0
909#define RCDNEI 0x111b4
910#define RSTDBYCTL 0x111b8
792#define RCX_SW_EXIT (1<<23) 911#define RCX_SW_EXIT (1<<23)
793#define RSX_STATUS_MASK 0x00700000 912#define RSX_STATUS_MASK 0x00700000
913#define VIDCTL 0x111c0
914#define VIDSTS 0x111c8
915#define VIDSTART 0x111cc /* 8 bits */
916#define MEMSTAT_ILK 0x111f8
917#define MEMSTAT_VID_MASK 0x7f00
918#define MEMSTAT_VID_SHIFT 8
919#define MEMSTAT_PSTATE_MASK 0x00f8
920#define MEMSTAT_PSTATE_SHIFT 3
921#define MEMSTAT_MON_ACTV (1<<2)
922#define MEMSTAT_SRC_CTL_MASK 0x0003
923#define MEMSTAT_SRC_CTL_CORE 0
924#define MEMSTAT_SRC_CTL_TRB 1
925#define MEMSTAT_SRC_CTL_THM 2
926#define MEMSTAT_SRC_CTL_STDBY 3
927#define RCPREVBSYTUPAVG 0x113b8
928#define RCPREVBSYTDNAVG 0x113bc
794#define PEG_BAND_GAP_DATA 0x14d68 929#define PEG_BAND_GAP_DATA 0x14d68
795 930
796/* 931/*
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index a3b90c9561dc..2c346645acfa 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -682,6 +682,7 @@ void i915_restore_display(struct drm_device *dev)
682 I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS); 682 I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
683 I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR); 683 I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR);
684 I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL); 684 I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL);
685 I915_WRITE(RSTDBYCTL, dev_priv->saveRSTDBYCTL);
685 } else { 686 } else {
686 I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); 687 I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
687 I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); 688 I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
@@ -745,11 +746,15 @@ int i915_save_state(struct drm_device *dev)
745 dev_priv->saveGTIMR = I915_READ(GTIMR); 746 dev_priv->saveGTIMR = I915_READ(GTIMR);
746 dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR); 747 dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR);
747 dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR); 748 dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR);
749 dev_priv->saveRSTDBYCTL = I915_READ(RSTDBYCTL);
748 } else { 750 } else {
749 dev_priv->saveIER = I915_READ(IER); 751 dev_priv->saveIER = I915_READ(IER);
750 dev_priv->saveIMR = I915_READ(IMR); 752 dev_priv->saveIMR = I915_READ(IMR);
751 } 753 }
752 754
755 if (IS_IRONLAKE_M(dev))
756 ironlake_disable_drps(dev);
757
753 /* Cache mode state */ 758 /* Cache mode state */
754 dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); 759 dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
755 760
@@ -820,6 +825,9 @@ int i915_restore_state(struct drm_device *dev)
820 /* Clock gating state */ 825 /* Clock gating state */
821 intel_init_clock_gating(dev); 826 intel_init_clock_gating(dev);
822 827
828 if (IS_IRONLAKE_M(dev))
829 ironlake_enable_drps(dev);
830
823 /* Cache mode state */ 831 /* Cache mode state */
824 I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); 832 I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
825 833
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index af9ec217cd1d..4a93f7a0f58d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4616,6 +4616,91 @@ err_unref:
4616 return NULL; 4616 return NULL;
4617} 4617}
4618 4618
4619void ironlake_enable_drps(struct drm_device *dev)
4620{
4621 struct drm_i915_private *dev_priv = dev->dev_private;
4622 u32 rgvmodectl = I915_READ(MEMMODECTL), rgvswctl;
4623 u8 fmax, fmin, fstart, vstart;
4624 int i = 0;
4625
4626 /* 100ms RC evaluation intervals */
4627 I915_WRITE(RCUPEI, 100000);
4628 I915_WRITE(RCDNEI, 100000);
4629
4630 /* Set max/min thresholds to 90ms and 80ms respectively */
4631 I915_WRITE(RCBMAXAVG, 90000);
4632 I915_WRITE(RCBMINAVG, 80000);
4633
4634 I915_WRITE(MEMIHYST, 1);
4635
4636 /* Set up min, max, and cur for interrupt handling */
4637 fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
4638 fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
4639 fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
4640 MEMMODE_FSTART_SHIFT;
4641 vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
4642 PXVFREQ_PX_SHIFT;
4643
4644 dev_priv->max_delay = fstart; /* can't go to fmax w/o IPS */
4645 dev_priv->min_delay = fmin;
4646 dev_priv->cur_delay = fstart;
4647
4648 I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
4649
4650 /*
4651 * Interrupts will be enabled in ironlake_irq_postinstall
4652 */
4653
4654 I915_WRITE(VIDSTART, vstart);
4655 POSTING_READ(VIDSTART);
4656
4657 rgvmodectl |= MEMMODE_SWMODE_EN;
4658 I915_WRITE(MEMMODECTL, rgvmodectl);
4659
4660 while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) {
4661 if (i++ > 100) {
4662 DRM_ERROR("stuck trying to change perf mode\n");
4663 break;
4664 }
4665 msleep(1);
4666 }
4667 msleep(1);
4668
4669 rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
4670 (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
4671 I915_WRITE(MEMSWCTL, rgvswctl);
4672 POSTING_READ(MEMSWCTL);
4673
4674 rgvswctl |= MEMCTL_CMD_STS;
4675 I915_WRITE(MEMSWCTL, rgvswctl);
4676}
4677
4678void ironlake_disable_drps(struct drm_device *dev)
4679{
4680 struct drm_i915_private *dev_priv = dev->dev_private;
4681 u32 rgvswctl;
4682 u8 fstart;
4683
4684 /* Ack interrupts, disable EFC interrupt */
4685 I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
4686 I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
4687 I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
4688 I915_WRITE(DEIIR, DE_PCU_EVENT);
4689 I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
4690
4691 /* Go back to the starting frequency */
4692 fstart = (I915_READ(MEMMODECTL) & MEMMODE_FSTART_MASK) >>
4693 MEMMODE_FSTART_SHIFT;
4694 rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
4695 (fstart << MEMCTL_FREQ_SHIFT);
4696 I915_WRITE(MEMSWCTL, rgvswctl);
4697 msleep(1);
4698 rgvswctl |= MEMCTL_CMD_STS;
4699 I915_WRITE(MEMSWCTL, rgvswctl);
4700 msleep(1);
4701
4702}
4703
4619void intel_init_clock_gating(struct drm_device *dev) 4704void intel_init_clock_gating(struct drm_device *dev)
4620{ 4705{
4621 struct drm_i915_private *dev_priv = dev->dev_private; 4706 struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4685,8 +4770,8 @@ void intel_init_clock_gating(struct drm_device *dev)
4685 4770
4686 if (obj_priv) { 4771 if (obj_priv) {
4687 I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN); 4772 I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN);
4688 I915_WRITE(MCHBAR_RENDER_STANDBY, 4773 I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) &
4689 I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT); 4774 ~RCX_SW_EXIT);
4690 } 4775 }
4691 } 4776 }
4692} 4777}
@@ -4799,11 +4884,6 @@ void intel_modeset_init(struct drm_device *dev)
4799 DRM_DEBUG_KMS("%d display pipe%s available.\n", 4884 DRM_DEBUG_KMS("%d display pipe%s available.\n",
4800 num_pipe, num_pipe > 1 ? "s" : ""); 4885 num_pipe, num_pipe > 1 ? "s" : "");
4801 4886
4802 if (IS_I85X(dev))
4803 pci_read_config_word(dev->pdev, HPLLCC, &dev_priv->orig_clock);
4804 else if (IS_I9XX(dev) || IS_G4X(dev))
4805 pci_read_config_word(dev->pdev, GCFGC, &dev_priv->orig_clock);
4806
4807 for (i = 0; i < num_pipe; i++) { 4887 for (i = 0; i < num_pipe; i++) {
4808 intel_crtc_init(dev, i); 4888 intel_crtc_init(dev, i);
4809 } 4889 }
@@ -4812,6 +4892,9 @@ void intel_modeset_init(struct drm_device *dev)
4812 4892
4813 intel_init_clock_gating(dev); 4893 intel_init_clock_gating(dev);
4814 4894
4895 if (IS_IRONLAKE_M(dev))
4896 ironlake_enable_drps(dev);
4897
4815 INIT_WORK(&dev_priv->idle_work, intel_idle_update); 4898 INIT_WORK(&dev_priv->idle_work, intel_idle_update);
4816 setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, 4899 setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
4817 (unsigned long)dev); 4900 (unsigned long)dev);
@@ -4859,6 +4942,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
4859 drm_gem_object_unreference(dev_priv->pwrctx); 4942 drm_gem_object_unreference(dev_priv->pwrctx);
4860 } 4943 }
4861 4944
4945 if (IS_IRONLAKE_M(dev))
4946 ironlake_disable_drps(dev);
4947
4862 mutex_unlock(&dev->struct_mutex); 4948 mutex_unlock(&dev->struct_mutex);
4863 4949
4864 drm_mode_config_cleanup(dev); 4950 drm_mode_config_cleanup(dev);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a51573da1ff6..3a467ca57857 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -209,6 +209,8 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
209extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, 209extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
210 u16 *blue, int regno); 210 u16 *blue, int regno);
211extern void intel_init_clock_gating(struct drm_device *dev); 211extern void intel_init_clock_gating(struct drm_device *dev);
212extern void ironlake_enable_drps(struct drm_device *dev);
213extern void ironlake_disable_drps(struct drm_device *dev);
212 214
213extern int intel_framebuffer_create(struct drm_device *dev, 215extern int intel_framebuffer_create(struct drm_device *dev,
214 struct drm_mode_fb_cmd *mode_cmd, 216 struct drm_mode_fb_cmd *mode_cmd,