From 88b8ba90570067178d32c654ad95786041e86e86 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 3 Jul 2008 12:24:46 +0300 Subject: ARM: OMAP2: Clock: New OMAP2/3 DPLL rate rounding algorithm This patch adds a new rate rounding algorithm for DPLL clocks on the OMAP2/3 architecture. For a desired DPLL target rate, there may be several multiplier/divider (M, N) values which will generate a sufficiently close rate. Lower N values result in greater power economy. However, lower N values can cause the difference between the rounded rate and the target rate ("rate error") to be larger than it would be with a higher N. This can cause downstream devices to run more slowly than they otherwise would. This DPLL rate rounding algorithm: - attempts to find the lowest possible N (DPLL divider) to reach the target_rate (since, according to Richard Woodruff , lower N values save more power than higher N values). - allows developers to set an upper bound on the error between the rounded rate and the desired target rate ("rate tolerance"), so an appropriate balance between rate fidelity and power savings can be set. This maximum rate error tolerance is set via omap2_set_dpll_rate_tolerance(). - never returns a rounded rate higher than the target rate. The rate rounding algorithm caches the last rounded M, N, and rate computation to avoid rounding the rate twice for each clk_set_rate() call. (This patch does not yet implement set_rate for DPLLs; that follows in a future patch.) The algorithm trades execution speed for rate accuracy. It will find the (M, N) set that results in the least rate error, within a specified rate tolerance. It does this by evaluating each divider setting - on OMAP3, this involves 128 steps. Another approach to DPLL rate rounding would be to bail out as soon as a valid rate is found within the rate tolerance, which would trade rate accuracy for execution speed. Alternate implementations welcome. This code is not yet used by the OMAP24XX DPLL clock, since it is currently defined as a composite clock, fusing the DPLL M,N and the M2 output divider. This patch also renames the existing OMAP24xx DPLL programming functions to highlight that they program both the DPLL and the DPLL's output multiplier. Signed-off-by: Paul Walmsley Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clock34xx.h | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) (limited to 'arch/arm/mach-omap2/clock34xx.h') diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h index e349d48ee80..05757eb032b 100644 --- a/arch/arm/mach-omap2/clock34xx.h +++ b/arch/arm/mach-omap2/clock34xx.h @@ -35,6 +35,10 @@ static u32 omap3_dpll_autoidle_read(struct clk *clk); static int omap3_noncore_dpll_enable(struct clk *clk); static void omap3_noncore_dpll_disable(struct clk *clk); +/* Maximum DPLL multiplier, divider values for OMAP3 */ +#define OMAP3_MAX_DPLL_MULT 2048 +#define OMAP3_MAX_DPLL_DIV 128 + /* * DPLL1 supplies clock to the MPU. * DPLL2 supplies clock to the IVA2. @@ -255,7 +259,7 @@ static const struct clksel_rate div16_dpll_rates[] = { /* DPLL1 */ /* MPU clock source */ /* Type: DPLL */ -static const struct dpll_data dpll1_dd = { +static struct dpll_data dpll1_dd = { .mult_div1_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL), .mult_mask = OMAP3430_MPU_DPLL_MULT_MASK, .div1_mask = OMAP3430_MPU_DPLL_DIV_MASK, @@ -269,6 +273,9 @@ static const struct dpll_data dpll1_dd = { .autoidle_mask = OMAP3430_AUTO_MPU_DPLL_MASK, .idlest_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL), .idlest_bit = OMAP3430_ST_MPU_CLK_SHIFT, + .max_multiplier = OMAP3_MAX_DPLL_MULT, + .max_divider = OMAP3_MAX_DPLL_DIV, + .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE }; static struct clk dpll1_ck = { @@ -276,6 +283,7 @@ static struct clk dpll1_ck = { .parent = &sys_ck, .dpll_data = &dpll1_dd, .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED, + .round_rate = &omap2_dpll_round_rate, .recalc = &omap3_dpll_recalc, }; @@ -317,7 +325,7 @@ static struct clk dpll1_x2m2_ck = { /* IVA2 clock source */ /* Type: DPLL */ -static const struct dpll_data dpll2_dd = { +static struct dpll_data dpll2_dd = { .mult_div1_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSEL1_PLL), .mult_mask = OMAP3430_IVA2_DPLL_MULT_MASK, .div1_mask = OMAP3430_IVA2_DPLL_DIV_MASK, @@ -331,7 +339,10 @@ static const struct dpll_data dpll2_dd = { .autoidle_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_AUTOIDLE_PLL), .autoidle_mask = OMAP3430_AUTO_IVA2_DPLL_MASK, .idlest_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_IDLEST_PLL), - .idlest_bit = OMAP3430_ST_IVA2_CLK_SHIFT + .idlest_bit = OMAP3430_ST_IVA2_CLK_SHIFT, + .max_multiplier = OMAP3_MAX_DPLL_MULT, + .max_divider = OMAP3_MAX_DPLL_DIV, + .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE }; static struct clk dpll2_ck = { @@ -341,6 +352,7 @@ static struct clk dpll2_ck = { .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES, .enable = &omap3_noncore_dpll_enable, .disable = &omap3_noncore_dpll_disable, + .round_rate = &omap2_dpll_round_rate, .recalc = &omap3_dpll_recalc, }; @@ -371,7 +383,7 @@ static struct clk dpll2_m2_ck = { * Source clock for all interfaces and for some device fclks * REVISIT: Also supports fast relock bypass - not included below */ -static const struct dpll_data dpll3_dd = { +static struct dpll_data dpll3_dd = { .mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), .mult_mask = OMAP3430_CORE_DPLL_MULT_MASK, .div1_mask = OMAP3430_CORE_DPLL_DIV_MASK, @@ -382,6 +394,9 @@ static const struct dpll_data dpll3_dd = { .recal_st_bit = OMAP3430_CORE_DPLL_ST_SHIFT, .autoidle_reg = OMAP_CM_REGADDR(PLL_MOD, CM_AUTOIDLE), .autoidle_mask = OMAP3430_AUTO_CORE_DPLL_MASK, + .max_multiplier = OMAP3_MAX_DPLL_MULT, + .max_divider = OMAP3_MAX_DPLL_DIV, + .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE }; static struct clk dpll3_ck = { @@ -389,6 +404,7 @@ static struct clk dpll3_ck = { .parent = &sys_ck, .dpll_data = &dpll3_dd, .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED, + .round_rate = &omap2_dpll_round_rate, .recalc = &omap3_dpll_recalc, }; @@ -545,7 +561,7 @@ static struct clk emu_core_alwon_ck = { /* DPLL4 */ /* Supplies 96MHz, 54Mhz TV DAC, DSS fclk, CAM sensor clock, emul trace clk */ /* Type: DPLL */ -static const struct dpll_data dpll4_dd = { +static struct dpll_data dpll4_dd = { .mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL2), .mult_mask = OMAP3430_PERIPH_DPLL_MULT_MASK, .div1_mask = OMAP3430_PERIPH_DPLL_DIV_MASK, @@ -559,6 +575,9 @@ static const struct dpll_data dpll4_dd = { .autoidle_mask = OMAP3430_AUTO_PERIPH_DPLL_MASK, .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), .idlest_bit = OMAP3430_ST_PERIPH_CLK_SHIFT, + .max_multiplier = OMAP3_MAX_DPLL_MULT, + .max_divider = OMAP3_MAX_DPLL_DIV, + .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE }; static struct clk dpll4_ck = { @@ -568,6 +587,7 @@ static struct clk dpll4_ck = { .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES, .enable = &omap3_noncore_dpll_enable, .disable = &omap3_noncore_dpll_disable, + .round_rate = &omap2_dpll_round_rate, .recalc = &omap3_dpll_recalc, }; @@ -843,7 +863,7 @@ static struct clk emu_per_alwon_ck = { /* Supplies 120MHz clock, USIM source clock */ /* Type: DPLL */ /* 3430ES2 only */ -static const struct dpll_data dpll5_dd = { +static struct dpll_data dpll5_dd = { .mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKSEL4), .mult_mask = OMAP3430ES2_PERIPH2_DPLL_MULT_MASK, .div1_mask = OMAP3430ES2_PERIPH2_DPLL_DIV_MASK, @@ -857,6 +877,9 @@ static const struct dpll_data dpll5_dd = { .autoidle_mask = OMAP3430ES2_AUTO_PERIPH2_DPLL_MASK, .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST2), .idlest_bit = OMAP3430ES2_ST_PERIPH2_CLK_SHIFT, + .max_multiplier = OMAP3_MAX_DPLL_MULT, + .max_divider = OMAP3_MAX_DPLL_DIV, + .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE }; static struct clk dpll5_ck = { @@ -866,6 +889,7 @@ static struct clk dpll5_ck = { .flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES, .enable = &omap3_noncore_dpll_enable, .disable = &omap3_noncore_dpll_disable, + .round_rate = &omap2_dpll_round_rate, .recalc = &omap3_dpll_recalc, }; -- cgit v1.2.3-70-g09d2