blob: f3d578be327238d6e6dddd11f6af9fa37b1e6c3c [file] [log] [blame]
Paul Walmsley21325b252012-10-21 01:01:12 -06001/*
2 * OMAP2+ common Clock Management (CM) IP block functions
3 *
4 * Copyright (C) 2012 Texas Instruments, Inc.
Paul Walmsleyd9a16f92012-10-29 20:57:39 -06005 * Paul Walmsley
Paul Walmsley21325b252012-10-21 01:01:12 -06006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * XXX This code should eventually be moved to a CM driver.
12 */
13
14#include <linux/kernel.h>
15#include <linux/init.h>
Peter Ujfalusicc4b1e22012-11-12 16:17:08 +010016#include <linux/errno.h>
Tero Kristo47942082014-05-11 19:41:50 -060017#include <linux/bug.h>
Tero Kristofe874142014-03-12 18:33:45 +020018#include <linux/of.h>
19#include <linux/of_address.h>
Paul Walmsley21325b252012-10-21 01:01:12 -060020
21#include "cm2xxx.h"
22#include "cm3xxx.h"
23#include "cm44xx.h"
Tero Kristofe874142014-03-12 18:33:45 +020024#include "clock.h"
Paul Walmsley21325b252012-10-21 01:01:12 -060025
26/*
27 * cm_ll_data: function pointers to SoC-specific implementations of
28 * common CM functions
29 */
30static struct cm_ll_data null_cm_ll_data;
31static struct cm_ll_data *cm_ll_data = &null_cm_ll_data;
32
Paul Walmsleyd9a16f92012-10-29 20:57:39 -060033/* cm_base: base virtual address of the CM IP block */
34void __iomem *cm_base;
35
36/* cm2_base: base virtual address of the CM2 IP block (OMAP44xx only) */
37void __iomem *cm2_base;
38
39/**
40 * omap2_set_globals_cm - set the CM/CM2 base addresses (for early use)
41 * @cm: CM base virtual address
42 * @cm2: CM2 base virtual address (if present on the booted SoC)
43 *
44 * XXX Will be replaced when the PRM/CM drivers are completed.
45 */
46void __init omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2)
47{
48 cm_base = cm;
49 cm2_base = cm2;
50}
51
Paul Walmsley21325b252012-10-21 01:01:12 -060052/**
Paul Walmsleyc4ceedc2012-10-29 20:56:29 -060053 * cm_split_idlest_reg - split CM_IDLEST reg addr into its components
54 * @idlest_reg: CM_IDLEST* virtual address
55 * @prcm_inst: pointer to an s16 to return the PRCM instance offset
56 * @idlest_reg_id: pointer to a u8 to return the CM_IDLESTx register ID
57 *
58 * Given an absolute CM_IDLEST register address @idlest_reg, passes
59 * the PRCM instance offset and IDLEST register ID back to the caller
60 * via the @prcm_inst and @idlest_reg_id. Returns -EINVAL upon error,
61 * or 0 upon success. XXX This function is only needed until absolute
62 * register addresses are removed from the OMAP struct clk records.
63 */
64int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
65 u8 *idlest_reg_id)
66{
67 if (!cm_ll_data->split_idlest_reg) {
68 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
69 __func__);
70 return -EINVAL;
71 }
72
73 return cm_ll_data->split_idlest_reg(idlest_reg, prcm_inst,
74 idlest_reg_id);
75}
76
77/**
Tero Kristo021b6ff2014-10-27 08:39:23 -070078 * omap_cm_wait_module_ready - wait for a module to leave idle or standby
79 * @part: PRCM partition
Paul Walmsleyc4ceedc2012-10-29 20:56:29 -060080 * @prcm_mod: PRCM module offset
Tero Kristo021b6ff2014-10-27 08:39:23 -070081 * @idlest_reg: CM_IDLESTx register
Paul Walmsleyc4ceedc2012-10-29 20:56:29 -060082 * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
83 *
84 * Wait for the PRCM to indicate that the module identified by
85 * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon
86 * success, -EBUSY if the module doesn't enable in time, or -EINVAL if
87 * no per-SoC wait_module_ready() function pointer has been registered
88 * or if the idlest register is unknown on the SoC.
89 */
Tero Kristo021b6ff2014-10-27 08:39:23 -070090int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg,
91 u8 idlest_shift)
Paul Walmsleyc4ceedc2012-10-29 20:56:29 -060092{
93 if (!cm_ll_data->wait_module_ready) {
94 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
95 __func__);
96 return -EINVAL;
97 }
98
Tero Kristo021b6ff2014-10-27 08:39:23 -070099 return cm_ll_data->wait_module_ready(part, prcm_mod, idlest_reg,
100 idlest_shift);
Paul Walmsleyc4ceedc2012-10-29 20:56:29 -0600101}
102
103/**
Tero Kristoa8ae5af2014-10-27 08:39:23 -0700104 * omap_cm_wait_module_idle - wait for a module to enter idle or standby
105 * @part: PRCM partition
106 * @prcm_mod: PRCM module offset
107 * @idlest_reg: CM_IDLESTx register
108 * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
109 *
110 * Wait for the PRCM to indicate that the module identified by
111 * (@prcm_mod, @idlest_id, @idlest_shift) is no longer clocked. Return
112 * 0 upon success, -EBUSY if the module doesn't enable in time, or
113 * -EINVAL if no per-SoC wait_module_idle() function pointer has been
114 * registered or if the idlest register is unknown on the SoC.
115 */
116int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg,
117 u8 idlest_shift)
118{
119 if (!cm_ll_data->wait_module_idle) {
120 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
121 __func__);
122 return -EINVAL;
123 }
124
125 return cm_ll_data->wait_module_idle(part, prcm_mod, idlest_reg,
126 idlest_shift);
127}
128
129/**
Tero Kristo128603f2014-10-27 08:39:24 -0700130 * omap_cm_module_enable - enable a module
131 * @mode: target mode for the module
132 * @part: PRCM partition
133 * @inst: PRCM instance
134 * @clkctrl_offs: CM_CLKCTRL register offset for the module
135 *
136 * Enables clocks for a module identified by (@part, @inst, @clkctrl_offs)
137 * making its IO space accessible. Return 0 upon success, -EINVAL if no
138 * per-SoC module_enable() function pointer has been registered.
139 */
140int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs)
141{
142 if (!cm_ll_data->module_enable) {
143 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
144 __func__);
145 return -EINVAL;
146 }
147
148 cm_ll_data->module_enable(mode, part, inst, clkctrl_offs);
149 return 0;
150}
151
152/**
153 * omap_cm_module_disable - disable a module
154 * @part: PRCM partition
155 * @inst: PRCM instance
156 * @clkctrl_offs: CM_CLKCTRL register offset for the module
157 *
158 * Disables clocks for a module identified by (@part, @inst, @clkctrl_offs)
159 * makings its IO space inaccessible. Return 0 upon success, -EINVAL if
160 * no per-SoC module_disable() function pointer has been registered.
161 */
162int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
163{
164 if (!cm_ll_data->module_disable) {
165 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
166 __func__);
167 return -EINVAL;
168 }
169
170 cm_ll_data->module_disable(part, inst, clkctrl_offs);
171 return 0;
172}
173
174/**
Paul Walmsley21325b252012-10-21 01:01:12 -0600175 * cm_register - register per-SoC low-level data with the CM
176 * @cld: low-level per-SoC OMAP CM data & function pointers to register
177 *
178 * Register per-SoC low-level OMAP CM data and function pointers with
179 * the OMAP CM common interface. The caller must keep the data
180 * pointed to by @cld valid until it calls cm_unregister() and
181 * it returns successfully. Returns 0 upon success, -EINVAL if @cld
182 * is NULL, or -EEXIST if cm_register() has already been called
183 * without an intervening cm_unregister().
184 */
185int cm_register(struct cm_ll_data *cld)
186{
187 if (!cld)
188 return -EINVAL;
189
190 if (cm_ll_data != &null_cm_ll_data)
191 return -EEXIST;
192
193 cm_ll_data = cld;
194
195 return 0;
196}
197
198/**
199 * cm_unregister - unregister per-SoC low-level data & function pointers
200 * @cld: low-level per-SoC OMAP CM data & function pointers to unregister
201 *
202 * Unregister per-SoC low-level OMAP CM data and function pointers
203 * that were previously registered with cm_register(). The
204 * caller may not destroy any of the data pointed to by @cld until
205 * this function returns successfully. Returns 0 upon success, or
206 * -EINVAL if @cld is NULL or if @cld does not match the struct
207 * cm_ll_data * previously registered by cm_register().
208 */
209int cm_unregister(struct cm_ll_data *cld)
210{
211 if (!cld || cm_ll_data != cld)
212 return -EINVAL;
213
214 cm_ll_data = &null_cm_ll_data;
215
216 return 0;
217}
Tero Kristofe874142014-03-12 18:33:45 +0200218
219static struct omap_prcm_init_data cm_data = {
220 .index = TI_CLKM_CM,
221};
222
223static struct omap_prcm_init_data cm2_data = {
224 .index = TI_CLKM_CM2,
225};
226
227static const struct of_device_id omap_cm_dt_match_table[] = {
228 { .compatible = "ti,omap3-cm", .data = &cm_data },
229 { .compatible = "ti,omap4-cm1", .data = &cm_data },
230 { .compatible = "ti,omap4-cm2", .data = &cm2_data },
231 { .compatible = "ti,omap5-cm-core-aon", .data = &cm_data },
232 { .compatible = "ti,omap5-cm-core", .data = &cm2_data },
233 { .compatible = "ti,dra7-cm-core-aon", .data = &cm_data },
234 { .compatible = "ti,dra7-cm-core", .data = &cm2_data },
235 { }
236};
237
238/**
239 * omap_cm_init - low level init for the CM drivers
240 *
241 * Initializes the low level clock infrastructure for CM drivers.
242 * Returns 0 in success, negative error value in failure.
243 */
244int __init omap_cm_init(void)
245{
246 struct device_node *np;
247 void __iomem *mem;
248 const struct of_device_id *match;
249 const struct omap_prcm_init_data *data;
250 int ret;
251
252 for_each_matching_node_and_match(np, omap_cm_dt_match_table, &match) {
253 data = match->data;
254
255 mem = of_iomap(np, 0);
256 if (!mem)
257 return -ENOMEM;
258
259 ret = omap2_clk_provider_init(np, data->index, mem);
260 if (ret)
261 return ret;
262 }
263
264 return 0;
265}