From patchwork Sun Feb 10 15:38:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Katsuhiro Suzuki X-Patchwork-Id: 10804831 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1C8AC13B5 for ; Sun, 10 Feb 2019 15:38:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0AFE129E87 for ; Sun, 10 Feb 2019 15:38:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F278F29E90; Sun, 10 Feb 2019 15:38:28 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 59EFC29E87 for ; Sun, 10 Feb 2019 15:38:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:To :From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=QMAc76dLJQw/2vvZwAcGSYEtSmi1ayW6rfejgGESlYo=; b=OMDnjVYyI543Th tTrntYF5mzFXA2WzllzUDH39exeoOb8kk8ieDun27VDB5IDcsPgeOf8lulK4DQo7+Y9xZYZd2GIeP At30jR3KoC94qvZhdsgc/qBEN8QkWhzxlUXk1bmk8p+uZjnbRou/VgZeXLcih04b664MsPBcZo4wd GsYC4l1Hv2WexFjgkAw6PVl58VkW47UU/n6kNGp1BU3lGEJ0VfXS4pEE08807/XJYznP7hJSaDan7 vQjxsbdxst/AkHwWKM0iamti42v08bppcgmXIgvgmb1b6BCRX04YfNYJpUdAK+i6r7r/z278E4RrU Psf8wuy1UjeznhAgtMhg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1gsrBY-0006fJ-3m; Sun, 10 Feb 2019 15:38:24 +0000 Received: from www1102.sakura.ne.jp ([219.94.129.142]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1gsrBT-0006eo-7a for linux-arm-kernel@lists.infradead.org; Sun, 10 Feb 2019 15:38:21 +0000 Received: from fsav304.sakura.ne.jp (fsav304.sakura.ne.jp [153.120.85.135]) by www1102.sakura.ne.jp (8.15.2/8.15.2) with ESMTP id x1AFcC2U070970; Mon, 11 Feb 2019 00:38:12 +0900 (JST) (envelope-from katsuhiro@katsuster.net) Received: from www1102.sakura.ne.jp (219.94.129.142) by fsav304.sakura.ne.jp (F-Secure/fsigk_smtp/530/fsav304.sakura.ne.jp); Mon, 11 Feb 2019 00:38:12 +0900 (JST) X-Virus-Status: clean(F-Secure/fsigk_smtp/530/fsav304.sakura.ne.jp) Received: from localhost.localdomain (119.104.232.153.ap.dti.ne.jp [153.232.104.119]) (authenticated bits=0) by www1102.sakura.ne.jp (8.15.2/8.15.2) with ESMTPSA id x1AFc9M3070960 (version=TLSv1.2 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 11 Feb 2019 00:38:12 +0900 (JST) (envelope-from katsuhiro@katsuster.net) From: Katsuhiro Suzuki To: Michael Turquette , Stephen Boyd , linux-clk@vger.kernel.org Subject: [PATCH v2] clk: fractional-divider: check parent rate only if flag is set Date: Mon, 11 Feb 2019 00:38:06 +0900 Message-Id: <20190210153806.24201-1-katsuhiro@katsuster.net> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190210_073819_597239_72D252F3 X-CRM114-Status: GOOD ( 14.37 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Katsuhiro Suzuki , Heiko Stuebner , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Custom approximation of fractional-divider may not need parent clock rate checking. For example Rockchip SoCs work fine using grand parent clock rate even if target rate is greater than parent. This patch checks parent clock rate only if CLK_SET_RATE_PARENT flag is set. For detailed example, clock tree of Rockchip I2S audio hardware. - Clock rate of CPLL is 1.2GHz, GPLL is 491.52MHz. - i2s1_div is integer divider can divide N (N is 1~128). Input clock is CPLL or GPLL. Initial divider value is N = 1. Ex) PLL = CPLL, N = 10, i2s1_div output rate is CPLL / 10 = 1.2GHz / 10 = 120MHz - i2s1_frac is fractional divider can divide input to x/y, x and y are 16bit integer. CPLL --> | selector | ---> i2s1_div -+--> | selector | --> I2S1 MCLK GPLL --> | | ,--------------' | | `--> i2s1_frac ---> | | Clock mux system try to choose suitable one from i2s1_div and i2s1_frac for master clock (MCLK) of I2S1. Bad scenario as follows: - Try to set MCLK to 8.192MHz (32kHz audio replay) Candidate setting is - i2s1_div: GPLL / 60 = 8.192MHz i2s1_div candidate is exactly same as target clock rate, so mux choose this clock source. i2s1_div output rate is changed 491.52MHz -> 8.192MHz - After that try to set to 11.2896MHz (44.1kHz audio replay) Candidate settings are - i2s1_div : CPLL / 107 = 11.214945MHz - i2s1_frac: i2s1_div = 8.192MHz This is because clk_fd_round_rate() thinks target rate (11.2896MHz) is higher than parent rate (i2s1_div = 8.192MHz) and returns parent clock rate. Above is current upstreamed behavior. Clock mux system choose i2s1_div, but this clock rate is not acceptable for I2S driver, so users cannot replay audio. Expected behavior is: - Try to set master clock to 11.2896MHz (44.1kHz audio replay) Candidate settings are - i2s1_div : CPLL / 107 = 11.214945MHz - i2s1_frac: i2s1_div * 147/6400 = 11.2896MHz Change i2s1_div to GPLL / 1 = 491.52MHz at same time. If apply this commit, clk_fd_round_rate() calls custom approximate function of Rockchip even if target rate is higher than parent. Custom function changes both grand parent (i2s1_div) and parent (i2s_frac) settings at same time. Clock mux system can choose i2s1_frac and audio works fine. Signed-off-by: Katsuhiro Suzuki Reviewed-by: Heiko Stuebner --- drivers/clk/clk-fractional-divider.c | 2 +- drivers/clk/clk.c | 8 ++++++++ include/linux/clk-provider.h | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index 545dceec0bbf..fdfe2e423d15 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -79,7 +79,7 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long m, n; u64 ret; - if (!rate || rate >= *parent_rate) + if (!rate || (!clk_hw_can_set_rate_parent(hw) && rate >= *parent_rate)) return *parent_rate; if (fd->approximation) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index d2477a5058ac..070c0cb29ee8 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -518,6 +518,14 @@ void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate, } EXPORT_SYMBOL_GPL(clk_hw_set_rate_range); +bool clk_hw_can_set_rate_parent(struct clk_hw *hw) +{ + unsigned long flags = clk_hw_get_flags(hw); + + return flags & CLK_SET_RATE_PARENT; +} +EXPORT_SYMBOL_GPL(clk_hw_can_set_rate_parent); + /* * Helper for finding best parent to provide a given frequency. This can be used * directly as a determine_rate callback (e.g. for a mux), or from a more diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index e443fa9fa859..693a51937ded 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -808,6 +808,7 @@ int clk_mux_determine_rate_flags(struct clk_hw *hw, void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent); void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate, unsigned long max_rate); +bool clk_hw_can_set_rate_parent(struct clk_hw *hw); static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src) {