From patchwork Wed Oct 12 10:31:41 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emil Lundmark X-Patchwork-Id: 9372355 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 C3E9660839 for ; Wed, 12 Oct 2016 10:32:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B423829479 for ; Wed, 12 Oct 2016 10:32:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A8D1C2947E; Wed, 12 Oct 2016 10:32:47 +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.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, 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 2239C29479 for ; Wed, 12 Oct 2016 10:32:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932827AbcJLKcq (ORCPT ); Wed, 12 Oct 2016 06:32:46 -0400 Received: from mail-lf0-f51.google.com ([209.85.215.51]:32831 "EHLO mail-lf0-f51.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932817AbcJLKcm (ORCPT ); Wed, 12 Oct 2016 06:32:42 -0400 Received: by mail-lf0-f51.google.com with SMTP id x79so70612050lff.0 for ; Wed, 12 Oct 2016 03:32:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=limesaudio.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=DqRIwcxmXcqLepNNJA+NoYnZBxRe/M+QyHcQplrRFgg=; b=UZTSJClIEYZw2RJ50hScdoL+fNIIBQja7MQ8TvVsZ9sfoFExhfWNJ5JS1eoVfpb0Mi c89naGv+hAdLQbrrNV6hdLggTT7TxTe7hoV/zFsx1bztBMRm5XfMuJjX+i0iG6Mtk3/U rGBZt6JppePFCyjgNdkoH1I02BSAoMWSxtDVc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=DqRIwcxmXcqLepNNJA+NoYnZBxRe/M+QyHcQplrRFgg=; b=lrkaS0B+LLu8uDifgoaVJRw/fAlVf4c6k30iKncNazof5p1675S5+TrHfioQ+xu9n4 i4fp/PRCmgcUwApTlC06MH2+v7gjnqk8pnF/mD7vlH5IV6FnMQXDFfNg29xirZlaLD8x ESTv2fkjMo3msWjCcXXZEpPU2hNpLOzTPej654y6qpO0rnq3yN7P3l2q33a7PdjU6Kv7 NTs8Py9rXTf+aG4mms0SHJmiuCp5QJIfwmOxvtsAKI3G20HB/09bq1Pf1za8fwUA48kb EvAXa5/LH3H7eoccLhawmWTPHYX49lt0ICTwMFg4cZAa4YrJtPZ8JzCPTxeYleh1xYZe w+Zg== X-Gm-Message-State: AA6/9RkcMWMq8JcH0AV7n/7eW11OMcEkMB6/tV3FCPqJF96Zb/VtLcVUWxbpLIIqQDZ0rH/v X-Received: by 10.25.8.6 with SMTP id 6mr301609lfi.64.1476268359635; Wed, 12 Oct 2016 03:32:39 -0700 (PDT) Received: from lime.limes.local ([85.24.204.168]) by smtp.gmail.com with ESMTPSA id f35sm1944257lji.37.2016.10.12.03.32.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 12 Oct 2016 03:32:39 -0700 (PDT) From: Emil Lundmark To: Shawn Guo , Sascha Hauer , Fabio Estevam , Michael Turquette , Stephen Boyd Cc: linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org, "Ken . Lin" , Emil Lundmark Subject: [PATCH v3 2/2] clk: imx: improve precision of AV PLL to 1 Hz Date: Wed, 12 Oct 2016 12:31:41 +0200 Message-Id: <66f5967187f915fe7039f4dbfb77db88a2423094.1476267249.git.emil@limesaudio.com> In-Reply-To: References: In-Reply-To: References: 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 The audio and video PLLs are designed to have a precision of 1 Hz if some conditions are met. The current implementation only allows a precision that depends on the rate of the parent clock. E.g., if the parent clock is 24 MHz, the precision will be 24 Hz; or more generally the precision will be p / 10^6 Hz where p is the parent clock rate. This comes down to how the register values for the PLL's fractional loop divider are chosen. The clock rate calculation for the PLL is PLL output frequency = Fref * (DIV_SELECT + NUM / DENOM) or with a shorter notation r = p * (d + a / b) In addition to all variables being integers, we also have the following conditions: 27 <= d <= 54 -2^29 <= a <= 2^29-1 0 < b <= 2^30-1 |a| < b Here, d, a and b are register values for the fractional loop divider. We want to chose d, a and b such that f(p, r) = p, i.e. f is our round_rate function. Currently, d and b are chosen as d = r / p b = 10^6 hence we get the poor precision. And a is defined in terms of r, d, p and b: a = (r - d * p) * b / p I propose that if p <= 2^30-1 (i.e., the max value for b), we chose b as b = p We can do this since |a| < b |(r - d * p) * b / p| < b |r - d * p| < p Which have two solutions, one of them is when p < 0, so we can skip that one. The other is when p > 0 and p * (d - 1) < r < p * (d + 1) Substitute d = r / p: (r - p) < r < (r + p) <=> p > 0 So, as long as p > 0, we can chose b = p. This is a good choise for b since a = (r - d * p) * b / p = (r - d * p) * p / p = r - d * p r = p * (d + a / b) = p * d + p * a / b = p * d + p * a / p = p * d + a and if d = r / p: a = r - d * p = r - r / p * p = 0 r = p * d + a = p * d + 0 = p * r / p = r I reckon this is the intention by the design of the clock rate formula. Signed-off-by: Emil Lundmark Reviewed-by: Fabio Estevam --- drivers/clk/imx/clk-pllv3.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index 7a6acc3e4a92..ed3a2df536ea 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -234,6 +234,7 @@ static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long max_rate = parent_rate * 54; u32 div; u32 mfn, mfd = 1000000; + u32 max_mfd = 0x3FFFFFFF; u64 temp64; if (rate > max_rate) @@ -241,6 +242,9 @@ static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate, else if (rate < min_rate) rate = min_rate; + if (parent_rate <= max_mfd) + mfd = parent_rate; + div = rate / parent_rate; temp64 = (u64) (rate - div * parent_rate); temp64 *= mfd; @@ -262,11 +266,15 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long max_rate = parent_rate * 54; u32 val, div; u32 mfn, mfd = 1000000; + u32 max_mfd = 0x3FFFFFFF; u64 temp64; if (rate < min_rate || rate > max_rate) return -EINVAL; + if (parent_rate <= max_mfd) + mfd = parent_rate; + div = rate / parent_rate; temp64 = (u64) (rate - div * parent_rate); temp64 *= mfd;