diff options
Diffstat (limited to 'arch/arm/mach-omap2/cm3xxx.c')
-rw-r--r-- | arch/arm/mach-omap2/cm3xxx.c | 174 |
1 files changed, 172 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c index 8f92c56e2254..8b03ec2f4394 100644 --- a/arch/arm/mach-omap2/cm3xxx.c +++ b/arch/arm/mach-omap2/cm3xxx.c | |||
@@ -1,9 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * OMAP2/3 CM module functions | 2 | * OMAP3xxx CM module functions |
3 | * | 3 | * |
4 | * Copyright (C) 2009 Nokia Corporation | 4 | * Copyright (C) 2009 Nokia Corporation |
5 | * Copyright (C) 2012 Texas Instruments, Inc. | 5 | * Copyright (C) 2008-2010, 2012 Texas Instruments, Inc. |
6 | * Paul Walmsley | 6 | * Paul Walmsley |
7 | * Rajendra Nayak <rnayak@ti.com> | ||
7 | * | 8 | * |
8 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
@@ -20,9 +21,11 @@ | |||
20 | #include "soc.h" | 21 | #include "soc.h" |
21 | #include "iomap.h" | 22 | #include "iomap.h" |
22 | #include "common.h" | 23 | #include "common.h" |
24 | #include "prm2xxx_3xxx.h" | ||
23 | #include "cm.h" | 25 | #include "cm.h" |
24 | #include "cm3xxx.h" | 26 | #include "cm3xxx.h" |
25 | #include "cm-regbits-34xx.h" | 27 | #include "cm-regbits-34xx.h" |
28 | #include "clockdomain.h" | ||
26 | 29 | ||
27 | static const u8 omap3xxx_cm_idlest_offs[] = { | 30 | static const u8 omap3xxx_cm_idlest_offs[] = { |
28 | CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3 | 31 | CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3 |
@@ -107,6 +110,173 @@ int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) | |||
107 | return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; | 110 | return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; |
108 | } | 111 | } |
109 | 112 | ||
113 | /* Clockdomain low-level operations */ | ||
114 | |||
115 | static int omap3xxx_clkdm_add_sleepdep(struct clockdomain *clkdm1, | ||
116 | struct clockdomain *clkdm2) | ||
117 | { | ||
118 | omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit), | ||
119 | clkdm1->pwrdm.ptr->prcm_offs, | ||
120 | OMAP3430_CM_SLEEPDEP); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int omap3xxx_clkdm_del_sleepdep(struct clockdomain *clkdm1, | ||
125 | struct clockdomain *clkdm2) | ||
126 | { | ||
127 | omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), | ||
128 | clkdm1->pwrdm.ptr->prcm_offs, | ||
129 | OMAP3430_CM_SLEEPDEP); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int omap3xxx_clkdm_read_sleepdep(struct clockdomain *clkdm1, | ||
134 | struct clockdomain *clkdm2) | ||
135 | { | ||
136 | return omap2_cm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, | ||
137 | OMAP3430_CM_SLEEPDEP, | ||
138 | (1 << clkdm2->dep_bit)); | ||
139 | } | ||
140 | |||
141 | static int omap3xxx_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) | ||
142 | { | ||
143 | struct clkdm_dep *cd; | ||
144 | u32 mask = 0; | ||
145 | |||
146 | for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) { | ||
147 | if (!cd->clkdm) | ||
148 | continue; /* only happens if data is erroneous */ | ||
149 | |||
150 | mask |= 1 << cd->clkdm->dep_bit; | ||
151 | atomic_set(&cd->sleepdep_usecount, 0); | ||
152 | } | ||
153 | omap2_cm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, | ||
154 | OMAP3430_CM_SLEEPDEP); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int omap3xxx_clkdm_sleep(struct clockdomain *clkdm) | ||
159 | { | ||
160 | omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs, | ||
161 | clkdm->clktrctrl_mask); | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int omap3xxx_clkdm_wakeup(struct clockdomain *clkdm) | ||
166 | { | ||
167 | omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs, | ||
168 | clkdm->clktrctrl_mask); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static void omap3xxx_clkdm_allow_idle(struct clockdomain *clkdm) | ||
173 | { | ||
174 | if (atomic_read(&clkdm->usecount) > 0) | ||
175 | _clkdm_add_autodeps(clkdm); | ||
176 | |||
177 | omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
178 | clkdm->clktrctrl_mask); | ||
179 | } | ||
180 | |||
181 | static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm) | ||
182 | { | ||
183 | omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
184 | clkdm->clktrctrl_mask); | ||
185 | |||
186 | if (atomic_read(&clkdm->usecount) > 0) | ||
187 | _clkdm_del_autodeps(clkdm); | ||
188 | } | ||
189 | |||
190 | static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) | ||
191 | { | ||
192 | bool hwsup = false; | ||
193 | |||
194 | if (!clkdm->clktrctrl_mask) | ||
195 | return 0; | ||
196 | |||
197 | /* | ||
198 | * The CLKDM_MISSING_IDLE_REPORTING flag documentation has | ||
199 | * more details on the unpleasant problem this is working | ||
200 | * around | ||
201 | */ | ||
202 | if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) && | ||
203 | (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) { | ||
204 | omap3xxx_clkdm_wakeup(clkdm); | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
209 | clkdm->clktrctrl_mask); | ||
210 | |||
211 | if (hwsup) { | ||
212 | /* Disable HW transitions when we are changing deps */ | ||
213 | omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
214 | clkdm->clktrctrl_mask); | ||
215 | _clkdm_add_autodeps(clkdm); | ||
216 | omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
217 | clkdm->clktrctrl_mask); | ||
218 | } else { | ||
219 | if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) | ||
220 | omap3xxx_clkdm_wakeup(clkdm); | ||
221 | } | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm) | ||
227 | { | ||
228 | bool hwsup = false; | ||
229 | |||
230 | if (!clkdm->clktrctrl_mask) | ||
231 | return 0; | ||
232 | |||
233 | /* | ||
234 | * The CLKDM_MISSING_IDLE_REPORTING flag documentation has | ||
235 | * more details on the unpleasant problem this is working | ||
236 | * around | ||
237 | */ | ||
238 | if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING && | ||
239 | !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) { | ||
240 | omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
241 | clkdm->clktrctrl_mask); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
246 | clkdm->clktrctrl_mask); | ||
247 | |||
248 | if (hwsup) { | ||
249 | /* Disable HW transitions when we are changing deps */ | ||
250 | omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
251 | clkdm->clktrctrl_mask); | ||
252 | _clkdm_del_autodeps(clkdm); | ||
253 | omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
254 | clkdm->clktrctrl_mask); | ||
255 | } else { | ||
256 | if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP) | ||
257 | omap3xxx_clkdm_sleep(clkdm); | ||
258 | } | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | struct clkdm_ops omap3_clkdm_operations = { | ||
264 | .clkdm_add_wkdep = omap2_clkdm_add_wkdep, | ||
265 | .clkdm_del_wkdep = omap2_clkdm_del_wkdep, | ||
266 | .clkdm_read_wkdep = omap2_clkdm_read_wkdep, | ||
267 | .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps, | ||
268 | .clkdm_add_sleepdep = omap3xxx_clkdm_add_sleepdep, | ||
269 | .clkdm_del_sleepdep = omap3xxx_clkdm_del_sleepdep, | ||
270 | .clkdm_read_sleepdep = omap3xxx_clkdm_read_sleepdep, | ||
271 | .clkdm_clear_all_sleepdeps = omap3xxx_clkdm_clear_all_sleepdeps, | ||
272 | .clkdm_sleep = omap3xxx_clkdm_sleep, | ||
273 | .clkdm_wakeup = omap3xxx_clkdm_wakeup, | ||
274 | .clkdm_allow_idle = omap3xxx_clkdm_allow_idle, | ||
275 | .clkdm_deny_idle = omap3xxx_clkdm_deny_idle, | ||
276 | .clkdm_clk_enable = omap3xxx_clkdm_clk_enable, | ||
277 | .clkdm_clk_disable = omap3xxx_clkdm_clk_disable, | ||
278 | }; | ||
279 | |||
110 | /* | 280 | /* |
111 | * Context save/restore code - OMAP3 only | 281 | * Context save/restore code - OMAP3 only |
112 | */ | 282 | */ |