mirror of
https://github.com/torvalds/linux.git
synced 2024-12-02 09:01:34 +00:00
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>
This commit is contained in:
parent
ee980b8003
commit
f97108d1d0
@ -386,6 +386,97 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_rstdby_delays(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 crstanddelay = I915_READ16(CRSTANDVID);
|
||||
|
||||
seq_printf(m, "w/ctx: %d, w/o ctx: %d\n", (crstanddelay >> 8) & 0x3f, (crstanddelay & 0x3f));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
seq_printf(m, "Last command: 0x%01x\n", (rgvswctl >> 13) & 0x3);
|
||||
seq_printf(m, "Command status: %d\n", (rgvswctl >> 12) & 1);
|
||||
seq_printf(m, "P%d DELAY 0x%02x\n", (rgvswctl >> 8) & 0xf,
|
||||
rgvswctl & 0x3f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_delayfreq_table(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;
|
||||
u32 delayfreq;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
delayfreq = I915_READ(PXVFREQ_BASE + i * 4);
|
||||
seq_printf(m, "P%02dVIDFREQ: 0x%08x\n", i, delayfreq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int MAP_TO_MV(int map)
|
||||
{
|
||||
return 1250 - (map * 25);
|
||||
}
|
||||
|
||||
static int i915_inttoext_table(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;
|
||||
u32 inttoext;
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= 32; i++) {
|
||||
inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4);
|
||||
seq_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_drpc_info(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;
|
||||
u32 rgvmodectl = I915_READ(MEMMODECTL);
|
||||
|
||||
seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ?
|
||||
"yes" : "no");
|
||||
seq_printf(m, "Boost freq: %d\n",
|
||||
(rgvmodectl & MEMMODE_BOOST_FREQ_MASK) >>
|
||||
MEMMODE_BOOST_FREQ_SHIFT);
|
||||
seq_printf(m, "HW control enabled: %s\n",
|
||||
rgvmodectl & MEMMODE_HWIDLE_EN ? "yes" : "no");
|
||||
seq_printf(m, "SW control enabled: %s\n",
|
||||
rgvmodectl & MEMMODE_SWMODE_EN ? "yes" : "no");
|
||||
seq_printf(m, "Gated voltage change: %s\n",
|
||||
rgvmodectl & MEMMODE_RCLK_GATE ? "yes" : "no");
|
||||
seq_printf(m, "Starting frequency: P%d\n",
|
||||
(rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT);
|
||||
seq_printf(m, "Max frequency: P%d\n",
|
||||
(rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT);
|
||||
seq_printf(m, "Min frequency: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_wedged_open(struct inode *inode,
|
||||
struct file *filp)
|
||||
@ -503,6 +594,11 @@ static struct drm_info_list i915_debugfs_list[] = {
|
||||
{"i915_ringbuffer_info", i915_ringbuffer_info, 0},
|
||||
{"i915_batchbuffers", i915_batchbuffer_info, 0},
|
||||
{"i915_error_state", i915_error_state, 0},
|
||||
{"i915_rstdby_delays", i915_rstdby_delays, 0},
|
||||
{"i915_cur_delayinfo", i915_cur_delayinfo, 0},
|
||||
{"i915_delayfreq_table", i915_delayfreq_table, 0},
|
||||
{"i915_inttoext_table", i915_inttoext_table, 0},
|
||||
{"i915_drpc_info", i915_drpc_info, 0},
|
||||
};
|
||||
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
|
||||
|
||||
|
@ -583,6 +583,11 @@ static int __init i915_init(void)
|
||||
driver.driver_features &= ~DRIVER_MODESET;
|
||||
#endif
|
||||
|
||||
if (!(driver.driver_features & DRIVER_MODESET)) {
|
||||
driver.suspend = i915_suspend;
|
||||
driver.resume = i915_resume;
|
||||
}
|
||||
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
|
@ -452,6 +452,7 @@ typedef struct drm_i915_private {
|
||||
u32 savePIPEB_DATA_N1;
|
||||
u32 savePIPEB_LINK_M1;
|
||||
u32 savePIPEB_LINK_N1;
|
||||
u32 saveRSTDBYCTL;
|
||||
|
||||
struct {
|
||||
struct drm_mm gtt_space;
|
||||
@ -590,7 +591,12 @@ typedef struct drm_i915_private {
|
||||
int child_dev_num;
|
||||
struct child_device_config *child_dev;
|
||||
struct drm_connector *int_lvds_connector;
|
||||
|
||||
bool mchbar_need_disable;
|
||||
|
||||
u8 cur_delay;
|
||||
u8 min_delay;
|
||||
u8 max_delay;
|
||||
} drm_i915_private_t;
|
||||
|
||||
/** driver private structure attached to each drm_gem_object */
|
||||
|
@ -269,6 +269,57 @@ static void i915_hotplug_work_func(struct work_struct *work)
|
||||
drm_sysfs_hotplug_event(dev);
|
||||
}
|
||||
|
||||
static void i915_handle_rps_change(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
u32 slow_up, slow_down, max_avg, min_avg;
|
||||
u16 rgvswctl;
|
||||
u8 new_delay = dev_priv->cur_delay;
|
||||
|
||||
I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS) & ~MEMINT_EVAL_CHG);
|
||||
slow_up = I915_READ(RCPREVBSYTUPAVG);
|
||||
slow_down = I915_READ(RCPREVBSYTDNAVG);
|
||||
max_avg = I915_READ(RCBMAXAVG);
|
||||
min_avg = I915_READ(RCBMINAVG);
|
||||
|
||||
/* Handle RCS change request from hw */
|
||||
if (slow_up > max_avg) {
|
||||
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 (slow_down < min_avg) {
|
||||
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;
|
||||
}
|
||||
|
||||
DRM_DEBUG("rps change requested: %d -> %d\n",
|
||||
dev_priv->cur_delay, new_delay);
|
||||
|
||||
rgvswctl = I915_READ(MEMSWCTL);
|
||||
if (rgvswctl & MEMCTL_CMD_STS) {
|
||||
DRM_ERROR("gpu slow, RCS change rejected\n");
|
||||
return; /* still slow with another command */
|
||||
}
|
||||
|
||||
/* Program the new state */
|
||||
rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
|
||||
(new_delay << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
POSTING_READ(MEMSWCTL);
|
||||
|
||||
rgvswctl |= MEMCTL_CMD_STS;
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
|
||||
dev_priv->cur_delay = new_delay;
|
||||
|
||||
DRM_DEBUG("rps changed\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
irqreturn_t ironlake_irq_handler(struct drm_device *dev)
|
||||
{
|
||||
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)
|
||||
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
|
||||
}
|
||||
|
||||
if (de_iir & DE_PCU_EVENT) {
|
||||
I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS));
|
||||
i915_handle_rps_change(dev);
|
||||
}
|
||||
|
||||
/* should clear PCH hotplug event before clear CPU irq */
|
||||
I915_WRITE(SDEIIR, pch_iir);
|
||||
I915_WRITE(GTIIR, gt_iir);
|
||||
@ -1064,6 +1120,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
|
||||
I915_WRITE(SDEIER, dev_priv->pch_irq_enable_reg);
|
||||
(void) I915_READ(SDEIER);
|
||||
|
||||
if (IS_IRONLAKE_M(dev)) {
|
||||
/* Clear & enable PCU event interrupts */
|
||||
I915_WRITE(DEIIR, DE_PCU_EVENT);
|
||||
I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
|
||||
ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,7 @@
|
||||
#define GC_CLOCK_100_200 (1 << 0)
|
||||
#define GC_CLOCK_100_133 (2 << 0)
|
||||
#define GC_CLOCK_166_250 (3 << 0)
|
||||
#define GCFGC2 0xda
|
||||
#define GCFGC 0xf0 /* 915+ only */
|
||||
#define GC_LOW_FREQUENCY_ENABLE (1 << 7)
|
||||
#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
|
||||
@ -282,7 +283,7 @@
|
||||
#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
|
||||
#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
|
||||
#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
|
||||
#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14)
|
||||
#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */
|
||||
#define I915_HWB_OOM_INTERRUPT (1<<13)
|
||||
#define I915_SYNC_STATUS_INTERRUPT (1<<12)
|
||||
#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11)
|
||||
@ -787,10 +788,144 @@
|
||||
#define CLKCFG_MEM_800 (3 << 4)
|
||||
#define CLKCFG_MEM_MASK (7 << 4)
|
||||
|
||||
/** GM965 GM45 render standby register */
|
||||
#define MCHBAR_RENDER_STANDBY 0x111B8
|
||||
#define CRSTANDVID 0x11100
|
||||
#define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
|
||||
#define PXVFREQ_PX_MASK 0x7f000000
|
||||
#define PXVFREQ_PX_SHIFT 24
|
||||
#define VIDFREQ_BASE 0x11110
|
||||
#define VIDFREQ1 0x11110 /* VIDFREQ1-4 (0x1111c) (Cantiga) */
|
||||
#define VIDFREQ2 0x11114
|
||||
#define VIDFREQ3 0x11118
|
||||
#define VIDFREQ4 0x1111c
|
||||
#define VIDFREQ_P0_MASK 0x1f000000
|
||||
#define VIDFREQ_P0_SHIFT 24
|
||||
#define VIDFREQ_P0_CSCLK_MASK 0x00f00000
|
||||
#define VIDFREQ_P0_CSCLK_SHIFT 20
|
||||
#define VIDFREQ_P0_CRCLK_MASK 0x000f0000
|
||||
#define VIDFREQ_P0_CRCLK_SHIFT 16
|
||||
#define VIDFREQ_P1_MASK 0x00001f00
|
||||
#define VIDFREQ_P1_SHIFT 8
|
||||
#define VIDFREQ_P1_CSCLK_MASK 0x000000f0
|
||||
#define VIDFREQ_P1_CSCLK_SHIFT 4
|
||||
#define VIDFREQ_P1_CRCLK_MASK 0x0000000f
|
||||
#define INTTOEXT_BASE_ILK 0x11300
|
||||
#define INTTOEXT_BASE 0x11120 /* INTTOEXT1-8 (0x1113c) */
|
||||
#define INTTOEXT_MAP3_SHIFT 24
|
||||
#define INTTOEXT_MAP3_MASK (0x1f << INTTOEXT_MAP3_SHIFT)
|
||||
#define INTTOEXT_MAP2_SHIFT 16
|
||||
#define INTTOEXT_MAP2_MASK (0x1f << INTTOEXT_MAP2_SHIFT)
|
||||
#define INTTOEXT_MAP1_SHIFT 8
|
||||
#define INTTOEXT_MAP1_MASK (0x1f << INTTOEXT_MAP1_SHIFT)
|
||||
#define INTTOEXT_MAP0_SHIFT 0
|
||||
#define INTTOEXT_MAP0_MASK (0x1f << INTTOEXT_MAP0_SHIFT)
|
||||
#define MEMSWCTL 0x11170 /* Ironlake only */
|
||||
#define MEMCTL_CMD_MASK 0xe000
|
||||
#define MEMCTL_CMD_SHIFT 13
|
||||
#define MEMCTL_CMD_RCLK_OFF 0
|
||||
#define MEMCTL_CMD_RCLK_ON 1
|
||||
#define MEMCTL_CMD_CHFREQ 2
|
||||
#define MEMCTL_CMD_CHVID 3
|
||||
#define MEMCTL_CMD_VMMOFF 4
|
||||
#define MEMCTL_CMD_VMMON 5
|
||||
#define MEMCTL_CMD_STS (1<<12) /* write 1 triggers command, clears
|
||||
when command complete */
|
||||
#define MEMCTL_FREQ_MASK 0x0f00 /* jitter, from 0-15 */
|
||||
#define MEMCTL_FREQ_SHIFT 8
|
||||
#define MEMCTL_SFCAVM (1<<7)
|
||||
#define MEMCTL_TGT_VID_MASK 0x007f
|
||||
#define MEMIHYST 0x1117c
|
||||
#define MEMINTREN 0x11180 /* 16 bits */
|
||||
#define MEMINT_RSEXIT_EN (1<<8)
|
||||
#define MEMINT_CX_SUPR_EN (1<<7)
|
||||
#define MEMINT_CONT_BUSY_EN (1<<6)
|
||||
#define MEMINT_AVG_BUSY_EN (1<<5)
|
||||
#define MEMINT_EVAL_CHG_EN (1<<4)
|
||||
#define MEMINT_MON_IDLE_EN (1<<3)
|
||||
#define MEMINT_UP_EVAL_EN (1<<2)
|
||||
#define MEMINT_DOWN_EVAL_EN (1<<1)
|
||||
#define MEMINT_SW_CMD_EN (1<<0)
|
||||
#define MEMINTRSTR 0x11182 /* 16 bits */
|
||||
#define MEM_RSEXIT_MASK 0xc000
|
||||
#define MEM_RSEXIT_SHIFT 14
|
||||
#define MEM_CONT_BUSY_MASK 0x3000
|
||||
#define MEM_CONT_BUSY_SHIFT 12
|
||||
#define MEM_AVG_BUSY_MASK 0x0c00
|
||||
#define MEM_AVG_BUSY_SHIFT 10
|
||||
#define MEM_EVAL_CHG_MASK 0x0300
|
||||
#define MEM_EVAL_BUSY_SHIFT 8
|
||||
#define MEM_MON_IDLE_MASK 0x00c0
|
||||
#define MEM_MON_IDLE_SHIFT 6
|
||||
#define MEM_UP_EVAL_MASK 0x0030
|
||||
#define MEM_UP_EVAL_SHIFT 4
|
||||
#define MEM_DOWN_EVAL_MASK 0x000c
|
||||
#define MEM_DOWN_EVAL_SHIFT 2
|
||||
#define MEM_SW_CMD_MASK 0x0003
|
||||
#define MEM_INT_STEER_GFX 0
|
||||
#define MEM_INT_STEER_CMR 1
|
||||
#define MEM_INT_STEER_SMI 2
|
||||
#define MEM_INT_STEER_SCI 3
|
||||
#define MEMINTRSTS 0x11184
|
||||
#define MEMINT_RSEXIT (1<<7)
|
||||
#define MEMINT_CONT_BUSY (1<<6)
|
||||
#define MEMINT_AVG_BUSY (1<<5)
|
||||
#define MEMINT_EVAL_CHG (1<<4)
|
||||
#define MEMINT_MON_IDLE (1<<3)
|
||||
#define MEMINT_UP_EVAL (1<<2)
|
||||
#define MEMINT_DOWN_EVAL (1<<1)
|
||||
#define MEMINT_SW_CMD (1<<0)
|
||||
#define MEMMODECTL 0x11190
|
||||
#define MEMMODE_BOOST_EN (1<<31)
|
||||
#define MEMMODE_BOOST_FREQ_MASK 0x0f000000 /* jitter for boost, 0-15 */
|
||||
#define MEMMODE_BOOST_FREQ_SHIFT 24
|
||||
#define MEMMODE_IDLE_MODE_MASK 0x00030000
|
||||
#define MEMMODE_IDLE_MODE_SHIFT 16
|
||||
#define MEMMODE_IDLE_MODE_EVAL 0
|
||||
#define MEMMODE_IDLE_MODE_CONT 1
|
||||
#define MEMMODE_HWIDLE_EN (1<<15)
|
||||
#define MEMMODE_SWMODE_EN (1<<14)
|
||||
#define MEMMODE_RCLK_GATE (1<<13)
|
||||
#define MEMMODE_HW_UPDATE (1<<12)
|
||||
#define MEMMODE_FSTART_MASK 0x00000f00 /* starting jitter, 0-15 */
|
||||
#define MEMMODE_FSTART_SHIFT 8
|
||||
#define MEMMODE_FMAX_MASK 0x000000f0 /* max jitter, 0-15 */
|
||||
#define MEMMODE_FMAX_SHIFT 4
|
||||
#define MEMMODE_FMIN_MASK 0x0000000f /* min jitter, 0-15 */
|
||||
#define RCBMAXAVG 0x1119c
|
||||
#define MEMSWCTL2 0x1119e /* Cantiga only */
|
||||
#define SWMEMCMD_RENDER_OFF (0 << 13)
|
||||
#define SWMEMCMD_RENDER_ON (1 << 13)
|
||||
#define SWMEMCMD_SWFREQ (2 << 13)
|
||||
#define SWMEMCMD_TARVID (3 << 13)
|
||||
#define SWMEMCMD_VRM_OFF (4 << 13)
|
||||
#define SWMEMCMD_VRM_ON (5 << 13)
|
||||
#define CMDSTS (1<<12)
|
||||
#define SFCAVM (1<<11)
|
||||
#define SWFREQ_MASK 0x0380 /* P0-7 */
|
||||
#define SWFREQ_SHIFT 7
|
||||
#define TARVID_MASK 0x001f
|
||||
#define MEMSTAT_CTG 0x111a0
|
||||
#define RCBMINAVG 0x111a0
|
||||
#define RCUPEI 0x111b0
|
||||
#define RCDNEI 0x111b4
|
||||
#define RSTDBYCTL 0x111b8
|
||||
#define RCX_SW_EXIT (1<<23)
|
||||
#define RSX_STATUS_MASK 0x00700000
|
||||
#define VIDCTL 0x111c0
|
||||
#define VIDSTS 0x111c8
|
||||
#define VIDSTART 0x111cc /* 8 bits */
|
||||
#define MEMSTAT_ILK 0x111f8
|
||||
#define MEMSTAT_VID_MASK 0x7f00
|
||||
#define MEMSTAT_VID_SHIFT 8
|
||||
#define MEMSTAT_PSTATE_MASK 0x00f8
|
||||
#define MEMSTAT_PSTATE_SHIFT 3
|
||||
#define MEMSTAT_MON_ACTV (1<<2)
|
||||
#define MEMSTAT_SRC_CTL_MASK 0x0003
|
||||
#define MEMSTAT_SRC_CTL_CORE 0
|
||||
#define MEMSTAT_SRC_CTL_TRB 1
|
||||
#define MEMSTAT_SRC_CTL_THM 2
|
||||
#define MEMSTAT_SRC_CTL_STDBY 3
|
||||
#define RCPREVBSYTUPAVG 0x113b8
|
||||
#define RCPREVBSYTDNAVG 0x113bc
|
||||
#define PEG_BAND_GAP_DATA 0x14d68
|
||||
|
||||
/*
|
||||
|
@ -682,6 +682,7 @@ void i915_restore_display(struct drm_device *dev)
|
||||
I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
|
||||
I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR);
|
||||
I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL);
|
||||
I915_WRITE(RSTDBYCTL, dev_priv->saveRSTDBYCTL);
|
||||
} else {
|
||||
I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
|
||||
I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
|
||||
@ -745,11 +746,15 @@ int i915_save_state(struct drm_device *dev)
|
||||
dev_priv->saveGTIMR = I915_READ(GTIMR);
|
||||
dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR);
|
||||
dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR);
|
||||
dev_priv->saveRSTDBYCTL = I915_READ(RSTDBYCTL);
|
||||
} else {
|
||||
dev_priv->saveIER = I915_READ(IER);
|
||||
dev_priv->saveIMR = I915_READ(IMR);
|
||||
}
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_disable_drps(dev);
|
||||
|
||||
/* Cache mode state */
|
||||
dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
|
||||
|
||||
@ -820,6 +825,9 @@ int i915_restore_state(struct drm_device *dev)
|
||||
/* Clock gating state */
|
||||
intel_init_clock_gating(dev);
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_enable_drps(dev);
|
||||
|
||||
/* Cache mode state */
|
||||
I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
|
||||
|
||||
|
@ -4616,6 +4616,91 @@ err_unref:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ironlake_enable_drps(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 rgvmodectl = I915_READ(MEMMODECTL), rgvswctl;
|
||||
u8 fmax, fmin, fstart, vstart;
|
||||
int i = 0;
|
||||
|
||||
/* 100ms RC evaluation intervals */
|
||||
I915_WRITE(RCUPEI, 100000);
|
||||
I915_WRITE(RCDNEI, 100000);
|
||||
|
||||
/* Set max/min thresholds to 90ms and 80ms respectively */
|
||||
I915_WRITE(RCBMAXAVG, 90000);
|
||||
I915_WRITE(RCBMINAVG, 80000);
|
||||
|
||||
I915_WRITE(MEMIHYST, 1);
|
||||
|
||||
/* Set up min, max, and cur for interrupt handling */
|
||||
fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
|
||||
fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
|
||||
fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
|
||||
MEMMODE_FSTART_SHIFT;
|
||||
vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
|
||||
PXVFREQ_PX_SHIFT;
|
||||
|
||||
dev_priv->max_delay = fstart; /* can't go to fmax w/o IPS */
|
||||
dev_priv->min_delay = fmin;
|
||||
dev_priv->cur_delay = fstart;
|
||||
|
||||
I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
|
||||
|
||||
/*
|
||||
* Interrupts will be enabled in ironlake_irq_postinstall
|
||||
*/
|
||||
|
||||
I915_WRITE(VIDSTART, vstart);
|
||||
POSTING_READ(VIDSTART);
|
||||
|
||||
rgvmodectl |= MEMMODE_SWMODE_EN;
|
||||
I915_WRITE(MEMMODECTL, rgvmodectl);
|
||||
|
||||
while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) {
|
||||
if (i++ > 100) {
|
||||
DRM_ERROR("stuck trying to change perf mode\n");
|
||||
break;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
msleep(1);
|
||||
|
||||
rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
|
||||
(fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
POSTING_READ(MEMSWCTL);
|
||||
|
||||
rgvswctl |= MEMCTL_CMD_STS;
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
}
|
||||
|
||||
void ironlake_disable_drps(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 rgvswctl;
|
||||
u8 fstart;
|
||||
|
||||
/* Ack interrupts, disable EFC interrupt */
|
||||
I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
|
||||
I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
|
||||
I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
|
||||
I915_WRITE(DEIIR, DE_PCU_EVENT);
|
||||
I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
|
||||
|
||||
/* Go back to the starting frequency */
|
||||
fstart = (I915_READ(MEMMODECTL) & MEMMODE_FSTART_MASK) >>
|
||||
MEMMODE_FSTART_SHIFT;
|
||||
rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
|
||||
(fstart << MEMCTL_FREQ_SHIFT);
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
msleep(1);
|
||||
rgvswctl |= MEMCTL_CMD_STS;
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
msleep(1);
|
||||
|
||||
}
|
||||
|
||||
void intel_init_clock_gating(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
@ -4685,8 +4770,8 @@ void intel_init_clock_gating(struct drm_device *dev)
|
||||
|
||||
if (obj_priv) {
|
||||
I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN);
|
||||
I915_WRITE(MCHBAR_RENDER_STANDBY,
|
||||
I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT);
|
||||
I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) &
|
||||
~RCX_SW_EXIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4799,11 +4884,6 @@ void intel_modeset_init(struct drm_device *dev)
|
||||
DRM_DEBUG_KMS("%d display pipe%s available.\n",
|
||||
num_pipe, num_pipe > 1 ? "s" : "");
|
||||
|
||||
if (IS_I85X(dev))
|
||||
pci_read_config_word(dev->pdev, HPLLCC, &dev_priv->orig_clock);
|
||||
else if (IS_I9XX(dev) || IS_G4X(dev))
|
||||
pci_read_config_word(dev->pdev, GCFGC, &dev_priv->orig_clock);
|
||||
|
||||
for (i = 0; i < num_pipe; i++) {
|
||||
intel_crtc_init(dev, i);
|
||||
}
|
||||
@ -4812,6 +4892,9 @@ void intel_modeset_init(struct drm_device *dev)
|
||||
|
||||
intel_init_clock_gating(dev);
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_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);
|
||||
@ -4859,6 +4942,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
|
||||
drm_gem_object_unreference(dev_priv->pwrctx);
|
||||
}
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_disable_drps(dev);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_mode_config_cleanup(dev);
|
||||
|
@ -209,6 +209,8 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
|
||||
extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
|
||||
u16 *blue, int regno);
|
||||
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 int intel_framebuffer_create(struct drm_device *dev,
|
||||
struct drm_mode_fb_cmd *mode_cmd,
|
||||
|
Loading…
Reference in New Issue
Block a user