diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_drv.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 176 |
1 files changed, 108 insertions, 68 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index be631cc3e4dc..79beffcf5936 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -45,6 +45,9 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); | |||
45 | unsigned int i915_powersave = 1; | 45 | unsigned int i915_powersave = 1; |
46 | module_param_named(powersave, i915_powersave, int, 0400); | 46 | module_param_named(powersave, i915_powersave, int, 0400); |
47 | 47 | ||
48 | unsigned int i915_lvds_downclock = 0; | ||
49 | module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); | ||
50 | |||
48 | static struct drm_driver driver; | 51 | static struct drm_driver driver; |
49 | 52 | ||
50 | #define INTEL_VGA_DEVICE(id, info) { \ | 53 | #define INTEL_VGA_DEVICE(id, info) { \ |
@@ -117,7 +120,7 @@ const static struct intel_device_info intel_gm45_info = { | |||
117 | 120 | ||
118 | const static struct intel_device_info intel_pineview_info = { | 121 | const static struct intel_device_info intel_pineview_info = { |
119 | .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1, | 122 | .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1, |
120 | .has_pipe_cxsr = 1, | 123 | .need_gfx_hws = 1, |
121 | .has_hotplug = 1, | 124 | .has_hotplug = 1, |
122 | }; | 125 | }; |
123 | 126 | ||
@@ -171,78 +174,100 @@ const static struct pci_device_id pciidlist[] = { | |||
171 | MODULE_DEVICE_TABLE(pci, pciidlist); | 174 | MODULE_DEVICE_TABLE(pci, pciidlist); |
172 | #endif | 175 | #endif |
173 | 176 | ||
174 | static int i915_suspend(struct drm_device *dev, pm_message_t state) | 177 | static int i915_drm_freeze(struct drm_device *dev) |
175 | { | 178 | { |
176 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
177 | |||
178 | if (!dev || !dev_priv) { | ||
179 | DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv); | ||
180 | DRM_ERROR("DRM not initialized, aborting suspend.\n"); | ||
181 | return -ENODEV; | ||
182 | } | ||
183 | |||
184 | if (state.event == PM_EVENT_PRETHAW) | ||
185 | return 0; | ||
186 | |||
187 | pci_save_state(dev->pdev); | 179 | pci_save_state(dev->pdev); |
188 | 180 | ||
189 | /* If KMS is active, we do the leavevt stuff here */ | 181 | /* If KMS is active, we do the leavevt stuff here */ |
190 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | 182 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
191 | if (i915_gem_idle(dev)) | 183 | int error = i915_gem_idle(dev); |
184 | if (error) { | ||
192 | dev_err(&dev->pdev->dev, | 185 | dev_err(&dev->pdev->dev, |
193 | "GEM idle failed, resume may fail\n"); | 186 | "GEM idle failed, resume might fail\n"); |
187 | return error; | ||
188 | } | ||
194 | drm_irq_uninstall(dev); | 189 | drm_irq_uninstall(dev); |
195 | } | 190 | } |
196 | 191 | ||
197 | i915_save_state(dev); | 192 | i915_save_state(dev); |
198 | 193 | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static void i915_drm_suspend(struct drm_device *dev) | ||
198 | { | ||
199 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
200 | |||
199 | intel_opregion_free(dev, 1); | 201 | intel_opregion_free(dev, 1); |
200 | 202 | ||
203 | /* Modeset on resume, not lid events */ | ||
204 | dev_priv->modeset_on_lid = 0; | ||
205 | } | ||
206 | |||
207 | static int i915_suspend(struct drm_device *dev, pm_message_t state) | ||
208 | { | ||
209 | int error; | ||
210 | |||
211 | if (!dev || !dev->dev_private) { | ||
212 | DRM_ERROR("dev: %p\n", dev); | ||
213 | DRM_ERROR("DRM not initialized, aborting suspend.\n"); | ||
214 | return -ENODEV; | ||
215 | } | ||
216 | |||
217 | if (state.event == PM_EVENT_PRETHAW) | ||
218 | return 0; | ||
219 | |||
220 | error = i915_drm_freeze(dev); | ||
221 | if (error) | ||
222 | return error; | ||
223 | |||
224 | i915_drm_suspend(dev); | ||
225 | |||
201 | if (state.event == PM_EVENT_SUSPEND) { | 226 | if (state.event == PM_EVENT_SUSPEND) { |
202 | /* Shut down the device */ | 227 | /* Shut down the device */ |
203 | pci_disable_device(dev->pdev); | 228 | pci_disable_device(dev->pdev); |
204 | pci_set_power_state(dev->pdev, PCI_D3hot); | 229 | pci_set_power_state(dev->pdev, PCI_D3hot); |
205 | } | 230 | } |
206 | 231 | ||
207 | /* Modeset on resume, not lid events */ | ||
208 | dev_priv->modeset_on_lid = 0; | ||
209 | |||
210 | return 0; | 232 | return 0; |
211 | } | 233 | } |
212 | 234 | ||
213 | static int i915_resume(struct drm_device *dev) | 235 | static int i915_drm_thaw(struct drm_device *dev) |
214 | { | 236 | { |
215 | struct drm_i915_private *dev_priv = dev->dev_private; | 237 | struct drm_i915_private *dev_priv = dev->dev_private; |
216 | int ret = 0; | 238 | int error = 0; |
217 | |||
218 | if (pci_enable_device(dev->pdev)) | ||
219 | return -1; | ||
220 | pci_set_master(dev->pdev); | ||
221 | |||
222 | i915_restore_state(dev); | ||
223 | |||
224 | intel_opregion_init(dev, 1); | ||
225 | 239 | ||
226 | /* KMS EnterVT equivalent */ | 240 | /* KMS EnterVT equivalent */ |
227 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | 241 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
228 | mutex_lock(&dev->struct_mutex); | 242 | mutex_lock(&dev->struct_mutex); |
229 | dev_priv->mm.suspended = 0; | 243 | dev_priv->mm.suspended = 0; |
230 | 244 | ||
231 | ret = i915_gem_init_ringbuffer(dev); | 245 | error = i915_gem_init_ringbuffer(dev); |
232 | if (ret != 0) | ||
233 | ret = -1; | ||
234 | mutex_unlock(&dev->struct_mutex); | 246 | mutex_unlock(&dev->struct_mutex); |
235 | 247 | ||
236 | drm_irq_install(dev); | 248 | drm_irq_install(dev); |
237 | } | 249 | |
238 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
239 | /* Resume the modeset for every activated CRTC */ | 250 | /* Resume the modeset for every activated CRTC */ |
240 | drm_helper_resume_force_mode(dev); | 251 | drm_helper_resume_force_mode(dev); |
241 | } | 252 | } |
242 | 253 | ||
243 | dev_priv->modeset_on_lid = 0; | 254 | dev_priv->modeset_on_lid = 0; |
244 | 255 | ||
245 | return ret; | 256 | return error; |
257 | } | ||
258 | |||
259 | static int i915_resume(struct drm_device *dev) | ||
260 | { | ||
261 | if (pci_enable_device(dev->pdev)) | ||
262 | return -EIO; | ||
263 | |||
264 | pci_set_master(dev->pdev); | ||
265 | |||
266 | i915_restore_state(dev); | ||
267 | |||
268 | intel_opregion_init(dev, 1); | ||
269 | |||
270 | return i915_drm_thaw(dev); | ||
246 | } | 271 | } |
247 | 272 | ||
248 | /** | 273 | /** |
@@ -383,57 +408,69 @@ i915_pci_remove(struct pci_dev *pdev) | |||
383 | drm_put_dev(dev); | 408 | drm_put_dev(dev); |
384 | } | 409 | } |
385 | 410 | ||
386 | static int | 411 | static int i915_pm_suspend(struct device *dev) |
387 | i915_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
388 | { | 412 | { |
389 | struct drm_device *dev = pci_get_drvdata(pdev); | 413 | struct pci_dev *pdev = to_pci_dev(dev); |
414 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
415 | int error; | ||
390 | 416 | ||
391 | return i915_suspend(dev, state); | 417 | if (!drm_dev || !drm_dev->dev_private) { |
392 | } | 418 | dev_err(dev, "DRM not initialized, aborting suspend.\n"); |
419 | return -ENODEV; | ||
420 | } | ||
393 | 421 | ||
394 | static int | 422 | error = i915_drm_freeze(drm_dev); |
395 | i915_pci_resume(struct pci_dev *pdev) | 423 | if (error) |
396 | { | 424 | return error; |
397 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
398 | 425 | ||
399 | return i915_resume(dev); | 426 | i915_drm_suspend(drm_dev); |
400 | } | ||
401 | 427 | ||
402 | static int | 428 | pci_disable_device(pdev); |
403 | i915_pm_suspend(struct device *dev) | 429 | pci_set_power_state(pdev, PCI_D3hot); |
404 | { | ||
405 | return i915_pci_suspend(to_pci_dev(dev), PMSG_SUSPEND); | ||
406 | } | ||
407 | 430 | ||
408 | static int | 431 | return 0; |
409 | i915_pm_resume(struct device *dev) | ||
410 | { | ||
411 | return i915_pci_resume(to_pci_dev(dev)); | ||
412 | } | 432 | } |
413 | 433 | ||
414 | static int | 434 | static int i915_pm_resume(struct device *dev) |
415 | i915_pm_freeze(struct device *dev) | ||
416 | { | 435 | { |
417 | return i915_pci_suspend(to_pci_dev(dev), PMSG_FREEZE); | 436 | struct pci_dev *pdev = to_pci_dev(dev); |
437 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
438 | |||
439 | return i915_resume(drm_dev); | ||
418 | } | 440 | } |
419 | 441 | ||
420 | static int | 442 | static int i915_pm_freeze(struct device *dev) |
421 | i915_pm_thaw(struct device *dev) | ||
422 | { | 443 | { |
423 | /* thaw during hibernate, do nothing! */ | 444 | struct pci_dev *pdev = to_pci_dev(dev); |
424 | return 0; | 445 | struct drm_device *drm_dev = pci_get_drvdata(pdev); |
446 | |||
447 | if (!drm_dev || !drm_dev->dev_private) { | ||
448 | dev_err(dev, "DRM not initialized, aborting suspend.\n"); | ||
449 | return -ENODEV; | ||
450 | } | ||
451 | |||
452 | return i915_drm_freeze(drm_dev); | ||
425 | } | 453 | } |
426 | 454 | ||
427 | static int | 455 | static int i915_pm_thaw(struct device *dev) |
428 | i915_pm_poweroff(struct device *dev) | ||
429 | { | 456 | { |
430 | return i915_pci_suspend(to_pci_dev(dev), PMSG_HIBERNATE); | 457 | struct pci_dev *pdev = to_pci_dev(dev); |
458 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
459 | |||
460 | return i915_drm_thaw(drm_dev); | ||
431 | } | 461 | } |
432 | 462 | ||
433 | static int | 463 | static int i915_pm_poweroff(struct device *dev) |
434 | i915_pm_restore(struct device *dev) | ||
435 | { | 464 | { |
436 | return i915_pci_resume(to_pci_dev(dev)); | 465 | struct pci_dev *pdev = to_pci_dev(dev); |
466 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
467 | int error; | ||
468 | |||
469 | error = i915_drm_freeze(drm_dev); | ||
470 | if (!error) | ||
471 | i915_drm_suspend(drm_dev); | ||
472 | |||
473 | return error; | ||
437 | } | 474 | } |
438 | 475 | ||
439 | const struct dev_pm_ops i915_pm_ops = { | 476 | const struct dev_pm_ops i915_pm_ops = { |
@@ -442,7 +479,7 @@ const struct dev_pm_ops i915_pm_ops = { | |||
442 | .freeze = i915_pm_freeze, | 479 | .freeze = i915_pm_freeze, |
443 | .thaw = i915_pm_thaw, | 480 | .thaw = i915_pm_thaw, |
444 | .poweroff = i915_pm_poweroff, | 481 | .poweroff = i915_pm_poweroff, |
445 | .restore = i915_pm_restore, | 482 | .restore = i915_pm_resume, |
446 | }; | 483 | }; |
447 | 484 | ||
448 | static struct vm_operations_struct i915_gem_vm_ops = { | 485 | static struct vm_operations_struct i915_gem_vm_ops = { |
@@ -464,8 +501,11 @@ static struct drm_driver driver = { | |||
464 | .lastclose = i915_driver_lastclose, | 501 | .lastclose = i915_driver_lastclose, |
465 | .preclose = i915_driver_preclose, | 502 | .preclose = i915_driver_preclose, |
466 | .postclose = i915_driver_postclose, | 503 | .postclose = i915_driver_postclose, |
504 | |||
505 | /* Used in place of i915_pm_ops for non-DRIVER_MODESET */ | ||
467 | .suspend = i915_suspend, | 506 | .suspend = i915_suspend, |
468 | .resume = i915_resume, | 507 | .resume = i915_resume, |
508 | |||
469 | .device_is_agp = i915_driver_device_is_agp, | 509 | .device_is_agp = i915_driver_device_is_agp, |
470 | .enable_vblank = i915_enable_vblank, | 510 | .enable_vblank = i915_enable_vblank, |
471 | .disable_vblank = i915_disable_vblank, | 511 | .disable_vblank = i915_disable_vblank, |