1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * omap_hwmod implementation for OMAP2/3/4
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2009-2011 Nokia Corporation
6*4882a593Smuzhiyun * Copyright (C) 2011-2012 Texas Instruments, Inc.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Paul Walmsley, Benoît Cousson, Kevin Hilman
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Created in collaboration with (alphabetical order): Thara Gopinath,
11*4882a593Smuzhiyun * Tony Lindgren, Rajendra Nayak, Vikram Pandita, Sakari Poussa, Anand
12*4882a593Smuzhiyun * Sawant, Santosh Shilimkar, Richard Woodruff
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * Introduction
15*4882a593Smuzhiyun * ------------
16*4882a593Smuzhiyun * One way to view an OMAP SoC is as a collection of largely unrelated
17*4882a593Smuzhiyun * IP blocks connected by interconnects. The IP blocks include
18*4882a593Smuzhiyun * devices such as ARM processors, audio serial interfaces, UARTs,
19*4882a593Smuzhiyun * etc. Some of these devices, like the DSP, are created by TI;
20*4882a593Smuzhiyun * others, like the SGX, largely originate from external vendors. In
21*4882a593Smuzhiyun * TI's documentation, on-chip devices are referred to as "OMAP
22*4882a593Smuzhiyun * modules." Some of these IP blocks are identical across several
23*4882a593Smuzhiyun * OMAP versions. Others are revised frequently.
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * These OMAP modules are tied together by various interconnects.
26*4882a593Smuzhiyun * Most of the address and data flow between modules is via OCP-based
27*4882a593Smuzhiyun * interconnects such as the L3 and L4 buses; but there are other
28*4882a593Smuzhiyun * interconnects that distribute the hardware clock tree, handle idle
29*4882a593Smuzhiyun * and reset signaling, supply power, and connect the modules to
30*4882a593Smuzhiyun * various pads or balls on the OMAP package.
31*4882a593Smuzhiyun *
32*4882a593Smuzhiyun * OMAP hwmod provides a consistent way to describe the on-chip
33*4882a593Smuzhiyun * hardware blocks and their integration into the rest of the chip.
34*4882a593Smuzhiyun * This description can be automatically generated from the TI
35*4882a593Smuzhiyun * hardware database. OMAP hwmod provides a standard, consistent API
36*4882a593Smuzhiyun * to reset, enable, idle, and disable these hardware blocks. And
37*4882a593Smuzhiyun * hwmod provides a way for other core code, such as the Linux device
38*4882a593Smuzhiyun * code or the OMAP power management and address space mapping code,
39*4882a593Smuzhiyun * to query the hardware database.
40*4882a593Smuzhiyun *
41*4882a593Smuzhiyun * Using hwmod
42*4882a593Smuzhiyun * -----------
43*4882a593Smuzhiyun * Drivers won't call hwmod functions directly. That is done by the
44*4882a593Smuzhiyun * omap_device code, and in rare occasions, by custom integration code
45*4882a593Smuzhiyun * in arch/arm/ *omap*. The omap_device code includes functions to
46*4882a593Smuzhiyun * build a struct platform_device using omap_hwmod data, and that is
47*4882a593Smuzhiyun * currently how hwmod data is communicated to drivers and to the
48*4882a593Smuzhiyun * Linux driver model. Most drivers will call omap_hwmod functions only
49*4882a593Smuzhiyun * indirectly, via pm_runtime*() functions.
50*4882a593Smuzhiyun *
51*4882a593Smuzhiyun * From a layering perspective, here is where the OMAP hwmod code
52*4882a593Smuzhiyun * fits into the kernel software stack:
53*4882a593Smuzhiyun *
54*4882a593Smuzhiyun * +-------------------------------+
55*4882a593Smuzhiyun * | Device driver code |
56*4882a593Smuzhiyun * | (e.g., drivers/) |
57*4882a593Smuzhiyun * +-------------------------------+
58*4882a593Smuzhiyun * | Linux driver model |
59*4882a593Smuzhiyun * | (platform_device / |
60*4882a593Smuzhiyun * | platform_driver data/code) |
61*4882a593Smuzhiyun * +-------------------------------+
62*4882a593Smuzhiyun * | OMAP core-driver integration |
63*4882a593Smuzhiyun * |(arch/arm/mach-omap2/devices.c)|
64*4882a593Smuzhiyun * +-------------------------------+
65*4882a593Smuzhiyun * | omap_device code |
66*4882a593Smuzhiyun * | (../plat-omap/omap_device.c) |
67*4882a593Smuzhiyun * +-------------------------------+
68*4882a593Smuzhiyun * ----> | omap_hwmod code/data | <-----
69*4882a593Smuzhiyun * | (../mach-omap2/omap_hwmod*) |
70*4882a593Smuzhiyun * +-------------------------------+
71*4882a593Smuzhiyun * | OMAP clock/PRCM/register fns |
72*4882a593Smuzhiyun * | ({read,write}l_relaxed, clk*) |
73*4882a593Smuzhiyun * +-------------------------------+
74*4882a593Smuzhiyun *
75*4882a593Smuzhiyun * Device drivers should not contain any OMAP-specific code or data in
76*4882a593Smuzhiyun * them. They should only contain code to operate the IP block that
77*4882a593Smuzhiyun * the driver is responsible for. This is because these IP blocks can
78*4882a593Smuzhiyun * also appear in other SoCs, either from TI (such as DaVinci) or from
79*4882a593Smuzhiyun * other manufacturers; and drivers should be reusable across other
80*4882a593Smuzhiyun * platforms.
81*4882a593Smuzhiyun *
82*4882a593Smuzhiyun * The OMAP hwmod code also will attempt to reset and idle all on-chip
83*4882a593Smuzhiyun * devices upon boot. The goal here is for the kernel to be
84*4882a593Smuzhiyun * completely self-reliant and independent from bootloaders. This is
85*4882a593Smuzhiyun * to ensure a repeatable configuration, both to ensure consistent
86*4882a593Smuzhiyun * runtime behavior, and to make it easier for others to reproduce
87*4882a593Smuzhiyun * bugs.
88*4882a593Smuzhiyun *
89*4882a593Smuzhiyun * OMAP module activity states
90*4882a593Smuzhiyun * ---------------------------
91*4882a593Smuzhiyun * The hwmod code considers modules to be in one of several activity
92*4882a593Smuzhiyun * states. IP blocks start out in an UNKNOWN state, then once they
93*4882a593Smuzhiyun * are registered via the hwmod code, proceed to the REGISTERED state.
94*4882a593Smuzhiyun * Once their clock names are resolved to clock pointers, the module
95*4882a593Smuzhiyun * enters the CLKS_INITED state; and finally, once the module has been
96*4882a593Smuzhiyun * reset and the integration registers programmed, the INITIALIZED state
97*4882a593Smuzhiyun * is entered. The hwmod code will then place the module into either
98*4882a593Smuzhiyun * the IDLE state to save power, or in the case of a critical system
99*4882a593Smuzhiyun * module, the ENABLED state.
100*4882a593Smuzhiyun *
101*4882a593Smuzhiyun * OMAP core integration code can then call omap_hwmod*() functions
102*4882a593Smuzhiyun * directly to move the module between the IDLE, ENABLED, and DISABLED
103*4882a593Smuzhiyun * states, as needed. This is done during both the PM idle loop, and
104*4882a593Smuzhiyun * in the OMAP core integration code's implementation of the PM runtime
105*4882a593Smuzhiyun * functions.
106*4882a593Smuzhiyun *
107*4882a593Smuzhiyun * References
108*4882a593Smuzhiyun * ----------
109*4882a593Smuzhiyun * This is a partial list.
110*4882a593Smuzhiyun * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064)
111*4882a593Smuzhiyun * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090)
112*4882a593Smuzhiyun * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108)
113*4882a593Smuzhiyun * - OMAP4430 Multimedia Device Silicon Revision 1.0 (SWPU140)
114*4882a593Smuzhiyun * - Open Core Protocol Specification 2.2
115*4882a593Smuzhiyun *
116*4882a593Smuzhiyun * To do:
117*4882a593Smuzhiyun * - handle IO mapping
118*4882a593Smuzhiyun * - bus throughput & module latency measurement code
119*4882a593Smuzhiyun *
120*4882a593Smuzhiyun * XXX add tests at the beginning of each function to ensure the hwmod is
121*4882a593Smuzhiyun * in the appropriate state
122*4882a593Smuzhiyun * XXX error return values should be checked to ensure that they are
123*4882a593Smuzhiyun * appropriate
124*4882a593Smuzhiyun */
125*4882a593Smuzhiyun #undef DEBUG
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun #include <linux/kernel.h>
128*4882a593Smuzhiyun #include <linux/errno.h>
129*4882a593Smuzhiyun #include <linux/io.h>
130*4882a593Smuzhiyun #include <linux/clk.h>
131*4882a593Smuzhiyun #include <linux/clk-provider.h>
132*4882a593Smuzhiyun #include <linux/delay.h>
133*4882a593Smuzhiyun #include <linux/err.h>
134*4882a593Smuzhiyun #include <linux/list.h>
135*4882a593Smuzhiyun #include <linux/mutex.h>
136*4882a593Smuzhiyun #include <linux/spinlock.h>
137*4882a593Smuzhiyun #include <linux/slab.h>
138*4882a593Smuzhiyun #include <linux/cpu.h>
139*4882a593Smuzhiyun #include <linux/of.h>
140*4882a593Smuzhiyun #include <linux/of_address.h>
141*4882a593Smuzhiyun #include <linux/memblock.h>
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun #include <linux/platform_data/ti-sysc.h>
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun #include <dt-bindings/bus/ti-sysc.h>
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun #include <asm/system_misc.h>
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun #include "clock.h"
150*4882a593Smuzhiyun #include "omap_hwmod.h"
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun #include "soc.h"
153*4882a593Smuzhiyun #include "common.h"
154*4882a593Smuzhiyun #include "clockdomain.h"
155*4882a593Smuzhiyun #include "hdq1w.h"
156*4882a593Smuzhiyun #include "mmc.h"
157*4882a593Smuzhiyun #include "powerdomain.h"
158*4882a593Smuzhiyun #include "cm2xxx.h"
159*4882a593Smuzhiyun #include "cm3xxx.h"
160*4882a593Smuzhiyun #include "cm33xx.h"
161*4882a593Smuzhiyun #include "prm.h"
162*4882a593Smuzhiyun #include "prm3xxx.h"
163*4882a593Smuzhiyun #include "prm44xx.h"
164*4882a593Smuzhiyun #include "prm33xx.h"
165*4882a593Smuzhiyun #include "prminst44xx.h"
166*4882a593Smuzhiyun #include "pm.h"
167*4882a593Smuzhiyun #include "wd_timer.h"
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun /* Name of the OMAP hwmod for the MPU */
170*4882a593Smuzhiyun #define MPU_INITIATOR_NAME "mpu"
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /*
173*4882a593Smuzhiyun * Number of struct omap_hwmod_link records per struct
174*4882a593Smuzhiyun * omap_hwmod_ocp_if record (master->slave and slave->master)
175*4882a593Smuzhiyun */
176*4882a593Smuzhiyun #define LINKS_PER_OCP_IF 2
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /*
179*4882a593Smuzhiyun * Address offset (in bytes) between the reset control and the reset
180*4882a593Smuzhiyun * status registers: 4 bytes on OMAP4
181*4882a593Smuzhiyun */
182*4882a593Smuzhiyun #define OMAP4_RST_CTRL_ST_OFFSET 4
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /*
185*4882a593Smuzhiyun * Maximum length for module clock handle names
186*4882a593Smuzhiyun */
187*4882a593Smuzhiyun #define MOD_CLK_MAX_NAME_LEN 32
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun /**
190*4882a593Smuzhiyun * struct clkctrl_provider - clkctrl provider mapping data
191*4882a593Smuzhiyun * @num_addrs: number of base address ranges for the provider
192*4882a593Smuzhiyun * @addr: base address(es) for the provider
193*4882a593Smuzhiyun * @size: size(s) of the provider address space(s)
194*4882a593Smuzhiyun * @node: device node associated with the provider
195*4882a593Smuzhiyun * @link: list link
196*4882a593Smuzhiyun */
197*4882a593Smuzhiyun struct clkctrl_provider {
198*4882a593Smuzhiyun int num_addrs;
199*4882a593Smuzhiyun u32 *addr;
200*4882a593Smuzhiyun u32 *size;
201*4882a593Smuzhiyun struct device_node *node;
202*4882a593Smuzhiyun struct list_head link;
203*4882a593Smuzhiyun };
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun static LIST_HEAD(clkctrl_providers);
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /**
208*4882a593Smuzhiyun * struct omap_hwmod_reset - IP specific reset functions
209*4882a593Smuzhiyun * @match: string to match against the module name
210*4882a593Smuzhiyun * @len: number of characters to match
211*4882a593Smuzhiyun * @reset: IP specific reset function
212*4882a593Smuzhiyun *
213*4882a593Smuzhiyun * Used only in cases where struct omap_hwmod is dynamically allocated.
214*4882a593Smuzhiyun */
215*4882a593Smuzhiyun struct omap_hwmod_reset {
216*4882a593Smuzhiyun const char *match;
217*4882a593Smuzhiyun int len;
218*4882a593Smuzhiyun int (*reset)(struct omap_hwmod *oh);
219*4882a593Smuzhiyun };
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun /**
222*4882a593Smuzhiyun * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations
223*4882a593Smuzhiyun * @enable_module: function to enable a module (via MODULEMODE)
224*4882a593Smuzhiyun * @disable_module: function to disable a module (via MODULEMODE)
225*4882a593Smuzhiyun *
226*4882a593Smuzhiyun * XXX Eventually this functionality will be hidden inside the PRM/CM
227*4882a593Smuzhiyun * device drivers. Until then, this should avoid huge blocks of cpu_is_*()
228*4882a593Smuzhiyun * conditionals in this code.
229*4882a593Smuzhiyun */
230*4882a593Smuzhiyun struct omap_hwmod_soc_ops {
231*4882a593Smuzhiyun void (*enable_module)(struct omap_hwmod *oh);
232*4882a593Smuzhiyun int (*disable_module)(struct omap_hwmod *oh);
233*4882a593Smuzhiyun int (*wait_target_ready)(struct omap_hwmod *oh);
234*4882a593Smuzhiyun int (*assert_hardreset)(struct omap_hwmod *oh,
235*4882a593Smuzhiyun struct omap_hwmod_rst_info *ohri);
236*4882a593Smuzhiyun int (*deassert_hardreset)(struct omap_hwmod *oh,
237*4882a593Smuzhiyun struct omap_hwmod_rst_info *ohri);
238*4882a593Smuzhiyun int (*is_hardreset_asserted)(struct omap_hwmod *oh,
239*4882a593Smuzhiyun struct omap_hwmod_rst_info *ohri);
240*4882a593Smuzhiyun int (*init_clkdm)(struct omap_hwmod *oh);
241*4882a593Smuzhiyun void (*update_context_lost)(struct omap_hwmod *oh);
242*4882a593Smuzhiyun int (*get_context_lost)(struct omap_hwmod *oh);
243*4882a593Smuzhiyun int (*disable_direct_prcm)(struct omap_hwmod *oh);
244*4882a593Smuzhiyun u32 (*xlate_clkctrl)(struct omap_hwmod *oh);
245*4882a593Smuzhiyun };
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun /* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */
248*4882a593Smuzhiyun static struct omap_hwmod_soc_ops soc_ops;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /* omap_hwmod_list contains all registered struct omap_hwmods */
251*4882a593Smuzhiyun static LIST_HEAD(omap_hwmod_list);
252*4882a593Smuzhiyun static DEFINE_MUTEX(list_lock);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun /* mpu_oh: used to add/remove MPU initiator from sleepdep list */
255*4882a593Smuzhiyun static struct omap_hwmod *mpu_oh;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /* inited: set to true once the hwmod code is initialized */
258*4882a593Smuzhiyun static bool inited;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /* Private functions */
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /**
263*4882a593Smuzhiyun * _update_sysc_cache - return the module OCP_SYSCONFIG register, keep copy
264*4882a593Smuzhiyun * @oh: struct omap_hwmod *
265*4882a593Smuzhiyun *
266*4882a593Smuzhiyun * Load the current value of the hwmod OCP_SYSCONFIG register into the
267*4882a593Smuzhiyun * struct omap_hwmod for later use. Returns -EINVAL if the hwmod has no
268*4882a593Smuzhiyun * OCP_SYSCONFIG register or 0 upon success.
269*4882a593Smuzhiyun */
_update_sysc_cache(struct omap_hwmod * oh)270*4882a593Smuzhiyun static int _update_sysc_cache(struct omap_hwmod *oh)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun if (!oh->class->sysc) {
273*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: cannot read OCP_SYSCONFIG: not defined on hwmod's class\n", oh->name);
274*4882a593Smuzhiyun return -EINVAL;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun /* XXX ensure module interface clock is up */
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun oh->_sysc_cache = omap_hwmod_read(oh, oh->class->sysc->sysc_offs);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun if (!(oh->class->sysc->sysc_flags & SYSC_NO_CACHE))
282*4882a593Smuzhiyun oh->_int_flags |= _HWMOD_SYSCONFIG_LOADED;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun return 0;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun /**
288*4882a593Smuzhiyun * _write_sysconfig - write a value to the module's OCP_SYSCONFIG register
289*4882a593Smuzhiyun * @v: OCP_SYSCONFIG value to write
290*4882a593Smuzhiyun * @oh: struct omap_hwmod *
291*4882a593Smuzhiyun *
292*4882a593Smuzhiyun * Write @v into the module class' OCP_SYSCONFIG register, if it has
293*4882a593Smuzhiyun * one. No return value.
294*4882a593Smuzhiyun */
_write_sysconfig(u32 v,struct omap_hwmod * oh)295*4882a593Smuzhiyun static void _write_sysconfig(u32 v, struct omap_hwmod *oh)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun if (!oh->class->sysc) {
298*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: cannot write OCP_SYSCONFIG: not defined on hwmod's class\n", oh->name);
299*4882a593Smuzhiyun return;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* XXX ensure module interface clock is up */
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun /* Module might have lost context, always update cache and register */
305*4882a593Smuzhiyun oh->_sysc_cache = v;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun /*
308*4882a593Smuzhiyun * Some IP blocks (such as RTC) require unlocking of IP before
309*4882a593Smuzhiyun * accessing its registers. If a function pointer is present
310*4882a593Smuzhiyun * to unlock, then call it before accessing sysconfig and
311*4882a593Smuzhiyun * call lock after writing sysconfig.
312*4882a593Smuzhiyun */
313*4882a593Smuzhiyun if (oh->class->unlock)
314*4882a593Smuzhiyun oh->class->unlock(oh);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun omap_hwmod_write(v, oh, oh->class->sysc->sysc_offs);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (oh->class->lock)
319*4882a593Smuzhiyun oh->class->lock(oh);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun /**
323*4882a593Smuzhiyun * _set_master_standbymode: set the OCP_SYSCONFIG MIDLEMODE field in @v
324*4882a593Smuzhiyun * @oh: struct omap_hwmod *
325*4882a593Smuzhiyun * @standbymode: MIDLEMODE field bits
326*4882a593Smuzhiyun * @v: pointer to register contents to modify
327*4882a593Smuzhiyun *
328*4882a593Smuzhiyun * Update the master standby mode bits in @v to be @standbymode for
329*4882a593Smuzhiyun * the @oh hwmod. Does not write to the hardware. Returns -EINVAL
330*4882a593Smuzhiyun * upon error or 0 upon success.
331*4882a593Smuzhiyun */
_set_master_standbymode(struct omap_hwmod * oh,u8 standbymode,u32 * v)332*4882a593Smuzhiyun static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode,
333*4882a593Smuzhiyun u32 *v)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun u32 mstandby_mask;
336*4882a593Smuzhiyun u8 mstandby_shift;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun if (!oh->class->sysc ||
339*4882a593Smuzhiyun !(oh->class->sysc->sysc_flags & SYSC_HAS_MIDLEMODE))
340*4882a593Smuzhiyun return -EINVAL;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (!oh->class->sysc->sysc_fields) {
343*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
344*4882a593Smuzhiyun return -EINVAL;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun mstandby_shift = oh->class->sysc->sysc_fields->midle_shift;
348*4882a593Smuzhiyun mstandby_mask = (0x3 << mstandby_shift);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun *v &= ~mstandby_mask;
351*4882a593Smuzhiyun *v |= __ffs(standbymode) << mstandby_shift;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun return 0;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /**
357*4882a593Smuzhiyun * _set_slave_idlemode: set the OCP_SYSCONFIG SIDLEMODE field in @v
358*4882a593Smuzhiyun * @oh: struct omap_hwmod *
359*4882a593Smuzhiyun * @idlemode: SIDLEMODE field bits
360*4882a593Smuzhiyun * @v: pointer to register contents to modify
361*4882a593Smuzhiyun *
362*4882a593Smuzhiyun * Update the slave idle mode bits in @v to be @idlemode for the @oh
363*4882a593Smuzhiyun * hwmod. Does not write to the hardware. Returns -EINVAL upon error
364*4882a593Smuzhiyun * or 0 upon success.
365*4882a593Smuzhiyun */
_set_slave_idlemode(struct omap_hwmod * oh,u8 idlemode,u32 * v)366*4882a593Smuzhiyun static int _set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode, u32 *v)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun u32 sidle_mask;
369*4882a593Smuzhiyun u8 sidle_shift;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (!oh->class->sysc ||
372*4882a593Smuzhiyun !(oh->class->sysc->sysc_flags & SYSC_HAS_SIDLEMODE))
373*4882a593Smuzhiyun return -EINVAL;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun if (!oh->class->sysc->sysc_fields) {
376*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
377*4882a593Smuzhiyun return -EINVAL;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun sidle_shift = oh->class->sysc->sysc_fields->sidle_shift;
381*4882a593Smuzhiyun sidle_mask = (0x3 << sidle_shift);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun *v &= ~sidle_mask;
384*4882a593Smuzhiyun *v |= __ffs(idlemode) << sidle_shift;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun return 0;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun /**
390*4882a593Smuzhiyun * _set_clockactivity: set OCP_SYSCONFIG.CLOCKACTIVITY bits in @v
391*4882a593Smuzhiyun * @oh: struct omap_hwmod *
392*4882a593Smuzhiyun * @clockact: CLOCKACTIVITY field bits
393*4882a593Smuzhiyun * @v: pointer to register contents to modify
394*4882a593Smuzhiyun *
395*4882a593Smuzhiyun * Update the clockactivity mode bits in @v to be @clockact for the
396*4882a593Smuzhiyun * @oh hwmod. Used for additional powersaving on some modules. Does
397*4882a593Smuzhiyun * not write to the hardware. Returns -EINVAL upon error or 0 upon
398*4882a593Smuzhiyun * success.
399*4882a593Smuzhiyun */
_set_clockactivity(struct omap_hwmod * oh,u8 clockact,u32 * v)400*4882a593Smuzhiyun static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun u32 clkact_mask;
403*4882a593Smuzhiyun u8 clkact_shift;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun if (!oh->class->sysc ||
406*4882a593Smuzhiyun !(oh->class->sysc->sysc_flags & SYSC_HAS_CLOCKACTIVITY))
407*4882a593Smuzhiyun return -EINVAL;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun if (!oh->class->sysc->sysc_fields) {
410*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
411*4882a593Smuzhiyun return -EINVAL;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun clkact_shift = oh->class->sysc->sysc_fields->clkact_shift;
415*4882a593Smuzhiyun clkact_mask = (0x3 << clkact_shift);
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun *v &= ~clkact_mask;
418*4882a593Smuzhiyun *v |= clockact << clkact_shift;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun return 0;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun /**
424*4882a593Smuzhiyun * _set_softreset: set OCP_SYSCONFIG.SOFTRESET bit in @v
425*4882a593Smuzhiyun * @oh: struct omap_hwmod *
426*4882a593Smuzhiyun * @v: pointer to register contents to modify
427*4882a593Smuzhiyun *
428*4882a593Smuzhiyun * Set the SOFTRESET bit in @v for hwmod @oh. Returns -EINVAL upon
429*4882a593Smuzhiyun * error or 0 upon success.
430*4882a593Smuzhiyun */
_set_softreset(struct omap_hwmod * oh,u32 * v)431*4882a593Smuzhiyun static int _set_softreset(struct omap_hwmod *oh, u32 *v)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun u32 softrst_mask;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun if (!oh->class->sysc ||
436*4882a593Smuzhiyun !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
437*4882a593Smuzhiyun return -EINVAL;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun if (!oh->class->sysc->sysc_fields) {
440*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
441*4882a593Smuzhiyun return -EINVAL;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun softrst_mask = (0x1 << oh->class->sysc->sysc_fields->srst_shift);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun *v |= softrst_mask;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun return 0;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /**
452*4882a593Smuzhiyun * _clear_softreset: clear OCP_SYSCONFIG.SOFTRESET bit in @v
453*4882a593Smuzhiyun * @oh: struct omap_hwmod *
454*4882a593Smuzhiyun * @v: pointer to register contents to modify
455*4882a593Smuzhiyun *
456*4882a593Smuzhiyun * Clear the SOFTRESET bit in @v for hwmod @oh. Returns -EINVAL upon
457*4882a593Smuzhiyun * error or 0 upon success.
458*4882a593Smuzhiyun */
_clear_softreset(struct omap_hwmod * oh,u32 * v)459*4882a593Smuzhiyun static int _clear_softreset(struct omap_hwmod *oh, u32 *v)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun u32 softrst_mask;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun if (!oh->class->sysc ||
464*4882a593Smuzhiyun !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
465*4882a593Smuzhiyun return -EINVAL;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun if (!oh->class->sysc->sysc_fields) {
468*4882a593Smuzhiyun WARN(1,
469*4882a593Smuzhiyun "omap_hwmod: %s: sysc_fields absent for sysconfig class\n",
470*4882a593Smuzhiyun oh->name);
471*4882a593Smuzhiyun return -EINVAL;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun softrst_mask = (0x1 << oh->class->sysc->sysc_fields->srst_shift);
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun *v &= ~softrst_mask;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun return 0;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun /**
482*4882a593Smuzhiyun * _wait_softreset_complete - wait for an OCP softreset to complete
483*4882a593Smuzhiyun * @oh: struct omap_hwmod * to wait on
484*4882a593Smuzhiyun *
485*4882a593Smuzhiyun * Wait until the IP block represented by @oh reports that its OCP
486*4882a593Smuzhiyun * softreset is complete. This can be triggered by software (see
487*4882a593Smuzhiyun * _ocp_softreset()) or by hardware upon returning from off-mode (one
488*4882a593Smuzhiyun * example is HSMMC). Waits for up to MAX_MODULE_SOFTRESET_WAIT
489*4882a593Smuzhiyun * microseconds. Returns the number of microseconds waited.
490*4882a593Smuzhiyun */
_wait_softreset_complete(struct omap_hwmod * oh)491*4882a593Smuzhiyun static int _wait_softreset_complete(struct omap_hwmod *oh)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun struct omap_hwmod_class_sysconfig *sysc;
494*4882a593Smuzhiyun u32 softrst_mask;
495*4882a593Smuzhiyun int c = 0;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun sysc = oh->class->sysc;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun if (sysc->sysc_flags & SYSS_HAS_RESET_STATUS && sysc->syss_offs > 0)
500*4882a593Smuzhiyun omap_test_timeout((omap_hwmod_read(oh, sysc->syss_offs)
501*4882a593Smuzhiyun & SYSS_RESETDONE_MASK),
502*4882a593Smuzhiyun MAX_MODULE_SOFTRESET_WAIT, c);
503*4882a593Smuzhiyun else if (sysc->sysc_flags & SYSC_HAS_RESET_STATUS) {
504*4882a593Smuzhiyun softrst_mask = (0x1 << sysc->sysc_fields->srst_shift);
505*4882a593Smuzhiyun omap_test_timeout(!(omap_hwmod_read(oh, sysc->sysc_offs)
506*4882a593Smuzhiyun & softrst_mask),
507*4882a593Smuzhiyun MAX_MODULE_SOFTRESET_WAIT, c);
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun return c;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun /**
514*4882a593Smuzhiyun * _set_dmadisable: set OCP_SYSCONFIG.DMADISABLE bit in @v
515*4882a593Smuzhiyun * @oh: struct omap_hwmod *
516*4882a593Smuzhiyun *
517*4882a593Smuzhiyun * The DMADISABLE bit is a semi-automatic bit present in sysconfig register
518*4882a593Smuzhiyun * of some modules. When the DMA must perform read/write accesses, the
519*4882a593Smuzhiyun * DMADISABLE bit is cleared by the hardware. But when the DMA must stop
520*4882a593Smuzhiyun * for power management, software must set the DMADISABLE bit back to 1.
521*4882a593Smuzhiyun *
522*4882a593Smuzhiyun * Set the DMADISABLE bit in @v for hwmod @oh. Returns -EINVAL upon
523*4882a593Smuzhiyun * error or 0 upon success.
524*4882a593Smuzhiyun */
_set_dmadisable(struct omap_hwmod * oh)525*4882a593Smuzhiyun static int _set_dmadisable(struct omap_hwmod *oh)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun u32 v;
528*4882a593Smuzhiyun u32 dmadisable_mask;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun if (!oh->class->sysc ||
531*4882a593Smuzhiyun !(oh->class->sysc->sysc_flags & SYSC_HAS_DMADISABLE))
532*4882a593Smuzhiyun return -EINVAL;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun if (!oh->class->sysc->sysc_fields) {
535*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
536*4882a593Smuzhiyun return -EINVAL;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun /* clocks must be on for this operation */
540*4882a593Smuzhiyun if (oh->_state != _HWMOD_STATE_ENABLED) {
541*4882a593Smuzhiyun pr_warn("omap_hwmod: %s: dma can be disabled only from enabled state\n", oh->name);
542*4882a593Smuzhiyun return -EINVAL;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: setting DMADISABLE\n", oh->name);
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun v = oh->_sysc_cache;
548*4882a593Smuzhiyun dmadisable_mask =
549*4882a593Smuzhiyun (0x1 << oh->class->sysc->sysc_fields->dmadisable_shift);
550*4882a593Smuzhiyun v |= dmadisable_mask;
551*4882a593Smuzhiyun _write_sysconfig(v, oh);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun return 0;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun /**
557*4882a593Smuzhiyun * _set_module_autoidle: set the OCP_SYSCONFIG AUTOIDLE field in @v
558*4882a593Smuzhiyun * @oh: struct omap_hwmod *
559*4882a593Smuzhiyun * @autoidle: desired AUTOIDLE bitfield value (0 or 1)
560*4882a593Smuzhiyun * @v: pointer to register contents to modify
561*4882a593Smuzhiyun *
562*4882a593Smuzhiyun * Update the module autoidle bit in @v to be @autoidle for the @oh
563*4882a593Smuzhiyun * hwmod. The autoidle bit controls whether the module can gate
564*4882a593Smuzhiyun * internal clocks automatically when it isn't doing anything; the
565*4882a593Smuzhiyun * exact function of this bit varies on a per-module basis. This
566*4882a593Smuzhiyun * function does not write to the hardware. Returns -EINVAL upon
567*4882a593Smuzhiyun * error or 0 upon success.
568*4882a593Smuzhiyun */
_set_module_autoidle(struct omap_hwmod * oh,u8 autoidle,u32 * v)569*4882a593Smuzhiyun static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
570*4882a593Smuzhiyun u32 *v)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun u32 autoidle_mask;
573*4882a593Smuzhiyun u8 autoidle_shift;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun if (!oh->class->sysc ||
576*4882a593Smuzhiyun !(oh->class->sysc->sysc_flags & SYSC_HAS_AUTOIDLE))
577*4882a593Smuzhiyun return -EINVAL;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun if (!oh->class->sysc->sysc_fields) {
580*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
581*4882a593Smuzhiyun return -EINVAL;
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun autoidle_shift = oh->class->sysc->sysc_fields->autoidle_shift;
585*4882a593Smuzhiyun autoidle_mask = (0x1 << autoidle_shift);
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun *v &= ~autoidle_mask;
588*4882a593Smuzhiyun *v |= autoidle << autoidle_shift;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun return 0;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun /**
594*4882a593Smuzhiyun * _enable_wakeup: set OCP_SYSCONFIG.ENAWAKEUP bit in the hardware
595*4882a593Smuzhiyun * @oh: struct omap_hwmod *
596*4882a593Smuzhiyun *
597*4882a593Smuzhiyun * Allow the hardware module @oh to send wakeups. Returns -EINVAL
598*4882a593Smuzhiyun * upon error or 0 upon success.
599*4882a593Smuzhiyun */
_enable_wakeup(struct omap_hwmod * oh,u32 * v)600*4882a593Smuzhiyun static int _enable_wakeup(struct omap_hwmod *oh, u32 *v)
601*4882a593Smuzhiyun {
602*4882a593Smuzhiyun if (!oh->class->sysc ||
603*4882a593Smuzhiyun !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) ||
604*4882a593Smuzhiyun (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) ||
605*4882a593Smuzhiyun (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)))
606*4882a593Smuzhiyun return -EINVAL;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun if (!oh->class->sysc->sysc_fields) {
609*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
610*4882a593Smuzhiyun return -EINVAL;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)
614*4882a593Smuzhiyun *v |= 0x1 << oh->class->sysc->sysc_fields->enwkup_shift;
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
617*4882a593Smuzhiyun _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v);
618*4882a593Smuzhiyun if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
619*4882a593Smuzhiyun _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v);
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun /* XXX test pwrdm_get_wken for this hwmod's subsystem */
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun return 0;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun
_get_clkdm(struct omap_hwmod * oh)626*4882a593Smuzhiyun static struct clockdomain *_get_clkdm(struct omap_hwmod *oh)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun struct clk_hw_omap *clk;
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun if (oh->clkdm) {
631*4882a593Smuzhiyun return oh->clkdm;
632*4882a593Smuzhiyun } else if (oh->_clk) {
633*4882a593Smuzhiyun if (!omap2_clk_is_hw_omap(__clk_get_hw(oh->_clk)))
634*4882a593Smuzhiyun return NULL;
635*4882a593Smuzhiyun clk = to_clk_hw_omap(__clk_get_hw(oh->_clk));
636*4882a593Smuzhiyun return clk->clkdm;
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun return NULL;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun /**
642*4882a593Smuzhiyun * _add_initiator_dep: prevent @oh from smart-idling while @init_oh is active
643*4882a593Smuzhiyun * @oh: struct omap_hwmod *
644*4882a593Smuzhiyun *
645*4882a593Smuzhiyun * Prevent the hardware module @oh from entering idle while the
646*4882a593Smuzhiyun * hardare module initiator @init_oh is active. Useful when a module
647*4882a593Smuzhiyun * will be accessed by a particular initiator (e.g., if a module will
648*4882a593Smuzhiyun * be accessed by the IVA, there should be a sleepdep between the IVA
649*4882a593Smuzhiyun * initiator and the module). Only applies to modules in smart-idle
650*4882a593Smuzhiyun * mode. If the clockdomain is marked as not needing autodeps, return
651*4882a593Smuzhiyun * 0 without doing anything. Otherwise, returns -EINVAL upon error or
652*4882a593Smuzhiyun * passes along clkdm_add_sleepdep() value upon success.
653*4882a593Smuzhiyun */
_add_initiator_dep(struct omap_hwmod * oh,struct omap_hwmod * init_oh)654*4882a593Smuzhiyun static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun struct clockdomain *clkdm, *init_clkdm;
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun clkdm = _get_clkdm(oh);
659*4882a593Smuzhiyun init_clkdm = _get_clkdm(init_oh);
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun if (!clkdm || !init_clkdm)
662*4882a593Smuzhiyun return -EINVAL;
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun if (clkdm && clkdm->flags & CLKDM_NO_AUTODEPS)
665*4882a593Smuzhiyun return 0;
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun return clkdm_add_sleepdep(clkdm, init_clkdm);
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun /**
671*4882a593Smuzhiyun * _del_initiator_dep: allow @oh to smart-idle even if @init_oh is active
672*4882a593Smuzhiyun * @oh: struct omap_hwmod *
673*4882a593Smuzhiyun *
674*4882a593Smuzhiyun * Allow the hardware module @oh to enter idle while the hardare
675*4882a593Smuzhiyun * module initiator @init_oh is active. Useful when a module will not
676*4882a593Smuzhiyun * be accessed by a particular initiator (e.g., if a module will not
677*4882a593Smuzhiyun * be accessed by the IVA, there should be no sleepdep between the IVA
678*4882a593Smuzhiyun * initiator and the module). Only applies to modules in smart-idle
679*4882a593Smuzhiyun * mode. If the clockdomain is marked as not needing autodeps, return
680*4882a593Smuzhiyun * 0 without doing anything. Returns -EINVAL upon error or passes
681*4882a593Smuzhiyun * along clkdm_del_sleepdep() value upon success.
682*4882a593Smuzhiyun */
_del_initiator_dep(struct omap_hwmod * oh,struct omap_hwmod * init_oh)683*4882a593Smuzhiyun static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh)
684*4882a593Smuzhiyun {
685*4882a593Smuzhiyun struct clockdomain *clkdm, *init_clkdm;
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun clkdm = _get_clkdm(oh);
688*4882a593Smuzhiyun init_clkdm = _get_clkdm(init_oh);
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun if (!clkdm || !init_clkdm)
691*4882a593Smuzhiyun return -EINVAL;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun if (clkdm && clkdm->flags & CLKDM_NO_AUTODEPS)
694*4882a593Smuzhiyun return 0;
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun return clkdm_del_sleepdep(clkdm, init_clkdm);
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun static const struct of_device_id ti_clkctrl_match_table[] __initconst = {
700*4882a593Smuzhiyun { .compatible = "ti,clkctrl" },
701*4882a593Smuzhiyun { }
702*4882a593Smuzhiyun };
703*4882a593Smuzhiyun
_setup_clkctrl_provider(struct device_node * np)704*4882a593Smuzhiyun static int __init _setup_clkctrl_provider(struct device_node *np)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun const __be32 *addrp;
707*4882a593Smuzhiyun struct clkctrl_provider *provider;
708*4882a593Smuzhiyun u64 size;
709*4882a593Smuzhiyun int i;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun provider = memblock_alloc(sizeof(*provider), SMP_CACHE_BYTES);
712*4882a593Smuzhiyun if (!provider)
713*4882a593Smuzhiyun return -ENOMEM;
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun provider->node = np;
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun provider->num_addrs =
718*4882a593Smuzhiyun of_property_count_elems_of_size(np, "reg", sizeof(u32)) / 2;
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun provider->addr =
721*4882a593Smuzhiyun memblock_alloc(sizeof(void *) * provider->num_addrs,
722*4882a593Smuzhiyun SMP_CACHE_BYTES);
723*4882a593Smuzhiyun if (!provider->addr)
724*4882a593Smuzhiyun return -ENOMEM;
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun provider->size =
727*4882a593Smuzhiyun memblock_alloc(sizeof(u32) * provider->num_addrs,
728*4882a593Smuzhiyun SMP_CACHE_BYTES);
729*4882a593Smuzhiyun if (!provider->size)
730*4882a593Smuzhiyun return -ENOMEM;
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun for (i = 0; i < provider->num_addrs; i++) {
733*4882a593Smuzhiyun addrp = of_get_address(np, i, &size, NULL);
734*4882a593Smuzhiyun provider->addr[i] = (u32)of_translate_address(np, addrp);
735*4882a593Smuzhiyun provider->size[i] = size;
736*4882a593Smuzhiyun pr_debug("%s: %pOF: %x...%x\n", __func__, np, provider->addr[i],
737*4882a593Smuzhiyun provider->addr[i] + provider->size[i]);
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun list_add(&provider->link, &clkctrl_providers);
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun return 0;
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun
_init_clkctrl_providers(void)745*4882a593Smuzhiyun static int __init _init_clkctrl_providers(void)
746*4882a593Smuzhiyun {
747*4882a593Smuzhiyun struct device_node *np;
748*4882a593Smuzhiyun int ret = 0;
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun for_each_matching_node(np, ti_clkctrl_match_table) {
751*4882a593Smuzhiyun ret = _setup_clkctrl_provider(np);
752*4882a593Smuzhiyun if (ret) {
753*4882a593Smuzhiyun of_node_put(np);
754*4882a593Smuzhiyun break;
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun return ret;
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun
_omap4_xlate_clkctrl(struct omap_hwmod * oh)761*4882a593Smuzhiyun static u32 _omap4_xlate_clkctrl(struct omap_hwmod *oh)
762*4882a593Smuzhiyun {
763*4882a593Smuzhiyun if (!oh->prcm.omap4.modulemode)
764*4882a593Smuzhiyun return 0;
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun return omap_cm_xlate_clkctrl(oh->clkdm->prcm_partition,
767*4882a593Smuzhiyun oh->clkdm->cm_inst,
768*4882a593Smuzhiyun oh->prcm.omap4.clkctrl_offs);
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun
_lookup_clkctrl_clk(struct omap_hwmod * oh)771*4882a593Smuzhiyun static struct clk *_lookup_clkctrl_clk(struct omap_hwmod *oh)
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun struct clkctrl_provider *provider;
774*4882a593Smuzhiyun struct clk *clk;
775*4882a593Smuzhiyun u32 addr;
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun if (!soc_ops.xlate_clkctrl)
778*4882a593Smuzhiyun return NULL;
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun addr = soc_ops.xlate_clkctrl(oh);
781*4882a593Smuzhiyun if (!addr)
782*4882a593Smuzhiyun return NULL;
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun pr_debug("%s: %s: addr=%x\n", __func__, oh->name, addr);
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun list_for_each_entry(provider, &clkctrl_providers, link) {
787*4882a593Smuzhiyun int i;
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun for (i = 0; i < provider->num_addrs; i++) {
790*4882a593Smuzhiyun if (provider->addr[i] <= addr &&
791*4882a593Smuzhiyun provider->addr[i] + provider->size[i] > addr) {
792*4882a593Smuzhiyun struct of_phandle_args clkspec;
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun clkspec.np = provider->node;
795*4882a593Smuzhiyun clkspec.args_count = 2;
796*4882a593Smuzhiyun clkspec.args[0] = addr - provider->addr[0];
797*4882a593Smuzhiyun clkspec.args[1] = 0;
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun clk = of_clk_get_from_provider(&clkspec);
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun pr_debug("%s: %s got %p (offset=%x, provider=%pOF)\n",
802*4882a593Smuzhiyun __func__, oh->name, clk,
803*4882a593Smuzhiyun clkspec.args[0], provider->node);
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun return clk;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun return NULL;
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun /**
814*4882a593Smuzhiyun * _init_main_clk - get a struct clk * for the the hwmod's main functional clk
815*4882a593Smuzhiyun * @oh: struct omap_hwmod *
816*4882a593Smuzhiyun *
817*4882a593Smuzhiyun * Called from _init_clocks(). Populates the @oh _clk (main
818*4882a593Smuzhiyun * functional clock pointer) if a clock matching the hwmod name is found,
819*4882a593Smuzhiyun * or a main_clk is present. Returns 0 on success or -EINVAL on error.
820*4882a593Smuzhiyun */
_init_main_clk(struct omap_hwmod * oh)821*4882a593Smuzhiyun static int _init_main_clk(struct omap_hwmod *oh)
822*4882a593Smuzhiyun {
823*4882a593Smuzhiyun int ret = 0;
824*4882a593Smuzhiyun struct clk *clk = NULL;
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun clk = _lookup_clkctrl_clk(oh);
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun if (!IS_ERR_OR_NULL(clk)) {
829*4882a593Smuzhiyun pr_debug("%s: mapped main_clk %s for %s\n", __func__,
830*4882a593Smuzhiyun __clk_get_name(clk), oh->name);
831*4882a593Smuzhiyun oh->main_clk = __clk_get_name(clk);
832*4882a593Smuzhiyun oh->_clk = clk;
833*4882a593Smuzhiyun soc_ops.disable_direct_prcm(oh);
834*4882a593Smuzhiyun } else {
835*4882a593Smuzhiyun if (!oh->main_clk)
836*4882a593Smuzhiyun return 0;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun oh->_clk = clk_get(NULL, oh->main_clk);
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun if (IS_ERR(oh->_clk)) {
842*4882a593Smuzhiyun pr_warn("omap_hwmod: %s: cannot clk_get main_clk %s\n",
843*4882a593Smuzhiyun oh->name, oh->main_clk);
844*4882a593Smuzhiyun return -EINVAL;
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun /*
847*4882a593Smuzhiyun * HACK: This needs a re-visit once clk_prepare() is implemented
848*4882a593Smuzhiyun * to do something meaningful. Today its just a no-op.
849*4882a593Smuzhiyun * If clk_prepare() is used at some point to do things like
850*4882a593Smuzhiyun * voltage scaling etc, then this would have to be moved to
851*4882a593Smuzhiyun * some point where subsystems like i2c and pmic become
852*4882a593Smuzhiyun * available.
853*4882a593Smuzhiyun */
854*4882a593Smuzhiyun clk_prepare(oh->_clk);
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun if (!_get_clkdm(oh))
857*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: missing clockdomain for %s.\n",
858*4882a593Smuzhiyun oh->name, oh->main_clk);
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun return ret;
861*4882a593Smuzhiyun }
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun /**
864*4882a593Smuzhiyun * _init_interface_clks - get a struct clk * for the the hwmod's interface clks
865*4882a593Smuzhiyun * @oh: struct omap_hwmod *
866*4882a593Smuzhiyun *
867*4882a593Smuzhiyun * Called from _init_clocks(). Populates the @oh OCP slave interface
868*4882a593Smuzhiyun * clock pointers. Returns 0 on success or -EINVAL on error.
869*4882a593Smuzhiyun */
_init_interface_clks(struct omap_hwmod * oh)870*4882a593Smuzhiyun static int _init_interface_clks(struct omap_hwmod *oh)
871*4882a593Smuzhiyun {
872*4882a593Smuzhiyun struct omap_hwmod_ocp_if *os;
873*4882a593Smuzhiyun struct clk *c;
874*4882a593Smuzhiyun int ret = 0;
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun list_for_each_entry(os, &oh->slave_ports, node) {
877*4882a593Smuzhiyun if (!os->clk)
878*4882a593Smuzhiyun continue;
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun c = clk_get(NULL, os->clk);
881*4882a593Smuzhiyun if (IS_ERR(c)) {
882*4882a593Smuzhiyun pr_warn("omap_hwmod: %s: cannot clk_get interface_clk %s\n",
883*4882a593Smuzhiyun oh->name, os->clk);
884*4882a593Smuzhiyun ret = -EINVAL;
885*4882a593Smuzhiyun continue;
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun os->_clk = c;
888*4882a593Smuzhiyun /*
889*4882a593Smuzhiyun * HACK: This needs a re-visit once clk_prepare() is implemented
890*4882a593Smuzhiyun * to do something meaningful. Today its just a no-op.
891*4882a593Smuzhiyun * If clk_prepare() is used at some point to do things like
892*4882a593Smuzhiyun * voltage scaling etc, then this would have to be moved to
893*4882a593Smuzhiyun * some point where subsystems like i2c and pmic become
894*4882a593Smuzhiyun * available.
895*4882a593Smuzhiyun */
896*4882a593Smuzhiyun clk_prepare(os->_clk);
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun return ret;
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun /**
903*4882a593Smuzhiyun * _init_opt_clk - get a struct clk * for the the hwmod's optional clocks
904*4882a593Smuzhiyun * @oh: struct omap_hwmod *
905*4882a593Smuzhiyun *
906*4882a593Smuzhiyun * Called from _init_clocks(). Populates the @oh omap_hwmod_opt_clk
907*4882a593Smuzhiyun * clock pointers. Returns 0 on success or -EINVAL on error.
908*4882a593Smuzhiyun */
_init_opt_clks(struct omap_hwmod * oh)909*4882a593Smuzhiyun static int _init_opt_clks(struct omap_hwmod *oh)
910*4882a593Smuzhiyun {
911*4882a593Smuzhiyun struct omap_hwmod_opt_clk *oc;
912*4882a593Smuzhiyun struct clk *c;
913*4882a593Smuzhiyun int i;
914*4882a593Smuzhiyun int ret = 0;
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) {
917*4882a593Smuzhiyun c = clk_get(NULL, oc->clk);
918*4882a593Smuzhiyun if (IS_ERR(c)) {
919*4882a593Smuzhiyun pr_warn("omap_hwmod: %s: cannot clk_get opt_clk %s\n",
920*4882a593Smuzhiyun oh->name, oc->clk);
921*4882a593Smuzhiyun ret = -EINVAL;
922*4882a593Smuzhiyun continue;
923*4882a593Smuzhiyun }
924*4882a593Smuzhiyun oc->_clk = c;
925*4882a593Smuzhiyun /*
926*4882a593Smuzhiyun * HACK: This needs a re-visit once clk_prepare() is implemented
927*4882a593Smuzhiyun * to do something meaningful. Today its just a no-op.
928*4882a593Smuzhiyun * If clk_prepare() is used at some point to do things like
929*4882a593Smuzhiyun * voltage scaling etc, then this would have to be moved to
930*4882a593Smuzhiyun * some point where subsystems like i2c and pmic become
931*4882a593Smuzhiyun * available.
932*4882a593Smuzhiyun */
933*4882a593Smuzhiyun clk_prepare(oc->_clk);
934*4882a593Smuzhiyun }
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun return ret;
937*4882a593Smuzhiyun }
938*4882a593Smuzhiyun
_enable_optional_clocks(struct omap_hwmod * oh)939*4882a593Smuzhiyun static void _enable_optional_clocks(struct omap_hwmod *oh)
940*4882a593Smuzhiyun {
941*4882a593Smuzhiyun struct omap_hwmod_opt_clk *oc;
942*4882a593Smuzhiyun int i;
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name);
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
947*4882a593Smuzhiyun if (oc->_clk) {
948*4882a593Smuzhiyun pr_debug("omap_hwmod: enable %s:%s\n", oc->role,
949*4882a593Smuzhiyun __clk_get_name(oc->_clk));
950*4882a593Smuzhiyun clk_enable(oc->_clk);
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun
_disable_optional_clocks(struct omap_hwmod * oh)954*4882a593Smuzhiyun static void _disable_optional_clocks(struct omap_hwmod *oh)
955*4882a593Smuzhiyun {
956*4882a593Smuzhiyun struct omap_hwmod_opt_clk *oc;
957*4882a593Smuzhiyun int i;
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name);
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
962*4882a593Smuzhiyun if (oc->_clk) {
963*4882a593Smuzhiyun pr_debug("omap_hwmod: disable %s:%s\n", oc->role,
964*4882a593Smuzhiyun __clk_get_name(oc->_clk));
965*4882a593Smuzhiyun clk_disable(oc->_clk);
966*4882a593Smuzhiyun }
967*4882a593Smuzhiyun }
968*4882a593Smuzhiyun
969*4882a593Smuzhiyun /**
970*4882a593Smuzhiyun * _enable_clocks - enable hwmod main clock and interface clocks
971*4882a593Smuzhiyun * @oh: struct omap_hwmod *
972*4882a593Smuzhiyun *
973*4882a593Smuzhiyun * Enables all clocks necessary for register reads and writes to succeed
974*4882a593Smuzhiyun * on the hwmod @oh. Returns 0.
975*4882a593Smuzhiyun */
_enable_clocks(struct omap_hwmod * oh)976*4882a593Smuzhiyun static int _enable_clocks(struct omap_hwmod *oh)
977*4882a593Smuzhiyun {
978*4882a593Smuzhiyun struct omap_hwmod_ocp_if *os;
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name);
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
983*4882a593Smuzhiyun _enable_optional_clocks(oh);
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun if (oh->_clk)
986*4882a593Smuzhiyun clk_enable(oh->_clk);
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun list_for_each_entry(os, &oh->slave_ports, node) {
989*4882a593Smuzhiyun if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) {
990*4882a593Smuzhiyun omap2_clk_deny_idle(os->_clk);
991*4882a593Smuzhiyun clk_enable(os->_clk);
992*4882a593Smuzhiyun }
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun /* The opt clocks are controlled by the device driver. */
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun return 0;
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun /**
1001*4882a593Smuzhiyun * _omap4_clkctrl_managed_by_clkfwk - true if clkctrl managed by clock framework
1002*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1003*4882a593Smuzhiyun */
_omap4_clkctrl_managed_by_clkfwk(struct omap_hwmod * oh)1004*4882a593Smuzhiyun static bool _omap4_clkctrl_managed_by_clkfwk(struct omap_hwmod *oh)
1005*4882a593Smuzhiyun {
1006*4882a593Smuzhiyun if (oh->prcm.omap4.flags & HWMOD_OMAP4_CLKFWK_CLKCTR_CLOCK)
1007*4882a593Smuzhiyun return true;
1008*4882a593Smuzhiyun
1009*4882a593Smuzhiyun return false;
1010*4882a593Smuzhiyun }
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun /**
1013*4882a593Smuzhiyun * _omap4_has_clkctrl_clock - returns true if a module has clkctrl clock
1014*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1015*4882a593Smuzhiyun */
_omap4_has_clkctrl_clock(struct omap_hwmod * oh)1016*4882a593Smuzhiyun static bool _omap4_has_clkctrl_clock(struct omap_hwmod *oh)
1017*4882a593Smuzhiyun {
1018*4882a593Smuzhiyun if (oh->prcm.omap4.clkctrl_offs)
1019*4882a593Smuzhiyun return true;
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun if (!oh->prcm.omap4.clkctrl_offs &&
1022*4882a593Smuzhiyun oh->prcm.omap4.flags & HWMOD_OMAP4_ZERO_CLKCTRL_OFFSET)
1023*4882a593Smuzhiyun return true;
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun return false;
1026*4882a593Smuzhiyun }
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun /**
1029*4882a593Smuzhiyun * _disable_clocks - disable hwmod main clock and interface clocks
1030*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1031*4882a593Smuzhiyun *
1032*4882a593Smuzhiyun * Disables the hwmod @oh main functional and interface clocks. Returns 0.
1033*4882a593Smuzhiyun */
_disable_clocks(struct omap_hwmod * oh)1034*4882a593Smuzhiyun static int _disable_clocks(struct omap_hwmod *oh)
1035*4882a593Smuzhiyun {
1036*4882a593Smuzhiyun struct omap_hwmod_ocp_if *os;
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name);
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun if (oh->_clk)
1041*4882a593Smuzhiyun clk_disable(oh->_clk);
1042*4882a593Smuzhiyun
1043*4882a593Smuzhiyun list_for_each_entry(os, &oh->slave_ports, node) {
1044*4882a593Smuzhiyun if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) {
1045*4882a593Smuzhiyun clk_disable(os->_clk);
1046*4882a593Smuzhiyun omap2_clk_allow_idle(os->_clk);
1047*4882a593Smuzhiyun }
1048*4882a593Smuzhiyun }
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
1051*4882a593Smuzhiyun _disable_optional_clocks(oh);
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun /* The opt clocks are controlled by the device driver. */
1054*4882a593Smuzhiyun
1055*4882a593Smuzhiyun return 0;
1056*4882a593Smuzhiyun }
1057*4882a593Smuzhiyun
1058*4882a593Smuzhiyun /**
1059*4882a593Smuzhiyun * _omap4_enable_module - enable CLKCTRL modulemode on OMAP4
1060*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1061*4882a593Smuzhiyun *
1062*4882a593Smuzhiyun * Enables the PRCM module mode related to the hwmod @oh.
1063*4882a593Smuzhiyun * No return value.
1064*4882a593Smuzhiyun */
_omap4_enable_module(struct omap_hwmod * oh)1065*4882a593Smuzhiyun static void _omap4_enable_module(struct omap_hwmod *oh)
1066*4882a593Smuzhiyun {
1067*4882a593Smuzhiyun if (!oh->clkdm || !oh->prcm.omap4.modulemode ||
1068*4882a593Smuzhiyun _omap4_clkctrl_managed_by_clkfwk(oh))
1069*4882a593Smuzhiyun return;
1070*4882a593Smuzhiyun
1071*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: %s: %d\n",
1072*4882a593Smuzhiyun oh->name, __func__, oh->prcm.omap4.modulemode);
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun omap_cm_module_enable(oh->prcm.omap4.modulemode,
1075*4882a593Smuzhiyun oh->clkdm->prcm_partition,
1076*4882a593Smuzhiyun oh->clkdm->cm_inst, oh->prcm.omap4.clkctrl_offs);
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun /**
1080*4882a593Smuzhiyun * _omap4_wait_target_disable - wait for a module to be disabled on OMAP4
1081*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1082*4882a593Smuzhiyun *
1083*4882a593Smuzhiyun * Wait for a module @oh to enter slave idle. Returns 0 if the module
1084*4882a593Smuzhiyun * does not have an IDLEST bit or if the module successfully enters
1085*4882a593Smuzhiyun * slave idle; otherwise, pass along the return value of the
1086*4882a593Smuzhiyun * appropriate *_cm*_wait_module_idle() function.
1087*4882a593Smuzhiyun */
_omap4_wait_target_disable(struct omap_hwmod * oh)1088*4882a593Smuzhiyun static int _omap4_wait_target_disable(struct omap_hwmod *oh)
1089*4882a593Smuzhiyun {
1090*4882a593Smuzhiyun if (!oh)
1091*4882a593Smuzhiyun return -EINVAL;
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun if (oh->_int_flags & _HWMOD_NO_MPU_PORT || !oh->clkdm)
1094*4882a593Smuzhiyun return 0;
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun if (oh->flags & HWMOD_NO_IDLEST)
1097*4882a593Smuzhiyun return 0;
1098*4882a593Smuzhiyun
1099*4882a593Smuzhiyun if (_omap4_clkctrl_managed_by_clkfwk(oh))
1100*4882a593Smuzhiyun return 0;
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun if (!_omap4_has_clkctrl_clock(oh))
1103*4882a593Smuzhiyun return 0;
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun return omap_cm_wait_module_idle(oh->clkdm->prcm_partition,
1106*4882a593Smuzhiyun oh->clkdm->cm_inst,
1107*4882a593Smuzhiyun oh->prcm.omap4.clkctrl_offs, 0);
1108*4882a593Smuzhiyun }
1109*4882a593Smuzhiyun
1110*4882a593Smuzhiyun /**
1111*4882a593Smuzhiyun * _save_mpu_port_index - find and save the index to @oh's MPU port
1112*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1113*4882a593Smuzhiyun *
1114*4882a593Smuzhiyun * Determines the array index of the OCP slave port that the MPU uses
1115*4882a593Smuzhiyun * to address the device, and saves it into the struct omap_hwmod.
1116*4882a593Smuzhiyun * Intended to be called during hwmod registration only. No return
1117*4882a593Smuzhiyun * value.
1118*4882a593Smuzhiyun */
_save_mpu_port_index(struct omap_hwmod * oh)1119*4882a593Smuzhiyun static void __init _save_mpu_port_index(struct omap_hwmod *oh)
1120*4882a593Smuzhiyun {
1121*4882a593Smuzhiyun struct omap_hwmod_ocp_if *os = NULL;
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun if (!oh)
1124*4882a593Smuzhiyun return;
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun oh->_int_flags |= _HWMOD_NO_MPU_PORT;
1127*4882a593Smuzhiyun
1128*4882a593Smuzhiyun list_for_each_entry(os, &oh->slave_ports, node) {
1129*4882a593Smuzhiyun if (os->user & OCP_USER_MPU) {
1130*4882a593Smuzhiyun oh->_mpu_port = os;
1131*4882a593Smuzhiyun oh->_int_flags &= ~_HWMOD_NO_MPU_PORT;
1132*4882a593Smuzhiyun break;
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun }
1135*4882a593Smuzhiyun
1136*4882a593Smuzhiyun return;
1137*4882a593Smuzhiyun }
1138*4882a593Smuzhiyun
1139*4882a593Smuzhiyun /**
1140*4882a593Smuzhiyun * _find_mpu_rt_port - return omap_hwmod_ocp_if accessible by the MPU
1141*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1142*4882a593Smuzhiyun *
1143*4882a593Smuzhiyun * Given a pointer to a struct omap_hwmod record @oh, return a pointer
1144*4882a593Smuzhiyun * to the struct omap_hwmod_ocp_if record that is used by the MPU to
1145*4882a593Smuzhiyun * communicate with the IP block. This interface need not be directly
1146*4882a593Smuzhiyun * connected to the MPU (and almost certainly is not), but is directly
1147*4882a593Smuzhiyun * connected to the IP block represented by @oh. Returns a pointer
1148*4882a593Smuzhiyun * to the struct omap_hwmod_ocp_if * upon success, or returns NULL upon
1149*4882a593Smuzhiyun * error or if there does not appear to be a path from the MPU to this
1150*4882a593Smuzhiyun * IP block.
1151*4882a593Smuzhiyun */
_find_mpu_rt_port(struct omap_hwmod * oh)1152*4882a593Smuzhiyun static struct omap_hwmod_ocp_if *_find_mpu_rt_port(struct omap_hwmod *oh)
1153*4882a593Smuzhiyun {
1154*4882a593Smuzhiyun if (!oh || oh->_int_flags & _HWMOD_NO_MPU_PORT || oh->slaves_cnt == 0)
1155*4882a593Smuzhiyun return NULL;
1156*4882a593Smuzhiyun
1157*4882a593Smuzhiyun return oh->_mpu_port;
1158*4882a593Smuzhiyun };
1159*4882a593Smuzhiyun
1160*4882a593Smuzhiyun /**
1161*4882a593Smuzhiyun * _enable_sysc - try to bring a module out of idle via OCP_SYSCONFIG
1162*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1163*4882a593Smuzhiyun *
1164*4882a593Smuzhiyun * Ensure that the OCP_SYSCONFIG register for the IP block represented
1165*4882a593Smuzhiyun * by @oh is set to indicate to the PRCM that the IP block is active.
1166*4882a593Smuzhiyun * Usually this means placing the module into smart-idle mode and
1167*4882a593Smuzhiyun * smart-standby, but if there is a bug in the automatic idle handling
1168*4882a593Smuzhiyun * for the IP block, it may need to be placed into the force-idle or
1169*4882a593Smuzhiyun * no-idle variants of these modes. No return value.
1170*4882a593Smuzhiyun */
_enable_sysc(struct omap_hwmod * oh)1171*4882a593Smuzhiyun static void _enable_sysc(struct omap_hwmod *oh)
1172*4882a593Smuzhiyun {
1173*4882a593Smuzhiyun u8 idlemode, sf;
1174*4882a593Smuzhiyun u32 v;
1175*4882a593Smuzhiyun bool clkdm_act;
1176*4882a593Smuzhiyun struct clockdomain *clkdm;
1177*4882a593Smuzhiyun
1178*4882a593Smuzhiyun if (!oh->class->sysc)
1179*4882a593Smuzhiyun return;
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun /*
1182*4882a593Smuzhiyun * Wait until reset has completed, this is needed as the IP
1183*4882a593Smuzhiyun * block is reset automatically by hardware in some cases
1184*4882a593Smuzhiyun * (off-mode for example), and the drivers require the
1185*4882a593Smuzhiyun * IP to be ready when they access it
1186*4882a593Smuzhiyun */
1187*4882a593Smuzhiyun if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
1188*4882a593Smuzhiyun _enable_optional_clocks(oh);
1189*4882a593Smuzhiyun _wait_softreset_complete(oh);
1190*4882a593Smuzhiyun if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
1191*4882a593Smuzhiyun _disable_optional_clocks(oh);
1192*4882a593Smuzhiyun
1193*4882a593Smuzhiyun v = oh->_sysc_cache;
1194*4882a593Smuzhiyun sf = oh->class->sysc->sysc_flags;
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun clkdm = _get_clkdm(oh);
1197*4882a593Smuzhiyun if (sf & SYSC_HAS_SIDLEMODE) {
1198*4882a593Smuzhiyun if (oh->flags & HWMOD_SWSUP_SIDLE ||
1199*4882a593Smuzhiyun oh->flags & HWMOD_SWSUP_SIDLE_ACT) {
1200*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_NO;
1201*4882a593Smuzhiyun } else {
1202*4882a593Smuzhiyun if (sf & SYSC_HAS_ENAWAKEUP)
1203*4882a593Smuzhiyun _enable_wakeup(oh, &v);
1204*4882a593Smuzhiyun if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
1205*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_SMART_WKUP;
1206*4882a593Smuzhiyun else
1207*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_SMART;
1208*4882a593Smuzhiyun }
1209*4882a593Smuzhiyun
1210*4882a593Smuzhiyun /*
1211*4882a593Smuzhiyun * This is special handling for some IPs like
1212*4882a593Smuzhiyun * 32k sync timer. Force them to idle!
1213*4882a593Smuzhiyun */
1214*4882a593Smuzhiyun clkdm_act = (clkdm && clkdm->flags & CLKDM_ACTIVE_WITH_MPU);
1215*4882a593Smuzhiyun if (clkdm_act && !(oh->class->sysc->idlemodes &
1216*4882a593Smuzhiyun (SIDLE_SMART | SIDLE_SMART_WKUP)))
1217*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_FORCE;
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun _set_slave_idlemode(oh, idlemode, &v);
1220*4882a593Smuzhiyun }
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun if (sf & SYSC_HAS_MIDLEMODE) {
1223*4882a593Smuzhiyun if (oh->flags & HWMOD_FORCE_MSTANDBY) {
1224*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_FORCE;
1225*4882a593Smuzhiyun } else if (oh->flags & HWMOD_SWSUP_MSTANDBY) {
1226*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_NO;
1227*4882a593Smuzhiyun } else {
1228*4882a593Smuzhiyun if (sf & SYSC_HAS_ENAWAKEUP)
1229*4882a593Smuzhiyun _enable_wakeup(oh, &v);
1230*4882a593Smuzhiyun if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
1231*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_SMART_WKUP;
1232*4882a593Smuzhiyun else
1233*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_SMART;
1234*4882a593Smuzhiyun }
1235*4882a593Smuzhiyun _set_master_standbymode(oh, idlemode, &v);
1236*4882a593Smuzhiyun }
1237*4882a593Smuzhiyun
1238*4882a593Smuzhiyun /*
1239*4882a593Smuzhiyun * XXX The clock framework should handle this, by
1240*4882a593Smuzhiyun * calling into this code. But this must wait until the
1241*4882a593Smuzhiyun * clock structures are tagged with omap_hwmod entries
1242*4882a593Smuzhiyun */
1243*4882a593Smuzhiyun if ((oh->flags & HWMOD_SET_DEFAULT_CLOCKACT) &&
1244*4882a593Smuzhiyun (sf & SYSC_HAS_CLOCKACTIVITY))
1245*4882a593Smuzhiyun _set_clockactivity(oh, CLOCKACT_TEST_ICLK, &v);
1246*4882a593Smuzhiyun
1247*4882a593Smuzhiyun _write_sysconfig(v, oh);
1248*4882a593Smuzhiyun
1249*4882a593Smuzhiyun /*
1250*4882a593Smuzhiyun * Set the autoidle bit only after setting the smartidle bit
1251*4882a593Smuzhiyun * Setting this will not have any impact on the other modules.
1252*4882a593Smuzhiyun */
1253*4882a593Smuzhiyun if (sf & SYSC_HAS_AUTOIDLE) {
1254*4882a593Smuzhiyun idlemode = (oh->flags & HWMOD_NO_OCP_AUTOIDLE) ?
1255*4882a593Smuzhiyun 0 : 1;
1256*4882a593Smuzhiyun _set_module_autoidle(oh, idlemode, &v);
1257*4882a593Smuzhiyun _write_sysconfig(v, oh);
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun }
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun /**
1262*4882a593Smuzhiyun * _idle_sysc - try to put a module into idle via OCP_SYSCONFIG
1263*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1264*4882a593Smuzhiyun *
1265*4882a593Smuzhiyun * If module is marked as SWSUP_SIDLE, force the module into slave
1266*4882a593Smuzhiyun * idle; otherwise, configure it for smart-idle. If module is marked
1267*4882a593Smuzhiyun * as SWSUP_MSUSPEND, force the module into master standby; otherwise,
1268*4882a593Smuzhiyun * configure it for smart-standby. No return value.
1269*4882a593Smuzhiyun */
_idle_sysc(struct omap_hwmod * oh)1270*4882a593Smuzhiyun static void _idle_sysc(struct omap_hwmod *oh)
1271*4882a593Smuzhiyun {
1272*4882a593Smuzhiyun u8 idlemode, sf;
1273*4882a593Smuzhiyun u32 v;
1274*4882a593Smuzhiyun
1275*4882a593Smuzhiyun if (!oh->class->sysc)
1276*4882a593Smuzhiyun return;
1277*4882a593Smuzhiyun
1278*4882a593Smuzhiyun v = oh->_sysc_cache;
1279*4882a593Smuzhiyun sf = oh->class->sysc->sysc_flags;
1280*4882a593Smuzhiyun
1281*4882a593Smuzhiyun if (sf & SYSC_HAS_SIDLEMODE) {
1282*4882a593Smuzhiyun if (oh->flags & HWMOD_SWSUP_SIDLE) {
1283*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_FORCE;
1284*4882a593Smuzhiyun } else {
1285*4882a593Smuzhiyun if (sf & SYSC_HAS_ENAWAKEUP)
1286*4882a593Smuzhiyun _enable_wakeup(oh, &v);
1287*4882a593Smuzhiyun if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
1288*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_SMART_WKUP;
1289*4882a593Smuzhiyun else
1290*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_SMART;
1291*4882a593Smuzhiyun }
1292*4882a593Smuzhiyun _set_slave_idlemode(oh, idlemode, &v);
1293*4882a593Smuzhiyun }
1294*4882a593Smuzhiyun
1295*4882a593Smuzhiyun if (sf & SYSC_HAS_MIDLEMODE) {
1296*4882a593Smuzhiyun if ((oh->flags & HWMOD_SWSUP_MSTANDBY) ||
1297*4882a593Smuzhiyun (oh->flags & HWMOD_FORCE_MSTANDBY)) {
1298*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_FORCE;
1299*4882a593Smuzhiyun } else {
1300*4882a593Smuzhiyun if (sf & SYSC_HAS_ENAWAKEUP)
1301*4882a593Smuzhiyun _enable_wakeup(oh, &v);
1302*4882a593Smuzhiyun if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
1303*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_SMART_WKUP;
1304*4882a593Smuzhiyun else
1305*4882a593Smuzhiyun idlemode = HWMOD_IDLEMODE_SMART;
1306*4882a593Smuzhiyun }
1307*4882a593Smuzhiyun _set_master_standbymode(oh, idlemode, &v);
1308*4882a593Smuzhiyun }
1309*4882a593Smuzhiyun
1310*4882a593Smuzhiyun /* If the cached value is the same as the new value, skip the write */
1311*4882a593Smuzhiyun if (oh->_sysc_cache != v)
1312*4882a593Smuzhiyun _write_sysconfig(v, oh);
1313*4882a593Smuzhiyun }
1314*4882a593Smuzhiyun
1315*4882a593Smuzhiyun /**
1316*4882a593Smuzhiyun * _shutdown_sysc - force a module into idle via OCP_SYSCONFIG
1317*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1318*4882a593Smuzhiyun *
1319*4882a593Smuzhiyun * Force the module into slave idle and master suspend. No return
1320*4882a593Smuzhiyun * value.
1321*4882a593Smuzhiyun */
_shutdown_sysc(struct omap_hwmod * oh)1322*4882a593Smuzhiyun static void _shutdown_sysc(struct omap_hwmod *oh)
1323*4882a593Smuzhiyun {
1324*4882a593Smuzhiyun u32 v;
1325*4882a593Smuzhiyun u8 sf;
1326*4882a593Smuzhiyun
1327*4882a593Smuzhiyun if (!oh->class->sysc)
1328*4882a593Smuzhiyun return;
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun v = oh->_sysc_cache;
1331*4882a593Smuzhiyun sf = oh->class->sysc->sysc_flags;
1332*4882a593Smuzhiyun
1333*4882a593Smuzhiyun if (sf & SYSC_HAS_SIDLEMODE)
1334*4882a593Smuzhiyun _set_slave_idlemode(oh, HWMOD_IDLEMODE_FORCE, &v);
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun if (sf & SYSC_HAS_MIDLEMODE)
1337*4882a593Smuzhiyun _set_master_standbymode(oh, HWMOD_IDLEMODE_FORCE, &v);
1338*4882a593Smuzhiyun
1339*4882a593Smuzhiyun if (sf & SYSC_HAS_AUTOIDLE)
1340*4882a593Smuzhiyun _set_module_autoidle(oh, 1, &v);
1341*4882a593Smuzhiyun
1342*4882a593Smuzhiyun _write_sysconfig(v, oh);
1343*4882a593Smuzhiyun }
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun /**
1346*4882a593Smuzhiyun * _lookup - find an omap_hwmod by name
1347*4882a593Smuzhiyun * @name: find an omap_hwmod by name
1348*4882a593Smuzhiyun *
1349*4882a593Smuzhiyun * Return a pointer to an omap_hwmod by name, or NULL if not found.
1350*4882a593Smuzhiyun */
_lookup(const char * name)1351*4882a593Smuzhiyun static struct omap_hwmod *_lookup(const char *name)
1352*4882a593Smuzhiyun {
1353*4882a593Smuzhiyun struct omap_hwmod *oh, *temp_oh;
1354*4882a593Smuzhiyun
1355*4882a593Smuzhiyun oh = NULL;
1356*4882a593Smuzhiyun
1357*4882a593Smuzhiyun list_for_each_entry(temp_oh, &omap_hwmod_list, node) {
1358*4882a593Smuzhiyun if (!strcmp(name, temp_oh->name)) {
1359*4882a593Smuzhiyun oh = temp_oh;
1360*4882a593Smuzhiyun break;
1361*4882a593Smuzhiyun }
1362*4882a593Smuzhiyun }
1363*4882a593Smuzhiyun
1364*4882a593Smuzhiyun return oh;
1365*4882a593Smuzhiyun }
1366*4882a593Smuzhiyun
1367*4882a593Smuzhiyun /**
1368*4882a593Smuzhiyun * _init_clkdm - look up a clockdomain name, store pointer in omap_hwmod
1369*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1370*4882a593Smuzhiyun *
1371*4882a593Smuzhiyun * Convert a clockdomain name stored in a struct omap_hwmod into a
1372*4882a593Smuzhiyun * clockdomain pointer, and save it into the struct omap_hwmod.
1373*4882a593Smuzhiyun * Return -EINVAL if the clkdm_name lookup failed.
1374*4882a593Smuzhiyun */
_init_clkdm(struct omap_hwmod * oh)1375*4882a593Smuzhiyun static int _init_clkdm(struct omap_hwmod *oh)
1376*4882a593Smuzhiyun {
1377*4882a593Smuzhiyun if (!oh->clkdm_name) {
1378*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: missing clockdomain\n", oh->name);
1379*4882a593Smuzhiyun return 0;
1380*4882a593Smuzhiyun }
1381*4882a593Smuzhiyun
1382*4882a593Smuzhiyun oh->clkdm = clkdm_lookup(oh->clkdm_name);
1383*4882a593Smuzhiyun if (!oh->clkdm) {
1384*4882a593Smuzhiyun pr_warn("omap_hwmod: %s: could not associate to clkdm %s\n",
1385*4882a593Smuzhiyun oh->name, oh->clkdm_name);
1386*4882a593Smuzhiyun return 0;
1387*4882a593Smuzhiyun }
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: associated to clkdm %s\n",
1390*4882a593Smuzhiyun oh->name, oh->clkdm_name);
1391*4882a593Smuzhiyun
1392*4882a593Smuzhiyun return 0;
1393*4882a593Smuzhiyun }
1394*4882a593Smuzhiyun
1395*4882a593Smuzhiyun /**
1396*4882a593Smuzhiyun * _init_clocks - clk_get() all clocks associated with this hwmod. Retrieve as
1397*4882a593Smuzhiyun * well the clockdomain.
1398*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1399*4882a593Smuzhiyun * @np: device_node mapped to this hwmod
1400*4882a593Smuzhiyun *
1401*4882a593Smuzhiyun * Called by omap_hwmod_setup_*() (after omap2_clk_init()).
1402*4882a593Smuzhiyun * Resolves all clock names embedded in the hwmod. Returns 0 on
1403*4882a593Smuzhiyun * success, or a negative error code on failure.
1404*4882a593Smuzhiyun */
_init_clocks(struct omap_hwmod * oh,struct device_node * np)1405*4882a593Smuzhiyun static int _init_clocks(struct omap_hwmod *oh, struct device_node *np)
1406*4882a593Smuzhiyun {
1407*4882a593Smuzhiyun int ret = 0;
1408*4882a593Smuzhiyun
1409*4882a593Smuzhiyun if (oh->_state != _HWMOD_STATE_REGISTERED)
1410*4882a593Smuzhiyun return 0;
1411*4882a593Smuzhiyun
1412*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name);
1413*4882a593Smuzhiyun
1414*4882a593Smuzhiyun if (soc_ops.init_clkdm)
1415*4882a593Smuzhiyun ret |= soc_ops.init_clkdm(oh);
1416*4882a593Smuzhiyun
1417*4882a593Smuzhiyun ret |= _init_main_clk(oh);
1418*4882a593Smuzhiyun ret |= _init_interface_clks(oh);
1419*4882a593Smuzhiyun ret |= _init_opt_clks(oh);
1420*4882a593Smuzhiyun
1421*4882a593Smuzhiyun if (!ret)
1422*4882a593Smuzhiyun oh->_state = _HWMOD_STATE_CLKS_INITED;
1423*4882a593Smuzhiyun else
1424*4882a593Smuzhiyun pr_warn("omap_hwmod: %s: cannot _init_clocks\n", oh->name);
1425*4882a593Smuzhiyun
1426*4882a593Smuzhiyun return ret;
1427*4882a593Smuzhiyun }
1428*4882a593Smuzhiyun
1429*4882a593Smuzhiyun /**
1430*4882a593Smuzhiyun * _lookup_hardreset - fill register bit info for this hwmod/reset line
1431*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1432*4882a593Smuzhiyun * @name: name of the reset line in the context of this hwmod
1433*4882a593Smuzhiyun * @ohri: struct omap_hwmod_rst_info * that this function will fill in
1434*4882a593Smuzhiyun *
1435*4882a593Smuzhiyun * Return the bit position of the reset line that match the
1436*4882a593Smuzhiyun * input name. Return -ENOENT if not found.
1437*4882a593Smuzhiyun */
_lookup_hardreset(struct omap_hwmod * oh,const char * name,struct omap_hwmod_rst_info * ohri)1438*4882a593Smuzhiyun static int _lookup_hardreset(struct omap_hwmod *oh, const char *name,
1439*4882a593Smuzhiyun struct omap_hwmod_rst_info *ohri)
1440*4882a593Smuzhiyun {
1441*4882a593Smuzhiyun int i;
1442*4882a593Smuzhiyun
1443*4882a593Smuzhiyun for (i = 0; i < oh->rst_lines_cnt; i++) {
1444*4882a593Smuzhiyun const char *rst_line = oh->rst_lines[i].name;
1445*4882a593Smuzhiyun if (!strcmp(rst_line, name)) {
1446*4882a593Smuzhiyun ohri->rst_shift = oh->rst_lines[i].rst_shift;
1447*4882a593Smuzhiyun ohri->st_shift = oh->rst_lines[i].st_shift;
1448*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: %s: %s: rst %d st %d\n",
1449*4882a593Smuzhiyun oh->name, __func__, rst_line, ohri->rst_shift,
1450*4882a593Smuzhiyun ohri->st_shift);
1451*4882a593Smuzhiyun
1452*4882a593Smuzhiyun return 0;
1453*4882a593Smuzhiyun }
1454*4882a593Smuzhiyun }
1455*4882a593Smuzhiyun
1456*4882a593Smuzhiyun return -ENOENT;
1457*4882a593Smuzhiyun }
1458*4882a593Smuzhiyun
1459*4882a593Smuzhiyun /**
1460*4882a593Smuzhiyun * _assert_hardreset - assert the HW reset line of submodules
1461*4882a593Smuzhiyun * contained in the hwmod module.
1462*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1463*4882a593Smuzhiyun * @name: name of the reset line to lookup and assert
1464*4882a593Smuzhiyun *
1465*4882a593Smuzhiyun * Some IP like dsp, ipu or iva contain processor that require an HW
1466*4882a593Smuzhiyun * reset line to be assert / deassert in order to enable fully the IP.
1467*4882a593Smuzhiyun * Returns -EINVAL if @oh is null, -ENOSYS if we have no way of
1468*4882a593Smuzhiyun * asserting the hardreset line on the currently-booted SoC, or passes
1469*4882a593Smuzhiyun * along the return value from _lookup_hardreset() or the SoC's
1470*4882a593Smuzhiyun * assert_hardreset code.
1471*4882a593Smuzhiyun */
_assert_hardreset(struct omap_hwmod * oh,const char * name)1472*4882a593Smuzhiyun static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
1473*4882a593Smuzhiyun {
1474*4882a593Smuzhiyun struct omap_hwmod_rst_info ohri;
1475*4882a593Smuzhiyun int ret = -EINVAL;
1476*4882a593Smuzhiyun
1477*4882a593Smuzhiyun if (!oh)
1478*4882a593Smuzhiyun return -EINVAL;
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun if (!soc_ops.assert_hardreset)
1481*4882a593Smuzhiyun return -ENOSYS;
1482*4882a593Smuzhiyun
1483*4882a593Smuzhiyun ret = _lookup_hardreset(oh, name, &ohri);
1484*4882a593Smuzhiyun if (ret < 0)
1485*4882a593Smuzhiyun return ret;
1486*4882a593Smuzhiyun
1487*4882a593Smuzhiyun ret = soc_ops.assert_hardreset(oh, &ohri);
1488*4882a593Smuzhiyun
1489*4882a593Smuzhiyun return ret;
1490*4882a593Smuzhiyun }
1491*4882a593Smuzhiyun
1492*4882a593Smuzhiyun /**
1493*4882a593Smuzhiyun * _deassert_hardreset - deassert the HW reset line of submodules contained
1494*4882a593Smuzhiyun * in the hwmod module.
1495*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1496*4882a593Smuzhiyun * @name: name of the reset line to look up and deassert
1497*4882a593Smuzhiyun *
1498*4882a593Smuzhiyun * Some IP like dsp, ipu or iva contain processor that require an HW
1499*4882a593Smuzhiyun * reset line to be assert / deassert in order to enable fully the IP.
1500*4882a593Smuzhiyun * Returns -EINVAL if @oh is null, -ENOSYS if we have no way of
1501*4882a593Smuzhiyun * deasserting the hardreset line on the currently-booted SoC, or passes
1502*4882a593Smuzhiyun * along the return value from _lookup_hardreset() or the SoC's
1503*4882a593Smuzhiyun * deassert_hardreset code.
1504*4882a593Smuzhiyun */
_deassert_hardreset(struct omap_hwmod * oh,const char * name)1505*4882a593Smuzhiyun static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
1506*4882a593Smuzhiyun {
1507*4882a593Smuzhiyun struct omap_hwmod_rst_info ohri;
1508*4882a593Smuzhiyun int ret = -EINVAL;
1509*4882a593Smuzhiyun
1510*4882a593Smuzhiyun if (!oh)
1511*4882a593Smuzhiyun return -EINVAL;
1512*4882a593Smuzhiyun
1513*4882a593Smuzhiyun if (!soc_ops.deassert_hardreset)
1514*4882a593Smuzhiyun return -ENOSYS;
1515*4882a593Smuzhiyun
1516*4882a593Smuzhiyun ret = _lookup_hardreset(oh, name, &ohri);
1517*4882a593Smuzhiyun if (ret < 0)
1518*4882a593Smuzhiyun return ret;
1519*4882a593Smuzhiyun
1520*4882a593Smuzhiyun if (oh->clkdm) {
1521*4882a593Smuzhiyun /*
1522*4882a593Smuzhiyun * A clockdomain must be in SW_SUP otherwise reset
1523*4882a593Smuzhiyun * might not be completed. The clockdomain can be set
1524*4882a593Smuzhiyun * in HW_AUTO only when the module become ready.
1525*4882a593Smuzhiyun */
1526*4882a593Smuzhiyun clkdm_deny_idle(oh->clkdm);
1527*4882a593Smuzhiyun ret = clkdm_hwmod_enable(oh->clkdm, oh);
1528*4882a593Smuzhiyun if (ret) {
1529*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n",
1530*4882a593Smuzhiyun oh->name, oh->clkdm->name, ret);
1531*4882a593Smuzhiyun return ret;
1532*4882a593Smuzhiyun }
1533*4882a593Smuzhiyun }
1534*4882a593Smuzhiyun
1535*4882a593Smuzhiyun _enable_clocks(oh);
1536*4882a593Smuzhiyun if (soc_ops.enable_module)
1537*4882a593Smuzhiyun soc_ops.enable_module(oh);
1538*4882a593Smuzhiyun
1539*4882a593Smuzhiyun ret = soc_ops.deassert_hardreset(oh, &ohri);
1540*4882a593Smuzhiyun
1541*4882a593Smuzhiyun if (soc_ops.disable_module)
1542*4882a593Smuzhiyun soc_ops.disable_module(oh);
1543*4882a593Smuzhiyun _disable_clocks(oh);
1544*4882a593Smuzhiyun
1545*4882a593Smuzhiyun if (ret == -EBUSY)
1546*4882a593Smuzhiyun pr_warn("omap_hwmod: %s: failed to hardreset\n", oh->name);
1547*4882a593Smuzhiyun
1548*4882a593Smuzhiyun if (oh->clkdm) {
1549*4882a593Smuzhiyun /*
1550*4882a593Smuzhiyun * Set the clockdomain to HW_AUTO, assuming that the
1551*4882a593Smuzhiyun * previous state was HW_AUTO.
1552*4882a593Smuzhiyun */
1553*4882a593Smuzhiyun clkdm_allow_idle(oh->clkdm);
1554*4882a593Smuzhiyun
1555*4882a593Smuzhiyun clkdm_hwmod_disable(oh->clkdm, oh);
1556*4882a593Smuzhiyun }
1557*4882a593Smuzhiyun
1558*4882a593Smuzhiyun return ret;
1559*4882a593Smuzhiyun }
1560*4882a593Smuzhiyun
1561*4882a593Smuzhiyun /**
1562*4882a593Smuzhiyun * _read_hardreset - read the HW reset line state of submodules
1563*4882a593Smuzhiyun * contained in the hwmod module
1564*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1565*4882a593Smuzhiyun * @name: name of the reset line to look up and read
1566*4882a593Smuzhiyun *
1567*4882a593Smuzhiyun * Return the state of the reset line. Returns -EINVAL if @oh is
1568*4882a593Smuzhiyun * null, -ENOSYS if we have no way of reading the hardreset line
1569*4882a593Smuzhiyun * status on the currently-booted SoC, or passes along the return
1570*4882a593Smuzhiyun * value from _lookup_hardreset() or the SoC's is_hardreset_asserted
1571*4882a593Smuzhiyun * code.
1572*4882a593Smuzhiyun */
_read_hardreset(struct omap_hwmod * oh,const char * name)1573*4882a593Smuzhiyun static int _read_hardreset(struct omap_hwmod *oh, const char *name)
1574*4882a593Smuzhiyun {
1575*4882a593Smuzhiyun struct omap_hwmod_rst_info ohri;
1576*4882a593Smuzhiyun int ret = -EINVAL;
1577*4882a593Smuzhiyun
1578*4882a593Smuzhiyun if (!oh)
1579*4882a593Smuzhiyun return -EINVAL;
1580*4882a593Smuzhiyun
1581*4882a593Smuzhiyun if (!soc_ops.is_hardreset_asserted)
1582*4882a593Smuzhiyun return -ENOSYS;
1583*4882a593Smuzhiyun
1584*4882a593Smuzhiyun ret = _lookup_hardreset(oh, name, &ohri);
1585*4882a593Smuzhiyun if (ret < 0)
1586*4882a593Smuzhiyun return ret;
1587*4882a593Smuzhiyun
1588*4882a593Smuzhiyun return soc_ops.is_hardreset_asserted(oh, &ohri);
1589*4882a593Smuzhiyun }
1590*4882a593Smuzhiyun
1591*4882a593Smuzhiyun /**
1592*4882a593Smuzhiyun * _are_all_hardreset_lines_asserted - return true if the @oh is hard-reset
1593*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1594*4882a593Smuzhiyun *
1595*4882a593Smuzhiyun * If all hardreset lines associated with @oh are asserted, then return true.
1596*4882a593Smuzhiyun * Otherwise, if part of @oh is out hardreset or if no hardreset lines
1597*4882a593Smuzhiyun * associated with @oh are asserted, then return false.
1598*4882a593Smuzhiyun * This function is used to avoid executing some parts of the IP block
1599*4882a593Smuzhiyun * enable/disable sequence if its hardreset line is set.
1600*4882a593Smuzhiyun */
_are_all_hardreset_lines_asserted(struct omap_hwmod * oh)1601*4882a593Smuzhiyun static bool _are_all_hardreset_lines_asserted(struct omap_hwmod *oh)
1602*4882a593Smuzhiyun {
1603*4882a593Smuzhiyun int i, rst_cnt = 0;
1604*4882a593Smuzhiyun
1605*4882a593Smuzhiyun if (oh->rst_lines_cnt == 0)
1606*4882a593Smuzhiyun return false;
1607*4882a593Smuzhiyun
1608*4882a593Smuzhiyun for (i = 0; i < oh->rst_lines_cnt; i++)
1609*4882a593Smuzhiyun if (_read_hardreset(oh, oh->rst_lines[i].name) > 0)
1610*4882a593Smuzhiyun rst_cnt++;
1611*4882a593Smuzhiyun
1612*4882a593Smuzhiyun if (oh->rst_lines_cnt == rst_cnt)
1613*4882a593Smuzhiyun return true;
1614*4882a593Smuzhiyun
1615*4882a593Smuzhiyun return false;
1616*4882a593Smuzhiyun }
1617*4882a593Smuzhiyun
1618*4882a593Smuzhiyun /**
1619*4882a593Smuzhiyun * _are_any_hardreset_lines_asserted - return true if any part of @oh is
1620*4882a593Smuzhiyun * hard-reset
1621*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1622*4882a593Smuzhiyun *
1623*4882a593Smuzhiyun * If any hardreset lines associated with @oh are asserted, then
1624*4882a593Smuzhiyun * return true. Otherwise, if no hardreset lines associated with @oh
1625*4882a593Smuzhiyun * are asserted, or if @oh has no hardreset lines, then return false.
1626*4882a593Smuzhiyun * This function is used to avoid executing some parts of the IP block
1627*4882a593Smuzhiyun * enable/disable sequence if any hardreset line is set.
1628*4882a593Smuzhiyun */
_are_any_hardreset_lines_asserted(struct omap_hwmod * oh)1629*4882a593Smuzhiyun static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh)
1630*4882a593Smuzhiyun {
1631*4882a593Smuzhiyun int rst_cnt = 0;
1632*4882a593Smuzhiyun int i;
1633*4882a593Smuzhiyun
1634*4882a593Smuzhiyun for (i = 0; i < oh->rst_lines_cnt && rst_cnt == 0; i++)
1635*4882a593Smuzhiyun if (_read_hardreset(oh, oh->rst_lines[i].name) > 0)
1636*4882a593Smuzhiyun rst_cnt++;
1637*4882a593Smuzhiyun
1638*4882a593Smuzhiyun return (rst_cnt) ? true : false;
1639*4882a593Smuzhiyun }
1640*4882a593Smuzhiyun
1641*4882a593Smuzhiyun /**
1642*4882a593Smuzhiyun * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
1643*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1644*4882a593Smuzhiyun *
1645*4882a593Smuzhiyun * Disable the PRCM module mode related to the hwmod @oh.
1646*4882a593Smuzhiyun * Return EINVAL if the modulemode is not supported and 0 in case of success.
1647*4882a593Smuzhiyun */
_omap4_disable_module(struct omap_hwmod * oh)1648*4882a593Smuzhiyun static int _omap4_disable_module(struct omap_hwmod *oh)
1649*4882a593Smuzhiyun {
1650*4882a593Smuzhiyun int v;
1651*4882a593Smuzhiyun
1652*4882a593Smuzhiyun if (!oh->clkdm || !oh->prcm.omap4.modulemode ||
1653*4882a593Smuzhiyun _omap4_clkctrl_managed_by_clkfwk(oh))
1654*4882a593Smuzhiyun return -EINVAL;
1655*4882a593Smuzhiyun
1656*4882a593Smuzhiyun /*
1657*4882a593Smuzhiyun * Since integration code might still be doing something, only
1658*4882a593Smuzhiyun * disable if all lines are under hardreset.
1659*4882a593Smuzhiyun */
1660*4882a593Smuzhiyun if (_are_any_hardreset_lines_asserted(oh))
1661*4882a593Smuzhiyun return 0;
1662*4882a593Smuzhiyun
1663*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
1664*4882a593Smuzhiyun
1665*4882a593Smuzhiyun omap_cm_module_disable(oh->clkdm->prcm_partition, oh->clkdm->cm_inst,
1666*4882a593Smuzhiyun oh->prcm.omap4.clkctrl_offs);
1667*4882a593Smuzhiyun
1668*4882a593Smuzhiyun v = _omap4_wait_target_disable(oh);
1669*4882a593Smuzhiyun if (v)
1670*4882a593Smuzhiyun pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
1671*4882a593Smuzhiyun oh->name);
1672*4882a593Smuzhiyun
1673*4882a593Smuzhiyun return 0;
1674*4882a593Smuzhiyun }
1675*4882a593Smuzhiyun
1676*4882a593Smuzhiyun /**
1677*4882a593Smuzhiyun * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit
1678*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1679*4882a593Smuzhiyun *
1680*4882a593Smuzhiyun * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be
1681*4882a593Smuzhiyun * enabled for this to work. Returns -ENOENT if the hwmod cannot be
1682*4882a593Smuzhiyun * reset this way, -EINVAL if the hwmod is in the wrong state,
1683*4882a593Smuzhiyun * -ETIMEDOUT if the module did not reset in time, or 0 upon success.
1684*4882a593Smuzhiyun *
1685*4882a593Smuzhiyun * In OMAP3 a specific SYSSTATUS register is used to get the reset status.
1686*4882a593Smuzhiyun * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead
1687*4882a593Smuzhiyun * use the SYSCONFIG softreset bit to provide the status.
1688*4882a593Smuzhiyun *
1689*4882a593Smuzhiyun * Note that some IP like McBSP do have reset control but don't have
1690*4882a593Smuzhiyun * reset status.
1691*4882a593Smuzhiyun */
_ocp_softreset(struct omap_hwmod * oh)1692*4882a593Smuzhiyun static int _ocp_softreset(struct omap_hwmod *oh)
1693*4882a593Smuzhiyun {
1694*4882a593Smuzhiyun u32 v;
1695*4882a593Smuzhiyun int c = 0;
1696*4882a593Smuzhiyun int ret = 0;
1697*4882a593Smuzhiyun
1698*4882a593Smuzhiyun if (!oh->class->sysc ||
1699*4882a593Smuzhiyun !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
1700*4882a593Smuzhiyun return -ENOENT;
1701*4882a593Smuzhiyun
1702*4882a593Smuzhiyun /* clocks must be on for this operation */
1703*4882a593Smuzhiyun if (oh->_state != _HWMOD_STATE_ENABLED) {
1704*4882a593Smuzhiyun pr_warn("omap_hwmod: %s: reset can only be entered from enabled state\n",
1705*4882a593Smuzhiyun oh->name);
1706*4882a593Smuzhiyun return -EINVAL;
1707*4882a593Smuzhiyun }
1708*4882a593Smuzhiyun
1709*4882a593Smuzhiyun /* For some modules, all optionnal clocks need to be enabled as well */
1710*4882a593Smuzhiyun if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
1711*4882a593Smuzhiyun _enable_optional_clocks(oh);
1712*4882a593Smuzhiyun
1713*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: resetting via OCP SOFTRESET\n", oh->name);
1714*4882a593Smuzhiyun
1715*4882a593Smuzhiyun v = oh->_sysc_cache;
1716*4882a593Smuzhiyun ret = _set_softreset(oh, &v);
1717*4882a593Smuzhiyun if (ret)
1718*4882a593Smuzhiyun goto dis_opt_clks;
1719*4882a593Smuzhiyun
1720*4882a593Smuzhiyun _write_sysconfig(v, oh);
1721*4882a593Smuzhiyun
1722*4882a593Smuzhiyun if (oh->class->sysc->srst_udelay)
1723*4882a593Smuzhiyun udelay(oh->class->sysc->srst_udelay);
1724*4882a593Smuzhiyun
1725*4882a593Smuzhiyun c = _wait_softreset_complete(oh);
1726*4882a593Smuzhiyun if (c == MAX_MODULE_SOFTRESET_WAIT) {
1727*4882a593Smuzhiyun pr_warn("omap_hwmod: %s: softreset failed (waited %d usec)\n",
1728*4882a593Smuzhiyun oh->name, MAX_MODULE_SOFTRESET_WAIT);
1729*4882a593Smuzhiyun ret = -ETIMEDOUT;
1730*4882a593Smuzhiyun goto dis_opt_clks;
1731*4882a593Smuzhiyun } else {
1732*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c);
1733*4882a593Smuzhiyun }
1734*4882a593Smuzhiyun
1735*4882a593Smuzhiyun ret = _clear_softreset(oh, &v);
1736*4882a593Smuzhiyun if (ret)
1737*4882a593Smuzhiyun goto dis_opt_clks;
1738*4882a593Smuzhiyun
1739*4882a593Smuzhiyun _write_sysconfig(v, oh);
1740*4882a593Smuzhiyun
1741*4882a593Smuzhiyun /*
1742*4882a593Smuzhiyun * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
1743*4882a593Smuzhiyun * _wait_target_ready() or _reset()
1744*4882a593Smuzhiyun */
1745*4882a593Smuzhiyun
1746*4882a593Smuzhiyun dis_opt_clks:
1747*4882a593Smuzhiyun if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
1748*4882a593Smuzhiyun _disable_optional_clocks(oh);
1749*4882a593Smuzhiyun
1750*4882a593Smuzhiyun return ret;
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun
1753*4882a593Smuzhiyun /**
1754*4882a593Smuzhiyun * _reset - reset an omap_hwmod
1755*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1756*4882a593Smuzhiyun *
1757*4882a593Smuzhiyun * Resets an omap_hwmod @oh. If the module has a custom reset
1758*4882a593Smuzhiyun * function pointer defined, then call it to reset the IP block, and
1759*4882a593Smuzhiyun * pass along its return value to the caller. Otherwise, if the IP
1760*4882a593Smuzhiyun * block has an OCP_SYSCONFIG register with a SOFTRESET bitfield
1761*4882a593Smuzhiyun * associated with it, call a function to reset the IP block via that
1762*4882a593Smuzhiyun * method, and pass along the return value to the caller. Finally, if
1763*4882a593Smuzhiyun * the IP block has some hardreset lines associated with it, assert
1764*4882a593Smuzhiyun * all of those, but do _not_ deassert them. (This is because driver
1765*4882a593Smuzhiyun * authors have expressed an apparent requirement to control the
1766*4882a593Smuzhiyun * deassertion of the hardreset lines themselves.)
1767*4882a593Smuzhiyun *
1768*4882a593Smuzhiyun * The default software reset mechanism for most OMAP IP blocks is
1769*4882a593Smuzhiyun * triggered via the OCP_SYSCONFIG.SOFTRESET bit. However, some
1770*4882a593Smuzhiyun * hwmods cannot be reset via this method. Some are not targets and
1771*4882a593Smuzhiyun * therefore have no OCP header registers to access. Others (like the
1772*4882a593Smuzhiyun * IVA) have idiosyncratic reset sequences. So for these relatively
1773*4882a593Smuzhiyun * rare cases, custom reset code can be supplied in the struct
1774*4882a593Smuzhiyun * omap_hwmod_class .reset function pointer.
1775*4882a593Smuzhiyun *
1776*4882a593Smuzhiyun * _set_dmadisable() is called to set the DMADISABLE bit so that it
1777*4882a593Smuzhiyun * does not prevent idling of the system. This is necessary for cases
1778*4882a593Smuzhiyun * where ROMCODE/BOOTLOADER uses dma and transfers control to the
1779*4882a593Smuzhiyun * kernel without disabling dma.
1780*4882a593Smuzhiyun *
1781*4882a593Smuzhiyun * Passes along the return value from either _ocp_softreset() or the
1782*4882a593Smuzhiyun * custom reset function - these must return -EINVAL if the hwmod
1783*4882a593Smuzhiyun * cannot be reset this way or if the hwmod is in the wrong state,
1784*4882a593Smuzhiyun * -ETIMEDOUT if the module did not reset in time, or 0 upon success.
1785*4882a593Smuzhiyun */
_reset(struct omap_hwmod * oh)1786*4882a593Smuzhiyun static int _reset(struct omap_hwmod *oh)
1787*4882a593Smuzhiyun {
1788*4882a593Smuzhiyun int i, r;
1789*4882a593Smuzhiyun
1790*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: resetting\n", oh->name);
1791*4882a593Smuzhiyun
1792*4882a593Smuzhiyun if (oh->class->reset) {
1793*4882a593Smuzhiyun r = oh->class->reset(oh);
1794*4882a593Smuzhiyun } else {
1795*4882a593Smuzhiyun if (oh->rst_lines_cnt > 0) {
1796*4882a593Smuzhiyun for (i = 0; i < oh->rst_lines_cnt; i++)
1797*4882a593Smuzhiyun _assert_hardreset(oh, oh->rst_lines[i].name);
1798*4882a593Smuzhiyun return 0;
1799*4882a593Smuzhiyun } else {
1800*4882a593Smuzhiyun r = _ocp_softreset(oh);
1801*4882a593Smuzhiyun if (r == -ENOENT)
1802*4882a593Smuzhiyun r = 0;
1803*4882a593Smuzhiyun }
1804*4882a593Smuzhiyun }
1805*4882a593Smuzhiyun
1806*4882a593Smuzhiyun _set_dmadisable(oh);
1807*4882a593Smuzhiyun
1808*4882a593Smuzhiyun /*
1809*4882a593Smuzhiyun * OCP_SYSCONFIG bits need to be reprogrammed after a
1810*4882a593Smuzhiyun * softreset. The _enable() function should be split to avoid
1811*4882a593Smuzhiyun * the rewrite of the OCP_SYSCONFIG register.
1812*4882a593Smuzhiyun */
1813*4882a593Smuzhiyun if (oh->class->sysc) {
1814*4882a593Smuzhiyun _update_sysc_cache(oh);
1815*4882a593Smuzhiyun _enable_sysc(oh);
1816*4882a593Smuzhiyun }
1817*4882a593Smuzhiyun
1818*4882a593Smuzhiyun return r;
1819*4882a593Smuzhiyun }
1820*4882a593Smuzhiyun
1821*4882a593Smuzhiyun /**
1822*4882a593Smuzhiyun * _omap4_update_context_lost - increment hwmod context loss counter if
1823*4882a593Smuzhiyun * hwmod context was lost, and clear hardware context loss reg
1824*4882a593Smuzhiyun * @oh: hwmod to check for context loss
1825*4882a593Smuzhiyun *
1826*4882a593Smuzhiyun * If the PRCM indicates that the hwmod @oh lost context, increment
1827*4882a593Smuzhiyun * our in-memory context loss counter, and clear the RM_*_CONTEXT
1828*4882a593Smuzhiyun * bits. No return value.
1829*4882a593Smuzhiyun */
_omap4_update_context_lost(struct omap_hwmod * oh)1830*4882a593Smuzhiyun static void _omap4_update_context_lost(struct omap_hwmod *oh)
1831*4882a593Smuzhiyun {
1832*4882a593Smuzhiyun if (oh->prcm.omap4.flags & HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT)
1833*4882a593Smuzhiyun return;
1834*4882a593Smuzhiyun
1835*4882a593Smuzhiyun if (!prm_was_any_context_lost_old(oh->clkdm->pwrdm.ptr->prcm_partition,
1836*4882a593Smuzhiyun oh->clkdm->pwrdm.ptr->prcm_offs,
1837*4882a593Smuzhiyun oh->prcm.omap4.context_offs))
1838*4882a593Smuzhiyun return;
1839*4882a593Smuzhiyun
1840*4882a593Smuzhiyun oh->prcm.omap4.context_lost_counter++;
1841*4882a593Smuzhiyun prm_clear_context_loss_flags_old(oh->clkdm->pwrdm.ptr->prcm_partition,
1842*4882a593Smuzhiyun oh->clkdm->pwrdm.ptr->prcm_offs,
1843*4882a593Smuzhiyun oh->prcm.omap4.context_offs);
1844*4882a593Smuzhiyun }
1845*4882a593Smuzhiyun
1846*4882a593Smuzhiyun /**
1847*4882a593Smuzhiyun * _omap4_get_context_lost - get context loss counter for a hwmod
1848*4882a593Smuzhiyun * @oh: hwmod to get context loss counter for
1849*4882a593Smuzhiyun *
1850*4882a593Smuzhiyun * Returns the in-memory context loss counter for a hwmod.
1851*4882a593Smuzhiyun */
_omap4_get_context_lost(struct omap_hwmod * oh)1852*4882a593Smuzhiyun static int _omap4_get_context_lost(struct omap_hwmod *oh)
1853*4882a593Smuzhiyun {
1854*4882a593Smuzhiyun return oh->prcm.omap4.context_lost_counter;
1855*4882a593Smuzhiyun }
1856*4882a593Smuzhiyun
1857*4882a593Smuzhiyun /**
1858*4882a593Smuzhiyun * _enable - enable an omap_hwmod
1859*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1860*4882a593Smuzhiyun *
1861*4882a593Smuzhiyun * Enables an omap_hwmod @oh such that the MPU can access the hwmod's
1862*4882a593Smuzhiyun * register target. Returns -EINVAL if the hwmod is in the wrong
1863*4882a593Smuzhiyun * state or passes along the return value of _wait_target_ready().
1864*4882a593Smuzhiyun */
_enable(struct omap_hwmod * oh)1865*4882a593Smuzhiyun static int _enable(struct omap_hwmod *oh)
1866*4882a593Smuzhiyun {
1867*4882a593Smuzhiyun int r;
1868*4882a593Smuzhiyun
1869*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: enabling\n", oh->name);
1870*4882a593Smuzhiyun
1871*4882a593Smuzhiyun /*
1872*4882a593Smuzhiyun * hwmods with HWMOD_INIT_NO_IDLE flag set are left in enabled
1873*4882a593Smuzhiyun * state at init.
1874*4882a593Smuzhiyun */
1875*4882a593Smuzhiyun if (oh->_int_flags & _HWMOD_SKIP_ENABLE) {
1876*4882a593Smuzhiyun oh->_int_flags &= ~_HWMOD_SKIP_ENABLE;
1877*4882a593Smuzhiyun return 0;
1878*4882a593Smuzhiyun }
1879*4882a593Smuzhiyun
1880*4882a593Smuzhiyun if (oh->_state != _HWMOD_STATE_INITIALIZED &&
1881*4882a593Smuzhiyun oh->_state != _HWMOD_STATE_IDLE &&
1882*4882a593Smuzhiyun oh->_state != _HWMOD_STATE_DISABLED) {
1883*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: enabled state can only be entered from initialized, idle, or disabled state\n",
1884*4882a593Smuzhiyun oh->name);
1885*4882a593Smuzhiyun return -EINVAL;
1886*4882a593Smuzhiyun }
1887*4882a593Smuzhiyun
1888*4882a593Smuzhiyun /*
1889*4882a593Smuzhiyun * If an IP block contains HW reset lines and all of them are
1890*4882a593Smuzhiyun * asserted, we let integration code associated with that
1891*4882a593Smuzhiyun * block handle the enable. We've received very little
1892*4882a593Smuzhiyun * information on what those driver authors need, and until
1893*4882a593Smuzhiyun * detailed information is provided and the driver code is
1894*4882a593Smuzhiyun * posted to the public lists, this is probably the best we
1895*4882a593Smuzhiyun * can do.
1896*4882a593Smuzhiyun */
1897*4882a593Smuzhiyun if (_are_all_hardreset_lines_asserted(oh))
1898*4882a593Smuzhiyun return 0;
1899*4882a593Smuzhiyun
1900*4882a593Smuzhiyun _add_initiator_dep(oh, mpu_oh);
1901*4882a593Smuzhiyun
1902*4882a593Smuzhiyun if (oh->clkdm) {
1903*4882a593Smuzhiyun /*
1904*4882a593Smuzhiyun * A clockdomain must be in SW_SUP before enabling
1905*4882a593Smuzhiyun * completely the module. The clockdomain can be set
1906*4882a593Smuzhiyun * in HW_AUTO only when the module become ready.
1907*4882a593Smuzhiyun */
1908*4882a593Smuzhiyun clkdm_deny_idle(oh->clkdm);
1909*4882a593Smuzhiyun r = clkdm_hwmod_enable(oh->clkdm, oh);
1910*4882a593Smuzhiyun if (r) {
1911*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n",
1912*4882a593Smuzhiyun oh->name, oh->clkdm->name, r);
1913*4882a593Smuzhiyun return r;
1914*4882a593Smuzhiyun }
1915*4882a593Smuzhiyun }
1916*4882a593Smuzhiyun
1917*4882a593Smuzhiyun _enable_clocks(oh);
1918*4882a593Smuzhiyun if (soc_ops.enable_module)
1919*4882a593Smuzhiyun soc_ops.enable_module(oh);
1920*4882a593Smuzhiyun if (oh->flags & HWMOD_BLOCK_WFI)
1921*4882a593Smuzhiyun cpu_idle_poll_ctrl(true);
1922*4882a593Smuzhiyun
1923*4882a593Smuzhiyun if (soc_ops.update_context_lost)
1924*4882a593Smuzhiyun soc_ops.update_context_lost(oh);
1925*4882a593Smuzhiyun
1926*4882a593Smuzhiyun r = (soc_ops.wait_target_ready) ? soc_ops.wait_target_ready(oh) :
1927*4882a593Smuzhiyun -EINVAL;
1928*4882a593Smuzhiyun if (oh->clkdm && !(oh->flags & HWMOD_CLKDM_NOAUTO))
1929*4882a593Smuzhiyun clkdm_allow_idle(oh->clkdm);
1930*4882a593Smuzhiyun
1931*4882a593Smuzhiyun if (!r) {
1932*4882a593Smuzhiyun oh->_state = _HWMOD_STATE_ENABLED;
1933*4882a593Smuzhiyun
1934*4882a593Smuzhiyun /* Access the sysconfig only if the target is ready */
1935*4882a593Smuzhiyun if (oh->class->sysc) {
1936*4882a593Smuzhiyun if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
1937*4882a593Smuzhiyun _update_sysc_cache(oh);
1938*4882a593Smuzhiyun _enable_sysc(oh);
1939*4882a593Smuzhiyun }
1940*4882a593Smuzhiyun } else {
1941*4882a593Smuzhiyun if (soc_ops.disable_module)
1942*4882a593Smuzhiyun soc_ops.disable_module(oh);
1943*4882a593Smuzhiyun _disable_clocks(oh);
1944*4882a593Smuzhiyun pr_err("omap_hwmod: %s: _wait_target_ready failed: %d\n",
1945*4882a593Smuzhiyun oh->name, r);
1946*4882a593Smuzhiyun
1947*4882a593Smuzhiyun if (oh->clkdm)
1948*4882a593Smuzhiyun clkdm_hwmod_disable(oh->clkdm, oh);
1949*4882a593Smuzhiyun }
1950*4882a593Smuzhiyun
1951*4882a593Smuzhiyun return r;
1952*4882a593Smuzhiyun }
1953*4882a593Smuzhiyun
1954*4882a593Smuzhiyun /**
1955*4882a593Smuzhiyun * _idle - idle an omap_hwmod
1956*4882a593Smuzhiyun * @oh: struct omap_hwmod *
1957*4882a593Smuzhiyun *
1958*4882a593Smuzhiyun * Idles an omap_hwmod @oh. This should be called once the hwmod has
1959*4882a593Smuzhiyun * no further work. Returns -EINVAL if the hwmod is in the wrong
1960*4882a593Smuzhiyun * state or returns 0.
1961*4882a593Smuzhiyun */
_idle(struct omap_hwmod * oh)1962*4882a593Smuzhiyun static int _idle(struct omap_hwmod *oh)
1963*4882a593Smuzhiyun {
1964*4882a593Smuzhiyun if (oh->flags & HWMOD_NO_IDLE) {
1965*4882a593Smuzhiyun oh->_int_flags |= _HWMOD_SKIP_ENABLE;
1966*4882a593Smuzhiyun return 0;
1967*4882a593Smuzhiyun }
1968*4882a593Smuzhiyun
1969*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: idling\n", oh->name);
1970*4882a593Smuzhiyun
1971*4882a593Smuzhiyun if (_are_all_hardreset_lines_asserted(oh))
1972*4882a593Smuzhiyun return 0;
1973*4882a593Smuzhiyun
1974*4882a593Smuzhiyun if (oh->_state != _HWMOD_STATE_ENABLED) {
1975*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: idle state can only be entered from enabled state\n",
1976*4882a593Smuzhiyun oh->name);
1977*4882a593Smuzhiyun return -EINVAL;
1978*4882a593Smuzhiyun }
1979*4882a593Smuzhiyun
1980*4882a593Smuzhiyun if (oh->class->sysc)
1981*4882a593Smuzhiyun _idle_sysc(oh);
1982*4882a593Smuzhiyun _del_initiator_dep(oh, mpu_oh);
1983*4882a593Smuzhiyun
1984*4882a593Smuzhiyun /*
1985*4882a593Smuzhiyun * If HWMOD_CLKDM_NOAUTO is set then we don't
1986*4882a593Smuzhiyun * deny idle the clkdm again since idle was already denied
1987*4882a593Smuzhiyun * in _enable()
1988*4882a593Smuzhiyun */
1989*4882a593Smuzhiyun if (oh->clkdm && !(oh->flags & HWMOD_CLKDM_NOAUTO))
1990*4882a593Smuzhiyun clkdm_deny_idle(oh->clkdm);
1991*4882a593Smuzhiyun
1992*4882a593Smuzhiyun if (oh->flags & HWMOD_BLOCK_WFI)
1993*4882a593Smuzhiyun cpu_idle_poll_ctrl(false);
1994*4882a593Smuzhiyun if (soc_ops.disable_module)
1995*4882a593Smuzhiyun soc_ops.disable_module(oh);
1996*4882a593Smuzhiyun
1997*4882a593Smuzhiyun /*
1998*4882a593Smuzhiyun * The module must be in idle mode before disabling any parents
1999*4882a593Smuzhiyun * clocks. Otherwise, the parent clock might be disabled before
2000*4882a593Smuzhiyun * the module transition is done, and thus will prevent the
2001*4882a593Smuzhiyun * transition to complete properly.
2002*4882a593Smuzhiyun */
2003*4882a593Smuzhiyun _disable_clocks(oh);
2004*4882a593Smuzhiyun if (oh->clkdm) {
2005*4882a593Smuzhiyun clkdm_allow_idle(oh->clkdm);
2006*4882a593Smuzhiyun clkdm_hwmod_disable(oh->clkdm, oh);
2007*4882a593Smuzhiyun }
2008*4882a593Smuzhiyun
2009*4882a593Smuzhiyun oh->_state = _HWMOD_STATE_IDLE;
2010*4882a593Smuzhiyun
2011*4882a593Smuzhiyun return 0;
2012*4882a593Smuzhiyun }
2013*4882a593Smuzhiyun
2014*4882a593Smuzhiyun /**
2015*4882a593Smuzhiyun * _shutdown - shutdown an omap_hwmod
2016*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2017*4882a593Smuzhiyun *
2018*4882a593Smuzhiyun * Shut down an omap_hwmod @oh. This should be called when the driver
2019*4882a593Smuzhiyun * used for the hwmod is removed or unloaded or if the driver is not
2020*4882a593Smuzhiyun * used by the system. Returns -EINVAL if the hwmod is in the wrong
2021*4882a593Smuzhiyun * state or returns 0.
2022*4882a593Smuzhiyun */
_shutdown(struct omap_hwmod * oh)2023*4882a593Smuzhiyun static int _shutdown(struct omap_hwmod *oh)
2024*4882a593Smuzhiyun {
2025*4882a593Smuzhiyun int ret, i;
2026*4882a593Smuzhiyun u8 prev_state;
2027*4882a593Smuzhiyun
2028*4882a593Smuzhiyun if (_are_all_hardreset_lines_asserted(oh))
2029*4882a593Smuzhiyun return 0;
2030*4882a593Smuzhiyun
2031*4882a593Smuzhiyun if (oh->_state != _HWMOD_STATE_IDLE &&
2032*4882a593Smuzhiyun oh->_state != _HWMOD_STATE_ENABLED) {
2033*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: disabled state can only be entered from idle, or enabled state\n",
2034*4882a593Smuzhiyun oh->name);
2035*4882a593Smuzhiyun return -EINVAL;
2036*4882a593Smuzhiyun }
2037*4882a593Smuzhiyun
2038*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: disabling\n", oh->name);
2039*4882a593Smuzhiyun
2040*4882a593Smuzhiyun if (oh->class->pre_shutdown) {
2041*4882a593Smuzhiyun prev_state = oh->_state;
2042*4882a593Smuzhiyun if (oh->_state == _HWMOD_STATE_IDLE)
2043*4882a593Smuzhiyun _enable(oh);
2044*4882a593Smuzhiyun ret = oh->class->pre_shutdown(oh);
2045*4882a593Smuzhiyun if (ret) {
2046*4882a593Smuzhiyun if (prev_state == _HWMOD_STATE_IDLE)
2047*4882a593Smuzhiyun _idle(oh);
2048*4882a593Smuzhiyun return ret;
2049*4882a593Smuzhiyun }
2050*4882a593Smuzhiyun }
2051*4882a593Smuzhiyun
2052*4882a593Smuzhiyun if (oh->class->sysc) {
2053*4882a593Smuzhiyun if (oh->_state == _HWMOD_STATE_IDLE)
2054*4882a593Smuzhiyun _enable(oh);
2055*4882a593Smuzhiyun _shutdown_sysc(oh);
2056*4882a593Smuzhiyun }
2057*4882a593Smuzhiyun
2058*4882a593Smuzhiyun /* clocks and deps are already disabled in idle */
2059*4882a593Smuzhiyun if (oh->_state == _HWMOD_STATE_ENABLED) {
2060*4882a593Smuzhiyun _del_initiator_dep(oh, mpu_oh);
2061*4882a593Smuzhiyun /* XXX what about the other system initiators here? dma, dsp */
2062*4882a593Smuzhiyun if (oh->flags & HWMOD_BLOCK_WFI)
2063*4882a593Smuzhiyun cpu_idle_poll_ctrl(false);
2064*4882a593Smuzhiyun if (soc_ops.disable_module)
2065*4882a593Smuzhiyun soc_ops.disable_module(oh);
2066*4882a593Smuzhiyun _disable_clocks(oh);
2067*4882a593Smuzhiyun if (oh->clkdm)
2068*4882a593Smuzhiyun clkdm_hwmod_disable(oh->clkdm, oh);
2069*4882a593Smuzhiyun }
2070*4882a593Smuzhiyun /* XXX Should this code also force-disable the optional clocks? */
2071*4882a593Smuzhiyun
2072*4882a593Smuzhiyun for (i = 0; i < oh->rst_lines_cnt; i++)
2073*4882a593Smuzhiyun _assert_hardreset(oh, oh->rst_lines[i].name);
2074*4882a593Smuzhiyun
2075*4882a593Smuzhiyun oh->_state = _HWMOD_STATE_DISABLED;
2076*4882a593Smuzhiyun
2077*4882a593Smuzhiyun return 0;
2078*4882a593Smuzhiyun }
2079*4882a593Smuzhiyun
of_dev_find_hwmod(struct device_node * np,struct omap_hwmod * oh)2080*4882a593Smuzhiyun static int of_dev_find_hwmod(struct device_node *np,
2081*4882a593Smuzhiyun struct omap_hwmod *oh)
2082*4882a593Smuzhiyun {
2083*4882a593Smuzhiyun int count, i, res;
2084*4882a593Smuzhiyun const char *p;
2085*4882a593Smuzhiyun
2086*4882a593Smuzhiyun count = of_property_count_strings(np, "ti,hwmods");
2087*4882a593Smuzhiyun if (count < 1)
2088*4882a593Smuzhiyun return -ENODEV;
2089*4882a593Smuzhiyun
2090*4882a593Smuzhiyun for (i = 0; i < count; i++) {
2091*4882a593Smuzhiyun res = of_property_read_string_index(np, "ti,hwmods",
2092*4882a593Smuzhiyun i, &p);
2093*4882a593Smuzhiyun if (res)
2094*4882a593Smuzhiyun continue;
2095*4882a593Smuzhiyun if (!strcmp(p, oh->name)) {
2096*4882a593Smuzhiyun pr_debug("omap_hwmod: dt %pOFn[%i] uses hwmod %s\n",
2097*4882a593Smuzhiyun np, i, oh->name);
2098*4882a593Smuzhiyun return i;
2099*4882a593Smuzhiyun }
2100*4882a593Smuzhiyun }
2101*4882a593Smuzhiyun
2102*4882a593Smuzhiyun return -ENODEV;
2103*4882a593Smuzhiyun }
2104*4882a593Smuzhiyun
2105*4882a593Smuzhiyun /**
2106*4882a593Smuzhiyun * of_dev_hwmod_lookup - look up needed hwmod from dt blob
2107*4882a593Smuzhiyun * @np: struct device_node *
2108*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2109*4882a593Smuzhiyun * @index: index of the entry found
2110*4882a593Smuzhiyun * @found: struct device_node * found or NULL
2111*4882a593Smuzhiyun *
2112*4882a593Smuzhiyun * Parse the dt blob and find out needed hwmod. Recursive function is
2113*4882a593Smuzhiyun * implemented to take care hierarchical dt blob parsing.
2114*4882a593Smuzhiyun * Return: Returns 0 on success, -ENODEV when not found.
2115*4882a593Smuzhiyun */
of_dev_hwmod_lookup(struct device_node * np,struct omap_hwmod * oh,int * index,struct device_node ** found)2116*4882a593Smuzhiyun static int of_dev_hwmod_lookup(struct device_node *np,
2117*4882a593Smuzhiyun struct omap_hwmod *oh,
2118*4882a593Smuzhiyun int *index,
2119*4882a593Smuzhiyun struct device_node **found)
2120*4882a593Smuzhiyun {
2121*4882a593Smuzhiyun struct device_node *np0 = NULL;
2122*4882a593Smuzhiyun int res;
2123*4882a593Smuzhiyun
2124*4882a593Smuzhiyun res = of_dev_find_hwmod(np, oh);
2125*4882a593Smuzhiyun if (res >= 0) {
2126*4882a593Smuzhiyun *found = np;
2127*4882a593Smuzhiyun *index = res;
2128*4882a593Smuzhiyun return 0;
2129*4882a593Smuzhiyun }
2130*4882a593Smuzhiyun
2131*4882a593Smuzhiyun for_each_child_of_node(np, np0) {
2132*4882a593Smuzhiyun struct device_node *fc;
2133*4882a593Smuzhiyun int i;
2134*4882a593Smuzhiyun
2135*4882a593Smuzhiyun res = of_dev_hwmod_lookup(np0, oh, &i, &fc);
2136*4882a593Smuzhiyun if (res == 0) {
2137*4882a593Smuzhiyun *found = fc;
2138*4882a593Smuzhiyun *index = i;
2139*4882a593Smuzhiyun return 0;
2140*4882a593Smuzhiyun }
2141*4882a593Smuzhiyun }
2142*4882a593Smuzhiyun
2143*4882a593Smuzhiyun *found = NULL;
2144*4882a593Smuzhiyun *index = 0;
2145*4882a593Smuzhiyun
2146*4882a593Smuzhiyun return -ENODEV;
2147*4882a593Smuzhiyun }
2148*4882a593Smuzhiyun
2149*4882a593Smuzhiyun /**
2150*4882a593Smuzhiyun * omap_hwmod_fix_mpu_rt_idx - fix up mpu_rt_idx register offsets
2151*4882a593Smuzhiyun *
2152*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2153*4882a593Smuzhiyun * @np: struct device_node *
2154*4882a593Smuzhiyun *
2155*4882a593Smuzhiyun * Fix up module register offsets for modules with mpu_rt_idx.
2156*4882a593Smuzhiyun * Only needed for cpsw with interconnect target module defined
2157*4882a593Smuzhiyun * in device tree while still using legacy hwmod platform data
2158*4882a593Smuzhiyun * for rev, sysc and syss registers.
2159*4882a593Smuzhiyun *
2160*4882a593Smuzhiyun * Can be removed when all cpsw hwmod platform data has been
2161*4882a593Smuzhiyun * dropped.
2162*4882a593Smuzhiyun */
omap_hwmod_fix_mpu_rt_idx(struct omap_hwmod * oh,struct device_node * np,struct resource * res)2163*4882a593Smuzhiyun static void omap_hwmod_fix_mpu_rt_idx(struct omap_hwmod *oh,
2164*4882a593Smuzhiyun struct device_node *np,
2165*4882a593Smuzhiyun struct resource *res)
2166*4882a593Smuzhiyun {
2167*4882a593Smuzhiyun struct device_node *child = NULL;
2168*4882a593Smuzhiyun int error;
2169*4882a593Smuzhiyun
2170*4882a593Smuzhiyun child = of_get_next_child(np, child);
2171*4882a593Smuzhiyun if (!child)
2172*4882a593Smuzhiyun return;
2173*4882a593Smuzhiyun
2174*4882a593Smuzhiyun error = of_address_to_resource(child, oh->mpu_rt_idx, res);
2175*4882a593Smuzhiyun if (error)
2176*4882a593Smuzhiyun pr_err("%s: error mapping mpu_rt_idx: %i\n",
2177*4882a593Smuzhiyun __func__, error);
2178*4882a593Smuzhiyun }
2179*4882a593Smuzhiyun
2180*4882a593Smuzhiyun /**
2181*4882a593Smuzhiyun * omap_hwmod_parse_module_range - map module IO range from device tree
2182*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2183*4882a593Smuzhiyun * @np: struct device_node *
2184*4882a593Smuzhiyun *
2185*4882a593Smuzhiyun * Parse the device tree range an interconnect target module provides
2186*4882a593Smuzhiyun * for it's child device IP blocks. This way we can support the old
2187*4882a593Smuzhiyun * "ti,hwmods" property with just dts data without a need for platform
2188*4882a593Smuzhiyun * data for IO resources. And we don't need all the child IP device
2189*4882a593Smuzhiyun * nodes available in the dts.
2190*4882a593Smuzhiyun */
omap_hwmod_parse_module_range(struct omap_hwmod * oh,struct device_node * np,struct resource * res)2191*4882a593Smuzhiyun int omap_hwmod_parse_module_range(struct omap_hwmod *oh,
2192*4882a593Smuzhiyun struct device_node *np,
2193*4882a593Smuzhiyun struct resource *res)
2194*4882a593Smuzhiyun {
2195*4882a593Smuzhiyun struct property *prop;
2196*4882a593Smuzhiyun const __be32 *ranges;
2197*4882a593Smuzhiyun const char *name;
2198*4882a593Smuzhiyun u32 nr_addr, nr_size;
2199*4882a593Smuzhiyun u64 base, size;
2200*4882a593Smuzhiyun int len, error;
2201*4882a593Smuzhiyun
2202*4882a593Smuzhiyun if (!res)
2203*4882a593Smuzhiyun return -EINVAL;
2204*4882a593Smuzhiyun
2205*4882a593Smuzhiyun ranges = of_get_property(np, "ranges", &len);
2206*4882a593Smuzhiyun if (!ranges)
2207*4882a593Smuzhiyun return -ENOENT;
2208*4882a593Smuzhiyun
2209*4882a593Smuzhiyun len /= sizeof(*ranges);
2210*4882a593Smuzhiyun
2211*4882a593Smuzhiyun if (len < 3)
2212*4882a593Smuzhiyun return -EINVAL;
2213*4882a593Smuzhiyun
2214*4882a593Smuzhiyun of_property_for_each_string(np, "compatible", prop, name)
2215*4882a593Smuzhiyun if (!strncmp("ti,sysc-", name, 8))
2216*4882a593Smuzhiyun break;
2217*4882a593Smuzhiyun
2218*4882a593Smuzhiyun if (!name)
2219*4882a593Smuzhiyun return -ENOENT;
2220*4882a593Smuzhiyun
2221*4882a593Smuzhiyun error = of_property_read_u32(np, "#address-cells", &nr_addr);
2222*4882a593Smuzhiyun if (error)
2223*4882a593Smuzhiyun return -ENOENT;
2224*4882a593Smuzhiyun
2225*4882a593Smuzhiyun error = of_property_read_u32(np, "#size-cells", &nr_size);
2226*4882a593Smuzhiyun if (error)
2227*4882a593Smuzhiyun return -ENOENT;
2228*4882a593Smuzhiyun
2229*4882a593Smuzhiyun if (nr_addr != 1 || nr_size != 1) {
2230*4882a593Smuzhiyun pr_err("%s: invalid range for %s->%pOFn\n", __func__,
2231*4882a593Smuzhiyun oh->name, np);
2232*4882a593Smuzhiyun return -EINVAL;
2233*4882a593Smuzhiyun }
2234*4882a593Smuzhiyun
2235*4882a593Smuzhiyun ranges++;
2236*4882a593Smuzhiyun base = of_translate_address(np, ranges++);
2237*4882a593Smuzhiyun size = be32_to_cpup(ranges);
2238*4882a593Smuzhiyun
2239*4882a593Smuzhiyun pr_debug("omap_hwmod: %s %pOFn at 0x%llx size 0x%llx\n",
2240*4882a593Smuzhiyun oh->name, np, base, size);
2241*4882a593Smuzhiyun
2242*4882a593Smuzhiyun if (oh && oh->mpu_rt_idx) {
2243*4882a593Smuzhiyun omap_hwmod_fix_mpu_rt_idx(oh, np, res);
2244*4882a593Smuzhiyun
2245*4882a593Smuzhiyun return 0;
2246*4882a593Smuzhiyun }
2247*4882a593Smuzhiyun
2248*4882a593Smuzhiyun res->start = base;
2249*4882a593Smuzhiyun res->end = base + size - 1;
2250*4882a593Smuzhiyun res->flags = IORESOURCE_MEM;
2251*4882a593Smuzhiyun
2252*4882a593Smuzhiyun return 0;
2253*4882a593Smuzhiyun }
2254*4882a593Smuzhiyun
2255*4882a593Smuzhiyun /**
2256*4882a593Smuzhiyun * _init_mpu_rt_base - populate the virtual address for a hwmod
2257*4882a593Smuzhiyun * @oh: struct omap_hwmod * to locate the virtual address
2258*4882a593Smuzhiyun * @data: (unused, caller should pass NULL)
2259*4882a593Smuzhiyun * @index: index of the reg entry iospace in device tree
2260*4882a593Smuzhiyun * @np: struct device_node * of the IP block's device node in the DT data
2261*4882a593Smuzhiyun *
2262*4882a593Smuzhiyun * Cache the virtual address used by the MPU to access this IP block's
2263*4882a593Smuzhiyun * registers. This address is needed early so the OCP registers that
2264*4882a593Smuzhiyun * are part of the device's address space can be ioremapped properly.
2265*4882a593Smuzhiyun *
2266*4882a593Smuzhiyun * If SYSC access is not needed, the registers will not be remapped
2267*4882a593Smuzhiyun * and non-availability of MPU access is not treated as an error.
2268*4882a593Smuzhiyun *
2269*4882a593Smuzhiyun * Returns 0 on success, -EINVAL if an invalid hwmod is passed, and
2270*4882a593Smuzhiyun * -ENXIO on absent or invalid register target address space.
2271*4882a593Smuzhiyun */
_init_mpu_rt_base(struct omap_hwmod * oh,void * data,int index,struct device_node * np)2272*4882a593Smuzhiyun static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
2273*4882a593Smuzhiyun int index, struct device_node *np)
2274*4882a593Smuzhiyun {
2275*4882a593Smuzhiyun void __iomem *va_start = NULL;
2276*4882a593Smuzhiyun struct resource res;
2277*4882a593Smuzhiyun int error;
2278*4882a593Smuzhiyun
2279*4882a593Smuzhiyun if (!oh)
2280*4882a593Smuzhiyun return -EINVAL;
2281*4882a593Smuzhiyun
2282*4882a593Smuzhiyun _save_mpu_port_index(oh);
2283*4882a593Smuzhiyun
2284*4882a593Smuzhiyun /* if we don't need sysc access we don't need to ioremap */
2285*4882a593Smuzhiyun if (!oh->class->sysc)
2286*4882a593Smuzhiyun return 0;
2287*4882a593Smuzhiyun
2288*4882a593Smuzhiyun /* we can't continue without MPU PORT if we need sysc access */
2289*4882a593Smuzhiyun if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
2290*4882a593Smuzhiyun return -ENXIO;
2291*4882a593Smuzhiyun
2292*4882a593Smuzhiyun if (!np) {
2293*4882a593Smuzhiyun pr_err("omap_hwmod: %s: no dt node\n", oh->name);
2294*4882a593Smuzhiyun return -ENXIO;
2295*4882a593Smuzhiyun }
2296*4882a593Smuzhiyun
2297*4882a593Smuzhiyun /* Do we have a dts range for the interconnect target module? */
2298*4882a593Smuzhiyun error = omap_hwmod_parse_module_range(oh, np, &res);
2299*4882a593Smuzhiyun if (!error)
2300*4882a593Smuzhiyun va_start = ioremap(res.start, resource_size(&res));
2301*4882a593Smuzhiyun
2302*4882a593Smuzhiyun /* No ranges, rely on device reg entry */
2303*4882a593Smuzhiyun if (!va_start)
2304*4882a593Smuzhiyun va_start = of_iomap(np, index + oh->mpu_rt_idx);
2305*4882a593Smuzhiyun if (!va_start) {
2306*4882a593Smuzhiyun pr_err("omap_hwmod: %s: Missing dt reg%i for %pOF\n",
2307*4882a593Smuzhiyun oh->name, index, np);
2308*4882a593Smuzhiyun return -ENXIO;
2309*4882a593Smuzhiyun }
2310*4882a593Smuzhiyun
2311*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: MPU register target at va %p\n",
2312*4882a593Smuzhiyun oh->name, va_start);
2313*4882a593Smuzhiyun
2314*4882a593Smuzhiyun oh->_mpu_rt_va = va_start;
2315*4882a593Smuzhiyun return 0;
2316*4882a593Smuzhiyun }
2317*4882a593Smuzhiyun
parse_module_flags(struct omap_hwmod * oh,struct device_node * np)2318*4882a593Smuzhiyun static void __init parse_module_flags(struct omap_hwmod *oh,
2319*4882a593Smuzhiyun struct device_node *np)
2320*4882a593Smuzhiyun {
2321*4882a593Smuzhiyun if (of_find_property(np, "ti,no-reset-on-init", NULL))
2322*4882a593Smuzhiyun oh->flags |= HWMOD_INIT_NO_RESET;
2323*4882a593Smuzhiyun if (of_find_property(np, "ti,no-idle-on-init", NULL))
2324*4882a593Smuzhiyun oh->flags |= HWMOD_INIT_NO_IDLE;
2325*4882a593Smuzhiyun if (of_find_property(np, "ti,no-idle", NULL))
2326*4882a593Smuzhiyun oh->flags |= HWMOD_NO_IDLE;
2327*4882a593Smuzhiyun }
2328*4882a593Smuzhiyun
2329*4882a593Smuzhiyun /**
2330*4882a593Smuzhiyun * _init - initialize internal data for the hwmod @oh
2331*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2332*4882a593Smuzhiyun * @n: (unused)
2333*4882a593Smuzhiyun *
2334*4882a593Smuzhiyun * Look up the clocks and the address space used by the MPU to access
2335*4882a593Smuzhiyun * registers belonging to the hwmod @oh. @oh must already be
2336*4882a593Smuzhiyun * registered at this point. This is the first of two phases for
2337*4882a593Smuzhiyun * hwmod initialization. Code called here does not touch any hardware
2338*4882a593Smuzhiyun * registers, it simply prepares internal data structures. Returns 0
2339*4882a593Smuzhiyun * upon success or if the hwmod isn't registered or if the hwmod's
2340*4882a593Smuzhiyun * address space is not defined, or -EINVAL upon failure.
2341*4882a593Smuzhiyun */
_init(struct omap_hwmod * oh,void * data)2342*4882a593Smuzhiyun static int __init _init(struct omap_hwmod *oh, void *data)
2343*4882a593Smuzhiyun {
2344*4882a593Smuzhiyun int r, index;
2345*4882a593Smuzhiyun struct device_node *np = NULL;
2346*4882a593Smuzhiyun struct device_node *bus;
2347*4882a593Smuzhiyun
2348*4882a593Smuzhiyun if (oh->_state != _HWMOD_STATE_REGISTERED)
2349*4882a593Smuzhiyun return 0;
2350*4882a593Smuzhiyun
2351*4882a593Smuzhiyun bus = of_find_node_by_name(NULL, "ocp");
2352*4882a593Smuzhiyun if (!bus)
2353*4882a593Smuzhiyun return -ENODEV;
2354*4882a593Smuzhiyun
2355*4882a593Smuzhiyun r = of_dev_hwmod_lookup(bus, oh, &index, &np);
2356*4882a593Smuzhiyun if (r)
2357*4882a593Smuzhiyun pr_debug("omap_hwmod: %s missing dt data\n", oh->name);
2358*4882a593Smuzhiyun else if (np && index)
2359*4882a593Smuzhiyun pr_warn("omap_hwmod: %s using broken dt data from %pOFn\n",
2360*4882a593Smuzhiyun oh->name, np);
2361*4882a593Smuzhiyun
2362*4882a593Smuzhiyun r = _init_mpu_rt_base(oh, NULL, index, np);
2363*4882a593Smuzhiyun if (r < 0) {
2364*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: doesn't have mpu register target base\n",
2365*4882a593Smuzhiyun oh->name);
2366*4882a593Smuzhiyun return 0;
2367*4882a593Smuzhiyun }
2368*4882a593Smuzhiyun
2369*4882a593Smuzhiyun r = _init_clocks(oh, np);
2370*4882a593Smuzhiyun if (r < 0) {
2371*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh->name);
2372*4882a593Smuzhiyun return -EINVAL;
2373*4882a593Smuzhiyun }
2374*4882a593Smuzhiyun
2375*4882a593Smuzhiyun if (np) {
2376*4882a593Smuzhiyun struct device_node *child;
2377*4882a593Smuzhiyun
2378*4882a593Smuzhiyun parse_module_flags(oh, np);
2379*4882a593Smuzhiyun child = of_get_next_child(np, NULL);
2380*4882a593Smuzhiyun if (child)
2381*4882a593Smuzhiyun parse_module_flags(oh, child);
2382*4882a593Smuzhiyun }
2383*4882a593Smuzhiyun
2384*4882a593Smuzhiyun oh->_state = _HWMOD_STATE_INITIALIZED;
2385*4882a593Smuzhiyun
2386*4882a593Smuzhiyun return 0;
2387*4882a593Smuzhiyun }
2388*4882a593Smuzhiyun
2389*4882a593Smuzhiyun /**
2390*4882a593Smuzhiyun * _setup_iclk_autoidle - configure an IP block's interface clocks
2391*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2392*4882a593Smuzhiyun *
2393*4882a593Smuzhiyun * Set up the module's interface clocks. XXX This function is still mostly
2394*4882a593Smuzhiyun * a stub; implementing this properly requires iclk autoidle usecounting in
2395*4882a593Smuzhiyun * the clock code. No return value.
2396*4882a593Smuzhiyun */
_setup_iclk_autoidle(struct omap_hwmod * oh)2397*4882a593Smuzhiyun static void _setup_iclk_autoidle(struct omap_hwmod *oh)
2398*4882a593Smuzhiyun {
2399*4882a593Smuzhiyun struct omap_hwmod_ocp_if *os;
2400*4882a593Smuzhiyun
2401*4882a593Smuzhiyun if (oh->_state != _HWMOD_STATE_INITIALIZED)
2402*4882a593Smuzhiyun return;
2403*4882a593Smuzhiyun
2404*4882a593Smuzhiyun list_for_each_entry(os, &oh->slave_ports, node) {
2405*4882a593Smuzhiyun if (!os->_clk)
2406*4882a593Smuzhiyun continue;
2407*4882a593Smuzhiyun
2408*4882a593Smuzhiyun if (os->flags & OCPIF_SWSUP_IDLE) {
2409*4882a593Smuzhiyun /*
2410*4882a593Smuzhiyun * we might have multiple users of one iclk with
2411*4882a593Smuzhiyun * different requirements, disable autoidle when
2412*4882a593Smuzhiyun * the module is enabled, e.g. dss iclk
2413*4882a593Smuzhiyun */
2414*4882a593Smuzhiyun } else {
2415*4882a593Smuzhiyun /* we are enabling autoidle afterwards anyways */
2416*4882a593Smuzhiyun clk_enable(os->_clk);
2417*4882a593Smuzhiyun }
2418*4882a593Smuzhiyun }
2419*4882a593Smuzhiyun
2420*4882a593Smuzhiyun return;
2421*4882a593Smuzhiyun }
2422*4882a593Smuzhiyun
2423*4882a593Smuzhiyun /**
2424*4882a593Smuzhiyun * _setup_reset - reset an IP block during the setup process
2425*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2426*4882a593Smuzhiyun *
2427*4882a593Smuzhiyun * Reset the IP block corresponding to the hwmod @oh during the setup
2428*4882a593Smuzhiyun * process. The IP block is first enabled so it can be successfully
2429*4882a593Smuzhiyun * reset. Returns 0 upon success or a negative error code upon
2430*4882a593Smuzhiyun * failure.
2431*4882a593Smuzhiyun */
_setup_reset(struct omap_hwmod * oh)2432*4882a593Smuzhiyun static int _setup_reset(struct omap_hwmod *oh)
2433*4882a593Smuzhiyun {
2434*4882a593Smuzhiyun int r = 0;
2435*4882a593Smuzhiyun
2436*4882a593Smuzhiyun if (oh->_state != _HWMOD_STATE_INITIALIZED)
2437*4882a593Smuzhiyun return -EINVAL;
2438*4882a593Smuzhiyun
2439*4882a593Smuzhiyun if (oh->flags & HWMOD_EXT_OPT_MAIN_CLK)
2440*4882a593Smuzhiyun return -EPERM;
2441*4882a593Smuzhiyun
2442*4882a593Smuzhiyun if (oh->rst_lines_cnt == 0) {
2443*4882a593Smuzhiyun r = _enable(oh);
2444*4882a593Smuzhiyun if (r) {
2445*4882a593Smuzhiyun pr_warn("omap_hwmod: %s: cannot be enabled for reset (%d)\n",
2446*4882a593Smuzhiyun oh->name, oh->_state);
2447*4882a593Smuzhiyun return -EINVAL;
2448*4882a593Smuzhiyun }
2449*4882a593Smuzhiyun }
2450*4882a593Smuzhiyun
2451*4882a593Smuzhiyun if (!(oh->flags & HWMOD_INIT_NO_RESET))
2452*4882a593Smuzhiyun r = _reset(oh);
2453*4882a593Smuzhiyun
2454*4882a593Smuzhiyun return r;
2455*4882a593Smuzhiyun }
2456*4882a593Smuzhiyun
2457*4882a593Smuzhiyun /**
2458*4882a593Smuzhiyun * _setup_postsetup - transition to the appropriate state after _setup
2459*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2460*4882a593Smuzhiyun *
2461*4882a593Smuzhiyun * Place an IP block represented by @oh into a "post-setup" state --
2462*4882a593Smuzhiyun * either IDLE, ENABLED, or DISABLED. ("post-setup" simply means that
2463*4882a593Smuzhiyun * this function is called at the end of _setup().) The postsetup
2464*4882a593Smuzhiyun * state for an IP block can be changed by calling
2465*4882a593Smuzhiyun * omap_hwmod_enter_postsetup_state() early in the boot process,
2466*4882a593Smuzhiyun * before one of the omap_hwmod_setup*() functions are called for the
2467*4882a593Smuzhiyun * IP block.
2468*4882a593Smuzhiyun *
2469*4882a593Smuzhiyun * The IP block stays in this state until a PM runtime-based driver is
2470*4882a593Smuzhiyun * loaded for that IP block. A post-setup state of IDLE is
2471*4882a593Smuzhiyun * appropriate for almost all IP blocks with runtime PM-enabled
2472*4882a593Smuzhiyun * drivers, since those drivers are able to enable the IP block. A
2473*4882a593Smuzhiyun * post-setup state of ENABLED is appropriate for kernels with PM
2474*4882a593Smuzhiyun * runtime disabled. The DISABLED state is appropriate for unusual IP
2475*4882a593Smuzhiyun * blocks such as the MPU WDTIMER on kernels without WDTIMER drivers
2476*4882a593Smuzhiyun * included, since the WDTIMER starts running on reset and will reset
2477*4882a593Smuzhiyun * the MPU if left active.
2478*4882a593Smuzhiyun *
2479*4882a593Smuzhiyun * This post-setup mechanism is deprecated. Once all of the OMAP
2480*4882a593Smuzhiyun * drivers have been converted to use PM runtime, and all of the IP
2481*4882a593Smuzhiyun * block data and interconnect data is available to the hwmod code, it
2482*4882a593Smuzhiyun * should be possible to replace this mechanism with a "lazy reset"
2483*4882a593Smuzhiyun * arrangement. In a "lazy reset" setup, each IP block is enabled
2484*4882a593Smuzhiyun * when the driver first probes, then all remaining IP blocks without
2485*4882a593Smuzhiyun * drivers are either shut down or enabled after the drivers have
2486*4882a593Smuzhiyun * loaded. However, this cannot take place until the above
2487*4882a593Smuzhiyun * preconditions have been met, since otherwise the late reset code
2488*4882a593Smuzhiyun * has no way of knowing which IP blocks are in use by drivers, and
2489*4882a593Smuzhiyun * which ones are unused.
2490*4882a593Smuzhiyun *
2491*4882a593Smuzhiyun * No return value.
2492*4882a593Smuzhiyun */
_setup_postsetup(struct omap_hwmod * oh)2493*4882a593Smuzhiyun static void _setup_postsetup(struct omap_hwmod *oh)
2494*4882a593Smuzhiyun {
2495*4882a593Smuzhiyun u8 postsetup_state;
2496*4882a593Smuzhiyun
2497*4882a593Smuzhiyun if (oh->rst_lines_cnt > 0)
2498*4882a593Smuzhiyun return;
2499*4882a593Smuzhiyun
2500*4882a593Smuzhiyun postsetup_state = oh->_postsetup_state;
2501*4882a593Smuzhiyun if (postsetup_state == _HWMOD_STATE_UNKNOWN)
2502*4882a593Smuzhiyun postsetup_state = _HWMOD_STATE_ENABLED;
2503*4882a593Smuzhiyun
2504*4882a593Smuzhiyun /*
2505*4882a593Smuzhiyun * XXX HWMOD_INIT_NO_IDLE does not belong in hwmod data -
2506*4882a593Smuzhiyun * it should be set by the core code as a runtime flag during startup
2507*4882a593Smuzhiyun */
2508*4882a593Smuzhiyun if ((oh->flags & (HWMOD_INIT_NO_IDLE | HWMOD_NO_IDLE)) &&
2509*4882a593Smuzhiyun (postsetup_state == _HWMOD_STATE_IDLE)) {
2510*4882a593Smuzhiyun oh->_int_flags |= _HWMOD_SKIP_ENABLE;
2511*4882a593Smuzhiyun postsetup_state = _HWMOD_STATE_ENABLED;
2512*4882a593Smuzhiyun }
2513*4882a593Smuzhiyun
2514*4882a593Smuzhiyun if (postsetup_state == _HWMOD_STATE_IDLE)
2515*4882a593Smuzhiyun _idle(oh);
2516*4882a593Smuzhiyun else if (postsetup_state == _HWMOD_STATE_DISABLED)
2517*4882a593Smuzhiyun _shutdown(oh);
2518*4882a593Smuzhiyun else if (postsetup_state != _HWMOD_STATE_ENABLED)
2519*4882a593Smuzhiyun WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n",
2520*4882a593Smuzhiyun oh->name, postsetup_state);
2521*4882a593Smuzhiyun
2522*4882a593Smuzhiyun return;
2523*4882a593Smuzhiyun }
2524*4882a593Smuzhiyun
2525*4882a593Smuzhiyun /**
2526*4882a593Smuzhiyun * _setup - prepare IP block hardware for use
2527*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2528*4882a593Smuzhiyun * @n: (unused, pass NULL)
2529*4882a593Smuzhiyun *
2530*4882a593Smuzhiyun * Configure the IP block represented by @oh. This may include
2531*4882a593Smuzhiyun * enabling the IP block, resetting it, and placing it into a
2532*4882a593Smuzhiyun * post-setup state, depending on the type of IP block and applicable
2533*4882a593Smuzhiyun * flags. IP blocks are reset to prevent any previous configuration
2534*4882a593Smuzhiyun * by the bootloader or previous operating system from interfering
2535*4882a593Smuzhiyun * with power management or other parts of the system. The reset can
2536*4882a593Smuzhiyun * be avoided; see omap_hwmod_no_setup_reset(). This is the second of
2537*4882a593Smuzhiyun * two phases for hwmod initialization. Code called here generally
2538*4882a593Smuzhiyun * affects the IP block hardware, or system integration hardware
2539*4882a593Smuzhiyun * associated with the IP block. Returns 0.
2540*4882a593Smuzhiyun */
_setup(struct omap_hwmod * oh,void * data)2541*4882a593Smuzhiyun static int _setup(struct omap_hwmod *oh, void *data)
2542*4882a593Smuzhiyun {
2543*4882a593Smuzhiyun if (oh->_state != _HWMOD_STATE_INITIALIZED)
2544*4882a593Smuzhiyun return 0;
2545*4882a593Smuzhiyun
2546*4882a593Smuzhiyun if (oh->parent_hwmod) {
2547*4882a593Smuzhiyun int r;
2548*4882a593Smuzhiyun
2549*4882a593Smuzhiyun r = _enable(oh->parent_hwmod);
2550*4882a593Smuzhiyun WARN(r, "hwmod: %s: setup: failed to enable parent hwmod %s\n",
2551*4882a593Smuzhiyun oh->name, oh->parent_hwmod->name);
2552*4882a593Smuzhiyun }
2553*4882a593Smuzhiyun
2554*4882a593Smuzhiyun _setup_iclk_autoidle(oh);
2555*4882a593Smuzhiyun
2556*4882a593Smuzhiyun if (!_setup_reset(oh))
2557*4882a593Smuzhiyun _setup_postsetup(oh);
2558*4882a593Smuzhiyun
2559*4882a593Smuzhiyun if (oh->parent_hwmod) {
2560*4882a593Smuzhiyun u8 postsetup_state;
2561*4882a593Smuzhiyun
2562*4882a593Smuzhiyun postsetup_state = oh->parent_hwmod->_postsetup_state;
2563*4882a593Smuzhiyun
2564*4882a593Smuzhiyun if (postsetup_state == _HWMOD_STATE_IDLE)
2565*4882a593Smuzhiyun _idle(oh->parent_hwmod);
2566*4882a593Smuzhiyun else if (postsetup_state == _HWMOD_STATE_DISABLED)
2567*4882a593Smuzhiyun _shutdown(oh->parent_hwmod);
2568*4882a593Smuzhiyun else if (postsetup_state != _HWMOD_STATE_ENABLED)
2569*4882a593Smuzhiyun WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n",
2570*4882a593Smuzhiyun oh->parent_hwmod->name, postsetup_state);
2571*4882a593Smuzhiyun }
2572*4882a593Smuzhiyun
2573*4882a593Smuzhiyun return 0;
2574*4882a593Smuzhiyun }
2575*4882a593Smuzhiyun
2576*4882a593Smuzhiyun /**
2577*4882a593Smuzhiyun * _register - register a struct omap_hwmod
2578*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2579*4882a593Smuzhiyun *
2580*4882a593Smuzhiyun * Registers the omap_hwmod @oh. Returns -EEXIST if an omap_hwmod
2581*4882a593Smuzhiyun * already has been registered by the same name; -EINVAL if the
2582*4882a593Smuzhiyun * omap_hwmod is in the wrong state, if @oh is NULL, if the
2583*4882a593Smuzhiyun * omap_hwmod's class field is NULL; if the omap_hwmod is missing a
2584*4882a593Smuzhiyun * name, or if the omap_hwmod's class is missing a name; or 0 upon
2585*4882a593Smuzhiyun * success.
2586*4882a593Smuzhiyun *
2587*4882a593Smuzhiyun * XXX The data should be copied into bootmem, so the original data
2588*4882a593Smuzhiyun * should be marked __initdata and freed after init. This would allow
2589*4882a593Smuzhiyun * unneeded omap_hwmods to be freed on multi-OMAP configurations. Note
2590*4882a593Smuzhiyun * that the copy process would be relatively complex due to the large number
2591*4882a593Smuzhiyun * of substructures.
2592*4882a593Smuzhiyun */
_register(struct omap_hwmod * oh)2593*4882a593Smuzhiyun static int _register(struct omap_hwmod *oh)
2594*4882a593Smuzhiyun {
2595*4882a593Smuzhiyun if (!oh || !oh->name || !oh->class || !oh->class->name ||
2596*4882a593Smuzhiyun (oh->_state != _HWMOD_STATE_UNKNOWN))
2597*4882a593Smuzhiyun return -EINVAL;
2598*4882a593Smuzhiyun
2599*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: registering\n", oh->name);
2600*4882a593Smuzhiyun
2601*4882a593Smuzhiyun if (_lookup(oh->name))
2602*4882a593Smuzhiyun return -EEXIST;
2603*4882a593Smuzhiyun
2604*4882a593Smuzhiyun list_add_tail(&oh->node, &omap_hwmod_list);
2605*4882a593Smuzhiyun
2606*4882a593Smuzhiyun INIT_LIST_HEAD(&oh->slave_ports);
2607*4882a593Smuzhiyun spin_lock_init(&oh->_lock);
2608*4882a593Smuzhiyun lockdep_set_class(&oh->_lock, &oh->hwmod_key);
2609*4882a593Smuzhiyun
2610*4882a593Smuzhiyun oh->_state = _HWMOD_STATE_REGISTERED;
2611*4882a593Smuzhiyun
2612*4882a593Smuzhiyun /*
2613*4882a593Smuzhiyun * XXX Rather than doing a strcmp(), this should test a flag
2614*4882a593Smuzhiyun * set in the hwmod data, inserted by the autogenerator code.
2615*4882a593Smuzhiyun */
2616*4882a593Smuzhiyun if (!strcmp(oh->name, MPU_INITIATOR_NAME))
2617*4882a593Smuzhiyun mpu_oh = oh;
2618*4882a593Smuzhiyun
2619*4882a593Smuzhiyun return 0;
2620*4882a593Smuzhiyun }
2621*4882a593Smuzhiyun
2622*4882a593Smuzhiyun /**
2623*4882a593Smuzhiyun * _add_link - add an interconnect between two IP blocks
2624*4882a593Smuzhiyun * @oi: pointer to a struct omap_hwmod_ocp_if record
2625*4882a593Smuzhiyun *
2626*4882a593Smuzhiyun * Add struct omap_hwmod_link records connecting the slave IP block
2627*4882a593Smuzhiyun * specified in @oi->slave to @oi. This code is assumed to run before
2628*4882a593Smuzhiyun * preemption or SMP has been enabled, thus avoiding the need for
2629*4882a593Smuzhiyun * locking in this code. Changes to this assumption will require
2630*4882a593Smuzhiyun * additional locking. Returns 0.
2631*4882a593Smuzhiyun */
_add_link(struct omap_hwmod_ocp_if * oi)2632*4882a593Smuzhiyun static int _add_link(struct omap_hwmod_ocp_if *oi)
2633*4882a593Smuzhiyun {
2634*4882a593Smuzhiyun pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name,
2635*4882a593Smuzhiyun oi->slave->name);
2636*4882a593Smuzhiyun
2637*4882a593Smuzhiyun list_add(&oi->node, &oi->slave->slave_ports);
2638*4882a593Smuzhiyun oi->slave->slaves_cnt++;
2639*4882a593Smuzhiyun
2640*4882a593Smuzhiyun return 0;
2641*4882a593Smuzhiyun }
2642*4882a593Smuzhiyun
2643*4882a593Smuzhiyun /**
2644*4882a593Smuzhiyun * _register_link - register a struct omap_hwmod_ocp_if
2645*4882a593Smuzhiyun * @oi: struct omap_hwmod_ocp_if *
2646*4882a593Smuzhiyun *
2647*4882a593Smuzhiyun * Registers the omap_hwmod_ocp_if record @oi. Returns -EEXIST if it
2648*4882a593Smuzhiyun * has already been registered; -EINVAL if @oi is NULL or if the
2649*4882a593Smuzhiyun * record pointed to by @oi is missing required fields; or 0 upon
2650*4882a593Smuzhiyun * success.
2651*4882a593Smuzhiyun *
2652*4882a593Smuzhiyun * XXX The data should be copied into bootmem, so the original data
2653*4882a593Smuzhiyun * should be marked __initdata and freed after init. This would allow
2654*4882a593Smuzhiyun * unneeded omap_hwmods to be freed on multi-OMAP configurations.
2655*4882a593Smuzhiyun */
_register_link(struct omap_hwmod_ocp_if * oi)2656*4882a593Smuzhiyun static int __init _register_link(struct omap_hwmod_ocp_if *oi)
2657*4882a593Smuzhiyun {
2658*4882a593Smuzhiyun if (!oi || !oi->master || !oi->slave || !oi->user)
2659*4882a593Smuzhiyun return -EINVAL;
2660*4882a593Smuzhiyun
2661*4882a593Smuzhiyun if (oi->_int_flags & _OCPIF_INT_FLAGS_REGISTERED)
2662*4882a593Smuzhiyun return -EEXIST;
2663*4882a593Smuzhiyun
2664*4882a593Smuzhiyun pr_debug("omap_hwmod: registering link from %s to %s\n",
2665*4882a593Smuzhiyun oi->master->name, oi->slave->name);
2666*4882a593Smuzhiyun
2667*4882a593Smuzhiyun /*
2668*4882a593Smuzhiyun * Register the connected hwmods, if they haven't been
2669*4882a593Smuzhiyun * registered already
2670*4882a593Smuzhiyun */
2671*4882a593Smuzhiyun if (oi->master->_state != _HWMOD_STATE_REGISTERED)
2672*4882a593Smuzhiyun _register(oi->master);
2673*4882a593Smuzhiyun
2674*4882a593Smuzhiyun if (oi->slave->_state != _HWMOD_STATE_REGISTERED)
2675*4882a593Smuzhiyun _register(oi->slave);
2676*4882a593Smuzhiyun
2677*4882a593Smuzhiyun _add_link(oi);
2678*4882a593Smuzhiyun
2679*4882a593Smuzhiyun oi->_int_flags |= _OCPIF_INT_FLAGS_REGISTERED;
2680*4882a593Smuzhiyun
2681*4882a593Smuzhiyun return 0;
2682*4882a593Smuzhiyun }
2683*4882a593Smuzhiyun
2684*4882a593Smuzhiyun /* Static functions intended only for use in soc_ops field function pointers */
2685*4882a593Smuzhiyun
2686*4882a593Smuzhiyun /**
2687*4882a593Smuzhiyun * _omap2xxx_3xxx_wait_target_ready - wait for a module to leave slave idle
2688*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2689*4882a593Smuzhiyun *
2690*4882a593Smuzhiyun * Wait for a module @oh to leave slave idle. Returns 0 if the module
2691*4882a593Smuzhiyun * does not have an IDLEST bit or if the module successfully leaves
2692*4882a593Smuzhiyun * slave idle; otherwise, pass along the return value of the
2693*4882a593Smuzhiyun * appropriate *_cm*_wait_module_ready() function.
2694*4882a593Smuzhiyun */
_omap2xxx_3xxx_wait_target_ready(struct omap_hwmod * oh)2695*4882a593Smuzhiyun static int _omap2xxx_3xxx_wait_target_ready(struct omap_hwmod *oh)
2696*4882a593Smuzhiyun {
2697*4882a593Smuzhiyun if (!oh)
2698*4882a593Smuzhiyun return -EINVAL;
2699*4882a593Smuzhiyun
2700*4882a593Smuzhiyun if (oh->flags & HWMOD_NO_IDLEST)
2701*4882a593Smuzhiyun return 0;
2702*4882a593Smuzhiyun
2703*4882a593Smuzhiyun if (!_find_mpu_rt_port(oh))
2704*4882a593Smuzhiyun return 0;
2705*4882a593Smuzhiyun
2706*4882a593Smuzhiyun /* XXX check module SIDLEMODE, hardreset status, enabled clocks */
2707*4882a593Smuzhiyun
2708*4882a593Smuzhiyun return omap_cm_wait_module_ready(0, oh->prcm.omap2.module_offs,
2709*4882a593Smuzhiyun oh->prcm.omap2.idlest_reg_id,
2710*4882a593Smuzhiyun oh->prcm.omap2.idlest_idle_bit);
2711*4882a593Smuzhiyun }
2712*4882a593Smuzhiyun
2713*4882a593Smuzhiyun /**
2714*4882a593Smuzhiyun * _omap4_wait_target_ready - wait for a module to leave slave idle
2715*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2716*4882a593Smuzhiyun *
2717*4882a593Smuzhiyun * Wait for a module @oh to leave slave idle. Returns 0 if the module
2718*4882a593Smuzhiyun * does not have an IDLEST bit or if the module successfully leaves
2719*4882a593Smuzhiyun * slave idle; otherwise, pass along the return value of the
2720*4882a593Smuzhiyun * appropriate *_cm*_wait_module_ready() function.
2721*4882a593Smuzhiyun */
_omap4_wait_target_ready(struct omap_hwmod * oh)2722*4882a593Smuzhiyun static int _omap4_wait_target_ready(struct omap_hwmod *oh)
2723*4882a593Smuzhiyun {
2724*4882a593Smuzhiyun if (!oh)
2725*4882a593Smuzhiyun return -EINVAL;
2726*4882a593Smuzhiyun
2727*4882a593Smuzhiyun if (oh->flags & HWMOD_NO_IDLEST || !oh->clkdm)
2728*4882a593Smuzhiyun return 0;
2729*4882a593Smuzhiyun
2730*4882a593Smuzhiyun if (!_find_mpu_rt_port(oh))
2731*4882a593Smuzhiyun return 0;
2732*4882a593Smuzhiyun
2733*4882a593Smuzhiyun if (_omap4_clkctrl_managed_by_clkfwk(oh))
2734*4882a593Smuzhiyun return 0;
2735*4882a593Smuzhiyun
2736*4882a593Smuzhiyun if (!_omap4_has_clkctrl_clock(oh))
2737*4882a593Smuzhiyun return 0;
2738*4882a593Smuzhiyun
2739*4882a593Smuzhiyun /* XXX check module SIDLEMODE, hardreset status */
2740*4882a593Smuzhiyun
2741*4882a593Smuzhiyun return omap_cm_wait_module_ready(oh->clkdm->prcm_partition,
2742*4882a593Smuzhiyun oh->clkdm->cm_inst,
2743*4882a593Smuzhiyun oh->prcm.omap4.clkctrl_offs, 0);
2744*4882a593Smuzhiyun }
2745*4882a593Smuzhiyun
2746*4882a593Smuzhiyun /**
2747*4882a593Smuzhiyun * _omap2_assert_hardreset - call OMAP2 PRM hardreset fn with hwmod args
2748*4882a593Smuzhiyun * @oh: struct omap_hwmod * to assert hardreset
2749*4882a593Smuzhiyun * @ohri: hardreset line data
2750*4882a593Smuzhiyun *
2751*4882a593Smuzhiyun * Call omap2_prm_assert_hardreset() with parameters extracted from
2752*4882a593Smuzhiyun * the hwmod @oh and the hardreset line data @ohri. Only intended for
2753*4882a593Smuzhiyun * use as an soc_ops function pointer. Passes along the return value
2754*4882a593Smuzhiyun * from omap2_prm_assert_hardreset(). XXX This function is scheduled
2755*4882a593Smuzhiyun * for removal when the PRM code is moved into drivers/.
2756*4882a593Smuzhiyun */
_omap2_assert_hardreset(struct omap_hwmod * oh,struct omap_hwmod_rst_info * ohri)2757*4882a593Smuzhiyun static int _omap2_assert_hardreset(struct omap_hwmod *oh,
2758*4882a593Smuzhiyun struct omap_hwmod_rst_info *ohri)
2759*4882a593Smuzhiyun {
2760*4882a593Smuzhiyun return omap_prm_assert_hardreset(ohri->rst_shift, 0,
2761*4882a593Smuzhiyun oh->prcm.omap2.module_offs, 0);
2762*4882a593Smuzhiyun }
2763*4882a593Smuzhiyun
2764*4882a593Smuzhiyun /**
2765*4882a593Smuzhiyun * _omap2_deassert_hardreset - call OMAP2 PRM hardreset fn with hwmod args
2766*4882a593Smuzhiyun * @oh: struct omap_hwmod * to deassert hardreset
2767*4882a593Smuzhiyun * @ohri: hardreset line data
2768*4882a593Smuzhiyun *
2769*4882a593Smuzhiyun * Call omap2_prm_deassert_hardreset() with parameters extracted from
2770*4882a593Smuzhiyun * the hwmod @oh and the hardreset line data @ohri. Only intended for
2771*4882a593Smuzhiyun * use as an soc_ops function pointer. Passes along the return value
2772*4882a593Smuzhiyun * from omap2_prm_deassert_hardreset(). XXX This function is
2773*4882a593Smuzhiyun * scheduled for removal when the PRM code is moved into drivers/.
2774*4882a593Smuzhiyun */
_omap2_deassert_hardreset(struct omap_hwmod * oh,struct omap_hwmod_rst_info * ohri)2775*4882a593Smuzhiyun static int _omap2_deassert_hardreset(struct omap_hwmod *oh,
2776*4882a593Smuzhiyun struct omap_hwmod_rst_info *ohri)
2777*4882a593Smuzhiyun {
2778*4882a593Smuzhiyun return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0,
2779*4882a593Smuzhiyun oh->prcm.omap2.module_offs, 0, 0);
2780*4882a593Smuzhiyun }
2781*4882a593Smuzhiyun
2782*4882a593Smuzhiyun /**
2783*4882a593Smuzhiyun * _omap2_is_hardreset_asserted - call OMAP2 PRM hardreset fn with hwmod args
2784*4882a593Smuzhiyun * @oh: struct omap_hwmod * to test hardreset
2785*4882a593Smuzhiyun * @ohri: hardreset line data
2786*4882a593Smuzhiyun *
2787*4882a593Smuzhiyun * Call omap2_prm_is_hardreset_asserted() with parameters extracted
2788*4882a593Smuzhiyun * from the hwmod @oh and the hardreset line data @ohri. Only
2789*4882a593Smuzhiyun * intended for use as an soc_ops function pointer. Passes along the
2790*4882a593Smuzhiyun * return value from omap2_prm_is_hardreset_asserted(). XXX This
2791*4882a593Smuzhiyun * function is scheduled for removal when the PRM code is moved into
2792*4882a593Smuzhiyun * drivers/.
2793*4882a593Smuzhiyun */
_omap2_is_hardreset_asserted(struct omap_hwmod * oh,struct omap_hwmod_rst_info * ohri)2794*4882a593Smuzhiyun static int _omap2_is_hardreset_asserted(struct omap_hwmod *oh,
2795*4882a593Smuzhiyun struct omap_hwmod_rst_info *ohri)
2796*4882a593Smuzhiyun {
2797*4882a593Smuzhiyun return omap_prm_is_hardreset_asserted(ohri->st_shift, 0,
2798*4882a593Smuzhiyun oh->prcm.omap2.module_offs, 0);
2799*4882a593Smuzhiyun }
2800*4882a593Smuzhiyun
2801*4882a593Smuzhiyun /**
2802*4882a593Smuzhiyun * _omap4_assert_hardreset - call OMAP4 PRM hardreset fn with hwmod args
2803*4882a593Smuzhiyun * @oh: struct omap_hwmod * to assert hardreset
2804*4882a593Smuzhiyun * @ohri: hardreset line data
2805*4882a593Smuzhiyun *
2806*4882a593Smuzhiyun * Call omap4_prminst_assert_hardreset() with parameters extracted
2807*4882a593Smuzhiyun * from the hwmod @oh and the hardreset line data @ohri. Only
2808*4882a593Smuzhiyun * intended for use as an soc_ops function pointer. Passes along the
2809*4882a593Smuzhiyun * return value from omap4_prminst_assert_hardreset(). XXX This
2810*4882a593Smuzhiyun * function is scheduled for removal when the PRM code is moved into
2811*4882a593Smuzhiyun * drivers/.
2812*4882a593Smuzhiyun */
_omap4_assert_hardreset(struct omap_hwmod * oh,struct omap_hwmod_rst_info * ohri)2813*4882a593Smuzhiyun static int _omap4_assert_hardreset(struct omap_hwmod *oh,
2814*4882a593Smuzhiyun struct omap_hwmod_rst_info *ohri)
2815*4882a593Smuzhiyun {
2816*4882a593Smuzhiyun if (!oh->clkdm)
2817*4882a593Smuzhiyun return -EINVAL;
2818*4882a593Smuzhiyun
2819*4882a593Smuzhiyun return omap_prm_assert_hardreset(ohri->rst_shift,
2820*4882a593Smuzhiyun oh->clkdm->pwrdm.ptr->prcm_partition,
2821*4882a593Smuzhiyun oh->clkdm->pwrdm.ptr->prcm_offs,
2822*4882a593Smuzhiyun oh->prcm.omap4.rstctrl_offs);
2823*4882a593Smuzhiyun }
2824*4882a593Smuzhiyun
2825*4882a593Smuzhiyun /**
2826*4882a593Smuzhiyun * _omap4_deassert_hardreset - call OMAP4 PRM hardreset fn with hwmod args
2827*4882a593Smuzhiyun * @oh: struct omap_hwmod * to deassert hardreset
2828*4882a593Smuzhiyun * @ohri: hardreset line data
2829*4882a593Smuzhiyun *
2830*4882a593Smuzhiyun * Call omap4_prminst_deassert_hardreset() with parameters extracted
2831*4882a593Smuzhiyun * from the hwmod @oh and the hardreset line data @ohri. Only
2832*4882a593Smuzhiyun * intended for use as an soc_ops function pointer. Passes along the
2833*4882a593Smuzhiyun * return value from omap4_prminst_deassert_hardreset(). XXX This
2834*4882a593Smuzhiyun * function is scheduled for removal when the PRM code is moved into
2835*4882a593Smuzhiyun * drivers/.
2836*4882a593Smuzhiyun */
_omap4_deassert_hardreset(struct omap_hwmod * oh,struct omap_hwmod_rst_info * ohri)2837*4882a593Smuzhiyun static int _omap4_deassert_hardreset(struct omap_hwmod *oh,
2838*4882a593Smuzhiyun struct omap_hwmod_rst_info *ohri)
2839*4882a593Smuzhiyun {
2840*4882a593Smuzhiyun if (!oh->clkdm)
2841*4882a593Smuzhiyun return -EINVAL;
2842*4882a593Smuzhiyun
2843*4882a593Smuzhiyun if (ohri->st_shift)
2844*4882a593Smuzhiyun pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n",
2845*4882a593Smuzhiyun oh->name, ohri->name);
2846*4882a593Smuzhiyun return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->rst_shift,
2847*4882a593Smuzhiyun oh->clkdm->pwrdm.ptr->prcm_partition,
2848*4882a593Smuzhiyun oh->clkdm->pwrdm.ptr->prcm_offs,
2849*4882a593Smuzhiyun oh->prcm.omap4.rstctrl_offs,
2850*4882a593Smuzhiyun oh->prcm.omap4.rstctrl_offs +
2851*4882a593Smuzhiyun OMAP4_RST_CTRL_ST_OFFSET);
2852*4882a593Smuzhiyun }
2853*4882a593Smuzhiyun
2854*4882a593Smuzhiyun /**
2855*4882a593Smuzhiyun * _omap4_is_hardreset_asserted - call OMAP4 PRM hardreset fn with hwmod args
2856*4882a593Smuzhiyun * @oh: struct omap_hwmod * to test hardreset
2857*4882a593Smuzhiyun * @ohri: hardreset line data
2858*4882a593Smuzhiyun *
2859*4882a593Smuzhiyun * Call omap4_prminst_is_hardreset_asserted() with parameters
2860*4882a593Smuzhiyun * extracted from the hwmod @oh and the hardreset line data @ohri.
2861*4882a593Smuzhiyun * Only intended for use as an soc_ops function pointer. Passes along
2862*4882a593Smuzhiyun * the return value from omap4_prminst_is_hardreset_asserted(). XXX
2863*4882a593Smuzhiyun * This function is scheduled for removal when the PRM code is moved
2864*4882a593Smuzhiyun * into drivers/.
2865*4882a593Smuzhiyun */
_omap4_is_hardreset_asserted(struct omap_hwmod * oh,struct omap_hwmod_rst_info * ohri)2866*4882a593Smuzhiyun static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh,
2867*4882a593Smuzhiyun struct omap_hwmod_rst_info *ohri)
2868*4882a593Smuzhiyun {
2869*4882a593Smuzhiyun if (!oh->clkdm)
2870*4882a593Smuzhiyun return -EINVAL;
2871*4882a593Smuzhiyun
2872*4882a593Smuzhiyun return omap_prm_is_hardreset_asserted(ohri->rst_shift,
2873*4882a593Smuzhiyun oh->clkdm->pwrdm.ptr->
2874*4882a593Smuzhiyun prcm_partition,
2875*4882a593Smuzhiyun oh->clkdm->pwrdm.ptr->prcm_offs,
2876*4882a593Smuzhiyun oh->prcm.omap4.rstctrl_offs);
2877*4882a593Smuzhiyun }
2878*4882a593Smuzhiyun
2879*4882a593Smuzhiyun /**
2880*4882a593Smuzhiyun * _omap4_disable_direct_prcm - disable direct PRCM control for hwmod
2881*4882a593Smuzhiyun * @oh: struct omap_hwmod * to disable control for
2882*4882a593Smuzhiyun *
2883*4882a593Smuzhiyun * Disables direct PRCM clkctrl done by hwmod core. Instead, the hwmod
2884*4882a593Smuzhiyun * will be using its main_clk to enable/disable the module. Returns
2885*4882a593Smuzhiyun * 0 if successful.
2886*4882a593Smuzhiyun */
_omap4_disable_direct_prcm(struct omap_hwmod * oh)2887*4882a593Smuzhiyun static int _omap4_disable_direct_prcm(struct omap_hwmod *oh)
2888*4882a593Smuzhiyun {
2889*4882a593Smuzhiyun if (!oh)
2890*4882a593Smuzhiyun return -EINVAL;
2891*4882a593Smuzhiyun
2892*4882a593Smuzhiyun oh->prcm.omap4.flags |= HWMOD_OMAP4_CLKFWK_CLKCTR_CLOCK;
2893*4882a593Smuzhiyun
2894*4882a593Smuzhiyun return 0;
2895*4882a593Smuzhiyun }
2896*4882a593Smuzhiyun
2897*4882a593Smuzhiyun /**
2898*4882a593Smuzhiyun * _am33xx_deassert_hardreset - call AM33XX PRM hardreset fn with hwmod args
2899*4882a593Smuzhiyun * @oh: struct omap_hwmod * to deassert hardreset
2900*4882a593Smuzhiyun * @ohri: hardreset line data
2901*4882a593Smuzhiyun *
2902*4882a593Smuzhiyun * Call am33xx_prminst_deassert_hardreset() with parameters extracted
2903*4882a593Smuzhiyun * from the hwmod @oh and the hardreset line data @ohri. Only
2904*4882a593Smuzhiyun * intended for use as an soc_ops function pointer. Passes along the
2905*4882a593Smuzhiyun * return value from am33xx_prminst_deassert_hardreset(). XXX This
2906*4882a593Smuzhiyun * function is scheduled for removal when the PRM code is moved into
2907*4882a593Smuzhiyun * drivers/.
2908*4882a593Smuzhiyun */
_am33xx_deassert_hardreset(struct omap_hwmod * oh,struct omap_hwmod_rst_info * ohri)2909*4882a593Smuzhiyun static int _am33xx_deassert_hardreset(struct omap_hwmod *oh,
2910*4882a593Smuzhiyun struct omap_hwmod_rst_info *ohri)
2911*4882a593Smuzhiyun {
2912*4882a593Smuzhiyun return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift,
2913*4882a593Smuzhiyun oh->clkdm->pwrdm.ptr->prcm_partition,
2914*4882a593Smuzhiyun oh->clkdm->pwrdm.ptr->prcm_offs,
2915*4882a593Smuzhiyun oh->prcm.omap4.rstctrl_offs,
2916*4882a593Smuzhiyun oh->prcm.omap4.rstst_offs);
2917*4882a593Smuzhiyun }
2918*4882a593Smuzhiyun
2919*4882a593Smuzhiyun /* Public functions */
2920*4882a593Smuzhiyun
omap_hwmod_read(struct omap_hwmod * oh,u16 reg_offs)2921*4882a593Smuzhiyun u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs)
2922*4882a593Smuzhiyun {
2923*4882a593Smuzhiyun if (oh->flags & HWMOD_16BIT_REG)
2924*4882a593Smuzhiyun return readw_relaxed(oh->_mpu_rt_va + reg_offs);
2925*4882a593Smuzhiyun else
2926*4882a593Smuzhiyun return readl_relaxed(oh->_mpu_rt_va + reg_offs);
2927*4882a593Smuzhiyun }
2928*4882a593Smuzhiyun
omap_hwmod_write(u32 v,struct omap_hwmod * oh,u16 reg_offs)2929*4882a593Smuzhiyun void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs)
2930*4882a593Smuzhiyun {
2931*4882a593Smuzhiyun if (oh->flags & HWMOD_16BIT_REG)
2932*4882a593Smuzhiyun writew_relaxed(v, oh->_mpu_rt_va + reg_offs);
2933*4882a593Smuzhiyun else
2934*4882a593Smuzhiyun writel_relaxed(v, oh->_mpu_rt_va + reg_offs);
2935*4882a593Smuzhiyun }
2936*4882a593Smuzhiyun
2937*4882a593Smuzhiyun /**
2938*4882a593Smuzhiyun * omap_hwmod_softreset - reset a module via SYSCONFIG.SOFTRESET bit
2939*4882a593Smuzhiyun * @oh: struct omap_hwmod *
2940*4882a593Smuzhiyun *
2941*4882a593Smuzhiyun * This is a public function exposed to drivers. Some drivers may need to do
2942*4882a593Smuzhiyun * some settings before and after resetting the device. Those drivers after
2943*4882a593Smuzhiyun * doing the necessary settings could use this function to start a reset by
2944*4882a593Smuzhiyun * setting the SYSCONFIG.SOFTRESET bit.
2945*4882a593Smuzhiyun */
omap_hwmod_softreset(struct omap_hwmod * oh)2946*4882a593Smuzhiyun int omap_hwmod_softreset(struct omap_hwmod *oh)
2947*4882a593Smuzhiyun {
2948*4882a593Smuzhiyun u32 v;
2949*4882a593Smuzhiyun int ret;
2950*4882a593Smuzhiyun
2951*4882a593Smuzhiyun if (!oh || !(oh->_sysc_cache))
2952*4882a593Smuzhiyun return -EINVAL;
2953*4882a593Smuzhiyun
2954*4882a593Smuzhiyun v = oh->_sysc_cache;
2955*4882a593Smuzhiyun ret = _set_softreset(oh, &v);
2956*4882a593Smuzhiyun if (ret)
2957*4882a593Smuzhiyun goto error;
2958*4882a593Smuzhiyun _write_sysconfig(v, oh);
2959*4882a593Smuzhiyun
2960*4882a593Smuzhiyun ret = _clear_softreset(oh, &v);
2961*4882a593Smuzhiyun if (ret)
2962*4882a593Smuzhiyun goto error;
2963*4882a593Smuzhiyun _write_sysconfig(v, oh);
2964*4882a593Smuzhiyun
2965*4882a593Smuzhiyun error:
2966*4882a593Smuzhiyun return ret;
2967*4882a593Smuzhiyun }
2968*4882a593Smuzhiyun
2969*4882a593Smuzhiyun /**
2970*4882a593Smuzhiyun * omap_hwmod_lookup - look up a registered omap_hwmod by name
2971*4882a593Smuzhiyun * @name: name of the omap_hwmod to look up
2972*4882a593Smuzhiyun *
2973*4882a593Smuzhiyun * Given a @name of an omap_hwmod, return a pointer to the registered
2974*4882a593Smuzhiyun * struct omap_hwmod *, or NULL upon error.
2975*4882a593Smuzhiyun */
omap_hwmod_lookup(const char * name)2976*4882a593Smuzhiyun struct omap_hwmod *omap_hwmod_lookup(const char *name)
2977*4882a593Smuzhiyun {
2978*4882a593Smuzhiyun struct omap_hwmod *oh;
2979*4882a593Smuzhiyun
2980*4882a593Smuzhiyun if (!name)
2981*4882a593Smuzhiyun return NULL;
2982*4882a593Smuzhiyun
2983*4882a593Smuzhiyun oh = _lookup(name);
2984*4882a593Smuzhiyun
2985*4882a593Smuzhiyun return oh;
2986*4882a593Smuzhiyun }
2987*4882a593Smuzhiyun
2988*4882a593Smuzhiyun /**
2989*4882a593Smuzhiyun * omap_hwmod_for_each - call function for each registered omap_hwmod
2990*4882a593Smuzhiyun * @fn: pointer to a callback function
2991*4882a593Smuzhiyun * @data: void * data to pass to callback function
2992*4882a593Smuzhiyun *
2993*4882a593Smuzhiyun * Call @fn for each registered omap_hwmod, passing @data to each
2994*4882a593Smuzhiyun * function. @fn must return 0 for success or any other value for
2995*4882a593Smuzhiyun * failure. If @fn returns non-zero, the iteration across omap_hwmods
2996*4882a593Smuzhiyun * will stop and the non-zero return value will be passed to the
2997*4882a593Smuzhiyun * caller of omap_hwmod_for_each(). @fn is called with
2998*4882a593Smuzhiyun * omap_hwmod_for_each() held.
2999*4882a593Smuzhiyun */
omap_hwmod_for_each(int (* fn)(struct omap_hwmod * oh,void * data),void * data)3000*4882a593Smuzhiyun int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
3001*4882a593Smuzhiyun void *data)
3002*4882a593Smuzhiyun {
3003*4882a593Smuzhiyun struct omap_hwmod *temp_oh;
3004*4882a593Smuzhiyun int ret = 0;
3005*4882a593Smuzhiyun
3006*4882a593Smuzhiyun if (!fn)
3007*4882a593Smuzhiyun return -EINVAL;
3008*4882a593Smuzhiyun
3009*4882a593Smuzhiyun list_for_each_entry(temp_oh, &omap_hwmod_list, node) {
3010*4882a593Smuzhiyun ret = (*fn)(temp_oh, data);
3011*4882a593Smuzhiyun if (ret)
3012*4882a593Smuzhiyun break;
3013*4882a593Smuzhiyun }
3014*4882a593Smuzhiyun
3015*4882a593Smuzhiyun return ret;
3016*4882a593Smuzhiyun }
3017*4882a593Smuzhiyun
3018*4882a593Smuzhiyun /**
3019*4882a593Smuzhiyun * omap_hwmod_register_links - register an array of hwmod links
3020*4882a593Smuzhiyun * @ois: pointer to an array of omap_hwmod_ocp_if to register
3021*4882a593Smuzhiyun *
3022*4882a593Smuzhiyun * Intended to be called early in boot before the clock framework is
3023*4882a593Smuzhiyun * initialized. If @ois is not null, will register all omap_hwmods
3024*4882a593Smuzhiyun * listed in @ois that are valid for this chip. Returns -EINVAL if
3025*4882a593Smuzhiyun * omap_hwmod_init() hasn't been called before calling this function,
3026*4882a593Smuzhiyun * -ENOMEM if the link memory area can't be allocated, or 0 upon
3027*4882a593Smuzhiyun * success.
3028*4882a593Smuzhiyun */
omap_hwmod_register_links(struct omap_hwmod_ocp_if ** ois)3029*4882a593Smuzhiyun int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois)
3030*4882a593Smuzhiyun {
3031*4882a593Smuzhiyun int r, i;
3032*4882a593Smuzhiyun
3033*4882a593Smuzhiyun if (!inited)
3034*4882a593Smuzhiyun return -EINVAL;
3035*4882a593Smuzhiyun
3036*4882a593Smuzhiyun if (!ois)
3037*4882a593Smuzhiyun return 0;
3038*4882a593Smuzhiyun
3039*4882a593Smuzhiyun if (ois[0] == NULL) /* Empty list */
3040*4882a593Smuzhiyun return 0;
3041*4882a593Smuzhiyun
3042*4882a593Smuzhiyun i = 0;
3043*4882a593Smuzhiyun do {
3044*4882a593Smuzhiyun r = _register_link(ois[i]);
3045*4882a593Smuzhiyun WARN(r && r != -EEXIST,
3046*4882a593Smuzhiyun "omap_hwmod: _register_link(%s -> %s) returned %d\n",
3047*4882a593Smuzhiyun ois[i]->master->name, ois[i]->slave->name, r);
3048*4882a593Smuzhiyun } while (ois[++i]);
3049*4882a593Smuzhiyun
3050*4882a593Smuzhiyun return 0;
3051*4882a593Smuzhiyun }
3052*4882a593Smuzhiyun
3053*4882a593Smuzhiyun /**
3054*4882a593Smuzhiyun * _ensure_mpu_hwmod_is_setup - ensure the MPU SS hwmod is init'ed and set up
3055*4882a593Smuzhiyun * @oh: pointer to the hwmod currently being set up (usually not the MPU)
3056*4882a593Smuzhiyun *
3057*4882a593Smuzhiyun * If the hwmod data corresponding to the MPU subsystem IP block
3058*4882a593Smuzhiyun * hasn't been initialized and set up yet, do so now. This must be
3059*4882a593Smuzhiyun * done first since sleep dependencies may be added from other hwmods
3060*4882a593Smuzhiyun * to the MPU. Intended to be called only by omap_hwmod_setup*(). No
3061*4882a593Smuzhiyun * return value.
3062*4882a593Smuzhiyun */
_ensure_mpu_hwmod_is_setup(struct omap_hwmod * oh)3063*4882a593Smuzhiyun static void __init _ensure_mpu_hwmod_is_setup(struct omap_hwmod *oh)
3064*4882a593Smuzhiyun {
3065*4882a593Smuzhiyun if (!mpu_oh || mpu_oh->_state == _HWMOD_STATE_UNKNOWN)
3066*4882a593Smuzhiyun pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n",
3067*4882a593Smuzhiyun __func__, MPU_INITIATOR_NAME);
3068*4882a593Smuzhiyun else if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh)
3069*4882a593Smuzhiyun omap_hwmod_setup_one(MPU_INITIATOR_NAME);
3070*4882a593Smuzhiyun }
3071*4882a593Smuzhiyun
3072*4882a593Smuzhiyun /**
3073*4882a593Smuzhiyun * omap_hwmod_setup_one - set up a single hwmod
3074*4882a593Smuzhiyun * @oh_name: const char * name of the already-registered hwmod to set up
3075*4882a593Smuzhiyun *
3076*4882a593Smuzhiyun * Initialize and set up a single hwmod. Intended to be used for a
3077*4882a593Smuzhiyun * small number of early devices, such as the timer IP blocks used for
3078*4882a593Smuzhiyun * the scheduler clock. Must be called after omap2_clk_init().
3079*4882a593Smuzhiyun * Resolves the struct clk names to struct clk pointers for each
3080*4882a593Smuzhiyun * registered omap_hwmod. Also calls _setup() on each hwmod. Returns
3081*4882a593Smuzhiyun * -EINVAL upon error or 0 upon success.
3082*4882a593Smuzhiyun */
omap_hwmod_setup_one(const char * oh_name)3083*4882a593Smuzhiyun int __init omap_hwmod_setup_one(const char *oh_name)
3084*4882a593Smuzhiyun {
3085*4882a593Smuzhiyun struct omap_hwmod *oh;
3086*4882a593Smuzhiyun
3087*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: %s\n", oh_name, __func__);
3088*4882a593Smuzhiyun
3089*4882a593Smuzhiyun oh = _lookup(oh_name);
3090*4882a593Smuzhiyun if (!oh) {
3091*4882a593Smuzhiyun WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name);
3092*4882a593Smuzhiyun return -EINVAL;
3093*4882a593Smuzhiyun }
3094*4882a593Smuzhiyun
3095*4882a593Smuzhiyun _ensure_mpu_hwmod_is_setup(oh);
3096*4882a593Smuzhiyun
3097*4882a593Smuzhiyun _init(oh, NULL);
3098*4882a593Smuzhiyun _setup(oh, NULL);
3099*4882a593Smuzhiyun
3100*4882a593Smuzhiyun return 0;
3101*4882a593Smuzhiyun }
3102*4882a593Smuzhiyun
omap_hwmod_check_one(struct device * dev,const char * name,s8 v1,u8 v2)3103*4882a593Smuzhiyun static void omap_hwmod_check_one(struct device *dev,
3104*4882a593Smuzhiyun const char *name, s8 v1, u8 v2)
3105*4882a593Smuzhiyun {
3106*4882a593Smuzhiyun if (v1 < 0)
3107*4882a593Smuzhiyun return;
3108*4882a593Smuzhiyun
3109*4882a593Smuzhiyun if (v1 != v2)
3110*4882a593Smuzhiyun dev_warn(dev, "%s %d != %d\n", name, v1, v2);
3111*4882a593Smuzhiyun }
3112*4882a593Smuzhiyun
3113*4882a593Smuzhiyun /**
3114*4882a593Smuzhiyun * omap_hwmod_check_sysc - check sysc against platform sysc
3115*4882a593Smuzhiyun * @dev: struct device
3116*4882a593Smuzhiyun * @data: module data
3117*4882a593Smuzhiyun * @sysc_fields: new sysc configuration
3118*4882a593Smuzhiyun */
omap_hwmod_check_sysc(struct device * dev,const struct ti_sysc_module_data * data,struct sysc_regbits * sysc_fields)3119*4882a593Smuzhiyun static int omap_hwmod_check_sysc(struct device *dev,
3120*4882a593Smuzhiyun const struct ti_sysc_module_data *data,
3121*4882a593Smuzhiyun struct sysc_regbits *sysc_fields)
3122*4882a593Smuzhiyun {
3123*4882a593Smuzhiyun const struct sysc_regbits *regbits = data->cap->regbits;
3124*4882a593Smuzhiyun
3125*4882a593Smuzhiyun omap_hwmod_check_one(dev, "dmadisable_shift",
3126*4882a593Smuzhiyun regbits->dmadisable_shift,
3127*4882a593Smuzhiyun sysc_fields->dmadisable_shift);
3128*4882a593Smuzhiyun omap_hwmod_check_one(dev, "midle_shift",
3129*4882a593Smuzhiyun regbits->midle_shift,
3130*4882a593Smuzhiyun sysc_fields->midle_shift);
3131*4882a593Smuzhiyun omap_hwmod_check_one(dev, "sidle_shift",
3132*4882a593Smuzhiyun regbits->sidle_shift,
3133*4882a593Smuzhiyun sysc_fields->sidle_shift);
3134*4882a593Smuzhiyun omap_hwmod_check_one(dev, "clkact_shift",
3135*4882a593Smuzhiyun regbits->clkact_shift,
3136*4882a593Smuzhiyun sysc_fields->clkact_shift);
3137*4882a593Smuzhiyun omap_hwmod_check_one(dev, "enwkup_shift",
3138*4882a593Smuzhiyun regbits->enwkup_shift,
3139*4882a593Smuzhiyun sysc_fields->enwkup_shift);
3140*4882a593Smuzhiyun omap_hwmod_check_one(dev, "srst_shift",
3141*4882a593Smuzhiyun regbits->srst_shift,
3142*4882a593Smuzhiyun sysc_fields->srst_shift);
3143*4882a593Smuzhiyun omap_hwmod_check_one(dev, "autoidle_shift",
3144*4882a593Smuzhiyun regbits->autoidle_shift,
3145*4882a593Smuzhiyun sysc_fields->autoidle_shift);
3146*4882a593Smuzhiyun
3147*4882a593Smuzhiyun return 0;
3148*4882a593Smuzhiyun }
3149*4882a593Smuzhiyun
3150*4882a593Smuzhiyun /**
3151*4882a593Smuzhiyun * omap_hwmod_init_regbits - init sysconfig specific register bits
3152*4882a593Smuzhiyun * @dev: struct device
3153*4882a593Smuzhiyun * @oh: module
3154*4882a593Smuzhiyun * @data: module data
3155*4882a593Smuzhiyun * @sysc_fields: new sysc configuration
3156*4882a593Smuzhiyun */
omap_hwmod_init_regbits(struct device * dev,struct omap_hwmod * oh,const struct ti_sysc_module_data * data,struct sysc_regbits ** sysc_fields)3157*4882a593Smuzhiyun static int omap_hwmod_init_regbits(struct device *dev, struct omap_hwmod *oh,
3158*4882a593Smuzhiyun const struct ti_sysc_module_data *data,
3159*4882a593Smuzhiyun struct sysc_regbits **sysc_fields)
3160*4882a593Smuzhiyun {
3161*4882a593Smuzhiyun switch (data->cap->type) {
3162*4882a593Smuzhiyun case TI_SYSC_OMAP2:
3163*4882a593Smuzhiyun case TI_SYSC_OMAP2_TIMER:
3164*4882a593Smuzhiyun *sysc_fields = &omap_hwmod_sysc_type1;
3165*4882a593Smuzhiyun break;
3166*4882a593Smuzhiyun case TI_SYSC_OMAP3_SHAM:
3167*4882a593Smuzhiyun *sysc_fields = &omap3_sham_sysc_fields;
3168*4882a593Smuzhiyun break;
3169*4882a593Smuzhiyun case TI_SYSC_OMAP3_AES:
3170*4882a593Smuzhiyun *sysc_fields = &omap3xxx_aes_sysc_fields;
3171*4882a593Smuzhiyun break;
3172*4882a593Smuzhiyun case TI_SYSC_OMAP4:
3173*4882a593Smuzhiyun case TI_SYSC_OMAP4_TIMER:
3174*4882a593Smuzhiyun *sysc_fields = &omap_hwmod_sysc_type2;
3175*4882a593Smuzhiyun break;
3176*4882a593Smuzhiyun case TI_SYSC_OMAP4_SIMPLE:
3177*4882a593Smuzhiyun *sysc_fields = &omap_hwmod_sysc_type3;
3178*4882a593Smuzhiyun break;
3179*4882a593Smuzhiyun case TI_SYSC_OMAP34XX_SR:
3180*4882a593Smuzhiyun *sysc_fields = &omap34xx_sr_sysc_fields;
3181*4882a593Smuzhiyun break;
3182*4882a593Smuzhiyun case TI_SYSC_OMAP36XX_SR:
3183*4882a593Smuzhiyun *sysc_fields = &omap36xx_sr_sysc_fields;
3184*4882a593Smuzhiyun break;
3185*4882a593Smuzhiyun case TI_SYSC_OMAP4_SR:
3186*4882a593Smuzhiyun *sysc_fields = &omap36xx_sr_sysc_fields;
3187*4882a593Smuzhiyun break;
3188*4882a593Smuzhiyun case TI_SYSC_OMAP4_MCASP:
3189*4882a593Smuzhiyun *sysc_fields = &omap_hwmod_sysc_type_mcasp;
3190*4882a593Smuzhiyun break;
3191*4882a593Smuzhiyun case TI_SYSC_OMAP4_USB_HOST_FS:
3192*4882a593Smuzhiyun *sysc_fields = &omap_hwmod_sysc_type_usb_host_fs;
3193*4882a593Smuzhiyun break;
3194*4882a593Smuzhiyun default:
3195*4882a593Smuzhiyun *sysc_fields = NULL;
3196*4882a593Smuzhiyun if (!oh->class->sysc->sysc_fields)
3197*4882a593Smuzhiyun return 0;
3198*4882a593Smuzhiyun
3199*4882a593Smuzhiyun dev_err(dev, "sysc_fields not found\n");
3200*4882a593Smuzhiyun
3201*4882a593Smuzhiyun return -EINVAL;
3202*4882a593Smuzhiyun }
3203*4882a593Smuzhiyun
3204*4882a593Smuzhiyun return omap_hwmod_check_sysc(dev, data, *sysc_fields);
3205*4882a593Smuzhiyun }
3206*4882a593Smuzhiyun
3207*4882a593Smuzhiyun /**
3208*4882a593Smuzhiyun * omap_hwmod_init_reg_offs - initialize sysconfig register offsets
3209*4882a593Smuzhiyun * @dev: struct device
3210*4882a593Smuzhiyun * @data: module data
3211*4882a593Smuzhiyun * @rev_offs: revision register offset
3212*4882a593Smuzhiyun * @sysc_offs: sysc register offset
3213*4882a593Smuzhiyun * @syss_offs: syss register offset
3214*4882a593Smuzhiyun */
omap_hwmod_init_reg_offs(struct device * dev,const struct ti_sysc_module_data * data,s32 * rev_offs,s32 * sysc_offs,s32 * syss_offs)3215*4882a593Smuzhiyun static int omap_hwmod_init_reg_offs(struct device *dev,
3216*4882a593Smuzhiyun const struct ti_sysc_module_data *data,
3217*4882a593Smuzhiyun s32 *rev_offs, s32 *sysc_offs,
3218*4882a593Smuzhiyun s32 *syss_offs)
3219*4882a593Smuzhiyun {
3220*4882a593Smuzhiyun *rev_offs = -ENODEV;
3221*4882a593Smuzhiyun *sysc_offs = 0;
3222*4882a593Smuzhiyun *syss_offs = 0;
3223*4882a593Smuzhiyun
3224*4882a593Smuzhiyun if (data->offsets[SYSC_REVISION] >= 0)
3225*4882a593Smuzhiyun *rev_offs = data->offsets[SYSC_REVISION];
3226*4882a593Smuzhiyun
3227*4882a593Smuzhiyun if (data->offsets[SYSC_SYSCONFIG] >= 0)
3228*4882a593Smuzhiyun *sysc_offs = data->offsets[SYSC_SYSCONFIG];
3229*4882a593Smuzhiyun
3230*4882a593Smuzhiyun if (data->offsets[SYSC_SYSSTATUS] >= 0)
3231*4882a593Smuzhiyun *syss_offs = data->offsets[SYSC_SYSSTATUS];
3232*4882a593Smuzhiyun
3233*4882a593Smuzhiyun return 0;
3234*4882a593Smuzhiyun }
3235*4882a593Smuzhiyun
3236*4882a593Smuzhiyun /**
3237*4882a593Smuzhiyun * omap_hwmod_init_sysc_flags - initialize sysconfig features
3238*4882a593Smuzhiyun * @dev: struct device
3239*4882a593Smuzhiyun * @data: module data
3240*4882a593Smuzhiyun * @sysc_flags: module configuration
3241*4882a593Smuzhiyun */
omap_hwmod_init_sysc_flags(struct device * dev,const struct ti_sysc_module_data * data,u32 * sysc_flags)3242*4882a593Smuzhiyun static int omap_hwmod_init_sysc_flags(struct device *dev,
3243*4882a593Smuzhiyun const struct ti_sysc_module_data *data,
3244*4882a593Smuzhiyun u32 *sysc_flags)
3245*4882a593Smuzhiyun {
3246*4882a593Smuzhiyun *sysc_flags = 0;
3247*4882a593Smuzhiyun
3248*4882a593Smuzhiyun switch (data->cap->type) {
3249*4882a593Smuzhiyun case TI_SYSC_OMAP2:
3250*4882a593Smuzhiyun case TI_SYSC_OMAP2_TIMER:
3251*4882a593Smuzhiyun /* See SYSC_OMAP2_* in include/dt-bindings/bus/ti-sysc.h */
3252*4882a593Smuzhiyun if (data->cfg->sysc_val & SYSC_OMAP2_CLOCKACTIVITY)
3253*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_CLOCKACTIVITY;
3254*4882a593Smuzhiyun if (data->cfg->sysc_val & SYSC_OMAP2_EMUFREE)
3255*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_EMUFREE;
3256*4882a593Smuzhiyun if (data->cfg->sysc_val & SYSC_OMAP2_ENAWAKEUP)
3257*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_ENAWAKEUP;
3258*4882a593Smuzhiyun if (data->cfg->sysc_val & SYSC_OMAP2_SOFTRESET)
3259*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_SOFTRESET;
3260*4882a593Smuzhiyun if (data->cfg->sysc_val & SYSC_OMAP2_AUTOIDLE)
3261*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_AUTOIDLE;
3262*4882a593Smuzhiyun break;
3263*4882a593Smuzhiyun case TI_SYSC_OMAP4:
3264*4882a593Smuzhiyun case TI_SYSC_OMAP4_TIMER:
3265*4882a593Smuzhiyun /* See SYSC_OMAP4_* in include/dt-bindings/bus/ti-sysc.h */
3266*4882a593Smuzhiyun if (data->cfg->sysc_val & SYSC_OMAP4_DMADISABLE)
3267*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_DMADISABLE;
3268*4882a593Smuzhiyun if (data->cfg->sysc_val & SYSC_OMAP4_FREEEMU)
3269*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_EMUFREE;
3270*4882a593Smuzhiyun if (data->cfg->sysc_val & SYSC_OMAP4_SOFTRESET)
3271*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_SOFTRESET;
3272*4882a593Smuzhiyun break;
3273*4882a593Smuzhiyun case TI_SYSC_OMAP34XX_SR:
3274*4882a593Smuzhiyun case TI_SYSC_OMAP36XX_SR:
3275*4882a593Smuzhiyun /* See SYSC_OMAP3_SR_* in include/dt-bindings/bus/ti-sysc.h */
3276*4882a593Smuzhiyun if (data->cfg->sysc_val & SYSC_OMAP3_SR_ENAWAKEUP)
3277*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_ENAWAKEUP;
3278*4882a593Smuzhiyun break;
3279*4882a593Smuzhiyun default:
3280*4882a593Smuzhiyun if (data->cap->regbits->emufree_shift >= 0)
3281*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_EMUFREE;
3282*4882a593Smuzhiyun if (data->cap->regbits->enwkup_shift >= 0)
3283*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_ENAWAKEUP;
3284*4882a593Smuzhiyun if (data->cap->regbits->srst_shift >= 0)
3285*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_SOFTRESET;
3286*4882a593Smuzhiyun if (data->cap->regbits->autoidle_shift >= 0)
3287*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_AUTOIDLE;
3288*4882a593Smuzhiyun break;
3289*4882a593Smuzhiyun }
3290*4882a593Smuzhiyun
3291*4882a593Smuzhiyun if (data->cap->regbits->midle_shift >= 0 &&
3292*4882a593Smuzhiyun data->cfg->midlemodes)
3293*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_MIDLEMODE;
3294*4882a593Smuzhiyun
3295*4882a593Smuzhiyun if (data->cap->regbits->sidle_shift >= 0 &&
3296*4882a593Smuzhiyun data->cfg->sidlemodes)
3297*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_SIDLEMODE;
3298*4882a593Smuzhiyun
3299*4882a593Smuzhiyun if (data->cfg->quirks & SYSC_QUIRK_UNCACHED)
3300*4882a593Smuzhiyun *sysc_flags |= SYSC_NO_CACHE;
3301*4882a593Smuzhiyun if (data->cfg->quirks & SYSC_QUIRK_RESET_STATUS)
3302*4882a593Smuzhiyun *sysc_flags |= SYSC_HAS_RESET_STATUS;
3303*4882a593Smuzhiyun
3304*4882a593Smuzhiyun if (data->cfg->syss_mask & 1)
3305*4882a593Smuzhiyun *sysc_flags |= SYSS_HAS_RESET_STATUS;
3306*4882a593Smuzhiyun
3307*4882a593Smuzhiyun return 0;
3308*4882a593Smuzhiyun }
3309*4882a593Smuzhiyun
3310*4882a593Smuzhiyun /**
3311*4882a593Smuzhiyun * omap_hwmod_init_idlemodes - initialize module idle modes
3312*4882a593Smuzhiyun * @dev: struct device
3313*4882a593Smuzhiyun * @data: module data
3314*4882a593Smuzhiyun * @idlemodes: module supported idle modes
3315*4882a593Smuzhiyun */
omap_hwmod_init_idlemodes(struct device * dev,const struct ti_sysc_module_data * data,u32 * idlemodes)3316*4882a593Smuzhiyun static int omap_hwmod_init_idlemodes(struct device *dev,
3317*4882a593Smuzhiyun const struct ti_sysc_module_data *data,
3318*4882a593Smuzhiyun u32 *idlemodes)
3319*4882a593Smuzhiyun {
3320*4882a593Smuzhiyun *idlemodes = 0;
3321*4882a593Smuzhiyun
3322*4882a593Smuzhiyun if (data->cfg->midlemodes & BIT(SYSC_IDLE_FORCE))
3323*4882a593Smuzhiyun *idlemodes |= MSTANDBY_FORCE;
3324*4882a593Smuzhiyun if (data->cfg->midlemodes & BIT(SYSC_IDLE_NO))
3325*4882a593Smuzhiyun *idlemodes |= MSTANDBY_NO;
3326*4882a593Smuzhiyun if (data->cfg->midlemodes & BIT(SYSC_IDLE_SMART))
3327*4882a593Smuzhiyun *idlemodes |= MSTANDBY_SMART;
3328*4882a593Smuzhiyun if (data->cfg->midlemodes & BIT(SYSC_IDLE_SMART_WKUP))
3329*4882a593Smuzhiyun *idlemodes |= MSTANDBY_SMART_WKUP;
3330*4882a593Smuzhiyun
3331*4882a593Smuzhiyun if (data->cfg->sidlemodes & BIT(SYSC_IDLE_FORCE))
3332*4882a593Smuzhiyun *idlemodes |= SIDLE_FORCE;
3333*4882a593Smuzhiyun if (data->cfg->sidlemodes & BIT(SYSC_IDLE_NO))
3334*4882a593Smuzhiyun *idlemodes |= SIDLE_NO;
3335*4882a593Smuzhiyun if (data->cfg->sidlemodes & BIT(SYSC_IDLE_SMART))
3336*4882a593Smuzhiyun *idlemodes |= SIDLE_SMART;
3337*4882a593Smuzhiyun if (data->cfg->sidlemodes & BIT(SYSC_IDLE_SMART_WKUP))
3338*4882a593Smuzhiyun *idlemodes |= SIDLE_SMART_WKUP;
3339*4882a593Smuzhiyun
3340*4882a593Smuzhiyun return 0;
3341*4882a593Smuzhiyun }
3342*4882a593Smuzhiyun
3343*4882a593Smuzhiyun /**
3344*4882a593Smuzhiyun * omap_hwmod_check_module - check new module against platform data
3345*4882a593Smuzhiyun * @dev: struct device
3346*4882a593Smuzhiyun * @oh: module
3347*4882a593Smuzhiyun * @data: new module data
3348*4882a593Smuzhiyun * @sysc_fields: sysc register bits
3349*4882a593Smuzhiyun * @rev_offs: revision register offset
3350*4882a593Smuzhiyun * @sysc_offs: sysconfig register offset
3351*4882a593Smuzhiyun * @syss_offs: sysstatus register offset
3352*4882a593Smuzhiyun * @sysc_flags: sysc specific flags
3353*4882a593Smuzhiyun * @idlemodes: sysc supported idlemodes
3354*4882a593Smuzhiyun */
omap_hwmod_check_module(struct device * dev,struct omap_hwmod * oh,const struct ti_sysc_module_data * data,struct sysc_regbits * sysc_fields,s32 rev_offs,s32 sysc_offs,s32 syss_offs,u32 sysc_flags,u32 idlemodes)3355*4882a593Smuzhiyun static int omap_hwmod_check_module(struct device *dev,
3356*4882a593Smuzhiyun struct omap_hwmod *oh,
3357*4882a593Smuzhiyun const struct ti_sysc_module_data *data,
3358*4882a593Smuzhiyun struct sysc_regbits *sysc_fields,
3359*4882a593Smuzhiyun s32 rev_offs, s32 sysc_offs,
3360*4882a593Smuzhiyun s32 syss_offs, u32 sysc_flags,
3361*4882a593Smuzhiyun u32 idlemodes)
3362*4882a593Smuzhiyun {
3363*4882a593Smuzhiyun if (!oh->class->sysc)
3364*4882a593Smuzhiyun return -ENODEV;
3365*4882a593Smuzhiyun
3366*4882a593Smuzhiyun if (oh->class->sysc->sysc_fields &&
3367*4882a593Smuzhiyun sysc_fields != oh->class->sysc->sysc_fields)
3368*4882a593Smuzhiyun dev_warn(dev, "sysc_fields mismatch\n");
3369*4882a593Smuzhiyun
3370*4882a593Smuzhiyun if (rev_offs != oh->class->sysc->rev_offs)
3371*4882a593Smuzhiyun dev_warn(dev, "rev_offs %08x != %08x\n", rev_offs,
3372*4882a593Smuzhiyun oh->class->sysc->rev_offs);
3373*4882a593Smuzhiyun if (sysc_offs != oh->class->sysc->sysc_offs)
3374*4882a593Smuzhiyun dev_warn(dev, "sysc_offs %08x != %08x\n", sysc_offs,
3375*4882a593Smuzhiyun oh->class->sysc->sysc_offs);
3376*4882a593Smuzhiyun if (syss_offs != oh->class->sysc->syss_offs)
3377*4882a593Smuzhiyun dev_warn(dev, "syss_offs %08x != %08x\n", syss_offs,
3378*4882a593Smuzhiyun oh->class->sysc->syss_offs);
3379*4882a593Smuzhiyun
3380*4882a593Smuzhiyun if (sysc_flags != oh->class->sysc->sysc_flags)
3381*4882a593Smuzhiyun dev_warn(dev, "sysc_flags %08x != %08x\n", sysc_flags,
3382*4882a593Smuzhiyun oh->class->sysc->sysc_flags);
3383*4882a593Smuzhiyun
3384*4882a593Smuzhiyun if (idlemodes != oh->class->sysc->idlemodes)
3385*4882a593Smuzhiyun dev_warn(dev, "idlemodes %08x != %08x\n", idlemodes,
3386*4882a593Smuzhiyun oh->class->sysc->idlemodes);
3387*4882a593Smuzhiyun
3388*4882a593Smuzhiyun if (data->cfg->srst_udelay != oh->class->sysc->srst_udelay)
3389*4882a593Smuzhiyun dev_warn(dev, "srst_udelay %i != %i\n",
3390*4882a593Smuzhiyun data->cfg->srst_udelay,
3391*4882a593Smuzhiyun oh->class->sysc->srst_udelay);
3392*4882a593Smuzhiyun
3393*4882a593Smuzhiyun return 0;
3394*4882a593Smuzhiyun }
3395*4882a593Smuzhiyun
3396*4882a593Smuzhiyun /**
3397*4882a593Smuzhiyun * omap_hwmod_allocate_module - allocate new module
3398*4882a593Smuzhiyun * @dev: struct device
3399*4882a593Smuzhiyun * @oh: module
3400*4882a593Smuzhiyun * @sysc_fields: sysc register bits
3401*4882a593Smuzhiyun * @clockdomain: clockdomain
3402*4882a593Smuzhiyun * @rev_offs: revision register offset
3403*4882a593Smuzhiyun * @sysc_offs: sysconfig register offset
3404*4882a593Smuzhiyun * @syss_offs: sysstatus register offset
3405*4882a593Smuzhiyun * @sysc_flags: sysc specific flags
3406*4882a593Smuzhiyun * @idlemodes: sysc supported idlemodes
3407*4882a593Smuzhiyun *
3408*4882a593Smuzhiyun * Note that the allocations here cannot use devm as ti-sysc can rebind.
3409*4882a593Smuzhiyun */
omap_hwmod_allocate_module(struct device * dev,struct omap_hwmod * oh,const struct ti_sysc_module_data * data,struct sysc_regbits * sysc_fields,struct clockdomain * clkdm,s32 rev_offs,s32 sysc_offs,s32 syss_offs,u32 sysc_flags,u32 idlemodes)3410*4882a593Smuzhiyun static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
3411*4882a593Smuzhiyun const struct ti_sysc_module_data *data,
3412*4882a593Smuzhiyun struct sysc_regbits *sysc_fields,
3413*4882a593Smuzhiyun struct clockdomain *clkdm,
3414*4882a593Smuzhiyun s32 rev_offs, s32 sysc_offs,
3415*4882a593Smuzhiyun s32 syss_offs, u32 sysc_flags,
3416*4882a593Smuzhiyun u32 idlemodes)
3417*4882a593Smuzhiyun {
3418*4882a593Smuzhiyun struct omap_hwmod_class_sysconfig *sysc;
3419*4882a593Smuzhiyun struct omap_hwmod_class *class = NULL;
3420*4882a593Smuzhiyun struct omap_hwmod_ocp_if *oi = NULL;
3421*4882a593Smuzhiyun void __iomem *regs = NULL;
3422*4882a593Smuzhiyun unsigned long flags;
3423*4882a593Smuzhiyun
3424*4882a593Smuzhiyun sysc = kzalloc(sizeof(*sysc), GFP_KERNEL);
3425*4882a593Smuzhiyun if (!sysc)
3426*4882a593Smuzhiyun return -ENOMEM;
3427*4882a593Smuzhiyun
3428*4882a593Smuzhiyun sysc->sysc_fields = sysc_fields;
3429*4882a593Smuzhiyun sysc->rev_offs = rev_offs;
3430*4882a593Smuzhiyun sysc->sysc_offs = sysc_offs;
3431*4882a593Smuzhiyun sysc->syss_offs = syss_offs;
3432*4882a593Smuzhiyun sysc->sysc_flags = sysc_flags;
3433*4882a593Smuzhiyun sysc->idlemodes = idlemodes;
3434*4882a593Smuzhiyun sysc->srst_udelay = data->cfg->srst_udelay;
3435*4882a593Smuzhiyun
3436*4882a593Smuzhiyun if (!oh->_mpu_rt_va) {
3437*4882a593Smuzhiyun regs = ioremap(data->module_pa,
3438*4882a593Smuzhiyun data->module_size);
3439*4882a593Smuzhiyun if (!regs)
3440*4882a593Smuzhiyun goto out_free_sysc;
3441*4882a593Smuzhiyun }
3442*4882a593Smuzhiyun
3443*4882a593Smuzhiyun /*
3444*4882a593Smuzhiyun * We may need a new oh->class as the other devices in the same class
3445*4882a593Smuzhiyun * may not yet have ioremapped their registers.
3446*4882a593Smuzhiyun */
3447*4882a593Smuzhiyun if (oh->class->name && strcmp(oh->class->name, data->name)) {
3448*4882a593Smuzhiyun class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL);
3449*4882a593Smuzhiyun if (!class)
3450*4882a593Smuzhiyun goto out_unmap;
3451*4882a593Smuzhiyun }
3452*4882a593Smuzhiyun
3453*4882a593Smuzhiyun if (list_empty(&oh->slave_ports)) {
3454*4882a593Smuzhiyun oi = kcalloc(1, sizeof(*oi), GFP_KERNEL);
3455*4882a593Smuzhiyun if (!oi)
3456*4882a593Smuzhiyun goto out_free_class;
3457*4882a593Smuzhiyun
3458*4882a593Smuzhiyun /*
3459*4882a593Smuzhiyun * Note that we assume interconnect interface clocks will be
3460*4882a593Smuzhiyun * managed by the interconnect driver for OCPIF_SWSUP_IDLE case
3461*4882a593Smuzhiyun * on omap24xx and omap3.
3462*4882a593Smuzhiyun */
3463*4882a593Smuzhiyun oi->slave = oh;
3464*4882a593Smuzhiyun oi->user = OCP_USER_MPU | OCP_USER_SDMA;
3465*4882a593Smuzhiyun }
3466*4882a593Smuzhiyun
3467*4882a593Smuzhiyun spin_lock_irqsave(&oh->_lock, flags);
3468*4882a593Smuzhiyun if (regs)
3469*4882a593Smuzhiyun oh->_mpu_rt_va = regs;
3470*4882a593Smuzhiyun if (class)
3471*4882a593Smuzhiyun oh->class = class;
3472*4882a593Smuzhiyun oh->class->sysc = sysc;
3473*4882a593Smuzhiyun if (oi)
3474*4882a593Smuzhiyun _add_link(oi);
3475*4882a593Smuzhiyun if (clkdm)
3476*4882a593Smuzhiyun oh->clkdm = clkdm;
3477*4882a593Smuzhiyun oh->_state = _HWMOD_STATE_INITIALIZED;
3478*4882a593Smuzhiyun oh->_postsetup_state = _HWMOD_STATE_DEFAULT;
3479*4882a593Smuzhiyun _setup(oh, NULL);
3480*4882a593Smuzhiyun spin_unlock_irqrestore(&oh->_lock, flags);
3481*4882a593Smuzhiyun
3482*4882a593Smuzhiyun return 0;
3483*4882a593Smuzhiyun
3484*4882a593Smuzhiyun out_free_class:
3485*4882a593Smuzhiyun kfree(class);
3486*4882a593Smuzhiyun out_unmap:
3487*4882a593Smuzhiyun iounmap(regs);
3488*4882a593Smuzhiyun out_free_sysc:
3489*4882a593Smuzhiyun kfree(sysc);
3490*4882a593Smuzhiyun return -ENOMEM;
3491*4882a593Smuzhiyun }
3492*4882a593Smuzhiyun
3493*4882a593Smuzhiyun static const struct omap_hwmod_reset omap24xx_reset_quirks[] = {
3494*4882a593Smuzhiyun { .match = "msdi", .len = 4, .reset = omap_msdi_reset, },
3495*4882a593Smuzhiyun };
3496*4882a593Smuzhiyun
3497*4882a593Smuzhiyun static const struct omap_hwmod_reset dra7_reset_quirks[] = {
3498*4882a593Smuzhiyun { .match = "pcie", .len = 4, .reset = dra7xx_pciess_reset, },
3499*4882a593Smuzhiyun };
3500*4882a593Smuzhiyun
3501*4882a593Smuzhiyun static const struct omap_hwmod_reset omap_reset_quirks[] = {
3502*4882a593Smuzhiyun { .match = "dss_core", .len = 8, .reset = omap_dss_reset, },
3503*4882a593Smuzhiyun { .match = "hdq1w", .len = 5, .reset = omap_hdq1w_reset, },
3504*4882a593Smuzhiyun { .match = "i2c", .len = 3, .reset = omap_i2c_reset, },
3505*4882a593Smuzhiyun { .match = "wd_timer", .len = 8, .reset = omap2_wd_timer_reset, },
3506*4882a593Smuzhiyun };
3507*4882a593Smuzhiyun
3508*4882a593Smuzhiyun static void
omap_hwmod_init_reset_quirk(struct device * dev,struct omap_hwmod * oh,const struct ti_sysc_module_data * data,const struct omap_hwmod_reset * quirks,int quirks_sz)3509*4882a593Smuzhiyun omap_hwmod_init_reset_quirk(struct device *dev, struct omap_hwmod *oh,
3510*4882a593Smuzhiyun const struct ti_sysc_module_data *data,
3511*4882a593Smuzhiyun const struct omap_hwmod_reset *quirks,
3512*4882a593Smuzhiyun int quirks_sz)
3513*4882a593Smuzhiyun {
3514*4882a593Smuzhiyun const struct omap_hwmod_reset *quirk;
3515*4882a593Smuzhiyun int i;
3516*4882a593Smuzhiyun
3517*4882a593Smuzhiyun for (i = 0; i < quirks_sz; i++) {
3518*4882a593Smuzhiyun quirk = &quirks[i];
3519*4882a593Smuzhiyun if (!strncmp(data->name, quirk->match, quirk->len)) {
3520*4882a593Smuzhiyun oh->class->reset = quirk->reset;
3521*4882a593Smuzhiyun
3522*4882a593Smuzhiyun return;
3523*4882a593Smuzhiyun }
3524*4882a593Smuzhiyun }
3525*4882a593Smuzhiyun }
3526*4882a593Smuzhiyun
3527*4882a593Smuzhiyun static void
omap_hwmod_init_reset_quirks(struct device * dev,struct omap_hwmod * oh,const struct ti_sysc_module_data * data)3528*4882a593Smuzhiyun omap_hwmod_init_reset_quirks(struct device *dev, struct omap_hwmod *oh,
3529*4882a593Smuzhiyun const struct ti_sysc_module_data *data)
3530*4882a593Smuzhiyun {
3531*4882a593Smuzhiyun if (soc_is_omap24xx())
3532*4882a593Smuzhiyun omap_hwmod_init_reset_quirk(dev, oh, data,
3533*4882a593Smuzhiyun omap24xx_reset_quirks,
3534*4882a593Smuzhiyun ARRAY_SIZE(omap24xx_reset_quirks));
3535*4882a593Smuzhiyun
3536*4882a593Smuzhiyun if (soc_is_dra7xx())
3537*4882a593Smuzhiyun omap_hwmod_init_reset_quirk(dev, oh, data, dra7_reset_quirks,
3538*4882a593Smuzhiyun ARRAY_SIZE(dra7_reset_quirks));
3539*4882a593Smuzhiyun
3540*4882a593Smuzhiyun omap_hwmod_init_reset_quirk(dev, oh, data, omap_reset_quirks,
3541*4882a593Smuzhiyun ARRAY_SIZE(omap_reset_quirks));
3542*4882a593Smuzhiyun }
3543*4882a593Smuzhiyun
3544*4882a593Smuzhiyun /**
3545*4882a593Smuzhiyun * omap_hwmod_init_module - initialize new module
3546*4882a593Smuzhiyun * @dev: struct device
3547*4882a593Smuzhiyun * @data: module data
3548*4882a593Smuzhiyun * @cookie: cookie for the caller to use for later calls
3549*4882a593Smuzhiyun */
omap_hwmod_init_module(struct device * dev,const struct ti_sysc_module_data * data,struct ti_sysc_cookie * cookie)3550*4882a593Smuzhiyun int omap_hwmod_init_module(struct device *dev,
3551*4882a593Smuzhiyun const struct ti_sysc_module_data *data,
3552*4882a593Smuzhiyun struct ti_sysc_cookie *cookie)
3553*4882a593Smuzhiyun {
3554*4882a593Smuzhiyun struct omap_hwmod *oh;
3555*4882a593Smuzhiyun struct sysc_regbits *sysc_fields;
3556*4882a593Smuzhiyun s32 rev_offs, sysc_offs, syss_offs;
3557*4882a593Smuzhiyun u32 sysc_flags, idlemodes;
3558*4882a593Smuzhiyun int error;
3559*4882a593Smuzhiyun
3560*4882a593Smuzhiyun if (!dev || !data || !data->name || !cookie)
3561*4882a593Smuzhiyun return -EINVAL;
3562*4882a593Smuzhiyun
3563*4882a593Smuzhiyun oh = _lookup(data->name);
3564*4882a593Smuzhiyun if (!oh) {
3565*4882a593Smuzhiyun oh = kzalloc(sizeof(*oh), GFP_KERNEL);
3566*4882a593Smuzhiyun if (!oh)
3567*4882a593Smuzhiyun return -ENOMEM;
3568*4882a593Smuzhiyun
3569*4882a593Smuzhiyun oh->name = data->name;
3570*4882a593Smuzhiyun oh->_state = _HWMOD_STATE_UNKNOWN;
3571*4882a593Smuzhiyun lockdep_register_key(&oh->hwmod_key);
3572*4882a593Smuzhiyun
3573*4882a593Smuzhiyun /* Unused, can be handled by PRM driver handling resets */
3574*4882a593Smuzhiyun oh->prcm.omap4.flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT;
3575*4882a593Smuzhiyun
3576*4882a593Smuzhiyun oh->class = kzalloc(sizeof(*oh->class), GFP_KERNEL);
3577*4882a593Smuzhiyun if (!oh->class) {
3578*4882a593Smuzhiyun kfree(oh);
3579*4882a593Smuzhiyun return -ENOMEM;
3580*4882a593Smuzhiyun }
3581*4882a593Smuzhiyun
3582*4882a593Smuzhiyun omap_hwmod_init_reset_quirks(dev, oh, data);
3583*4882a593Smuzhiyun
3584*4882a593Smuzhiyun oh->class->name = data->name;
3585*4882a593Smuzhiyun mutex_lock(&list_lock);
3586*4882a593Smuzhiyun error = _register(oh);
3587*4882a593Smuzhiyun mutex_unlock(&list_lock);
3588*4882a593Smuzhiyun }
3589*4882a593Smuzhiyun
3590*4882a593Smuzhiyun cookie->data = oh;
3591*4882a593Smuzhiyun
3592*4882a593Smuzhiyun error = omap_hwmod_init_regbits(dev, oh, data, &sysc_fields);
3593*4882a593Smuzhiyun if (error)
3594*4882a593Smuzhiyun return error;
3595*4882a593Smuzhiyun
3596*4882a593Smuzhiyun error = omap_hwmod_init_reg_offs(dev, data, &rev_offs,
3597*4882a593Smuzhiyun &sysc_offs, &syss_offs);
3598*4882a593Smuzhiyun if (error)
3599*4882a593Smuzhiyun return error;
3600*4882a593Smuzhiyun
3601*4882a593Smuzhiyun error = omap_hwmod_init_sysc_flags(dev, data, &sysc_flags);
3602*4882a593Smuzhiyun if (error)
3603*4882a593Smuzhiyun return error;
3604*4882a593Smuzhiyun
3605*4882a593Smuzhiyun error = omap_hwmod_init_idlemodes(dev, data, &idlemodes);
3606*4882a593Smuzhiyun if (error)
3607*4882a593Smuzhiyun return error;
3608*4882a593Smuzhiyun
3609*4882a593Smuzhiyun if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE)
3610*4882a593Smuzhiyun oh->flags |= HWMOD_NO_IDLE;
3611*4882a593Smuzhiyun if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE_ON_INIT)
3612*4882a593Smuzhiyun oh->flags |= HWMOD_INIT_NO_IDLE;
3613*4882a593Smuzhiyun if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
3614*4882a593Smuzhiyun oh->flags |= HWMOD_INIT_NO_RESET;
3615*4882a593Smuzhiyun if (data->cfg->quirks & SYSC_QUIRK_USE_CLOCKACT)
3616*4882a593Smuzhiyun oh->flags |= HWMOD_SET_DEFAULT_CLOCKACT;
3617*4882a593Smuzhiyun if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE)
3618*4882a593Smuzhiyun oh->flags |= HWMOD_SWSUP_SIDLE;
3619*4882a593Smuzhiyun if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE_ACT)
3620*4882a593Smuzhiyun oh->flags |= HWMOD_SWSUP_SIDLE_ACT;
3621*4882a593Smuzhiyun if (data->cfg->quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
3622*4882a593Smuzhiyun oh->flags |= HWMOD_SWSUP_MSTANDBY;
3623*4882a593Smuzhiyun if (data->cfg->quirks & SYSC_QUIRK_CLKDM_NOAUTO)
3624*4882a593Smuzhiyun oh->flags |= HWMOD_CLKDM_NOAUTO;
3625*4882a593Smuzhiyun
3626*4882a593Smuzhiyun error = omap_hwmod_check_module(dev, oh, data, sysc_fields,
3627*4882a593Smuzhiyun rev_offs, sysc_offs, syss_offs,
3628*4882a593Smuzhiyun sysc_flags, idlemodes);
3629*4882a593Smuzhiyun if (!error)
3630*4882a593Smuzhiyun return error;
3631*4882a593Smuzhiyun
3632*4882a593Smuzhiyun return omap_hwmod_allocate_module(dev, oh, data, sysc_fields,
3633*4882a593Smuzhiyun cookie->clkdm, rev_offs,
3634*4882a593Smuzhiyun sysc_offs, syss_offs,
3635*4882a593Smuzhiyun sysc_flags, idlemodes);
3636*4882a593Smuzhiyun }
3637*4882a593Smuzhiyun
3638*4882a593Smuzhiyun /**
3639*4882a593Smuzhiyun * omap_hwmod_setup_earlycon_flags - set up flags for early console
3640*4882a593Smuzhiyun *
3641*4882a593Smuzhiyun * Enable DEBUG_OMAPUART_FLAGS for uart hwmod that is being used as
3642*4882a593Smuzhiyun * early concole so that hwmod core doesn't reset and keep it in idle
3643*4882a593Smuzhiyun * that specific uart.
3644*4882a593Smuzhiyun */
3645*4882a593Smuzhiyun #ifdef CONFIG_SERIAL_EARLYCON
omap_hwmod_setup_earlycon_flags(void)3646*4882a593Smuzhiyun static void __init omap_hwmod_setup_earlycon_flags(void)
3647*4882a593Smuzhiyun {
3648*4882a593Smuzhiyun struct device_node *np;
3649*4882a593Smuzhiyun struct omap_hwmod *oh;
3650*4882a593Smuzhiyun const char *uart;
3651*4882a593Smuzhiyun
3652*4882a593Smuzhiyun np = of_find_node_by_path("/chosen");
3653*4882a593Smuzhiyun if (np) {
3654*4882a593Smuzhiyun uart = of_get_property(np, "stdout-path", NULL);
3655*4882a593Smuzhiyun if (uart) {
3656*4882a593Smuzhiyun np = of_find_node_by_path(uart);
3657*4882a593Smuzhiyun if (np) {
3658*4882a593Smuzhiyun uart = of_get_property(np, "ti,hwmods", NULL);
3659*4882a593Smuzhiyun oh = omap_hwmod_lookup(uart);
3660*4882a593Smuzhiyun if (!oh) {
3661*4882a593Smuzhiyun uart = of_get_property(np->parent,
3662*4882a593Smuzhiyun "ti,hwmods",
3663*4882a593Smuzhiyun NULL);
3664*4882a593Smuzhiyun oh = omap_hwmod_lookup(uart);
3665*4882a593Smuzhiyun }
3666*4882a593Smuzhiyun if (oh)
3667*4882a593Smuzhiyun oh->flags |= DEBUG_OMAPUART_FLAGS;
3668*4882a593Smuzhiyun }
3669*4882a593Smuzhiyun }
3670*4882a593Smuzhiyun }
3671*4882a593Smuzhiyun }
3672*4882a593Smuzhiyun #endif
3673*4882a593Smuzhiyun
3674*4882a593Smuzhiyun /**
3675*4882a593Smuzhiyun * omap_hwmod_setup_all - set up all registered IP blocks
3676*4882a593Smuzhiyun *
3677*4882a593Smuzhiyun * Initialize and set up all IP blocks registered with the hwmod code.
3678*4882a593Smuzhiyun * Must be called after omap2_clk_init(). Resolves the struct clk
3679*4882a593Smuzhiyun * names to struct clk pointers for each registered omap_hwmod. Also
3680*4882a593Smuzhiyun * calls _setup() on each hwmod. Returns 0 upon success.
3681*4882a593Smuzhiyun */
omap_hwmod_setup_all(void)3682*4882a593Smuzhiyun static int __init omap_hwmod_setup_all(void)
3683*4882a593Smuzhiyun {
3684*4882a593Smuzhiyun _ensure_mpu_hwmod_is_setup(NULL);
3685*4882a593Smuzhiyun
3686*4882a593Smuzhiyun omap_hwmod_for_each(_init, NULL);
3687*4882a593Smuzhiyun #ifdef CONFIG_SERIAL_EARLYCON
3688*4882a593Smuzhiyun omap_hwmod_setup_earlycon_flags();
3689*4882a593Smuzhiyun #endif
3690*4882a593Smuzhiyun omap_hwmod_for_each(_setup, NULL);
3691*4882a593Smuzhiyun
3692*4882a593Smuzhiyun return 0;
3693*4882a593Smuzhiyun }
3694*4882a593Smuzhiyun omap_postcore_initcall(omap_hwmod_setup_all);
3695*4882a593Smuzhiyun
3696*4882a593Smuzhiyun /**
3697*4882a593Smuzhiyun * omap_hwmod_enable - enable an omap_hwmod
3698*4882a593Smuzhiyun * @oh: struct omap_hwmod *
3699*4882a593Smuzhiyun *
3700*4882a593Smuzhiyun * Enable an omap_hwmod @oh. Intended to be called by omap_device_enable().
3701*4882a593Smuzhiyun * Returns -EINVAL on error or passes along the return value from _enable().
3702*4882a593Smuzhiyun */
omap_hwmod_enable(struct omap_hwmod * oh)3703*4882a593Smuzhiyun int omap_hwmod_enable(struct omap_hwmod *oh)
3704*4882a593Smuzhiyun {
3705*4882a593Smuzhiyun int r;
3706*4882a593Smuzhiyun unsigned long flags;
3707*4882a593Smuzhiyun
3708*4882a593Smuzhiyun if (!oh)
3709*4882a593Smuzhiyun return -EINVAL;
3710*4882a593Smuzhiyun
3711*4882a593Smuzhiyun spin_lock_irqsave(&oh->_lock, flags);
3712*4882a593Smuzhiyun r = _enable(oh);
3713*4882a593Smuzhiyun spin_unlock_irqrestore(&oh->_lock, flags);
3714*4882a593Smuzhiyun
3715*4882a593Smuzhiyun return r;
3716*4882a593Smuzhiyun }
3717*4882a593Smuzhiyun
3718*4882a593Smuzhiyun /**
3719*4882a593Smuzhiyun * omap_hwmod_idle - idle an omap_hwmod
3720*4882a593Smuzhiyun * @oh: struct omap_hwmod *
3721*4882a593Smuzhiyun *
3722*4882a593Smuzhiyun * Idle an omap_hwmod @oh. Intended to be called by omap_device_idle().
3723*4882a593Smuzhiyun * Returns -EINVAL on error or passes along the return value from _idle().
3724*4882a593Smuzhiyun */
omap_hwmod_idle(struct omap_hwmod * oh)3725*4882a593Smuzhiyun int omap_hwmod_idle(struct omap_hwmod *oh)
3726*4882a593Smuzhiyun {
3727*4882a593Smuzhiyun int r;
3728*4882a593Smuzhiyun unsigned long flags;
3729*4882a593Smuzhiyun
3730*4882a593Smuzhiyun if (!oh)
3731*4882a593Smuzhiyun return -EINVAL;
3732*4882a593Smuzhiyun
3733*4882a593Smuzhiyun spin_lock_irqsave(&oh->_lock, flags);
3734*4882a593Smuzhiyun r = _idle(oh);
3735*4882a593Smuzhiyun spin_unlock_irqrestore(&oh->_lock, flags);
3736*4882a593Smuzhiyun
3737*4882a593Smuzhiyun return r;
3738*4882a593Smuzhiyun }
3739*4882a593Smuzhiyun
3740*4882a593Smuzhiyun /**
3741*4882a593Smuzhiyun * omap_hwmod_shutdown - shutdown an omap_hwmod
3742*4882a593Smuzhiyun * @oh: struct omap_hwmod *
3743*4882a593Smuzhiyun *
3744*4882a593Smuzhiyun * Shutdown an omap_hwmod @oh. Intended to be called by
3745*4882a593Smuzhiyun * omap_device_shutdown(). Returns -EINVAL on error or passes along
3746*4882a593Smuzhiyun * the return value from _shutdown().
3747*4882a593Smuzhiyun */
omap_hwmod_shutdown(struct omap_hwmod * oh)3748*4882a593Smuzhiyun int omap_hwmod_shutdown(struct omap_hwmod *oh)
3749*4882a593Smuzhiyun {
3750*4882a593Smuzhiyun int r;
3751*4882a593Smuzhiyun unsigned long flags;
3752*4882a593Smuzhiyun
3753*4882a593Smuzhiyun if (!oh)
3754*4882a593Smuzhiyun return -EINVAL;
3755*4882a593Smuzhiyun
3756*4882a593Smuzhiyun spin_lock_irqsave(&oh->_lock, flags);
3757*4882a593Smuzhiyun r = _shutdown(oh);
3758*4882a593Smuzhiyun spin_unlock_irqrestore(&oh->_lock, flags);
3759*4882a593Smuzhiyun
3760*4882a593Smuzhiyun return r;
3761*4882a593Smuzhiyun }
3762*4882a593Smuzhiyun
3763*4882a593Smuzhiyun /*
3764*4882a593Smuzhiyun * IP block data retrieval functions
3765*4882a593Smuzhiyun */
3766*4882a593Smuzhiyun
3767*4882a593Smuzhiyun /**
3768*4882a593Smuzhiyun * omap_hwmod_get_pwrdm - return pointer to this module's main powerdomain
3769*4882a593Smuzhiyun * @oh: struct omap_hwmod *
3770*4882a593Smuzhiyun *
3771*4882a593Smuzhiyun * Return the powerdomain pointer associated with the OMAP module
3772*4882a593Smuzhiyun * @oh's main clock. If @oh does not have a main clk, return the
3773*4882a593Smuzhiyun * powerdomain associated with the interface clock associated with the
3774*4882a593Smuzhiyun * module's MPU port. (XXX Perhaps this should use the SDMA port
3775*4882a593Smuzhiyun * instead?) Returns NULL on error, or a struct powerdomain * on
3776*4882a593Smuzhiyun * success.
3777*4882a593Smuzhiyun */
omap_hwmod_get_pwrdm(struct omap_hwmod * oh)3778*4882a593Smuzhiyun struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh)
3779*4882a593Smuzhiyun {
3780*4882a593Smuzhiyun struct clk *c;
3781*4882a593Smuzhiyun struct omap_hwmod_ocp_if *oi;
3782*4882a593Smuzhiyun struct clockdomain *clkdm;
3783*4882a593Smuzhiyun struct clk_hw_omap *clk;
3784*4882a593Smuzhiyun struct clk_hw *hw;
3785*4882a593Smuzhiyun
3786*4882a593Smuzhiyun if (!oh)
3787*4882a593Smuzhiyun return NULL;
3788*4882a593Smuzhiyun
3789*4882a593Smuzhiyun if (oh->clkdm)
3790*4882a593Smuzhiyun return oh->clkdm->pwrdm.ptr;
3791*4882a593Smuzhiyun
3792*4882a593Smuzhiyun if (oh->_clk) {
3793*4882a593Smuzhiyun c = oh->_clk;
3794*4882a593Smuzhiyun } else {
3795*4882a593Smuzhiyun oi = _find_mpu_rt_port(oh);
3796*4882a593Smuzhiyun if (!oi)
3797*4882a593Smuzhiyun return NULL;
3798*4882a593Smuzhiyun c = oi->_clk;
3799*4882a593Smuzhiyun }
3800*4882a593Smuzhiyun
3801*4882a593Smuzhiyun hw = __clk_get_hw(c);
3802*4882a593Smuzhiyun if (!hw)
3803*4882a593Smuzhiyun return NULL;
3804*4882a593Smuzhiyun
3805*4882a593Smuzhiyun clk = to_clk_hw_omap(hw);
3806*4882a593Smuzhiyun if (!clk)
3807*4882a593Smuzhiyun return NULL;
3808*4882a593Smuzhiyun
3809*4882a593Smuzhiyun clkdm = clk->clkdm;
3810*4882a593Smuzhiyun if (!clkdm)
3811*4882a593Smuzhiyun return NULL;
3812*4882a593Smuzhiyun
3813*4882a593Smuzhiyun return clkdm->pwrdm.ptr;
3814*4882a593Smuzhiyun }
3815*4882a593Smuzhiyun
3816*4882a593Smuzhiyun /**
3817*4882a593Smuzhiyun * omap_hwmod_get_mpu_rt_va - return the module's base address (for the MPU)
3818*4882a593Smuzhiyun * @oh: struct omap_hwmod *
3819*4882a593Smuzhiyun *
3820*4882a593Smuzhiyun * Returns the virtual address corresponding to the beginning of the
3821*4882a593Smuzhiyun * module's register target, in the address range that is intended to
3822*4882a593Smuzhiyun * be used by the MPU. Returns the virtual address upon success or NULL
3823*4882a593Smuzhiyun * upon error.
3824*4882a593Smuzhiyun */
omap_hwmod_get_mpu_rt_va(struct omap_hwmod * oh)3825*4882a593Smuzhiyun void __iomem *omap_hwmod_get_mpu_rt_va(struct omap_hwmod *oh)
3826*4882a593Smuzhiyun {
3827*4882a593Smuzhiyun if (!oh)
3828*4882a593Smuzhiyun return NULL;
3829*4882a593Smuzhiyun
3830*4882a593Smuzhiyun if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
3831*4882a593Smuzhiyun return NULL;
3832*4882a593Smuzhiyun
3833*4882a593Smuzhiyun if (oh->_state == _HWMOD_STATE_UNKNOWN)
3834*4882a593Smuzhiyun return NULL;
3835*4882a593Smuzhiyun
3836*4882a593Smuzhiyun return oh->_mpu_rt_va;
3837*4882a593Smuzhiyun }
3838*4882a593Smuzhiyun
3839*4882a593Smuzhiyun /*
3840*4882a593Smuzhiyun * XXX what about functions for drivers to save/restore ocp_sysconfig
3841*4882a593Smuzhiyun * for context save/restore operations?
3842*4882a593Smuzhiyun */
3843*4882a593Smuzhiyun
3844*4882a593Smuzhiyun /**
3845*4882a593Smuzhiyun * omap_hwmod_assert_hardreset - assert the HW reset line of submodules
3846*4882a593Smuzhiyun * contained in the hwmod module.
3847*4882a593Smuzhiyun * @oh: struct omap_hwmod *
3848*4882a593Smuzhiyun * @name: name of the reset line to lookup and assert
3849*4882a593Smuzhiyun *
3850*4882a593Smuzhiyun * Some IP like dsp, ipu or iva contain processor that require
3851*4882a593Smuzhiyun * an HW reset line to be assert / deassert in order to enable fully
3852*4882a593Smuzhiyun * the IP. Returns -EINVAL if @oh is null or if the operation is not
3853*4882a593Smuzhiyun * yet supported on this OMAP; otherwise, passes along the return value
3854*4882a593Smuzhiyun * from _assert_hardreset().
3855*4882a593Smuzhiyun */
omap_hwmod_assert_hardreset(struct omap_hwmod * oh,const char * name)3856*4882a593Smuzhiyun int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name)
3857*4882a593Smuzhiyun {
3858*4882a593Smuzhiyun int ret;
3859*4882a593Smuzhiyun unsigned long flags;
3860*4882a593Smuzhiyun
3861*4882a593Smuzhiyun if (!oh)
3862*4882a593Smuzhiyun return -EINVAL;
3863*4882a593Smuzhiyun
3864*4882a593Smuzhiyun spin_lock_irqsave(&oh->_lock, flags);
3865*4882a593Smuzhiyun ret = _assert_hardreset(oh, name);
3866*4882a593Smuzhiyun spin_unlock_irqrestore(&oh->_lock, flags);
3867*4882a593Smuzhiyun
3868*4882a593Smuzhiyun return ret;
3869*4882a593Smuzhiyun }
3870*4882a593Smuzhiyun
3871*4882a593Smuzhiyun /**
3872*4882a593Smuzhiyun * omap_hwmod_deassert_hardreset - deassert the HW reset line of submodules
3873*4882a593Smuzhiyun * contained in the hwmod module.
3874*4882a593Smuzhiyun * @oh: struct omap_hwmod *
3875*4882a593Smuzhiyun * @name: name of the reset line to look up and deassert
3876*4882a593Smuzhiyun *
3877*4882a593Smuzhiyun * Some IP like dsp, ipu or iva contain processor that require
3878*4882a593Smuzhiyun * an HW reset line to be assert / deassert in order to enable fully
3879*4882a593Smuzhiyun * the IP. Returns -EINVAL if @oh is null or if the operation is not
3880*4882a593Smuzhiyun * yet supported on this OMAP; otherwise, passes along the return value
3881*4882a593Smuzhiyun * from _deassert_hardreset().
3882*4882a593Smuzhiyun */
omap_hwmod_deassert_hardreset(struct omap_hwmod * oh,const char * name)3883*4882a593Smuzhiyun int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name)
3884*4882a593Smuzhiyun {
3885*4882a593Smuzhiyun int ret;
3886*4882a593Smuzhiyun unsigned long flags;
3887*4882a593Smuzhiyun
3888*4882a593Smuzhiyun if (!oh)
3889*4882a593Smuzhiyun return -EINVAL;
3890*4882a593Smuzhiyun
3891*4882a593Smuzhiyun spin_lock_irqsave(&oh->_lock, flags);
3892*4882a593Smuzhiyun ret = _deassert_hardreset(oh, name);
3893*4882a593Smuzhiyun spin_unlock_irqrestore(&oh->_lock, flags);
3894*4882a593Smuzhiyun
3895*4882a593Smuzhiyun return ret;
3896*4882a593Smuzhiyun }
3897*4882a593Smuzhiyun
3898*4882a593Smuzhiyun /**
3899*4882a593Smuzhiyun * omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname
3900*4882a593Smuzhiyun * @classname: struct omap_hwmod_class name to search for
3901*4882a593Smuzhiyun * @fn: callback function pointer to call for each hwmod in class @classname
3902*4882a593Smuzhiyun * @user: arbitrary context data to pass to the callback function
3903*4882a593Smuzhiyun *
3904*4882a593Smuzhiyun * For each omap_hwmod of class @classname, call @fn.
3905*4882a593Smuzhiyun * If the callback function returns something other than
3906*4882a593Smuzhiyun * zero, the iterator is terminated, and the callback function's return
3907*4882a593Smuzhiyun * value is passed back to the caller. Returns 0 upon success, -EINVAL
3908*4882a593Smuzhiyun * if @classname or @fn are NULL, or passes back the error code from @fn.
3909*4882a593Smuzhiyun */
omap_hwmod_for_each_by_class(const char * classname,int (* fn)(struct omap_hwmod * oh,void * user),void * user)3910*4882a593Smuzhiyun int omap_hwmod_for_each_by_class(const char *classname,
3911*4882a593Smuzhiyun int (*fn)(struct omap_hwmod *oh,
3912*4882a593Smuzhiyun void *user),
3913*4882a593Smuzhiyun void *user)
3914*4882a593Smuzhiyun {
3915*4882a593Smuzhiyun struct omap_hwmod *temp_oh;
3916*4882a593Smuzhiyun int ret = 0;
3917*4882a593Smuzhiyun
3918*4882a593Smuzhiyun if (!classname || !fn)
3919*4882a593Smuzhiyun return -EINVAL;
3920*4882a593Smuzhiyun
3921*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: looking for modules of class %s\n",
3922*4882a593Smuzhiyun __func__, classname);
3923*4882a593Smuzhiyun
3924*4882a593Smuzhiyun list_for_each_entry(temp_oh, &omap_hwmod_list, node) {
3925*4882a593Smuzhiyun if (!strcmp(temp_oh->class->name, classname)) {
3926*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: %s: calling callback fn\n",
3927*4882a593Smuzhiyun __func__, temp_oh->name);
3928*4882a593Smuzhiyun ret = (*fn)(temp_oh, user);
3929*4882a593Smuzhiyun if (ret)
3930*4882a593Smuzhiyun break;
3931*4882a593Smuzhiyun }
3932*4882a593Smuzhiyun }
3933*4882a593Smuzhiyun
3934*4882a593Smuzhiyun if (ret)
3935*4882a593Smuzhiyun pr_debug("omap_hwmod: %s: iterator terminated early: %d\n",
3936*4882a593Smuzhiyun __func__, ret);
3937*4882a593Smuzhiyun
3938*4882a593Smuzhiyun return ret;
3939*4882a593Smuzhiyun }
3940*4882a593Smuzhiyun
3941*4882a593Smuzhiyun /**
3942*4882a593Smuzhiyun * omap_hwmod_set_postsetup_state - set the post-_setup() state for this hwmod
3943*4882a593Smuzhiyun * @oh: struct omap_hwmod *
3944*4882a593Smuzhiyun * @state: state that _setup() should leave the hwmod in
3945*4882a593Smuzhiyun *
3946*4882a593Smuzhiyun * Sets the hwmod state that @oh will enter at the end of _setup()
3947*4882a593Smuzhiyun * (called by omap_hwmod_setup_*()). See also the documentation
3948*4882a593Smuzhiyun * for _setup_postsetup(), above. Returns 0 upon success or
3949*4882a593Smuzhiyun * -EINVAL if there is a problem with the arguments or if the hwmod is
3950*4882a593Smuzhiyun * in the wrong state.
3951*4882a593Smuzhiyun */
omap_hwmod_set_postsetup_state(struct omap_hwmod * oh,u8 state)3952*4882a593Smuzhiyun int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state)
3953*4882a593Smuzhiyun {
3954*4882a593Smuzhiyun int ret;
3955*4882a593Smuzhiyun unsigned long flags;
3956*4882a593Smuzhiyun
3957*4882a593Smuzhiyun if (!oh)
3958*4882a593Smuzhiyun return -EINVAL;
3959*4882a593Smuzhiyun
3960*4882a593Smuzhiyun if (state != _HWMOD_STATE_DISABLED &&
3961*4882a593Smuzhiyun state != _HWMOD_STATE_ENABLED &&
3962*4882a593Smuzhiyun state != _HWMOD_STATE_IDLE)
3963*4882a593Smuzhiyun return -EINVAL;
3964*4882a593Smuzhiyun
3965*4882a593Smuzhiyun spin_lock_irqsave(&oh->_lock, flags);
3966*4882a593Smuzhiyun
3967*4882a593Smuzhiyun if (oh->_state != _HWMOD_STATE_REGISTERED) {
3968*4882a593Smuzhiyun ret = -EINVAL;
3969*4882a593Smuzhiyun goto ohsps_unlock;
3970*4882a593Smuzhiyun }
3971*4882a593Smuzhiyun
3972*4882a593Smuzhiyun oh->_postsetup_state = state;
3973*4882a593Smuzhiyun ret = 0;
3974*4882a593Smuzhiyun
3975*4882a593Smuzhiyun ohsps_unlock:
3976*4882a593Smuzhiyun spin_unlock_irqrestore(&oh->_lock, flags);
3977*4882a593Smuzhiyun
3978*4882a593Smuzhiyun return ret;
3979*4882a593Smuzhiyun }
3980*4882a593Smuzhiyun
3981*4882a593Smuzhiyun /**
3982*4882a593Smuzhiyun * omap_hwmod_get_context_loss_count - get lost context count
3983*4882a593Smuzhiyun * @oh: struct omap_hwmod *
3984*4882a593Smuzhiyun *
3985*4882a593Smuzhiyun * Returns the context loss count of associated @oh
3986*4882a593Smuzhiyun * upon success, or zero if no context loss data is available.
3987*4882a593Smuzhiyun *
3988*4882a593Smuzhiyun * On OMAP4, this queries the per-hwmod context loss register,
3989*4882a593Smuzhiyun * assuming one exists. If not, or on OMAP2/3, this queries the
3990*4882a593Smuzhiyun * enclosing powerdomain context loss count.
3991*4882a593Smuzhiyun */
omap_hwmod_get_context_loss_count(struct omap_hwmod * oh)3992*4882a593Smuzhiyun int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh)
3993*4882a593Smuzhiyun {
3994*4882a593Smuzhiyun struct powerdomain *pwrdm;
3995*4882a593Smuzhiyun int ret = 0;
3996*4882a593Smuzhiyun
3997*4882a593Smuzhiyun if (soc_ops.get_context_lost)
3998*4882a593Smuzhiyun return soc_ops.get_context_lost(oh);
3999*4882a593Smuzhiyun
4000*4882a593Smuzhiyun pwrdm = omap_hwmod_get_pwrdm(oh);
4001*4882a593Smuzhiyun if (pwrdm)
4002*4882a593Smuzhiyun ret = pwrdm_get_context_loss_count(pwrdm);
4003*4882a593Smuzhiyun
4004*4882a593Smuzhiyun return ret;
4005*4882a593Smuzhiyun }
4006*4882a593Smuzhiyun
4007*4882a593Smuzhiyun /**
4008*4882a593Smuzhiyun * omap_hwmod_init - initialize the hwmod code
4009*4882a593Smuzhiyun *
4010*4882a593Smuzhiyun * Sets up some function pointers needed by the hwmod code to operate on the
4011*4882a593Smuzhiyun * currently-booted SoC. Intended to be called once during kernel init
4012*4882a593Smuzhiyun * before any hwmods are registered. No return value.
4013*4882a593Smuzhiyun */
omap_hwmod_init(void)4014*4882a593Smuzhiyun void __init omap_hwmod_init(void)
4015*4882a593Smuzhiyun {
4016*4882a593Smuzhiyun if (cpu_is_omap24xx()) {
4017*4882a593Smuzhiyun soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready;
4018*4882a593Smuzhiyun soc_ops.assert_hardreset = _omap2_assert_hardreset;
4019*4882a593Smuzhiyun soc_ops.deassert_hardreset = _omap2_deassert_hardreset;
4020*4882a593Smuzhiyun soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted;
4021*4882a593Smuzhiyun } else if (cpu_is_omap34xx()) {
4022*4882a593Smuzhiyun soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready;
4023*4882a593Smuzhiyun soc_ops.assert_hardreset = _omap2_assert_hardreset;
4024*4882a593Smuzhiyun soc_ops.deassert_hardreset = _omap2_deassert_hardreset;
4025*4882a593Smuzhiyun soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted;
4026*4882a593Smuzhiyun soc_ops.init_clkdm = _init_clkdm;
4027*4882a593Smuzhiyun } else if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) {
4028*4882a593Smuzhiyun soc_ops.enable_module = _omap4_enable_module;
4029*4882a593Smuzhiyun soc_ops.disable_module = _omap4_disable_module;
4030*4882a593Smuzhiyun soc_ops.wait_target_ready = _omap4_wait_target_ready;
4031*4882a593Smuzhiyun soc_ops.assert_hardreset = _omap4_assert_hardreset;
4032*4882a593Smuzhiyun soc_ops.deassert_hardreset = _omap4_deassert_hardreset;
4033*4882a593Smuzhiyun soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted;
4034*4882a593Smuzhiyun soc_ops.init_clkdm = _init_clkdm;
4035*4882a593Smuzhiyun soc_ops.update_context_lost = _omap4_update_context_lost;
4036*4882a593Smuzhiyun soc_ops.get_context_lost = _omap4_get_context_lost;
4037*4882a593Smuzhiyun soc_ops.disable_direct_prcm = _omap4_disable_direct_prcm;
4038*4882a593Smuzhiyun soc_ops.xlate_clkctrl = _omap4_xlate_clkctrl;
4039*4882a593Smuzhiyun } else if (cpu_is_ti814x() || cpu_is_ti816x() || soc_is_am33xx() ||
4040*4882a593Smuzhiyun soc_is_am43xx()) {
4041*4882a593Smuzhiyun soc_ops.enable_module = _omap4_enable_module;
4042*4882a593Smuzhiyun soc_ops.disable_module = _omap4_disable_module;
4043*4882a593Smuzhiyun soc_ops.wait_target_ready = _omap4_wait_target_ready;
4044*4882a593Smuzhiyun soc_ops.assert_hardreset = _omap4_assert_hardreset;
4045*4882a593Smuzhiyun soc_ops.deassert_hardreset = _am33xx_deassert_hardreset;
4046*4882a593Smuzhiyun soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted;
4047*4882a593Smuzhiyun soc_ops.init_clkdm = _init_clkdm;
4048*4882a593Smuzhiyun soc_ops.disable_direct_prcm = _omap4_disable_direct_prcm;
4049*4882a593Smuzhiyun soc_ops.xlate_clkctrl = _omap4_xlate_clkctrl;
4050*4882a593Smuzhiyun } else {
4051*4882a593Smuzhiyun WARN(1, "omap_hwmod: unknown SoC type\n");
4052*4882a593Smuzhiyun }
4053*4882a593Smuzhiyun
4054*4882a593Smuzhiyun _init_clkctrl_providers();
4055*4882a593Smuzhiyun
4056*4882a593Smuzhiyun inited = true;
4057*4882a593Smuzhiyun }
4058*4882a593Smuzhiyun
4059*4882a593Smuzhiyun /**
4060*4882a593Smuzhiyun * omap_hwmod_get_main_clk - get pointer to main clock name
4061*4882a593Smuzhiyun * @oh: struct omap_hwmod *
4062*4882a593Smuzhiyun *
4063*4882a593Smuzhiyun * Returns the main clock name assocated with @oh upon success,
4064*4882a593Smuzhiyun * or NULL if @oh is NULL.
4065*4882a593Smuzhiyun */
omap_hwmod_get_main_clk(struct omap_hwmod * oh)4066*4882a593Smuzhiyun const char *omap_hwmod_get_main_clk(struct omap_hwmod *oh)
4067*4882a593Smuzhiyun {
4068*4882a593Smuzhiyun if (!oh)
4069*4882a593Smuzhiyun return NULL;
4070*4882a593Smuzhiyun
4071*4882a593Smuzhiyun return oh->main_clk;
4072*4882a593Smuzhiyun }
4073