From ae9a25bb9fb0e59d0a5d83e13fe71d03627a7925 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 2 Aug 2007 12:10:22 -0600 Subject: [PATCH] omap2 clock: add fixed divisor clock code The rates of some clocks are equal to their parents' rates, divided by some fixed integer. This contrasts with the existing 'followparent' clocks, which follow their parents' rates strictly; and the existing 'clksel' clocks, which follow their parents' rates divided by a runtime-selectable divisor. Add code to implement these clocks without resorting to specifying a fixed rate. Signed-off-by: Paul Walmsley Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clock.c | 79 +++++++++++++++++-------------- arch/arm/mach-omap2/clock.h | 11 +++-- include/asm-arm/arch-omap/clock.h | 3 ++ 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 0df6bb790b3..5f9a0331e4a 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -134,6 +134,20 @@ static void omap2_followparent_recalc(struct clk *clk) followparent_recalc(clk); } +/* + * Used for clocks that have the same value as the parent clock, + * divided by some factor + */ +static void omap2_fixed_divisor_recalc(struct clk *clk) +{ + WARN_ON(!clk->fixed_div); + + clk->rate = clk->parent->rate / clk->fixed_div; + + if (clk->flags & RATE_PROPAGATES) + propagate_rate(clk); +} + static void omap2_propagate_rate(struct clk * clk) { if (!(clk->flags & RATE_FIXED)) @@ -400,39 +414,27 @@ static void omap2_dpll_recalc(struct clk *clk) */ static void omap2_clksel_recalc(struct clk * clk) { - u32 fixed = 0, div = 0; - u32 clksel1_core; - - if (clk == &iva1_mpu_int_ifck) { - div = 2; - fixed = 1; - } + u32 clksel1_core, div = 0; clksel1_core = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1); if ((clk == &dss1_fck) && (clksel1_core & OMAP24XX_CLKSEL_DSS1_MASK) == 0) { - clk->rate = sys_ck.rate; - return; + div = 1; } if ((clk == &vlynq_fck) && cpu_is_omap2420() && (clksel1_core & OMAP2420_CLKSEL_VLYNQ_MASK) == CLKSEL_VLYNQ_96MHZ) { - clk->rate = func_96m_ck.rate; - return; + div = 1; } - if (!fixed) { - div = omap2_clksel_get_divisor(clk); - if (div == 0) - return; - } + div = omap2_clksel_get_divisor(clk); + if (div == 0) + return; - if (div != 0) { - if (unlikely(clk->rate == clk->parent->rate / div)) - return; - clk->rate = clk->parent->rate / div; - } + if (unlikely(clk->rate == clk->parent->rate / div)) + return; + clk->rate = clk->parent->rate / div; if (unlikely(clk->flags & RATE_PROPAGATES)) propagate_rate(clk); @@ -832,12 +834,13 @@ static int omap2_clk_set_rate(struct clk *clk, unsigned long rate) /* Converts encoded control register address into a full address */ static u32 omap2_clksel_get_src_field(void __iomem **src_addr, struct clk *src_clk, u32 *field_mask, - struct clk *clk) + struct clk *clk, u32 *parent_div) { u32 val = ~0, mask = 0; void __iomem *src_reg_addr = 0; u32 reg_offset; + *parent_div = 0; reg_offset = clk->src_offset; /* Find target control register.*/ @@ -854,21 +857,25 @@ static u32 omap2_clksel_get_src_field(void __iomem **src_addr, WARN_ON(1); /* unknown src_clk */ } else if (reg_offset == OMAP24XX_CLKSEL_DSS1_SHIFT) { mask = OMAP24XX_CLKSEL_DSS1_MASK; - if (src_clk == &sys_ck) + if (src_clk == &sys_ck) { val = CLKSEL_DSS1_SYSCLK; - else if (src_clk == &core_ck) /* divided clock */ - val = CLKSEL_DSS1_CORECLK_16; /* rate needs fixing */ - else + } 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) + if (src_clk == &func_96m_ck) { val = CLKSEL_VLYNQ_96MHZ; - else if (src_clk == &core_ck) + } else if (src_clk == &core_ck) { val = CLKSEL_VLYNQ_CORECLK_16; - else + *parent_div = 16; + } else { WARN_ON(1); /* unknown src_clk */ + } } else { WARN_ON(1); /* unknown reg_offset */ } @@ -974,7 +981,7 @@ static u32 omap2_clksel_get_src_field(void __iomem **src_addr, static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) { void __iomem *src_addr; - u32 field_val, field_mask, reg_val; + u32 field_val, field_mask, reg_val, parent_div; if (unlikely(clk->flags & CONFIG_PARTICIPANT)) return -EINVAL; @@ -983,7 +990,7 @@ static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) return -EINVAL; field_val = omap2_clksel_get_src_field(&src_addr, new_parent, - &field_mask, clk); + &field_mask, clk, &parent_div); if (src_addr == 0) return -EINVAL; @@ -1001,17 +1008,17 @@ static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) OMAP24XX_PRCM_CLKCFG_CTRL); wmb(); } + if (clk->usecount > 0) _omap2_clk_enable(clk); clk->parent = new_parent; /* SRC_RATE_SEL_MASK clocks follow their parents rates.*/ - if ((new_parent == &core_ck) && - (clk == &dss1_fck || clk == &vlynq_fck)) - clk->rate = new_parent->rate / 0x10; - else - clk->rate = new_parent->rate; + clk->rate = new_parent->rate; + + if (parent_div > 0) + clk->rate /= parent_div; if (unlikely(clk->flags & RATE_PROPAGATES)) propagate_rate(clk); diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 5991aba12d4..f4cd6a72df6 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -34,6 +34,7 @@ static void omap2_sys_clk_recalc(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); +static void omap2_fixed_divisor_recalc(struct clk *clk); #define RATE_IN_242X (1 << 0) #define RATE_IN_243X (1 << 1) @@ -704,11 +705,10 @@ static struct clk func_48m_ck = { static struct clk func_12m_ck = { .name = "func_12m_ck", .parent = &func_48m_ck, - .rate = 12000000, + .fixed_div = 4, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | - RATE_FIXED | RATE_PROPAGATES | - PARENT_CONTROLS_CLOCK, - .recalc = &omap2_propagate_rate, + RATE_PROPAGATES | PARENT_CONTROLS_CLOCK, + .recalc = &omap2_fixed_divisor_recalc, }; /* Secure timer, only available in secure mode */ @@ -848,7 +848,8 @@ static struct clk iva1_mpu_int_ifck = { .flags = CLOCK_IN_OMAP242X, .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP24XX_CM_FCLKEN), .enable_bit = OMAP2420_EN_IVA_MPU_SHIFT, - .recalc = &omap2_clksel_recalc, + .fixed_div = 2, + .recalc = &omap2_fixed_divisor_recalc, }; /* diff --git a/include/asm-arm/arch-omap/clock.h b/include/asm-arm/arch-omap/clock.h index d90649a1660..c81f0d0f4a3 100644 --- a/include/asm-arm/arch-omap/clock.h +++ b/include/asm-arm/arch-omap/clock.h @@ -34,6 +34,9 @@ struct clk { void (*init)(struct clk *); int (*enable)(struct clk *); void (*disable)(struct clk *); +#if defined(CONFIG_ARCH_OMAP2420) + u8 fixed_div; +#endif }; struct clk_functions { -- 2.41.1