Skip to content

Commit

Permalink
[ARM] OMAP3 clock: optimize DPLL rate rounding algorithm
Browse files Browse the repository at this point in the history
The previous DPLL rate rounding algorithm counted the divider (N) down
from the maximum to 1.  Since we currently use a broad DPLL rate
tolerance, and lower N values are more power-efficient, we can often
bypass several iterations through the loop by counting N upwards from
1.

Peter de Schrijver <peter.de-schrijver@nokia.com> put up with several
test cycles of this patch - thanks Peter.

linux-omap source commit is 6f6d82bb2f80fa20a841ac3e95a6f44a5a156188.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Peter de Schrijver <peter.de-schrijver@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Paul Walmsley authored and Russell King committed Feb 8, 2009
1 parent b324504 commit 85a5f78
Showing 1 changed file with 18 additions and 17 deletions.
35 changes: 18 additions & 17 deletions arch/arm/mach-omap2/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
#define DPLL_MIN_DIVIDER 1

/* Possible error results from _dpll_test_mult */
#define DPLL_MULT_UNDERFLOW (1 << 0)
#define DPLL_MULT_UNDERFLOW -1

/*
* Scale factor to mitigate roundoff errors in DPLL rate rounding.
Expand Down Expand Up @@ -826,7 +826,7 @@ static int _dpll_test_mult(int *m, int n, unsigned long *new_rate,
unsigned long target_rate,
unsigned long parent_rate)
{
int flags = 0, carry = 0;
int r = 0, carry = 0;

/* Unscale m and round if necessary */
if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL)
Expand All @@ -847,13 +847,13 @@ static int _dpll_test_mult(int *m, int n, unsigned long *new_rate,
if (*m < DPLL_MIN_MULTIPLIER) {
*m = DPLL_MIN_MULTIPLIER;
*new_rate = 0;
flags = DPLL_MULT_UNDERFLOW;
r = DPLL_MULT_UNDERFLOW;
}

if (*new_rate == 0)
*new_rate = _dpll_compute_new_rate(parent_rate, *m, n);

return flags;
return r;
}

/**
Expand Down Expand Up @@ -892,21 +892,27 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)

dd->last_rounded_rate = 0;

for (n = dd->max_divider; n >= DPLL_MIN_DIVIDER; n--) {
for (n = DPLL_MIN_DIVIDER; n <= dd->max_divider; n++) {

/* Compute the scaled DPLL multiplier, based on the divider */
m = scaled_rt_rp * n;

/*
* Since we're counting n down, a m overflow means we can
* can immediately skip to the next n
* Since we're counting n up, a m overflow means we
* can bail out completely (since as n increases in
* the next iteration, there's no way that m can
* increase beyond the current m)
*/
if (m > scaled_max_m)
continue;
break;

r = _dpll_test_mult(&m, n, &new_rate, target_rate,
clk->parent->rate);

/* m can't be set low enough for this n - try with a larger n */
if (r == DPLL_MULT_UNDERFLOW)
continue;

e = target_rate - new_rate;
pr_debug("clock: n = %d: m = %d: rate error is %d "
"(new_rate = %ld)\n", n, m, e, new_rate);
Expand All @@ -918,16 +924,11 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
min_e_n = n;

pr_debug("clock: found new least error %d\n", min_e);
}

/*
* Since we're counting n down, a m underflow means we
* can bail out completely (since as n decreases in
* the next iteration, there's no way that m can
* increase beyond the current m)
*/
if (r & DPLL_MULT_UNDERFLOW)
break;
/* We found good settings -- bail out now */
if (min_e <= clk->dpll_data->rate_tolerance)
break;
}
}

if (min_e < 0) {
Expand Down

0 comments on commit 85a5f78

Please sign in to comment.