diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 248 |
1 files changed, 127 insertions, 121 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 62b97c4eef8d..65910e3aed0c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -613,26 +613,6 @@ fail_display: | |||
613 | return ret; | 613 | return ret; |
614 | } | 614 | } |
615 | 615 | ||
616 | int nouveau_pmops_suspend(struct device *dev) | ||
617 | { | ||
618 | struct pci_dev *pdev = to_pci_dev(dev); | ||
619 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
620 | int ret; | ||
621 | |||
622 | if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF || | ||
623 | drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) | ||
624 | return 0; | ||
625 | |||
626 | ret = nouveau_do_suspend(drm_dev, false); | ||
627 | if (ret) | ||
628 | return ret; | ||
629 | |||
630 | pci_save_state(pdev); | ||
631 | pci_disable_device(pdev); | ||
632 | pci_set_power_state(pdev, PCI_D3hot); | ||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | static int | 616 | static int |
637 | nouveau_do_resume(struct drm_device *dev, bool runtime) | 617 | nouveau_do_resume(struct drm_device *dev, bool runtime) |
638 | { | 618 | { |
@@ -667,7 +647,29 @@ nouveau_do_resume(struct drm_device *dev, bool runtime) | |||
667 | return 0; | 647 | return 0; |
668 | } | 648 | } |
669 | 649 | ||
670 | int nouveau_pmops_resume(struct device *dev) | 650 | int |
651 | nouveau_pmops_suspend(struct device *dev) | ||
652 | { | ||
653 | struct pci_dev *pdev = to_pci_dev(dev); | ||
654 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
655 | int ret; | ||
656 | |||
657 | if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF || | ||
658 | drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) | ||
659 | return 0; | ||
660 | |||
661 | ret = nouveau_do_suspend(drm_dev, false); | ||
662 | if (ret) | ||
663 | return ret; | ||
664 | |||
665 | pci_save_state(pdev); | ||
666 | pci_disable_device(pdev); | ||
667 | pci_set_power_state(pdev, PCI_D3hot); | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | int | ||
672 | nouveau_pmops_resume(struct device *dev) | ||
671 | { | 673 | { |
672 | struct pci_dev *pdev = to_pci_dev(dev); | 674 | struct pci_dev *pdev = to_pci_dev(dev); |
673 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | 675 | struct drm_device *drm_dev = pci_get_drvdata(pdev); |
@@ -687,20 +689,122 @@ int nouveau_pmops_resume(struct device *dev) | |||
687 | return nouveau_do_resume(drm_dev, false); | 689 | return nouveau_do_resume(drm_dev, false); |
688 | } | 690 | } |
689 | 691 | ||
690 | static int nouveau_pmops_freeze(struct device *dev) | 692 | static int |
693 | nouveau_pmops_freeze(struct device *dev) | ||
691 | { | 694 | { |
692 | struct pci_dev *pdev = to_pci_dev(dev); | 695 | struct pci_dev *pdev = to_pci_dev(dev); |
693 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | 696 | struct drm_device *drm_dev = pci_get_drvdata(pdev); |
694 | return nouveau_do_suspend(drm_dev, false); | 697 | return nouveau_do_suspend(drm_dev, false); |
695 | } | 698 | } |
696 | 699 | ||
697 | static int nouveau_pmops_thaw(struct device *dev) | 700 | static int |
701 | nouveau_pmops_thaw(struct device *dev) | ||
698 | { | 702 | { |
699 | struct pci_dev *pdev = to_pci_dev(dev); | 703 | struct pci_dev *pdev = to_pci_dev(dev); |
700 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | 704 | struct drm_device *drm_dev = pci_get_drvdata(pdev); |
701 | return nouveau_do_resume(drm_dev, false); | 705 | return nouveau_do_resume(drm_dev, false); |
702 | } | 706 | } |
703 | 707 | ||
708 | static int | ||
709 | nouveau_pmops_runtime_suspend(struct device *dev) | ||
710 | { | ||
711 | struct pci_dev *pdev = to_pci_dev(dev); | ||
712 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
713 | int ret; | ||
714 | |||
715 | if (nouveau_runtime_pm == 0) { | ||
716 | pm_runtime_forbid(dev); | ||
717 | return -EBUSY; | ||
718 | } | ||
719 | |||
720 | /* are we optimus enabled? */ | ||
721 | if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) { | ||
722 | DRM_DEBUG_DRIVER("failing to power off - not optimus\n"); | ||
723 | pm_runtime_forbid(dev); | ||
724 | return -EBUSY; | ||
725 | } | ||
726 | |||
727 | nv_debug_level(SILENT); | ||
728 | drm_kms_helper_poll_disable(drm_dev); | ||
729 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); | ||
730 | nouveau_switcheroo_optimus_dsm(); | ||
731 | ret = nouveau_do_suspend(drm_dev, true); | ||
732 | pci_save_state(pdev); | ||
733 | pci_disable_device(pdev); | ||
734 | pci_ignore_hotplug(pdev); | ||
735 | pci_set_power_state(pdev, PCI_D3cold); | ||
736 | drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; | ||
737 | return ret; | ||
738 | } | ||
739 | |||
740 | static int | ||
741 | nouveau_pmops_runtime_resume(struct device *dev) | ||
742 | { | ||
743 | struct pci_dev *pdev = to_pci_dev(dev); | ||
744 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
745 | struct nvif_device *device = &nouveau_drm(drm_dev)->device; | ||
746 | int ret; | ||
747 | |||
748 | if (nouveau_runtime_pm == 0) | ||
749 | return -EINVAL; | ||
750 | |||
751 | pci_set_power_state(pdev, PCI_D0); | ||
752 | pci_restore_state(pdev); | ||
753 | ret = pci_enable_device(pdev); | ||
754 | if (ret) | ||
755 | return ret; | ||
756 | pci_set_master(pdev); | ||
757 | |||
758 | ret = nouveau_do_resume(drm_dev, true); | ||
759 | drm_kms_helper_poll_enable(drm_dev); | ||
760 | /* do magic */ | ||
761 | nvif_mask(device, 0x88488, (1 << 25), (1 << 25)); | ||
762 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); | ||
763 | drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; | ||
764 | nv_debug_level(NORMAL); | ||
765 | return ret; | ||
766 | } | ||
767 | |||
768 | static int | ||
769 | nouveau_pmops_runtime_idle(struct device *dev) | ||
770 | { | ||
771 | struct pci_dev *pdev = to_pci_dev(dev); | ||
772 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
773 | struct nouveau_drm *drm = nouveau_drm(drm_dev); | ||
774 | struct drm_crtc *crtc; | ||
775 | |||
776 | if (nouveau_runtime_pm == 0) { | ||
777 | pm_runtime_forbid(dev); | ||
778 | return -EBUSY; | ||
779 | } | ||
780 | |||
781 | /* are we optimus enabled? */ | ||
782 | if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) { | ||
783 | DRM_DEBUG_DRIVER("failing to power off - not optimus\n"); | ||
784 | pm_runtime_forbid(dev); | ||
785 | return -EBUSY; | ||
786 | } | ||
787 | |||
788 | /* if we have a hdmi audio device - make sure it has a driver loaded */ | ||
789 | if (drm->hdmi_device) { | ||
790 | if (!drm->hdmi_device->driver) { | ||
791 | DRM_DEBUG_DRIVER("failing to power off - no HDMI audio driver loaded\n"); | ||
792 | pm_runtime_mark_last_busy(dev); | ||
793 | return -EBUSY; | ||
794 | } | ||
795 | } | ||
796 | |||
797 | list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) { | ||
798 | if (crtc->enabled) { | ||
799 | DRM_DEBUG_DRIVER("failing to power off - crtc active\n"); | ||
800 | return -EBUSY; | ||
801 | } | ||
802 | } | ||
803 | pm_runtime_mark_last_busy(dev); | ||
804 | pm_runtime_autosuspend(dev); | ||
805 | /* we don't want the main rpm_idle to call suspend - we want to autosuspend */ | ||
806 | return 1; | ||
807 | } | ||
704 | 808 | ||
705 | static int | 809 | static int |
706 | nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) | 810 | nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) |
@@ -907,104 +1011,6 @@ nouveau_drm_pci_table[] = { | |||
907 | {} | 1011 | {} |
908 | }; | 1012 | }; |
909 | 1013 | ||
910 | static int nouveau_pmops_runtime_suspend(struct device *dev) | ||
911 | { | ||
912 | struct pci_dev *pdev = to_pci_dev(dev); | ||
913 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
914 | int ret; | ||
915 | |||
916 | if (nouveau_runtime_pm == 0) { | ||
917 | pm_runtime_forbid(dev); | ||
918 | return -EBUSY; | ||
919 | } | ||
920 | |||
921 | /* are we optimus enabled? */ | ||
922 | if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) { | ||
923 | DRM_DEBUG_DRIVER("failing to power off - not optimus\n"); | ||
924 | pm_runtime_forbid(dev); | ||
925 | return -EBUSY; | ||
926 | } | ||
927 | |||
928 | nv_debug_level(SILENT); | ||
929 | drm_kms_helper_poll_disable(drm_dev); | ||
930 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); | ||
931 | nouveau_switcheroo_optimus_dsm(); | ||
932 | ret = nouveau_do_suspend(drm_dev, true); | ||
933 | pci_save_state(pdev); | ||
934 | pci_disable_device(pdev); | ||
935 | pci_ignore_hotplug(pdev); | ||
936 | pci_set_power_state(pdev, PCI_D3cold); | ||
937 | drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; | ||
938 | return ret; | ||
939 | } | ||
940 | |||
941 | static int nouveau_pmops_runtime_resume(struct device *dev) | ||
942 | { | ||
943 | struct pci_dev *pdev = to_pci_dev(dev); | ||
944 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
945 | struct nvif_device *device = &nouveau_drm(drm_dev)->device; | ||
946 | int ret; | ||
947 | |||
948 | if (nouveau_runtime_pm == 0) | ||
949 | return -EINVAL; | ||
950 | |||
951 | pci_set_power_state(pdev, PCI_D0); | ||
952 | pci_restore_state(pdev); | ||
953 | ret = pci_enable_device(pdev); | ||
954 | if (ret) | ||
955 | return ret; | ||
956 | pci_set_master(pdev); | ||
957 | |||
958 | ret = nouveau_do_resume(drm_dev, true); | ||
959 | drm_kms_helper_poll_enable(drm_dev); | ||
960 | /* do magic */ | ||
961 | nvif_mask(device, 0x88488, (1 << 25), (1 << 25)); | ||
962 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); | ||
963 | drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; | ||
964 | nv_debug_level(NORMAL); | ||
965 | return ret; | ||
966 | } | ||
967 | |||
968 | static int nouveau_pmops_runtime_idle(struct device *dev) | ||
969 | { | ||
970 | struct pci_dev *pdev = to_pci_dev(dev); | ||
971 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
972 | struct nouveau_drm *drm = nouveau_drm(drm_dev); | ||
973 | struct drm_crtc *crtc; | ||
974 | |||
975 | if (nouveau_runtime_pm == 0) { | ||
976 | pm_runtime_forbid(dev); | ||
977 | return -EBUSY; | ||
978 | } | ||
979 | |||
980 | /* are we optimus enabled? */ | ||
981 | if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) { | ||
982 | DRM_DEBUG_DRIVER("failing to power off - not optimus\n"); | ||
983 | pm_runtime_forbid(dev); | ||
984 | return -EBUSY; | ||
985 | } | ||
986 | |||
987 | /* if we have a hdmi audio device - make sure it has a driver loaded */ | ||
988 | if (drm->hdmi_device) { | ||
989 | if (!drm->hdmi_device->driver) { | ||
990 | DRM_DEBUG_DRIVER("failing to power off - no HDMI audio driver loaded\n"); | ||
991 | pm_runtime_mark_last_busy(dev); | ||
992 | return -EBUSY; | ||
993 | } | ||
994 | } | ||
995 | |||
996 | list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) { | ||
997 | if (crtc->enabled) { | ||
998 | DRM_DEBUG_DRIVER("failing to power off - crtc active\n"); | ||
999 | return -EBUSY; | ||
1000 | } | ||
1001 | } | ||
1002 | pm_runtime_mark_last_busy(dev); | ||
1003 | pm_runtime_autosuspend(dev); | ||
1004 | /* we don't want the main rpm_idle to call suspend - we want to autosuspend */ | ||
1005 | return 1; | ||
1006 | } | ||
1007 | |||
1008 | static void nouveau_display_options(void) | 1014 | static void nouveau_display_options(void) |
1009 | { | 1015 | { |
1010 | DRM_DEBUG_DRIVER("Loading Nouveau with parameters:\n"); | 1016 | DRM_DEBUG_DRIVER("Loading Nouveau with parameters:\n"); |