aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/gma500/cdv_device.c169
-rw-r--r--drivers/gpu/drm/gma500/power.c3
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.h20
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_reg.h9
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
213static void cdv_init_pm(struct drm_device *dev) 212static 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 */
255static int cdv_save_display_registers(struct drm_device *dev) 248static 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, &regs->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 */
268static int cdv_restore_display_registers(struct drm_device *dev) 302static 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
273static int cdv_power_down(struct drm_device *dev) 370static 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
278static int cdv_power_up(struct drm_device *dev) 392static 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
301int psb_runtime_resume(struct device *dev) 302int psb_runtime_resume(struct device *dev)
302{ 303{
303 return gma_power_resume(dev);; 304 return gma_power_resume(dev);
304} 305}
305 306
306int psb_runtime_idle(struct device *dev) 307int 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
459struct 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
459struct psb_save_area { 478struct 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 */