From patchwork Wed Nov 23 05:36:34 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Long X-Patchwork-Id: 5287 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 0267523E08 for ; Wed, 23 Nov 2011 05:36:41 +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 D8A14A1819B for ; Wed, 23 Nov 2011 05:36:40 +0000 (UTC) Received: by faaa26 with SMTP id a26so1732255faa.11 for ; Tue, 22 Nov 2011 21:36:40 -0800 (PST) Received: by 10.152.144.136 with SMTP id sm8mr13684941lab.33.1322026600601; Tue, 22 Nov 2011 21:36:40 -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 h6cs214690lal; Tue, 22 Nov 2011 21:36:40 -0800 (PST) Received: by 10.52.99.74 with SMTP id eo10mr6006015vdb.12.1322026597634; Tue, 22 Nov 2011 21:36:37 -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 z15si3233137vcv.4.2011.11.22.21.36.36 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 22 Nov 2011 21:36:37 -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 fd1so1213797vbb.37 for ; Tue, 22 Nov 2011 21:36:36 -0800 (PST) Received: by 10.52.35.70 with SMTP id f6mr23453193vdj.84.1322026596744; Tue, 22 Nov 2011 21:36:36 -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 k4sm22184541vdu.2.2011.11.22.21.36.35 (version=SSLv3 cipher=OTHER); Tue, 22 Nov 2011 21:36:35 -0800 (PST) Subject: [PATCH v2] Improve DPLL frequency rounding code From: David Long To: andy.green@linaro.org Cc: patches@linaro.org Date: Wed, 23 Nov 2011 00:36:34 -0500 Message-ID: <1322026594.1796.27.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 | 73 ++++++++++++++++++++++++++----- arch/arm/plat-omap/include/plat/clock.h | 25 ++++++++++- 2 files changed, 84 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c index f95c2ef..57e0cb1 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,50 @@ 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; + pr_debug("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) + 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 };