1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * OMAP4 CM instance functions
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2009 Nokia Corporation
6*4882a593Smuzhiyun * Copyright (C) 2008-2011 Texas Instruments, Inc.
7*4882a593Smuzhiyun * Paul Walmsley
8*4882a593Smuzhiyun * Rajendra Nayak <rnayak@ti.com>
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * This is needed since CM instances can be in the PRM, PRCM_MPU, CM1,
11*4882a593Smuzhiyun * or CM2 hardware modules. For example, the EMU_CM CM instance is in
12*4882a593Smuzhiyun * the PRM hardware module. What a mess...
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/types.h>
17*4882a593Smuzhiyun #include <linux/errno.h>
18*4882a593Smuzhiyun #include <linux/err.h>
19*4882a593Smuzhiyun #include <linux/io.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include "clockdomain.h"
22*4882a593Smuzhiyun #include "cm.h"
23*4882a593Smuzhiyun #include "cm1_44xx.h"
24*4882a593Smuzhiyun #include "cm2_44xx.h"
25*4882a593Smuzhiyun #include "cm44xx.h"
26*4882a593Smuzhiyun #include "cm-regbits-34xx.h"
27*4882a593Smuzhiyun #include "prcm44xx.h"
28*4882a593Smuzhiyun #include "prm44xx.h"
29*4882a593Smuzhiyun #include "prcm_mpu44xx.h"
30*4882a593Smuzhiyun #include "prcm-common.h"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define OMAP4430_IDLEST_SHIFT 16
33*4882a593Smuzhiyun #define OMAP4430_IDLEST_MASK (0x3 << 16)
34*4882a593Smuzhiyun #define OMAP4430_CLKTRCTRL_SHIFT 0
35*4882a593Smuzhiyun #define OMAP4430_CLKTRCTRL_MASK (0x3 << 0)
36*4882a593Smuzhiyun #define OMAP4430_MODULEMODE_SHIFT 0
37*4882a593Smuzhiyun #define OMAP4430_MODULEMODE_MASK (0x3 << 0)
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun /*
40*4882a593Smuzhiyun * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
41*4882a593Smuzhiyun *
42*4882a593Smuzhiyun * 0x0 func: Module is fully functional, including OCP
43*4882a593Smuzhiyun * 0x1 trans: Module is performing transition: wakeup, or sleep, or sleep
44*4882a593Smuzhiyun * abortion
45*4882a593Smuzhiyun * 0x2 idle: Module is in Idle mode (only OCP part). It is functional if
46*4882a593Smuzhiyun * using separate functional clock
47*4882a593Smuzhiyun * 0x3 disabled: Module is disabled and cannot be accessed
48*4882a593Smuzhiyun *
49*4882a593Smuzhiyun */
50*4882a593Smuzhiyun #define CLKCTRL_IDLEST_FUNCTIONAL 0x0
51*4882a593Smuzhiyun #define CLKCTRL_IDLEST_INTRANSITION 0x1
52*4882a593Smuzhiyun #define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2
53*4882a593Smuzhiyun #define CLKCTRL_IDLEST_DISABLED 0x3
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun static struct omap_domain_base _cm_bases[OMAP4_MAX_PRCM_PARTITIONS];
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /**
58*4882a593Smuzhiyun * omap_cm_base_init - Populates the cm partitions
59*4882a593Smuzhiyun *
60*4882a593Smuzhiyun * Populates the base addresses of the _cm_bases
61*4882a593Smuzhiyun * array used for read/write of cm module registers.
62*4882a593Smuzhiyun */
omap_cm_base_init(void)63*4882a593Smuzhiyun static void omap_cm_base_init(void)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun memcpy(&_cm_bases[OMAP4430_PRM_PARTITION], &prm_base, sizeof(prm_base));
66*4882a593Smuzhiyun memcpy(&_cm_bases[OMAP4430_CM1_PARTITION], &cm_base, sizeof(cm_base));
67*4882a593Smuzhiyun memcpy(&_cm_bases[OMAP4430_CM2_PARTITION], &cm2_base, sizeof(cm2_base));
68*4882a593Smuzhiyun memcpy(&_cm_bases[OMAP4430_PRCM_MPU_PARTITION], &prcm_mpu_base,
69*4882a593Smuzhiyun sizeof(prcm_mpu_base));
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* Private functions */
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /**
77*4882a593Smuzhiyun * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
78*4882a593Smuzhiyun * @part: PRCM partition ID that the CM_CLKCTRL register exists in
79*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
80*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
81*4882a593Smuzhiyun *
82*4882a593Smuzhiyun * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
83*4882a593Smuzhiyun * bit 0.
84*4882a593Smuzhiyun */
_clkctrl_idlest(u8 part,u16 inst,u16 clkctrl_offs)85*4882a593Smuzhiyun static u32 _clkctrl_idlest(u8 part, u16 inst, u16 clkctrl_offs)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
88*4882a593Smuzhiyun v &= OMAP4430_IDLEST_MASK;
89*4882a593Smuzhiyun v >>= OMAP4430_IDLEST_SHIFT;
90*4882a593Smuzhiyun return v;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /**
94*4882a593Smuzhiyun * _is_module_ready - can module registers be accessed without causing an abort?
95*4882a593Smuzhiyun * @part: PRCM partition ID that the CM_CLKCTRL register exists in
96*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
97*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
98*4882a593Smuzhiyun *
99*4882a593Smuzhiyun * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
100*4882a593Smuzhiyun * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
101*4882a593Smuzhiyun */
_is_module_ready(u8 part,u16 inst,u16 clkctrl_offs)102*4882a593Smuzhiyun static bool _is_module_ready(u8 part, u16 inst, u16 clkctrl_offs)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun u32 v;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun v = _clkctrl_idlest(part, inst, clkctrl_offs);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
109*4882a593Smuzhiyun v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* Read a register in a CM instance */
omap4_cminst_read_inst_reg(u8 part,u16 inst,u16 idx)113*4882a593Smuzhiyun static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
116*4882a593Smuzhiyun part == OMAP4430_INVALID_PRCM_PARTITION ||
117*4882a593Smuzhiyun !_cm_bases[part].va);
118*4882a593Smuzhiyun return readl_relaxed(_cm_bases[part].va + inst + idx);
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /* Write into a register in a CM instance */
omap4_cminst_write_inst_reg(u32 val,u8 part,u16 inst,u16 idx)122*4882a593Smuzhiyun static void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
125*4882a593Smuzhiyun part == OMAP4430_INVALID_PRCM_PARTITION ||
126*4882a593Smuzhiyun !_cm_bases[part].va);
127*4882a593Smuzhiyun writel_relaxed(val, _cm_bases[part].va + inst + idx);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* Read-modify-write a register in CM1. Caller must lock */
omap4_cminst_rmw_inst_reg_bits(u32 mask,u32 bits,u8 part,u16 inst,s16 idx)131*4882a593Smuzhiyun static u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst,
132*4882a593Smuzhiyun s16 idx)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun u32 v;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun v = omap4_cminst_read_inst_reg(part, inst, idx);
137*4882a593Smuzhiyun v &= ~mask;
138*4882a593Smuzhiyun v |= bits;
139*4882a593Smuzhiyun omap4_cminst_write_inst_reg(v, part, inst, idx);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun return v;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
omap4_cminst_set_inst_reg_bits(u32 bits,u8 part,u16 inst,s16 idx)144*4882a593Smuzhiyun static u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx);
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
omap4_cminst_clear_inst_reg_bits(u32 bits,u8 part,u16 inst,s16 idx)149*4882a593Smuzhiyun static u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst,
150*4882a593Smuzhiyun s16 idx)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx);
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
omap4_cminst_read_inst_reg_bits(u8 part,u16 inst,s16 idx,u32 mask)155*4882a593Smuzhiyun static u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun u32 v;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun v = omap4_cminst_read_inst_reg(part, inst, idx);
160*4882a593Smuzhiyun v &= mask;
161*4882a593Smuzhiyun v >>= __ffs(mask);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun return v;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /*
167*4882a593Smuzhiyun *
168*4882a593Smuzhiyun */
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /**
171*4882a593Smuzhiyun * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield
172*4882a593Smuzhiyun * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted)
173*4882a593Smuzhiyun * @part: PRCM partition ID that the CM_CLKSTCTRL register exists in
174*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
175*4882a593Smuzhiyun * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
176*4882a593Smuzhiyun *
177*4882a593Smuzhiyun * @c must be the unshifted value for CLKTRCTRL - i.e., this function
178*4882a593Smuzhiyun * will handle the shift itself.
179*4882a593Smuzhiyun */
_clktrctrl_write(u8 c,u8 part,u16 inst,u16 cdoffs)180*4882a593Smuzhiyun static void _clktrctrl_write(u8 c, u8 part, u16 inst, u16 cdoffs)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun u32 v;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
185*4882a593Smuzhiyun v &= ~OMAP4430_CLKTRCTRL_MASK;
186*4882a593Smuzhiyun v |= c << OMAP4430_CLKTRCTRL_SHIFT;
187*4882a593Smuzhiyun omap4_cminst_write_inst_reg(v, part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /**
191*4882a593Smuzhiyun * omap4_cminst_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode?
192*4882a593Smuzhiyun * @part: PRCM partition ID that the CM_CLKSTCTRL register exists in
193*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
194*4882a593Smuzhiyun * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
195*4882a593Smuzhiyun *
196*4882a593Smuzhiyun * Returns true if the clockdomain referred to by (@part, @inst, @cdoffs)
197*4882a593Smuzhiyun * is in hardware-supervised idle mode, or 0 otherwise.
198*4882a593Smuzhiyun */
omap4_cminst_is_clkdm_in_hwsup(u8 part,u16 inst,u16 cdoffs)199*4882a593Smuzhiyun static bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun u32 v;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
204*4882a593Smuzhiyun v &= OMAP4430_CLKTRCTRL_MASK;
205*4882a593Smuzhiyun v >>= OMAP4430_CLKTRCTRL_SHIFT;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun /**
211*4882a593Smuzhiyun * omap4_cminst_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode
212*4882a593Smuzhiyun * @part: PRCM partition ID that the clockdomain registers exist in
213*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
214*4882a593Smuzhiyun * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
215*4882a593Smuzhiyun *
216*4882a593Smuzhiyun * Put a clockdomain referred to by (@part, @inst, @cdoffs) into
217*4882a593Smuzhiyun * hardware-supervised idle mode. No return value.
218*4882a593Smuzhiyun */
omap4_cminst_clkdm_enable_hwsup(u8 part,u16 inst,u16 cdoffs)219*4882a593Smuzhiyun static void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /**
225*4882a593Smuzhiyun * omap4_cminst_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode
226*4882a593Smuzhiyun * @part: PRCM partition ID that the clockdomain registers exist in
227*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
228*4882a593Smuzhiyun * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
229*4882a593Smuzhiyun *
230*4882a593Smuzhiyun * Put a clockdomain referred to by (@part, @inst, @cdoffs) into
231*4882a593Smuzhiyun * software-supervised idle mode, i.e., controlled manually by the
232*4882a593Smuzhiyun * Linux OMAP clockdomain code. No return value.
233*4882a593Smuzhiyun */
omap4_cminst_clkdm_disable_hwsup(u8 part,u16 inst,u16 cdoffs)234*4882a593Smuzhiyun static void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /**
240*4882a593Smuzhiyun * omap4_cminst_clkdm_force_sleep - try to take a clockdomain out of idle
241*4882a593Smuzhiyun * @part: PRCM partition ID that the clockdomain registers exist in
242*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
243*4882a593Smuzhiyun * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
244*4882a593Smuzhiyun *
245*4882a593Smuzhiyun * Take a clockdomain referred to by (@part, @inst, @cdoffs) out of idle,
246*4882a593Smuzhiyun * waking it up. No return value.
247*4882a593Smuzhiyun */
omap4_cminst_clkdm_force_wakeup(u8 part,u16 inst,u16 cdoffs)248*4882a593Smuzhiyun static void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs);
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /*
254*4882a593Smuzhiyun *
255*4882a593Smuzhiyun */
256*4882a593Smuzhiyun
omap4_cminst_clkdm_force_sleep(u8 part,u16 inst,u16 cdoffs)257*4882a593Smuzhiyun static void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, part, inst, cdoffs);
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /**
263*4882a593Smuzhiyun * omap4_cminst_wait_module_ready - wait for a module to be in 'func' state
264*4882a593Smuzhiyun * @part: PRCM partition ID that the CM_CLKCTRL register exists in
265*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
266*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
267*4882a593Smuzhiyun * @bit_shift: bit shift for the register, ignored for OMAP4+
268*4882a593Smuzhiyun *
269*4882a593Smuzhiyun * Wait for the module IDLEST to be functional. If the idle state is in any
270*4882a593Smuzhiyun * the non functional state (trans, idle or disabled), module and thus the
271*4882a593Smuzhiyun * sysconfig cannot be accessed and will probably lead to an "imprecise
272*4882a593Smuzhiyun * external abort"
273*4882a593Smuzhiyun */
omap4_cminst_wait_module_ready(u8 part,s16 inst,u16 clkctrl_offs,u8 bit_shift)274*4882a593Smuzhiyun static int omap4_cminst_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
275*4882a593Smuzhiyun u8 bit_shift)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun int i = 0;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun omap_test_timeout(_is_module_ready(part, inst, clkctrl_offs),
280*4882a593Smuzhiyun MAX_MODULE_READY_TIME, i);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /**
286*4882a593Smuzhiyun * omap4_cminst_wait_module_idle - wait for a module to be in 'disabled'
287*4882a593Smuzhiyun * state
288*4882a593Smuzhiyun * @part: PRCM partition ID that the CM_CLKCTRL register exists in
289*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
290*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
291*4882a593Smuzhiyun * @bit_shift: Bit shift for the register, ignored for OMAP4+
292*4882a593Smuzhiyun *
293*4882a593Smuzhiyun * Wait for the module IDLEST to be disabled. Some PRCM transition,
294*4882a593Smuzhiyun * like reset assertion or parent clock de-activation must wait the
295*4882a593Smuzhiyun * module to be fully disabled.
296*4882a593Smuzhiyun */
omap4_cminst_wait_module_idle(u8 part,s16 inst,u16 clkctrl_offs,u8 bit_shift)297*4882a593Smuzhiyun static int omap4_cminst_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
298*4882a593Smuzhiyun u8 bit_shift)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun int i = 0;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun omap_test_timeout((_clkctrl_idlest(part, inst, clkctrl_offs) ==
303*4882a593Smuzhiyun CLKCTRL_IDLEST_DISABLED),
304*4882a593Smuzhiyun MAX_MODULE_DISABLE_TIME, i);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun return (i < MAX_MODULE_DISABLE_TIME) ? 0 : -EBUSY;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun /**
310*4882a593Smuzhiyun * omap4_cminst_module_enable - Enable the modulemode inside CLKCTRL
311*4882a593Smuzhiyun * @mode: Module mode (SW or HW)
312*4882a593Smuzhiyun * @part: PRCM partition ID that the CM_CLKCTRL register exists in
313*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
314*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
315*4882a593Smuzhiyun *
316*4882a593Smuzhiyun * No return value.
317*4882a593Smuzhiyun */
omap4_cminst_module_enable(u8 mode,u8 part,u16 inst,u16 clkctrl_offs)318*4882a593Smuzhiyun static void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst,
319*4882a593Smuzhiyun u16 clkctrl_offs)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun u32 v;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
324*4882a593Smuzhiyun v &= ~OMAP4430_MODULEMODE_MASK;
325*4882a593Smuzhiyun v |= mode << OMAP4430_MODULEMODE_SHIFT;
326*4882a593Smuzhiyun omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs);
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun /**
330*4882a593Smuzhiyun * omap4_cminst_module_disable - Disable the module inside CLKCTRL
331*4882a593Smuzhiyun * @part: PRCM partition ID that the CM_CLKCTRL register exists in
332*4882a593Smuzhiyun * @inst: CM instance register offset (*_INST macro)
333*4882a593Smuzhiyun * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
334*4882a593Smuzhiyun *
335*4882a593Smuzhiyun * No return value.
336*4882a593Smuzhiyun */
omap4_cminst_module_disable(u8 part,u16 inst,u16 clkctrl_offs)337*4882a593Smuzhiyun static void omap4_cminst_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun u32 v;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
342*4882a593Smuzhiyun v &= ~OMAP4430_MODULEMODE_MASK;
343*4882a593Smuzhiyun omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun /*
347*4882a593Smuzhiyun * Clockdomain low-level functions
348*4882a593Smuzhiyun */
349*4882a593Smuzhiyun
omap4_clkdm_add_wkup_sleep_dep(struct clockdomain * clkdm1,struct clockdomain * clkdm2)350*4882a593Smuzhiyun static int omap4_clkdm_add_wkup_sleep_dep(struct clockdomain *clkdm1,
351*4882a593Smuzhiyun struct clockdomain *clkdm2)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun omap4_cminst_set_inst_reg_bits((1 << clkdm2->dep_bit),
354*4882a593Smuzhiyun clkdm1->prcm_partition,
355*4882a593Smuzhiyun clkdm1->cm_inst, clkdm1->clkdm_offs +
356*4882a593Smuzhiyun OMAP4_CM_STATICDEP);
357*4882a593Smuzhiyun return 0;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
omap4_clkdm_del_wkup_sleep_dep(struct clockdomain * clkdm1,struct clockdomain * clkdm2)360*4882a593Smuzhiyun static int omap4_clkdm_del_wkup_sleep_dep(struct clockdomain *clkdm1,
361*4882a593Smuzhiyun struct clockdomain *clkdm2)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun omap4_cminst_clear_inst_reg_bits((1 << clkdm2->dep_bit),
364*4882a593Smuzhiyun clkdm1->prcm_partition,
365*4882a593Smuzhiyun clkdm1->cm_inst, clkdm1->clkdm_offs +
366*4882a593Smuzhiyun OMAP4_CM_STATICDEP);
367*4882a593Smuzhiyun return 0;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
omap4_clkdm_read_wkup_sleep_dep(struct clockdomain * clkdm1,struct clockdomain * clkdm2)370*4882a593Smuzhiyun static int omap4_clkdm_read_wkup_sleep_dep(struct clockdomain *clkdm1,
371*4882a593Smuzhiyun struct clockdomain *clkdm2)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun return omap4_cminst_read_inst_reg_bits(clkdm1->prcm_partition,
374*4882a593Smuzhiyun clkdm1->cm_inst,
375*4882a593Smuzhiyun clkdm1->clkdm_offs +
376*4882a593Smuzhiyun OMAP4_CM_STATICDEP,
377*4882a593Smuzhiyun (1 << clkdm2->dep_bit));
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain * clkdm)380*4882a593Smuzhiyun static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun struct clkdm_dep *cd;
383*4882a593Smuzhiyun u32 mask = 0;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun if (!clkdm->prcm_partition)
386*4882a593Smuzhiyun return 0;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
389*4882a593Smuzhiyun if (!cd->clkdm)
390*4882a593Smuzhiyun continue; /* only happens if data is erroneous */
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun mask |= 1 << cd->clkdm->dep_bit;
393*4882a593Smuzhiyun cd->wkdep_usecount = 0;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition,
397*4882a593Smuzhiyun clkdm->cm_inst, clkdm->clkdm_offs +
398*4882a593Smuzhiyun OMAP4_CM_STATICDEP);
399*4882a593Smuzhiyun return 0;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
omap4_clkdm_sleep(struct clockdomain * clkdm)402*4882a593Smuzhiyun static int omap4_clkdm_sleep(struct clockdomain *clkdm)
403*4882a593Smuzhiyun {
404*4882a593Smuzhiyun if (clkdm->flags & CLKDM_CAN_HWSUP)
405*4882a593Smuzhiyun omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
406*4882a593Smuzhiyun clkdm->cm_inst,
407*4882a593Smuzhiyun clkdm->clkdm_offs);
408*4882a593Smuzhiyun else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
409*4882a593Smuzhiyun omap4_cminst_clkdm_force_sleep(clkdm->prcm_partition,
410*4882a593Smuzhiyun clkdm->cm_inst,
411*4882a593Smuzhiyun clkdm->clkdm_offs);
412*4882a593Smuzhiyun else
413*4882a593Smuzhiyun return -EINVAL;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun return 0;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
omap4_clkdm_wakeup(struct clockdomain * clkdm)418*4882a593Smuzhiyun static int omap4_clkdm_wakeup(struct clockdomain *clkdm)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
421*4882a593Smuzhiyun clkdm->cm_inst, clkdm->clkdm_offs);
422*4882a593Smuzhiyun return 0;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
omap4_clkdm_allow_idle(struct clockdomain * clkdm)425*4882a593Smuzhiyun static void omap4_clkdm_allow_idle(struct clockdomain *clkdm)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
428*4882a593Smuzhiyun clkdm->cm_inst, clkdm->clkdm_offs);
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
omap4_clkdm_deny_idle(struct clockdomain * clkdm)431*4882a593Smuzhiyun static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
434*4882a593Smuzhiyun omap4_clkdm_wakeup(clkdm);
435*4882a593Smuzhiyun else
436*4882a593Smuzhiyun omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
437*4882a593Smuzhiyun clkdm->cm_inst,
438*4882a593Smuzhiyun clkdm->clkdm_offs);
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
omap4_clkdm_clk_enable(struct clockdomain * clkdm)441*4882a593Smuzhiyun static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
444*4882a593Smuzhiyun return omap4_clkdm_wakeup(clkdm);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun return 0;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
omap4_clkdm_clk_disable(struct clockdomain * clkdm)449*4882a593Smuzhiyun static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun bool hwsup = false;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun if (!clkdm->prcm_partition)
454*4882a593Smuzhiyun return 0;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun /*
457*4882a593Smuzhiyun * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
458*4882a593Smuzhiyun * more details on the unpleasant problem this is working
459*4882a593Smuzhiyun * around
460*4882a593Smuzhiyun */
461*4882a593Smuzhiyun if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
462*4882a593Smuzhiyun !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
463*4882a593Smuzhiyun omap4_clkdm_allow_idle(clkdm);
464*4882a593Smuzhiyun return 0;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
468*4882a593Smuzhiyun clkdm->cm_inst, clkdm->clkdm_offs);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
471*4882a593Smuzhiyun omap4_clkdm_sleep(clkdm);
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun return 0;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
omap4_cminst_xlate_clkctrl(u8 part,u16 inst,u16 offset)476*4882a593Smuzhiyun static u32 omap4_cminst_xlate_clkctrl(u8 part, u16 inst, u16 offset)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun return _cm_bases[part].pa + inst + offset;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun /**
482*4882a593Smuzhiyun * omap4_clkdm_save_context - Save the clockdomain modulemode context
483*4882a593Smuzhiyun * @clkdm: The clockdomain pointer whose context needs to be saved
484*4882a593Smuzhiyun *
485*4882a593Smuzhiyun * Save the clockdomain modulemode context.
486*4882a593Smuzhiyun */
omap4_clkdm_save_context(struct clockdomain * clkdm)487*4882a593Smuzhiyun static int omap4_clkdm_save_context(struct clockdomain *clkdm)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun clkdm->context = omap4_cminst_read_inst_reg(clkdm->prcm_partition,
490*4882a593Smuzhiyun clkdm->cm_inst,
491*4882a593Smuzhiyun clkdm->clkdm_offs +
492*4882a593Smuzhiyun OMAP4_CM_CLKSTCTRL);
493*4882a593Smuzhiyun clkdm->context &= OMAP4430_MODULEMODE_MASK;
494*4882a593Smuzhiyun return 0;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun /**
498*4882a593Smuzhiyun * omap4_clkdm_restore_context - Restore the clockdomain modulemode context
499*4882a593Smuzhiyun * @clkdm: The clockdomain pointer whose context needs to be restored
500*4882a593Smuzhiyun *
501*4882a593Smuzhiyun * Restore the clockdomain modulemode context.
502*4882a593Smuzhiyun */
omap4_clkdm_restore_context(struct clockdomain * clkdm)503*4882a593Smuzhiyun static int omap4_clkdm_restore_context(struct clockdomain *clkdm)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun switch (clkdm->context) {
506*4882a593Smuzhiyun case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
507*4882a593Smuzhiyun omap4_clkdm_deny_idle(clkdm);
508*4882a593Smuzhiyun break;
509*4882a593Smuzhiyun case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
510*4882a593Smuzhiyun omap4_clkdm_sleep(clkdm);
511*4882a593Smuzhiyun break;
512*4882a593Smuzhiyun case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
513*4882a593Smuzhiyun omap4_clkdm_wakeup(clkdm);
514*4882a593Smuzhiyun break;
515*4882a593Smuzhiyun case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
516*4882a593Smuzhiyun omap4_clkdm_allow_idle(clkdm);
517*4882a593Smuzhiyun break;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun return 0;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun struct clkdm_ops omap4_clkdm_operations = {
523*4882a593Smuzhiyun .clkdm_add_wkdep = omap4_clkdm_add_wkup_sleep_dep,
524*4882a593Smuzhiyun .clkdm_del_wkdep = omap4_clkdm_del_wkup_sleep_dep,
525*4882a593Smuzhiyun .clkdm_read_wkdep = omap4_clkdm_read_wkup_sleep_dep,
526*4882a593Smuzhiyun .clkdm_clear_all_wkdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
527*4882a593Smuzhiyun .clkdm_add_sleepdep = omap4_clkdm_add_wkup_sleep_dep,
528*4882a593Smuzhiyun .clkdm_del_sleepdep = omap4_clkdm_del_wkup_sleep_dep,
529*4882a593Smuzhiyun .clkdm_read_sleepdep = omap4_clkdm_read_wkup_sleep_dep,
530*4882a593Smuzhiyun .clkdm_clear_all_sleepdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
531*4882a593Smuzhiyun .clkdm_sleep = omap4_clkdm_sleep,
532*4882a593Smuzhiyun .clkdm_wakeup = omap4_clkdm_wakeup,
533*4882a593Smuzhiyun .clkdm_allow_idle = omap4_clkdm_allow_idle,
534*4882a593Smuzhiyun .clkdm_deny_idle = omap4_clkdm_deny_idle,
535*4882a593Smuzhiyun .clkdm_clk_enable = omap4_clkdm_clk_enable,
536*4882a593Smuzhiyun .clkdm_clk_disable = omap4_clkdm_clk_disable,
537*4882a593Smuzhiyun .clkdm_save_context = omap4_clkdm_save_context,
538*4882a593Smuzhiyun .clkdm_restore_context = omap4_clkdm_restore_context,
539*4882a593Smuzhiyun };
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun struct clkdm_ops am43xx_clkdm_operations = {
542*4882a593Smuzhiyun .clkdm_sleep = omap4_clkdm_sleep,
543*4882a593Smuzhiyun .clkdm_wakeup = omap4_clkdm_wakeup,
544*4882a593Smuzhiyun .clkdm_allow_idle = omap4_clkdm_allow_idle,
545*4882a593Smuzhiyun .clkdm_deny_idle = omap4_clkdm_deny_idle,
546*4882a593Smuzhiyun .clkdm_clk_enable = omap4_clkdm_clk_enable,
547*4882a593Smuzhiyun .clkdm_clk_disable = omap4_clkdm_clk_disable,
548*4882a593Smuzhiyun };
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun static const struct cm_ll_data omap4xxx_cm_ll_data = {
551*4882a593Smuzhiyun .wait_module_ready = &omap4_cminst_wait_module_ready,
552*4882a593Smuzhiyun .wait_module_idle = &omap4_cminst_wait_module_idle,
553*4882a593Smuzhiyun .module_enable = &omap4_cminst_module_enable,
554*4882a593Smuzhiyun .module_disable = &omap4_cminst_module_disable,
555*4882a593Smuzhiyun .xlate_clkctrl = &omap4_cminst_xlate_clkctrl,
556*4882a593Smuzhiyun };
557*4882a593Smuzhiyun
omap4_cm_init(const struct omap_prcm_init_data * data)558*4882a593Smuzhiyun int __init omap4_cm_init(const struct omap_prcm_init_data *data)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun omap_cm_base_init();
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun return cm_register(&omap4xxx_cm_ll_data);
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun
omap4_cm_exit(void)565*4882a593Smuzhiyun static void __exit omap4_cm_exit(void)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun cm_unregister(&omap4xxx_cm_ll_data);
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun __exitcall(omap4_cm_exit);
570