blob: d3ebb74873f8b14e95fab68ea6176b3a7cc5f51a [file] [log] [blame]
Paul Walmsley543d9372008-03-18 10:22:06 +02001/*
2 * linux/arch/arm/mach-omap2/clock.c
3 *
Tony Lindgrena16e9702008-03-18 11:56:39 +02004 * Copyright (C) 2005-2008 Texas Instruments, Inc.
5 * Copyright (C) 2004-2008 Nokia Corporation
6 *
7 * Contacts:
Paul Walmsley543d9372008-03-18 10:22:06 +02008 * Richard Woodruff <r-woodruff2@ti.com>
Paul Walmsley543d9372008-03-18 10:22:06 +02009 * Paul Walmsley
10 *
Paul Walmsley543d9372008-03-18 10:22:06 +020011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15#undef DEBUG
16
17#include <linux/module.h>
18#include <linux/kernel.h>
19#include <linux/device.h>
20#include <linux/list.h>
21#include <linux/errno.h>
22#include <linux/delay.h>
23#include <linux/clk.h>
Russell Kingfced80c2008-09-06 12:10:45 +010024#include <linux/io.h>
Russell Kingfbd3bdb2008-09-06 12:13:59 +010025#include <linux/bitops.h>
Paul Walmsley543d9372008-03-18 10:22:06 +020026
Tony Lindgrence491cf2009-10-20 09:40:47 -070027#include <plat/clock.h>
28#include <plat/clockdomain.h>
29#include <plat/cpu.h>
30#include <plat/prcm.h>
Paul Walmsley543d9372008-03-18 10:22:06 +020031
Paul Walmsley543d9372008-03-18 10:22:06 +020032#include "clock.h"
33#include "prm.h"
34#include "prm-regbits-24xx.h"
35#include "cm.h"
36#include "cm-regbits-24xx.h"
37#include "cm-regbits-34xx.h"
38
Paul Walmsley543d9372008-03-18 10:22:06 +020039u8 cpu_mask;
40
41/*-------------------------------------------------------------------------
Rajendra Nayak911bd732009-12-08 18:47:17 -070042 * OMAP2/3/4 specific clock functions
Paul Walmsley543d9372008-03-18 10:22:06 +020043 *-------------------------------------------------------------------------*/
44
45/**
Paul Walmsleydf791b32010-01-26 20:13:04 -070046 * omap2xxx_clk_commit - commit clock parent/rate changes in hardware
Paul Walmsley439764c2009-01-28 12:35:03 -070047 * @clk: struct clk *
48 *
49 * If @clk has the DELAYED_APP flag set, meaning that parent/rate changes
50 * don't take effect until the VALID_CONFIG bit is written, write the
51 * VALID_CONFIG bit and wait for the write to complete. No return value.
52 */
Paul Walmsleydf791b32010-01-26 20:13:04 -070053void omap2xxx_clk_commit(struct clk *clk)
Paul Walmsley439764c2009-01-28 12:35:03 -070054{
55 if (!cpu_is_omap24xx())
56 return;
57
58 if (!(clk->flags & DELAYED_APP))
59 return;
60
61 prm_write_mod_reg(OMAP24XX_VALID_CONFIG, OMAP24XX_GR_MOD,
Tony Lindgren8e3bd352009-05-25 11:26:42 -070062 OMAP2_PRCM_CLKCFG_CTRL_OFFSET);
Paul Walmsley439764c2009-01-28 12:35:03 -070063 /* OCP barrier */
Tony Lindgren8e3bd352009-05-25 11:26:42 -070064 prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET);
Paul Walmsley439764c2009-01-28 12:35:03 -070065}
66
Paul Walmsley543d9372008-03-18 10:22:06 +020067/**
Paul Walmsley333943b2008-08-19 11:08:45 +030068 * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
69 * @clk: OMAP clock struct ptr to use
70 *
71 * Convert a clockdomain name stored in a struct clk 'clk' into a
72 * clockdomain pointer, and save it into the struct clk. Intended to be
73 * called during clk_register(). No return value.
74 */
75void omap2_init_clk_clkdm(struct clk *clk)
76{
77 struct clockdomain *clkdm;
78
79 if (!clk->clkdm_name)
80 return;
81
82 clkdm = clkdm_lookup(clk->clkdm_name);
83 if (clkdm) {
84 pr_debug("clock: associated clk %s to clkdm %s\n",
85 clk->name, clk->clkdm_name);
86 clk->clkdm = clkdm;
87 } else {
88 pr_debug("clock: could not associate clk %s to "
89 "clkdm %s\n", clk->name, clk->clkdm_name);
90 }
91}
92
93/**
Paul Walmsley72350b22009-07-24 19:44:03 -060094 * omap2_clk_dflt_find_companion - find companion clock to @clk
95 * @clk: struct clk * to find the companion clock of
96 * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in
97 * @other_bit: u8 ** to return the companion clock bit shift in
Paul Walmsley543d9372008-03-18 10:22:06 +020098 *
Paul Walmsley72350b22009-07-24 19:44:03 -060099 * Note: We don't need special code here for INVERT_ENABLE for the
100 * time being since INVERT_ENABLE only applies to clocks enabled by
Paul Walmsley543d9372008-03-18 10:22:06 +0200101 * CM_CLKEN_PLL
Paul Walmsley72350b22009-07-24 19:44:03 -0600102 *
103 * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's
104 * just a matter of XORing the bits.
105 *
106 * Some clocks don't have companion clocks. For example, modules with
107 * only an interface clock (such as MAILBOXES) don't have a companion
108 * clock. Right now, this code relies on the hardware exporting a bit
109 * in the correct companion register that indicates that the
110 * nonexistent 'companion clock' is active. Future patches will
111 * associate this type of code with per-module data structures to
112 * avoid this issue, and remove the casts. No return value.
Paul Walmsley543d9372008-03-18 10:22:06 +0200113 */
Paul Walmsley72350b22009-07-24 19:44:03 -0600114void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg,
115 u8 *other_bit)
Paul Walmsley543d9372008-03-18 10:22:06 +0200116{
Paul Walmsley72350b22009-07-24 19:44:03 -0600117 u32 r;
Paul Walmsley543d9372008-03-18 10:22:06 +0200118
Russell Kingc1168dc2008-11-04 21:24:00 +0000119 /*
120 * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes
121 * it's just a matter of XORing the bits.
122 */
Paul Walmsley72350b22009-07-24 19:44:03 -0600123 r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN));
Paul Walmsley543d9372008-03-18 10:22:06 +0200124
Paul Walmsley72350b22009-07-24 19:44:03 -0600125 *other_reg = (__force void __iomem *)r;
126 *other_bit = clk->enable_bit;
Paul Walmsley543d9372008-03-18 10:22:06 +0200127}
128
Paul Walmsley72350b22009-07-24 19:44:03 -0600129/**
130 * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk
131 * @clk: struct clk * to find IDLEST info for
132 * @idlest_reg: void __iomem ** to return the CM_IDLEST va in
133 * @idlest_bit: u8 ** to return the CM_IDLEST bit shift in
134 *
135 * Return the CM_IDLEST register address and bit shift corresponding
136 * to the module that "owns" this clock. This default code assumes
137 * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that
138 * the IDLEST register address ID corresponds to the CM_*CLKEN
139 * register address ID (e.g., that CM_FCLKEN2 corresponds to
140 * CM_IDLEST2). This is not true for all modules. No return value.
141 */
142void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg,
143 u8 *idlest_bit)
144{
145 u32 r;
146
147 r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
148 *idlest_reg = (__force void __iomem *)r;
149 *idlest_bit = clk->enable_bit;
150}
151
152/**
153 * omap2_module_wait_ready - wait for an OMAP module to leave IDLE
154 * @clk: struct clk * belonging to the module
155 *
156 * If the necessary clocks for the OMAP hardware IP block that
157 * corresponds to clock @clk are enabled, then wait for the module to
158 * indicate readiness (i.e., to leave IDLE). This code does not
159 * belong in the clock code and will be moved in the medium term to
160 * module-dependent code. No return value.
161 */
162static void omap2_module_wait_ready(struct clk *clk)
163{
164 void __iomem *companion_reg, *idlest_reg;
165 u8 other_bit, idlest_bit;
166
167 /* Not all modules have multiple clocks that their IDLEST depends on */
168 if (clk->ops->find_companion) {
169 clk->ops->find_companion(clk, &companion_reg, &other_bit);
170 if (!(__raw_readl(companion_reg) & (1 << other_bit)))
171 return;
172 }
173
174 clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit);
175
176 omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), clk->name);
177}
178
179int omap2_dflt_clk_enable(struct clk *clk)
Paul Walmsley543d9372008-03-18 10:22:06 +0200180{
Paul Walmsleyee1eec32009-01-28 12:18:19 -0700181 u32 v;
Paul Walmsley543d9372008-03-18 10:22:06 +0200182
Russell Kingc0fc18c2008-09-05 15:10:27 +0100183 if (unlikely(clk->enable_reg == NULL)) {
Paul Walmsley72350b22009-07-24 19:44:03 -0600184 pr_err("clock.c: Enable for %s without enable code\n",
Paul Walmsley543d9372008-03-18 10:22:06 +0200185 clk->name);
186 return 0; /* REVISIT: -EINVAL */
187 }
188
Paul Walmsleyee1eec32009-01-28 12:18:19 -0700189 v = __raw_readl(clk->enable_reg);
Paul Walmsley543d9372008-03-18 10:22:06 +0200190 if (clk->flags & INVERT_ENABLE)
Paul Walmsleyee1eec32009-01-28 12:18:19 -0700191 v &= ~(1 << clk->enable_bit);
Paul Walmsley543d9372008-03-18 10:22:06 +0200192 else
Paul Walmsleyee1eec32009-01-28 12:18:19 -0700193 v |= (1 << clk->enable_bit);
194 __raw_writel(v, clk->enable_reg);
Paul Walmsleyf11fda62009-01-28 12:35:06 -0700195 v = __raw_readl(clk->enable_reg); /* OCP barrier */
Paul Walmsley543d9372008-03-18 10:22:06 +0200196
Paul Walmsley72350b22009-07-24 19:44:03 -0600197 if (clk->ops->find_idlest)
198 omap2_module_wait_ready(clk);
199
Paul Walmsley543d9372008-03-18 10:22:06 +0200200 return 0;
201}
202
Paul Walmsley72350b22009-07-24 19:44:03 -0600203void omap2_dflt_clk_disable(struct clk *clk)
Paul Walmsley543d9372008-03-18 10:22:06 +0200204{
Paul Walmsleyee1eec32009-01-28 12:18:19 -0700205 u32 v;
Paul Walmsley543d9372008-03-18 10:22:06 +0200206
Paul Walmsleyfecb4942009-01-27 19:12:50 -0700207 if (!clk->enable_reg) {
Paul Walmsley543d9372008-03-18 10:22:06 +0200208 /*
209 * 'Independent' here refers to a clock which is not
210 * controlled by its parent.
211 */
212 printk(KERN_ERR "clock: clk_disable called on independent "
213 "clock %s which has no enable_reg\n", clk->name);
214 return;
215 }
216
Paul Walmsleyee1eec32009-01-28 12:18:19 -0700217 v = __raw_readl(clk->enable_reg);
Paul Walmsley543d9372008-03-18 10:22:06 +0200218 if (clk->flags & INVERT_ENABLE)
Paul Walmsleyee1eec32009-01-28 12:18:19 -0700219 v |= (1 << clk->enable_bit);
Paul Walmsley543d9372008-03-18 10:22:06 +0200220 else
Paul Walmsleyee1eec32009-01-28 12:18:19 -0700221 v &= ~(1 << clk->enable_bit);
222 __raw_writel(v, clk->enable_reg);
Paul Walmsleyde07fed2009-01-28 12:35:01 -0700223 /* No OCP barrier needed here since it is a disable operation */
Paul Walmsley543d9372008-03-18 10:22:06 +0200224}
225
Russell Kingb36ee722008-11-04 17:59:52 +0000226const struct clkops clkops_omap2_dflt_wait = {
Paul Walmsley72350b22009-07-24 19:44:03 -0600227 .enable = omap2_dflt_clk_enable,
Russell Kingb36ee722008-11-04 17:59:52 +0000228 .disable = omap2_dflt_clk_disable,
Paul Walmsley72350b22009-07-24 19:44:03 -0600229 .find_companion = omap2_clk_dflt_find_companion,
230 .find_idlest = omap2_clk_dflt_find_idlest,
Russell Kingb36ee722008-11-04 17:59:52 +0000231};
232
Russell Kingbc51da42008-11-04 18:59:32 +0000233const struct clkops clkops_omap2_dflt = {
234 .enable = omap2_dflt_clk_enable,
235 .disable = omap2_dflt_clk_disable,
236};
237
Russell Kingb36ee722008-11-04 17:59:52 +0000238/* Enables clock without considering parent dependencies or use count
239 * REVISIT: Maybe change this to use clk->enable like on omap1?
240 */
241static int _omap2_clk_enable(struct clk *clk)
242{
243 return clk->ops->enable(clk);
244}
245
246/* Disables clock without considering parent dependencies or use count */
247static void _omap2_clk_disable(struct clk *clk)
248{
249 clk->ops->disable(clk);
Paul Walmsley543d9372008-03-18 10:22:06 +0200250}
251
252void omap2_clk_disable(struct clk *clk)
253{
254 if (clk->usecount > 0 && !(--clk->usecount)) {
255 _omap2_clk_disable(clk);
Paul Walmsleyfecb4942009-01-27 19:12:50 -0700256 if (clk->parent)
Paul Walmsley543d9372008-03-18 10:22:06 +0200257 omap2_clk_disable(clk->parent);
Paul Walmsley333943b2008-08-19 11:08:45 +0300258 if (clk->clkdm)
259 omap2_clkdm_clk_disable(clk->clkdm, clk);
260
Paul Walmsley543d9372008-03-18 10:22:06 +0200261 }
262}
263
264int omap2_clk_enable(struct clk *clk)
265{
266 int ret = 0;
267
268 if (clk->usecount++ == 0) {
Paul Walmsley333943b2008-08-19 11:08:45 +0300269 if (clk->clkdm)
270 omap2_clkdm_clk_enable(clk->clkdm, clk);
271
Russell Kinga7f8c592009-01-31 11:00:17 +0000272 if (clk->parent) {
Paul Walmsley543d9372008-03-18 10:22:06 +0200273 ret = omap2_clk_enable(clk->parent);
Russell Kinga7f8c592009-01-31 11:00:17 +0000274 if (ret)
275 goto err;
Paul Walmsley543d9372008-03-18 10:22:06 +0200276 }
277
Paul Walmsley543d9372008-03-18 10:22:06 +0200278 ret = _omap2_clk_enable(clk);
Russell Kinga7f8c592009-01-31 11:00:17 +0000279 if (ret) {
Russell Kinga7f8c592009-01-31 11:00:17 +0000280 if (clk->parent)
Paul Walmsley333943b2008-08-19 11:08:45 +0300281 omap2_clk_disable(clk->parent);
Russell Kinga7f8c592009-01-31 11:00:17 +0000282
283 goto err;
Paul Walmsley543d9372008-03-18 10:22:06 +0200284 }
285 }
Russell Kinga7f8c592009-01-31 11:00:17 +0000286 return ret;
Paul Walmsley543d9372008-03-18 10:22:06 +0200287
Russell Kinga7f8c592009-01-31 11:00:17 +0000288err:
Russell King8263e5b2009-01-31 11:02:37 +0000289 if (clk->clkdm)
290 omap2_clkdm_clk_disable(clk->clkdm, clk);
Russell Kinga7f8c592009-01-31 11:00:17 +0000291 clk->usecount--;
Paul Walmsley543d9372008-03-18 10:22:06 +0200292 return ret;
293}
294
Paul Walmsley543d9372008-03-18 10:22:06 +0200295/* Set the clock rate for a clock source */
296int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
297{
298 int ret = -EINVAL;
299
300 pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate);
301
302 /* CONFIG_PARTICIPANT clocks are changed only in sets via the
303 rate table mechanism, driven by mpu_speed */
304 if (clk->flags & CONFIG_PARTICIPANT)
305 return -EINVAL;
306
307 /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */
Paul Walmsleyfecb4942009-01-27 19:12:50 -0700308 if (clk->set_rate)
Paul Walmsley543d9372008-03-18 10:22:06 +0200309 ret = clk->set_rate(clk, rate);
310
Paul Walmsley543d9372008-03-18 10:22:06 +0200311 return ret;
312}
313
Paul Walmsley543d9372008-03-18 10:22:06 +0200314int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
315{
Paul Walmsleyfecb4942009-01-27 19:12:50 -0700316 if (clk->flags & CONFIG_PARTICIPANT)
Paul Walmsley543d9372008-03-18 10:22:06 +0200317 return -EINVAL;
318
319 if (!clk->clksel)
320 return -EINVAL;
321
Paul Walmsleydf791b32010-01-26 20:13:04 -0700322 return omap2_clksel_set_parent(clk, new_parent);
Paul Walmsley543d9372008-03-18 10:22:06 +0200323}
324
Paul Walmsley543d9372008-03-18 10:22:06 +0200325/*-------------------------------------------------------------------------
326 * Omap2 clock reset and init functions
327 *-------------------------------------------------------------------------*/
328
329#ifdef CONFIG_OMAP_RESET_CLOCKS
330void omap2_clk_disable_unused(struct clk *clk)
331{
332 u32 regval32, v;
333
334 v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0;
335
336 regval32 = __raw_readl(clk->enable_reg);
337 if ((regval32 & (1 << clk->enable_bit)) == v)
338 return;
339
Artem Bityutskiy0db4e822009-05-12 17:34:40 -0600340 printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name);
Tero Kristo8463e202009-01-28 12:27:45 -0700341 if (cpu_is_omap34xx()) {
342 omap2_clk_enable(clk);
343 omap2_clk_disable(clk);
344 } else
345 _omap2_clk_disable(clk);
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300346 if (clk->clkdm != NULL)
347 pwrdm_clkdm_state_switch(clk->clkdm);
Paul Walmsley543d9372008-03-18 10:22:06 +0200348}
349#endif