diff options
author | Alan Cox <alan@linux.intel.com> | 2012-03-14 08:00:29 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-03-15 05:46:22 -0400 |
commit | 09016a11fc738e82ca1303e2332473b517bbd660 (patch) | |
tree | e347502a2cec3008c8a17269f9bee34c9509be1c | |
parent | 50d44a523759c39af1119285a5396ca387288af0 (diff) |
gma500: suspend/resume support for Cedartrail
Update our tree to match the current driver head.
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/gma500/cdv_device.c | 169 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/power.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/psb_drv.h | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/psb_intel_reg.h | 9 |
4 files changed, 181 insertions, 20 deletions
diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c index 4a5b099c3bc5..eefcef6fa32f 100644 --- a/drivers/gpu/drm/gma500/cdv_device.c +++ b/drivers/gpu/drm/gma500/cdv_device.c | |||
@@ -202,13 +202,12 @@ static inline void CDV_MSG_WRITE32(uint port, uint offset, u32 value) | |||
202 | pci_dev_put(pci_root); | 202 | pci_dev_put(pci_root); |
203 | } | 203 | } |
204 | 204 | ||
205 | #define PSB_APM_CMD 0x0 | ||
206 | #define PSB_APM_STS 0x04 | ||
207 | #define PSB_PM_SSC 0x20 | 205 | #define PSB_PM_SSC 0x20 |
208 | #define PSB_PM_SSS 0x30 | 206 | #define PSB_PM_SSS 0x30 |
209 | #define PSB_PWRGT_GFX_MASK 0x3 | 207 | #define PSB_PWRGT_GFX_ON 0x02 |
210 | #define CDV_PWRGT_DISPLAY_CNTR 0x000fc00c | 208 | #define PSB_PWRGT_GFX_OFF 0x01 |
211 | #define CDV_PWRGT_DISPLAY_STS 0x000fc00c | 209 | #define PSB_PWRGT_GFX_D0 0x00 |
210 | #define PSB_PWRGT_GFX_D3 0x03 | ||
212 | 211 | ||
213 | static void cdv_init_pm(struct drm_device *dev) | 212 | static void cdv_init_pm(struct drm_device *dev) |
214 | { | 213 | { |
@@ -221,26 +220,22 @@ static void cdv_init_pm(struct drm_device *dev) | |||
221 | dev_priv->ospm_base = CDV_MSG_READ32(PSB_PUNIT_PORT, | 220 | dev_priv->ospm_base = CDV_MSG_READ32(PSB_PUNIT_PORT, |
222 | PSB_OSPMBA) & 0xFFFF; | 221 | PSB_OSPMBA) & 0xFFFF; |
223 | 222 | ||
224 | /* Force power on for now */ | 223 | /* Power status */ |
225 | pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD); | 224 | pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD); |
226 | pwr_cnt &= ~PSB_PWRGT_GFX_MASK; | ||
227 | 225 | ||
226 | /* Enable the GPU */ | ||
227 | pwr_cnt &= ~PSB_PWRGT_GFX_MASK; | ||
228 | pwr_cnt |= PSB_PWRGT_GFX_ON; | ||
228 | outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD); | 229 | outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD); |
230 | |||
231 | /* Wait for the GPU power */ | ||
229 | for (i = 0; i < 5; i++) { | 232 | for (i = 0; i < 5; i++) { |
230 | u32 pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS); | 233 | u32 pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS); |
231 | if ((pwr_sts & PSB_PWRGT_GFX_MASK) == 0) | 234 | if ((pwr_sts & PSB_PWRGT_GFX_MASK) == 0) |
232 | break; | 235 | return; |
233 | udelay(10); | ||
234 | } | ||
235 | pwr_cnt = inl(dev_priv->ospm_base + PSB_PM_SSC); | ||
236 | pwr_cnt &= ~CDV_PWRGT_DISPLAY_CNTR; | ||
237 | outl(pwr_cnt, dev_priv->ospm_base + PSB_PM_SSC); | ||
238 | for (i = 0; i < 5; i++) { | ||
239 | u32 pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS); | ||
240 | if ((pwr_sts & CDV_PWRGT_DISPLAY_STS) == 0) | ||
241 | break; | ||
242 | udelay(10); | 236 | udelay(10); |
243 | } | 237 | } |
238 | dev_err(dev->dev, "GPU: power management timed out.\n"); | ||
244 | } | 239 | } |
245 | 240 | ||
246 | /** | 241 | /** |
@@ -249,11 +244,50 @@ static void cdv_init_pm(struct drm_device *dev) | |||
249 | * | 244 | * |
250 | * Save the state we need in order to be able to restore the interface | 245 | * Save the state we need in order to be able to restore the interface |
251 | * upon resume from suspend | 246 | * upon resume from suspend |
252 | * | ||
253 | * FIXME: review | ||
254 | */ | 247 | */ |
255 | static int cdv_save_display_registers(struct drm_device *dev) | 248 | static int cdv_save_display_registers(struct drm_device *dev) |
256 | { | 249 | { |
250 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
251 | struct psb_save_area *regs = &dev_priv->regs; | ||
252 | struct drm_connector *connector; | ||
253 | |||
254 | dev_info(dev->dev, "Saving GPU registers.\n"); | ||
255 | |||
256 | pci_read_config_byte(dev->pdev, 0xF4, ®s->cdv.saveLBB); | ||
257 | |||
258 | regs->cdv.saveDSPCLK_GATE_D = REG_READ(DSPCLK_GATE_D); | ||
259 | regs->cdv.saveRAMCLK_GATE_D = REG_READ(RAMCLK_GATE_D); | ||
260 | |||
261 | regs->cdv.saveDSPARB = REG_READ(DSPARB); | ||
262 | regs->cdv.saveDSPFW[0] = REG_READ(DSPFW1); | ||
263 | regs->cdv.saveDSPFW[1] = REG_READ(DSPFW2); | ||
264 | regs->cdv.saveDSPFW[2] = REG_READ(DSPFW3); | ||
265 | regs->cdv.saveDSPFW[3] = REG_READ(DSPFW4); | ||
266 | regs->cdv.saveDSPFW[4] = REG_READ(DSPFW5); | ||
267 | regs->cdv.saveDSPFW[5] = REG_READ(DSPFW6); | ||
268 | |||
269 | regs->cdv.saveADPA = REG_READ(ADPA); | ||
270 | |||
271 | regs->cdv.savePP_CONTROL = REG_READ(PP_CONTROL); | ||
272 | regs->cdv.savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS); | ||
273 | regs->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); | ||
274 | regs->saveBLC_PWM_CTL2 = REG_READ(BLC_PWM_CTL2); | ||
275 | regs->cdv.saveLVDS = REG_READ(LVDS); | ||
276 | |||
277 | regs->cdv.savePFIT_CONTROL = REG_READ(PFIT_CONTROL); | ||
278 | |||
279 | regs->cdv.savePP_ON_DELAYS = REG_READ(PP_ON_DELAYS); | ||
280 | regs->cdv.savePP_OFF_DELAYS = REG_READ(PP_OFF_DELAYS); | ||
281 | regs->cdv.savePP_CYCLE = REG_READ(PP_CYCLE); | ||
282 | |||
283 | regs->cdv.saveVGACNTRL = REG_READ(VGACNTRL); | ||
284 | |||
285 | regs->cdv.saveIER = REG_READ(PSB_INT_ENABLE_R); | ||
286 | regs->cdv.saveIMR = REG_READ(PSB_INT_MASK_R); | ||
287 | |||
288 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) | ||
289 | connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF); | ||
290 | |||
257 | return 0; | 291 | return 0; |
258 | } | 292 | } |
259 | 293 | ||
@@ -267,16 +301,113 @@ static int cdv_save_display_registers(struct drm_device *dev) | |||
267 | */ | 301 | */ |
268 | static int cdv_restore_display_registers(struct drm_device *dev) | 302 | static int cdv_restore_display_registers(struct drm_device *dev) |
269 | { | 303 | { |
304 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
305 | struct psb_save_area *regs = &dev_priv->regs; | ||
306 | struct drm_connector *connector; | ||
307 | u32 temp; | ||
308 | |||
309 | pci_write_config_byte(dev->pdev, 0xF4, regs->cdv.saveLBB); | ||
310 | |||
311 | REG_WRITE(DSPCLK_GATE_D, regs->cdv.saveDSPCLK_GATE_D); | ||
312 | REG_WRITE(RAMCLK_GATE_D, regs->cdv.saveRAMCLK_GATE_D); | ||
313 | |||
314 | /* BIOS does below anyway */ | ||
315 | REG_WRITE(DPIO_CFG, 0); | ||
316 | REG_WRITE(DPIO_CFG, DPIO_MODE_SELECT_0 | DPIO_CMN_RESET_N); | ||
317 | |||
318 | temp = REG_READ(DPLL_A); | ||
319 | if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) { | ||
320 | REG_WRITE(DPLL_A, temp | DPLL_SYNCLOCK_ENABLE); | ||
321 | REG_READ(DPLL_A); | ||
322 | } | ||
323 | |||
324 | temp = REG_READ(DPLL_B); | ||
325 | if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) { | ||
326 | REG_WRITE(DPLL_B, temp | DPLL_SYNCLOCK_ENABLE); | ||
327 | REG_READ(DPLL_B); | ||
328 | } | ||
329 | |||
330 | udelay(500); | ||
331 | |||
332 | REG_WRITE(DSPFW1, regs->cdv.saveDSPFW[0]); | ||
333 | REG_WRITE(DSPFW2, regs->cdv.saveDSPFW[1]); | ||
334 | REG_WRITE(DSPFW3, regs->cdv.saveDSPFW[2]); | ||
335 | REG_WRITE(DSPFW4, regs->cdv.saveDSPFW[3]); | ||
336 | REG_WRITE(DSPFW5, regs->cdv.saveDSPFW[4]); | ||
337 | REG_WRITE(DSPFW6, regs->cdv.saveDSPFW[5]); | ||
338 | |||
339 | REG_WRITE(DSPARB, regs->cdv.saveDSPARB); | ||
340 | REG_WRITE(ADPA, regs->cdv.saveADPA); | ||
341 | |||
342 | REG_WRITE(BLC_PWM_CTL2, regs->saveBLC_PWM_CTL2); | ||
343 | REG_WRITE(LVDS, regs->cdv.saveLVDS); | ||
344 | REG_WRITE(PFIT_CONTROL, regs->cdv.savePFIT_CONTROL); | ||
345 | REG_WRITE(PFIT_PGM_RATIOS, regs->cdv.savePFIT_PGM_RATIOS); | ||
346 | REG_WRITE(BLC_PWM_CTL, regs->saveBLC_PWM_CTL); | ||
347 | REG_WRITE(PP_ON_DELAYS, regs->cdv.savePP_ON_DELAYS); | ||
348 | REG_WRITE(PP_OFF_DELAYS, regs->cdv.savePP_OFF_DELAYS); | ||
349 | REG_WRITE(PP_CYCLE, regs->cdv.savePP_CYCLE); | ||
350 | REG_WRITE(PP_CONTROL, regs->cdv.savePP_CONTROL); | ||
351 | |||
352 | REG_WRITE(VGACNTRL, regs->cdv.saveVGACNTRL); | ||
353 | |||
354 | REG_WRITE(PSB_INT_ENABLE_R, regs->cdv.saveIER); | ||
355 | REG_WRITE(PSB_INT_MASK_R, regs->cdv.saveIMR); | ||
356 | |||
357 | /* Fix arbitration bug */ | ||
358 | CDV_MSG_WRITE32(3, 0x30, 0x08027108); | ||
359 | |||
360 | drm_mode_config_reset(dev); | ||
361 | |||
362 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) | ||
363 | connector->funcs->dpms(connector, DRM_MODE_DPMS_ON); | ||
364 | |||
365 | /* Resume the modeset for every activated CRTC */ | ||
366 | drm_helper_resume_force_mode(dev); | ||
270 | return 0; | 367 | return 0; |
271 | } | 368 | } |
272 | 369 | ||
273 | static int cdv_power_down(struct drm_device *dev) | 370 | static int cdv_power_down(struct drm_device *dev) |
274 | { | 371 | { |
372 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
373 | u32 pwr_cnt, pwr_mask, pwr_sts; | ||
374 | int tries = 5; | ||
375 | |||
376 | pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD); | ||
377 | pwr_cnt &= ~PSB_PWRGT_GFX_MASK; | ||
378 | pwr_cnt |= PSB_PWRGT_GFX_OFF; | ||
379 | pwr_mask = PSB_PWRGT_GFX_MASK; | ||
380 | |||
381 | outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD); | ||
382 | |||
383 | while (tries--) { | ||
384 | pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS); | ||
385 | if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D3) | ||
386 | return 0; | ||
387 | udelay(10); | ||
388 | } | ||
275 | return 0; | 389 | return 0; |
276 | } | 390 | } |
277 | 391 | ||
278 | static int cdv_power_up(struct drm_device *dev) | 392 | static int cdv_power_up(struct drm_device *dev) |
279 | { | 393 | { |
394 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
395 | u32 pwr_cnt, pwr_mask, pwr_sts; | ||
396 | int tries = 5; | ||
397 | |||
398 | pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD); | ||
399 | pwr_cnt &= ~PSB_PWRGT_GFX_MASK; | ||
400 | pwr_cnt |= PSB_PWRGT_GFX_ON; | ||
401 | pwr_mask = PSB_PWRGT_GFX_MASK; | ||
402 | |||
403 | outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD); | ||
404 | |||
405 | while (tries--) { | ||
406 | pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS); | ||
407 | if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D0) | ||
408 | return 0; | ||
409 | udelay(10); | ||
410 | } | ||
280 | return 0; | 411 | return 0; |
281 | } | 412 | } |
282 | 413 | ||
diff --git a/drivers/gpu/drm/gma500/power.c b/drivers/gpu/drm/gma500/power.c index 8d23c45b5bc6..889b854751da 100644 --- a/drivers/gpu/drm/gma500/power.c +++ b/drivers/gpu/drm/gma500/power.c | |||
@@ -193,6 +193,7 @@ int gma_power_suspend(struct device *_dev) | |||
193 | if (!dev_priv->suspended) { | 193 | if (!dev_priv->suspended) { |
194 | if (dev_priv->display_count) { | 194 | if (dev_priv->display_count) { |
195 | mutex_unlock(&power_mutex); | 195 | mutex_unlock(&power_mutex); |
196 | dev_err(dev->dev, "GPU hardware busy, cannot suspend\n"); | ||
196 | return -EBUSY; | 197 | return -EBUSY; |
197 | } | 198 | } |
198 | psb_irq_uninstall(dev); | 199 | psb_irq_uninstall(dev); |
@@ -300,7 +301,7 @@ int psb_runtime_suspend(struct device *dev) | |||
300 | 301 | ||
301 | int psb_runtime_resume(struct device *dev) | 302 | int psb_runtime_resume(struct device *dev) |
302 | { | 303 | { |
303 | return gma_power_resume(dev);; | 304 | return gma_power_resume(dev); |
304 | } | 305 | } |
305 | 306 | ||
306 | int psb_runtime_idle(struct device *dev) | 307 | int psb_runtime_idle(struct device *dev) |
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index af1c99752000..40ce2c9bc2e4 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h | |||
@@ -456,12 +456,32 @@ struct medfield_state { | |||
456 | uint32_t saveHDMIB_CONTROL; | 456 | uint32_t saveHDMIB_CONTROL; |
457 | }; | 457 | }; |
458 | 458 | ||
459 | struct cdv_state { | ||
460 | uint32_t saveDSPCLK_GATE_D; | ||
461 | uint32_t saveRAMCLK_GATE_D; | ||
462 | uint32_t saveDSPARB; | ||
463 | uint32_t saveDSPFW[6]; | ||
464 | uint32_t saveADPA; | ||
465 | uint32_t savePP_CONTROL; | ||
466 | uint32_t savePFIT_PGM_RATIOS; | ||
467 | uint32_t saveLVDS; | ||
468 | uint32_t savePFIT_CONTROL; | ||
469 | uint32_t savePP_ON_DELAYS; | ||
470 | uint32_t savePP_OFF_DELAYS; | ||
471 | uint32_t savePP_CYCLE; | ||
472 | uint32_t saveVGACNTRL; | ||
473 | uint32_t saveIER; | ||
474 | uint32_t saveIMR; | ||
475 | u8 saveLBB; | ||
476 | }; | ||
477 | |||
459 | struct psb_save_area { | 478 | struct psb_save_area { |
460 | uint32_t saveBSM; | 479 | uint32_t saveBSM; |
461 | uint32_t saveVBT; | 480 | uint32_t saveVBT; |
462 | union { | 481 | union { |
463 | struct psb_state psb; | 482 | struct psb_state psb; |
464 | struct medfield_state mdfld; | 483 | struct medfield_state mdfld; |
484 | struct cdv_state cdv; | ||
465 | }; | 485 | }; |
466 | uint32_t saveBLC_PWM_CTL2; | 486 | uint32_t saveBLC_PWM_CTL2; |
467 | uint32_t saveBLC_PWM_CTL; | 487 | uint32_t saveBLC_PWM_CTL; |
diff --git a/drivers/gpu/drm/gma500/psb_intel_reg.h b/drivers/gpu/drm/gma500/psb_intel_reg.h index fcc0af03d685..e89d3a2e8fdc 100644 --- a/drivers/gpu/drm/gma500/psb_intel_reg.h +++ b/drivers/gpu/drm/gma500/psb_intel_reg.h | |||
@@ -177,6 +177,9 @@ | |||
177 | #define LVDSPP_OFF 0x6120c | 177 | #define LVDSPP_OFF 0x6120c |
178 | #define PP_CYCLE 0x61210 | 178 | #define PP_CYCLE 0x61210 |
179 | 179 | ||
180 | #define PP_ON_DELAYS 0x61208 /* Cedartrail */ | ||
181 | #define PP_OFF_DELAYS 0x6120c /* Cedartrail */ | ||
182 | |||
180 | #define PFIT_CONTROL 0x61230 | 183 | #define PFIT_CONTROL 0x61230 |
181 | #define PFIT_ENABLE (1 << 31) | 184 | #define PFIT_ENABLE (1 << 31) |
182 | #define PFIT_PIPE_MASK (3 << 29) | 185 | #define PFIT_PIPE_MASK (3 << 29) |
@@ -1252,6 +1255,12 @@ No status bits are changed. | |||
1252 | # define SB_BYTE_ENABLE_SHIFT 4 | 1255 | # define SB_BYTE_ENABLE_SHIFT 4 |
1253 | # define SB_BUSY (1 << 0) | 1256 | # define SB_BUSY (1 << 0) |
1254 | 1257 | ||
1258 | #define DSPCLK_GATE_D 0x6200 | ||
1259 | # define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* Fixed value on CDV */ | ||
1260 | # define DPOUNIT_CLOCK_GATE_DISABLE (1 << 11) | ||
1261 | # define DPIOUNIT_CLOCK_GATE_DISABLE (1 << 6) | ||
1262 | |||
1263 | #define RAMCLK_GATE_D 0x6210 | ||
1255 | 1264 | ||
1256 | /* 32-bit value read/written from the DPIO reg. */ | 1265 | /* 32-bit value read/written from the DPIO reg. */ |
1257 | #define SB_DATA 0x02104 /* cedarview */ | 1266 | #define SB_DATA 0x02104 /* cedarview */ |