omap2 clock: framework generalization, cleanup
Subsystems (5)
Paul Walmsley
maintainercover omap2 clock: framework generalization, cleanup
Hello,
This set of patches contains some significant changes to the OMAP2 clock framework. The main goal of these patches is to generalize the framework enough to be usable for the OMAP3430 clock tree, although in the process I think the OMAP2 clock code is improved quite a bit - I hope you'll agree.
The major change in this patch set is the rewrite of clksel clock handling, which:
* enables clksel parent clocks to be updated at clock framework init, from whatever the bootloader configured,
* properly encodes platform restrictions for particular rates,
* generalizes the clksel code to be useful for OMAP3430 clocks,
* facilitates future improved clock state reporting,
* and improves readability and maintainability.
The clksel patches are patches 6 through 20. A few other notable changes in this patchset:
* Cleanups/bug fixes: patches 1, 3, 4, 5
* Generalize root clock propagation at clock framework init: patch 2
* Use OMAP clock framework enable/disable fns for osc_ck, APLLs: patches 21, 22, 23
* Recalculate osc_ck and sys_ck via recalculate fns, rather than omap2_get_crystal_rate(): patch 24
* Generalize DPLL multiplier, divider handling: patches 25
* Generalize clocks enabled at init via ENABLE_ON_INIT clock flag: patch 26
* Generalize clock autoidle configuration: patches 27, 28
The patches were boot-tested on N800. Comments and testing are appreciated. In particular, any testing on 2430SDP are particularly welcome, since I don't have one here.
Patches apply cleanly against current git head, and seem to run fine, but I've been doing most of my testing against 2.6.22-omap1, since my N800 touchscreen does not work consistently with git head.
These changes increase uncompressed kernel memory footprint by about 6kB:
text data bss dec hex filename
2877920 147788 85992 3111700 2f7b14 vmlinux.orig 2881092 150908 85992 3117992 2f93a8 vmlinux
diffstat:
arch/arm/mach-omap2/clock.c | 978 +++++++++---------- arch/arm/mach-omap2/clock.h | 1092 +++++++++++++++++----- arch/arm/plat-omap/clock.c | 20 include/asm-arm/arch-omap/clock.h | 57 - linux-omap/arch/arm/mach-omap2/board-n800-audio.c | 13 linux-omap/arch/arm/mach-omap2/clock.c | 6 linux-omap/arch/arm/mach-omap2/clock.h | 2 linux-omap/arch/arm/mach-omap2/cm_regbits_24xx.h | 50 + linux-omap/arch/arm/mach-omap2/pm.c | 63 - linux-omap/arch/arm/plat-omap/clock.c | 17 linux-omap/include/asm-arm/arch-omap/clock.h | 1 11 files changed, 1492 insertions(+), 807 deletions(-)
My apologies in advance for the double 'Index:' lines in some of the patches - must be some quilt bug - it seems harmless and I have not yet had the chance to track it down.
- Paul
Paul Walmsley
maintainerPATCH 1/28 omap2 clock: dsp_ick parent is dsp_fck, not core_ck
dsp_ick's parent clock is dsp_fck, not core_ck. 2420 TRM ES2.1.1 2.2 Rev Q pp. 4-9, 5-28.
--- arch/arm/mach-omap2/clock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Index: linux-omap/arch/arm/mach-omap2/clock.h
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
arch/arm/mach-omap2/clock.h +1 -1
@@ -820,7 +820,7 @@ static struct clk dsp_fck = {static struct clk dsp_ick = { .name ="dsp_ick" ,/* apparently ipi and isp */ - .parent = &dsp_fck, + .parent = &core_ck, .flags =CLOCK_IN_OMAP242X |RATE_CKCTL |CM_DSP_SEL1 |DELAYED_APP |CONFIG_PARTICIPANT , .rate_offset =OMAP24XX_CLKSEL_DSP_IF_SHIFT ,
Paul Walmsley
maintainerPATCH 2/28 omap2 clock: generalize initial clock rate setup: recalculate_root_clocks()
In reply to Paul WalmsleyAdd a new clock framework function, recalculate_root_clocks(), that recalculates all root clocks (i.e., clocks with no parent clock). Call this function in omap2_clk_arch_init(), rather than manually propagating specific clocks. Add propagate_rate() recalcs to func_32k_ck and osc_ck.
--- arch/arm/mach-omap2/clock.c | 6 ++---- arch/arm/mach-omap2/clock.h | 4 +++- arch/arm/plat-omap/clock.c | 17 +++++++++++++++++ include/asm-arm/arch-omap/clock.h | 1 + 4 files changed, 23 insertions(+), 5 deletions(-)
Index: linux-omap/arch/arm/plat-omap/clock.c
Index: linux-omap/arch/arm/plat-omap/clock.c
===================================================================
arch/arm/plat-omap/clock.c +17 -0
@@ -312,6 +312,23 @@ void propagate_rate(struct clk * tclk) } } +/** +* recalculate_root_clocks - recalculate and propagate all root clocks +* +* Recalculates all root clocks (clocks with no parent), which if the +* clock's .recalc is set correctly, should also propagate their rates. +* Called at init. +*/ +void recalculate_root_clocks (void ) +{ +struct clk *clkp; + +list_for_each_entry (clkp, &clocks, node) { +if (unlikely (!clkp->parent) &&likely ((u32 )clkp->recalc)) + clkp->recalc (clkp); + } +} +int clk_register (struct clk *clk) {if (clk ==NULL ||IS_ERR (clk))
include/asm-arm/arch-omap/clock.h +1 -0
@@ -57,6 +57,7 @@ extern int clk_init(struct clk_functionsextern int clk_register (struct clk *clk);extern void clk_unregister (struct clk *clk);extern void propagate_rate (struct clk *clk); +extern void recalculate_root_clocks (void );extern void followparent_recalc (struct clk * clk);extern void clk_allow_idle (struct clk *clk);extern void clk_deny_idle (struct clk *clk);
arch/arm/mach-omap2/clock.c +2 -4
@@ -1179,8 +1179,7 @@ static int __init omap2_clk_arch_init(voif (omap2_select_table_rate (&virt_prcm_set, mpurate))printk (KERN_ERR "Could not find matching MPU rate\n" ); -propagate_rate (&osc_ck);/* update main root fast */ -propagate_rate (&func_32k_ck);/* update main root slow */ +recalculate_root_clocks (); printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL/MPU): " "%ld.%01ld/%ld/%ld MHz\n",
@@ -1231,8 +1230,7 @@ int __init omap2_clk_init(void) } curr_prcm_set = prcm; -propagate_rate (&osc_ck);/* update main root fast */ -propagate_rate (&func_32k_ck);/* update main root slow */ +recalculate_root_clocks (); printk(KERN_INFO "Clocking rate (Crystal/DPLL/MPU): " "%ld.%01ld/%ld/%ld MHz\n",
arch/arm/mach-omap2/clock.h +3 -1
@@ -592,7 +592,8 @@ static struct clk func_32k_ck = { .name = "func_32k_ck", .rate = 32000, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | - RATE_FIXED | ALWAYS_ENABLED, + RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES, + .recalc = &propagate_rate, };/* Typical 12/13MHz in standalone mode, will be 26Mhz in chassis mode */
@@ -601,6 +602,7 @@ static struct clk osc_ck = { /* (*12, * .rate = 26000000, /* fixed up in clock init */ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_FIXED | RATE_PROPAGATES, + .recalc = &propagate_rate, };/* With out modem likely 12MHz, with modem likely 13MHz */
Paul Walmsley
maintainerPATCH 3/28 omap2 clock: mark onchip_clks as __initdata
In reply to Paul WalmsleyThe onchip_clks array is only used during init, so, mark it __initdata.
--- arch/arm/mach-omap2/clock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Index: linux-omap/arch/arm/mach-omap2/clock.h
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
arch/arm/mach-omap2/clock.h +1 -1
@@ -1988,7 +1988,7 @@ static struct clk virt_prcm_set = { .round_rate = &omap2_round_to_table_rate, }; -static struct clk *onchip_clks[] = { +static struct clk *onchip_clks[]__initdata = {/* external root sources */ &func_32k_ck, &osc_ck,
Paul Walmsley
maintainerPATCH 5/28 omap2 clock: rename, add comment to omap2_mpu_recalc()
In reply to Paul Walmsleyomap2_mpu_recalc() actually just looks up what the MPU speed 'should' currently be from the current virt_prcm_set rate set, rather than reporting the actual hardware settings. Clarify this by renaming it to omap2_table_mpu_recalc() and adding some comments.
--- arch/arm/mach-omap2/clock.c | 9 +++++++-- arch/arm/mach-omap2/clock.h | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +7 -2
@@ -592,8 +592,13 @@ dpll_exit:return (ret); } -/* Just return the MPU speed */ -static void omap2_mpu_recalc (struct clk * clk) +/** +* omap2_table_mpu_recalc - just return the MPU speed +* @clk: virt_prcm_set struct clk +* +* Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set. +*/ +static void omap2_table_mpu_recalc (struct clk * clk) { clk->rate = curr_prcm_set->mpu_speed; }
arch/arm/mach-omap2/clock.h +2 -2
@@ -24,7 +24,7 @@static void omap2_sys_clk_recalc (struct clk * clk);static void omap2_clksel_recalc (struct clk * clk); -static void omap2_mpu_recalc (struct clk * clk); +static void omap2_table_mpu_recalc (struct clk *clk);static int omap2_select_table_rate (struct clk * clk,unsigned long rate);static long omap2_round_to_table_rate (struct clk * clk,unsigned long rate);static void omap2_clk_disable (struct clk *clk);
@@ -1982,7 +1982,7 @@ static struct clk virt_prcm_set = { .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | VIRTUAL_CLOCK | ALWAYS_ENABLED | DELAYED_APP, .parent = &mpu_ck, /* Indexed by mpu speed, no parent */ - .recalc = &omap2_mpu_recalc, /* sets are keyed on mpu rate */ + .recalc = &omap2_table_mpu_recalc, /* sets are keyed on mpu rate */ .set_rate = &omap2_select_table_rate, .round_rate = &omap2_round_to_table_rate, };
Paul Walmsley
maintainerPATCH 6/28 omap2 clock: add clksel and clksel_rate data
In reply to Paul WalmsleyMany OMAP2 clocks are either source- or divisor-selectable by twiddling various register bits; these are 'clksel' clocks. The table of rate divisors and source clock settings was previously embedded in the clock.c source code. Encode this data in two data structures:
1) struct clksel_rate for divisor-selection, mapping divisor values to register bit field values, along with a flags field indicating which chips the rate is available for -- one for each parent-rate combination; and:
2) struct clksel for source-selection, mapping parent struct clk pointers to struct clksel_rate array pointers; one for each parent.
Also, add several fields to the clk structure:
1) clksel: pointer to the struct clksel array
2) clksel_reg: pointer to the clksel register
3) clksel_mask: mask for the clksel bitfield
Add this data to each clksel clock. All this data is not yet used by the clock framework; that functionality is in the following patches.
N.B. Two clocks, sys_clkout and sys_clkout2, could not be converted to this setup without splitting source selection and divisor selection. This is because these clocks use separate registers for each selector. So, create two new clocks, sys_clkout_src and sys_clkout2_src, and locate source-selection there, and keep divisor selection in sys_clkout/sys_clkout2. This entailed modifying board-n800-audio.c.
--- arch/arm/mach-omap2/board-n800-audio.c | 13 arch/arm/mach-omap2/clock.h | 536 ++++++++++++++++++++++++++++++++- include/asm-arm/arch-omap/clock.h | 25 + 3 files changed, 557 insertions(+), 17 deletions(-)
Index: linux-omap/include/asm-arm/arch-omap/clock.h
Index: linux-omap/include/asm-arm/arch-omap/clock.h
===================================================================
include/asm-arm/arch-omap/clock.h +25 -0
@@ -14,6 +14,22 @@#define __ARCH_ARM_OMAP_CLOCK_Hstruct module ; +struct clk ; + +#if defined(CONFIG_ARCH_OMAP2 ) + +struct clksel_rate { +u8 div; +u32 val; +u8 flags; +}; + +struct clksel { +struct clk *parent; +const struct clksel_rate *rates; +}; + +#endif struct clk {struct list_head node;
@@ -36,6 +52,9 @@ struct clk {void (*disable)(struct clk *);#if defined(CONFIG_ARCH_OMAP2 )u8 fixed_div; +void __iomem *clksel_reg; +u32 clksel_mask; +const struct clksel *clksel;#endif };
@@ -94,6 +113,12 @@ extern int clk_get_usecount(struct clk *#define CLOCK_IN_OMAP343X (1 << 27)#define PARENT_CONTROLS_CLOCK (1 << 28) +/* Clksel_rate flags */ +#define DEFAULT_RATE (1 << 0) +#define RATE_IN_242X (1 << 1) +#define RATE_IN_243X (1 << 2) +#define RATE_IN_343X (1 << 3) +#define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X)/* CM_CLKSEL2_PLL.CORE_CLK_SRC options (24XX) */
arch/arm/mach-omap2/clock.h +521 -15
879 lines not on this page · raw message
arch/arm/mach-omap2/board-n800-audio.c +11 -2
@@ -35,6 +35,7 @@#define AUDIO_ENABLED static struct clk *sys_clkout2; +static struct clk *sys_clkout2_src;static struct clk *func96m_clk;static struct device *eac_device;static struct device *tsc2301_device;
@@ -186,9 +187,15 @@ static void n800_eac_cleanup(struct devistatic int n800_codec_get_clocks (struct device *dev) { + sys_clkout2_src =clk_get (dev,"sys_clkout2_src" ); +if (IS_ERR (sys_clkout2_src)) { +dev_err (dev,"Could not get sys_clkout2_src clock\n" ); +return -ENODEV ; + } sys_clkout2 =clk_get (dev,"sys_clkout2" );if (IS_ERR (sys_clkout2)) { -dev_err (dev,"Could not get sys_clkout2\n" ); +dev_err (dev,"Could not get sys_clkout2 clock\n" ); +clk_put (sys_clkout2_src);return -ENODEV ; }/* configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
@@ -197,10 +204,11 @@ static int n800_codec_get_clocks(structif (IS_ERR (func96m_clk)) {dev_err (dev,"Could not get func 96M clock\n" );clk_put (sys_clkout2); +clk_put (sys_clkout2_src);return -ENODEV ; } -clk_set_parent (sys_clkout2, func96m_clk); +clk_set_parent (sys_clkout2_src, func96m_clk);clk_set_rate (sys_clkout2,12000000 );return 0 ;
@@ -210,6 +218,7 @@ static void n800_codec_put_clocks(struct {clk_put (func96m_clk);clk_put (sys_clkout2); +clk_put (sys_clkout2_src); }static int n800_codec_enable_clock (struct device *dev)
Paul Walmsley
maintainerPATCH 7/28 omap2 clock: init clksel clock parents to hardware reality at clock init
In reply to Paul WalmsleySource-selectable clksel clocks have a 'default parent' assigned to them at compile-time. This default parent may or may not match the reality that is configured in the hardware registers by the bootloader. Clock tree recalculations could be erratic if the struct clk parent field contents don't match the hardware registers.
Resolve this by creating omap2_init_clksel_parent() to read the hardware registers and update the struct clk parent field as appropriate for clksel clocks. Add an '.init' field to each source-selectable clk structure so that the parent is fixed up when the clock is initially registered. (We don't do this for clksel clocks that are only rate-selectable, since they only have one possible parent clock.)
--- arch/arm/mach-omap2/clock.c | 58 ++++++++++++++++++++++++++++++++++++++++---- arch/arm/mach-omap2/clock.h | 22 ++++++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +53 -5
@@ -93,6 +93,54 @@ static u32 sysclkout_div[] = {1, 2, 4, 8* Omap2 specific clock functions *-------------------------------------------------------------------------*/ +static inline u8 convert_mask_to_shift (u32 mask) { +return ffs (mask) -1 ; +} + +/** +* omap2_init_clksel_parent - set a clksel clk's parent field from the hardware +* @clk: OMAP clock struct ptr to use +* +* Given a pointer to a source-selectable struct clk, read the hardware +* register and determine what its parent is currently set to. Update the +* clk->parent field with the appropriate clk ptr. +*/ +static void omap2_init_clksel_parent (struct clk *clk) +{ +const struct clksel *clks; +const struct clksel_rate *clkr; +u32 r, found =0 ; + +if (!clk->clksel) +return ; + +/* XXX Should be __raw_readl for non-CM 3430 clocks ? */ + r =cm_read_reg (clk->clksel_reg) & clk->clksel_mask; + r >>=convert_mask_to_shift (clk->clksel_mask); + +for (clks = clk->clksel; clks->parent && !found; clks++) { +for (clkr = clks->rates; clkr->div && !found; clkr++) { +if ((clkr->flags & cpu_mask) && (clkr->val == r)) { +if (clk->parent != clks->parent) { +pr_debug ("clock: inited %s parent " +"to %s (was %s)\n" , + clk->name, clks->parent->name, + ((clk->parent->name) ? + clk->parent->name :"NULL" )); + clk->parent = clks->parent; + }; + found =1 ; + } + } + } + +if (!found) +printk (KERN_ERR "clock: init parent: could not find " +"regval %0x for clock %s\n" , r, clk->name); + +return ; +} +/* Recalculate SYST_CLK */ static void omap2_sys_clk_recalc (struct clk * clk) {
@@ -1193,6 +1241,11 @@ int __init omap2_clk_init(void)struct clk ** clkp;u32 clkrate; +if (cpu_is_omap242x ()) + cpu_mask =RATE_IN_242X ; +else if (cpu_is_omap2430 ()) + cpu_mask =RATE_IN_243X ; +clk_init (&omap2_clk_functions);omap2_get_crystal_rate (&osc_ck, &sys_ck);
@@ -1210,11 +1263,6 @@ int __init omap2_clk_init(void) } } -if (cpu_is_omap242x ()) - cpu_mask =RATE_IN_242X ; -else if (cpu_is_omap2430 ()) - cpu_mask =RATE_IN_243X ; -/* Check the MPU rate set by bootloader */ clkrate =omap2_get_dpll_rate (&dpll_ck);for (prcm = rate_table; prcm->mpu_speed; prcm++) {
arch/arm/mach-omap2/clock.h +22 -0
@@ -29,6 +29,7 @@ static int omap2_select_table_rate(strucstatic long omap2_round_to_table_rate (struct clk * clk,unsigned long rate);static void omap2_clk_disable (struct clk *clk);static void omap2_sys_clk_recalc (struct clk * clk); +static void omap2_init_clksel_parent (struct clk *clk);static u32 omap2_clksel_to_divisor (u32 div_sel,u32 field_val);static u32 omap2_clksel_get_divisor (struct clk *clk);static void omap2_dpll_recalc (struct clk *clk);
@@ -690,6 +691,7 @@ static struct clk func_54m_ck = {RATE_FIXED |CM_PLL_SEL1 |RATE_PROPAGATES | PARENT_CONTROLS_CLOCK, .src_offset = OMAP24XX_54M_SOURCE_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_54M_SOURCE, .clksel = func_54m_clksel,
@@ -729,6 +731,7 @@ static struct clk func_96m_ck = { .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |RATE_FIXED |RATE_PROPAGATES | PARENT_CONTROLS_CLOCK, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), .clksel_mask = OMAP2430_96M_SOURCE, .clksel = func_96m_clksel,
@@ -761,6 +764,7 @@ static struct clk func_48m_ck = {RATE_FIXED |CM_PLL_SEL1 |RATE_PROPAGATES | PARENT_CONTROLS_CLOCK, .src_offset = OMAP24XX_48M_SOURCE_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_48M_SOURCE, .clksel = func_48m_clksel,
@@ -830,6 +834,7 @@ static struct clk sys_clkout_src = { .src_offset = OMAP24XX_CLKOUT_SOURCE_SHIFT, .enable_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .enable_bit = OMAP24XX_CLKOUT_EN_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .clksel_mask = OMAP24XX_CLKOUT_SOURCE_MASK, .clksel = common_clkout_src_clksel,
@@ -872,6 +877,7 @@ static struct clk sys_clkout2_src = { RATE_PROPAGATES, .enable_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .enable_bit = OMAP2420_CLKOUT2_EN_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .clksel_mask = OMAP2420_CLKOUT2_SOURCE_MASK, .clksel = common_clkout_src_clksel,
@@ -937,6 +943,7 @@ static struct clk mpu_ck = { /* ControlALWAYS_ENABLED |CM_MPU_SEL1 |DELAYED_APP | CONFIG_PARTICIPANT | RATE_PROPAGATES, .rate_offset = OMAP24XX_CLKSEL_MPU_SHIFT, /* bits 0-4 */ + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL), .clksel_mask = OMAP24XX_CLKSEL_MPU_MASK, .clksel = mpu_clksel,
@@ -1431,6 +1438,7 @@ static struct clk dss1_fck = { .enable_bit = OMAP24XX_EN_DSS1_SHIFT, .rate_offset = OMAP24XX_CLKSEL_DSS1_SHIFT, .src_offset = OMAP24XX_CLKSEL_DSS1_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_CLKSEL_DSS1_MASK, .clksel = dss1_fck_clksel,
@@ -1462,6 +1470,7 @@ static struct clk dss2_fck = { /* Alt c .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_DSS2_SHIFT, .src_offset = OMAP24XX_CLKSEL_DSS2_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_CLKSEL_DSS2_MASK, .clksel = dss2_fck_clksel,
@@ -1522,6 +1531,7 @@ static struct clk gpt1_fck = { .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, OMAP24XX_CM_FCLKEN), /* Bit0 */ .enable_bit = OMAP24XX_EN_GPT1_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT1_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT1_MASK, .clksel = gpt_clksel,
@@ -1545,6 +1555,7 @@ static struct clk gpt2_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT2_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT2_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT2_MASK, .clksel = gpt_clksel,
@@ -1568,6 +1579,7 @@ static struct clk gpt3_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT3_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT3_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT3_MASK, .clksel = gpt_clksel,
@@ -1591,6 +1603,7 @@ static struct clk gpt4_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT4_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT4_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT4_MASK, .clksel = gpt_clksel,
@@ -1614,6 +1627,7 @@ static struct clk gpt5_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT5_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT5_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT5_MASK, .clksel = gpt_clksel,
@@ -1637,6 +1651,7 @@ static struct clk gpt6_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT6_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT6_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT6_MASK, .clksel = gpt_clksel,
@@ -1660,6 +1675,7 @@ static struct clk gpt7_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT7_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT7_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT7_MASK, .clksel = gpt_clksel,
@@ -1683,6 +1699,7 @@ static struct clk gpt8_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT8_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT8_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT8_MASK, .clksel = gpt_clksel,
@@ -1706,6 +1723,7 @@ static struct clk gpt9_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT9_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT9_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT9_MASK, .clksel = gpt_clksel,
@@ -1729,6 +1747,7 @@ static struct clk gpt10_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT10_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT10_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT10_MASK, .clksel = gpt_clksel,
@@ -1752,6 +1771,7 @@ static struct clk gpt11_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT11_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT11_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT11_MASK, .clksel = gpt_clksel,
@@ -1775,6 +1795,7 @@ static struct clk gpt12_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT12_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT12_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT12_MASK, .clksel = gpt_clksel,
@@ -2308,6 +2329,7 @@ static struct clk vlynq_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP2420_EN_VLYNQ_SHIFT, .src_offset = OMAP2420_CLKSEL_VLYNQ_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP2420_CLKSEL_VLYNQ_MASK, .clksel = vlynq_fck_clksel,
RE: [PATCH 07/28] omap2 clock: init clksel clock parents to hardwarereality at clock init
Paul,
This will be a nice addition and was hole. Thanks.
Karthik added this type function for OMAP3 on its first go around. Might be worth looking at that also. I don't think he did it via the .init function.
BTW: Do you know if OMAP1 has this function, I don't think it used to.
In OMAP3 right now there has been a strong push to pull out much of the register accesses into a lower layer. This sets up for higher compatibility in the face of multiple changes which may come in some OMAP3 variants and OMAP4. Trying to extend the access macros to account for widely changing implementations but with similar concepts does not provide enough flexibility.
Regards,
Richard W.
Quoted 1 line
Source-selectable clksel clocks have a 'default parent' assigned to
them
Quoted 4 lines
at compile-time. This default parent may or may not match the reality that is configured in the hardware registers by the bootloader. Clock tree
recalculations could be erratic if the struct clk parent field
contents
Quoted 3 lines
don't match the hardware registers.
Resolve this by creating
omap2_init_clksel_parent()to read the
hardware
Quoted 1 line
registers and update the struct clk parent field as appropriate for
clksel
Quoted 1 line
clocks. Add an '.init' field to each source-selectable clk structure
so
Quoted 1 line
that the parent is fixed up when the clock is initially registered.
(We
Quoted 1 line
don't do this for clksel clocks that are only rate-selectable, since
they
Quoted 16 lines
only have one possible parent clock.)
Signed-off-by Paul Walmsley <[email protected]>--- arch/arm/mach-omap2/clock.c | 58 ++++++++++++++++++++++++++++++++++++++++---- arch/arm/mach-omap2/clock.h | 22 ++++++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-)Index:
linux-omap/arch/arm/mach-omap2/clock.c
Index:linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c static u32 sysclkout_div[] = {1, 2, 4, 8 · line 94
Quoted 2 lines
arch/arm/mach-omap2/clock.c +0
-0@@ -93,6 +93,54 @@ static u32 sysclkout_div[] = {1, 2, 4, 8* Omap2 specific clock functions
*-----------------------------------------------------------------------
arch/arm/mach-omap2/clock.c static u32 sysclkout_div[] = {1, 2, 4, 8
Quoted 8 lines
arch/arm/mach-omap2/clock.c +6
-1--*/ +static inline u8 convert_mask_to_shift (u32 mask) { +return ffs (mask) -1 ; +} + +/** +* omap2_init_clksel_parent - set a clksel clk's parent field from
the
Quoted 4 lines
hardware
+ * @clk: OMAP clock struct ptr to use
+ *
+ * Given a pointer to a source-selectable struct clk, read the
hardware
Quoted 1 line
+ * register and determine what its parent is currently set to.
Update
Quoted 9 lines
the
+ *clk->parentfield with the appropriate clk ptr.
+ */arch/arm/mach-omap2/clock.c +6
-0+static void omap2_init_clksel_parent (struct clk *clk) +{ +const struct clksel *clks; +const struct clksel_rate *clkr; +u32 r, found =0 ; +
arch/arm/mach-omap2/clock.c static u32 sysclkout_div[] = {1, 2, 4, 8
Quoted 10 lines
arch/arm/mach-omap2/clock.c +10
-0+if (!clk->clksel) +return ; + +/* XXX Should be __raw_readl for non-CM 3430 clocks ? */ + r =cm_read_reg (clk->clksel_reg) & clk->clksel_mask; + r >>=convert_mask_to_shift (clk->clksel_mask); + +for (clks = clk->clksel; clks->parent && !found; clks++) { +for (clkr = clks->rates; clkr->div && !found; clkr++) { + if ((clkr->flags & cpu_mask) && (clkr->val ==
r)) {
arch/arm/mach-omap2/clock.c
Quoted 2 lines
arch/arm/mach-omap2/clock.c +2
-0+if (clk->parent != clks->parent) { + pr_debug("clock: inited %s
parent "
arch/arm/mach-omap2/clock.c
Quoted 2 lines
arch/arm/mach-omap2/clock.c +2
-0+"to %s (was %s)\n" , + clk->name,
clks->parent->name,
arch/arm/mach-omap2/clock.c
Quoted 2 lines
arch/arm/mach-omap2/clock.c +2
-0+ ((clk->parent->name) ? + clk->parent->name :
"NULL"));
Quoted 55 lines
arch/arm/mach-omap2/clock.c +19
-5+ clk->parent = clks->parent; + }; + found =1 ; + } + } + } + +if (!found) +printk (KERN_ERR "clock: init parent: could not find " +"regval %0x for clock %s\n" , r, clk->name); + +return ; +} +/* Recalculate SYST_CLK */ static void omap2_sys_clk_recalc (struct clk * clk) {@@ -1193,6 +1241,11 @@ int __init omap2_clk_init(void)struct clk ** clkp;u32 clkrate; +if (cpu_is_omap242x ()) + cpu_mask =RATE_IN_242X ; +else if (cpu_is_omap2430 ()) + cpu_mask =RATE_IN_243X ; +clk_init (&omap2_clk_functions);omap2_get_crystal_rate (&osc_ck, &sys_ck);@@ -1210,11 +1263,6 @@ int __init omap2_clk_init(void) } } -if (cpu_is_omap242x ()) - cpu_mask =RATE_IN_242X ; -else if (cpu_is_omap2430 ()) - cpu_mask =RATE_IN_243X ; -/* Check the MPU rate set by bootloader */ clkrate =omap2_get_dpll_rate (&dpll_ck);for (prcm = rate_table; prcm->mpu_speed; prcm++) {Index:
linux-omap/arch/arm/mach-omap2/clock.h
===================================================================arch/arm/mach-omap2/clock.h +1
-0@@ -29,6 +29,7 @@ static int omap2_select_table_rate(strucstatic long omap2_round_to_table_rate (struct clk * clk,unsigned long rate);static void omap2_clk_disable (struct clk *clk);static void omap2_sys_clk_recalc (struct clk * clk); +static void omap2_init_clksel_parent (struct clk *clk);static u32 omap2_clksel_to_divisor (u32 div_sel,u32 field_val);static u32 omap2_clksel_get_divisor (struct clk *clk);static void
omap2_dpll_recalc(struct clk *clk);
arch/arm/mach-omap2/clock.h static struct clk func_54m_ck = { · line 691
Quoted 1 line
arch/arm/mach-omap2/clock.h +0
-0@@ -690,6 +691,7 @@ static struct clk func_54m_ck = { RATE_FIXED | CM_PLL_SEL1 |
RATE_PROPAGATES |
Quoted 15 lines
arch/arm/mach-omap2/clock.h +2
-0PARENT_CONTROLS_CLOCK, .src_offset = OMAP24XX_54M_SOURCE_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_54M_SOURCE, .clksel = func_54m_clksel,@@ -729,6 +731,7 @@ static struct clk func_96m_ck = { .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |RATE_FIXED |RATE_PROPAGATES | PARENT_CONTROLS_CLOCK, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), .clksel_mask = OMAP2430_96M_SOURCE, .clksel = func_96m_clksel,
arch/arm/mach-omap2/clock.h static struct clk func_48m_ck = { · line 764
Quoted 1 line
arch/arm/mach-omap2/clock.h +0
-0@@ -761,6 +764,7 @@ static struct clk func_48m_ck = { RATE_FIXED | CM_PLL_SEL1 |
RATE_PROPAGATES |
Quoted 23 lines
arch/arm/mach-omap2/clock.h +3
-0PARENT_CONTROLS_CLOCK, .src_offset = OMAP24XX_48M_SOURCE_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_48M_SOURCE, .clksel = func_48m_clksel,@@ -830,6 +834,7 @@ static struct clk sys_clkout_src = { .src_offset = OMAP24XX_CLKOUT_SOURCE_SHIFT, .enable_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .enable_bit = OMAP24XX_CLKOUT_EN_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .clksel_mask = OMAP24XX_CLKOUT_SOURCE_MASK, .clksel = common_clkout_src_clksel,@@ -872,6 +877,7 @@ static struct clk sys_clkout2_src = { RATE_PROPAGATES, .enable_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .enable_bit = OMAP2420_CLKOUT2_EN_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .clksel_mask = OMAP2420_CLKOUT2_SOURCE_MASK, .clksel = common_clkout_src_clksel,
arch/arm/mach-omap2/clock.h static struct clk mpu_ck = { /* Control · line 943
Quoted 1 line
arch/arm/mach-omap2/clock.h +0
-0@@ -937,6 +943,7 @@ static struct clk mpu_ck = { /* Control ALWAYS_ENABLED | CM_MPU_SEL1 |
DELAYED_APP |
Quoted 23 lines
arch/arm/mach-omap2/clock.h +3
-0CONFIG_PARTICIPANT | RATE_PROPAGATES, .rate_offset = OMAP24XX_CLKSEL_MPU_SHIFT, /* bits 0-4 */ + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL), .clksel_mask = OMAP24XX_CLKSEL_MPU_MASK, .clksel = mpu_clksel,@@ -1431,6 +1438,7 @@ static struct clk dss1_fck = { .enable_bit = OMAP24XX_EN_DSS1_SHIFT, .rate_offset = OMAP24XX_CLKSEL_DSS1_SHIFT, .src_offset = OMAP24XX_CLKSEL_DSS1_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_CLKSEL_DSS1_MASK, .clksel = dss1_fck_clksel,@@ -1462,6 +1470,7 @@ static struct clk dss2_fck = { /* Alt c .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_DSS2_SHIFT, .src_offset = OMAP24XX_CLKSEL_DSS2_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_CLKSEL_DSS2_MASK, .clksel = dss2_fck_clksel,
arch/arm/mach-omap2/clock.h static struct clk gpt1_fck = { · line 1531
Quoted 1 line
arch/arm/mach-omap2/clock.h +0
-0@@ -1522,6 +1531,7 @@ static struct clk gpt1_fck = { .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, OMAP24XX_CM_FCLKEN),
/*
Quoted 110 lines
Bit0 */
arch/arm/mach-omap2/clock.h +13
-1.enable_bit = OMAP24XX_EN_GPT1_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT1_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT1_MASK, .clksel = gpt_clksel,@@ -1545,6 +1555,7 @@ static struct clk gpt2_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT2_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT2_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT2_MASK, .clksel = gpt_clksel,@@ -1568,6 +1579,7 @@ static struct clk gpt3_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT3_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT3_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT3_MASK, .clksel = gpt_clksel,@@ -1591,6 +1603,7 @@ static struct clk gpt4_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT4_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT4_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT4_MASK, .clksel = gpt_clksel,@@ -1614,6 +1627,7 @@ static struct clk gpt5_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT5_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT5_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT5_MASK, .clksel = gpt_clksel,@@ -1637,6 +1651,7 @@ static struct clk gpt6_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT6_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT6_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT6_MASK, .clksel = gpt_clksel,@@ -1660,6 +1675,7 @@ static struct clk gpt7_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT7_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT7_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT7_MASK, .clksel = gpt_clksel,@@ -1683,6 +1699,7 @@ static struct clk gpt8_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT8_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT8_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT8_MASK, .clksel = gpt_clksel,@@ -1706,6 +1723,7 @@ static struct clk gpt9_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT9_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT9_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT9_MASK, .clksel = gpt_clksel,@@ -1729,6 +1747,7 @@ static struct clk gpt10_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT10_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT10_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT10_MASK, .clksel = gpt_clksel,@@ -1752,6 +1771,7 @@ static struct clk gpt11_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT11_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT11_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT11_MASK, .clksel = gpt_clksel,@@ -1775,6 +1795,7 @@ static struct clk gpt12_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT12_SHIFT, .src_offset = OMAP24XX_CLKSEL_GPT12_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT12_MASK, .clksel = gpt_clksel,@@ -2308,6 +2329,7 @@ static struct clk vlynq_fck = { .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP2420_EN_VLYNQ_SHIFT, .src_offset = OMAP2420_CLKSEL_VLYNQ_SHIFT, + .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP2420_CLKSEL_VLYNQ_MASK, .clksel = vlynq_fck_clksel, --_______________________________________________
Linux-omap-open-source mailing list
[email protected]
http://linux.omap.com/mailman/listinfo/linux-omap-open-source
Paul Walmsley
maintainerRE: [PATCH 07/28] omap2 clock: init clksel clock parents to hardwarereality at clock init
Quoted 1 line · Richard
BTW: Do you know if OMAP1 has this function, I don't think it used to.
No, just took a quick look, it doesn't seem to.
- Paul
Paul Walmsley
maintainerPATCH 8/28 omap2 clock: convert omap2_clksel_to_divisor and omap2_divisor_to_clksel to use new clksel struct
In reply to Paul WalmsleyConvert omap2_clksel_to_divisor() and omap2_divisor_to_clksel() to use the new struct clksel and struct clksel_rate data. Add omap2_get_clksel_by_parent() utility code, called by both functions, to return the appropriate struct clksel for a given (struct clk, parent struct clk) combination.
--- arch/arm/mach-omap2/clock.c | 132 +++++++++++++++++++++++++++++++++----------- arch/arm/mach-omap2/clock.h | 3 - 2 files changed, 102 insertions(+), 33 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +100 -32
@@ -497,6 +497,38 @@ static inline u32 omap2_divider_from_tabreturn ~0 ;/* No acceptable divider */ } +/** +* omap2_get_clksel_by_parent - return clksel struct for a given clk & parent +* @clk: OMAP struct clk ptr to inspect +* @src_clk: OMAP struct clk ptr of the parent clk to search for +* +* Scan the struct clksel array associated with the clock to find +* the element associated with the supplied parent clock address. +* Returns a pointer to the struct clksel on success or NULL on error. +*/ +const static struct clksel *omap2_get_clksel_by_parent (struct clk *clk, +struct clk *src_clk) +{ +const struct clksel *clks; + +if (!clk->clksel) +return NULL ; + +for (clks = clk->clksel; clks->parent; clks++) { +if (clks->parent == src_clk) +break ;/* Found the requested parent */ + } + +if (!clks->parent) { +printk (KERN_ERR "clock: Could not find parent clock %s in " +"clksel array of clock %s\n" , src_clk->name, + clk->name); +return NULL ; + } + +return clks; +} +/* * Find divisor for the given clock and target rate. *
@@ -683,38 +715,74 @@ static long omap2_round_to_table_rate(streturn highest_rate; } -/* -* omap2_clksel_to_divisor() - turn field value into integer divider +/** +* omap2_clksel_to_divisor() - turn clksel field value into integer divider +* @clk: OMAP struct clk to use +* @field_val: register field value to find +* +* Given a struct clk of a rate-selectable clksel clock, and a register field +* value to search for, find the corresponding clock divisor. The register +* field value should be pre-masked and shifted down so the LSB is at bit 0 +* before calling. Returns 0 on error */ -static u32 omap2_clksel_to_divisor (u32 div_sel,u32 field_val) +static u32 omap2_clksel_to_divisor (struct clk *clk,u32 field_val) { -u32 i; +const struct clksel *clks; +const struct clksel_rate *clkr; -if ((div_sel &SRC_RATE_SEL_MASK ) ==CM_SYSCLKOUT_SEL1 ) { -for (i =0 ; i <ARRAY_SIZE (sysclkout_div); i++) { -if (field_val == i) -return sysclkout_div[i]; - } + clks =omap2_get_clksel_by_parent (clk, clk->parent); +if (clks ==NULL )return 0 ; - }else -return field_val; + +for (clkr = clks->rates; clkr->div; clkr++) { +if ((clkr->flags & cpu_mask) && (clkr->val == field_val)) +break ; + } + +if (!clkr->div) { +printk (KERN_ERR "clock: Could not find fieldval %d for " +"clock %s parent %s\n" , field_val, clk->name, + clk->parent->name); +return 0 ; + } + +return clkr->div; } -/* -* omap2_divisor_to_clksel() - turn integer divider into field value +/** +* omap2_divisor_to_clksel() - turn clksel integer divisor into a field value +* @clk: OMAP struct clk to use +* @div: integer divisor to search for +* +* Given a struct clk of a rate-selectable clksel clock, and a clock divisor, +* find the corresponding register field value. The return register value is +* the value before left-shifting. Returns 0xffffffff on error */ -static u32 omap2_divisor_to_clksel (u32 div_sel,u32 div) +static u32 omap2_divisor_to_clksel (struct clk *clk,u32 div) { -u32 i; +const struct clksel *clks; +const struct clksel_rate *clkr; + +/* should never happen */ +WARN_ON (div ==0 ); -if ((div_sel &SRC_RATE_SEL_MASK ) ==CM_SYSCLKOUT_SEL1 ) { -for (i =0 ; i <ARRAY_SIZE (sysclkout_div); i++) { -if (div == sysclkout_div[i]) -return i; - } -return ~0 ; - }else -return div; + clks =omap2_get_clksel_by_parent (clk, clk->parent); +if (clks ==NULL ) +return 0 ; + +for (clkr = clks->rates; clkr->div; clkr++) { +if ((clkr->flags & cpu_mask) && (clkr->div == div)) +break ; + } + +if (!clkr->div) { +printk (KERN_ERR "clock: Could not find divisor %d for " +"clock %s parent %s\n" , div, clk->name, + clk->parent->name); +return 0 ; + } + +return clkr->val; }/*
@@ -800,13 +868,15 @@ static void __iomem *omap2_get_clksel(u3 } -/* -* Return divider to be applied to parent clock. -* Return 0 on error. +/** +* omap2_clksel_get_divisor - get current divider applied to parent clock. +* @clk: OMAP struct clk to use. +* +* Returns the integer divisor upon success or 0 on error. */ static u32 omap2_clksel_get_divisor (struct clk *clk) { -u32 div, field_mask, field_val; +u32 field_mask, field_val;void __iomem *div_addr; div_addr =omap2_get_clksel (&field_mask, clk);
@@ -814,11 +884,9 @@ static u32 omap2_clksel_get_divisor(strureturn 0 ; field_val =cm_read_reg (div_addr) & field_mask; - field_val >>= clk->rate_offset; - - div =omap2_clksel_to_divisor (clk->flags, field_val); + field_val >>=convert_mask_to_shift (field_mask); -return div; +return omap2_clksel_to_divisor (clk, field_val); }/* Set the clock rate for a clock source */
@@ -844,7 +912,7 @@ static int omap2_clk_set_rate(struct clkif (div_addr ==0 )return ret; - field_val =omap2_divisor_to_clksel (clk->flags, new_div); + field_val =omap2_divisor_to_clksel (clk, new_div);if (field_val == ~0 )return ret;
arch/arm/mach-omap2/clock.h +2 -1
@@ -30,8 +30,9 @@ static long omap2_round_to_table_rate(ststatic void omap2_clk_disable (struct clk *clk);static void omap2_sys_clk_recalc (struct clk * clk);static void omap2_init_clksel_parent (struct clk *clk); -static u32 omap2_clksel_to_divisor (u32 div_sel,u32 field_val);static u32 omap2_clksel_get_divisor (struct clk *clk); +static u32 omap2_clksel_to_divisor (struct clk *clk,u32 field_val); +static u32 omap2_divisor_to_clksel (struct clk *clk,u32 div);static void omap2_dpll_recalc (struct clk *clk);static void omap2_fixed_divisor_recalc (struct clk *clk);
Paul Walmsley
maintainerPATCH 9/28 omap2 clock: convert omap2_clksel_round_rate to use new clksel struct
In reply to Paul WalmsleyConvert omap2_clksel_round_rate() to use the new clksel struct data.
--- arch/arm/mach-omap2/clock.c | 98 ++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 48 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +50 -48
@@ -87,8 +87,6 @@ static struct clk *vclk;static struct clk *sclk;static u8 cpu_mask; -static u32 sysclkout_div[] = {1 ,2 ,4 ,8 ,16 }; -/*------------------------------------------------------------------------- * Omap2 specific clock functions *-------------------------------------------------------------------------*/
@@ -529,62 +527,66 @@ const static struct clksel *omap2_get_clreturn clks; } -/* -* Find divisor for the given clock and target rate. +/** +* omap2_clksel_round_rate - find divisor for the given clock and target rate. +* @clk: OMAP struct clk to use +* @target_rate: desired clock rate +* @new_div: ptr to where we should store the divisor * +* Finds 'best' divider value in an array based on the source and target +* rates. The divider array must be sorted with smallest divider first. * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, * they are only settable as part of virtual_prcm set. +* +* Returns the rounded clock rate or returns 0xffffffff on error. */ -static u32 omap2_clksel_round_rate (struct clk *tclk,u32 target_rate, -u32 *new_div) +static u32 omap2_clksel_round_rate (struct clk *clk,unsigned long target_rate, +u32 *new_div) { -u32 gfx_div[] = {2 ,3 ,4 }; -u32 dss1_div[] = {1 ,2 ,3 ,4 ,5 ,6 ,8 ,9 ,12 ,16 }; -u32 vlynq_div[] = {1 ,2 ,3 ,4 ,6 ,8 ,9 ,12 ,16 ,18 }; -u32 best_div = ~0 , asize =0 ; -u32 *div_array =NULL ; +unsigned long test_rate; +const struct clksel *clks; +const struct clksel_rate *clkr; +u32 last_div =0 ; -switch (tclk->flags &SRC_RATE_SEL_MASK ) { -case CM_GFX_SEL1 : - asize =ARRAY_SIZE (gfx_div); - div_array = gfx_div; -break ; -case CM_PLL_SEL1 : -return omap2_dpll_round_rate (target_rate); -case CM_SYSCLKOUT_SEL1 : - asize =ARRAY_SIZE (sysclkout_div); - div_array = sysclkout_div; -break ; -case CM_CORE_SEL1 : -if (tclk == &dss1_fck) { -if (tclk->parent == &core_ck) { - asize =ARRAY_SIZE (dss1_div); - div_array = dss1_div; - }else { - *new_div =0 ;/* fixed clk */ -return (tclk->parent->rate); - } - }else if ((tclk == &vlynq_fck) &&cpu_is_omap2420 ()) { -if (tclk->parent == &core_ck) { - asize =ARRAY_SIZE (vlynq_div); - div_array = vlynq_div; - }else { - *new_div =0 ;/* fixed clk */ -return (tclk->parent->rate); - } - } -break ; +printk (KERN_INFO "clock: clksel_round_rate for %s target_rate %ld\n" , + clk->name, target_rate); + + *new_div =1 ; + + clks =omap2_get_clksel_by_parent (clk, clk->parent); +if (clks ==NULL ) +return ~0 ; + +for (clkr = clks->rates; clkr->div; clkr++) { +if (!(clkr->flags & cpu_mask)) +continue ; + +/* Sanity check */ +if (clkr->div <= last_div) +printk (KERN_ERR "clock: clksel_rate table not sorted " +"for clock %s" , clk->name); + + last_div = clkr->div; + + test_rate = clk->parent->rate / clkr->div; + +if (test_rate <= target_rate) +break ;/* found it */ } - best_div =omap2_divider_from_table (asize, div_array, - tclk->parent->rate, target_rate); -if (best_div == ~0 ) { - *new_div =1 ; -return best_div;/* signal error */ +if (!clkr->div) { +printk (KERN_ERR "clock: Could not find divisor for target " +"rate %ld for clock %s parent %s\n" , target_rate, + clk->name, clk->parent->name); +return ~0 ; } - *new_div = best_div; -return (tclk->parent->rate / best_div); + *new_div = clkr->div; + +printk (KERN_INFO "clock: new_div = %d, new_rate = %ld\n" , *new_div, + (clk->parent->rate / clkr->div)); + +return (clk->parent->rate / clkr->div); }/* Given a clock and a rate apply a clock specific rounding function */
Paul Walmsley
maintainerPATCH 10/28 omap2 clock: convert omap2_get_clksel to use new clksel struct
In reply to Paul WalmsleyConvert omap2_get_clksel to use new struct clksel and struct clksel_rate data. Also fix its parameter order to conform with the rest of the clock framework functions (i.e., struct clk first).
--- arch/arm/mach-omap2/clock.c | 92 ++++++-------------------------------------- 1 file changed, 13 insertions(+), 79 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +13 -79
@@ -787,89 +787,23 @@ static u32 omap2_divisor_to_clksel(strucreturn clkr->val; } -/* -* Returns the CLKSEL divider register value +/** +* omap2_get_clksel - find clksel register addr & field mask for a clk +* @clk: struct clk to use +* @field_mask: ptr to u32 to store the register field mask +* +* Returns the address of the clksel register upon success or NULL on error. */ -static void __iomem *omap2_get_clksel (u32 *field_mask,struct clk *clk) +static void __iomem *omap2_get_clksel (struct clk *clk,u32 *field_mask) { -u32 div_off, mask = ~0 ; -void __iomem *div_addr =0 ; +if (unlikely ((clk->clksel_reg ==0 ) || (clk->clksel_mask ==0 ))) +return NULL ; - div_off = clk->rate_offset; + *field_mask = clk->clksel_mask; -switch (clk->flags &SRC_RATE_SEL_MASK ) { -case CM_MPU_SEL1 : - div_addr =OMAP_CM_REGADDR (MPU_MOD ,CM_CLKSEL ); - mask =OMAP24XX_CLKSEL_MPU_MASK ; -break ; -case CM_DSP_SEL1 : - div_addr =OMAP_CM_REGADDR (OMAP24XX_DSP_MOD ,CM_CLKSEL ); -if (cpu_is_omap2420 ()) { -if (div_off ==OMAP24XX_CLKSEL_DSP_SHIFT ) - mask =OMAP24XX_CLKSEL_DSP_MASK ; -else if (div_off ==OMAP2420_CLKSEL_IVA_SHIFT ) - mask =OMAP2420_CLKSEL_IVA_MASK ; -else if (div_off ==OMAP24XX_CLKSEL_DSP_IF_SHIFT ) - mask =OMAP24XX_CLKSEL_DSP_IF_MASK ; - }else if (cpu_is_omap2430 ()) { -if (div_off ==OMAP24XX_CLKSEL_DSP_SHIFT ) - mask =OMAP24XX_CLKSEL_DSP_MASK ; -else if (div_off ==OMAP24XX_CLKSEL_DSP_IF_SHIFT ) - mask =OMAP24XX_CLKSEL_DSP_IF_MASK ; - } -case CM_GFX_SEL1 : - div_addr =OMAP_CM_REGADDR (GFX_MOD ,CM_CLKSEL ); -if (div_off ==OMAP_CLKSEL_GFX_SHIFT ) - mask =OMAP_CLKSEL_GFX_MASK ; -break ; -case CM_MODEM_SEL1 : - div_addr =OMAP_CM_REGADDR (OMAP2430_MDM_MOD ,CM_CLKSEL ); -if (div_off ==OMAP2430_CLKSEL_MDM_SHIFT ) - mask =OMAP2430_CLKSEL_MDM_MASK ; -break ; -case CM_SYSCLKOUT_SEL1 : - div_addr =OMAP24XX_PRCM_CLKOUT_CTRL ; -if (div_off ==OMAP24XX_CLKOUT_DIV_SHIFT ) - mask =OMAP24XX_CLKOUT_DIV_MASK ; -else if (div_off ==OMAP2420_CLKOUT2_DIV_SHIFT ) - mask =OMAP2420_CLKOUT2_DIV_MASK ; -break ; -case CM_CORE_SEL1 : - div_addr =OMAP_CM_REGADDR (CORE_MOD ,CM_CLKSEL1 ); -switch (div_off) { -case OMAP24XX_CLKSEL_L3_SHIFT : - mask =OMAP24XX_CLKSEL_L3_MASK ; -break ; -case OMAP24XX_CLKSEL_L4_SHIFT : - mask =OMAP24XX_CLKSEL_L4_MASK ; -break ; -case OMAP24XX_CLKSEL_DSS1_SHIFT : - mask =OMAP24XX_CLKSEL_DSS1_MASK ; -break ; -case OMAP24XX_CLKSEL_DSS2_SHIFT : - mask =OMAP24XX_CLKSEL_DSS2_MASK ; -break ; -case OMAP2420_CLKSEL_VLYNQ_SHIFT : - mask =OMAP2420_CLKSEL_VLYNQ_MASK ; -break ; -case OMAP24XX_CLKSEL_SSI_SHIFT : - mask =OMAP24XX_CLKSEL_SSI_MASK ; -break ; -case OMAP24XX_CLKSEL_USB_SHIFT : - mask =OMAP24XX_CLKSEL_USB_MASK ; -break ; - } - } - -if (unlikely ((mask == ~0 ) || (div_addr ==0 ))) -return 0 ; - - *field_mask = mask; - -return div_addr; +return clk->clksel_reg; } -/** * omap2_clksel_get_divisor - get current divider applied to parent clock. * @clk: OMAP struct clk to use.
@@ -881,7 +815,7 @@ static u32 omap2_clksel_get_divisor(struu32 field_mask, field_val;void __iomem *div_addr; - div_addr =omap2_get_clksel (&field_mask, clk); + div_addr =omap2_get_clksel (clk, &field_mask);if (div_addr ==0 )return 0 ;
@@ -910,7 +844,7 @@ static int omap2_clk_set_rate(struct clkif (validrate != rate)return ret; - div_addr =omap2_get_clksel (&field_mask, clk); + div_addr =omap2_get_clksel (clk, &field_mask);if (div_addr ==0 )return ret;
Paul Walmsley
maintainerPATCH 11/28 omap2 clock: convert omap2_clksel_get_src_field() to use new clksel struct
In reply to Paul WalmsleyConvert omap2_clksel_get_src_field() to use new struct clksel and struct clksel_rate data.
--- arch/arm/mach-omap2/clock.c | 206 +++++--------------------------------------- 1 file changed, 25 insertions(+), 181 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +25 -181
@@ -46,38 +46,11 @@#define EN_APLL_STOPPED 0#define EN_APLL_LOCKED 3 -/* CM_{CLKSEL2_CORE,CLKSEL_WKUP}.CLKSEL_GPT* options (24XX) */ -#define CLKSEL_GPT_32K 0 -#define CLKSEL_GPT_SYSCLK 1 -#define CLKSEL_GPT_EXTALTCLK 2 - -/* CM_CLKSEL1_CORE.CLKSEL_DSS1 options (24XX) */ -#define CLKSEL_DSS1_SYSCLK 0 -#define CLKSEL_DSS1_CORECLK_16 0x10 - -/* CM_CLKSEL1_CORE.CLKSEL_DSS2 options (24XX) */ -#define CLKSEL_DSS2_SYSCLK 0 -#define CLKSEL_DSS2_48MHZ 1 -/* CM_CLKSEL1_PLL.APLLS_CLKIN options (24XX) */ #define APLLS_CLKIN_19_2MHZ 0#define APLLS_CLKIN_13MHZ 2#define APLLS_CLKIN_12MHZ 3 -/* CM_CLKSEL1_PLL.54M_SOURCE options (24XX) */ -#define CLK_54M_SOURCE_APLL 0 -#define CLK_54M_SOURCE_EXTALTCLK 1 - -/* CM_CLKSEL1_PLL.48M_SOURCE options (24XX) */ -#define CLK_48M_SOURCE_APLL 0 -#define CLK_48M_SOURCE_EXTALTCLK 1 - -/* PRCM_CLKOUT_CTRL.CLKOUT_SOURCE options (2420) */ -#define CLKOUT_SOURCE_CORE_CLK 0 -#define CLKOUT_SOURCE_SYS_CLK 1 -#define CLKOUT_SOURCE_96M_CLK 2 -#define CLKOUT_SOURCE_54M_CLK 3 -#define MAX_PLL_LOCK_WAIT 100000//#define DOWN_VARIABLE_DPLL 1 /* Experimental */
@@ -473,28 +446,6 @@ static void omap2_clksel_recalc(struct cpropagate_rate (clk); } -/* -* Finds best divider value in an array based on the source and target -* rates. The divider array must be sorted with smallest divider first. -*/ -static inline u32 omap2_divider_from_table (u32 size,u32 *div_array, -u32 src_rate,u32 tgt_rate) -{ -int i, test_rate; - -if (div_array ==NULL ) -return ~1 ; - -for (i =0 ; i < size; i++) { - test_rate = src_rate / *div_array; -if (test_rate <= tgt_rate) -return *div_array; - ++div_array; - } - -return ~0 ;/* No acceptable divider */ -} -/** * omap2_get_clksel_by_parent - return clksel struct for a given clk & parent * @clk: OMAP struct clk ptr to inspect
@@ -875,151 +826,44 @@ static int omap2_clk_set_rate(struct clkreturn ret; } -/* Converts encoded control register address into a full address */ +/* +* Converts encoded control register address into a full address +* On error, *src_addr will be returned as 0. +*/ static u32 omap2_clksel_get_src_field (void __iomem **src_addr,struct clk *src_clk,u32 *field_mask,struct clk *clk,u32 *parent_div) { -u32 val = ~0 , mask =0 ; -void __iomem *src_reg_addr =0 ; -u32 reg_offset; +const struct clksel *clks; +const struct clksel_rate *clkr; *parent_div =0 ; - reg_offset = clk->src_offset; + *src_addr =0 ; -/* Find target control register.*/ -switch (clk->flags &SRC_RATE_SEL_MASK ) { -case CM_CORE_SEL1 : - src_reg_addr =OMAP_CM_REGADDR (CORE_MOD ,CM_CLKSEL1 ); -if (reg_offset ==OMAP24XX_CLKSEL_DSS2_SHIFT ) { - mask =OMAP24XX_CLKSEL_DSS2_MASK ; -if (src_clk == &sys_ck) - val =CLKSEL_DSS2_SYSCLK ; -else if (src_clk == &func_48m_ck) - val =CLKSEL_DSS2_48MHZ ; -else -WARN_ON (1 );/* unknown src_clk */ - }else if (reg_offset ==OMAP24XX_CLKSEL_DSS1_SHIFT ) { - mask =OMAP24XX_CLKSEL_DSS1_MASK ; -if (src_clk == &sys_ck) { - val =CLKSEL_DSS1_SYSCLK ; - }else if (src_clk == &core_ck) { - val =CLKSEL_DSS1_CORECLK_16 ; - *parent_div =16 ; - }else { -WARN_ON (1 );/* unknown src clk */ - } - }else if ((reg_offset ==OMAP2420_CLKSEL_VLYNQ_SHIFT ) && -cpu_is_omap2420 ()) { - mask =OMAP2420_CLKSEL_VLYNQ_MASK ; -if (src_clk == &func_96m_ck) { - val =CLKSEL_VLYNQ_96MHZ ; - }else if (src_clk == &core_ck) { - val =CLKSEL_VLYNQ_CORECLK_16 ; - *parent_div =16 ; - }else { -WARN_ON (1 );/* unknown src_clk */ - } - }else { -WARN_ON (1 );/* unknown reg_offset */ - } -break ; -case CM_CORE_SEL2 : -WARN_ON (reg_offset <OMAP24XX_CLKSEL_GPT2_SHIFT || - reg_offset >OMAP24XX_CLKSEL_GPT12_SHIFT ); - src_reg_addr =OMAP_CM_REGADDR (CORE_MOD ,CM_CLKSEL2 ); - mask =OMAP24XX_CLKSEL_GPT2_MASK ; - mask <<= (reg_offset -OMAP24XX_CLKSEL_GPT2_SHIFT ); -if (src_clk == &func_32k_ck) - val =CLKSEL_GPT_32K ; -else if (src_clk == &sys_ck) - val =CLKSEL_GPT_SYSCLK ; -else if (src_clk == &alt_ck) - val =CLKSEL_GPT_EXTALTCLK ; -else -WARN_ON (1 );/* unknown src_clk */ -break ; -case CM_WKUP_SEL1 : -WARN_ON (reg_offset !=0 );/* unknown reg_offset */ - src_reg_addr =OMAP_CM_REGADDR (WKUP_MOD ,CM_CLKSEL ); - mask =OMAP24XX_CLKSEL_GPT1_MASK ; -if (src_clk == &func_32k_ck) - val =CLKSEL_GPT_32K ; -else if (src_clk == &sys_ck) - val =CLKSEL_GPT_SYSCLK ; -else if (src_clk == &alt_ck) - val =CLKSEL_GPT_EXTALTCLK ; -else -WARN_ON (1 );/* unknown src_clk */ -break ; -case CM_PLL_SEL1 : - src_reg_addr =OMAP_CM_REGADDR (PLL_MOD ,CM_CLKSEL1 ); -if (reg_offset ==0x3 ) { - mask =OMAP24XX_48M_SOURCE ; -if (src_clk == &apll96_ck) - val =CLK_48M_SOURCE_APLL ; -else if (src_clk == &alt_ck) - val =CLK_48M_SOURCE_EXTALTCLK ; -else -WARN_ON (1 );/* unknown src_clk */ - } -else if (reg_offset ==0x5 ) { - mask =OMAP24XX_54M_SOURCE ; -if (src_clk == &apll54_ck) - val =CLK_54M_SOURCE_APLL ; -else if (src_clk == &alt_ck) - val =CLK_54M_SOURCE_EXTALTCLK ; -else -WARN_ON (1 );/* unknown src_clk */ - }else { -WARN_ON (1 );/* unknown reg_offset */ - } -break ; -case CM_PLL_SEL2 : -WARN_ON (reg_offset !=0 ); - src_reg_addr =OMAP_CM_REGADDR (PLL_MOD ,CM_CLKSEL2 ); - mask =OMAP24XX_CORE_CLK_SRC_MASK ; -if (src_clk == &func_32k_ck) - val =CORE_CLK_SRC_32K ; -else if (src_clk == &dpll_ck) - val =CORE_CLK_SRC_DPLL_X2 ; -else -WARN_ON (1 );/* unknown src_clk */ -break ; -case CM_SYSCLKOUT_SEL1 : - src_reg_addr =OMAP24XX_PRCM_CLKOUT_CTRL ; - -if (reg_offset ==OMAP24XX_CLKOUT_SOURCE_SHIFT ) { - mask =OMAP24XX_CLKOUT_SOURCE_MASK ; - }else if (reg_offset ==OMAP2420_CLKOUT2_SOURCE_SHIFT ) { - mask =OMAP2420_CLKOUT2_SOURCE_MASK ; - }else { -WARN_ON (1 );/* unknown reg_offset */ - } + clks =omap2_get_clksel_by_parent (clk, src_clk); +if (clks ==NULL ) +return 0 ; -if (src_clk == &dpll_ck) - val =0 ; -else if (src_clk == &sys_ck) - val =1 ; -else if (src_clk == &func_96m_ck) - val =2 ; -else if (src_clk == &func_54m_ck) - val =3 ; -else -WARN_ON (1 );/* unknown src_clk */ -break ; +for (clkr = clks->rates; clkr->div; clkr++) { +if (clkr->flags & (cpu_mask |DEFAULT_RATE )) +break ;/* Found the default rate for this platform */ } -if (val == ~0 )/* Catch errors in offset */ - *src_addr =0 ; -else - *src_addr = src_reg_addr; +if (!clkr->div) { +printk (KERN_ERR "clock: Could not find default rate for " +"clock %s parent %s\n" , clk->name, + src_clk->parent->name); +return 0 ; + } -WARN_ON (mask ==0 ); +/* Should never happen. Add a clksel mask to the struct clk. */ +WARN_ON (clk->clksel_mask ==0 ); - *field_mask = mask; + *field_mask = clk->clksel_mask; + *src_addr = clk->clksel_reg; + *parent_div = clkr->div; -return val; +return clkr->val; }static int omap2_clk_set_parent (struct clk *clk,struct clk *new_parent)
Paul Walmsley
maintainerPATCH 12/28 omap2 clock: stop using clk->src_offset in omap2_clk_set_rate()
In reply to Paul WalmsleyStop using clk->rate_offset in omap2_clk_set_rate(); use what we get from the clksel code instead.
--- arch/arm/mach-omap2/clock.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +3 -6
@@ -780,17 +780,14 @@ static u32 omap2_clksel_get_divisor(strustatic int omap2_clk_set_rate (struct clk *clk,unsigned long rate) {int ret = -EINVAL ; -u32 div_off, field_mask, field_val, reg_val, validrate; -u32 new_div =0 ; +u32 field_mask, field_val, reg_val, new_div =0 ; +unsigned long validrate;void __iomem *div_addr;if (!(clk->flags &CONFIG_PARTICIPANT ) && (clk->flags &RATE_CKCTL )) {if (clk == &dpll_ck)return omap2_reprogram_dpll (clk, rate); -/* Isolate control register */ - div_off = clk->rate_offset; - validrate =omap2_clksel_round_rate (clk, rate, &new_div);if (validrate != rate)return ret;
@@ -805,7 +802,7 @@ static int omap2_clk_set_rate(struct clk reg_val =cm_read_reg (div_addr); reg_val &= ~field_mask; - reg_val |= (field_val << div_off); + reg_val |= (field_val <<convert_mask_to_shift (field_mask));cm_write_reg (reg_val, div_addr);wmb (); clk->rate = clk->parent->rate / new_div;
Paul Walmsley
maintainerPATCH 13/28 omap2 clock: stop using clk->src_offset in omap2_clk_set_parent()
In reply to Paul WalmsleyStop using clk->src_offset in omap2_clk_set_parent(); use what we get from the clksel code instead.
--- arch/arm/mach-omap2/clock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +4 -1
@@ -884,7 +884,7 @@ static int omap2_clk_set_parent(struct c/* Set new source value (previous dividers if any in effect) */ reg_val =__raw_readl (src_addr) & ~field_mask; - reg_val |= (field_val << clk->src_offset); + reg_val |= (field_val <<convert_mask_to_shift (field_mask));__raw_writel (reg_val, src_addr);wmb ();
@@ -905,6 +905,9 @@ static int omap2_clk_set_parent(struct cif (parent_div >0 ) clk->rate /= parent_div; +pr_debug ("clock: set parent of %s to %s (new rate %ld)\n" , + clk->name, clk->parent->name, clk->rate); +if (unlikely (clk->flags &RATE_PROPAGATES ))propagate_rate (clk);
Paul Walmsley
maintainerPATCH 14/28 omap2 clock: clean out old code from omap2_clksel_recalc()
In reply to Paul WalmsleyGet rid of now-obsolete code in omap2_clksel_recalc().
--- arch/arm/mach-omap2/clock.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +8 -16
@@ -8,6 +8,10 @@* Cleaned up and modified to use omap shared clock framework by * Tony Lindgren <[email protected]> * +* Copyright (C) 2007 Texas Instruments, Inc. +* Copyright (C) 2007 Nokia Corporation +* Paul Walmsley +* * Based on omap1 clock.c, Copyright (C) 2004 - 2005 Nokia corporation * Written by Tuukka Tikkanen <[email protected]> *
@@ -38,10 +42,6 @@#undef DEBUG -/* CM_CLKSEL1_CORE.CLKSEL_VLYNQ options (2420) */ -#define CLKSEL_VLYNQ_96MHZ 0 -#define CLKSEL_VLYNQ_CORECLK_16 0x10 -/* CM_CLKEN_PLL.EN_{54,96}M_PLL options (24XX) */ #define EN_APLL_STOPPED 0#define EN_APLL_LOCKED 3
@@ -420,19 +420,9 @@ static void omap2_dpll_recalc(struct clk*/ static void omap2_clksel_recalc (struct clk * clk) { -u32 clksel1_core, div =0 ; +u32 div =0 ; - clksel1_core =cm_read_mod_reg (CORE_MOD ,CM_CLKSEL1 ); - -if ((clk == &dss1_fck) && - (clksel1_core &OMAP24XX_CLKSEL_DSS1_MASK ) ==0 ) { - div =1 ; - } - -if ((clk == &vlynq_fck) &&cpu_is_omap2420 () && - (clksel1_core &OMAP2420_CLKSEL_VLYNQ_MASK ) ==CLKSEL_VLYNQ_96MHZ ) { - div =1 ; - } +pr_debug ("clock: recalc'ing clksel clk %s\n" , clk->name); div =omap2_clksel_get_divisor (clk);if (div ==0 )
@@ -442,6 +432,8 @@ static void omap2_clksel_recalc(struct creturn ; clk->rate = clk->parent->rate / div; +pr_debug ("clock: new clock rate is %ld (div %d)\n" , clk->rate, div); +if (unlikely (clk->flags &RATE_PROPAGATES ))propagate_rate (clk); }
Paul Walmsley
maintainerPATCH 15/28 omap2 clock: convert remaining clksel clocks to use omap2_clksel_recalc
In reply to Paul WalmsleyThis completes the transition to struct clksel/clksel_rate by converting the remaining clksel clocks to call omap2_clksel_recalc() on rate recalculation. Also remove RATE_FIXED from some clocks that can now recalculate their own rates correctly via clksel.
--- arch/arm/mach-omap2/clock.h | 56 +++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 29 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.h
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
arch/arm/mach-omap2/clock.h +27 -29
@@ -1,5 +1,5 @@/* -* linux/arch/arm/mach-omap24xx/clock.h +* linux/arch/arm/mach-omap2/clock.h * * Copyright (C) 2005 Texas Instruments Inc. * Richard Woodruff <[email protected]>
@@ -9,6 +9,10 @@* Written by Tuukka Tikkanen <[email protected]> * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc * +* Copyright (C) 2007 Texas Instruments, Inc. +* Copyright (C) 2007 Nokia Corporation +* Revised by Paul Walmsley +* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation.
@@ -687,16 +691,15 @@ static const struct clksel func_54m_clksstatic struct clk func_54m_ck = { .name ="func_54m_ck" , .parent = &apll54_ck,/* can also be alt_clk */ - .rate =54000000 , .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | -RATE_FIXED |CM_PLL_SEL1 |RATE_PROPAGATES | +CM_PLL_SEL1 |RATE_PROPAGATES |PARENT_CONTROLS_CLOCK , .src_offset =OMAP24XX_54M_SOURCE_SHIFT , .init = &omap2_init_clksel_parent, .clksel_reg =OMAP_CM_REGADDR (PLL_MOD ,CM_CLKSEL1 ), .clksel_mask =OMAP24XX_54M_SOURCE , .clksel = func_54m_clksel, - .recalc = &propagate_rate, + .recalc = &omap2_clksel_recalc, };static struct clk core_ck = {
@@ -728,15 +731,13 @@ static const struct clksel func_96m_clksstatic struct clk func_96m_ck = { .name ="func_96m_ck" , .parent = &apll96_ck, - .rate =96000000 , .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | -RATE_FIXED |RATE_PROPAGATES | -PARENT_CONTROLS_CLOCK , +RATE_PROPAGATES |PARENT_CONTROLS_CLOCK , .init = &omap2_init_clksel_parent, .clksel_reg =OMAP_CM_REGADDR (PLL_MOD ,CM_CLKSEL1 ), .clksel_mask =OMAP2430_96M_SOURCE , .clksel = func_96m_clksel, - .recalc = &propagate_rate, + .recalc = &omap2_clksel_recalc, };/* func_48m_ck */
@@ -760,16 +761,15 @@ static const struct clksel func_48m_clksstatic struct clk func_48m_ck = { .name ="func_48m_ck" , .parent = &apll96_ck,/* 96M or Alt */ - .rate =48000000 , .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | -RATE_FIXED |CM_PLL_SEL1 |RATE_PROPAGATES | +CM_PLL_SEL1 |RATE_PROPAGATES |PARENT_CONTROLS_CLOCK , .src_offset =OMAP24XX_48M_SOURCE_SHIFT , .init = &omap2_init_clksel_parent, .clksel_reg =OMAP_CM_REGADDR (PLL_MOD ,CM_CLKSEL1 ), .clksel_mask =OMAP24XX_48M_SOURCE , .clksel = func_48m_clksel, - .recalc = &propagate_rate, + .recalc = &omap2_clksel_recalc, };static struct clk func_12m_ck = {
@@ -828,7 +828,6 @@ static const struct clksel common_clkoutstatic struct clk sys_clkout_src = { .name ="sys_clkout_src" , .parent = &func_54m_ck, - .rate =54000000 , .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X |CM_SYSCLKOUT_SEL1 |RATE_CKCTL |RATE_PROPAGATES ,
@@ -839,7 +838,7 @@ static struct clk sys_clkout_src = { .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .clksel_mask = OMAP24XX_CLKOUT_SOURCE_MASK, .clksel = common_clkout_src_clksel, - .recalc = &propagate_rate, + .recalc = &omap2_clksel_recalc, };static const struct clksel_rate common_clkout_rates[] = {
@@ -882,7 +881,7 @@ static struct clk sys_clkout2_src = { .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .clksel_mask = OMAP2420_CLKOUT2_SOURCE_MASK, .clksel = common_clkout_src_clksel, - .recalc = &propagate_rate, + .recalc = &omap2_clksel_recalc, };static const struct clksel sys_clkout2_clksel[] = {
@@ -900,7 +899,7 @@ static struct clk sys_clkout2 = { .clksel_mask = OMAP2420_CLKOUT2_DIV_MASK, .clksel = sys_clkout2_clksel, .rate_offset = OMAP2420_CLKOUT2_DIV_SHIFT, - .recalc = &propagate_rate, + .recalc = &omap2_clksel_recalc, };static struct clk emul_ck = {
@@ -1466,8 +1465,7 @@ static struct clk dss2_fck = { /* Alt c .name = "dss2_fck", .parent = &sys_ck, /* fixed at sys_ck or 48MHz */ .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | -RATE_CKCTL |CM_CORE_SEL1 |RATE_FIXED | - DELAYED_APP, + RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_DSS2_SHIFT, .src_offset = OMAP24XX_CLKSEL_DSS2_SHIFT,
@@ -1536,7 +1534,7 @@ static struct clk gpt1_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT1_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk gpt2_ick = {
@@ -1560,7 +1558,7 @@ static struct clk gpt2_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT2_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk gpt3_ick = {
@@ -1584,7 +1582,7 @@ static struct clk gpt3_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT3_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk gpt4_ick = {
@@ -1608,7 +1606,7 @@ static struct clk gpt4_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT4_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk gpt5_ick = {
@@ -1632,7 +1630,7 @@ static struct clk gpt5_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT5_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk gpt6_ick = {
@@ -1656,7 +1654,7 @@ static struct clk gpt6_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT6_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk gpt7_ick = {
@@ -1680,7 +1678,7 @@ static struct clk gpt7_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT7_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk gpt8_ick = {
@@ -1704,7 +1702,7 @@ static struct clk gpt8_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT8_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk gpt9_ick = {
@@ -1728,7 +1726,7 @@ static struct clk gpt9_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT9_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk gpt10_ick = {
@@ -1752,7 +1750,7 @@ static struct clk gpt10_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT10_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk gpt11_ick = {
@@ -1776,7 +1774,7 @@ static struct clk gpt11_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT11_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk gpt12_ick = {
@@ -1800,7 +1798,7 @@ static struct clk gpt12_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT12_MASK, .clksel = gpt_clksel, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, };static struct clk mcbsp1_ick = {
Paul Walmsley
maintainerPATCH 16/28 omap2 clock: remove all {src, rate}_offset fields from struct clk
In reply to Paul Walmsleysrc_offset and rate_offset are no longer used in OMAP2 clock framework after the struct clksel/struct clksel_rate additions. Remove these fields from clock.h and #ifdef out those fields for OMAP24XX compiles.
--- arch/arm/mach-omap2/clock.c | 4 ++-- arch/arm/mach-omap2/clock.h | 38 +------------------------------------- include/asm-arm/arch-omap/clock.h | 5 +++-- 3 files changed, 6 insertions(+), 41 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +2 -2
@@ -121,7 +121,7 @@ static void omap2_sys_clk_recalc(struct div =prm_read_reg (OMAP24XX_PRCM_CLKSRC_CTRL );/* Test if ext clk divided by 1 or 2 */ div &=OMAP_SYSCLKDIV_MASK ; - div >>= clk->rate_offset; + div >>=OMAP_SYSCLKDIV_SHIFT ; clk->rate = (clk->parent->rate / div); }propagate_rate (clk);
@@ -1032,7 +1032,7 @@ static void __init omap2_get_crystal_rat div =prm_read_reg (OMAP24XX_PRCM_CLKSRC_CTRL ); div &=OMAP_SYSCLKDIV_MASK ; - div >>= sys->rate_offset; + div >>=OMAP_SYSCLKDIV_SHIFT ; osc->rate = sclk * div; sys->rate = sclk;
arch/arm/mach-omap2/clock.h +1 -37
@@ -11,7 +11,7 @@* * Copyright (C) 2007 Texas Instruments, Inc. * Copyright (C) 2007 Nokia Corporation -* Revised by Paul Walmsley +* Paul Walmsley * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as
@@ -615,7 +615,6 @@ static struct clk sys_ck = { /* (*12, * .rate = 13000000, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES, - .rate_offset = OMAP_SYSCLKDIV_SHIFT, /* sysclkdiv 1 or 2, already handled or no boot */ .recalc = &omap2_sys_clk_recalc, };
@@ -694,7 +693,6 @@ static struct clk func_54m_ck = { .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |CM_PLL_SEL1 |RATE_PROPAGATES | PARENT_CONTROLS_CLOCK, - .src_offset = OMAP24XX_54M_SOURCE_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_54M_SOURCE,
@@ -764,7 +762,6 @@ static struct clk func_48m_ck = { .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |CM_PLL_SEL1 |RATE_PROPAGATES | PARENT_CONTROLS_CLOCK, - .src_offset = OMAP24XX_48M_SOURCE_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_48M_SOURCE,
@@ -831,7 +828,6 @@ static struct clk sys_clkout_src = { .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |CM_SYSCLKOUT_SEL1 |RATE_CKCTL | RATE_PROPAGATES, - .src_offset = OMAP24XX_CLKOUT_SOURCE_SHIFT, .enable_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .enable_bit = OMAP24XX_CLKOUT_EN_SHIFT, .init = &omap2_init_clksel_parent,
@@ -864,7 +860,6 @@ static struct clk sys_clkout = { .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .clksel_mask = OMAP24XX_CLKOUT_DIV_MASK, .clksel = sys_clkout_clksel, - .rate_offset = OMAP24XX_CLKOUT_DIV_SHIFT, .recalc = &omap2_clksel_recalc, };
@@ -872,7 +867,6 @@ static struct clk sys_clkout = {static struct clk sys_clkout2_src = { .name ="sys_clkout2_src" , .parent = &func_54m_ck, - .src_offset =OMAP2420_CLKOUT2_SOURCE_SHIFT , .flags =CLOCK_IN_OMAP242X |CM_SYSCLKOUT_SEL1 |RATE_CKCTL |RATE_PROPAGATES , .enable_reg =OMAP24XX_PRCM_CLKOUT_CTRL ,
@@ -898,7 +892,6 @@ static struct clk sys_clkout2 = { .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .clksel_mask = OMAP2420_CLKOUT2_DIV_MASK, .clksel = sys_clkout2_clksel, - .rate_offset = OMAP2420_CLKOUT2_DIV_SHIFT, .recalc = &omap2_clksel_recalc, };
@@ -942,7 +935,6 @@ static struct clk mpu_ck = { /* Control .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_CKCTL |ALWAYS_ENABLED |CM_MPU_SEL1 |DELAYED_APP | CONFIG_PARTICIPANT | RATE_PROPAGATES, - .rate_offset = OMAP24XX_CLKSEL_MPU_SHIFT, /* bits 0-4 */ .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL), .clksel_mask = OMAP24XX_CLKSEL_MPU_MASK,
@@ -983,7 +975,6 @@ static struct clk iva2_1_fck = { .flags = CLOCK_IN_OMAP243X | RATE_CKCTL | CM_DSP_SEL1 |DELAYED_APP |RATE_PROPAGATES | CONFIG_PARTICIPANT, - .rate_offset = OMAP24XX_CLKSEL_DSP_SHIFT, .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP24XX_CM_FCLKEN), .enable_bit = OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT, .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
@@ -1010,7 +1001,6 @@ static struct clk iva2_1_ick = { .parent = &iva2_1_fck, .flags =CLOCK_IN_OMAP243X |RATE_CKCTL |CM_DSP_SEL1 | DELAYED_APP | CONFIG_PARTICIPANT, - .rate_offset = OMAP24XX_CLKSEL_DSP_IF_SHIFT, .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL), .clksel_mask = OMAP24XX_CLKSEL_DSP_IF_MASK, .clksel = iva2_1_ick_clksel,
@@ -1044,7 +1034,6 @@ static struct clk dsp_fck = { .parent = &core_ck, .flags =CLOCK_IN_OMAP242X |RATE_CKCTL |CM_DSP_SEL1 | DELAYED_APP | CONFIG_PARTICIPANT | RATE_PROPAGATES, - .rate_offset = OMAP24XX_CLKSEL_DSP_SHIFT, .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP24XX_CM_FCLKEN), .enable_bit = OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT, .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
@@ -1070,7 +1059,6 @@ static struct clk dsp_ick = { .parent = &core_ck, .flags =CLOCK_IN_OMAP242X |RATE_CKCTL |CM_DSP_SEL1 | DELAYED_APP | CONFIG_PARTICIPANT, - .rate_offset = OMAP24XX_CLKSEL_DSP_IF_SHIFT, .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_ICLKEN), .enable_bit = OMAP2420_EN_DSP_IPI_SHIFT, /* for ipi */ .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
@@ -1100,7 +1088,6 @@ static struct clk iva1_ifck = { .parent = &core_ck, .flags =CLOCK_IN_OMAP242X |CM_DSP_SEL1 |RATE_CKCTL | CONFIG_PARTICIPANT | RATE_PROPAGATES | DELAYED_APP, - .rate_offset = OMAP2420_CLKSEL_IVA_SHIFT, .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP24XX_CM_FCLKEN), .enable_bit = OMAP2420_EN_IVA_COP_SHIFT, .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
@@ -1162,7 +1149,6 @@ static struct clk core_l3_ck = { /* UsedRATE_CKCTL |ALWAYS_ENABLED |CM_CORE_SEL1 |DELAYED_APP |CONFIG_PARTICIPANT | RATE_PROPAGATES, - .rate_offset = OMAP24XX_CLKSEL_L3_SHIFT, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_CLKSEL_L3_MASK, .clksel = core_l3_clksel,
@@ -1190,7 +1176,6 @@ static struct clk usb_l4_ick = { /* FS-U CONFIG_PARTICIPANT, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2), .enable_bit = OMAP24XX_EN_USB_SHIFT, - .rate_offset = OMAP24XX_CLKSEL_USB_SHIFT, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_CLKSEL_USB_MASK, .clksel = usb_l4_ick_clksel,
@@ -1231,7 +1216,6 @@ static struct clk ssi_ssr_sst_fck = { .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_CLKSEL_SSI_MASK, .clksel = ssi_ssr_sst_fck_clksel, - .rate_offset = OMAP24XX_CLKSEL_SSI_SHIFT, .recalc = &omap2_clksel_recalc, };
@@ -1272,7 +1256,6 @@ static struct clk gfx_3d_fck = { RATE_CKCTL | CM_GFX_SEL1, .enable_reg = OMAP_CM_REGADDR(GFX_MOD, OMAP24XX_CM_FCLKEN), .enable_bit = OMAP24XX_EN_3D_SHIFT, - .rate_offset = OMAP_CLKSEL_GFX_SHIFT, .clksel_reg = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL), .clksel_mask = OMAP_CLKSEL_GFX_MASK, .clksel = gfx_fck_clksel,
@@ -1286,7 +1269,6 @@ static struct clk gfx_2d_fck = { RATE_CKCTL | CM_GFX_SEL1, .enable_reg = OMAP_CM_REGADDR(GFX_MOD, OMAP24XX_CM_FCLKEN), .enable_bit = OMAP24XX_EN_2D_SHIFT, - .rate_offset = OMAP_CLKSEL_GFX_SHIFT, .clksel_reg = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL), .clksel_mask = OMAP_CLKSEL_GFX_MASK, .clksel = gfx_fck_clksel,
@@ -1327,7 +1309,6 @@ static struct clk mdm_ick = { /* used b .parent = &core_ck, .flags =CLOCK_IN_OMAP243X |RATE_CKCTL |CM_MODEM_SEL1 | DELAYED_APP | CONFIG_PARTICIPANT, - .rate_offset = OMAP2430_CLKSEL_MDM_SHIFT, .enable_reg = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_ICLKEN), .enable_bit = OMAP2430_CM_ICLKEN_MDM_EN_MDM_SHIFT, .clksel_reg = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_CLKSEL),
@@ -1369,7 +1350,6 @@ static struct clk l4_ck = { /* used bot .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |RATE_CKCTL |ALWAYS_ENABLED |CM_CORE_SEL1 | DELAYED_APP | RATE_PROPAGATES, - .rate_offset = OMAP24XX_CLKSEL_L4_SHIFT, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_CLKSEL_L4_MASK, .clksel = l4_clksel,
@@ -1436,8 +1416,6 @@ static struct clk dss1_fck = { RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_DSS1_SHIFT, - .rate_offset = OMAP24XX_CLKSEL_DSS1_SHIFT, - .src_offset = OMAP24XX_CLKSEL_DSS1_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_CLKSEL_DSS1_MASK,
@@ -1468,7 +1446,6 @@ static struct clk dss2_fck = { /* Alt c RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_DSS2_SHIFT, - .src_offset = OMAP24XX_CLKSEL_DSS2_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_CLKSEL_DSS2_MASK,
@@ -1529,7 +1506,6 @@ static struct clk gpt1_fck = { CM_WKUP_SEL1, .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, OMAP24XX_CM_FCLKEN), /* Bit0 */ .enable_bit = OMAP24XX_EN_GPT1_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT1_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT1_MASK,
@@ -1553,7 +1529,6 @@ static struct clk gpt2_fck = { CM_CORE_SEL2, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT2_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT2_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT2_MASK,
@@ -1577,7 +1552,6 @@ static struct clk gpt3_fck = { CM_CORE_SEL2, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT3_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT3_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT3_MASK,
@@ -1601,7 +1575,6 @@ static struct clk gpt4_fck = { CM_CORE_SEL2, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT4_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT4_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT4_MASK,
@@ -1625,7 +1598,6 @@ static struct clk gpt5_fck = { CM_CORE_SEL2, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT5_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT5_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT5_MASK,
@@ -1649,7 +1621,6 @@ static struct clk gpt6_fck = { CM_CORE_SEL2, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT6_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT6_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT6_MASK,
@@ -1673,7 +1644,6 @@ static struct clk gpt7_fck = { CM_CORE_SEL2, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT7_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT7_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT7_MASK,
@@ -1697,7 +1667,6 @@ static struct clk gpt8_fck = { CM_CORE_SEL2, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT8_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT8_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT8_MASK,
@@ -1721,7 +1690,6 @@ static struct clk gpt9_fck = { CM_CORE_SEL2, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT9_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT9_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT9_MASK,
@@ -1745,7 +1713,6 @@ static struct clk gpt10_fck = { CM_CORE_SEL2, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT10_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT10_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT10_MASK,
@@ -1769,7 +1736,6 @@ static struct clk gpt11_fck = { CM_CORE_SEL2, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT11_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT11_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT11_MASK,
@@ -1793,7 +1759,6 @@ static struct clk gpt12_fck = { CM_CORE_SEL2, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_GPT12_SHIFT, - .src_offset = OMAP24XX_CLKSEL_GPT12_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2), .clksel_mask = OMAP24XX_CLKSEL_GPT12_MASK,
@@ -2327,7 +2292,6 @@ static struct clk vlynq_fck = { .flags = CLOCK_IN_OMAP242X | RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP2420_EN_VLYNQ_SHIFT, - .src_offset = OMAP2420_CLKSEL_VLYNQ_SHIFT, .init = &omap2_init_clksel_parent, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP2420_CLKSEL_VLYNQ_MASK,
include/asm-arm/arch-omap/clock.h +3 -2
@@ -41,8 +41,6 @@ struct clk {__u32 flags;void __iomem *enable_reg;__u8 enable_bit; -__u8 rate_offset; -__u8 src_offset;__s8 usecount;void (*recalc)(struct clk *);int (*set_rate)(struct clk *,unsigned long );
@@ -55,6 +53,9 @@ struct clk {void __iomem *clksel_reg;u32 clksel_mask;const struct clksel *clksel; +#else +__u8 rate_offset; +__u8 src_offset;#endif };
Paul Walmsley
maintainerPATCH 17/28 omap2 clock: use the struct clk round_rate field for clksel rate rounding code
In reply to Paul WalmsleyThe OMAP clock framework struct clk contains a field, .round_rate, that is intended to contain a function pointer to rate rounding code. Take advantage of it by converting all clksel clocks' round_rate field to point to omap2_clksel_round_rate(). Rename the existing omap2_clksel_round_rate() to omap2_clksel_round_rate_div(), to signify that it returns divisor information as well, and set up omap2_clksel_round_rate() as a wrapper for the clock framework to use. Simplify omap2_clk_round_rate() accordingly.
--- arch/arm/mach-omap2/clock.c | 42 ++++++++++++++++++++++++++++++------------ arch/arm/mach-omap2/clock.h | 21 +++++++++++++++++++++ 2 files changed, 51 insertions(+), 12 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +30 -12
@@ -471,7 +471,7 @@ const static struct clksel *omap2_get_cl }/** -* omap2_clksel_round_rate - find divisor for the given clock and target rate. +* omap2_clksel_round_rate_div - find divisor for the given clock and rate * @clk: OMAP struct clk to use * @target_rate: desired clock rate * @new_div: ptr to where we should store the divisor
@@ -483,15 +483,16 @@ const static struct clksel *omap2_get_cl* * Returns the rounded clock rate or returns 0xffffffff on error. */ -static u32 omap2_clksel_round_rate (struct clk *clk,unsigned long target_rate, -u32 *new_div) +static u32 omap2_clksel_round_rate_div (struct clk *clk, +unsigned long target_rate, +u32 *new_div) {unsigned long test_rate;const struct clksel *clks;const struct clksel_rate *clkr;u32 last_div =0 ; -printk (KERN_INFO "clock: clksel_round_rate for %s target_rate %ld\n" , +printk (KERN_INFO "clock: clksel_round_rate_div: %s target_rate %ld\n" , clk->name, target_rate); *new_div =1 ;
@@ -532,20 +533,37 @@ static u32 omap2_clksel_round_rate(strucreturn (clk->parent->rate / clkr->div); } -/* Given a clock and a rate apply a clock specific rounding function */ -static long omap2_clk_round_rate (struct clk *clk,unsigned long rate) +/** +* omap2_clksel_round_rate - find rounded rate for the given clock and rate +* @clk: OMAP struct clk to use +* @target_rate: desired clock rate +* +* Compatibility wrapper for OMAP clock framework +* Finds best target rate based on the source clock and possible dividers. +* rates. The divider array must be sorted with smallest divider first. +* Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, +* they are only settable as part of virtual_prcm set. +* +* Returns the rounded clock rate or returns 0xffffffff on error. +*/ +static long omap2_clksel_round_rate (struct clk *clk,unsigned long target_rate) { -u32 new_div =0 ; +u32 new_div; -if (clk->flags &RATE_FIXED ) -return clk->rate; +return omap2_clksel_round_rate_div (clk, target_rate, &new_div); +} -if (clk->flags &RATE_CKCTL ) -return omap2_clksel_round_rate (clk, rate, &new_div); +/* Given a clock and a rate apply a clock specific rounding function */ +static long omap2_clk_round_rate (struct clk *clk,unsigned long rate) +{if (clk->round_rate !=0 )return clk->round_rate (clk, rate); +if (clk->flags &RATE_FIXED ) +printk (KERN_ERR "clock: generic omap2_clk_round_rate called " +"on fixed-rate clock %s\n" , clk->name); +return clk->rate; }
@@ -780,7 +798,7 @@ static int omap2_clk_set_rate(struct clkif (clk == &dpll_ck)return omap2_reprogram_dpll (clk, rate); - validrate =omap2_clksel_round_rate (clk, rate, &new_div); + validrate =omap2_clksel_round_rate_div (clk, rate, &new_div);if (validrate != rate)return ret;
arch/arm/mach-omap2/clock.h +21 -0
@@ -39,6 +39,8 @@ static u32 omap2_clksel_to_divisor(strucstatic u32 omap2_divisor_to_clksel (struct clk *clk,u32 div);static void omap2_dpll_recalc (struct clk *clk);static void omap2_fixed_divisor_recalc (struct clk *clk); +static long omap2_clksel_round_rate (struct clk *clk,unsigned long target_rate); +/* Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated. * xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,CM_CLKSEL_DSP
@@ -736,6 +738,7 @@ static struct clk func_96m_ck = { .clksel_mask = OMAP2430_96M_SOURCE, .clksel = func_96m_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };/* func_48m_ck */
@@ -767,6 +770,7 @@ static struct clk func_48m_ck = { .clksel_mask = OMAP24XX_48M_SOURCE, .clksel = func_48m_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };static struct clk func_12m_ck = {
@@ -861,6 +865,7 @@ static struct clk sys_clkout = { .clksel_mask = OMAP24XX_CLKOUT_DIV_MASK, .clksel = sys_clkout_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };/* In 2430, new in 2420 ES2 */
@@ -940,6 +945,7 @@ static struct clk mpu_ck = { /* Control .clksel_mask = OMAP24XX_CLKSEL_MPU_MASK, .clksel = mpu_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };/*
@@ -981,6 +987,7 @@ static struct clk iva2_1_fck = { .clksel_mask = OMAP24XX_CLKSEL_DSP_MASK, .clksel = iva2_1_fck_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };/* iva2_1_ick */
@@ -1005,6 +1012,8 @@ static struct clk iva2_1_ick = { .clksel_mask = OMAP24XX_CLKSEL_DSP_IF_MASK, .clksel = iva2_1_ick_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate + };/*
@@ -1040,6 +1049,7 @@ static struct clk dsp_fck = { .clksel_mask = OMAP24XX_CLKSEL_DSP_MASK, .clksel = dsp_fck_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };static const struct clksel_rate dsp_ick_core_rates[] = {
@@ -1094,6 +1104,7 @@ static struct clk iva1_ifck = { .clksel_mask = OMAP2420_CLKSEL_IVA_MASK, .clksel = iva1_ifck_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };/* IVA1 mpu/int/i/f clocks are /2 of parent */
@@ -1153,6 +1164,7 @@ static struct clk core_l3_ck = { /* Used .clksel_mask = OMAP24XX_CLKSEL_L3_MASK, .clksel = core_l3_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };/* usb_l4_ick */
@@ -1180,6 +1192,7 @@ static struct clk usb_l4_ick = { /* FS-U .clksel_mask = OMAP24XX_CLKSEL_USB_MASK, .clksel = usb_l4_ick_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };/*
@@ -1217,6 +1230,7 @@ static struct clk ssi_ssr_sst_fck = { .clksel_mask = OMAP24XX_CLKSEL_SSI_MASK, .clksel = ssi_ssr_sst_fck_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };/*
@@ -1260,6 +1274,7 @@ static struct clk gfx_3d_fck = { .clksel_mask = OMAP_CLKSEL_GFX_MASK, .clksel = gfx_fck_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };static struct clk gfx_2d_fck = {
@@ -1273,6 +1288,7 @@ static struct clk gfx_2d_fck = { .clksel_mask = OMAP_CLKSEL_GFX_MASK, .clksel = gfx_fck_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };static struct clk gfx_ick = {
@@ -1315,6 +1331,7 @@ static struct clk mdm_ick = { /* used b .clksel_mask = OMAP2430_CLKSEL_MDM_MASK, .clksel = mdm_ick_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };static struct clk mdm_osc_ck = {
@@ -1354,6 +1371,7 @@ static struct clk l4_ck = { /* used bot .clksel_mask = OMAP24XX_CLKSEL_L4_MASK, .clksel = l4_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };static struct clk ssi_l4_ick = {
@@ -1421,6 +1439,7 @@ static struct clk dss1_fck = { .clksel_mask = OMAP24XX_CLKSEL_DSS1_MASK, .clksel = dss1_fck_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };static const struct clksel_rate dss2_fck_sys_rates[] = {
@@ -1511,6 +1530,7 @@ static struct clk gpt1_fck = { .clksel_mask = OMAP24XX_CLKSEL_GPT1_MASK, .clksel = gpt_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };static struct clk gpt2_ick = {
@@ -2297,6 +2317,7 @@ static struct clk vlynq_fck = { .clksel_mask = OMAP2420_CLKSEL_VLYNQ_MASK, .clksel = vlynq_fck_clksel, .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate };static struct clk sdrc_ick = {
Paul Walmsley
maintainerPATCH 19/28 omap2 clock: drop RATE_CKCTL from all OMAP2 clocks
In reply to Paul WalmsleyRATE_CKCTL is no longer meaningful in the OMAP2 clock framework, so, drop it from all clocks. We keep the flag around since it's still used by OMAP1.
--- arch/arm/mach-omap2/clock.h | 45 ++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.h
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
arch/arm/mach-omap2/clock.h +21 -24
@@ -641,8 +641,7 @@ static struct clk dpll_ck = { .name = "dpll_ck", .parent = &sys_ck, /* Can be func_32k also */ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | -RATE_PROPAGATES |RATE_CKCTL |CM_PLL_SEL1 | - ALWAYS_ENABLED, + RATE_PROPAGATES | CM_PLL_SEL1 | ALWAYS_ENABLED, .recalc = &omap2_dpll_recalc, .set_rate = &omap2_reprogram_dpll, };
@@ -834,8 +833,7 @@ static struct clk sys_clkout_src = { .name = "sys_clkout_src", .parent = &func_54m_ck, .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | -CM_SYSCLKOUT_SEL1 |RATE_CKCTL | - RATE_PROPAGATES, + CM_SYSCLKOUT_SEL1 | RATE_PROPAGATES, .enable_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .enable_bit = OMAP24XX_CLKOUT_EN_SHIFT, .init = &omap2_init_clksel_parent,
@@ -865,8 +863,7 @@ static struct clk sys_clkout = { .name = "sys_clkout", .parent = &sys_clkout_src, .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | -CM_SYSCLKOUT_SEL1 |RATE_CKCTL | - PARENT_CONTROLS_CLOCK, + CM_SYSCLKOUT_SEL1 | PARENT_CONTROLS_CLOCK, .clksel_reg = OMAP24XX_PRCM_CLKOUT_CTRL, .clksel_mask = OMAP24XX_CLKOUT_DIV_MASK, .clksel = sys_clkout_clksel,
@@ -879,7 +876,7 @@ static struct clk sys_clkout = {static struct clk sys_clkout2_src = { .name ="sys_clkout2_src" , .parent = &func_54m_ck, - .flags =CLOCK_IN_OMAP242X |CM_SYSCLKOUT_SEL1 |RATE_CKCTL | + .flags =CLOCK_IN_OMAP242X |CM_SYSCLKOUT_SEL1 |RATE_PROPAGATES , .enable_reg =OMAP24XX_PRCM_CLKOUT_CTRL , .enable_bit =OMAP2420_CLKOUT2_EN_SHIFT ,
@@ -901,7 +898,7 @@ static const struct clksel sys_clkout2_cstatic struct clk sys_clkout2 = { .name ="sys_clkout2" , .parent = &sys_clkout2_src, - .flags =CLOCK_IN_OMAP242X |CM_SYSCLKOUT_SEL1 |RATE_CKCTL | + .flags =CLOCK_IN_OMAP242X |CM_SYSCLKOUT_SEL1 |PARENT_CONTROLS_CLOCK , .clksel_reg =OMAP24XX_PRCM_CLKOUT_CTRL , .clksel_mask =OMAP2420_CLKOUT2_DIV_MASK ,
@@ -948,7 +945,7 @@ static const struct clksel mpu_clksel[]static struct clk mpu_ck = {/* Control cpu */ .name ="mpu_ck" , .parent = &core_ck, - .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X |RATE_CKCTL | + .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X |ALWAYS_ENABLED |CM_MPU_SEL1 |DELAYED_APP |CONFIG_PARTICIPANT |RATE_PROPAGATES , .init = &omap2_init_clksel_parent,
@@ -990,7 +987,7 @@ static const struct clksel iva2_1_fck_clstatic struct clk iva2_1_fck = { .name ="iva2_1_fck" , .parent = &core_ck, - .flags =CLOCK_IN_OMAP243X |RATE_CKCTL |CM_DSP_SEL1 | + .flags =CLOCK_IN_OMAP243X |CM_DSP_SEL1 |DELAYED_APP |RATE_PROPAGATES |CONFIG_PARTICIPANT , .enable_reg =OMAP_CM_REGADDR (OMAP24XX_DSP_MOD ,OMAP24XX_CM_FCLKEN ),
@@ -1019,7 +1016,7 @@ static const struct clksel iva2_1_ick_clstatic struct clk iva2_1_ick = { .name ="iva2_1_ick" , .parent = &iva2_1_fck, - .flags =CLOCK_IN_OMAP243X |RATE_CKCTL |CM_DSP_SEL1 | + .flags =CLOCK_IN_OMAP243X |CM_DSP_SEL1 |DELAYED_APP |CONFIG_PARTICIPANT , .clksel_reg =OMAP_CM_REGADDR (OMAP24XX_DSP_MOD ,CM_CLKSEL ), .clksel_mask =OMAP24XX_CLKSEL_DSP_IF_MASK ,
@@ -1054,7 +1051,7 @@ static const struct clksel dsp_fck_clksestatic struct clk dsp_fck = { .name ="dsp_fck" , .parent = &core_ck, - .flags =CLOCK_IN_OMAP242X |RATE_CKCTL |CM_DSP_SEL1 | + .flags =CLOCK_IN_OMAP242X |CM_DSP_SEL1 |DELAYED_APP |CONFIG_PARTICIPANT |RATE_PROPAGATES , .enable_reg =OMAP_CM_REGADDR (OMAP24XX_DSP_MOD ,OMAP24XX_CM_FCLKEN ), .enable_bit =OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT ,
@@ -1081,7 +1078,7 @@ static const struct clksel dsp_ick_clksestatic struct clk dsp_ick = { .name ="dsp_ick" ,/* apparently ipi and isp */ .parent = &core_ck, - .flags =CLOCK_IN_OMAP242X |RATE_CKCTL |CM_DSP_SEL1 | + .flags =CLOCK_IN_OMAP242X |CM_DSP_SEL1 |DELAYED_APP |CONFIG_PARTICIPANT , .enable_reg =OMAP_CM_REGADDR (OMAP24XX_DSP_MOD ,CM_ICLKEN ), .enable_bit =OMAP2420_EN_DSP_IPI_SHIFT ,/* for ipi */
@@ -1110,7 +1107,7 @@ static const struct clksel iva1_ifck_clkstatic struct clk iva1_ifck = { .name ="iva1_ifck" , .parent = &core_ck, - .flags =CLOCK_IN_OMAP242X |CM_DSP_SEL1 |RATE_CKCTL | + .flags =CLOCK_IN_OMAP242X |CM_DSP_SEL1 |CONFIG_PARTICIPANT |RATE_PROPAGATES |DELAYED_APP , .enable_reg =OMAP_CM_REGADDR (OMAP24XX_DSP_MOD ,OMAP24XX_CM_FCLKEN ), .enable_bit =OMAP2420_EN_IVA_COP_SHIFT ,
@@ -1172,7 +1169,7 @@ static struct clk core_l3_ck = { /* Used .name = "core_l3_ck", .parent = &core_ck, .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | -RATE_CKCTL |ALWAYS_ENABLED |CM_CORE_SEL1 | +ALWAYS_ENABLED |CM_CORE_SEL1 |DELAYED_APP |CONFIG_PARTICIPANT | RATE_PROPAGATES, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
@@ -1200,7 +1197,7 @@ static struct clk usb_l4_ick = { /* FS-U .name = "usb_l4_ick", .parent = &core_l3_ck, .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | -RATE_CKCTL |CM_CORE_SEL1 |DELAYED_APP | +CM_CORE_SEL1 |DELAYED_APP | CONFIG_PARTICIPANT, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2), .enable_bit = OMAP24XX_EN_USB_SHIFT,
@@ -1240,7 +1237,7 @@ static struct clk ssi_ssr_sst_fck = { .name = "ssi_fck", .parent = &core_ck, .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | - RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP, + CM_CORE_SEL1 | DELAYED_APP, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2), /* bit 1 */ .enable_bit = OMAP24XX_EN_SSI_SHIFT, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
@@ -1285,7 +1282,7 @@ static struct clk gfx_3d_fck = { .name = "gfx_3d_fck", .parent = &core_l3_ck, .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | - RATE_CKCTL | CM_GFX_SEL1, + CM_GFX_SEL1, .enable_reg = OMAP_CM_REGADDR(GFX_MOD, OMAP24XX_CM_FCLKEN), .enable_bit = OMAP24XX_EN_3D_SHIFT, .clksel_reg = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
@@ -1300,7 +1297,7 @@ static struct clk gfx_2d_fck = { .name = "gfx_2d_fck", .parent = &core_l3_ck, .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | - RATE_CKCTL | CM_GFX_SEL1, + CM_GFX_SEL1, .enable_reg = OMAP_CM_REGADDR(GFX_MOD, OMAP24XX_CM_FCLKEN), .enable_bit = OMAP24XX_EN_2D_SHIFT, .clksel_reg = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
@@ -1343,7 +1340,7 @@ static const struct clksel mdm_ick_clksestatic struct clk mdm_ick = {/* used both as a ick and fck */ .name ="mdm_ick" , .parent = &core_ck, - .flags =CLOCK_IN_OMAP243X |RATE_CKCTL |CM_MODEM_SEL1 | + .flags =CLOCK_IN_OMAP243X |CM_MODEM_SEL1 |DELAYED_APP |CONFIG_PARTICIPANT , .enable_reg =OMAP_CM_REGADDR (OMAP2430_MDM_MOD ,CM_ICLKEN ), .enable_bit =OMAP2430_CM_ICLKEN_MDM_EN_MDM_SHIFT ,
@@ -1386,7 +1383,7 @@ static struct clk l4_ck = { /* used bot .name = "l4_ck", .parent = &core_l3_ck, .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | -RATE_CKCTL |ALWAYS_ENABLED |CM_CORE_SEL1 | +ALWAYS_ENABLED |CM_CORE_SEL1 | DELAYED_APP | RATE_PROPAGATES, .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), .clksel_mask = OMAP24XX_CLKSEL_L4_MASK,
@@ -1453,7 +1450,7 @@ static struct clk dss1_fck = { .name = "dss1_fck", .parent = &core_ck, /* Core or sys */ .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | - RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP, + CM_CORE_SEL1 | DELAYED_APP, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_DSS1_SHIFT, .init = &omap2_init_clksel_parent,
@@ -1485,7 +1482,7 @@ static struct clk dss2_fck = { /* Alt c .name = "dss2_fck", .parent = &sys_ck, /* fixed at sys_ck or 48MHz */ .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | - RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP, + CM_CORE_SEL1 | DELAYED_APP, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP24XX_EN_DSS2_SHIFT, .init = &omap2_init_clksel_parent,
@@ -2333,7 +2330,7 @@ static const struct clksel vlynq_fck_clkstatic struct clk vlynq_fck = { .name ="vlynq_fck" , .parent = &func_96m_ck, - .flags =CLOCK_IN_OMAP242X |RATE_CKCTL |CM_CORE_SEL1 |DELAYED_APP , + .flags =CLOCK_IN_OMAP242X |CM_CORE_SEL1 |DELAYED_APP , .enable_reg =OMAP_CM_REGADDR (CORE_MOD ,CM_FCLKEN1 ), .enable_bit =OMAP2420_EN_VLYNQ_SHIFT , .init = &omap2_init_clksel_parent,
Paul Walmsley
maintainerPATCH 20/28 omap2 clock: remove *_SEL* clock flags
In reply to Paul WalmsleyWe no longer need the *_SEL* clock flags with the struct clksel conversion, so we get rid of them. This frees up 10 clock flag bits.
--- arch/arm/mach-omap2/clock.c | 4 - arch/arm/mach-omap2/clock.h | 111 +++++++++++++------------------------- include/asm-arm/arch-omap/clock.h | 11 --- 3 files changed, 41 insertions(+), 85 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +2 -2
@@ -890,7 +890,7 @@ static int omap2_clk_set_parent(struct cif (unlikely (clk->flags &CONFIG_PARTICIPANT ))return -EINVAL ; -if (unlikely (!(clk->flags &SRC_SEL_MASK ))) +if (!clk->clksel)return -EINVAL ; field_val = omap2_clksel_get_src_field(&src_addr, new_parent,
@@ -918,7 +918,7 @@ static int omap2_clk_set_parent(struct c clk->parent = new_parent; -/* SRC_RATE_SEL_MASK clocks follow their parents rates.*/ +/* CLKSEL clocks follow their parents' rates, divided by a divisor */ clk->rate = new_parent->rate;if (parent_div >0 )
arch/arm/mach-omap2/clock.h +38 -73
327 lines not on this page · raw message
include/asm-arm/arch-omap/clock.h +1 -10
@@ -95,16 +95,7 @@ extern int clk_get_usecount(struct clk *#define CLOCK_NO_IDLE_PARENT (1 << 8)#define DELAYED_APP (1 << 9)/* Delay application of clock */ #define CONFIG_PARTICIPANT (1 << 10)/* Fundamental clock */ -#define CM_MPU_SEL1 (1 << 11)/* Domain divider/source */ -#define CM_DSP_SEL1 (1 << 12) -#define CM_GFX_SEL1 (1 << 13) -#define CM_MODEM_SEL1 (1 << 14) -#define CM_CORE_SEL1 (1 << 15)/* Sets divider for many */ -#define CM_CORE_SEL2 (1 << 16)/* sets parent for GPT */ -#define CM_WKUP_SEL1 (1 << 17) -#define CM_PLL_SEL1 (1 << 18) -#define CM_PLL_SEL2 (1 << 19) -#define CM_SYSCLKOUT_SEL1 (1 << 20) +/* bits 11-20 are currently free */ #define CLOCK_IN_OMAP310 (1 << 21)#define CLOCK_IN_OMAP730 (1 << 22)#define CLOCK_IN_OMAP1510 (1 << 23)
Paul Walmsley
maintainerPATCH 21/28 omap2 clock: call clock-specific enable/disable functions if present
In reply to Paul WalmsleyCall clock-specific enable/disable functions if .enable/.disable function pointer fields are present in struct clk. Similar to OMAP1 clock code.
--- arch/arm/mach-omap2/clock.c | 8 ++++++++ 1 file changed, 8 insertions(+)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +8 -0
@@ -276,6 +276,9 @@ static int _omap2_clk_enable(struct clkreturn 0 ; } +if (clk->enable) +return clk->enable (clk); +if (unlikely (clk->enable_reg ==0 )) {printk (KERN_ERR "clock.c: Enable for %s without enable code\n" , clk->name);
@@ -315,6 +318,11 @@ static void _omap2_clk_disable(struct clif (clk->flags & (ALWAYS_ENABLED |PARENT_CONTROLS_CLOCK ))return ; +if (clk->disable) { + clk->disable (clk); +return ; + } +if (unlikely (clk == &osc_ck)) {omap2_set_osc_ck (0 );return ;
Paul Walmsley
maintainerPATCH 22/28 omap2 clock: use custom osc_ck enable/disable routines
In reply to Paul WalmsleyNow that we're paying attention to the .enable/.disable fields in struct clk, convert the osc_ck enable and disable code to use this standard mechanism. (osc_ck enable/disable does not technically enable or disable the osc_ck; it actually enables/disables autoidling.)
--- arch/arm/mach-omap2/clock.c | 32 +++++++++++++++----------------- arch/arm/mach-omap2/clock.h | 5 ++++- 2 files changed, 19 insertions(+), 18 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +15 -17
@@ -162,18 +162,26 @@ static void omap2_fixed_divisor_recalc(spropagate_rate (clk); } -static void omap2_set_osc_ck (int enable) +static int omap2_enable_osc_ck (struct clk *clk) {u32 pcc; pcc =prm_read_reg (OMAP24XX_PRCM_CLKSRC_CTRL ); -if (enable) -prm_write_reg (pcc & ~OMAP_AUTOEXTCLKMODE_MASK , -OMAP24XX_PRCM_CLKSRC_CTRL ); -else -prm_write_reg (pcc |OMAP_AUTOEXTCLKMODE_MASK , -OMAP24XX_PRCM_CLKSRC_CTRL ); +prm_write_reg (pcc & ~OMAP_AUTOEXTCLKMODE_MASK , +OMAP24XX_PRCM_CLKSRC_CTRL ); + +return 0 ; +} + +static void omap2_disable_osc_ck (struct clk *clk) +{ +u32 pcc; + + pcc =prm_read_reg (OMAP24XX_PRCM_CLKSRC_CTRL ); + +prm_write_reg (pcc |OMAP_AUTOEXTCLKMODE_MASK , +OMAP24XX_PRCM_CLKSRC_CTRL ); }/*
@@ -271,11 +279,6 @@ static int _omap2_clk_enable(struct clkif (clk->flags & (ALWAYS_ENABLED |PARENT_CONTROLS_CLOCK ))return 0 ; -if (unlikely (clk == &osc_ck)) { -omap2_set_osc_ck (1 ); -return 0 ; - } -if (clk->enable)return clk->enable (clk);
@@ -323,11 +326,6 @@ static void _omap2_clk_disable(struct clreturn ; } -if (unlikely (clk == &osc_ck)) { -omap2_set_osc_ck (0 ); -return ; - } -if (clk->enable_reg ==0 ) {/* * 'Independent' here refers to a clock which is not
arch/arm/mach-omap2/clock.h +4 -1
@@ -26,7 +26,6 @@#include "prm_regbits_24xx.h" #include "cm_regbits_24xx.h" -static void omap2_sys_clk_recalc (struct clk * clk);static void omap2_clksel_recalc (struct clk * clk);static void omap2_table_mpu_recalc (struct clk *clk);static int omap2_select_table_rate (struct clk * clk,unsigned long rate);
@@ -42,6 +41,8 @@ static void omap2_fixed_divisor_recalc(sstatic long omap2_clksel_round_rate (struct clk *clk,unsigned long target_rate);static int omap2_clksel_set_rate (struct clk *clk,unsigned long rate);static int omap2_reprogram_dpll (struct clk * clk,unsigned long rate); +static int omap2_enable_osc_ck (struct clk *clk); +static void omap2_disable_osc_ck (struct clk *clk);/* Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated. * xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,CM_CLKSEL_DSP
@@ -598,6 +599,8 @@ static struct clk osc_ck = { /* (*12, * .rate = 26000000, /* fixed up in clock init */ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_FIXED | RATE_PROPAGATES, + .enable = &omap2_enable_osc_ck, + .disable = &omap2_disable_osc_ck, .recalc = &propagate_rate, };
Paul Walmsley
maintainerPATCH 23/28 omap2 clock: use standard clk->enable/disable for APLLs
In reply to Paul WalmsleyNow that we're calling the clock-specific enable & disable code, we can get rid of the special-case code in _omap2_clk_{enable,disable}() for the APLLs.
--- arch/arm/mach-omap2/clock.c | 20 ++++++++------------ arch/arm/mach-omap2/clock.h | 6 ++++++ 2 files changed, 14 insertions(+), 12 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +8 -12
@@ -212,7 +212,7 @@ static int omap2_wait_clock_ready(void _/* Enable an APLL if off */ -static void omap2_clk_fixed_enable (struct clk *clk) +static int omap2_clk_fixed_enable (struct clk *clk) {u32 cval, apll_mask;
@@ -221,7 +221,7 @@ static void omap2_clk_fixed_enable(struc cval =cm_read_mod_reg (PLL_MOD ,CM_CLKEN );if ((cval & apll_mask) == apll_mask) -return ;/* apll already enabled */ +return 0 ;/* apll already enabled */ cval &= ~apll_mask; cval |= apll_mask;
@@ -234,6 +234,12 @@ static void omap2_clk_fixed_enable(strucomap2_wait_clock_ready (OMAP_CM_REGADDR (PLL_MOD ,CM_IDLEST ), cval, clk->name); + +/* +* REVISIT: Should we return an error code if omap2_wait_clock_ready() +* fails? +*/ +return 0 ; }static void omap2_clk_wait_ready (struct clk *clk)
@@ -288,11 +294,6 @@ static int _omap2_clk_enable(struct clkreturn -EINVAL ; } -if (clk->enable_reg ==OMAP_CM_REGADDR (PLL_MOD ,CM_CLKEN )) { -omap2_clk_fixed_enable (clk); -return 0 ; - } - regval32 =cm_read_reg (clk->enable_reg); regval32 |= (1 << clk->enable_bit);cm_write_reg (regval32, clk->enable_reg);
@@ -336,11 +337,6 @@ static void _omap2_clk_disable(struct clreturn ; } -if (clk->enable_reg ==OMAP_CM_REGADDR (PLL_MOD ,CM_CLKEN )) { -omap2_clk_fixed_disable (clk); -return ; - } - regval32 =cm_read_reg (clk->enable_reg); regval32 &= ~(1 << clk->enable_bit);cm_write_reg (regval32, clk->enable_reg);
arch/arm/mach-omap2/clock.h +6 -0
@@ -38,6 +38,8 @@ static u32 omap2_clksel_to_divisor(strucstatic u32 omap2_divisor_to_clksel (struct clk *clk,u32 div);static void omap2_dpll_recalc (struct clk *clk);static void omap2_fixed_divisor_recalc (struct clk *clk); +static int omap2_clk_fixed_enable (struct clk *clk); +static void omap2_clk_fixed_disable (struct clk *clk);static long omap2_clksel_round_rate (struct clk *clk,unsigned long target_rate);static int omap2_clksel_set_rate (struct clk *clk,unsigned long rate);static int omap2_reprogram_dpll (struct clk * clk,unsigned long rate);
@@ -647,6 +649,8 @@ static struct clk apll96_ck = { RATE_FIXED | RATE_PROPAGATES, .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN), .enable_bit = OMAP24XX_EN_96M_PLL_SHIFT, + .enable = &omap2_clk_fixed_enable, + .disable = &omap2_clk_fixed_disable, .recalc = &propagate_rate, };
@@ -658,6 +662,8 @@ static struct clk apll54_ck = { RATE_FIXED | RATE_PROPAGATES, .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN), .enable_bit = OMAP24XX_EN_54M_PLL_SHIFT, + .enable = &omap2_clk_fixed_enable, + .disable = &omap2_clk_fixed_disable, .recalc = &propagate_rate, };
Paul Walmsley
maintainerPATCH 24/28 omap2 clock: replace omap2_get_crystal_rate() with clock-specific recalc code
In reply to Paul WalmsleyThe OMAP2 clock framework currently uses a nonstandard function to assign the osc_ck and sys_ck rates, omap2_get_crystal_rate(). By using custom recalc code for these clocks, we can get rid of it and rely on the existing clock tree recalculation process.
--- arch/arm/mach-omap2/clock.c | 44 ++++++++++++++++++++++++-------------------- arch/arm/mach-omap2/clock.h | 10 +++++----- 2 files changed, 29 insertions(+), 25 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +24 -20
@@ -112,21 +112,6 @@ static void omap2_init_clksel_parent(strreturn ; } -/* Recalculate SYST_CLK */ -static void omap2_sys_clk_recalc (struct clk * clk) -{ -u32 div; - -if (!cpu_is_omap34xx ()) { - div =prm_read_reg (OMAP24XX_PRCM_CLKSRC_CTRL ); -/* Test if ext clk divided by 1 or 2 */ - div &=OMAP_SYSCLKDIV_MASK ; - div >>=OMAP_SYSCLKDIV_SHIFT ; - clk->rate = (clk->parent->rate / div); - } -propagate_rate (clk); -} -static u32 omap2_get_dpll_rate (struct clk * tclk) {long long dpll_clk;
@@ -1044,9 +1029,9 @@ static struct clk_functions omap2_clk_fu .clk_disable_unused = omap2_clk_disable_unused, }; -static void __init omap2_get_crystal_rate (struct clk *osc,struct clk *sys) +static u32 omap2_get_apll_clkin (void ) { -u32 div, aplls, sclk =13000000 ; +u32 aplls, sclk =0 ; aplls =cm_read_mod_reg (PLL_MOD ,CM_CLKSEL1 ); aplls &=OMAP24XX_APLLS_CLKIN_MASK ;
@@ -1059,12 +1044,30 @@ static void __init omap2_get_crystal_ratelse if (aplls ==APLLS_CLKIN_12MHZ ) sclk =12000000 ; +return sclk; +} + +static u32 omap2_get_sysclkdiv (void ) +{ +u32 div; + div =prm_read_reg (OMAP24XX_PRCM_CLKSRC_CTRL ); div &=OMAP_SYSCLKDIV_MASK ; div >>=OMAP_SYSCLKDIV_SHIFT ; - osc->rate = sclk * div; - sys->rate = sclk; +return div; +} + +static void omap2_osc_clk_recalc (struct clk *clk) +{ + clk->rate =omap2_get_apll_clkin () *omap2_get_sysclkdiv (); +propagate_rate (clk); +} + +static void omap2_sys_clk_recalc (struct clk *clk) +{ + clk->rate = clk->parent->rate /omap2_get_sysclkdiv (); +propagate_rate (clk); }/*
@@ -1116,7 +1119,8 @@ int __init omap2_clk_init(void) cpu_mask =RATE_IN_243X ;clk_init (&omap2_clk_functions); -omap2_get_crystal_rate (&osc_ck, &sys_ck); + +omap2_osc_clk_recalc (&osc_ck);for (clkp = onchip_clks; clkp < onchip_clks +ARRAY_SIZE (onchip_clks); clkp++) {
arch/arm/mach-omap2/clock.h +5 -5
@@ -36,6 +36,8 @@ static void omap2_init_clksel_parent(strstatic u32 omap2_clksel_get_divisor (struct clk *clk);static u32 omap2_clksel_to_divisor (struct clk *clk,u32 field_val);static u32 omap2_divisor_to_clksel (struct clk *clk,u32 div); +static void omap2_osc_clk_recalc (struct clk *clk); +static void omap2_sys_clk_recalc (struct clk *clk);static void omap2_dpll_recalc (struct clk *clk);static void omap2_fixed_divisor_recalc (struct clk *clk);static int omap2_clk_fixed_enable (struct clk *clk);
@@ -598,21 +600,19 @@ static struct clk func_32k_ck = {/* Typical 12/13MHz in standalone mode, will be 26Mhz in chassis mode */ static struct clk osc_ck = {/* (*12, *13, 19.2, *26, 38.4)MHz */ .name ="osc_ck" , - .rate =26000000 ,/* fixed up in clock init */ .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | -RATE_FIXED |RATE_PROPAGATES , +RATE_PROPAGATES , .enable = &omap2_enable_osc_ck, .disable = &omap2_disable_osc_ck, - .recalc = &propagate_rate, + .recalc = &omap2_osc_clk_recalc, };/* With out modem likely 12MHz, with modem likely 13MHz */ static struct clk sys_ck = {/* (*12, *13, 19.2, 26, 38.4)MHz */ .name ="sys_ck" ,/* ~ ref_clk also */ .parent = &osc_ck, - .rate =13000000 , .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X | -RATE_FIXED |ALWAYS_ENABLED |RATE_PROPAGATES , +ALWAYS_ENABLED |RATE_PROPAGATES , .recalc = &omap2_sys_clk_recalc, };
Paul Walmsley
maintainerPATCH 25/28 omap2 clock: Standardize DPLL rate recalculation with struct dpll_data
In reply to Paul WalmsleyIntroduce a new data structure, struct dpll_data, that contains DPLL multiplier, divider, and autoidle information. Update existing DPLL code to use struct dpll_data. The goal here is to set up something that will be usable for OMAP3430 clock tree. Note that this does not affect the SRAM DPLL assembly code - the DPLL register addresses are still hard-coded there.
--- arch/arm/mach-omap2/clock.c | 61 ++++++++++++++++++++++++++------------ arch/arm/mach-omap2/clock.h | 10 ++++++ include/asm-arm/arch-omap/clock.h | 9 +++++ 3 files changed, 61 insertions(+), 19 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +42 -19
@@ -112,20 +112,38 @@ static void omap2_init_clksel_parent(strreturn ; } -static u32 omap2_get_dpll_rate (struct clk * tclk) +/* Returns the DPLL rate */ +static u32 omap2_get_dpll_rate (struct clk *clk) +{ +long long dpll_clk; +u32 dpll_mult, dpll_div, dpll; +const struct dpll_data *dd; + + dd = clk->dpll_data; +/* REVISIT: What do we return on error? */ +if (!dd) +return 0 ; + + dpll =cm_read_reg (dd->mult_div1_reg); + dpll_mult = dpll & dd->mult_mask; + dpll_mult >>=convert_mask_to_shift (dd->mult_mask); + dpll_div = dpll & dd->div1_mask; + dpll_div >>=convert_mask_to_shift (dd->div1_mask); + + dpll_clk = (long long )clk->parent->rate * dpll_mult; +do_div (dpll_clk, dpll_div +1 ); + +return dpll_clk; +} + +/* This actually returns the rate of core_ck, not dpll_ck. */ +static u32 omap2_get_dpll_rate_24xx (struct clk *tclk) {long long dpll_clk; -int dpll_mult, dpll_div, amult; -u32 dpll; +u8 amult; - dpll =cm_read_mod_reg (PLL_MOD ,CM_CLKSEL1 ); + dpll_clk =omap2_get_dpll_rate (tclk); - dpll_mult = dpll &OMAP24XX_DPLL_MULT_MASK ; - dpll_mult >>=OMAP24XX_DPLL_MULT_SHIFT ;/* 10 bits */ - dpll_div = dpll &OMAP24XX_DPLL_DIV_MASK ; - dpll_div >>=OMAP24XX_DPLL_DIV_SHIFT ;/* 4 bits */ - dpll_clk = (long long )tclk->parent->rate * dpll_mult; -do_div (dpll_clk, dpll_div +1 ); amult =cm_read_mod_reg (PLL_MOD ,CM_CLKSEL2 ); amult &=OMAP24XX_CORE_CLK_SRC_MASK ; dpll_clk *= amult;
@@ -396,7 +414,7 @@ static u32 omap2_dpll_round_rate(unsignestatic void omap2_dpll_recalc (struct clk *clk) { - clk->rate =omap2_get_dpll_rate (clk); + clk->rate =omap2_get_dpll_rate_24xx (clk);propagate_rate (clk); }
@@ -559,10 +577,11 @@ static int omap2_reprogram_dpll(struct cu32 flags, cur_rate, low, mult, div, valid_rate, done_rate;u32 bypass =0 ;struct prcm_config tmpset; +const struct dpll_data *dd;int ret = -EINVAL ;local_irq_save (flags); - cur_rate =omap2_get_dpll_rate (&dpll_ck); + cur_rate =omap2_get_dpll_rate_24xx (&dpll_ck); mult =cm_read_mod_reg (PLL_MOD ,CM_CLKSEL2 ); mult &=OMAP24XX_CORE_CLK_SRC_MASK ;
@@ -580,9 +599,13 @@ static int omap2_reprogram_dpll(struct celse low = curr_prcm_set->dpll_speed /2 ; - tmpset.cm_clksel1_pll =cm_read_mod_reg (PLL_MOD ,CM_CLKSEL1 ); - tmpset.cm_clksel1_pll &= ~(OMAP24XX_DPLL_MULT_MASK | -OMAP24XX_DPLL_DIV_MASK ); + dd = clk->dpll_data; +if (!dd) + goto dpll_exit; + + tmpset.cm_clksel1_pll =cm_read_reg (dd->mult_div1_reg); + tmpset.cm_clksel1_pll &= ~(dd->mult_mask | + dd->div1_mask); div = ((curr_prcm_set->xtal_speed /1000000 ) -1 ); tmpset.cm_clksel2_pll =cm_read_mod_reg (PLL_MOD ,CM_CLKSEL2 ); tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK ;
@@ -595,8 +618,8 @@ static int omap2_reprogram_dpll(struct c mult = (rate /1000000 ); done_rate =CORE_CLK_SRC_DPLL ; } - tmpset.cm_clksel1_pll |= (div <<OMAP24XX_DPLL_DIV_SHIFT ); - tmpset.cm_clksel1_pll |= (mult <<OMAP24XX_DPLL_MULT_SHIFT ); + tmpset.cm_clksel1_pll |= (div <<convert_mask_to_shift (dd->mult_mask)); + tmpset.cm_clksel1_pll |= (mult <<convert_mask_to_shift (dd->div1_mask));/* Worst case */ tmpset.base_sdrc_rfr =V24XX_SDRC_RFR_CTRL_BYPASS ;
@@ -950,7 +973,7 @@ static int omap2_select_table_rate(struc } curr_prcm_set = prcm; - cur_rate =omap2_get_dpll_rate (&dpll_ck); + cur_rate =omap2_get_dpll_rate_24xx (&dpll_ck);if (prcm->dpll_speed == cur_rate /2 ) {omap2_reprogram_sdrc (CORE_CLK_SRC_DPLL ,1 );
@@ -1137,7 +1160,7 @@ int __init omap2_clk_init(void) }/* Check the MPU rate set by bootloader */ - clkrate =omap2_get_dpll_rate (&dpll_ck); + clkrate =omap2_get_dpll_rate_24xx (&dpll_ck);for (prcm = rate_table; prcm->mpu_speed; prcm++) {if (!(prcm->flags & cpu_mask))continue ;
arch/arm/mach-omap2/clock.h +10 -0
@@ -632,9 +632,19 @@ static struct clk alt_ck = { /* Typical/* REVISIT: Rate changes on dpll_ck trigger a full set change. ... * deal with this */ + +static const struct dpll_data dpll_dd = { + .mult_div1_reg =OMAP_CM_REGADDR (PLL_MOD ,CM_CLKSEL1 ), + .mult_mask =OMAP24XX_DPLL_MULT_MASK , + .div1_mask =OMAP24XX_DPLL_DIV_MASK , + .auto_idle_mask =OMAP24XX_AUTO_DPLL_MASK , + .auto_idle_val =0x3 ,/* stop DPLL upon idle */ +}; +static struct clk dpll_ck = { .name ="dpll_ck" , .parent = &sys_ck,/* Can be func_32k also */ + .dpll_data = &dpll_dd, .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X |RATE_PROPAGATES |ALWAYS_ENABLED , .recalc = &omap2_dpll_recalc,
include/asm-arm/arch-omap/clock.h +9 -0
@@ -29,6 +29,14 @@ struct clksel {const struct clksel_rate *rates; }; +struct dpll_data { +void __iomem *mult_div1_reg; +u32 mult_mask; +u32 div1_mask; +u32 auto_idle_mask; +u8 auto_idle_val; +}; +#endif struct clk {
@@ -53,6 +61,7 @@ struct clk {void __iomem *clksel_reg;u32 clksel_mask;const struct clksel *clksel; +const struct dpll_data *dpll_data;#else __u8 rate_offset;__u8 src_offset;
Paul Walmsley
maintainerPATCH 27/28 omap2 clock: add three missing clocks: gpmc_fck, sdma_{i, f}ck
In reply to Paul WalmsleyAdd three missing clocks: gpmc_fck, sdma_ick, and sdma_fck. This is in preparation for struct clk-based autoidling, added in the next patch.
--- arch/arm/mach-omap2/clock.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
Index: linux-omap/arch/arm/mach-omap2/clock.h
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
arch/arm/mach-omap2/clock.h +24 -0
@@ -2277,6 +2277,27 @@ static struct clk i2chs1_fck = { .recalc = &followparent_recalc, }; +static struct clk gpmc_fck = { + .name ="gpmc_fck" , + .parent = &core_l3_ck, + .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X , + .recalc = &followparent_recalc, +}; + +static struct clk sdma_fck = { + .name ="sdma_fck" , + .parent = &core_l3_ck, + .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X , + .recalc = &followparent_recalc, +}; + +static struct clk sdma_ick = { + .name ="sdma_ick" , + .parent = &l4_ck, + .flags =CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X , + .recalc = &followparent_recalc, +}; +static struct clk vlynq_ick = { .name ="vlynq_ick" , .parent = &core_l3_ck,
@@ -2633,6 +2654,9 @@ static struct clk *onchip_clks[] __initd &i2c2_ick, &i2c2_fck, &i2chs2_fck, + &gpmc_fck, + &sdma_fck, + &sdma_ick, &vlynq_ick, &vlynq_fck, &sdrc_ick,
Paul Walmsley
maintainerPATCH 28/28 omap2 clock: handle (almost) all clock autoidling via the clock framework
In reply to Paul WalmsleyExisting OMAP2 code autoidles clocks via pm.c. OMAP clock framework already has some support for enabling autoidle mode via the allow_idle function; however, this is currently unused. Take advantage of this support by adding autoidle register and bit information for each clock, defining an omap2_clk_allow_idle() function, and adding a framework-wide function, clk_allow_idle_all(), to autoidle all clocks, intended to be called on init. Remove all but the APLL/DPLL autoidle bit twiddling from pm.c -- we don't yet have generalized support for APLL autoidle. Handling autoidle via the clock framework ensures that we only touch clocks that are currently configured.
--- arch/arm/mach-omap2/clock.c | 34 +++++++++++ arch/arm/mach-omap2/clock.h | 103 ++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/cm_regbits_24xx.h | 50 ++++++++++++++++ arch/arm/mach-omap2/pm.c | 63 +------------------- arch/arm/plat-omap/clock.c | 9 ++ include/asm-arm/arch-omap/clock.h | 3 6 files changed, 204 insertions(+), 58 deletions(-)
Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
arch/arm/mach-omap2/clock.c +34 -0
@@ -165,6 +165,7 @@ static void omap2_fixed_divisor_recalc(spropagate_rate (clk); } +/* REVISIT: This is really autoidle control, not enable/disable */ static int omap2_enable_osc_ck (struct clk *clk) {u32 pcc;
@@ -177,6 +178,7 @@ static int omap2_enable_osc_ck(struct clreturn 0 ; } +/* REVISIT: This is really autoidle control, not enable/disable */ static void omap2_disable_osc_ck (struct clk *clk) {u32 pcc;
@@ -1023,6 +1025,34 @@ static int omap2_select_table_rate(strucreturn 0 ; } +static void omap2_clk_allow_idle (struct clk *clk) +{ +u32 regval; +u8 shift; +const struct dpll_data *dd; + +if (clk->auto_idle_reg) { + regval =cm_read_reg (clk->auto_idle_reg); + +if (clk->dpll_data) { +/* Special handling for DPLLs */ + + dd = clk->dpll_data; +if (!dd->auto_idle_mask || !dd->auto_idle_val) +return ; + + shift =convert_mask_to_shift (dd->auto_idle_mask); + regval &= dd->auto_idle_mask; + regval |= dd->auto_idle_val << shift; + + }else if (clk->auto_idle_bit) { + regval |= (1 << clk->auto_idle_bit); + } + +cm_write_reg (regval, clk->auto_idle_reg); + } +} +/*------------------------------------------------------------------------- * Omap2 clock reset and init functions *-------------------------------------------------------------------------*/
@@ -1049,6 +1079,7 @@ static struct clk_functions omap2_clk_fu .clk_round_rate = omap2_clk_round_rate, .clk_set_rate = omap2_clk_set_rate, .clk_set_parent = omap2_clk_set_parent, + .clk_allow_idle = omap2_clk_allow_idle, .clk_disable_unused = omap2_clk_disable_unused, };
@@ -1184,6 +1215,9 @@ int __init omap2_clk_init(void)*/ clk_enable_init_clocks (); +/* Autoidle all clocks that can be autoidled */ +clk_allow_idle_all (); +/* Avoid sleeping sleeping during omap2_clk_prepare_for_reboot() */ vclk =clk_get (NULL ,"virt_prcm_set" ); sclk =clk_get (NULL ,"sys_ck" );
arch/arm/mach-omap2/clock.h +103 -0
415 lines not on this page · raw message
include/asm-arm/arch-omap/clock.h +3 -0
@@ -62,6 +62,8 @@ struct clk {u32 clksel_mask;const struct clksel *clksel;const struct dpll_data *dpll_data; +void __iomem *auto_idle_reg; +u8 auto_idle_bit;#else __u8 rate_offset;__u8 src_offset;
@@ -92,6 +94,7 @@ extern void clk_allow_idle(struct clk *cextern void clk_deny_idle (struct clk *clk);extern int clk_get_usecount (struct clk *clk);extern void clk_enable_init_clocks (void ); +extern void clk_allow_idle_all (void );/* Clock flags */ #define RATE_CKCTL (1 << 0)/* Main fixed ratio clocks */
arch/arm/mach-omap2/pm.c +5 -58
74 lines not on this page · raw message
arch/arm/plat-omap/clock.c +9 -0
@@ -383,6 +383,15 @@ void clk_allow_idle(struct clk *clk) }EXPORT_SYMBOL (clk_allow_idle); +void clk_allow_idle_all (void ) +{ +struct clk *clkp; + +list_for_each_entry (clkp, &clocks, node) +clk_allow_idle (clkp); +} +EXPORT_SYMBOL (clk_allow_idle_all); +void clk_enable_init_clocks (void ) {struct clk *clkp;
arch/arm/mach-omap2/cm_regbits_24xx.h +50 -0
111 lines not on this page · raw message
RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework
Hi Paul,
Quoted 8 lines
Existing OMAP2 code autoidles clocks via
pm.c. OMAP clock framework already has some support for enabling autoidle mode via theallow_idlefunction; however, this is currently unused. Take advantage of this support by adding autoidle register and bit information for each clock, defining anomap2_clk_allow_idle()function, and adding a framework-wide function,clk_allow_idle_all(), to autoidle all clocks, intended to be called on init. Remove all but the APLL/DPLL autoidle bit twiddling frompm.c-- we don't yet have generalized support for
APLL
Quoted 1 line
autoidle. Handling autoidle via the clock framework ensures that we
only
Quoted 1 line
touch clocks that are currently configured.
I thought about doing this back when OMAP1 added this when I was more active on OMAP2. However, I dropped it as it didn't have enough 'bang' in this form. I think these registers (even in OMAP1) are widely mis-understood. This is partially a TRM issue and one of complexity.
Meaning you can set this register on a per-clock basis however they do nothing for run time except at L3/L4 domain change time. In the OMAP-GIT code this means at retention time the PRCM has permission to shut off your ICLK assuming your module acknowledges it. If the PM code does this manually (enable/disable) then this register has no effect.
It does have a useful run time property in that it is one form to gate a clock stop state assuming you have not forced it. This is one way to stop a cascade clock stop from happening when you are not expecting it. It would be a lighter weight way then the mutex which OMAP2-GIT code uses. However, for that to work other code would have to change.
Each IP-Module _does_ have an AUTOIDLE bit in its SYSCONIG space which does act as you might expect this bit to. Setting this AUTOIDLE does save significant power. It would be more useful to control that one from here.
If you hook up a current meter you can toggle all the CM_AUTOIDLES you like and nothing will happen. But if you do the same with the module autoidle you will see a bit change.
Regards,
Richard W.
Paul Walmsley
maintainerRE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework
Hi Richard,
Quoted 9 lines · Richard
I thought about doing this back when OMAP1 added this when I was more active on OMAP2. However, I dropped it as it didn't have enough 'bang' in this form. I think these registers (even in OMAP1) are widely mis-understood. This is partially a TRM issue and one of complexity.
Meaning you can set this register on a per-clock basis however they do nothing for run time except at L3/L4 domain change time. In the OMAP-GIT code this means at retention time the PRCM has permission to shut off your ICLK assuming your module acknowledges it.
I see. Thanks for the explanation. So in practical terms, it seems best to just enable this for all clocks unconditionally, as before in pm.c, no?
Quoted 2 lines
If the PM code
does this manually (enable/disable) then this register has no effect.
So, if the clock's enable/disable bit in its ICLKEN register is touched in any way, the clock auto-idle bit is ignored? Does that hidden state persist until reset?
Quoted 5 lines
It does have a useful run time property in that it is one form to gate a clock stop state assuming you have not forced it. This is one way to stop a cascade clock stop from happening when you are not expecting it. It would be a lighter weight way then the mutex which OMAP2-GIT code uses. However, for that to work other code would have to change.
But that would only happen when going to retention or off, correct?
Quoted 4 lines
Each IP-Module _does_ have an AUTOIDLE bit in its SYSCONIG space which does act as you might expect this bit to. Setting this AUTOIDLE does save significant power. It would be more useful to control that one from here.
Those cover potentially large numbers of clocks... So in lieu of a more general power domain API, is there a reason not to set all of those bits unconditionally in pm.c?
- Paul
RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework
Hi Paul,
Quoted 7 lines · Richard
Quoted 6 lines
I thought about doing this back when OMAP1 added this when I was more active on OMAP2. However, I dropped it as it didn't have enough 'bang' in this form. I think these registers (even in OMAP1) are widely mis-understood. This is partially a TRM issue and one of complexity.
Quoted 7 lines
Quoted 4 lines
Meaning you can set this register on a per-clock basis however they do nothing for run time except at L3/L4 domain change time. In the OMAP-GIT code this means at retention time the PRCM has permission to shut off your ICLK assuming your module acknowledges it.
I see. Thanks for the explanation. So in practical terms, it seems best to just enable this for all clocks unconditionally, as before in
pm.c, no?
Probably so... Given the current surrounding implementation it is not so effective and will result in many drivers adding some calls which are just noise. Hollow code...
I think even in OMAP1 a similar condition exists, it's been a long while since I looked. But its clock manager bits also allowed auto control during only full domain changes to its couple of sleep modes. One can consider an OMAP1 as only have a single big domain where and OMAP2 as several and an OMAP3 has many. Some ideas and techniques have been carried forward.
Like I was indicating for OMAP2/3 if the PRCM auto idle was switched with the module auto-idle it would not be noise it would be substantive.
-- One issue here is the address range for this bit is with each driver in the _generic_ IP OCP (open core protocol bus interface) wrapper header. To write to this you need i+f clock on. It still helps to set this bit even if the module is off as the clock tree can still be active and dissipating some power in the module. -- This is what the patch I sent out a while back was about (RFC/PATCH) to just enable all of these. It did save a lot of power.
-- A PRCM library can provide these access functions
-- It can be in lined in ever driver
-- Or the clock frame work can provide an interface for it.
** As its generic and symmetric for every IP in the OCP wrapper I personally like to stick it all in one spot inside of adding a bunch of defines to every driver.
** Recently we internally were debating a bit about if an API was needed as you really in some cases do need to set the CLOCKACTIVITY bits in the OCP wrapper depending on the drivers mode of activity.
Quoted 6 lines
Quoted 2 lines
If the PM code
does this manually (enable/disable) then this register has no effect.So, if the clock's enable/disable bit in its ICLKEN register is touched in any way, the clock auto-idle bit is ignored? Does that hidden state persist until reset?
No, not the way I read your question.
When ICLKEN is enabled and the PRCM-auto-idle is enabled hardware can manage that clock at domain change time assuming the peripheral handshakes it ok (force/no/smart).
If the ICLKEN is disabled the setting of PRCM-auto-idle has no effect.
Quoted 7 lines
Quoted 5 lines
It does have a useful run time property in that it is one form to gate a clock stop state assuming you have not forced it. This is one way to stop a cascade clock stop from happening when you are not expecting it. It would be a lighter weight way then the mutex which OMAP2-GIT code uses. However, for that to work other code would have to change.
But that would only happen when going to retention or off, correct?
Given the current OMAP-GIT code this is correct.
However this is a bit more to it than that. These clocks can be auto-handled during clock domain stop mode. The power domains have the properties of On/Retention/Off while the clock domains have properties of On/Inactive.
The i-clocks controlled by prcm-autoidle can be hardware managed (shut down) when the L3 and L4 clock domains go inactive. The power domains can be in any state at this time. As it likely turns out in the GIT code today, the L3/L4 clock domain and the core power domain effectively state change at the same time.
One of the big target states for big power savings is this so called 'partially' active state. In this case you do want the clock domains and the power domains states to not be in sync. The L3/L4 can be stopped, but say an F-Clock to a McBSP can still be running pushing data out to a codec. If programmed up correctly, the codec need for data can automatically signal the prcm to re-activate the L3/L4 then allow the new data to flow. This is the 10mA vs. 200mA kind of thing I was describing (you do need to clear the wake up status for it to happen again). When you hit 'retention' or OFF your currents are in the 50-100uA range, but there is absolutely no activity.
Quoted 8 lines
Quoted 4 lines
Each IP-Module _does_ have an AUTOIDLE bit in its SYSCONIG space which does act as you might expect this bit to. Setting this AUTOIDLE does save significant power. It would be more useful to control that one from here.
Those cover potentially large numbers of clocks... So in lieu of a more general power domain API, is there a reason not to set all of those bits unconditionally in
pm.c?
In the general case for this bit it turns out that you can set it at init time. Some bug work around might require some access.
However, other bits in the same range CLOCKACTIVTY do have a bit more need of dynamic access. WE enable also might be conditionally set. Also the handshakes sometimes take different settings (smart/force/no-idle/standby) for some bug work arounds (software or hardware). A force idle might clear some internal status in say a HSMMC which a driver didn't fully clear out.
Regards,
Richard W.
Paul Walmsley
maintainerRE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework
Hi Richard,
Quoted 1 line · Richard
Like I was indicating for OMAP2/3 if the PRCM auto idle was switched with the module auto-idle it would not be noise it would be substantive.
It sounds like one doesn't even need to switch these bits, once we turn them on, correct? Just enable *_SYSCONFIG autoidle and ICLK autoidle at boot in pm.c, and then never disable them, with no ill effects. Some extra latency perhaps? Drivers that need to toggle them to work around some hardware bug can just do that themselves, for the time being...
Quoted 2 lines
-- One issue here is the address range for this bit is with each
driver in the _generic_ IP OCP (open core protocol bus interface) wrapper header. To write to this you need i+f clock on. It still helps to set this bit even if the module is off as the clock tree can still be active and dissipating some power in the module.
You're talking about the *_SYSCONFIG autoidle bits here, right? So to set those properly we'd need to walk the clock tree, enabling module clocks and setting the *_SYSCONFIG autoidle bit, then powering the module clocks back down again?
Quoted 2 lines
-- This is what the patch I sent out a while back was about
(RFC/PATCH) to just enable all of these. It did save a lot of power.
I just took another look at that patch. The only downside is latency, right? Are you thinking about updating the patch for the new PRCM access code? That would make it much easier to test...
Quoted 2 lines
** As its generic and symmetric for every IP in the OCP wrapper I
personally like to stick it all in one spot inside of adding a bunch of defines to every driver.
Since all of those registers are in SCM space, perhaps an scm.h/scm.c file might be useful here. I've been running into this with CONTROL_DEVCONF* on 3430 code. I don't think the *_SYSCONFIG powersave bits fit well into the clock framework, so we should probably place it outside the clocks. I do think it would make sense to specifically encode the power domain that each clock resides in into the struct clk, for use by PM or SCM code.
Quoted 2 lines
** Recently we internally were debating a bit about if an API was
needed as you really in some cases do need to set the CLOCKACTIVITY bits in the OCP wrapper depending on the drivers mode of activity.
I've been looking at these CLOCKACTIVITY bits and am not clear on the intended use. They are read-only in many modules, at least according to the TRM. There is a notation about "Clock activity during wakeup mode period" -- could you elaborate about what that means?
Quoted 3 lines
When ICLKEN is enabled and the PRCM-auto-idle is enabled hardware can manage that clock at domain change time assuming the peripheral handshakes it ok (force/no/smart).
If the ICLKEN is disabled the setting of PRCM-auto-idle has no effect.
Okay, makes sense.
Quoted 1 line
One of the big target states for big power savings is this so called 'partially' active state. In this case you do want the clock domains and the power domains states to not be in sync. The L3/L4 can be stopped, but say an F-Clock to a McBSP can still be running pushing data out to a codec. If programmed up correctly, the codec need for data can automatically signal the prcm to re-activate the L3/L4 then allow the new data to flow.
This is via the WKDEP/SLEEPDEP registers, correct? or is this via another mechanism?
Quoted 1 line
However, other bits in the same range CLOCKACTIVTY do have a bit more need of dynamic access. WE enable also might be conditionally set.
Sorry, you lost me there - what is WE enable?
Thanks for all of the detailed information, Richard,
- Paul
RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework
Hi Paul,
Quoted 1 line
From: [email protected] [mailto:[email protected]] On
Behalf
Quoted 2 lines
Quoted 2 lines
Like I was indicating for OMAP2/3 if the PRCM auto idle was switched with the module auto-idle it would not be noise it would be
substantive.
Quoted 2 lines
It sounds like one doesn't even need to switch these bits, once we
turn
Quoted 1 line
them on, correct? Just enable
*_SYSCONFIGautoidle and ICLK autoidle
at
Quoted 2 lines
boot in
pm.c, and then never disable them, with no ill effects. Some extra latency perhaps? Drivers that need to toggle them to work
around
Quoted 1 line
some hardware bug can just do that themselves, for the time being...
Yes.
There are some nuances which could be talked about but probably not needed at this point.
Quoted 3 lines
Quoted 3 lines
-- One issue here is the address range for this bit is with each
driver in the _generic_ IP OCP (open core protocol bus interface) wrapper header. To write to this you need i+f clock on. It still
helps
Quoted 1 line
Quoted 1 line
to set this bit even if the module is off as the clock tree can
still be
Quoted 3 lines
Quoted 1 line
active and dissipating some power in the module.
You're talking about the
*_SYSCONFIGautoidle bits here, right? So to
set
Quoted 1 line
those properly we'd need to walk the clock tree, enabling module
clocks
Quoted 1 line
and setting the
*_SYSCONFIGautoidle bit, then powering the module
clocks
Quoted 1 line
back down again?
Yes.
Quoted 2 lines
Quoted 2 lines
-- This is what the patch I sent out a while back was about
(RFC/PATCH) to just enable all of these. It did save a lot of
power.
Quoted 3 lines
I just took another look at that patch. The only downside is latency, right? Are you thinking about updating the patch for the new PRCM
access
Quoted 1 line
code? That would make it much easier to test...
At this level the latency should be very minimal compared to the active power savings. At the module level it should be on the order of a few clocks. With many of these clocks in the MHz range its some nano seconds.
The danger is in cascade latency if all modules are set this way and the upper members of the tree have their auto controls set. The big latencies are not at the modules (except for some in OFF mode).
Actually the patch as I sent it was completely self contained it was done that way just to be fast :) Changing it to use the macros is no problem. I'd probably shy away from using the clock frame work to turn on and off each clock via name string though. They would result way too much code.
Quoted 1 line
Quoted 1 line
** As its generic and symmetric for every IP in the OCP wrapper
I
Quoted 1 line
Quoted 1 line
personally like to stick it all in one spot inside of adding a bunch
of
Quoted 3 lines
Quoted 1 line
defines to every driver.
Since all of those registers are in SCM space, perhaps an
scm.h/scm.c
file
Quoted 1 line
might be useful here. I've been running into this with
CONTROL_DEVCONF*
Quoted 1 line
on 3430 code. I don't think the
*_SYSCONFIGpowersave bits fit well
into
Quoted 1 line
the clock framework, so we should probably place it outside the
clocks.
Quoted 2 lines
I do think it would make sense to specifically encode the power domain that each clock resides in into the struct clk, for use by PM or SCM
code.
The OCP registers are in each modules address space. An example of what I was talking about is GTP1.TIOCP_CFG:0x48318010.
The SCM (system control module) is something else. It has bearing for power in setting the right state for pins in sleep and io ring wake up. I don't think they belong in the clock frame work either. Though the prcm many need to make api calls to it.
Quoted 1 line
Quoted 1 line
** Recently we internally were debating a bit about if an API
was
Quoted 1 line
Quoted 1 line
needed as you really in some cases do need to set the CLOCKACTIVITY
bits
Quoted 4 lines
Quoted 1 line
in the OCP wrapper depending on the drivers mode of activity.
I've been looking at these CLOCKACTIVITY bits and am not clear on the intended use. They are read-only in many modules, at least according
to
Quoted 2 lines
the TRM. There is a notation about "Clock activity during wakeup mode period" -- could you elaborate about what that means?
Well some aspects of this are a little fuzzy to me also. However, I know generally how they are to be used in practice.
I think of them as how the internal clocks of the module will be handled at idle-ack time (like when the L3/L4{interconnect} clock domains go idle, i.e. this auto ICLK handling time stuff which was being talked about).
Internally in the module at these times the module can choose to handle its clocks in different ways. If you don't need 'partial' activity (meaning functional clock working while iclock is cut) you set it up to allow gating of both I and F clocks. If you want partial activity you make sure the F clock isn't module-internal modified.
One example is say a timer. If I target a low power idle mode I can get the interconnects to go to clock stop (Iclocks off to CORE say) but I can set the activity on the gp-timer such that it keeps ticking -and- can even say generate a wake up (from clock stop) interrupt which brings the L3/L4 out of clock stop. On say a 2430 this will have a system at say average of 2mA but still be ticking at a HZ=100 rate from a core domain clock. This is compared to say a 60mA idle when not hitting clock stop. I can telnet into a system and it is still responsive but has really very low power. This is distinct from system wide retention who's currents might be in the 100uA range but nothing is functional. Only a 'wakeup' domain interrupt will start you chip going again. Make sure not to mix up 'chip' retention (all domains) with just say MPU-retention which is more or less independent of the CORE.
If during this idle time I don't' care about a particular modules I and F clocks I can set the clockactivity bits to allow internal gating of both I and F clocks. The F-clock tree won't stop as some other module might need it, but my module can gate it saving power.
On OMAP3 if you are using software control methods you may need to set these in a particular way to ensure data has cleared before shutting down the module. I don't expect control at this granularity makes sense for our typical usage, but if you are doing full hardware dependency for idling it is relevant.
Quoted 1 line
Quoted 1 line
When ICLKEN is enabled and the PRCM-auto-idle is enabled hardware
can
Quoted 4 lines
Quoted 4 lines
manage that clock at domain change time assuming the peripheral handshakes it ok (force/no/smart).
If the ICLKEN is disabled the setting of PRCM-auto-idle has no
effect.
Quoted 5 lines
Okay, makes sense.
Quoted 2 lines
One of the big target states for big power savings is this so called 'partially' active state. In this case you do want the clock
domains
Quoted 2 lines
Quoted 2 lines
and the power domains states to not be in sync. The L3/L4 can be stopped, but say an F-Clock to a McBSP can still be running pushing
data
Quoted 1 line
Quoted 1 line
out to a codec. If programmed up correctly, the codec need for data
can
Quoted 1 line
Quoted 1 line
automatically signal the prcm to re-activate the L3/L4 then allow
the
Quoted 3 lines
Quoted 1 line
new data to flow.
This is via the WKDEP/SLEEPDEP registers, correct? or is this via
another
Quoted 1 line
mechanism?
No. These registers are more targeted at reducing latency when OFF mode is used. They allow early power up of domains. These are useful when coming from inactive states not active or partially active ones.
One fun fact here is you can say set up a WKDEP such that the MPU is powered on when something happens on say the DSP (MPU used to be in retention). However, if you don't have an interrupt routed to the MPU, it will still be stuck in clock domain stop and just now be drawing more power in ON state. Some time later the OS timer fires and the MPU can wake do its thing and then re-WFI back to retention. The power draw due to the mis-programming of the WKDEP caused extra consumption even though the ARM wasn't doing work. Now, if the ARM was in OFF mode, this early power up could have saved some time.
Quoted 1 line
Quoted 1 line
However, other bits in the same range CLOCKACTIVTY do have a bit
more
Quoted 3 lines
Quoted 1 line
need of dynamic access. WE enable also might be conditionally set.
Sorry, you lost me there - what is WE enable?
I was talking about XYZ_SYSCONFIG.ENWAWAKEUP bit in OCP header.
Quoted 1 line
Thanks for all of the detailed information, Richard,
Happy to, especially if it translates to better functionality.
Regards,
Richard W.
Paul Walmsley
maintainerRE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework
Hello Richard,
Quoted 3 lines · Richard
Actually the patch as I sent it was completely self contained it was done that way just to be fast :) Changing it to use the macros is no problem.
Cool.
Quoted 1 line
I'd probably shy away from using the clock frame work to turn on and off each clock via name string though. They would result way too much code.
Yeah, in the autoidle patch I added a clk_allow_idle_all() function that just walked down the clock list and called ->allow_idle() on each clock that had one. This avoided the search by name string. Nevertheless, I think I will set that patch aside for now, it's not critical; maybe we'll take another look at it after the 3430 clock code shows up.
Quoted 2 lines
The OCP registers are in each modules address space. An example of what I was talking about is GTP1.TIOCP_CFG:0x48318010.
Indeed, my mistake; not sure what register I was looking at when I wrote the earlier post.
Quoted 5 lines
On OMAP3 if you are using software control methods you may need to set these in a particular way to ensure data has cleared before shutting down the module. I don't expect control at this granularity makes sense for our typical usage, but if you are doing full hardware dependency for idling it is relevant.
Is this only if we set *_SYSCONFIG.AUTOIDLE to force-idle?
- Paul
RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework
Quoted 6 lines
Quoted 2 lines
The OCP registers are in each modules address space. An example of what I was talking about is GTP1.TIOCP_CFG:0x48318010.
Indeed, my mistake; not sure what register I was looking at when I wrote the earlier post.
Quoted 7 lines
Quoted 5 lines
On OMAP3 if you are using software control methods you may need to set these in a particular way to ensure data has cleared before shutting down the module. I don't expect control at this granularity makes sense for our typical usage, but if you are doing full hardware dependency for idling it is relevant.
Is this only if we set *_SYSCONFIG.AUTOIDLE to force-idle?
Yes that is the bit I was talking about in this case.
Regards,
Richard W.
RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidlingviathe clock framework
In reply to Woodruff, Richard-----Original Message-----
Quoted 1 line
Subject: RE: [PATCH 28/28] omap2 clock: handle (almost) all clock
autoidlingviathe clock framework
Quoted 5 lines
Hi Paul,
Quoted 2 lines
Existing OMAP2 code autoidles clocks via
pm.c. OMAP clock framework already has some support for enabling autoidle mode via the
allow_idle
Quoted 4 lines
Quoted 4 lines
function; however, this is currently unused. Take advantage of this support by adding autoidle register and bit information for each clock, defining an
omap2_clk_allow_idle()function, and adding a framework-wide function,clk_allow_idle_all(), to autoidle all
clocks,
Quoted 1 line
Quoted 1 line
intended to be called on init. Remove all but the APLL/DPLL
autoidle
Quoted 8 lines
Quoted 1 line
bit twiddling from
pm.c-- we don't yet have generalized support forAPLL
Quoted 1 line
autoidle. Handling autoidle via the clock framework ensures that we
only
Quoted 1 line
touch clocks that are currently configured.
I thought about doing this back when OMAP1 added this when I was more active on OMAP2. However, I dropped it as it didn't have enough
'bang'
Quoted 2 lines
in this form. I think these registers (even in OMAP1) are widely mis-understood. This is partially a TRM issue and one of complexity.
One minor detail to note is that on OMAP2 the sleep code sometimes has to disable the autoidle feature on certain clocks. Not doing so would prevent desired functionality. This - at least the action of setting the autoidle state - of course could be handled via the clock framework. However, it was deemed to be unnecessary extra layer, as the sleep code already has to be very aware of the hardware its running on and any abstraction is useless. I think at least timers and DMA have some special restrictions in pm.c. Thus the original design of PM code handling the autoidle bits.
Tuukka
----------------------------------------------------------------
Please note: This e-mail may contain confidential information intended solely for the addressee. If you have received this e-mail in error, please do not disclose it to anyone, notify the sender promptly, and delete the message from your system. Thank you.
Paul Walmsley
maintainerRE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidlingviathe clock framework
Quoted 9 lines · On Thu, 23 Aug 2007, [email protected] wrote:
One minor detail to note is that on OMAP2 the sleep code sometimes has to disable the autoidle feature on certain clocks. Not doing so would prevent desired functionality. This - at least the action of setting the autoidle state - of course could be handled via the clock framework. However, it was deemed to be unnecessary extra layer, as the sleep code already has to be very aware of the hardware its running on and any abstraction is useless. I think at least timers and DMA have some special restrictions in
pm.c. Thus the original design of PM code handling the autoidle bits.
Hi Tuukka,
I took a quick look at pm.c, it configures ICLK autoidling for SDMA and GPT*, and sleep.S doesn't look like it touches the autoidle regs. Could you point me at the code you're talking about?
thanks,
- Paul
RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidlingviathe clock framework
From: [email protected] [mailto:[email protected]] On Behalf Of Paul Walmsley
Quoted 4 lines · On Thu, 23 Aug 2007, [email protected] wrote:
Quoted 2 lines
One minor detail to note is that on OMAP2 the sleep code sometimes
has
Quoted 1 line
Quoted 1 line
to disable the autoidle feature on certain clocks. Not doing so
would
Quoted 1 line
Quoted 1 line
prevent desired functionality. This - at least the action of setting
the
Quoted 2 lines
Quoted 2 lines
autoidle state - of course could be handled via the clock framework. However, it was deemed to be unnecessary extra layer, as the sleep
code
Quoted 8 lines
Quoted 4 lines
already has to be very aware of the hardware its running on and any abstraction is useless. I think at least timers and DMA have some special restrictions in
pm.c. Thus the original design of PM code handling the autoidle bits.Hi Tuukka,
I took a quick look at
pm.c, it configures ICLK autoidling for SDMA
and
Quoted 1 line
GPT*, and
sleep.Sdoesn't look like it touches the autoidle regs.
Could
Quoted 1 line
you point me at the code you're talking about?
Sorry for the false alarm, guys. The code I was thinking about lives in OMAP1 tree. The clock framework updates variable called arm_idlect1_mask. That value is programmed after some masking into hardware in omap_pm_idle when entering sleep state. Essentially what we have there is a mask of clocks that may not be autoidled during that particular idle call.
The OMAP2 tree seems to handle its special cases in another way by skipping the sleep completely.
Tuukka
----------------------------------------------------------------
Please note: This e-mail may contain confidential information intended solely for the addressee. If you have received this e-mail in error, please do not disclose it to anyone, notify the sender promptly, and delete the message from your system. Thank you.
RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework
In reply to Paul WalmsleyOne further note is in the 'ideal' model you should never have to control your I-CLK at all just your F-CLK. I'm sure our hardware people would be very pleased if the code moved in that direction (me too if it turned out to all work). They generally dislike the idea of the clock frame work as they feel it allows duplication of work the hardware can do if setup properly. Its APIs open up some choices which can nullify or reduce understanding of hardware capabilities. For OMAP1 there was no other way. For OMAP2/3 there are some options. I do very much like the frame work but do understand their points.
Ideally, you set all idles at all levels and all async interrupt wake and use the PRCM interrupt to clear status at wake up time, then the system can handle all clocks based on dependency. Iclocks can be managed automatically. Fclocks should be dynamically controlled by drivers on a demand basis. This means some activity timers. When this does work the savings are really massive and dramatic. The catch in it is that one dependency break from a bad driver (sw or hw) at any of the multiple levels will stop it from working. Looking at that way rather than OMAP1 compatibility results in something which looks a bit different.
Regards,
Richard W.
Quoted 4 lines
Hi Paul,
Quoted 2 lines
Existing OMAP2 code autoidles clocks via
pm.c. OMAP clock framework already has some support for enabling autoidle mode via the
allow_idle
Quoted 4 lines
Quoted 4 lines
function; however, this is currently unused. Take advantage of this support by adding autoidle register and bit information for each clock, defining an
omap2_clk_allow_idle()function, and adding a framework-wide function,clk_allow_idle_all(), to autoidle all
clocks,
Quoted 1 line
Quoted 1 line
intended to be called on init. Remove all but the APLL/DPLL
autoidle
Quoted 8 lines
Quoted 1 line
bit twiddling from
pm.c-- we don't yet have generalized support forAPLL
Quoted 1 line
autoidle. Handling autoidle via the clock framework ensures that we
only
Quoted 1 line
touch clocks that are currently configured.
I thought about doing this back when OMAP1 added this when I was more active on OMAP2. However, I dropped it as it didn't have enough
'bang' in
Quoted 5 lines
this form. I think these registers (even in OMAP1) are widely mis- understood. This is partially a TRM issue and one of complexity.
Meaning you can set this register on a per-clock basis however they do nothing for run time except at L3/L4 domain change time. In the
OMAP-GIT
Quoted 1 line
code this means at retention time the PRCM has permission to shut off
your
Quoted 4 lines
ICLK assuming your module acknowledges it. If the PM code does this manually (enable/disable) then this register has no effect.
It does have a useful run time property in that it is one form to gate
a
Quoted 1 line
clock stop state assuming you have not forced it. This is one way to
stop
Quoted 2 lines
a cascade clock stop from happening when you are not expecting it. It would be a lighter weight way then the mutex which OMAP2-GIT code
uses.
Quoted 4 lines
However, for that to work other code would have to change.
Each IP-Module _does_ have an AUTOIDLE bit in its SYSCONIG space which does act as you might expect this bit to. Setting this AUTOIDLE does
save
Quoted 1 line
significant power. It would be more useful to control that one from
here.
Quoted 7 lines
If you hook up a current meter you can toggle all the
CM_AUTOIDLESyou like and nothing will happen. But if you do the same with the module autoidle you will see a bit change.Regards,
Richard W.
RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework
Quoted 10 lines · Richard
One further note is in the 'ideal' model you should never have to control your I-CLK at all just your F-CLK. I'm sure our hardware people would be very pleased if the code moved in that direction (me too if it turned out to all work). They generally dislike the idea of the clock frame work as they feel it allows duplication of work the hardware can do if setup properly. Its APIs open up some choices which can nullify or reduce understanding of hardware capabilities. For OMAP1 there was no other way. For OMAP2/3 there are some options. I do very much like the frame work but do understand their points.
Quoted 5 lines
Ideally, you set all idles at all levels and all async interrupt wake and use the PRCM interrupt to clear status at wake up time, then the system can handle all clocks based on dependency. Iclocks can be managed automatically. Fclocks should be dynamically controlled by drivers on a demand basis. This means some activity timers.
I'm not new to these concepts, however I find extremely hard to accept the idea of using timers, since they assume to know what the duration of the activity will be.
Could that work on an internet tablet?
For the tablet there is not really a set of use-cases like on a phone, where you can have a closed set of fapplications and do some serious profiling.
Quoted 4 lines
When this
does work the savings are really massive and dramatic. The catch in it is that one dependency break from a bad driver (sw or hw) at any of the multiple levels will stop it from working.
And how easy is it to trace that? All the refcounting seems to be done in HW ...
Signature · 4 lines
Cheers, Igor Igor Stoppa <[email protected]> (Nokia Multimedia - CP - OSSO / Helsinki, Finland)
RE: [PATCH 28/28] omap2 clock: handle (almost) all clockautoidling viathe clock framework
Quoted 4 lines
From: Igor Stoppa [mailto:[email protected]]
Quoted 2 lines · Richard
One further note is in the 'ideal' model you should never have to control your I-CLK at all just your F-CLK. I'm sure our hardware
people
Quoted 1 line
Quoted 1 line
would be very pleased if the code moved in that direction (me too if
it
Quoted 1 line
Quoted 1 line
turned out to all work). They generally dislike the idea of the
clock
Quoted 1 line
Quoted 1 line
frame work as they feel it allows duplication of work the hardware
can
Quoted 1 line
Quoted 1 line
do if setup properly. Its APIs open up some choices which can
nullify
Quoted 1 line
Quoted 1 line
or reduce understanding of hardware capabilities. For OMAP1 there
was no
Quoted 1 line
Quoted 1 line
other way. For OMAP2/3 there are some options. I do very much like
the
Quoted 3 lines
Quoted 3 lines
frame work but do understand their points.
Ideally, you set all idles at all levels and all async interrupt
wake
Quoted 7 lines
Quoted 4 lines
and use the PRCM interrupt to clear status at wake up time, then the system can handle all clocks based on dependency. Iclocks can be managed automatically. Fclocks should be dynamically controlled by drivers on a demand basis. This means some activity timers.
I'm not new to these concepts, however I find extremely hard to accept the idea of using timers, since they assume to know what the duration
of
Quoted 1 line
the activity will be.
Activity timers on your FCLKS. Many of the Fclks can be tied to input activity and screen blanking. The rest of the clocks are set to driver activity. For some drivers like MMC this isn't so bad as you talk to the device. The main issue with these is making the clock usage well behaved.
The last set of drivers like UART (or Irda) are a bit more tricky as you much make sure the protocol can send a 'wakeup' packet. If the peripheral and its firmware work to spec and all code is right there is a chance. There are just a lot of details. Many of them can sort out such that it can work.
Quoted 1 line
Could that work on an internet tablet?
You can still optimized for some big usecases which you know about. Screen blanking type things. MP3 is a favorite one to talk about. Other things can only be as good as they can be.
One catch in some of these like low power refresh is you much recognize when you are there and adjust some parameters (like FIFO). Once you do this you are at really good power. This kind of activity timer is ok. What is needed is some notion of cost around some of these optimizations. Latency API and some extension can help make the choice for the few major cases it matters at.
Quoted 3 lines
For the tablet there is not really a set of use-cases like on a phone, where you can have a closed set of fapplications and do some serious profiling.
You can't compete with a closed system for sure in optimizations. But because you can't be a 200uA all the time doesn't mean you should settle for 200mA when you could be a 10mA.
Applying such control in fast moving open source is another level of challenge.
Quoted 2 lines
Quoted 2 lines
When this
does work the savings are really massive and dramatic. The catch in
it
Quoted 1 line
Quoted 1 line
is that one dependency break from a bad driver (sw or hw) at any of
the
Quoted 4 lines
Quoted 1 line
multiple levels will stop it from working.
And how easy is it to trace that? All the refcounting seems to be done in HW ...
Not so easy. This was one of the arguments of using a lower layer below the clock frame work. You can catch traces going in and out and send them off to simulation.
Hitting the states has been prototyped and proven on HLOS's so it can happen. It is not just a completely static validation level test.
Regards,
Richard W.