aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2012-10-29 22:56:29 -0400
committerPaul Walmsley <paul@pwsan.com>2012-11-08 14:33:08 -0500
commitc4ceedcb18cf7a06059482a3a1828b9aad9f78cf (patch)
treee9b5e9bb75aa84ea70159fa68e103a69518a1eee
parentb6ffa05091978c68e94d2802200f2aaa06a598d9 (diff)
ARM: OMAP2+: CM/clock: convert _omap2_module_wait_ready() to use SoC-independent CM functions
Convert the OMAP clock code's _omap2_module_wait_ready() to use SoC-independent CM functions that are provided by the CM code, rather than using a deprecated function from mach-omap2/prcm.c. This facilitates the future conversion of the CM code to a driver, and also removes a mach-omap2/prcm.c user. mach-omap2/prcm.c will be removed by a subsequent patch. Some modules have IDLEST registers that aren't in the CM module, such as the AM3517 IDLEST bits. So we also need a fallback function for these non-CM odd cases. Create a temporary one in mach-omap2/clock.c, intended to exist until the SCM drivers are ready. Signed-off-by: Paul Walmsley <paul@pwsan.com> Tested-by: Vaibhav Hiremath <hvaibhav@ti.com>
-rw-r--r--arch/arm/mach-omap2/clock.c56
-rw-r--r--arch/arm/mach-omap2/cm.h12
-rw-r--r--arch/arm/mach-omap2/cm2xxx.c65
-rw-r--r--arch/arm/mach-omap2/cm2xxx.h4
-rw-r--r--arch/arm/mach-omap2/cm3xxx.c66
-rw-r--r--arch/arm/mach-omap2/cm3xxx.h5
-rw-r--r--arch/arm/mach-omap2/cm_common.c48
-rw-r--r--arch/arm/mach-omap2/io.c5
8 files changed, 257 insertions, 4 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 9205ea7d8dde..2fe57d65d0f1 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -33,10 +33,18 @@
33#include "soc.h" 33#include "soc.h"
34#include "clockdomain.h" 34#include "clockdomain.h"
35#include "clock.h" 35#include "clock.h"
36#include "cm.h"
36#include "cm2xxx.h" 37#include "cm2xxx.h"
37#include "cm3xxx.h" 38#include "cm3xxx.h"
38#include "cm-regbits-24xx.h" 39#include "cm-regbits-24xx.h"
39#include "cm-regbits-34xx.h" 40#include "cm-regbits-34xx.h"
41#include "common.h"
42
43/*
44 * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait
45 * for a module to indicate that it is no longer in idle
46 */
47#define MAX_MODULE_ENABLE_WAIT 100000
40 48
41u16 cpu_mask; 49u16 cpu_mask;
42 50
@@ -58,6 +66,40 @@ static DEFINE_SPINLOCK(clockfw_lock);
58 66
59/* Private functions */ 67/* Private functions */
60 68
69
70/**
71 * _wait_idlest_generic - wait for a module to leave the idle state
72 * @reg: virtual address of module IDLEST register
73 * @mask: value to mask against to determine if the module is active
74 * @idlest: idle state indicator (0 or 1) for the clock
75 * @name: name of the clock (for printk)
76 *
77 * Wait for a module to leave idle, where its idle-status register is
78 * not inside the CM module. Returns 1 if the module left idle
79 * promptly, or 0 if the module did not leave idle before the timeout
80 * elapsed. XXX Deprecated - should be moved into drivers for the
81 * individual IP block that the IDLEST register exists in.
82 */
83static int _wait_idlest_generic(void __iomem *reg, u32 mask, u8 idlest,
84 const char *name)
85{
86 int i = 0, ena = 0;
87
88 ena = (idlest) ? 0 : mask;
89
90 omap_test_timeout(((__raw_readl(reg) & mask) == ena),
91 MAX_MODULE_ENABLE_WAIT, i);
92
93 if (i < MAX_MODULE_ENABLE_WAIT)
94 pr_debug("omap clock: module associated with clock %s ready after %d loops\n",
95 name, i);
96 else
97 pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n",
98 name, MAX_MODULE_ENABLE_WAIT);
99
100 return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0;
101};
102
61/** 103/**
62 * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE 104 * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE
63 * @clk: struct clk * belonging to the module 105 * @clk: struct clk * belonging to the module
@@ -71,7 +113,9 @@ static DEFINE_SPINLOCK(clockfw_lock);
71static void _omap2_module_wait_ready(struct clk *clk) 113static void _omap2_module_wait_ready(struct clk *clk)
72{ 114{
73 void __iomem *companion_reg, *idlest_reg; 115 void __iomem *companion_reg, *idlest_reg;
74 u8 other_bit, idlest_bit, idlest_val; 116 u8 other_bit, idlest_bit, idlest_val, idlest_reg_id;
117 s16 prcm_mod;
118 int r;
75 119
76 /* Not all modules have multiple clocks that their IDLEST depends on */ 120 /* Not all modules have multiple clocks that their IDLEST depends on */
77 if (clk->ops->find_companion) { 121 if (clk->ops->find_companion) {
@@ -82,8 +126,14 @@ static void _omap2_module_wait_ready(struct clk *clk)
82 126
83 clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val); 127 clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val);
84 128
85 omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), idlest_val, 129 r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id);
86 __clk_get_name(clk)); 130 if (r) {
131 /* IDLEST register not in the CM module */
132 _wait_idlest_generic(idlest_reg, (1 << idlest_bit), idlest_val,
133 clk->name);
134 } else {
135 cm_wait_module_ready(prcm_mod, idlest_reg_id, idlest_bit);
136 };
87} 137}
88 138
89/* Public functions */ 139/* Public functions */
diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h
index b3cee913dd67..e419ecb7cce4 100644
--- a/arch/arm/mach-omap2/cm.h
+++ b/arch/arm/mach-omap2/cm.h
@@ -37,8 +37,18 @@
37 37
38/** 38/**
39 * struct cm_ll_data - fn ptrs to per-SoC CM function implementations 39 * struct cm_ll_data - fn ptrs to per-SoC CM function implementations
40 * @split_idlest_reg: ptr to the SoC CM-specific split_idlest_reg impl
41 * @wait_module_ready: ptr to the SoC CM-specific wait_module_ready impl
40 */ 42 */
41struct cm_ll_data {}; 43struct cm_ll_data {
44 int (*split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst,
45 u8 *idlest_reg_id);
46 int (*wait_module_ready)(s16 prcm_mod, u8 idlest_id, u8 idlest_shift);
47};
48
49extern int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
50 u8 *idlest_reg_id);
51extern int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift);
42 52
43extern int cm_register(struct cm_ll_data *cld); 53extern int cm_register(struct cm_ll_data *cld);
44extern int cm_unregister(struct cm_ll_data *cld); 54extern int cm_unregister(struct cm_ll_data *cld);
diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c
index e96cd7041b66..db650690e9d0 100644
--- a/arch/arm/mach-omap2/cm2xxx.c
+++ b/arch/arm/mach-omap2/cm2xxx.c
@@ -198,6 +198,43 @@ void omap2xxx_cm_apll96_disable(void)
198 _omap2xxx_apll_disable(OMAP24XX_EN_96M_PLL_SHIFT); 198 _omap2xxx_apll_disable(OMAP24XX_EN_96M_PLL_SHIFT);
199} 199}
200 200
201/**
202 * omap2xxx_cm_split_idlest_reg - split CM_IDLEST reg addr into its components
203 * @idlest_reg: CM_IDLEST* virtual address
204 * @prcm_inst: pointer to an s16 to return the PRCM instance offset
205 * @idlest_reg_id: pointer to a u8 to return the CM_IDLESTx register ID
206 *
207 * XXX This function is only needed until absolute register addresses are
208 * removed from the OMAP struct clk records.
209 */
210int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
211 u8 *idlest_reg_id)
212{
213 unsigned long offs;
214 u8 idlest_offs;
215 int i;
216
217 if (idlest_reg < cm_base || idlest_reg > (cm_base + 0x0fff))
218 return -EINVAL;
219
220 idlest_offs = (unsigned long)idlest_reg & 0xff;
221 for (i = 0; i < ARRAY_SIZE(omap2xxx_cm_idlest_offs); i++) {
222 if (idlest_offs == omap2xxx_cm_idlest_offs[i]) {
223 *idlest_reg_id = i + 1;
224 break;
225 }
226 }
227
228 if (i == ARRAY_SIZE(omap2xxx_cm_idlest_offs))
229 return -EINVAL;
230
231 offs = idlest_reg - cm_base;
232 offs &= 0xff00;
233 *prcm_inst = offs;
234
235 return 0;
236}
237
201/* 238/*
202 * 239 *
203 */ 240 */
@@ -314,3 +351,31 @@ struct clkdm_ops omap2_clkdm_operations = {
314 .clkdm_clk_enable = omap2xxx_clkdm_clk_enable, 351 .clkdm_clk_enable = omap2xxx_clkdm_clk_enable,
315 .clkdm_clk_disable = omap2xxx_clkdm_clk_disable, 352 .clkdm_clk_disable = omap2xxx_clkdm_clk_disable,
316}; 353};
354
355/*
356 *
357 */
358
359static struct cm_ll_data omap2xxx_cm_ll_data = {
360 .split_idlest_reg = &omap2xxx_cm_split_idlest_reg,
361 .wait_module_ready = &omap2xxx_cm_wait_module_ready,
362};
363
364int __init omap2xxx_cm_init(void)
365{
366 if (!cpu_is_omap24xx())
367 return 0;
368
369 return cm_register(&omap2xxx_cm_ll_data);
370}
371
372static void __exit omap2xxx_cm_exit(void)
373{
374 if (!cpu_is_omap24xx())
375 return;
376
377 /* Should never happen */
378 WARN(cm_unregister(&omap2xxx_cm_ll_data),
379 "%s: cm_ll_data function pointer mismatch\n", __func__);
380}
381__exitcall(omap2xxx_cm_exit);
diff --git a/arch/arm/mach-omap2/cm2xxx.h b/arch/arm/mach-omap2/cm2xxx.h
index bce3c4be6d1f..4cbb39b051d2 100644
--- a/arch/arm/mach-omap2/cm2xxx.h
+++ b/arch/arm/mach-omap2/cm2xxx.h
@@ -60,6 +60,10 @@ extern void omap2xxx_cm_set_apll96_auto_low_power_stop(void);
60extern bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask); 60extern bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask);
61extern int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, 61extern int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id,
62 u8 idlest_shift); 62 u8 idlest_shift);
63extern int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
64 s16 *prcm_inst, u8 *idlest_reg_id);
65
66extern int __init omap2xxx_cm_init(void);
63 67
64#endif 68#endif
65 69
diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c
index 8b03ec2f4394..c2086f2e86b6 100644
--- a/arch/arm/mach-omap2/cm3xxx.c
+++ b/arch/arm/mach-omap2/cm3xxx.c
@@ -110,6 +110,44 @@ int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
110 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 110 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
111} 111}
112 112
113/**
114 * omap3xxx_cm_split_idlest_reg - split CM_IDLEST reg addr into its components
115 * @idlest_reg: CM_IDLEST* virtual address
116 * @prcm_inst: pointer to an s16 to return the PRCM instance offset
117 * @idlest_reg_id: pointer to a u8 to return the CM_IDLESTx register ID
118 *
119 * XXX This function is only needed until absolute register addresses are
120 * removed from the OMAP struct clk records.
121 */
122int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
123 u8 *idlest_reg_id)
124{
125 unsigned long offs;
126 u8 idlest_offs;
127 int i;
128
129 if (idlest_reg < (cm_base + OMAP3430_IVA2_MOD) ||
130 idlest_reg > (cm_base + 0x1ffff))
131 return -EINVAL;
132
133 idlest_offs = (unsigned long)idlest_reg & 0xff;
134 for (i = 0; i < ARRAY_SIZE(omap3xxx_cm_idlest_offs); i++) {
135 if (idlest_offs == omap3xxx_cm_idlest_offs[i]) {
136 *idlest_reg_id = i + 1;
137 break;
138 }
139 }
140
141 if (i == ARRAY_SIZE(omap3xxx_cm_idlest_offs))
142 return -EINVAL;
143
144 offs = idlest_reg - cm_base;
145 offs &= 0xff00;
146 *prcm_inst = offs;
147
148 return 0;
149}
150
113/* Clockdomain low-level operations */ 151/* Clockdomain low-level operations */
114 152
115static int omap3xxx_clkdm_add_sleepdep(struct clockdomain *clkdm1, 153static int omap3xxx_clkdm_add_sleepdep(struct clockdomain *clkdm1,
@@ -597,3 +635,31 @@ void omap3_cm_restore_context(void)
597 omap2_cm_write_mod_reg(cm_context.cm_clkout_ctrl, OMAP3430_CCR_MOD, 635 omap2_cm_write_mod_reg(cm_context.cm_clkout_ctrl, OMAP3430_CCR_MOD,
598 OMAP3_CM_CLKOUT_CTRL_OFFSET); 636 OMAP3_CM_CLKOUT_CTRL_OFFSET);
599} 637}
638
639/*
640 *
641 */
642
643static struct cm_ll_data omap3xxx_cm_ll_data = {
644 .split_idlest_reg = &omap3xxx_cm_split_idlest_reg,
645 .wait_module_ready = &omap3xxx_cm_wait_module_ready,
646};
647
648int __init omap3xxx_cm_init(void)
649{
650 if (!cpu_is_omap34xx())
651 return 0;
652
653 return cm_register(&omap3xxx_cm_ll_data);
654}
655
656static void __exit omap3xxx_cm_exit(void)
657{
658 if (!cpu_is_omap34xx())
659 return;
660
661 /* Should never happen */
662 WARN(cm_unregister(&omap3xxx_cm_ll_data),
663 "%s: cm_ll_data function pointer mismatch\n", __func__);
664}
665__exitcall(omap3xxx_cm_exit);
diff --git a/arch/arm/mach-omap2/cm3xxx.h b/arch/arm/mach-omap2/cm3xxx.h
index 4a6ac812edf4..e8e146f4a43f 100644
--- a/arch/arm/mach-omap2/cm3xxx.h
+++ b/arch/arm/mach-omap2/cm3xxx.h
@@ -78,9 +78,14 @@ extern bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask);
78extern int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, 78extern int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id,
79 u8 idlest_shift); 79 u8 idlest_shift);
80 80
81extern int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
82 s16 *prcm_inst, u8 *idlest_reg_id);
83
81extern void omap3_cm_save_context(void); 84extern void omap3_cm_save_context(void);
82extern void omap3_cm_restore_context(void); 85extern void omap3_cm_restore_context(void);
83 86
87extern int __init omap3xxx_cm_init(void);
88
84#endif 89#endif
85 90
86#endif 91#endif
diff --git a/arch/arm/mach-omap2/cm_common.c b/arch/arm/mach-omap2/cm_common.c
index 3246cef151dc..561969bb511e 100644
--- a/arch/arm/mach-omap2/cm_common.c
+++ b/arch/arm/mach-omap2/cm_common.c
@@ -26,6 +26,54 @@ static struct cm_ll_data null_cm_ll_data;
26static struct cm_ll_data *cm_ll_data = &null_cm_ll_data; 26static struct cm_ll_data *cm_ll_data = &null_cm_ll_data;
27 27
28/** 28/**
29 * cm_split_idlest_reg - split CM_IDLEST reg addr into its components
30 * @idlest_reg: CM_IDLEST* virtual address
31 * @prcm_inst: pointer to an s16 to return the PRCM instance offset
32 * @idlest_reg_id: pointer to a u8 to return the CM_IDLESTx register ID
33 *
34 * Given an absolute CM_IDLEST register address @idlest_reg, passes
35 * the PRCM instance offset and IDLEST register ID back to the caller
36 * via the @prcm_inst and @idlest_reg_id. Returns -EINVAL upon error,
37 * or 0 upon success. XXX This function is only needed until absolute
38 * register addresses are removed from the OMAP struct clk records.
39 */
40int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
41 u8 *idlest_reg_id)
42{
43 if (!cm_ll_data->split_idlest_reg) {
44 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
45 __func__);
46 return -EINVAL;
47 }
48
49 return cm_ll_data->split_idlest_reg(idlest_reg, prcm_inst,
50 idlest_reg_id);
51}
52
53/**
54 * cm_wait_module_ready - wait for a module to leave idle or standby
55 * @prcm_mod: PRCM module offset
56 * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3)
57 * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
58 *
59 * Wait for the PRCM to indicate that the module identified by
60 * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon
61 * success, -EBUSY if the module doesn't enable in time, or -EINVAL if
62 * no per-SoC wait_module_ready() function pointer has been registered
63 * or if the idlest register is unknown on the SoC.
64 */
65int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
66{
67 if (!cm_ll_data->wait_module_ready) {
68 WARN_ONCE(1, "cm: %s: no low-level function defined\n",
69 __func__);
70 return -EINVAL;
71 }
72
73 return cm_ll_data->wait_module_ready(prcm_mod, idlest_id, idlest_shift);
74}
75
76/**
29 * cm_register - register per-SoC low-level data with the CM 77 * cm_register - register per-SoC low-level data with the CM
30 * @cld: low-level per-SoC OMAP CM data & function pointers to register 78 * @cld: low-level per-SoC OMAP CM data & function pointers to register
31 * 79 *
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index a204b7055007..772dc7e05c88 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -45,6 +45,8 @@
45#include "sdrc.h" 45#include "sdrc.h"
46#include "control.h" 46#include "control.h"
47#include "serial.h" 47#include "serial.h"
48#include "cm2xxx.h"
49#include "cm3xxx.h"
48 50
49/* 51/*
50 * The machine specific code may provide the extra mapping besides the 52 * The machine specific code may provide the extra mapping besides the
@@ -388,6 +390,7 @@ void __init omap2420_init_early(void)
388 OMAP2_L4_IO_ADDRESS(OMAP2420_CM_BASE), 390 OMAP2_L4_IO_ADDRESS(OMAP2420_CM_BASE),
389 NULL, NULL); 391 NULL, NULL);
390 omap2xxx_check_revision(); 392 omap2xxx_check_revision();
393 omap2xxx_cm_init();
391 omap_common_init_early(); 394 omap_common_init_early();
392 omap2xxx_voltagedomains_init(); 395 omap2xxx_voltagedomains_init();
393 omap242x_powerdomains_init(); 396 omap242x_powerdomains_init();
@@ -417,6 +420,7 @@ void __init omap2430_init_early(void)
417 OMAP2_L4_IO_ADDRESS(OMAP2430_CM_BASE), 420 OMAP2_L4_IO_ADDRESS(OMAP2430_CM_BASE),
418 NULL, NULL); 421 NULL, NULL);
419 omap2xxx_check_revision(); 422 omap2xxx_check_revision();
423 omap2xxx_cm_init();
420 omap_common_init_early(); 424 omap_common_init_early();
421 omap2xxx_voltagedomains_init(); 425 omap2xxx_voltagedomains_init();
422 omap243x_powerdomains_init(); 426 omap243x_powerdomains_init();
@@ -451,6 +455,7 @@ void __init omap3_init_early(void)
451 NULL, NULL); 455 NULL, NULL);
452 omap3xxx_check_revision(); 456 omap3xxx_check_revision();
453 omap3xxx_check_features(); 457 omap3xxx_check_features();
458 omap3xxx_cm_init();
454 omap_common_init_early(); 459 omap_common_init_early();
455 omap3xxx_voltagedomains_init(); 460 omap3xxx_voltagedomains_init();
456 omap3xxx_powerdomains_init(); 461 omap3xxx_powerdomains_init();