diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_drv.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 44 |
1 files changed, 27 insertions, 17 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 8039cec71fc2..5c66b568bb81 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -622,7 +622,7 @@ static int i915_drm_suspend(struct drm_device *dev) | |||
622 | return 0; | 622 | return 0; |
623 | } | 623 | } |
624 | 624 | ||
625 | static int i915_drm_suspend_late(struct drm_device *drm_dev) | 625 | static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation) |
626 | { | 626 | { |
627 | struct drm_i915_private *dev_priv = drm_dev->dev_private; | 627 | struct drm_i915_private *dev_priv = drm_dev->dev_private; |
628 | int ret; | 628 | int ret; |
@@ -636,7 +636,17 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev) | |||
636 | } | 636 | } |
637 | 637 | ||
638 | pci_disable_device(drm_dev->pdev); | 638 | pci_disable_device(drm_dev->pdev); |
639 | pci_set_power_state(drm_dev->pdev, PCI_D3hot); | 639 | /* |
640 | * During hibernation on some GEN4 platforms the BIOS may try to access | ||
641 | * the device even though it's already in D3 and hang the machine. So | ||
642 | * leave the device in D0 on those platforms and hope the BIOS will | ||
643 | * power down the device properly. Platforms where this was seen: | ||
644 | * Lenovo Thinkpad X301, X61s | ||
645 | */ | ||
646 | if (!(hibernation && | ||
647 | drm_dev->pdev->subsystem_vendor == PCI_VENDOR_ID_LENOVO && | ||
648 | INTEL_INFO(dev_priv)->gen == 4)) | ||
649 | pci_set_power_state(drm_dev->pdev, PCI_D3hot); | ||
640 | 650 | ||
641 | return 0; | 651 | return 0; |
642 | } | 652 | } |
@@ -662,7 +672,7 @@ int i915_suspend_legacy(struct drm_device *dev, pm_message_t state) | |||
662 | if (error) | 672 | if (error) |
663 | return error; | 673 | return error; |
664 | 674 | ||
665 | return i915_drm_suspend_late(dev); | 675 | return i915_drm_suspend_late(dev, false); |
666 | } | 676 | } |
667 | 677 | ||
668 | static int i915_drm_resume(struct drm_device *dev) | 678 | static int i915_drm_resume(struct drm_device *dev) |
@@ -950,7 +960,17 @@ static int i915_pm_suspend_late(struct device *dev) | |||
950 | if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) | 960 | if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) |
951 | return 0; | 961 | return 0; |
952 | 962 | ||
953 | return i915_drm_suspend_late(drm_dev); | 963 | return i915_drm_suspend_late(drm_dev, false); |
964 | } | ||
965 | |||
966 | static int i915_pm_poweroff_late(struct device *dev) | ||
967 | { | ||
968 | struct drm_device *drm_dev = dev_to_i915(dev)->dev; | ||
969 | |||
970 | if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) | ||
971 | return 0; | ||
972 | |||
973 | return i915_drm_suspend_late(drm_dev, true); | ||
954 | } | 974 | } |
955 | 975 | ||
956 | static int i915_pm_resume_early(struct device *dev) | 976 | static int i915_pm_resume_early(struct device *dev) |
@@ -1075,6 +1095,7 @@ static void vlv_save_gunit_s0ix_state(struct drm_i915_private *dev_priv) | |||
1075 | /* Gunit-Display CZ domain, 0x182028-0x1821CF */ | 1095 | /* Gunit-Display CZ domain, 0x182028-0x1821CF */ |
1076 | s->gu_ctl0 = I915_READ(VLV_GU_CTL0); | 1096 | s->gu_ctl0 = I915_READ(VLV_GU_CTL0); |
1077 | s->gu_ctl1 = I915_READ(VLV_GU_CTL1); | 1097 | s->gu_ctl1 = I915_READ(VLV_GU_CTL1); |
1098 | s->pcbr = I915_READ(VLV_PCBR); | ||
1078 | s->clock_gate_dis2 = I915_READ(VLV_GUNIT_CLOCK_GATE2); | 1099 | s->clock_gate_dis2 = I915_READ(VLV_GUNIT_CLOCK_GATE2); |
1079 | 1100 | ||
1080 | /* | 1101 | /* |
@@ -1169,6 +1190,7 @@ static void vlv_restore_gunit_s0ix_state(struct drm_i915_private *dev_priv) | |||
1169 | /* Gunit-Display CZ domain, 0x182028-0x1821CF */ | 1190 | /* Gunit-Display CZ domain, 0x182028-0x1821CF */ |
1170 | I915_WRITE(VLV_GU_CTL0, s->gu_ctl0); | 1191 | I915_WRITE(VLV_GU_CTL0, s->gu_ctl0); |
1171 | I915_WRITE(VLV_GU_CTL1, s->gu_ctl1); | 1192 | I915_WRITE(VLV_GU_CTL1, s->gu_ctl1); |
1193 | I915_WRITE(VLV_PCBR, s->pcbr); | ||
1172 | I915_WRITE(VLV_GUNIT_CLOCK_GATE2, s->clock_gate_dis2); | 1194 | I915_WRITE(VLV_GUNIT_CLOCK_GATE2, s->clock_gate_dis2); |
1173 | } | 1195 | } |
1174 | 1196 | ||
@@ -1177,19 +1199,7 @@ int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool force_on) | |||
1177 | u32 val; | 1199 | u32 val; |
1178 | int err; | 1200 | int err; |
1179 | 1201 | ||
1180 | val = I915_READ(VLV_GTLC_SURVIVABILITY_REG); | ||
1181 | WARN_ON(!!(val & VLV_GFX_CLK_FORCE_ON_BIT) == force_on); | ||
1182 | |||
1183 | #define COND (I915_READ(VLV_GTLC_SURVIVABILITY_REG) & VLV_GFX_CLK_STATUS_BIT) | 1202 | #define COND (I915_READ(VLV_GTLC_SURVIVABILITY_REG) & VLV_GFX_CLK_STATUS_BIT) |
1184 | /* Wait for a previous force-off to settle */ | ||
1185 | if (force_on) { | ||
1186 | err = wait_for(!COND, 20); | ||
1187 | if (err) { | ||
1188 | DRM_ERROR("timeout waiting for GFX clock force-off (%08x)\n", | ||
1189 | I915_READ(VLV_GTLC_SURVIVABILITY_REG)); | ||
1190 | return err; | ||
1191 | } | ||
1192 | } | ||
1193 | 1203 | ||
1194 | val = I915_READ(VLV_GTLC_SURVIVABILITY_REG); | 1204 | val = I915_READ(VLV_GTLC_SURVIVABILITY_REG); |
1195 | val &= ~VLV_GFX_CLK_FORCE_ON_BIT; | 1205 | val &= ~VLV_GFX_CLK_FORCE_ON_BIT; |
@@ -1520,7 +1530,7 @@ static const struct dev_pm_ops i915_pm_ops = { | |||
1520 | .thaw_early = i915_pm_resume_early, | 1530 | .thaw_early = i915_pm_resume_early, |
1521 | .thaw = i915_pm_resume, | 1531 | .thaw = i915_pm_resume, |
1522 | .poweroff = i915_pm_suspend, | 1532 | .poweroff = i915_pm_suspend, |
1523 | .poweroff_late = i915_pm_suspend_late, | 1533 | .poweroff_late = i915_pm_poweroff_late, |
1524 | .restore_early = i915_pm_resume_early, | 1534 | .restore_early = i915_pm_resume_early, |
1525 | .restore = i915_pm_resume, | 1535 | .restore = i915_pm_resume, |
1526 | 1536 | ||