From patchwork Tue May 24 20:07:52 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roman Volkov X-Patchwork-Id: 9134241 X-Patchwork-Delegate: sboyd@codeaurora.org Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id DCE826075E for ; Tue, 24 May 2016 20:12:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D2D98281F9 for ; Tue, 24 May 2016 20:12:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C7C19282A0; Tue, 24 May 2016 20:12:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6C3C3281F9 for ; Tue, 24 May 2016 20:12:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932904AbcEXUMi (ORCPT ); Tue, 24 May 2016 16:12:38 -0400 Received: from fallback4.mail.ru ([94.100.181.169]:40770 "EHLO fallback4.mail.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932629AbcEXUMh (ORCPT ); Tue, 24 May 2016 16:12:37 -0400 Received: from smtp22.mail.ru (smtp22.mail.ru [94.100.181.177]) by fallback4.mail.ru (mPOP.Fallback_MX) with ESMTP id CE9001C8FDF4; Tue, 24 May 2016 23:12:33 +0300 (MSK) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mail.ru; s=mail2; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=e3eLoYy11BD2BV29bLKNBczF2su9WY1ttQMVl3Doq3g=; b=mrUJeS59OvHve/+cy1boEntj/1R5LjOhDoQ/KI9UkMVRpXmRg+49eihqmdLoDvVgqjugieFghfP7/TvFTHCtUu/E56/BotpcJabQJkRQKCBVQdMnY6lwA9omweNvVgoeqLOS9OmYT1hfqAmr9q/YtQeGnb8NH28WszUou/KEnTc=; Received: from [176.213.0.43] (port=57620 helo=v1ron-s7.localdomain) by smtp22.mail.ru with esmtpa (envelope-from ) id 1b5Igm-0001At-0O; Tue, 24 May 2016 23:12:29 +0300 From: Roman Volkov To: Arnd Bergmann Cc: linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org, Stephen Boyd , Michael Turquette , Roman Volkov , Tony Prisk Subject: [PATCH 1/2] clk/vt8500: Rework wm8650_find_pll_bits() Date: Tue, 24 May 2016 23:07:52 +0300 Message-Id: <1464120473-1808-2-git-send-email-v1ron@mail.ru> X-Mailer: git-send-email 2.8.0 In-Reply-To: <1464120473-1808-1-git-send-email-v1ron@mail.ru> References: <1464120473-1808-1-git-send-email-v1ron@mail.ru> X-Mras: OK Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Roman Volkov WM8650 has the following limitation in the clock architecture: 600MHz >= (M * parent) / P >= 300MHz Where M is multiplier and P is divisor 1 (refer to the source code comment). This information can be found in the WMT's GPL source. The algorithm from this change is optimized, performance increase is about 10000 times per the user-mode testing application. The following GCC warnings are fixed inside the function: 'best_div2', 'best_div1', 'best_mul' may be used uninitialized in this function [-Wmaybe-uninitialized] Fixes: 090341b0a95d ("clk: vt8500: fix sign of possible PLL values") Signed-off-by: Roman Volkov --- drivers/clk/clk-vt8500.c | 77 +++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c index b0f76a84f1e9..77650f19a9b6 100644 --- a/drivers/clk/clk-vt8500.c +++ b/drivers/clk/clk-vt8500.c @@ -383,52 +383,49 @@ static int vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate, return 0; } -static int wm8650_find_pll_bits(unsigned long rate, unsigned long parent_rate, - u32 *multiplier, u32 *divisor1, u32 *divisor2) +/* + * M * parent [O1] => / P [O2] => / D [O3] + * Where O1 is 900MHz...3GHz; + * O2 is 600MHz >= (M * parent) / P >= 300MHz; + * M is 36...120 [25MHz parent]; D is 1 or 2 or 4 or 8. + * Possible ranges (O3): + * D = 8: 37,5MHz...75MHz + * D = 4: 75MHz...150MHz + * D = 2: 150MHz...300MHz + * D = 1: 300MHz...600MHz + */ +static int wm8650_find_pll_bits(unsigned long rate, + unsigned long parent_rate, u32 *multiplier, u32 *divisor1, + u32 *divisor2) { - u32 mul, div1; - int div2; - u32 best_mul, best_div1, best_div2; - unsigned long tclk, rate_err, best_err; + unsigned long O1, min_err, rate_err; - best_err = (unsigned long)-1; - - /* Find the closest match (lower or equal to requested) */ - for (div1 = 5; div1 >= 3; div1--) - for (div2 = 3; div2 >= 0; div2--) - for (mul = 3; mul <= 1023; mul++) { - tclk = parent_rate * mul / (div1 * (1 << div2)); - if (tclk > rate) - continue; - /* error will always be +ve */ - rate_err = rate - tclk; - if (rate_err == 0) { - *multiplier = mul; - *divisor1 = div1; - *divisor2 = div2; - return 0; - } - - if (rate_err < best_err) { - best_err = rate_err; - best_mul = mul; - best_div1 = div1; - best_div2 = div2; - } - } - - if (best_err == (unsigned long)-1) { - pr_warn("%s: impossible rate %lu\n", __func__, rate); + if (!parent_rate || (rate < 37500000) || (rate > 600000000)) return -EINVAL; + + *divisor2 = rate <= 75000000 ? 3 : rate <= 150000000 ? 2 : + rate <= 300000000 ? 1 : 0; + /* + * Divisor P cannot be calculated. Test all divisors and find where M + * will be as close as possible to the requested rate. + */ + min_err = ULONG_MAX; + for (*divisor1 = 5; *divisor1 >= 3; (*divisor1)--) { + O1 = rate * *divisor1 * (1 << (*divisor2)); + rate_err = O1 % parent_rate; + if (rate_err < min_err) { + *multiplier = O1 / parent_rate; + if (rate_err == 0) + return 0; + + min_err = rate_err; + } } - /* if we got here, it wasn't an exact match */ - pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate, - rate - best_err); - *multiplier = best_mul; - *divisor1 = best_div1; - *divisor2 = best_div2; + if ((*multiplier < 3) || (*multiplier > 1023)) + return -EINVAL; + pr_warn("%s: rate error is %lu\n", __func__, min_err); return 0; }