aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/clockdomain.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/clockdomain.c')
-rw-r--r--arch/arm/mach-omap2/clockdomain.c220
1 files changed, 124 insertions, 96 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 6fb61b1a0d46..e20b98636ab4 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -13,7 +13,6 @@
13 */ 13 */
14#undef DEBUG 14#undef DEBUG
15 15
16#include <linux/module.h>
17#include <linux/kernel.h> 16#include <linux/kernel.h>
18#include <linux/device.h> 17#include <linux/device.h>
19#include <linux/list.h> 18#include <linux/list.h>
@@ -27,13 +26,16 @@
27 26
28#include <linux/bitops.h> 27#include <linux/bitops.h>
29 28
30#include "prm.h" 29#include "prm2xxx_3xxx.h"
31#include "prm-regbits-24xx.h" 30#include "prm-regbits-24xx.h"
32#include "cm.h" 31#include "cm2xxx_3xxx.h"
32#include "cm-regbits-24xx.h"
33#include "cminst44xx.h"
34#include "prcm44xx.h"
33 35
34#include <plat/clock.h> 36#include <plat/clock.h>
35#include <plat/powerdomain.h> 37#include "powerdomain.h"
36#include <plat/clockdomain.h> 38#include "clockdomain.h"
37#include <plat/prcm.h> 39#include <plat/prcm.h>
38 40
39/* clkdm_list contains all registered struct clockdomains */ 41/* clkdm_list contains all registered struct clockdomains */
@@ -141,6 +143,9 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,
141 * clockdomain is in hardware-supervised mode. Meant to be called 143 * clockdomain is in hardware-supervised mode. Meant to be called
142 * once at clockdomain layer initialization, since these should remain 144 * once at clockdomain layer initialization, since these should remain
143 * fixed for a particular architecture. No return value. 145 * fixed for a particular architecture. No return value.
146 *
147 * XXX autodeps are deprecated and should be removed at the earliest
148 * opportunity
144 */ 149 */
145static void _autodep_lookup(struct clkdm_autodep *autodep) 150static void _autodep_lookup(struct clkdm_autodep *autodep)
146{ 151{
@@ -168,6 +173,9 @@ static void _autodep_lookup(struct clkdm_autodep *autodep)
168 * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' 173 * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
169 * in hardware-supervised mode. Meant to be called from clock framework 174 * in hardware-supervised mode. Meant to be called from clock framework
170 * when a clock inside clockdomain 'clkdm' is enabled. No return value. 175 * when a clock inside clockdomain 'clkdm' is enabled. No return value.
176 *
177 * XXX autodeps are deprecated and should be removed at the earliest
178 * opportunity
171 */ 179 */
172static void _clkdm_add_autodeps(struct clockdomain *clkdm) 180static void _clkdm_add_autodeps(struct clockdomain *clkdm)
173{ 181{
@@ -199,6 +207,9 @@ static void _clkdm_add_autodeps(struct clockdomain *clkdm)
199 * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' 207 * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
200 * in hardware-supervised mode. Meant to be called from clock framework 208 * in hardware-supervised mode. Meant to be called from clock framework
201 * when a clock inside clockdomain 'clkdm' is disabled. No return value. 209 * when a clock inside clockdomain 'clkdm' is disabled. No return value.
210 *
211 * XXX autodeps are deprecated and should be removed at the earliest
212 * opportunity
202 */ 213 */
203static void _clkdm_del_autodeps(struct clockdomain *clkdm) 214static void _clkdm_del_autodeps(struct clockdomain *clkdm)
204{ 215{
@@ -223,39 +234,56 @@ static void _clkdm_del_autodeps(struct clockdomain *clkdm)
223 } 234 }
224} 235}
225 236
226/* 237/**
227 * _omap2_clkdm_set_hwsup - set the hwsup idle transition bit 238 * _enable_hwsup - place a clockdomain into hardware-supervised idle
228 * @clkdm: struct clockdomain * 239 * @clkdm: struct clockdomain *
229 * @enable: int 0 to disable, 1 to enable
230 * 240 *
231 * Internal helper for actually switching the bit that controls hwsup 241 * Place the clockdomain into hardware-supervised idle mode. No return
232 * idle transitions for clkdm. 242 * value.
243 *
244 * XXX Should this return an error if the clockdomain does not support
245 * hardware-supervised idle mode?
233 */ 246 */
234static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable) 247static void _enable_hwsup(struct clockdomain *clkdm)
235{ 248{
236 u32 bits, v; 249 if (cpu_is_omap24xx())
237 250 omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
238 if (cpu_is_omap24xx()) { 251 clkdm->clktrctrl_mask);
239 if (enable) 252 else if (cpu_is_omap34xx())
240 bits = OMAP24XX_CLKSTCTRL_ENABLE_AUTO; 253 omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
241 else 254 clkdm->clktrctrl_mask);
242 bits = OMAP24XX_CLKSTCTRL_DISABLE_AUTO; 255 else if (cpu_is_omap44xx())
243 } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) { 256 return omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
244 if (enable) 257 clkdm->cm_inst,
245 bits = OMAP34XX_CLKSTCTRL_ENABLE_AUTO; 258 clkdm->clkdm_offs);
246 else 259 else
247 bits = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
248 } else {
249 BUG(); 260 BUG();
250 } 261}
251
252 bits = bits << __ffs(clkdm->clktrctrl_mask);
253
254 v = __raw_readl(clkdm->clkstctrl_reg);
255 v &= ~(clkdm->clktrctrl_mask);
256 v |= bits;
257 __raw_writel(v, clkdm->clkstctrl_reg);
258 262
263/**
264 * _disable_hwsup - place a clockdomain into software-supervised idle
265 * @clkdm: struct clockdomain *
266 *
267 * Place the clockdomain @clkdm into software-supervised idle mode.
268 * No return value.
269 *
270 * XXX Should this return an error if the clockdomain does not support
271 * software-supervised idle mode?
272 */
273static void _disable_hwsup(struct clockdomain *clkdm)
274{
275 if (cpu_is_omap24xx())
276 omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
277 clkdm->clktrctrl_mask);
278 else if (cpu_is_omap34xx())
279 omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
280 clkdm->clktrctrl_mask);
281 else if (cpu_is_omap44xx())
282 return omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
283 clkdm->cm_inst,
284 clkdm->clkdm_offs);
285 else
286 BUG();
259} 287}
260 288
261/* Public functions */ 289/* Public functions */
@@ -409,7 +437,7 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
409 pr_debug("clockdomain: hardware will wake up %s when %s wakes " 437 pr_debug("clockdomain: hardware will wake up %s when %s wakes "
410 "up\n", clkdm1->name, clkdm2->name); 438 "up\n", clkdm1->name, clkdm2->name);
411 439
412 prm_set_mod_reg_bits((1 << clkdm2->dep_bit), 440 omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
413 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); 441 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
414 } 442 }
415 443
@@ -444,7 +472,7 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
444 pr_debug("clockdomain: hardware will no longer wake up %s " 472 pr_debug("clockdomain: hardware will no longer wake up %s "
445 "after %s wakes up\n", clkdm1->name, clkdm2->name); 473 "after %s wakes up\n", clkdm1->name, clkdm2->name);
446 474
447 prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), 475 omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
448 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); 476 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
449 } 477 }
450 478
@@ -480,7 +508,7 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
480 } 508 }
481 509
482 /* XXX It's faster to return the atomic wkdep_usecount */ 510 /* XXX It's faster to return the atomic wkdep_usecount */
483 return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP, 511 return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP,
484 (1 << clkdm2->dep_bit)); 512 (1 << clkdm2->dep_bit));
485} 513}
486 514
@@ -514,7 +542,7 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
514 atomic_set(&cd->wkdep_usecount, 0); 542 atomic_set(&cd->wkdep_usecount, 0);
515 } 543 }
516 544
517 prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP); 545 omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP);
518 546
519 return 0; 547 return 0;
520} 548}
@@ -553,7 +581,7 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
553 pr_debug("clockdomain: will prevent %s from sleeping if %s " 581 pr_debug("clockdomain: will prevent %s from sleeping if %s "
554 "is active\n", clkdm1->name, clkdm2->name); 582 "is active\n", clkdm1->name, clkdm2->name);
555 583
556 cm_set_mod_reg_bits((1 << clkdm2->dep_bit), 584 omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
557 clkdm1->pwrdm.ptr->prcm_offs, 585 clkdm1->pwrdm.ptr->prcm_offs,
558 OMAP3430_CM_SLEEPDEP); 586 OMAP3430_CM_SLEEPDEP);
559 } 587 }
@@ -596,7 +624,7 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
596 "sleeping if %s is active\n", clkdm1->name, 624 "sleeping if %s is active\n", clkdm1->name,
597 clkdm2->name); 625 clkdm2->name);
598 626
599 cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), 627 omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
600 clkdm1->pwrdm.ptr->prcm_offs, 628 clkdm1->pwrdm.ptr->prcm_offs,
601 OMAP3430_CM_SLEEPDEP); 629 OMAP3430_CM_SLEEPDEP);
602 } 630 }
@@ -639,7 +667,7 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
639 } 667 }
640 668
641 /* XXX It's faster to return the atomic sleepdep_usecount */ 669 /* XXX It's faster to return the atomic sleepdep_usecount */
642 return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, 670 return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
643 OMAP3430_CM_SLEEPDEP, 671 OMAP3430_CM_SLEEPDEP,
644 (1 << clkdm2->dep_bit)); 672 (1 << clkdm2->dep_bit));
645} 673}
@@ -677,35 +705,13 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
677 atomic_set(&cd->sleepdep_usecount, 0); 705 atomic_set(&cd->sleepdep_usecount, 0);
678 } 706 }
679 707
680 prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, 708 omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
681 OMAP3430_CM_SLEEPDEP); 709 OMAP3430_CM_SLEEPDEP);
682 710
683 return 0; 711 return 0;
684} 712}
685 713
686/** 714/**
687 * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode
688 * @clkdm: struct clkdm * of a clockdomain
689 *
690 * Return the clockdomain @clkdm current state transition mode from the
691 * corresponding domain CM_CLKSTCTRL register. Returns -EINVAL if @clkdm
692 * is NULL or the current mode upon success.
693 */
694static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm)
695{
696 u32 v;
697
698 if (!clkdm)
699 return -EINVAL;
700
701 v = __raw_readl(clkdm->clkstctrl_reg);
702 v &= clkdm->clktrctrl_mask;
703 v >>= __ffs(clkdm->clktrctrl_mask);
704
705 return v;
706}
707
708/**
709 * omap2_clkdm_sleep - force clockdomain sleep transition 715 * omap2_clkdm_sleep - force clockdomain sleep transition
710 * @clkdm: struct clockdomain * 716 * @clkdm: struct clockdomain *
711 * 717 *
@@ -729,18 +735,19 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm)
729 735
730 if (cpu_is_omap24xx()) { 736 if (cpu_is_omap24xx()) {
731 737
732 cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 738 omap2_cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
733 clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); 739 clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL);
734 740
735 } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) { 741 } else if (cpu_is_omap34xx()) {
742
743 omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
744 clkdm->clktrctrl_mask);
736 745
737 u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP << 746 } else if (cpu_is_omap44xx()) {
738 __ffs(clkdm->clktrctrl_mask));
739 747
740 u32 v = __raw_readl(clkdm->clkstctrl_reg); 748 omap4_cminst_clkdm_force_sleep(clkdm->prcm_partition,
741 v &= ~(clkdm->clktrctrl_mask); 749 clkdm->cm_inst,
742 v |= bits; 750 clkdm->clkdm_offs);
743 __raw_writel(v, clkdm->clkstctrl_reg);
744 751
745 } else { 752 } else {
746 BUG(); 753 BUG();
@@ -773,18 +780,19 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm)
773 780
774 if (cpu_is_omap24xx()) { 781 if (cpu_is_omap24xx()) {
775 782
776 cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 783 omap2_cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
777 clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); 784 clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL);
778 785
779 } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) { 786 } else if (cpu_is_omap34xx()) {
780 787
781 u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP << 788 omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs,
782 __ffs(clkdm->clktrctrl_mask)); 789 clkdm->clktrctrl_mask);
783 790
784 u32 v = __raw_readl(clkdm->clkstctrl_reg); 791 } else if (cpu_is_omap44xx()) {
785 v &= ~(clkdm->clktrctrl_mask); 792
786 v |= bits; 793 omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
787 __raw_writel(v, clkdm->clkstctrl_reg); 794 clkdm->cm_inst,
795 clkdm->clkdm_offs);
788 796
789 } else { 797 } else {
790 BUG(); 798 BUG();
@@ -829,7 +837,7 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
829 _clkdm_add_autodeps(clkdm); 837 _clkdm_add_autodeps(clkdm);
830 } 838 }
831 839
832 _omap2_clkdm_set_hwsup(clkdm, 1); 840 _enable_hwsup(clkdm);
833 841
834 pwrdm_clkdm_state_switch(clkdm); 842 pwrdm_clkdm_state_switch(clkdm);
835} 843}
@@ -857,7 +865,7 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
857 pr_debug("clockdomain: disabling automatic idle transitions for %s\n", 865 pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
858 clkdm->name); 866 clkdm->name);
859 867
860 _omap2_clkdm_set_hwsup(clkdm, 0); 868 _disable_hwsup(clkdm);
861 869
862 /* 870 /*
863 * XXX This should be removed once TI adds wakeup/sleep 871 * XXX This should be removed once TI adds wakeup/sleep
@@ -891,7 +899,7 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
891 */ 899 */
892int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) 900int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
893{ 901{
894 int v; 902 bool hwsup = false;
895 903
896 /* 904 /*
897 * XXX Rewrite this code to maintain a list of enabled 905 * XXX Rewrite this code to maintain a list of enabled
@@ -909,17 +917,27 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
909 pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name, 917 pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name,
910 clk->name); 918 clk->name);
911 919
912 if (!clkdm->clkstctrl_reg) 920 if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
913 return 0;
914 921
915 v = omap2_clkdm_clktrctrl_read(clkdm); 922 if (!clkdm->clktrctrl_mask)
923 return 0;
916 924
917 if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) || 925 hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
918 (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) { 926 clkdm->clktrctrl_mask);
927
928 } else if (cpu_is_omap44xx()) {
929
930 hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
931 clkdm->cm_inst,
932 clkdm->clkdm_offs);
933
934 }
935
936 if (hwsup) {
919 /* Disable HW transitions when we are changing deps */ 937 /* Disable HW transitions when we are changing deps */
920 _omap2_clkdm_set_hwsup(clkdm, 0); 938 _disable_hwsup(clkdm);
921 _clkdm_add_autodeps(clkdm); 939 _clkdm_add_autodeps(clkdm);
922 _omap2_clkdm_set_hwsup(clkdm, 1); 940 _enable_hwsup(clkdm);
923 } else { 941 } else {
924 omap2_clkdm_wakeup(clkdm); 942 omap2_clkdm_wakeup(clkdm);
925 } 943 }
@@ -946,7 +964,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
946 */ 964 */
947int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) 965int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
948{ 966{
949 int v; 967 bool hwsup = false;
950 968
951 /* 969 /*
952 * XXX Rewrite this code to maintain a list of enabled 970 * XXX Rewrite this code to maintain a list of enabled
@@ -971,17 +989,27 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
971 pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name, 989 pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name,
972 clk->name); 990 clk->name);
973 991
974 if (!clkdm->clkstctrl_reg) 992 if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
975 return 0;
976 993
977 v = omap2_clkdm_clktrctrl_read(clkdm); 994 if (!clkdm->clktrctrl_mask)
995 return 0;
996
997 hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
998 clkdm->clktrctrl_mask);
999
1000 } else if (cpu_is_omap44xx()) {
1001
1002 hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
1003 clkdm->cm_inst,
1004 clkdm->clkdm_offs);
1005
1006 }
978 1007
979 if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) || 1008 if (hwsup) {
980 (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) {
981 /* Disable HW transitions when we are changing deps */ 1009 /* Disable HW transitions when we are changing deps */
982 _omap2_clkdm_set_hwsup(clkdm, 0); 1010 _disable_hwsup(clkdm);
983 _clkdm_del_autodeps(clkdm); 1011 _clkdm_del_autodeps(clkdm);
984 _omap2_clkdm_set_hwsup(clkdm, 1); 1012 _enable_hwsup(clkdm);
985 } else { 1013 } else {
986 omap2_clkdm_sleep(clkdm); 1014 omap2_clkdm_sleep(clkdm);
987 } 1015 }