From patchwork Wed Nov 23 04:56:51 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Long X-Patchwork-Id: 5286 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 5A0BD24017 for ; Wed, 23 Nov 2011 04:56:57 +0000 (UTC) Received: from mail-fx0-f52.google.com (mail-fx0-f52.google.com [209.85.161.52]) by fiordland.canonical.com (Postfix) with ESMTP id 2A2A4A181A6 for ; Wed, 23 Nov 2011 04:56:57 +0000 (UTC) Received: by faaa26 with SMTP id a26so1703880faa.11 for ; Tue, 22 Nov 2011 20:56:57 -0800 (PST) Received: by 10.152.144.136 with SMTP id sm8mr13634465lab.33.1322024216545; Tue, 22 Nov 2011 20:56:56 -0800 (PST) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.152.41.198 with SMTP id h6cs213517lal; Tue, 22 Nov 2011 20:56:56 -0800 (PST) Received: by 10.52.36.41 with SMTP id n9mr23698260vdj.41.1322024213687; Tue, 22 Nov 2011 20:56:53 -0800 (PST) Received: from mail-vw0-f50.google.com (mail-vw0-f50.google.com [209.85.212.50]) by mx.google.com with ESMTPS id hg5si5526235vdb.126.2011.11.22.20.56.53 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 22 Nov 2011 20:56:53 -0800 (PST) Received-SPF: neutral (google.com: 209.85.212.50 is neither permitted nor denied by best guess record for domain of dave.long@linaro.org) client-ip=209.85.212.50; Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.50 is neither permitted nor denied by best guess record for domain of dave.long@linaro.org) smtp.mail=dave.long@linaro.org Received: by vbbfd1 with SMTP id fd1so1195788vbb.37 for ; Tue, 22 Nov 2011 20:56:53 -0800 (PST) Received: by 10.52.97.136 with SMTP id ea8mr24279787vdb.16.1322024212837; Tue, 22 Nov 2011 20:56:52 -0800 (PST) Received: from [192.168.1.101] (pool-71-181-37-31.cncdnh.fast.myfairpoint.net. [71.181.37.31]) by mx.google.com with ESMTPS id z6sm22017931vdg.18.2011.11.22.20.56.51 (version=SSLv3 cipher=OTHER); Tue, 22 Nov 2011 20:56:52 -0800 (PST) Subject: [PATCH] Improve DPLL frequency rounding code From: David Long To: andy.green@linaro.org Cc: patches@linaro.org Date: Tue, 22 Nov 2011 23:56:51 -0500 Message-ID: <1322024211.1796.24.camel@dave-Dell-System-XPS-L502X> Mime-Version: 1.0 X-Mailer: Evolution 2.32.2 Maintain a list of successful frequency translations for any given DPLL. Speed up frequency calculations by searching the list first. Do a more exhaustive search for the best possible DPLL paramters for a new frequency. If an exact fit is not found, return the best possible match within jitter constraints. Change the worst case match criteria from +/-1MHZ to +/-0.01% (on the 4460 350MHz will be off by 0.003%). Signed-off-by: David A. Long --- arch/arm/mach-omap2/clkt_dpll.c | 75 ++++++++++++++++++++++++++----- arch/arm/plat-omap/include/plat/clock.h | 25 +++++++++- 2 files changed, 86 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c index f95c2ef..e23cdf8 100644 --- a/arch/arm/mach-omap2/clkt_dpll.c +++ b/arch/arm/mach-omap2/clkt_dpll.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -276,12 +278,28 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) unsigned long scaled_rt_rp; unsigned long new_rate = 0; struct dpll_data *dd; + unsigned long bestrate = 0, diff, bestdiff = ULONG_MAX; + int bestm = 0, bestn = 0; + struct list_head *lp; + struct dpll_rate_list *rs; if (!clk || !clk->dpll_data) return ~0; dd = clk->dpll_data; + /* It is assumed locking is handled by the caller */ + if (dd->rate_cache_len > 0) + list_for_each(lp, &dd->rate_cache) { + rs = container_of(lp, struct dpll_rate_list, list); + if (rs->target_rate == target_rate) { + dd->last_rounded_m = rs->m; + dd->last_rounded_n = rs->n; + dd->last_rounded_rate = rs->actual_rate; + return rs->actual_rate; + } + } + pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n", clk->name, target_rate); @@ -318,19 +336,52 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) if (r == DPLL_MULT_UNDERFLOW) continue; -// pr_err(" clock: target=%ld %s: m = %d: n = %d: new_rate = %ld\n", -// target_rate, clk->name, m, n, new_rate); - - if (target_rate == new_rate || - ((target_rate - new_rate) > 0 && (target_rate - new_rate) < 1000000) - ) { - dd->last_rounded_m = m; - dd->last_rounded_n = n; - dd->last_rounded_rate = target_rate; - break; +#ifdef DEBUG + pr_err("clock: target=%ld %s: m = %d: n = %d: new_rate = %ld\n", + target_rate, clk->name, m, n, new_rate); +#endif + + if (target_rate > new_rate) + diff = target_rate - new_rate; + else + diff = new_rate - target_rate; + if (diff < bestdiff) { + bestm = m; + bestn = n; + bestrate = new_rate; + bestdiff = diff; } + if (new_rate == target_rate) + break; } - - return new_rate; + /* + * The following if verifies that the new frequency is within 0.01% of + * the target frequency. + */ + if (bestdiff < (ULONG_MAX/10000) && + ((bestdiff*10000)/target_rate) < 1) { + dd->last_rounded_m = bestm; + dd->last_rounded_n = bestn; + dd->last_rounded_rate = bestrate; + + if (dd->rate_cache_len >= DPLL_MAX_RATE_CACHE) + return bestrate; + /* + * Add new rate to the cache + */ + rs = kzalloc(sizeof(struct dpll_rate_list), GFP_ATOMIC); + if (rs) { + rs->m = bestm; + rs->n = bestn; + rs->target_rate = target_rate; + rs->actual_rate = bestrate; + if (dd->rate_cache_len == 0) + INIT_LIST_HEAD(&dd->rate_cache); + list_add(&rs->list, &dd->rate_cache); + dd->rate_cache_len++; + } + return bestrate; + } else + return 0; } diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h index 6e724d5..2278230 100644 --- a/arch/arm/plat-omap/include/plat/clock.h +++ b/arch/arm/plat-omap/include/plat/clock.h @@ -104,6 +104,23 @@ struct clksel { }; /** + * struct dpll_rate_list - optional list of frequency translations + * @m: dpll multiplier value + * @n: dpll divisor value + * @target_rate: desired clock frequency + * @actual_frequency: rate caluclated from best multiplier/divisor combination + */ +struct dpll_rate_list { + struct list_head list; + int m; + int n; + unsigned long target_rate; + unsigned long actual_rate; +}; + +#define DPLL_MAX_RATE_CACHE 10 + +/** * struct dpll_data - DPLL registers and integration data * @mult_div1_reg: register containing the DPLL M and N bitfields * @mult_mask: mask of the DPLL M bitfield in @mult_div1_reg @@ -160,6 +177,8 @@ struct dpll_data { #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) void __iomem *autoidle_reg; void __iomem *idlest_reg; + struct list_head rate_cache; + int rate_cache_len; u32 autoidle_mask; u32 freqsel_mask; u32 idlest_mask; @@ -285,8 +304,10 @@ struct clk_functions { void (*clk_deny_idle)(struct clk *clk); void (*clk_disable_unused)(struct clk *clk); #ifdef CONFIG_CPU_FREQ - void (*clk_init_cpufreq_table)(struct cpufreq_frequency_table **); - void (*clk_exit_cpufreq_table)(struct cpufreq_frequency_table **); + void (*clk_init_cpufreq_table) + (struct cpufreq_frequency_table **); + void (*clk_exit_cpufreq_table) + (struct cpufreq_frequency_table **); #endif };