diff options
Diffstat (limited to 'arch/arm/mach-omap2/clock.c')
-rw-r--r-- | arch/arm/mach-omap2/clock.c | 146 |
1 files changed, 123 insertions, 23 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index d1b648a4efbf..0de201c3d50b 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c | |||
@@ -32,10 +32,14 @@ | |||
32 | #include "memory.h" | 32 | #include "memory.h" |
33 | #include "clock.h" | 33 | #include "clock.h" |
34 | 34 | ||
35 | #undef DEBUG | ||
36 | |||
35 | //#define DOWN_VARIABLE_DPLL 1 /* Experimental */ | 37 | //#define DOWN_VARIABLE_DPLL 1 /* Experimental */ |
36 | 38 | ||
37 | static struct prcm_config *curr_prcm_set; | 39 | static struct prcm_config *curr_prcm_set; |
38 | static u32 curr_perf_level = PRCM_FULL_SPEED; | 40 | static u32 curr_perf_level = PRCM_FULL_SPEED; |
41 | static struct clk *vclk; | ||
42 | static struct clk *sclk; | ||
39 | 43 | ||
40 | /*------------------------------------------------------------------------- | 44 | /*------------------------------------------------------------------------- |
41 | * Omap2 specific clock functions | 45 | * Omap2 specific clock functions |
@@ -79,6 +83,14 @@ static void omap2_propagate_rate(struct clk * clk) | |||
79 | propagate_rate(clk); | 83 | propagate_rate(clk); |
80 | } | 84 | } |
81 | 85 | ||
86 | static void omap2_set_osc_ck(int enable) | ||
87 | { | ||
88 | if (enable) | ||
89 | PRCM_CLKSRC_CTRL &= ~(0x3 << 3); | ||
90 | else | ||
91 | PRCM_CLKSRC_CTRL |= 0x3 << 3; | ||
92 | } | ||
93 | |||
82 | /* Enable an APLL if off */ | 94 | /* Enable an APLL if off */ |
83 | static void omap2_clk_fixed_enable(struct clk *clk) | 95 | static void omap2_clk_fixed_enable(struct clk *clk) |
84 | { | 96 | { |
@@ -101,12 +113,54 @@ static void omap2_clk_fixed_enable(struct clk *clk) | |||
101 | else if (clk == &apll54_ck) | 113 | else if (clk == &apll54_ck) |
102 | cval = (1 << 6); | 114 | cval = (1 << 6); |
103 | 115 | ||
104 | while (!CM_IDLEST_CKGEN & cval) { /* Wait for lock */ | 116 | while (!(CM_IDLEST_CKGEN & cval)) { /* Wait for lock */ |
105 | ++i; | 117 | ++i; |
106 | udelay(1); | 118 | udelay(1); |
107 | if (i == 100000) | 119 | if (i == 100000) { |
120 | printk(KERN_ERR "Clock %s didn't lock\n", clk->name); | ||
121 | break; | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static void omap2_clk_wait_ready(struct clk *clk) | ||
127 | { | ||
128 | unsigned long reg, other_reg, st_reg; | ||
129 | u32 bit; | ||
130 | int i; | ||
131 | |||
132 | reg = (unsigned long) clk->enable_reg; | ||
133 | if (reg == (unsigned long) &CM_FCLKEN1_CORE || | ||
134 | reg == (unsigned long) &CM_FCLKEN2_CORE) | ||
135 | other_reg = (reg & ~0xf0) | 0x10; | ||
136 | else if (reg == (unsigned long) &CM_ICLKEN1_CORE || | ||
137 | reg == (unsigned long) &CM_ICLKEN2_CORE) | ||
138 | other_reg = (reg & ~0xf0) | 0x00; | ||
139 | else | ||
140 | return; | ||
141 | |||
142 | /* No check for DSS or cam clocks */ | ||
143 | if ((reg & 0x0f) == 0) { | ||
144 | if (clk->enable_bit <= 1 || clk->enable_bit == 31) | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | /* Check if both functional and interface clocks | ||
149 | * are running. */ | ||
150 | bit = 1 << clk->enable_bit; | ||
151 | if (!(__raw_readl(other_reg) & bit)) | ||
152 | return; | ||
153 | st_reg = (other_reg & ~0xf0) | 0x20; | ||
154 | i = 0; | ||
155 | while (!(__raw_readl(st_reg) & bit)) { | ||
156 | i++; | ||
157 | if (i == 100000) { | ||
158 | printk(KERN_ERR "Timeout enabling clock %s\n", clk->name); | ||
108 | break; | 159 | break; |
160 | } | ||
109 | } | 161 | } |
162 | if (i) | ||
163 | pr_debug("Clock %s stable after %d loops\n", clk->name, i); | ||
110 | } | 164 | } |
111 | 165 | ||
112 | /* Enables clock without considering parent dependencies or use count | 166 | /* Enables clock without considering parent dependencies or use count |
@@ -119,6 +173,11 @@ static int _omap2_clk_enable(struct clk * clk) | |||
119 | if (clk->flags & ALWAYS_ENABLED) | 173 | if (clk->flags & ALWAYS_ENABLED) |
120 | return 0; | 174 | return 0; |
121 | 175 | ||
176 | if (unlikely(clk == &osc_ck)) { | ||
177 | omap2_set_osc_ck(1); | ||
178 | return 0; | ||
179 | } | ||
180 | |||
122 | if (unlikely(clk->enable_reg == 0)) { | 181 | if (unlikely(clk->enable_reg == 0)) { |
123 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", | 182 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", |
124 | clk->name); | 183 | clk->name); |
@@ -133,6 +192,9 @@ static int _omap2_clk_enable(struct clk * clk) | |||
133 | regval32 = __raw_readl(clk->enable_reg); | 192 | regval32 = __raw_readl(clk->enable_reg); |
134 | regval32 |= (1 << clk->enable_bit); | 193 | regval32 |= (1 << clk->enable_bit); |
135 | __raw_writel(regval32, clk->enable_reg); | 194 | __raw_writel(regval32, clk->enable_reg); |
195 | wmb(); | ||
196 | |||
197 | omap2_clk_wait_ready(clk); | ||
136 | 198 | ||
137 | return 0; | 199 | return 0; |
138 | } | 200 | } |
@@ -155,6 +217,11 @@ static void _omap2_clk_disable(struct clk *clk) | |||
155 | { | 217 | { |
156 | u32 regval32; | 218 | u32 regval32; |
157 | 219 | ||
220 | if (unlikely(clk == &osc_ck)) { | ||
221 | omap2_set_osc_ck(0); | ||
222 | return; | ||
223 | } | ||
224 | |||
158 | if (clk->enable_reg == 0) | 225 | if (clk->enable_reg == 0) |
159 | return; | 226 | return; |
160 | 227 | ||
@@ -166,6 +233,7 @@ static void _omap2_clk_disable(struct clk *clk) | |||
166 | regval32 = __raw_readl(clk->enable_reg); | 233 | regval32 = __raw_readl(clk->enable_reg); |
167 | regval32 &= ~(1 << clk->enable_bit); | 234 | regval32 &= ~(1 << clk->enable_bit); |
168 | __raw_writel(regval32, clk->enable_reg); | 235 | __raw_writel(regval32, clk->enable_reg); |
236 | wmb(); | ||
169 | } | 237 | } |
170 | 238 | ||
171 | static int omap2_clk_enable(struct clk *clk) | 239 | static int omap2_clk_enable(struct clk *clk) |
@@ -695,12 +763,14 @@ static int omap2_clk_set_rate(struct clk *clk, unsigned long rate) | |||
695 | reg_val = __raw_readl(reg); | 763 | reg_val = __raw_readl(reg); |
696 | reg_val &= ~(field_mask << div_off); | 764 | reg_val &= ~(field_mask << div_off); |
697 | reg_val |= (field_val << div_off); | 765 | reg_val |= (field_val << div_off); |
698 | |||
699 | __raw_writel(reg_val, reg); | 766 | __raw_writel(reg_val, reg); |
767 | wmb(); | ||
700 | clk->rate = clk->parent->rate / field_val; | 768 | clk->rate = clk->parent->rate / field_val; |
701 | 769 | ||
702 | if (clk->flags & DELAYED_APP) | 770 | if (clk->flags & DELAYED_APP) { |
703 | __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL); | 771 | __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL); |
772 | wmb(); | ||
773 | } | ||
704 | ret = 0; | 774 | ret = 0; |
705 | } else if (clk->set_rate != 0) | 775 | } else if (clk->set_rate != 0) |
706 | ret = clk->set_rate(clk, rate); | 776 | ret = clk->set_rate(clk, rate); |
@@ -836,10 +906,12 @@ static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) | |||
836 | reg_val = __raw_readl(reg) & ~(field_mask << src_off); | 906 | reg_val = __raw_readl(reg) & ~(field_mask << src_off); |
837 | reg_val |= (field_val << src_off); | 907 | reg_val |= (field_val << src_off); |
838 | __raw_writel(reg_val, reg); | 908 | __raw_writel(reg_val, reg); |
909 | wmb(); | ||
839 | 910 | ||
840 | if (clk->flags & DELAYED_APP) | 911 | if (clk->flags & DELAYED_APP) { |
841 | __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL); | 912 | __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL); |
842 | 913 | wmb(); | |
914 | } | ||
843 | if (clk->usecount > 0) | 915 | if (clk->usecount > 0) |
844 | _omap2_clk_enable(clk); | 916 | _omap2_clk_enable(clk); |
845 | 917 | ||
@@ -953,12 +1025,29 @@ static int omap2_select_table_rate(struct clk * clk, unsigned long rate) | |||
953 | * Omap2 clock reset and init functions | 1025 | * Omap2 clock reset and init functions |
954 | *-------------------------------------------------------------------------*/ | 1026 | *-------------------------------------------------------------------------*/ |
955 | 1027 | ||
1028 | #ifdef CONFIG_OMAP_RESET_CLOCKS | ||
1029 | static void __init omap2_clk_disable_unused(struct clk *clk) | ||
1030 | { | ||
1031 | u32 regval32; | ||
1032 | |||
1033 | regval32 = __raw_readl(clk->enable_reg); | ||
1034 | if ((regval32 & (1 << clk->enable_bit)) == 0) | ||
1035 | return; | ||
1036 | |||
1037 | printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name); | ||
1038 | _omap2_clk_disable(clk); | ||
1039 | } | ||
1040 | #else | ||
1041 | #define omap2_clk_disable_unused NULL | ||
1042 | #endif | ||
1043 | |||
956 | static struct clk_functions omap2_clk_functions = { | 1044 | static struct clk_functions omap2_clk_functions = { |
957 | .clk_enable = omap2_clk_enable, | 1045 | .clk_enable = omap2_clk_enable, |
958 | .clk_disable = omap2_clk_disable, | 1046 | .clk_disable = omap2_clk_disable, |
959 | .clk_round_rate = omap2_clk_round_rate, | 1047 | .clk_round_rate = omap2_clk_round_rate, |
960 | .clk_set_rate = omap2_clk_set_rate, | 1048 | .clk_set_rate = omap2_clk_set_rate, |
961 | .clk_set_parent = omap2_clk_set_parent, | 1049 | .clk_set_parent = omap2_clk_set_parent, |
1050 | .clk_disable_unused = omap2_clk_disable_unused, | ||
962 | }; | 1051 | }; |
963 | 1052 | ||
964 | static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys) | 1053 | static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys) |
@@ -984,27 +1073,19 @@ static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys) | |||
984 | sys->rate = sclk; | 1073 | sys->rate = sclk; |
985 | } | 1074 | } |
986 | 1075 | ||
987 | #ifdef CONFIG_OMAP_RESET_CLOCKS | 1076 | /* |
988 | static void __init omap2_disable_unused_clocks(void) | 1077 | * Set clocks for bypass mode for reboot to work. |
1078 | */ | ||
1079 | void omap2_clk_prepare_for_reboot(void) | ||
989 | { | 1080 | { |
990 | struct clk *ck; | 1081 | u32 rate; |
991 | u32 regval32; | ||
992 | 1082 | ||
993 | list_for_each_entry(ck, &clocks, node) { | 1083 | if (vclk == NULL || sclk == NULL) |
994 | if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) || | 1084 | return; |
995 | ck->enable_reg == 0) | ||
996 | continue; | ||
997 | |||
998 | regval32 = __raw_readl(ck->enable_reg); | ||
999 | if ((regval32 & (1 << ck->enable_bit)) == 0) | ||
1000 | continue; | ||
1001 | 1085 | ||
1002 | printk(KERN_INFO "Disabling unused clock \"%s\"\n", ck->name); | 1086 | rate = clk_get_rate(sclk); |
1003 | _omap2_clk_disable(ck); | 1087 | clk_set_rate(vclk, rate); |
1004 | } | ||
1005 | } | 1088 | } |
1006 | late_initcall(omap2_disable_unused_clocks); | ||
1007 | #endif | ||
1008 | 1089 | ||
1009 | /* | 1090 | /* |
1010 | * Switch the MPU rate if specified on cmdline. | 1091 | * Switch the MPU rate if specified on cmdline. |
@@ -1077,8 +1158,27 @@ int __init omap2_clk_init(void) | |||
1077 | */ | 1158 | */ |
1078 | clk_enable(&sync_32k_ick); | 1159 | clk_enable(&sync_32k_ick); |
1079 | clk_enable(&omapctrl_ick); | 1160 | clk_enable(&omapctrl_ick); |
1161 | |||
1162 | /* Force the APLLs active during bootup to avoid disabling and | ||
1163 | * enabling them unnecessarily. */ | ||
1164 | clk_enable(&apll96_ck); | ||
1165 | clk_enable(&apll54_ck); | ||
1166 | |||
1080 | if (cpu_is_omap2430()) | 1167 | if (cpu_is_omap2430()) |
1081 | clk_enable(&sdrc_ick); | 1168 | clk_enable(&sdrc_ick); |
1082 | 1169 | ||
1170 | /* Avoid sleeping sleeping during omap2_clk_prepare_for_reboot() */ | ||
1171 | vclk = clk_get(NULL, "virt_prcm_set"); | ||
1172 | sclk = clk_get(NULL, "sys_ck"); | ||
1173 | |||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | static int __init omap2_disable_aplls(void) | ||
1178 | { | ||
1179 | clk_disable(&apll96_ck); | ||
1180 | clk_disable(&apll54_ck); | ||
1181 | |||
1083 | return 0; | 1182 | return 0; |
1084 | } | 1183 | } |
1184 | late_initcall(omap2_disable_aplls); | ||