1 /*
2 * AM33XX CM instance functions
3 *
4 * Copyright (C) 2011 Texas Instruments, Inc.
5 * Vaibhav Hiremath <hvaibhav@ti.com>
6 *
7 * Reference taken from from OMAP4
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
14 #include <linux/kernel.h>
15 #include <linux/types.h>
16 #include <linux/errno.h>
17 #include <linux/err.h>
18 #include <linux/io.h>
20 #include <plat/common.h>
22 #include "cm.h"
23 #include "cm33xx.h"
24 #include "cminst33xx.h"
25 #include "cm-regbits-34xx.h"
26 #include "cm-regbits-33xx.h"
27 #include "common.h"
28 #include "prm33xx.h"
30 /*
31 * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
32 *
33 * 0x0 func: Module is fully functional, including OCP
34 * 0x1 trans: Module is performing transition: wakeup, or sleep, or sleep
35 * abortion
36 * 0x2 idle: Module is in Idle mode (only OCP part). It is functional if
37 * using separate functional clock
38 * 0x3 disabled: Module is disabled and cannot be accessed
39 *
40 */
41 #define CLKCTRL_IDLEST_FUNCTIONAL 0x0
42 #define CLKCTRL_IDLEST_INTRANSITION 0x1
43 #define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2
44 #define CLKCTRL_IDLEST_DISABLED 0x3
46 /* Private functions */
48 /**
49 * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
50 * @inst: CM instance register offset (*_INST macro)
51 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
52 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
53 *
54 * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
55 * bit 0.
56 */
57 static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs)
58 {
59 u32 v = am33xx_cminst_read_inst_reg(inst, clkctrl_offs);
60 v &= AM33XX_IDLEST_MASK;
61 v >>= AM33XX_IDLEST_SHIFT;
62 return v;
63 }
65 /**
66 * _is_module_ready - can module registers be accessed without causing an abort?
67 * @inst: CM instance register offset (*_INST macro)
68 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
69 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
70 *
71 * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
72 * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
73 */
74 static bool _is_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs)
75 {
76 u32 v;
78 v = _clkctrl_idlest(inst, cdoffs, clkctrl_offs);
80 return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
81 v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
82 }
84 /* Public functions */
86 /* Read a register in a CM instance */
87 u32 am33xx_cminst_read_inst_reg(s16 inst, u16 idx)
88 {
89 return __raw_readl(cm_base + inst + idx);
90 }
92 /* Write into a register in a CM instance */
93 void am33xx_cminst_write_inst_reg(u32 val, s16 inst, u16 idx)
94 {
95 __raw_writel(val, cm_base + inst + idx);
96 }
98 /* Read-modify-write a register in CM1. Caller must lock */
99 u32 am33xx_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
100 {
101 u32 v;
103 v = am33xx_cminst_read_inst_reg(inst, idx);
104 v &= ~mask;
105 v |= bits;
106 am33xx_cminst_write_inst_reg(v, inst, idx);
108 return v;
109 }
111 u32 am33xx_cminst_set_inst_reg_bits(u32 bits, s16 inst, s16 idx)
112 {
113 return am33xx_cminst_rmw_inst_reg_bits(bits, bits, inst, idx);
114 }
116 u32 am33xx_cminst_clear_inst_reg_bits(u32 bits, s16 inst, s16 idx)
117 {
118 return am33xx_cminst_rmw_inst_reg_bits(bits, 0x0, inst, idx);
119 }
121 u32 am33xx_cminst_read_inst_reg_bits(u16 inst, s16 idx, u32 mask)
122 {
123 u32 v;
125 v = am33xx_cminst_read_inst_reg(inst, idx);
126 v &= mask;
127 v >>= __ffs(mask);
129 return v;
130 }
132 /**
133 * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield
134 * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted)
135 * @inst: CM instance register offset (*_INST macro)
136 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
137 *
138 * @c must be the unshifted value for CLKTRCTRL - i.e., this function
139 * will handle the shift itself.
140 */
141 static void _clktrctrl_write(u8 c, s16 inst, u16 cdoffs)
142 {
143 u32 v;
145 v = am33xx_cminst_read_inst_reg(inst, cdoffs);
146 v &= ~AM33XX_CLKTRCTRL_MASK;
147 v |= c << AM33XX_CLKTRCTRL_SHIFT;
148 am33xx_cminst_write_inst_reg(v, inst, cdoffs);
149 }
151 /**
152 * am33xx_cminst_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode?
153 * @inst: CM instance register offset (*_INST macro)
154 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
155 *
156 * Returns true if the clockdomain referred to by (@inst, @cdoffs)
157 * is in hardware-supervised idle mode, or 0 otherwise.
158 */
159 bool am33xx_cminst_is_clkdm_in_hwsup(s16 inst, u16 cdoffs)
160 {
161 u32 v;
163 v = am33xx_cminst_read_inst_reg(inst, cdoffs);
164 v &= AM33XX_CLKTRCTRL_MASK;
165 v >>= AM33XX_CLKTRCTRL_SHIFT;
167 return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
168 }
170 /**
171 * am33xx_cminst_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode
172 * @inst: CM instance register offset (*_INST macro)
173 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
174 *
175 * Put a clockdomain referred to by (@inst, @cdoffs) into
176 * hardware-supervised idle mode. No return value.
177 */
178 void am33xx_cminst_clkdm_enable_hwsup(s16 inst, u16 cdoffs)
179 {
180 _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
181 }
183 /**
184 * am33xx_cminst_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode
185 * @inst: CM instance register offset (*_INST macro)
186 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
187 *
188 * Put a clockdomain referred to by (@inst, @cdoffs) into
189 * software-supervised idle mode, i.e., controlled manually by the
190 * Linux OMAP clockdomain code. No return value.
191 */
192 void am33xx_cminst_clkdm_disable_hwsup(s16 inst, u16 cdoffs)
193 {
194 _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
195 }
197 /**
198 * am33xx_cminst_clkdm_force_sleep - try to put a clockdomain into idle
199 * @inst: CM instance register offset (*_INST macro)
200 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
201 *
202 * Put a clockdomain referred to by (@inst, @cdoffs) into idle
203 * No return value.
204 */
205 void am33xx_cminst_clkdm_force_sleep(s16 inst, u16 cdoffs)
206 {
207 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
208 }
210 /**
211 * am33xx_cminst_clkdm_force_sleep - try to take a clockdomain out of idle
212 * @inst: CM instance register offset (*_INST macro)
213 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
214 *
215 * Take a clockdomain referred to by (@inst, @cdoffs) out of idle,
216 * waking it up. No return value.
217 */
218 void am33xx_cminst_clkdm_force_wakeup(s16 inst, u16 cdoffs)
219 {
220 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
221 }
223 /*
224 *
225 */
227 /**
228 * am33xx_cminst_wait_module_ready - wait for a module to be in 'func' state
229 * @inst: CM instance register offset (*_INST macro)
230 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
231 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
232 *
233 * Wait for the module IDLEST to be functional. If the idle state is in any
234 * the non functional state (trans, idle or disabled), module and thus the
235 * sysconfig cannot be accessed and will probably lead to an "imprecise
236 * external abort"
237 */
238 int am33xx_cminst_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs)
239 {
240 int i = 0;
242 if (!clkctrl_offs)
243 return 0;
245 omap_test_timeout(_is_module_ready(inst, cdoffs, clkctrl_offs),
246 MAX_MODULE_READY_TIME, i);
248 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
249 }
251 /**
252 * am33xx_cminst_wait_module_idle - wait for a module to be in 'disabled'
253 * state
254 * @inst: CM instance register offset (*_INST macro)
255 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
256 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
257 *
258 * Wait for the module IDLEST to be disabled. Some PRCM transition,
259 * like reset assertion or parent clock de-activation must wait the
260 * module to be fully disabled.
261 */
262 int am33xx_cminst_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs)
263 {
264 int i = 0;
266 if (!clkctrl_offs)
267 return 0;
269 omap_test_timeout((_clkctrl_idlest(inst, cdoffs, clkctrl_offs) ==
270 CLKCTRL_IDLEST_DISABLED),
271 MAX_MODULE_READY_TIME, i);
273 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
274 }
276 /**
277 * am33xx_cminst_module_enable - Enable the modulemode inside CLKCTRL
278 * @mode: Module mode (SW or HW)
279 * @inst: CM instance register offset (*_INST macro)
280 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
281 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
282 *
283 * No return value.
284 */
285 void am33xx_cminst_module_enable(u8 mode, u16 inst, s16 cdoffs,
286 u16 clkctrl_offs)
287 {
288 u32 v;
290 v = am33xx_cminst_read_inst_reg(inst, clkctrl_offs);
291 v &= ~AM33XX_MODULEMODE_MASK;
292 v |= mode << AM33XX_MODULEMODE_SHIFT;
293 am33xx_cminst_write_inst_reg(v, inst, clkctrl_offs);
294 }
296 /**
297 * am33xx_cminst_module_disable - Disable the module inside CLKCTRL
298 * @inst: CM instance register offset (*_INST macro)
299 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
300 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
301 *
302 * No return value.
303 */
304 void am33xx_cminst_module_disable(u16 inst, s16 cdoffs,
305 u16 clkctrl_offs)
306 {
307 u32 v;
309 v = am33xx_cminst_read_inst_reg(inst, clkctrl_offs);
310 v &= ~AM33XX_MODULEMODE_MASK;
311 am33xx_cminst_write_inst_reg(v, inst, clkctrl_offs);
312 }