diff options
author | Paul Walmsley <paul@pwsan.com> | 2013-01-26 02:58:16 -0500 |
---|---|---|
committer | Paul Walmsley <paul@pwsan.com> | 2013-01-29 16:59:57 -0500 |
commit | 3a090284056954f382612da42ebe9f3147403ef5 (patch) | |
tree | 6e9627679444b04614577cf55ad77f8e17aed0b9 /arch | |
parent | c4978fba6b2d4e3a584d72c067a371871fecbedc (diff) |
ARM: OMAP2+: powerdomain/clockdomain: add a per-powerdomain spinlock
Add a per-powerdomain spinlock. Use that instead of the clockdomain
spinlock. Add pwrdm_lock()/pwrdm_unlock() functions to allow other
code to acquire or release the powerdomain spinlock without reaching
directly into the struct powerdomain.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Jean Pihet <jean.pihet@newoldbits.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-omap2/clockdomain.c | 172 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clockdomain.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-omap2/powerdomain.c | 60 | ||||
-rw-r--r-- | arch/arm/mach-omap2/powerdomain.h | 11 |
4 files changed, 176 insertions, 73 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index f0ec51497ce2..275bdfbb6fc5 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c | |||
@@ -92,8 +92,6 @@ static int _clkdm_register(struct clockdomain *clkdm) | |||
92 | 92 | ||
93 | pwrdm_add_clkdm(pwrdm, clkdm); | 93 | pwrdm_add_clkdm(pwrdm, clkdm); |
94 | 94 | ||
95 | spin_lock_init(&clkdm->lock); | ||
96 | |||
97 | pr_debug("clockdomain: registered %s\n", clkdm->name); | 95 | pr_debug("clockdomain: registered %s\n", clkdm->name); |
98 | 96 | ||
99 | return 0; | 97 | return 0; |
@@ -734,18 +732,17 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) | |||
734 | } | 732 | } |
735 | 733 | ||
736 | /** | 734 | /** |
737 | * clkdm_sleep - force clockdomain sleep transition | 735 | * clkdm_sleep_nolock - force clockdomain sleep transition (lockless) |
738 | * @clkdm: struct clockdomain * | 736 | * @clkdm: struct clockdomain * |
739 | * | 737 | * |
740 | * Instruct the CM to force a sleep transition on the specified | 738 | * Instruct the CM to force a sleep transition on the specified |
741 | * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if | 739 | * clockdomain @clkdm. Only for use by the powerdomain code. Returns |
742 | * clockdomain does not support software-initiated sleep; 0 upon | 740 | * -EINVAL if @clkdm is NULL or if clockdomain does not support |
743 | * success. | 741 | * software-initiated sleep; 0 upon success. |
744 | */ | 742 | */ |
745 | int clkdm_sleep(struct clockdomain *clkdm) | 743 | int clkdm_sleep_nolock(struct clockdomain *clkdm) |
746 | { | 744 | { |
747 | int ret; | 745 | int ret; |
748 | unsigned long flags; | ||
749 | 746 | ||
750 | if (!clkdm) | 747 | if (!clkdm) |
751 | return -EINVAL; | 748 | return -EINVAL; |
@@ -761,27 +758,45 @@ int clkdm_sleep(struct clockdomain *clkdm) | |||
761 | 758 | ||
762 | pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); | 759 | pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); |
763 | 760 | ||
764 | spin_lock_irqsave(&clkdm->lock, flags); | ||
765 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; | 761 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; |
766 | ret = arch_clkdm->clkdm_sleep(clkdm); | 762 | ret = arch_clkdm->clkdm_sleep(clkdm); |
767 | ret |= pwrdm_state_switch(clkdm->pwrdm.ptr); | 763 | ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
768 | spin_unlock_irqrestore(&clkdm->lock, flags); | 764 | |
769 | return ret; | 765 | return ret; |
770 | } | 766 | } |
771 | 767 | ||
772 | /** | 768 | /** |
773 | * clkdm_wakeup - force clockdomain wakeup transition | 769 | * clkdm_sleep - force clockdomain sleep transition |
774 | * @clkdm: struct clockdomain * | 770 | * @clkdm: struct clockdomain * |
775 | * | 771 | * |
776 | * Instruct the CM to force a wakeup transition on the specified | 772 | * Instruct the CM to force a sleep transition on the specified |
777 | * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the | 773 | * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if |
778 | * clockdomain does not support software-controlled wakeup; 0 upon | 774 | * clockdomain does not support software-initiated sleep; 0 upon |
779 | * success. | 775 | * success. |
780 | */ | 776 | */ |
781 | int clkdm_wakeup(struct clockdomain *clkdm) | 777 | int clkdm_sleep(struct clockdomain *clkdm) |
778 | { | ||
779 | int ret; | ||
780 | |||
781 | pwrdm_lock(clkdm->pwrdm.ptr); | ||
782 | ret = clkdm_sleep_nolock(clkdm); | ||
783 | pwrdm_unlock(clkdm->pwrdm.ptr); | ||
784 | |||
785 | return ret; | ||
786 | } | ||
787 | |||
788 | /** | ||
789 | * clkdm_wakeup_nolock - force clockdomain wakeup transition (lockless) | ||
790 | * @clkdm: struct clockdomain * | ||
791 | * | ||
792 | * Instruct the CM to force a wakeup transition on the specified | ||
793 | * clockdomain @clkdm. Only for use by the powerdomain code. Returns | ||
794 | * -EINVAL if @clkdm is NULL or if the clockdomain does not support | ||
795 | * software-controlled wakeup; 0 upon success. | ||
796 | */ | ||
797 | int clkdm_wakeup_nolock(struct clockdomain *clkdm) | ||
782 | { | 798 | { |
783 | int ret; | 799 | int ret; |
784 | unsigned long flags; | ||
785 | 800 | ||
786 | if (!clkdm) | 801 | if (!clkdm) |
787 | return -EINVAL; | 802 | return -EINVAL; |
@@ -797,28 +812,46 @@ int clkdm_wakeup(struct clockdomain *clkdm) | |||
797 | 812 | ||
798 | pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); | 813 | pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); |
799 | 814 | ||
800 | spin_lock_irqsave(&clkdm->lock, flags); | ||
801 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; | 815 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; |
802 | ret = arch_clkdm->clkdm_wakeup(clkdm); | 816 | ret = arch_clkdm->clkdm_wakeup(clkdm); |
803 | ret |= pwrdm_state_switch(clkdm->pwrdm.ptr); | 817 | ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
804 | spin_unlock_irqrestore(&clkdm->lock, flags); | 818 | |
805 | return ret; | 819 | return ret; |
806 | } | 820 | } |
807 | 821 | ||
808 | /** | 822 | /** |
809 | * clkdm_allow_idle - enable hwsup idle transitions for clkdm | 823 | * clkdm_wakeup - force clockdomain wakeup transition |
810 | * @clkdm: struct clockdomain * | 824 | * @clkdm: struct clockdomain * |
811 | * | 825 | * |
812 | * Allow the hardware to automatically switch the clockdomain @clkdm into | 826 | * Instruct the CM to force a wakeup transition on the specified |
813 | * active or idle states, as needed by downstream clocks. If the | 827 | * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the |
828 | * clockdomain does not support software-controlled wakeup; 0 upon | ||
829 | * success. | ||
830 | */ | ||
831 | int clkdm_wakeup(struct clockdomain *clkdm) | ||
832 | { | ||
833 | int ret; | ||
834 | |||
835 | pwrdm_lock(clkdm->pwrdm.ptr); | ||
836 | ret = clkdm_wakeup_nolock(clkdm); | ||
837 | pwrdm_unlock(clkdm->pwrdm.ptr); | ||
838 | |||
839 | return ret; | ||
840 | } | ||
841 | |||
842 | /** | ||
843 | * clkdm_allow_idle_nolock - enable hwsup idle transitions for clkdm | ||
844 | * @clkdm: struct clockdomain * | ||
845 | * | ||
846 | * Allow the hardware to automatically switch the clockdomain @clkdm | ||
847 | * into active or idle states, as needed by downstream clocks. If the | ||
814 | * clockdomain has any downstream clocks enabled in the clock | 848 | * clockdomain has any downstream clocks enabled in the clock |
815 | * framework, wkdep/sleepdep autodependencies are added; this is so | 849 | * framework, wkdep/sleepdep autodependencies are added; this is so |
816 | * device drivers can read and write to the device. No return value. | 850 | * device drivers can read and write to the device. Only for use by |
851 | * the powerdomain code. No return value. | ||
817 | */ | 852 | */ |
818 | void clkdm_allow_idle(struct clockdomain *clkdm) | 853 | void clkdm_allow_idle_nolock(struct clockdomain *clkdm) |
819 | { | 854 | { |
820 | unsigned long flags; | ||
821 | |||
822 | if (!clkdm) | 855 | if (!clkdm) |
823 | return; | 856 | return; |
824 | 857 | ||
@@ -834,11 +867,26 @@ void clkdm_allow_idle(struct clockdomain *clkdm) | |||
834 | pr_debug("clockdomain: enabling automatic idle transitions for %s\n", | 867 | pr_debug("clockdomain: enabling automatic idle transitions for %s\n", |
835 | clkdm->name); | 868 | clkdm->name); |
836 | 869 | ||
837 | spin_lock_irqsave(&clkdm->lock, flags); | ||
838 | clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED; | 870 | clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED; |
839 | arch_clkdm->clkdm_allow_idle(clkdm); | 871 | arch_clkdm->clkdm_allow_idle(clkdm); |
840 | pwrdm_state_switch(clkdm->pwrdm.ptr); | 872 | pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
841 | spin_unlock_irqrestore(&clkdm->lock, flags); | 873 | } |
874 | |||
875 | /** | ||
876 | * clkdm_allow_idle - enable hwsup idle transitions for clkdm | ||
877 | * @clkdm: struct clockdomain * | ||
878 | * | ||
879 | * Allow the hardware to automatically switch the clockdomain @clkdm into | ||
880 | * active or idle states, as needed by downstream clocks. If the | ||
881 | * clockdomain has any downstream clocks enabled in the clock | ||
882 | * framework, wkdep/sleepdep autodependencies are added; this is so | ||
883 | * device drivers can read and write to the device. No return value. | ||
884 | */ | ||
885 | void clkdm_allow_idle(struct clockdomain *clkdm) | ||
886 | { | ||
887 | pwrdm_lock(clkdm->pwrdm.ptr); | ||
888 | clkdm_allow_idle_nolock(clkdm); | ||
889 | pwrdm_unlock(clkdm->pwrdm.ptr); | ||
842 | } | 890 | } |
843 | 891 | ||
844 | /** | 892 | /** |
@@ -848,12 +896,11 @@ void clkdm_allow_idle(struct clockdomain *clkdm) | |||
848 | * Prevent the hardware from automatically switching the clockdomain | 896 | * Prevent the hardware from automatically switching the clockdomain |
849 | * @clkdm into inactive or idle states. If the clockdomain has | 897 | * @clkdm into inactive or idle states. If the clockdomain has |
850 | * downstream clocks enabled in the clock framework, wkdep/sleepdep | 898 | * downstream clocks enabled in the clock framework, wkdep/sleepdep |
851 | * autodependencies are removed. No return value. | 899 | * autodependencies are removed. Only for use by the powerdomain |
900 | * code. No return value. | ||
852 | */ | 901 | */ |
853 | void clkdm_deny_idle(struct clockdomain *clkdm) | 902 | void clkdm_deny_idle_nolock(struct clockdomain *clkdm) |
854 | { | 903 | { |
855 | unsigned long flags; | ||
856 | |||
857 | if (!clkdm) | 904 | if (!clkdm) |
858 | return; | 905 | return; |
859 | 906 | ||
@@ -869,11 +916,25 @@ void clkdm_deny_idle(struct clockdomain *clkdm) | |||
869 | pr_debug("clockdomain: disabling automatic idle transitions for %s\n", | 916 | pr_debug("clockdomain: disabling automatic idle transitions for %s\n", |
870 | clkdm->name); | 917 | clkdm->name); |
871 | 918 | ||
872 | spin_lock_irqsave(&clkdm->lock, flags); | ||
873 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; | 919 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; |
874 | arch_clkdm->clkdm_deny_idle(clkdm); | 920 | arch_clkdm->clkdm_deny_idle(clkdm); |
875 | pwrdm_state_switch(clkdm->pwrdm.ptr); | 921 | pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
876 | spin_unlock_irqrestore(&clkdm->lock, flags); | 922 | } |
923 | |||
924 | /** | ||
925 | * clkdm_deny_idle - disable hwsup idle transitions for clkdm | ||
926 | * @clkdm: struct clockdomain * | ||
927 | * | ||
928 | * Prevent the hardware from automatically switching the clockdomain | ||
929 | * @clkdm into inactive or idle states. If the clockdomain has | ||
930 | * downstream clocks enabled in the clock framework, wkdep/sleepdep | ||
931 | * autodependencies are removed. No return value. | ||
932 | */ | ||
933 | void clkdm_deny_idle(struct clockdomain *clkdm) | ||
934 | { | ||
935 | pwrdm_lock(clkdm->pwrdm.ptr); | ||
936 | clkdm_deny_idle_nolock(clkdm); | ||
937 | pwrdm_unlock(clkdm->pwrdm.ptr); | ||
877 | } | 938 | } |
878 | 939 | ||
879 | /** | 940 | /** |
@@ -890,14 +951,11 @@ void clkdm_deny_idle(struct clockdomain *clkdm) | |||
890 | bool clkdm_in_hwsup(struct clockdomain *clkdm) | 951 | bool clkdm_in_hwsup(struct clockdomain *clkdm) |
891 | { | 952 | { |
892 | bool ret; | 953 | bool ret; |
893 | unsigned long flags; | ||
894 | 954 | ||
895 | if (!clkdm) | 955 | if (!clkdm) |
896 | return false; | 956 | return false; |
897 | 957 | ||
898 | spin_lock_irqsave(&clkdm->lock, flags); | ||
899 | ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false; | 958 | ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false; |
900 | spin_unlock_irqrestore(&clkdm->lock, flags); | ||
901 | 959 | ||
902 | return ret; | 960 | return ret; |
903 | } | 961 | } |
@@ -923,12 +981,10 @@ bool clkdm_missing_idle_reporting(struct clockdomain *clkdm) | |||
923 | 981 | ||
924 | static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) | 982 | static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) |
925 | { | 983 | { |
926 | unsigned long flags; | ||
927 | |||
928 | if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable) | 984 | if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable) |
929 | return -EINVAL; | 985 | return -EINVAL; |
930 | 986 | ||
931 | spin_lock_irqsave(&clkdm->lock, flags); | 987 | pwrdm_lock(clkdm->pwrdm.ptr); |
932 | 988 | ||
933 | /* | 989 | /* |
934 | * For arch's with no autodeps, clkcm_clk_enable | 990 | * For arch's with no autodeps, clkcm_clk_enable |
@@ -936,13 +992,13 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) | |||
936 | * enabled, so the clkdm can be force woken up. | 992 | * enabled, so the clkdm can be force woken up. |
937 | */ | 993 | */ |
938 | if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) { | 994 | if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) { |
939 | spin_unlock_irqrestore(&clkdm->lock, flags); | 995 | pwrdm_unlock(clkdm->pwrdm.ptr); |
940 | return 0; | 996 | return 0; |
941 | } | 997 | } |
942 | 998 | ||
943 | arch_clkdm->clkdm_clk_enable(clkdm); | 999 | arch_clkdm->clkdm_clk_enable(clkdm); |
944 | pwrdm_state_switch(clkdm->pwrdm.ptr); | 1000 | pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
945 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1001 | pwrdm_unlock(clkdm->pwrdm.ptr); |
946 | 1002 | ||
947 | pr_debug("clockdomain: %s: enabled\n", clkdm->name); | 1003 | pr_debug("clockdomain: %s: enabled\n", clkdm->name); |
948 | 1004 | ||
@@ -991,12 +1047,10 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | |||
991 | */ | 1047 | */ |
992 | int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) | 1048 | int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) |
993 | { | 1049 | { |
994 | unsigned long flags; | ||
995 | |||
996 | if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) | 1050 | if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) |
997 | return -EINVAL; | 1051 | return -EINVAL; |
998 | 1052 | ||
999 | spin_lock_irqsave(&clkdm->lock, flags); | 1053 | pwrdm_lock(clkdm->pwrdm.ptr); |
1000 | 1054 | ||
1001 | /* corner case: disabling unused clocks */ | 1055 | /* corner case: disabling unused clocks */ |
1002 | if ((__clk_get_enable_count(clk) == 0) && | 1056 | if ((__clk_get_enable_count(clk) == 0) && |
@@ -1004,23 +1058,23 @@ int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) | |||
1004 | goto ccd_exit; | 1058 | goto ccd_exit; |
1005 | 1059 | ||
1006 | if (atomic_read(&clkdm->usecount) == 0) { | 1060 | if (atomic_read(&clkdm->usecount) == 0) { |
1007 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1061 | pwrdm_unlock(clkdm->pwrdm.ptr); |
1008 | WARN_ON(1); /* underflow */ | 1062 | WARN_ON(1); /* underflow */ |
1009 | return -ERANGE; | 1063 | return -ERANGE; |
1010 | } | 1064 | } |
1011 | 1065 | ||
1012 | if (atomic_dec_return(&clkdm->usecount) > 0) { | 1066 | if (atomic_dec_return(&clkdm->usecount) > 0) { |
1013 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1067 | pwrdm_unlock(clkdm->pwrdm.ptr); |
1014 | return 0; | 1068 | return 0; |
1015 | } | 1069 | } |
1016 | 1070 | ||
1017 | arch_clkdm->clkdm_clk_disable(clkdm); | 1071 | arch_clkdm->clkdm_clk_disable(clkdm); |
1018 | pwrdm_state_switch(clkdm->pwrdm.ptr); | 1072 | pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
1019 | 1073 | ||
1020 | pr_debug("clockdomain: %s: disabled\n", clkdm->name); | 1074 | pr_debug("clockdomain: %s: disabled\n", clkdm->name); |
1021 | 1075 | ||
1022 | ccd_exit: | 1076 | ccd_exit: |
1023 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1077 | pwrdm_unlock(clkdm->pwrdm.ptr); |
1024 | 1078 | ||
1025 | return 0; | 1079 | return 0; |
1026 | } | 1080 | } |
@@ -1073,8 +1127,6 @@ int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh) | |||
1073 | */ | 1127 | */ |
1074 | int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) | 1128 | int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) |
1075 | { | 1129 | { |
1076 | unsigned long flags; | ||
1077 | |||
1078 | /* The clkdm attribute does not exist yet prior OMAP4 */ | 1130 | /* The clkdm attribute does not exist yet prior OMAP4 */ |
1079 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | 1131 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) |
1080 | return 0; | 1132 | return 0; |
@@ -1087,22 +1139,22 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) | |||
1087 | if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) | 1139 | if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) |
1088 | return -EINVAL; | 1140 | return -EINVAL; |
1089 | 1141 | ||
1090 | spin_lock_irqsave(&clkdm->lock, flags); | 1142 | pwrdm_lock(clkdm->pwrdm.ptr); |
1091 | 1143 | ||
1092 | if (atomic_read(&clkdm->usecount) == 0) { | 1144 | if (atomic_read(&clkdm->usecount) == 0) { |
1093 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1145 | pwrdm_unlock(clkdm->pwrdm.ptr); |
1094 | WARN_ON(1); /* underflow */ | 1146 | WARN_ON(1); /* underflow */ |
1095 | return -ERANGE; | 1147 | return -ERANGE; |
1096 | } | 1148 | } |
1097 | 1149 | ||
1098 | if (atomic_dec_return(&clkdm->usecount) > 0) { | 1150 | if (atomic_dec_return(&clkdm->usecount) > 0) { |
1099 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1151 | pwrdm_unlock(clkdm->pwrdm.ptr); |
1100 | return 0; | 1152 | return 0; |
1101 | } | 1153 | } |
1102 | 1154 | ||
1103 | arch_clkdm->clkdm_clk_disable(clkdm); | 1155 | arch_clkdm->clkdm_clk_disable(clkdm); |
1104 | pwrdm_state_switch(clkdm->pwrdm.ptr); | 1156 | pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
1105 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1157 | pwrdm_unlock(clkdm->pwrdm.ptr); |
1106 | 1158 | ||
1107 | pr_debug("clockdomain: %s: disabled\n", clkdm->name); | 1159 | pr_debug("clockdomain: %s: disabled\n", clkdm->name); |
1108 | 1160 | ||
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h index bc42446e23ab..e7f1b4ba2d5b 100644 --- a/arch/arm/mach-omap2/clockdomain.h +++ b/arch/arm/mach-omap2/clockdomain.h | |||
@@ -15,7 +15,6 @@ | |||
15 | #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H | 15 | #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H |
16 | 16 | ||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/spinlock.h> | ||
19 | 18 | ||
20 | #include "powerdomain.h" | 19 | #include "powerdomain.h" |
21 | #include "clock.h" | 20 | #include "clock.h" |
@@ -139,7 +138,6 @@ struct clockdomain { | |||
139 | struct clkdm_dep *sleepdep_srcs; | 138 | struct clkdm_dep *sleepdep_srcs; |
140 | atomic_t usecount; | 139 | atomic_t usecount; |
141 | struct list_head node; | 140 | struct list_head node; |
142 | spinlock_t lock; | ||
143 | }; | 141 | }; |
144 | 142 | ||
145 | /** | 143 | /** |
@@ -196,12 +194,16 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); | |||
196 | int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); | 194 | int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); |
197 | int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm); | 195 | int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm); |
198 | 196 | ||
197 | void clkdm_allow_idle_nolock(struct clockdomain *clkdm); | ||
199 | void clkdm_allow_idle(struct clockdomain *clkdm); | 198 | void clkdm_allow_idle(struct clockdomain *clkdm); |
199 | void clkdm_deny_idle_nolock(struct clockdomain *clkdm); | ||
200 | void clkdm_deny_idle(struct clockdomain *clkdm); | 200 | void clkdm_deny_idle(struct clockdomain *clkdm); |
201 | bool clkdm_in_hwsup(struct clockdomain *clkdm); | 201 | bool clkdm_in_hwsup(struct clockdomain *clkdm); |
202 | bool clkdm_missing_idle_reporting(struct clockdomain *clkdm); | 202 | bool clkdm_missing_idle_reporting(struct clockdomain *clkdm); |
203 | 203 | ||
204 | int clkdm_wakeup_nolock(struct clockdomain *clkdm); | ||
204 | int clkdm_wakeup(struct clockdomain *clkdm); | 205 | int clkdm_wakeup(struct clockdomain *clkdm); |
206 | int clkdm_sleep_nolock(struct clockdomain *clkdm); | ||
205 | int clkdm_sleep(struct clockdomain *clkdm); | 207 | int clkdm_sleep(struct clockdomain *clkdm); |
206 | 208 | ||
207 | int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); | 209 | int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); |
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 65c34645c8ed..8e61d80bf6b3 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/list.h> | 19 | #include <linux/list.h> |
20 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
21 | #include <linux/string.h> | 21 | #include <linux/string.h> |
22 | #include <linux/spinlock.h> | ||
22 | #include <trace/events/power.h> | 23 | #include <trace/events/power.h> |
23 | 24 | ||
24 | #include "cm2xxx_3xxx.h" | 25 | #include "cm2xxx_3xxx.h" |
@@ -111,6 +112,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm) | |||
111 | pwrdm->voltdm.ptr = voltdm; | 112 | pwrdm->voltdm.ptr = voltdm; |
112 | INIT_LIST_HEAD(&pwrdm->voltdm_node); | 113 | INIT_LIST_HEAD(&pwrdm->voltdm_node); |
113 | voltdm_add_pwrdm(voltdm, pwrdm); | 114 | voltdm_add_pwrdm(voltdm, pwrdm); |
115 | spin_lock_init(&pwrdm->_lock); | ||
114 | 116 | ||
115 | list_add(&pwrdm->node, &pwrdm_list); | 117 | list_add(&pwrdm->node, &pwrdm_list); |
116 | 118 | ||
@@ -241,7 +243,7 @@ static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm, | |||
241 | sleep_switch = LOWPOWERSTATE_SWITCH; | 243 | sleep_switch = LOWPOWERSTATE_SWITCH; |
242 | } else { | 244 | } else { |
243 | *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); | 245 | *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); |
244 | clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); | 246 | clkdm_wakeup_nolock(pwrdm->pwrdm_clkdms[0]); |
245 | sleep_switch = FORCEWAKEUP_SWITCH; | 247 | sleep_switch = FORCEWAKEUP_SWITCH; |
246 | } | 248 | } |
247 | } else { | 249 | } else { |
@@ -271,15 +273,15 @@ static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm, | |||
271 | switch (sleep_switch) { | 273 | switch (sleep_switch) { |
272 | case FORCEWAKEUP_SWITCH: | 274 | case FORCEWAKEUP_SWITCH: |
273 | if (hwsup) | 275 | if (hwsup) |
274 | clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); | 276 | clkdm_allow_idle_nolock(pwrdm->pwrdm_clkdms[0]); |
275 | else | 277 | else |
276 | clkdm_sleep(pwrdm->pwrdm_clkdms[0]); | 278 | clkdm_sleep_nolock(pwrdm->pwrdm_clkdms[0]); |
277 | break; | 279 | break; |
278 | case LOWPOWERSTATE_SWITCH: | 280 | case LOWPOWERSTATE_SWITCH: |
279 | if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE && | 281 | if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE && |
280 | arch_pwrdm->pwrdm_set_lowpwrstchange) | 282 | arch_pwrdm->pwrdm_set_lowpwrstchange) |
281 | arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm); | 283 | arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm); |
282 | pwrdm_state_switch(pwrdm); | 284 | pwrdm_state_switch_nolock(pwrdm); |
283 | break; | 285 | break; |
284 | } | 286 | } |
285 | } | 287 | } |
@@ -360,6 +362,30 @@ int pwrdm_complete_init(void) | |||
360 | } | 362 | } |
361 | 363 | ||
362 | /** | 364 | /** |
365 | * pwrdm_lock - acquire a Linux spinlock on a powerdomain | ||
366 | * @pwrdm: struct powerdomain * to lock | ||
367 | * | ||
368 | * Acquire the powerdomain spinlock on @pwrdm. No return value. | ||
369 | */ | ||
370 | void pwrdm_lock(struct powerdomain *pwrdm) | ||
371 | __acquires(&pwrdm->_lock) | ||
372 | { | ||
373 | spin_lock_irqsave(&pwrdm->_lock, pwrdm->_lock_flags); | ||
374 | } | ||
375 | |||
376 | /** | ||
377 | * pwrdm_unlock - release a Linux spinlock on a powerdomain | ||
378 | * @pwrdm: struct powerdomain * to unlock | ||
379 | * | ||
380 | * Release the powerdomain spinlock on @pwrdm. No return value. | ||
381 | */ | ||
382 | void pwrdm_unlock(struct powerdomain *pwrdm) | ||
383 | __releases(&pwrdm->_lock) | ||
384 | { | ||
385 | spin_unlock_irqrestore(&pwrdm->_lock, pwrdm->_lock_flags); | ||
386 | } | ||
387 | |||
388 | /** | ||
363 | * pwrdm_lookup - look up a powerdomain by name, return a pointer | 389 | * pwrdm_lookup - look up a powerdomain by name, return a pointer |
364 | * @name: name of powerdomain | 390 | * @name: name of powerdomain |
365 | * | 391 | * |
@@ -1005,7 +1031,7 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm) | |||
1005 | return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0; | 1031 | return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0; |
1006 | } | 1032 | } |
1007 | 1033 | ||
1008 | int pwrdm_state_switch(struct powerdomain *pwrdm) | 1034 | int pwrdm_state_switch_nolock(struct powerdomain *pwrdm) |
1009 | { | 1035 | { |
1010 | int ret; | 1036 | int ret; |
1011 | 1037 | ||
@@ -1019,6 +1045,17 @@ int pwrdm_state_switch(struct powerdomain *pwrdm) | |||
1019 | return ret; | 1045 | return ret; |
1020 | } | 1046 | } |
1021 | 1047 | ||
1048 | int __deprecated pwrdm_state_switch(struct powerdomain *pwrdm) | ||
1049 | { | ||
1050 | int ret; | ||
1051 | |||
1052 | pwrdm_lock(pwrdm); | ||
1053 | ret = pwrdm_state_switch_nolock(pwrdm); | ||
1054 | pwrdm_unlock(pwrdm); | ||
1055 | |||
1056 | return ret; | ||
1057 | } | ||
1058 | |||
1022 | int pwrdm_pre_transition(struct powerdomain *pwrdm) | 1059 | int pwrdm_pre_transition(struct powerdomain *pwrdm) |
1023 | { | 1060 | { |
1024 | if (pwrdm) | 1061 | if (pwrdm) |
@@ -1067,15 +1104,19 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst) | |||
1067 | pwrst--; | 1104 | pwrst--; |
1068 | } | 1105 | } |
1069 | 1106 | ||
1107 | pwrdm_lock(pwrdm); | ||
1108 | |||
1070 | curr_pwrst = pwrdm_read_pwrst(pwrdm); | 1109 | curr_pwrst = pwrdm_read_pwrst(pwrdm); |
1071 | next_pwrst = pwrdm_read_next_pwrst(pwrdm); | 1110 | next_pwrst = pwrdm_read_next_pwrst(pwrdm); |
1072 | if (curr_pwrst == pwrst && next_pwrst == pwrst) | 1111 | if (curr_pwrst == pwrst && next_pwrst == pwrst) |
1073 | return ret; | 1112 | goto osps_out; |
1074 | 1113 | ||
1075 | sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst, | 1114 | sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst, |
1076 | pwrst, &hwsup); | 1115 | pwrst, &hwsup); |
1077 | if (sleep_switch == ERROR_SWITCH) | 1116 | if (sleep_switch == ERROR_SWITCH) { |
1078 | return -EINVAL; | 1117 | ret = -EINVAL; |
1118 | goto osps_out; | ||
1119 | } | ||
1079 | 1120 | ||
1080 | ret = pwrdm_set_next_pwrst(pwrdm, pwrst); | 1121 | ret = pwrdm_set_next_pwrst(pwrdm, pwrst); |
1081 | if (ret) | 1122 | if (ret) |
@@ -1084,6 +1125,9 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst) | |||
1084 | 1125 | ||
1085 | _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup); | 1126 | _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup); |
1086 | 1127 | ||
1128 | osps_out: | ||
1129 | pwrdm_unlock(pwrdm); | ||
1130 | |||
1087 | return ret; | 1131 | return ret; |
1088 | } | 1132 | } |
1089 | 1133 | ||
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 93e7df824650..909cc5c1c23a 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h | |||
@@ -19,8 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | 22 | #include <linux/spinlock.h> | |
23 | #include <linux/atomic.h> | ||
24 | 23 | ||
25 | #include "voltage.h" | 24 | #include "voltage.h" |
26 | 25 | ||
@@ -103,6 +102,8 @@ struct powerdomain; | |||
103 | * @state_counter: | 102 | * @state_counter: |
104 | * @timer: | 103 | * @timer: |
105 | * @state_timer: | 104 | * @state_timer: |
105 | * @_lock: spinlock used to serialize powerdomain and some clockdomain ops | ||
106 | * @_lock_flags: stored flags when @_lock is taken | ||
106 | * | 107 | * |
107 | * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. | 108 | * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. |
108 | */ | 109 | */ |
@@ -127,7 +128,8 @@ struct powerdomain { | |||
127 | unsigned state_counter[PWRDM_MAX_PWRSTS]; | 128 | unsigned state_counter[PWRDM_MAX_PWRSTS]; |
128 | unsigned ret_logic_off_counter; | 129 | unsigned ret_logic_off_counter; |
129 | unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS]; | 130 | unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS]; |
130 | 131 | spinlock_t _lock; | |
132 | unsigned long _lock_flags; | ||
131 | const u8 pwrstctrl_offs; | 133 | const u8 pwrstctrl_offs; |
132 | const u8 pwrstst_offs; | 134 | const u8 pwrstst_offs; |
133 | const u32 logicretstate_mask; | 135 | const u32 logicretstate_mask; |
@@ -235,6 +237,7 @@ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm); | |||
235 | int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); | 237 | int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); |
236 | bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); | 238 | bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); |
237 | 239 | ||
240 | int pwrdm_state_switch_nolock(struct powerdomain *pwrdm); | ||
238 | int pwrdm_state_switch(struct powerdomain *pwrdm); | 241 | int pwrdm_state_switch(struct powerdomain *pwrdm); |
239 | int pwrdm_pre_transition(struct powerdomain *pwrdm); | 242 | int pwrdm_pre_transition(struct powerdomain *pwrdm); |
240 | int pwrdm_post_transition(struct powerdomain *pwrdm); | 243 | int pwrdm_post_transition(struct powerdomain *pwrdm); |
@@ -262,5 +265,7 @@ extern u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank); | |||
262 | extern struct powerdomain wkup_omap2_pwrdm; | 265 | extern struct powerdomain wkup_omap2_pwrdm; |
263 | extern struct powerdomain gfx_omap2_pwrdm; | 266 | extern struct powerdomain gfx_omap2_pwrdm; |
264 | 267 | ||
268 | extern void pwrdm_lock(struct powerdomain *pwrdm); | ||
269 | extern void pwrdm_unlock(struct powerdomain *pwrdm); | ||
265 | 270 | ||
266 | #endif | 271 | #endif |