aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2010-05-20 17:28:11 -0400
committerEric Anholt <eric@anholt.net>2010-05-26 17:10:01 -0400
commit7648fa99eb77a2e1a90b7beaa420e07d819b9c11 (patch)
tree29991eba782a22922441813dcc3a5cbde8377119 /drivers/gpu/drm/i915/intel_display.c
parent7a772c492fcfffae812ffca78a628e76fa57fe58 (diff)
drm/i915: add power monitoring support
Add power monitoring support to the i915 driver for use by the IPS driver. Export the available power info to the IPS driver through a few new inter-driver hooks. When used together, the IPS driver and this patch can significantly increase graphics performance on Ironlake class chips. Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> [anholt: Fixed 32-bit compile. stupid obfuscating div_u64()] Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c147
1 files changed, 131 insertions, 16 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 4c7c151114f7..e94d1db35364 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4459,6 +4459,8 @@ static void intel_idle_update(struct work_struct *work)
4459 4459
4460 mutex_lock(&dev->struct_mutex); 4460 mutex_lock(&dev->struct_mutex);
4461 4461
4462 i915_update_gfx_val(dev_priv);
4463
4462 if (IS_I945G(dev) || IS_I945GM(dev)) { 4464 if (IS_I945G(dev) || IS_I945GM(dev)) {
4463 DRM_DEBUG_DRIVER("enable memory self refresh on 945\n"); 4465 DRM_DEBUG_DRIVER("enable memory self refresh on 945\n");
4464 I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); 4466 I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
@@ -5045,10 +5047,32 @@ err_unref:
5045 return NULL; 5047 return NULL;
5046} 5048}
5047 5049
5050bool ironlake_set_drps(struct drm_device *dev, u8 val)
5051{
5052 struct drm_i915_private *dev_priv = dev->dev_private;
5053 u16 rgvswctl;
5054
5055 rgvswctl = I915_READ16(MEMSWCTL);
5056 if (rgvswctl & MEMCTL_CMD_STS) {
5057 DRM_DEBUG("gpu busy, RCS change rejected\n");
5058 return false; /* still busy with another command */
5059 }
5060
5061 rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
5062 (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
5063 I915_WRITE16(MEMSWCTL, rgvswctl);
5064 POSTING_READ16(MEMSWCTL);
5065
5066 rgvswctl |= MEMCTL_CMD_STS;
5067 I915_WRITE16(MEMSWCTL, rgvswctl);
5068
5069 return true;
5070}
5071
5048void ironlake_enable_drps(struct drm_device *dev) 5072void ironlake_enable_drps(struct drm_device *dev)
5049{ 5073{
5050 struct drm_i915_private *dev_priv = dev->dev_private; 5074 struct drm_i915_private *dev_priv = dev->dev_private;
5051 u32 rgvmodectl = I915_READ(MEMMODECTL), rgvswctl; 5075 u32 rgvmodectl = I915_READ(MEMMODECTL);
5052 u8 fmax, fmin, fstart, vstart; 5076 u8 fmax, fmin, fstart, vstart;
5053 int i = 0; 5077 int i = 0;
5054 5078
@@ -5067,13 +5091,21 @@ void ironlake_enable_drps(struct drm_device *dev)
5067 fmin = (rgvmodectl & MEMMODE_FMIN_MASK); 5091 fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
5068 fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >> 5092 fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
5069 MEMMODE_FSTART_SHIFT; 5093 MEMMODE_FSTART_SHIFT;
5094 fstart = fmax;
5095
5070 vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> 5096 vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
5071 PXVFREQ_PX_SHIFT; 5097 PXVFREQ_PX_SHIFT;
5072 5098
5073 dev_priv->max_delay = fstart; /* can't go to fmax w/o IPS */ 5099 dev_priv->fmax = fstart; /* IPS callback will increase this */
5100 dev_priv->fstart = fstart;
5101
5102 dev_priv->max_delay = fmax;
5074 dev_priv->min_delay = fmin; 5103 dev_priv->min_delay = fmin;
5075 dev_priv->cur_delay = fstart; 5104 dev_priv->cur_delay = fstart;
5076 5105
5106 DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", fmax, fmin,
5107 fstart);
5108
5077 I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN); 5109 I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
5078 5110
5079 /* 5111 /*
@@ -5095,20 +5127,19 @@ void ironlake_enable_drps(struct drm_device *dev)
5095 } 5127 }
5096 msleep(1); 5128 msleep(1);
5097 5129
5098 rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | 5130 ironlake_set_drps(dev, fstart);
5099 (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
5100 I915_WRITE(MEMSWCTL, rgvswctl);
5101 POSTING_READ(MEMSWCTL);
5102 5131
5103 rgvswctl |= MEMCTL_CMD_STS; 5132 dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
5104 I915_WRITE(MEMSWCTL, rgvswctl); 5133 I915_READ(0x112e0);
5134 dev_priv->last_time1 = jiffies_to_msecs(jiffies);
5135 dev_priv->last_count2 = I915_READ(0x112f4);
5136 getrawmonotonic(&dev_priv->last_time2);
5105} 5137}
5106 5138
5107void ironlake_disable_drps(struct drm_device *dev) 5139void ironlake_disable_drps(struct drm_device *dev)
5108{ 5140{
5109 struct drm_i915_private *dev_priv = dev->dev_private; 5141 struct drm_i915_private *dev_priv = dev->dev_private;
5110 u32 rgvswctl; 5142 u16 rgvswctl = I915_READ16(MEMSWCTL);
5111 u8 fstart;
5112 5143
5113 /* Ack interrupts, disable EFC interrupt */ 5144 /* Ack interrupts, disable EFC interrupt */
5114 I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN); 5145 I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
@@ -5118,11 +5149,7 @@ void ironlake_disable_drps(struct drm_device *dev)
5118 I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT); 5149 I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
5119 5150
5120 /* Go back to the starting frequency */ 5151 /* Go back to the starting frequency */
5121 fstart = (I915_READ(MEMMODECTL) & MEMMODE_FSTART_MASK) >> 5152 ironlake_set_drps(dev, dev_priv->fstart);
5122 MEMMODE_FSTART_SHIFT;
5123 rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
5124 (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
5125 I915_WRITE(MEMSWCTL, rgvswctl);
5126 msleep(1); 5153 msleep(1);
5127 rgvswctl |= MEMCTL_CMD_STS; 5154 rgvswctl |= MEMCTL_CMD_STS;
5128 I915_WRITE(MEMSWCTL, rgvswctl); 5155 I915_WRITE(MEMSWCTL, rgvswctl);
@@ -5130,6 +5157,92 @@ void ironlake_disable_drps(struct drm_device *dev)
5130 5157
5131} 5158}
5132 5159
5160static unsigned long intel_pxfreq(u32 vidfreq)
5161{
5162 unsigned long freq;
5163 int div = (vidfreq & 0x3f0000) >> 16;
5164 int post = (vidfreq & 0x3000) >> 12;
5165 int pre = (vidfreq & 0x7);
5166
5167 if (!pre)
5168 return 0;
5169
5170 freq = ((div * 133333) / ((1<<post) * pre));
5171
5172 return freq;
5173}
5174
5175void intel_init_emon(struct drm_device *dev)
5176{
5177 struct drm_i915_private *dev_priv = dev->dev_private;
5178 u32 lcfuse;
5179 u8 pxw[16];
5180 int i;
5181
5182 /* Disable to program */
5183 I915_WRITE(ECR, 0);
5184 POSTING_READ(ECR);
5185
5186 /* Program energy weights for various events */
5187 I915_WRITE(SDEW, 0x15040d00);
5188 I915_WRITE(CSIEW0, 0x007f0000);
5189 I915_WRITE(CSIEW1, 0x1e220004);
5190 I915_WRITE(CSIEW2, 0x04000004);
5191
5192 for (i = 0; i < 5; i++)
5193 I915_WRITE(PEW + (i * 4), 0);
5194 for (i = 0; i < 3; i++)
5195 I915_WRITE(DEW + (i * 4), 0);
5196
5197 /* Program P-state weights to account for frequency power adjustment */
5198 for (i = 0; i < 16; i++) {
5199 u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4));
5200 unsigned long freq = intel_pxfreq(pxvidfreq);
5201 unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >>
5202 PXVFREQ_PX_SHIFT;
5203 unsigned long val;
5204
5205 val = vid * vid;
5206 val *= (freq / 1000);
5207 val *= 255;
5208 val /= (127*127*900);
5209 if (val > 0xff)
5210 DRM_ERROR("bad pxval: %ld\n", val);
5211 pxw[i] = val;
5212 }
5213 /* Render standby states get 0 weight */
5214 pxw[14] = 0;
5215 pxw[15] = 0;
5216
5217 for (i = 0; i < 4; i++) {
5218 u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) |
5219 (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]);
5220 I915_WRITE(PXW + (i * 4), val);
5221 }
5222
5223 /* Adjust magic regs to magic values (more experimental results) */
5224 I915_WRITE(OGW0, 0);
5225 I915_WRITE(OGW1, 0);
5226 I915_WRITE(EG0, 0x00007f00);
5227 I915_WRITE(EG1, 0x0000000e);
5228 I915_WRITE(EG2, 0x000e0000);
5229 I915_WRITE(EG3, 0x68000300);
5230 I915_WRITE(EG4, 0x42000000);
5231 I915_WRITE(EG5, 0x00140031);
5232 I915_WRITE(EG6, 0);
5233 I915_WRITE(EG7, 0);
5234
5235 for (i = 0; i < 8; i++)
5236 I915_WRITE(PXWL + (i * 4), 0);
5237
5238 /* Enable PMON + select events */
5239 I915_WRITE(ECR, 0x80000019);
5240
5241 lcfuse = I915_READ(LCFUSE02);
5242
5243 dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
5244}
5245
5133void intel_init_clock_gating(struct drm_device *dev) 5246void intel_init_clock_gating(struct drm_device *dev)
5134{ 5247{
5135 struct drm_i915_private *dev_priv = dev->dev_private; 5248 struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5376,8 +5489,10 @@ void intel_modeset_init(struct drm_device *dev)
5376 5489
5377 intel_init_clock_gating(dev); 5490 intel_init_clock_gating(dev);
5378 5491
5379 if (IS_IRONLAKE_M(dev)) 5492 if (IS_IRONLAKE_M(dev)) {
5380 ironlake_enable_drps(dev); 5493 ironlake_enable_drps(dev);
5494 intel_init_emon(dev);
5495 }
5381 5496
5382 INIT_WORK(&dev_priv->idle_work, intel_idle_update); 5497 INIT_WORK(&dev_priv->idle_work, intel_idle_update);
5383 setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, 5498 setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,