diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2010-01-29 14:27:07 -0500 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2010-02-22 11:46:54 -0500 |
commit | f97108d1d0facc7902134ebc453b226bbd4d1cdb (patch) | |
tree | 563d14cb7c65b80e16df9246da25cade22f22fdd /drivers/gpu/drm | |
parent | ee980b8003a25fbfed50c3367f2b426c870eaf90 (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.c | 96 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 63 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 141 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_suspend.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 100 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 2 |
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 | ||
389 | static 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 | |||
401 | static 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 | |||
416 | static 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 | |||
432 | static inline int MAP_TO_MV(int map) | ||
433 | { | ||
434 | return 1250 - (map * 25); | ||
435 | } | ||
436 | |||
437 | static 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 | |||
453 | static 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 | |||
389 | static int | 480 | static int |
390 | i915_wedged_open(struct inode *inode, | 481 | i915_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 | ||
272 | static 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 | |||
272 | irqreturn_t ironlake_irq_handler(struct drm_device *dev) | 323 | irqreturn_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 | ||
4619 | void 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 | |||
4678 | void 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 | |||
4619 | void intel_init_clock_gating(struct drm_device *dev) | 4704 | void 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, | |||
209 | extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, | 209 | extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, |
210 | u16 *blue, int regno); | 210 | u16 *blue, int regno); |
211 | extern void intel_init_clock_gating(struct drm_device *dev); | 211 | extern void intel_init_clock_gating(struct drm_device *dev); |
212 | extern void ironlake_enable_drps(struct drm_device *dev); | ||
213 | extern void ironlake_disable_drps(struct drm_device *dev); | ||
212 | 214 | ||
213 | extern int intel_framebuffer_create(struct drm_device *dev, | 215 | extern int intel_framebuffer_create(struct drm_device *dev, |
214 | struct drm_mode_fb_cmd *mode_cmd, | 216 | struct drm_mode_fb_cmd *mode_cmd, |