xref: /openbmc/linux/arch/arm/mach-omap2/cm33xx.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
152e6676eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2f969a6dcSVaibhav Hiremath /*
3f969a6dcSVaibhav Hiremath  * AM33XX CM functions
4f969a6dcSVaibhav Hiremath  *
583bf6db0SAlexander A. Klimov  * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/
6f969a6dcSVaibhav Hiremath  * Vaibhav Hiremath <hvaibhav@ti.com>
7f969a6dcSVaibhav Hiremath  *
8*31006a88SJilin Yuan  * Reference taken from OMAP4 cminst44xx.c
9f969a6dcSVaibhav Hiremath  */
10f969a6dcSVaibhav Hiremath 
11f969a6dcSVaibhav Hiremath #include <linux/kernel.h>
12f969a6dcSVaibhav Hiremath #include <linux/types.h>
13f969a6dcSVaibhav Hiremath #include <linux/errno.h>
14f969a6dcSVaibhav Hiremath #include <linux/err.h>
15f969a6dcSVaibhav Hiremath #include <linux/io.h>
16f969a6dcSVaibhav Hiremath 
174bd5259eSPaul Walmsley #include "clockdomain.h"
18f969a6dcSVaibhav Hiremath #include "cm.h"
19f969a6dcSVaibhav Hiremath #include "cm33xx.h"
20f969a6dcSVaibhav Hiremath #include "cm-regbits-34xx.h"
21f969a6dcSVaibhav Hiremath #include "cm-regbits-33xx.h"
22f969a6dcSVaibhav Hiremath #include "prm33xx.h"
23f969a6dcSVaibhav Hiremath 
24f969a6dcSVaibhav Hiremath /*
25f969a6dcSVaibhav Hiremath  * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
26f969a6dcSVaibhav Hiremath  *
27f969a6dcSVaibhav Hiremath  *   0x0 func:     Module is fully functional, including OCP
28f969a6dcSVaibhav Hiremath  *   0x1 trans:    Module is performing transition: wakeup, or sleep, or sleep
29f969a6dcSVaibhav Hiremath  *                 abortion
30f969a6dcSVaibhav Hiremath  *   0x2 idle:     Module is in Idle mode (only OCP part). It is functional if
31f969a6dcSVaibhav Hiremath  *                 using separate functional clock
32f969a6dcSVaibhav Hiremath  *   0x3 disabled: Module is disabled and cannot be accessed
33f969a6dcSVaibhav Hiremath  *
34f969a6dcSVaibhav Hiremath  */
35f969a6dcSVaibhav Hiremath #define CLKCTRL_IDLEST_FUNCTIONAL		0x0
36f969a6dcSVaibhav Hiremath #define CLKCTRL_IDLEST_INTRANSITION		0x1
37f969a6dcSVaibhav Hiremath #define CLKCTRL_IDLEST_INTERFACE_IDLE		0x2
38f969a6dcSVaibhav Hiremath #define CLKCTRL_IDLEST_DISABLED			0x3
39f969a6dcSVaibhav Hiremath 
40f969a6dcSVaibhav Hiremath /* Private functions */
41f969a6dcSVaibhav Hiremath 
42f969a6dcSVaibhav Hiremath /* Read a register in a CM instance */
am33xx_cm_read_reg(u16 inst,u16 idx)43d3f5d551SAnkur Kishore static inline u32 am33xx_cm_read_reg(u16 inst, u16 idx)
44f969a6dcSVaibhav Hiremath {
4590129336STero Kristo 	return readl_relaxed(cm_base.va + inst + idx);
46f969a6dcSVaibhav Hiremath }
47f969a6dcSVaibhav Hiremath 
48f969a6dcSVaibhav Hiremath /* Write into a register in a CM */
am33xx_cm_write_reg(u32 val,u16 inst,u16 idx)49d3f5d551SAnkur Kishore static inline void am33xx_cm_write_reg(u32 val, u16 inst, u16 idx)
50f969a6dcSVaibhav Hiremath {
5190129336STero Kristo 	writel_relaxed(val, cm_base.va + inst + idx);
52f969a6dcSVaibhav Hiremath }
53f969a6dcSVaibhav Hiremath 
54f969a6dcSVaibhav Hiremath /* Read-modify-write a register in CM */
am33xx_cm_rmw_reg_bits(u32 mask,u32 bits,s16 inst,s16 idx)55f969a6dcSVaibhav Hiremath static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
56f969a6dcSVaibhav Hiremath {
57f969a6dcSVaibhav Hiremath 	u32 v;
58f969a6dcSVaibhav Hiremath 
59f969a6dcSVaibhav Hiremath 	v = am33xx_cm_read_reg(inst, idx);
60f969a6dcSVaibhav Hiremath 	v &= ~mask;
61f969a6dcSVaibhav Hiremath 	v |= bits;
62f969a6dcSVaibhav Hiremath 	am33xx_cm_write_reg(v, inst, idx);
63f969a6dcSVaibhav Hiremath 
64f969a6dcSVaibhav Hiremath 	return v;
65f969a6dcSVaibhav Hiremath }
66f969a6dcSVaibhav Hiremath 
am33xx_cm_read_reg_bits(u16 inst,s16 idx,u32 mask)671096d1c1SRuss Dill static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
681096d1c1SRuss Dill {
691096d1c1SRuss Dill 	u32 v;
701096d1c1SRuss Dill 
711096d1c1SRuss Dill 	v = am33xx_cm_read_reg(inst, idx);
721096d1c1SRuss Dill 	v &= mask;
731096d1c1SRuss Dill 	v >>= __ffs(mask);
741096d1c1SRuss Dill 
751096d1c1SRuss Dill 	return v;
761096d1c1SRuss Dill }
771096d1c1SRuss Dill 
78f969a6dcSVaibhav Hiremath /**
79f969a6dcSVaibhav Hiremath  * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
80f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
81f969a6dcSVaibhav Hiremath  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
82f969a6dcSVaibhav Hiremath  *
83f969a6dcSVaibhav Hiremath  * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
84f969a6dcSVaibhav Hiremath  * bit 0.
85f969a6dcSVaibhav Hiremath  */
_clkctrl_idlest(u16 inst,u16 clkctrl_offs)869907f85eSTero Kristo static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs)
87f969a6dcSVaibhav Hiremath {
88f969a6dcSVaibhav Hiremath 	u32 v = am33xx_cm_read_reg(inst, clkctrl_offs);
89f969a6dcSVaibhav Hiremath 	v &= AM33XX_IDLEST_MASK;
90f969a6dcSVaibhav Hiremath 	v >>= AM33XX_IDLEST_SHIFT;
91f969a6dcSVaibhav Hiremath 	return v;
92f969a6dcSVaibhav Hiremath }
93f969a6dcSVaibhav Hiremath 
94f969a6dcSVaibhav Hiremath /**
95f969a6dcSVaibhav Hiremath  * _is_module_ready - can module registers be accessed without causing an abort?
96f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
97f969a6dcSVaibhav Hiremath  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
98f969a6dcSVaibhav Hiremath  *
99f969a6dcSVaibhav Hiremath  * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
100f969a6dcSVaibhav Hiremath  * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
101f969a6dcSVaibhav Hiremath  */
_is_module_ready(u16 inst,u16 clkctrl_offs)1029907f85eSTero Kristo static bool _is_module_ready(u16 inst, u16 clkctrl_offs)
103f969a6dcSVaibhav Hiremath {
104f969a6dcSVaibhav Hiremath 	u32 v;
105f969a6dcSVaibhav Hiremath 
1069907f85eSTero Kristo 	v = _clkctrl_idlest(inst, clkctrl_offs);
107f969a6dcSVaibhav Hiremath 
108f969a6dcSVaibhav Hiremath 	return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
109f969a6dcSVaibhav Hiremath 		v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
110f969a6dcSVaibhav Hiremath }
111f969a6dcSVaibhav Hiremath 
112f969a6dcSVaibhav Hiremath /**
113f969a6dcSVaibhav Hiremath  * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield
114f969a6dcSVaibhav Hiremath  * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted)
115f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
116f969a6dcSVaibhav Hiremath  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
117f969a6dcSVaibhav Hiremath  *
118f969a6dcSVaibhav Hiremath  * @c must be the unshifted value for CLKTRCTRL - i.e., this function
119f969a6dcSVaibhav Hiremath  * will handle the shift itself.
120f969a6dcSVaibhav Hiremath  */
_clktrctrl_write(u8 c,u16 inst,u16 cdoffs)121d3f5d551SAnkur Kishore static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs)
122f969a6dcSVaibhav Hiremath {
123f969a6dcSVaibhav Hiremath 	u32 v;
124f969a6dcSVaibhav Hiremath 
125f969a6dcSVaibhav Hiremath 	v = am33xx_cm_read_reg(inst, cdoffs);
126f969a6dcSVaibhav Hiremath 	v &= ~AM33XX_CLKTRCTRL_MASK;
127f969a6dcSVaibhav Hiremath 	v |= c << AM33XX_CLKTRCTRL_SHIFT;
128f969a6dcSVaibhav Hiremath 	am33xx_cm_write_reg(v, inst, cdoffs);
129f969a6dcSVaibhav Hiremath }
130f969a6dcSVaibhav Hiremath 
131f969a6dcSVaibhav Hiremath /* Public functions */
132f969a6dcSVaibhav Hiremath 
133f969a6dcSVaibhav Hiremath /**
134f969a6dcSVaibhav Hiremath  * am33xx_cm_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode?
135f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
136f969a6dcSVaibhav Hiremath  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
137f969a6dcSVaibhav Hiremath  *
138f969a6dcSVaibhav Hiremath  * Returns true if the clockdomain referred to by (@inst, @cdoffs)
139f969a6dcSVaibhav Hiremath  * is in hardware-supervised idle mode, or 0 otherwise.
140f969a6dcSVaibhav Hiremath  */
am33xx_cm_is_clkdm_in_hwsup(u16 inst,u16 cdoffs)141f2650d6eSTero Kristo static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
142f969a6dcSVaibhav Hiremath {
143f969a6dcSVaibhav Hiremath 	u32 v;
144f969a6dcSVaibhav Hiremath 
145f969a6dcSVaibhav Hiremath 	v = am33xx_cm_read_reg(inst, cdoffs);
146f969a6dcSVaibhav Hiremath 	v &= AM33XX_CLKTRCTRL_MASK;
147f969a6dcSVaibhav Hiremath 	v >>= AM33XX_CLKTRCTRL_SHIFT;
148f969a6dcSVaibhav Hiremath 
149f969a6dcSVaibhav Hiremath 	return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
150f969a6dcSVaibhav Hiremath }
151f969a6dcSVaibhav Hiremath 
152f969a6dcSVaibhav Hiremath /**
153f969a6dcSVaibhav Hiremath  * am33xx_cm_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode
154f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
155f969a6dcSVaibhav Hiremath  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
156f969a6dcSVaibhav Hiremath  *
157f969a6dcSVaibhav Hiremath  * Put a clockdomain referred to by (@inst, @cdoffs) into
158f969a6dcSVaibhav Hiremath  * hardware-supervised idle mode.  No return value.
159f969a6dcSVaibhav Hiremath  */
am33xx_cm_clkdm_enable_hwsup(u16 inst,u16 cdoffs)160f2650d6eSTero Kristo static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
161f969a6dcSVaibhav Hiremath {
162f969a6dcSVaibhav Hiremath 	_clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
163f969a6dcSVaibhav Hiremath }
164f969a6dcSVaibhav Hiremath 
165f969a6dcSVaibhav Hiremath /**
166f969a6dcSVaibhav Hiremath  * am33xx_cm_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode
167f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
168f969a6dcSVaibhav Hiremath  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
169f969a6dcSVaibhav Hiremath  *
170f969a6dcSVaibhav Hiremath  * Put a clockdomain referred to by (@inst, @cdoffs) into
171f969a6dcSVaibhav Hiremath  * software-supervised idle mode, i.e., controlled manually by the
172f969a6dcSVaibhav Hiremath  * Linux OMAP clockdomain code.  No return value.
173f969a6dcSVaibhav Hiremath  */
am33xx_cm_clkdm_disable_hwsup(u16 inst,u16 cdoffs)174f2650d6eSTero Kristo static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
175f969a6dcSVaibhav Hiremath {
176f969a6dcSVaibhav Hiremath 	_clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
177f969a6dcSVaibhav Hiremath }
178f969a6dcSVaibhav Hiremath 
179f969a6dcSVaibhav Hiremath /**
180f969a6dcSVaibhav Hiremath  * am33xx_cm_clkdm_force_sleep - try to put a clockdomain into idle
181f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
182f969a6dcSVaibhav Hiremath  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
183f969a6dcSVaibhav Hiremath  *
184f969a6dcSVaibhav Hiremath  * Put a clockdomain referred to by (@inst, @cdoffs) into idle
185f969a6dcSVaibhav Hiremath  * No return value.
186f969a6dcSVaibhav Hiremath  */
am33xx_cm_clkdm_force_sleep(u16 inst,u16 cdoffs)187f2650d6eSTero Kristo static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
188f969a6dcSVaibhav Hiremath {
189f969a6dcSVaibhav Hiremath 	_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
190f969a6dcSVaibhav Hiremath }
191f969a6dcSVaibhav Hiremath 
192f969a6dcSVaibhav Hiremath /**
193f969a6dcSVaibhav Hiremath  * am33xx_cm_clkdm_force_wakeup - try to take a clockdomain out of idle
194f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
195f969a6dcSVaibhav Hiremath  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
196f969a6dcSVaibhav Hiremath  *
197f969a6dcSVaibhav Hiremath  * Take a clockdomain referred to by (@inst, @cdoffs) out of idle,
198f969a6dcSVaibhav Hiremath  * waking it up.  No return value.
199f969a6dcSVaibhav Hiremath  */
am33xx_cm_clkdm_force_wakeup(u16 inst,u16 cdoffs)200f2650d6eSTero Kristo static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
201f969a6dcSVaibhav Hiremath {
202f969a6dcSVaibhav Hiremath 	_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
203f969a6dcSVaibhav Hiremath }
204f969a6dcSVaibhav Hiremath 
205f969a6dcSVaibhav Hiremath /*
206f969a6dcSVaibhav Hiremath  *
207f969a6dcSVaibhav Hiremath  */
208f969a6dcSVaibhav Hiremath 
209f969a6dcSVaibhav Hiremath /**
210f969a6dcSVaibhav Hiremath  * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state
211021b6ff0STero Kristo  * @part: PRCM partition, ignored for AM33xx
212f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
213f969a6dcSVaibhav Hiremath  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
214021b6ff0STero Kristo  * @bit_shift: bit shift for the register, ignored for AM33xx
215f969a6dcSVaibhav Hiremath  *
216f969a6dcSVaibhav Hiremath  * Wait for the module IDLEST to be functional. If the idle state is in any
217f969a6dcSVaibhav Hiremath  * the non functional state (trans, idle or disabled), module and thus the
218f969a6dcSVaibhav Hiremath  * sysconfig cannot be accessed and will probably lead to an "imprecise
219f969a6dcSVaibhav Hiremath  * external abort"
220f969a6dcSVaibhav Hiremath  */
am33xx_cm_wait_module_ready(u8 part,s16 inst,u16 clkctrl_offs,u8 bit_shift)221021b6ff0STero Kristo static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
222021b6ff0STero Kristo 				       u8 bit_shift)
223f969a6dcSVaibhav Hiremath {
224f969a6dcSVaibhav Hiremath 	int i = 0;
225f969a6dcSVaibhav Hiremath 
2269907f85eSTero Kristo 	omap_test_timeout(_is_module_ready(inst, clkctrl_offs),
227f969a6dcSVaibhav Hiremath 			  MAX_MODULE_READY_TIME, i);
228f969a6dcSVaibhav Hiremath 
229f969a6dcSVaibhav Hiremath 	return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
230f969a6dcSVaibhav Hiremath }
231f969a6dcSVaibhav Hiremath 
232f969a6dcSVaibhav Hiremath /**
233f969a6dcSVaibhav Hiremath  * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled'
234f969a6dcSVaibhav Hiremath  * state
235a8ae5afaSTero Kristo  * @part: CM partition, ignored for AM33xx
236f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
237f969a6dcSVaibhav Hiremath  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
238a8ae5afaSTero Kristo  * @bit_shift: bit shift for the register, ignored for AM33xx
239f969a6dcSVaibhav Hiremath  *
240f969a6dcSVaibhav Hiremath  * Wait for the module IDLEST to be disabled. Some PRCM transition,
241f969a6dcSVaibhav Hiremath  * like reset assertion or parent clock de-activation must wait the
242f969a6dcSVaibhav Hiremath  * module to be fully disabled.
243f969a6dcSVaibhav Hiremath  */
am33xx_cm_wait_module_idle(u8 part,s16 inst,u16 clkctrl_offs,u8 bit_shift)244a8ae5afaSTero Kristo static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
245a8ae5afaSTero Kristo 				      u8 bit_shift)
246f969a6dcSVaibhav Hiremath {
247f969a6dcSVaibhav Hiremath 	int i = 0;
248f969a6dcSVaibhav Hiremath 
2499907f85eSTero Kristo 	omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) ==
250f969a6dcSVaibhav Hiremath 				CLKCTRL_IDLEST_DISABLED),
251f969a6dcSVaibhav Hiremath 				MAX_MODULE_READY_TIME, i);
252f969a6dcSVaibhav Hiremath 
253f969a6dcSVaibhav Hiremath 	return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
254f969a6dcSVaibhav Hiremath }
255f969a6dcSVaibhav Hiremath 
256f969a6dcSVaibhav Hiremath /**
257f969a6dcSVaibhav Hiremath  * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL
258f969a6dcSVaibhav Hiremath  * @mode: Module mode (SW or HW)
259128603f0STero Kristo  * @part: CM partition, ignored for AM33xx
260f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
261f969a6dcSVaibhav Hiremath  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
262f969a6dcSVaibhav Hiremath  *
263f969a6dcSVaibhav Hiremath  * No return value.
264f969a6dcSVaibhav Hiremath  */
am33xx_cm_module_enable(u8 mode,u8 part,u16 inst,u16 clkctrl_offs)265128603f0STero Kristo static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst,
266128603f0STero Kristo 				    u16 clkctrl_offs)
267f969a6dcSVaibhav Hiremath {
268f969a6dcSVaibhav Hiremath 	u32 v;
269f969a6dcSVaibhav Hiremath 
270f969a6dcSVaibhav Hiremath 	v = am33xx_cm_read_reg(inst, clkctrl_offs);
271f969a6dcSVaibhav Hiremath 	v &= ~AM33XX_MODULEMODE_MASK;
272f969a6dcSVaibhav Hiremath 	v |= mode << AM33XX_MODULEMODE_SHIFT;
273f969a6dcSVaibhav Hiremath 	am33xx_cm_write_reg(v, inst, clkctrl_offs);
274f969a6dcSVaibhav Hiremath }
275f969a6dcSVaibhav Hiremath 
276f969a6dcSVaibhav Hiremath /**
277f969a6dcSVaibhav Hiremath  * am33xx_cm_module_disable - Disable the module inside CLKCTRL
278128603f0STero Kristo  * @part: CM partition, ignored for AM33xx
279f969a6dcSVaibhav Hiremath  * @inst: CM instance register offset (*_INST macro)
280f969a6dcSVaibhav Hiremath  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
281f969a6dcSVaibhav Hiremath  *
282f969a6dcSVaibhav Hiremath  * No return value.
283f969a6dcSVaibhav Hiremath  */
am33xx_cm_module_disable(u8 part,u16 inst,u16 clkctrl_offs)284128603f0STero Kristo static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
285f969a6dcSVaibhav Hiremath {
286f969a6dcSVaibhav Hiremath 	u32 v;
287f969a6dcSVaibhav Hiremath 
288f969a6dcSVaibhav Hiremath 	v = am33xx_cm_read_reg(inst, clkctrl_offs);
289f969a6dcSVaibhav Hiremath 	v &= ~AM33XX_MODULEMODE_MASK;
290f969a6dcSVaibhav Hiremath 	am33xx_cm_write_reg(v, inst, clkctrl_offs);
291f969a6dcSVaibhav Hiremath }
2924bd5259eSPaul Walmsley 
2934bd5259eSPaul Walmsley /*
2944bd5259eSPaul Walmsley  * Clockdomain low-level functions
2954bd5259eSPaul Walmsley  */
2964bd5259eSPaul Walmsley 
am33xx_clkdm_sleep(struct clockdomain * clkdm)2974bd5259eSPaul Walmsley static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
2984bd5259eSPaul Walmsley {
2994bd5259eSPaul Walmsley 	am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
3004bd5259eSPaul Walmsley 	return 0;
3014bd5259eSPaul Walmsley }
3024bd5259eSPaul Walmsley 
am33xx_clkdm_wakeup(struct clockdomain * clkdm)3034bd5259eSPaul Walmsley static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
3044bd5259eSPaul Walmsley {
3054bd5259eSPaul Walmsley 	am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
3064bd5259eSPaul Walmsley 	return 0;
3074bd5259eSPaul Walmsley }
3084bd5259eSPaul Walmsley 
am33xx_clkdm_allow_idle(struct clockdomain * clkdm)3094bd5259eSPaul Walmsley static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
3104bd5259eSPaul Walmsley {
3114bd5259eSPaul Walmsley 	am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
3124bd5259eSPaul Walmsley }
3134bd5259eSPaul Walmsley 
am33xx_clkdm_deny_idle(struct clockdomain * clkdm)3144bd5259eSPaul Walmsley static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
3154bd5259eSPaul Walmsley {
3164bd5259eSPaul Walmsley 	am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
3174bd5259eSPaul Walmsley }
3184bd5259eSPaul Walmsley 
am33xx_clkdm_clk_enable(struct clockdomain * clkdm)3194bd5259eSPaul Walmsley static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
3204bd5259eSPaul Walmsley {
3214bd5259eSPaul Walmsley 	if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
3224bd5259eSPaul Walmsley 		return am33xx_clkdm_wakeup(clkdm);
3234bd5259eSPaul Walmsley 
3244bd5259eSPaul Walmsley 	return 0;
3254bd5259eSPaul Walmsley }
3264bd5259eSPaul Walmsley 
am33xx_clkdm_clk_disable(struct clockdomain * clkdm)3274bd5259eSPaul Walmsley static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
3284bd5259eSPaul Walmsley {
3294bd5259eSPaul Walmsley 	bool hwsup = false;
3304bd5259eSPaul Walmsley 
3314bd5259eSPaul Walmsley 	hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
3324bd5259eSPaul Walmsley 
3334bd5259eSPaul Walmsley 	if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
3344bd5259eSPaul Walmsley 		am33xx_clkdm_sleep(clkdm);
3354bd5259eSPaul Walmsley 
3364bd5259eSPaul Walmsley 	return 0;
3374bd5259eSPaul Walmsley }
3384bd5259eSPaul Walmsley 
am33xx_cm_xlate_clkctrl(u8 part,u16 inst,u16 offset)33985ab016cSTero Kristo static u32 am33xx_cm_xlate_clkctrl(u8 part, u16 inst, u16 offset)
34085ab016cSTero Kristo {
34185ab016cSTero Kristo 	return cm_base.pa + inst + offset;
34285ab016cSTero Kristo }
34385ab016cSTero Kristo 
3441096d1c1SRuss Dill /**
3451096d1c1SRuss Dill  * am33xx_clkdm_save_context - Save the clockdomain transition context
3461096d1c1SRuss Dill  * @clkdm: The clockdomain pointer whose context needs to be saved
3471096d1c1SRuss Dill  *
3481096d1c1SRuss Dill  * Save the clockdomain transition context.
3491096d1c1SRuss Dill  */
am33xx_clkdm_save_context(struct clockdomain * clkdm)3501096d1c1SRuss Dill static int am33xx_clkdm_save_context(struct clockdomain *clkdm)
3511096d1c1SRuss Dill {
3521096d1c1SRuss Dill 	clkdm->context = am33xx_cm_read_reg_bits(clkdm->cm_inst,
3531096d1c1SRuss Dill 						 clkdm->clkdm_offs,
3541096d1c1SRuss Dill 						 AM33XX_CLKTRCTRL_MASK);
3551096d1c1SRuss Dill 
3561096d1c1SRuss Dill 	return 0;
3571096d1c1SRuss Dill }
3581096d1c1SRuss Dill 
3591096d1c1SRuss Dill /**
3601096d1c1SRuss Dill  * am33xx_restore_save_context - Restore the clockdomain transition context
3611096d1c1SRuss Dill  * @clkdm: The clockdomain pointer whose context needs to be restored
3621096d1c1SRuss Dill  *
3631096d1c1SRuss Dill  * Restore the clockdomain transition context.
3641096d1c1SRuss Dill  */
am33xx_clkdm_restore_context(struct clockdomain * clkdm)3651096d1c1SRuss Dill static int am33xx_clkdm_restore_context(struct clockdomain *clkdm)
3661096d1c1SRuss Dill {
3671096d1c1SRuss Dill 	switch (clkdm->context) {
3681096d1c1SRuss Dill 	case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
3691096d1c1SRuss Dill 		am33xx_clkdm_deny_idle(clkdm);
3701096d1c1SRuss Dill 		break;
3711096d1c1SRuss Dill 	case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
3721096d1c1SRuss Dill 		am33xx_clkdm_sleep(clkdm);
3731096d1c1SRuss Dill 		break;
3741096d1c1SRuss Dill 	case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
3751096d1c1SRuss Dill 		am33xx_clkdm_wakeup(clkdm);
3761096d1c1SRuss Dill 		break;
3771096d1c1SRuss Dill 	case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
3781096d1c1SRuss Dill 		am33xx_clkdm_allow_idle(clkdm);
3791096d1c1SRuss Dill 		break;
3801096d1c1SRuss Dill 	}
3811096d1c1SRuss Dill 	return 0;
3821096d1c1SRuss Dill }
3831096d1c1SRuss Dill 
3844bd5259eSPaul Walmsley struct clkdm_ops am33xx_clkdm_operations = {
3854bd5259eSPaul Walmsley 	.clkdm_sleep		= am33xx_clkdm_sleep,
3864bd5259eSPaul Walmsley 	.clkdm_wakeup		= am33xx_clkdm_wakeup,
3874bd5259eSPaul Walmsley 	.clkdm_allow_idle	= am33xx_clkdm_allow_idle,
3884bd5259eSPaul Walmsley 	.clkdm_deny_idle	= am33xx_clkdm_deny_idle,
3894bd5259eSPaul Walmsley 	.clkdm_clk_enable	= am33xx_clkdm_clk_enable,
3904bd5259eSPaul Walmsley 	.clkdm_clk_disable	= am33xx_clkdm_clk_disable,
3911096d1c1SRuss Dill 	.clkdm_save_context	= am33xx_clkdm_save_context,
3921096d1c1SRuss Dill 	.clkdm_restore_context	= am33xx_clkdm_restore_context,
3934bd5259eSPaul Walmsley };
3947632a02fSTero Kristo 
39560af58cdSBhumika Goyal static const struct cm_ll_data am33xx_cm_ll_data = {
396021b6ff0STero Kristo 	.wait_module_ready	= &am33xx_cm_wait_module_ready,
397a8ae5afaSTero Kristo 	.wait_module_idle	= &am33xx_cm_wait_module_idle,
398128603f0STero Kristo 	.module_enable		= &am33xx_cm_module_enable,
399128603f0STero Kristo 	.module_disable		= &am33xx_cm_module_disable,
40085ab016cSTero Kristo 	.xlate_clkctrl		= &am33xx_cm_xlate_clkctrl,
401021b6ff0STero Kristo };
4027632a02fSTero Kristo 
am33xx_cm_init(const struct omap_prcm_init_data * data)403425dc8b2STero Kristo int __init am33xx_cm_init(const struct omap_prcm_init_data *data)
4047632a02fSTero Kristo {
4057632a02fSTero Kristo 	return cm_register(&am33xx_cm_ll_data);
4067632a02fSTero Kristo }
4077632a02fSTero Kristo 
am33xx_cm_exit(void)4087632a02fSTero Kristo static void __exit am33xx_cm_exit(void)
4097632a02fSTero Kristo {
4107632a02fSTero Kristo 	cm_unregister(&am33xx_cm_ll_data);
4117632a02fSTero Kristo }
4127632a02fSTero Kristo __exitcall(am33xx_cm_exit);
413