diff options
| author | Paul Walmsley <paul@pwsan.com> | 2009-07-24 21:44:03 -0400 |
|---|---|---|
| committer | paul <paul@twilight.(none)> | 2009-07-24 22:10:35 -0400 |
| commit | 72350b29a4c0debfc27c2edbeed9b4ff3f935dd4 (patch) | |
| tree | 0c4637987fdbe97bfbdab7e00031283af47aadc1 | |
| parent | df56556e571234cf26072cd58c01ac3520986b44 (diff) | |
OMAP2/3 clock: split, rename omap2_wait_clock_ready()
Some OMAP2/3 hardware modules have CM_IDLEST attributes that are not
handled by the current omap2_wait_clock_ready() code. In preparation
for patches that fix the unusual devices, rename the function
omap2_wait_clock_ready() to omap2_wait_module_ready() and split it
into three parts:
1. A clkops-specific companion clock return function (by default,
omap2_clk_dflt_find_companion())
2. A clkops-specific CM_IDLEST register address and bit shift return
function (by default, omap2_clk_dflt_find_idlest())
3. Code to wait for the CM to indicate that the module is ready
(omap2_cm_wait_idlest())
Clocks can now specify their own custom find_companion() and find_idlest()
functions; used in subsequent patches.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
| -rw-r--r-- | arch/arm/mach-omap2/clock.c | 156 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/clock.h | 6 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/prcm.c | 43 | ||||
| -rw-r--r-- | arch/arm/plat-omap/include/mach/clock.h | 2 | ||||
| -rw-r--r-- | arch/arm/plat-omap/include/mach/prcm.h | 1 |
5 files changed, 131 insertions, 77 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index b0665f161c03..456e2ad5f621 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <mach/clock.h> | 27 | #include <mach/clock.h> |
| 28 | #include <mach/clockdomain.h> | 28 | #include <mach/clockdomain.h> |
| 29 | #include <mach/cpu.h> | 29 | #include <mach/cpu.h> |
| 30 | #include <mach/prcm.h> | ||
| 30 | #include <asm/div64.h> | 31 | #include <asm/div64.h> |
| 31 | 32 | ||
| 32 | #include <mach/sdrc.h> | 33 | #include <mach/sdrc.h> |
| @@ -38,8 +39,6 @@ | |||
| 38 | #include "cm-regbits-24xx.h" | 39 | #include "cm-regbits-24xx.h" |
| 39 | #include "cm-regbits-34xx.h" | 40 | #include "cm-regbits-34xx.h" |
| 40 | 41 | ||
| 41 | #define MAX_CLOCK_ENABLE_WAIT 100000 | ||
| 42 | |||
| 43 | /* DPLL rate rounding: minimum DPLL multiplier, divider values */ | 42 | /* DPLL rate rounding: minimum DPLL multiplier, divider values */ |
| 44 | #define DPLL_MIN_MULTIPLIER 1 | 43 | #define DPLL_MIN_MULTIPLIER 1 |
| 45 | #define DPLL_MIN_DIVIDER 1 | 44 | #define DPLL_MIN_DIVIDER 1 |
| @@ -274,83 +273,97 @@ unsigned long omap2_fixed_divisor_recalc(struct clk *clk) | |||
| 274 | } | 273 | } |
| 275 | 274 | ||
| 276 | /** | 275 | /** |
| 277 | * omap2_wait_clock_ready - wait for clock to enable | 276 | * omap2_clk_dflt_find_companion - find companion clock to @clk |
| 278 | * @reg: physical address of clock IDLEST register | 277 | * @clk: struct clk * to find the companion clock of |
| 279 | * @mask: value to mask against to determine if the clock is active | 278 | * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in |
| 280 | * @name: name of the clock (for printk) | 279 | * @other_bit: u8 ** to return the companion clock bit shift in |
| 280 | * | ||
| 281 | * Note: We don't need special code here for INVERT_ENABLE for the | ||
| 282 | * time being since INVERT_ENABLE only applies to clocks enabled by | ||
| 283 | * CM_CLKEN_PLL | ||
| 281 | * | 284 | * |
| 282 | * Returns 1 if the clock enabled in time, or 0 if it failed to enable | 285 | * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's |
| 283 | * in roughly MAX_CLOCK_ENABLE_WAIT microseconds. | 286 | * just a matter of XORing the bits. |
| 287 | * | ||
| 288 | * Some clocks don't have companion clocks. For example, modules with | ||
| 289 | * only an interface clock (such as MAILBOXES) don't have a companion | ||
| 290 | * clock. Right now, this code relies on the hardware exporting a bit | ||
| 291 | * in the correct companion register that indicates that the | ||
| 292 | * nonexistent 'companion clock' is active. Future patches will | ||
| 293 | * associate this type of code with per-module data structures to | ||
| 294 | * avoid this issue, and remove the casts. No return value. | ||
| 284 | */ | 295 | */ |
| 285 | int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name) | 296 | void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, |
| 297 | u8 *other_bit) | ||
| 286 | { | 298 | { |
| 287 | int i = 0; | 299 | u32 r; |
| 288 | int ena = 0; | ||
| 289 | 300 | ||
| 290 | /* | 301 | /* |
| 291 | * 24xx uses 0 to indicate not ready, and 1 to indicate ready. | 302 | * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes |
| 292 | * 34xx reverses this, just to keep us on our toes | 303 | * it's just a matter of XORing the bits. |
| 293 | */ | 304 | */ |
| 294 | if (cpu_mask & (RATE_IN_242X | RATE_IN_243X)) | 305 | r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN)); |
| 295 | ena = mask; | ||
| 296 | else if (cpu_mask & RATE_IN_343X) | ||
| 297 | ena = 0; | ||
| 298 | |||
| 299 | /* Wait for lock */ | ||
| 300 | while (((__raw_readl(reg) & mask) != ena) && | ||
| 301 | (i++ < MAX_CLOCK_ENABLE_WAIT)) { | ||
| 302 | udelay(1); | ||
| 303 | } | ||
| 304 | |||
| 305 | if (i <= MAX_CLOCK_ENABLE_WAIT) | ||
| 306 | pr_debug("Clock %s stable after %d loops\n", name, i); | ||
| 307 | else | ||
| 308 | printk(KERN_ERR "Clock %s didn't enable in %d tries\n", | ||
| 309 | name, MAX_CLOCK_ENABLE_WAIT); | ||
| 310 | |||
| 311 | |||
| 312 | return (i < MAX_CLOCK_ENABLE_WAIT) ? 1 : 0; | ||
| 313 | }; | ||
| 314 | 306 | ||
| 307 | *other_reg = (__force void __iomem *)r; | ||
| 308 | *other_bit = clk->enable_bit; | ||
| 309 | } | ||
| 315 | 310 | ||
| 316 | /* | 311 | /** |
| 317 | * Note: We don't need special code here for INVERT_ENABLE | 312 | * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk |
| 318 | * for the time being since INVERT_ENABLE only applies to clocks enabled by | 313 | * @clk: struct clk * to find IDLEST info for |
| 319 | * CM_CLKEN_PLL | 314 | * @idlest_reg: void __iomem ** to return the CM_IDLEST va in |
| 315 | * @idlest_bit: u8 ** to return the CM_IDLEST bit shift in | ||
| 316 | * | ||
| 317 | * Return the CM_IDLEST register address and bit shift corresponding | ||
| 318 | * to the module that "owns" this clock. This default code assumes | ||
| 319 | * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that | ||
| 320 | * the IDLEST register address ID corresponds to the CM_*CLKEN | ||
| 321 | * register address ID (e.g., that CM_FCLKEN2 corresponds to | ||
| 322 | * CM_IDLEST2). This is not true for all modules. No return value. | ||
| 320 | */ | 323 | */ |
| 321 | static void omap2_clk_wait_ready(struct clk *clk) | 324 | void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, |
| 325 | u8 *idlest_bit) | ||
| 322 | { | 326 | { |
| 323 | void __iomem *reg, *other_reg, *st_reg; | 327 | u32 r; |
| 324 | u32 bit; | ||
| 325 | 328 | ||
| 326 | /* | 329 | r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); |
| 327 | * REVISIT: This code is pretty ugly. It would be nice to generalize | 330 | *idlest_reg = (__force void __iomem *)r; |
| 328 | * it and pull it into struct clk itself somehow. | 331 | *idlest_bit = clk->enable_bit; |
| 329 | */ | 332 | } |
| 330 | reg = clk->enable_reg; | ||
| 331 | 333 | ||
| 332 | /* | 334 | /** |
| 333 | * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes | 335 | * omap2_module_wait_ready - wait for an OMAP module to leave IDLE |
| 334 | * it's just a matter of XORing the bits. | 336 | * @clk: struct clk * belonging to the module |
| 335 | */ | 337 | * |
| 336 | other_reg = (void __iomem *)((u32)reg ^ (CM_FCLKEN ^ CM_ICLKEN)); | 338 | * If the necessary clocks for the OMAP hardware IP block that |
| 339 | * corresponds to clock @clk are enabled, then wait for the module to | ||
| 340 | * indicate readiness (i.e., to leave IDLE). This code does not | ||
| 341 | * belong in the clock code and will be moved in the medium term to | ||
| 342 | * module-dependent code. No return value. | ||
| 343 | */ | ||
| 344 | static void omap2_module_wait_ready(struct clk *clk) | ||
| 345 | { | ||
| 346 | void __iomem *companion_reg, *idlest_reg; | ||
| 347 | u8 other_bit, idlest_bit; | ||
| 348 | |||
| 349 | /* Not all modules have multiple clocks that their IDLEST depends on */ | ||
| 350 | if (clk->ops->find_companion) { | ||
| 351 | clk->ops->find_companion(clk, &companion_reg, &other_bit); | ||
| 352 | if (!(__raw_readl(companion_reg) & (1 << other_bit))) | ||
| 353 | return; | ||
| 354 | } | ||
| 337 | 355 | ||
| 338 | /* Check if both functional and interface clocks | 356 | clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit); |
| 339 | * are running. */ | ||
| 340 | bit = 1 << clk->enable_bit; | ||
| 341 | if (!(__raw_readl(other_reg) & bit)) | ||
| 342 | return; | ||
| 343 | st_reg = (void __iomem *)(((u32)other_reg & ~0xf0) | 0x20); /* CM_IDLEST* */ | ||
| 344 | 357 | ||
| 345 | omap2_wait_clock_ready(st_reg, bit, clk->name); | 358 | omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), clk->name); |
| 346 | } | 359 | } |
| 347 | 360 | ||
| 348 | static int omap2_dflt_clk_enable(struct clk *clk) | 361 | int omap2_dflt_clk_enable(struct clk *clk) |
| 349 | { | 362 | { |
| 350 | u32 v; | 363 | u32 v; |
| 351 | 364 | ||
| 352 | if (unlikely(clk->enable_reg == NULL)) { | 365 | if (unlikely(clk->enable_reg == NULL)) { |
| 353 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", | 366 | pr_err("clock.c: Enable for %s without enable code\n", |
| 354 | clk->name); | 367 | clk->name); |
| 355 | return 0; /* REVISIT: -EINVAL */ | 368 | return 0; /* REVISIT: -EINVAL */ |
| 356 | } | 369 | } |
| @@ -363,26 +376,13 @@ static int omap2_dflt_clk_enable(struct clk *clk) | |||
| 363 | __raw_writel(v, clk->enable_reg); | 376 | __raw_writel(v, clk->enable_reg); |
| 364 | v = __raw_readl(clk->enable_reg); /* OCP barrier */ | 377 | v = __raw_readl(clk->enable_reg); /* OCP barrier */ |
| 365 | 378 | ||
| 366 | return 0; | 379 | if (clk->ops->find_idlest) |
| 367 | } | 380 | omap2_module_wait_ready(clk); |
| 368 | 381 | ||
| 369 | static int omap2_dflt_clk_enable_wait(struct clk *clk) | 382 | return 0; |
| 370 | { | ||
| 371 | int ret; | ||
| 372 | |||
| 373 | if (!clk->enable_reg) { | ||
| 374 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", | ||
| 375 | clk->name); | ||
| 376 | return 0; /* REVISIT: -EINVAL */ | ||
| 377 | } | ||
| 378 | |||
| 379 | ret = omap2_dflt_clk_enable(clk); | ||
| 380 | if (ret == 0) | ||
| 381 | omap2_clk_wait_ready(clk); | ||
| 382 | return ret; | ||
| 383 | } | 383 | } |
| 384 | 384 | ||
| 385 | static void omap2_dflt_clk_disable(struct clk *clk) | 385 | void omap2_dflt_clk_disable(struct clk *clk) |
| 386 | { | 386 | { |
| 387 | u32 v; | 387 | u32 v; |
| 388 | 388 | ||
| @@ -406,8 +406,10 @@ static void omap2_dflt_clk_disable(struct clk *clk) | |||
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | const struct clkops clkops_omap2_dflt_wait = { | 408 | const struct clkops clkops_omap2_dflt_wait = { |
| 409 | .enable = omap2_dflt_clk_enable_wait, | 409 | .enable = omap2_dflt_clk_enable, |
| 410 | .disable = omap2_dflt_clk_disable, | 410 | .disable = omap2_dflt_clk_disable, |
| 411 | .find_companion = omap2_clk_dflt_find_companion, | ||
| 412 | .find_idlest = omap2_clk_dflt_find_idlest, | ||
| 411 | }; | 413 | }; |
| 412 | 414 | ||
| 413 | const struct clkops clkops_omap2_dflt = { | 415 | const struct clkops clkops_omap2_dflt = { |
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 2679ddfa6424..9ae7540f8af2 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h | |||
| @@ -65,6 +65,12 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate); | |||
| 65 | u32 omap2_get_dpll_rate(struct clk *clk); | 65 | u32 omap2_get_dpll_rate(struct clk *clk); |
| 66 | int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name); | 66 | int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name); |
| 67 | void omap2_clk_prepare_for_reboot(void); | 67 | void omap2_clk_prepare_for_reboot(void); |
| 68 | int omap2_dflt_clk_enable(struct clk *clk); | ||
| 69 | void omap2_dflt_clk_disable(struct clk *clk); | ||
| 70 | void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, | ||
| 71 | u8 *other_bit); | ||
| 72 | void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, | ||
| 73 | u8 *idlest_bit); | ||
| 68 | 74 | ||
| 69 | extern const struct clkops clkops_omap2_dflt_wait; | 75 | extern const struct clkops clkops_omap2_dflt_wait; |
| 70 | extern const struct clkops clkops_omap2_dflt; | 76 | extern const struct clkops clkops_omap2_dflt; |
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index f945156d5585..ced555a4cd1a 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
| 18 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
| 19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
| 20 | #include <linux/delay.h> | ||
| 20 | 21 | ||
| 21 | #include <mach/common.h> | 22 | #include <mach/common.h> |
| 22 | #include <mach/prcm.h> | 23 | #include <mach/prcm.h> |
| @@ -28,6 +29,8 @@ | |||
| 28 | static void __iomem *prm_base; | 29 | static void __iomem *prm_base; |
| 29 | static void __iomem *cm_base; | 30 | static void __iomem *cm_base; |
| 30 | 31 | ||
| 32 | #define MAX_MODULE_ENABLE_WAIT 100000 | ||
| 33 | |||
| 31 | u32 omap_prcm_get_reset_sources(void) | 34 | u32 omap_prcm_get_reset_sources(void) |
| 32 | { | 35 | { |
| 33 | /* XXX This presumably needs modification for 34XX */ | 36 | /* XXX This presumably needs modification for 34XX */ |
| @@ -120,6 +123,46 @@ u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx) | |||
| 120 | } | 123 | } |
| 121 | EXPORT_SYMBOL(cm_rmw_mod_reg_bits); | 124 | EXPORT_SYMBOL(cm_rmw_mod_reg_bits); |
| 122 | 125 | ||
| 126 | /** | ||
| 127 | * omap2_cm_wait_idlest - wait for IDLEST bit to indicate module readiness | ||
| 128 | * @reg: physical address of module IDLEST register | ||
| 129 | * @mask: value to mask against to determine if the module is active | ||
| 130 | * @name: name of the clock (for printk) | ||
| 131 | * | ||
| 132 | * Returns 1 if the module indicated readiness in time, or 0 if it | ||
| 133 | * failed to enable in roughly MAX_MODULE_ENABLE_WAIT microseconds. | ||
| 134 | */ | ||
| 135 | int omap2_cm_wait_idlest(void __iomem *reg, u32 mask, const char *name) | ||
| 136 | { | ||
| 137 | int i = 0; | ||
| 138 | int ena = 0; | ||
| 139 | |||
| 140 | /* | ||
| 141 | * 24xx uses 0 to indicate not ready, and 1 to indicate ready. | ||
| 142 | * 34xx reverses this, just to keep us on our toes | ||
| 143 | */ | ||
| 144 | if (cpu_is_omap24xx()) | ||
| 145 | ena = mask; | ||
| 146 | else if (cpu_is_omap34xx()) | ||
| 147 | ena = 0; | ||
| 148 | else | ||
| 149 | BUG(); | ||
| 150 | |||
| 151 | /* Wait for lock */ | ||
| 152 | while (((__raw_readl(reg) & mask) != ena) && | ||
| 153 | (i++ < MAX_MODULE_ENABLE_WAIT)) | ||
| 154 | udelay(1); | ||
| 155 | |||
| 156 | if (i < MAX_MODULE_ENABLE_WAIT) | ||
| 157 | pr_debug("cm: Module associated with clock %s ready after %d " | ||
| 158 | "loops\n", name, i); | ||
| 159 | else | ||
| 160 | pr_err("cm: Module associated with clock %s didn't enable in " | ||
| 161 | "%d tries\n", name, MAX_MODULE_ENABLE_WAIT); | ||
| 162 | |||
| 163 | return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0; | ||
| 164 | }; | ||
| 165 | |||
| 123 | void __init omap2_set_globals_prcm(struct omap_globals *omap2_globals) | 166 | void __init omap2_set_globals_prcm(struct omap_globals *omap2_globals) |
| 124 | { | 167 | { |
| 125 | prm_base = omap2_globals->prm; | 168 | prm_base = omap2_globals->prm; |
diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/mach/clock.h index f9f65e1ba3f1..4b8b0d65cbf2 100644 --- a/arch/arm/plat-omap/include/mach/clock.h +++ b/arch/arm/plat-omap/include/mach/clock.h | |||
| @@ -20,6 +20,8 @@ struct clockdomain; | |||
| 20 | struct clkops { | 20 | struct clkops { |
| 21 | int (*enable)(struct clk *); | 21 | int (*enable)(struct clk *); |
| 22 | void (*disable)(struct clk *); | 22 | void (*disable)(struct clk *); |
| 23 | void (*find_idlest)(struct clk *, void __iomem **, u8 *); | ||
| 24 | void (*find_companion)(struct clk *, void __iomem **, u8 *); | ||
| 23 | }; | 25 | }; |
| 24 | 26 | ||
| 25 | #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ | 27 | #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ |
diff --git a/arch/arm/plat-omap/include/mach/prcm.h b/arch/arm/plat-omap/include/mach/prcm.h index 24ac3c715912..cda2a70397b4 100644 --- a/arch/arm/plat-omap/include/mach/prcm.h +++ b/arch/arm/plat-omap/include/mach/prcm.h | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | 25 | ||
| 26 | u32 omap_prcm_get_reset_sources(void); | 26 | u32 omap_prcm_get_reset_sources(void); |
| 27 | void omap_prcm_arch_reset(char mode); | 27 | void omap_prcm_arch_reset(char mode); |
| 28 | int omap2_cm_wait_idlest(void __iomem *reg, u32 mask, const char *name); | ||
| 28 | 29 | ||
| 29 | #endif | 30 | #endif |
| 30 | 31 | ||
