|
|
@@ -613,27 +613,6 @@ fail_display:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-int nouveau_pmops_suspend(struct device *dev)
|
|
|
-{
|
|
|
- struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
|
|
- int ret;
|
|
|
-
|
|
|
- if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF ||
|
|
|
- drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF)
|
|
|
- return 0;
|
|
|
-
|
|
|
- ret = nouveau_do_suspend(drm_dev, false);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
-
|
|
|
- pci_save_state(pdev);
|
|
|
- pci_disable_device(pdev);
|
|
|
- pci_ignore_hotplug(pdev);
|
|
|
- pci_set_power_state(pdev, PCI_D3hot);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int
|
|
|
nouveau_do_resume(struct drm_device *dev, bool runtime)
|
|
|
{
|
|
|
@@ -668,7 +647,30 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int nouveau_pmops_resume(struct device *dev)
|
|
|
+int
|
|
|
+nouveau_pmops_suspend(struct device *dev)
|
|
|
+{
|
|
|
+ struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF ||
|
|
|
+ drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ ret = nouveau_do_suspend(drm_dev, false);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ pci_save_state(pdev);
|
|
|
+ pci_disable_device(pdev);
|
|
|
+ pci_ignore_hotplug(pdev);
|
|
|
+ pci_set_power_state(pdev, PCI_D3hot);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+nouveau_pmops_resume(struct device *dev)
|
|
|
{
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
|
|
@@ -688,20 +690,121 @@ int nouveau_pmops_resume(struct device *dev)
|
|
|
return nouveau_do_resume(drm_dev, false);
|
|
|
}
|
|
|
|
|
|
-static int nouveau_pmops_freeze(struct device *dev)
|
|
|
+static int
|
|
|
+nouveau_pmops_freeze(struct device *dev)
|
|
|
{
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
|
|
return nouveau_do_suspend(drm_dev, false);
|
|
|
}
|
|
|
|
|
|
-static int nouveau_pmops_thaw(struct device *dev)
|
|
|
+static int
|
|
|
+nouveau_pmops_thaw(struct device *dev)
|
|
|
{
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
|
|
return nouveau_do_resume(drm_dev, false);
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+nouveau_pmops_runtime_suspend(struct device *dev)
|
|
|
+{
|
|
|
+ struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (nouveau_runtime_pm == 0) {
|
|
|
+ pm_runtime_forbid(dev);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* are we optimus enabled? */
|
|
|
+ if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
|
|
|
+ DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
|
|
|
+ pm_runtime_forbid(dev);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ nv_debug_level(SILENT);
|
|
|
+ drm_kms_helper_poll_disable(drm_dev);
|
|
|
+ vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
|
|
|
+ nouveau_switcheroo_optimus_dsm();
|
|
|
+ ret = nouveau_do_suspend(drm_dev, true);
|
|
|
+ pci_save_state(pdev);
|
|
|
+ pci_disable_device(pdev);
|
|
|
+ pci_set_power_state(pdev, PCI_D3cold);
|
|
|
+ drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+nouveau_pmops_runtime_resume(struct device *dev)
|
|
|
+{
|
|
|
+ struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
|
|
+ struct nvif_device *device = &nouveau_drm(drm_dev)->device;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (nouveau_runtime_pm == 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ pci_set_power_state(pdev, PCI_D0);
|
|
|
+ pci_restore_state(pdev);
|
|
|
+ ret = pci_enable_device(pdev);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ pci_set_master(pdev);
|
|
|
+
|
|
|
+ ret = nouveau_do_resume(drm_dev, true);
|
|
|
+ drm_kms_helper_poll_enable(drm_dev);
|
|
|
+ /* do magic */
|
|
|
+ nvif_mask(device, 0x88488, (1 << 25), (1 << 25));
|
|
|
+ vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
|
|
|
+ drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
|
|
|
+ nv_debug_level(NORMAL);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+nouveau_pmops_runtime_idle(struct device *dev)
|
|
|
+{
|
|
|
+ struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
|
|
+ struct nouveau_drm *drm = nouveau_drm(drm_dev);
|
|
|
+ struct drm_crtc *crtc;
|
|
|
+
|
|
|
+ if (nouveau_runtime_pm == 0) {
|
|
|
+ pm_runtime_forbid(dev);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* are we optimus enabled? */
|
|
|
+ if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
|
|
|
+ DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
|
|
|
+ pm_runtime_forbid(dev);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* if we have a hdmi audio device - make sure it has a driver loaded */
|
|
|
+ if (drm->hdmi_device) {
|
|
|
+ if (!drm->hdmi_device->driver) {
|
|
|
+ DRM_DEBUG_DRIVER("failing to power off - no HDMI audio driver loaded\n");
|
|
|
+ pm_runtime_mark_last_busy(dev);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) {
|
|
|
+ if (crtc->enabled) {
|
|
|
+ DRM_DEBUG_DRIVER("failing to power off - crtc active\n");
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pm_runtime_mark_last_busy(dev);
|
|
|
+ pm_runtime_autosuspend(dev);
|
|
|
+ /* we don't want the main rpm_idle to call suspend - we want to autosuspend */
|
|
|
+ return 1;
|
|
|
+}
|
|
|
|
|
|
static int
|
|
|
nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
|
|
|
@@ -908,103 +1011,6 @@ nouveau_drm_pci_table[] = {
|
|
|
{}
|
|
|
};
|
|
|
|
|
|
-static int nouveau_pmops_runtime_suspend(struct device *dev)
|
|
|
-{
|
|
|
- struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
|
|
- int ret;
|
|
|
-
|
|
|
- if (nouveau_runtime_pm == 0) {
|
|
|
- pm_runtime_forbid(dev);
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
-
|
|
|
- /* are we optimus enabled? */
|
|
|
- if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
|
|
|
- DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
|
|
|
- pm_runtime_forbid(dev);
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
-
|
|
|
- nv_debug_level(SILENT);
|
|
|
- drm_kms_helper_poll_disable(drm_dev);
|
|
|
- vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
|
|
|
- nouveau_switcheroo_optimus_dsm();
|
|
|
- ret = nouveau_do_suspend(drm_dev, true);
|
|
|
- pci_save_state(pdev);
|
|
|
- pci_disable_device(pdev);
|
|
|
- pci_set_power_state(pdev, PCI_D3cold);
|
|
|
- drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-static int nouveau_pmops_runtime_resume(struct device *dev)
|
|
|
-{
|
|
|
- struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
|
|
- struct nvif_device *device = &nouveau_drm(drm_dev)->device;
|
|
|
- int ret;
|
|
|
-
|
|
|
- if (nouveau_runtime_pm == 0)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- pci_set_power_state(pdev, PCI_D0);
|
|
|
- pci_restore_state(pdev);
|
|
|
- ret = pci_enable_device(pdev);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
- pci_set_master(pdev);
|
|
|
-
|
|
|
- ret = nouveau_do_resume(drm_dev, true);
|
|
|
- drm_kms_helper_poll_enable(drm_dev);
|
|
|
- /* do magic */
|
|
|
- nvif_mask(device, 0x88488, (1 << 25), (1 << 25));
|
|
|
- vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
|
|
|
- drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
|
|
|
- nv_debug_level(NORMAL);
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-static int nouveau_pmops_runtime_idle(struct device *dev)
|
|
|
-{
|
|
|
- struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
|
|
- struct nouveau_drm *drm = nouveau_drm(drm_dev);
|
|
|
- struct drm_crtc *crtc;
|
|
|
-
|
|
|
- if (nouveau_runtime_pm == 0) {
|
|
|
- pm_runtime_forbid(dev);
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
-
|
|
|
- /* are we optimus enabled? */
|
|
|
- if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
|
|
|
- DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
|
|
|
- pm_runtime_forbid(dev);
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
-
|
|
|
- /* if we have a hdmi audio device - make sure it has a driver loaded */
|
|
|
- if (drm->hdmi_device) {
|
|
|
- if (!drm->hdmi_device->driver) {
|
|
|
- DRM_DEBUG_DRIVER("failing to power off - no HDMI audio driver loaded\n");
|
|
|
- pm_runtime_mark_last_busy(dev);
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) {
|
|
|
- if (crtc->enabled) {
|
|
|
- DRM_DEBUG_DRIVER("failing to power off - crtc active\n");
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
- }
|
|
|
- pm_runtime_mark_last_busy(dev);
|
|
|
- pm_runtime_autosuspend(dev);
|
|
|
- /* we don't want the main rpm_idle to call suspend - we want to autosuspend */
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
static void nouveau_display_options(void)
|
|
|
{
|
|
|
DRM_DEBUG_DRIVER("Loading Nouveau with parameters:\n");
|