From patchwork Wed May 21 14:47:51 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wang, Jiada" X-Patchwork-Id: 4217451 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id A90389F1CD for ; Wed, 21 May 2014 14:50:34 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7C39B20384 for ; Wed, 21 May 2014 14:50:33 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id AB1BE2037E for ; Wed, 21 May 2014 14:50:31 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wn7oV-0001HL-UD; Wed, 21 May 2014 14:48:15 +0000 Received: from relay1.mentorg.com ([192.94.38.131]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wn7oH-0001Ch-64 for linux-arm-kernel@lists.infradead.org; Wed, 21 May 2014 14:48:02 +0000 Received: from svr-orw-exc-10.mgc.mentorg.com ([147.34.98.58]) by relay1.mentorg.com with esmtp id 1Wn7nq-0004hU-Le from Jiada_Wang@mentor.com ; Wed, 21 May 2014 07:47:34 -0700 Received: from NA1-MAIL.mgc.mentorg.com ([147.34.98.181]) by SVR-ORW-EXC-10.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Wed, 21 May 2014 07:47:34 -0700 Received: from sb-ubuntu-1204-64bit.alm.mentorg.com ([134.86.97.10]) by NA1-MAIL.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.3959); Wed, 21 May 2014 07:47:34 -0700 From: jiada_wang@mentor.com To: shawn.guo@freescale.com, kernel@pengutronix.de, linux@arm.linux.org.uk, festevam@gmail.com, dirk.behme@de.bosch.com Subject: [PATCH 2/2] ARM: imx: powerdown PLL before changing of its setting Date: Wed, 21 May 2014 07:47:51 -0700 Message-Id: <1400683671-19132-3-git-send-email-jiada_wang@mentor.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1400683671-19132-1-git-send-email-jiada_wang@mentor.com> References: <1400683671-19132-1-git-send-email-jiada_wang@mentor.com> X-OriginalArrivalTime: 21 May 2014 14:47:34.0149 (UTC) FILETIME=[99BA0350:01CF7503] X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140521_074801_262152_D65E612D X-CRM114-Status: GOOD ( 13.89 ) X-Spam-Score: 0.0 (/) Cc: linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jiada Wang According to i.MX6 user manual, "Before changing the PLL setting, power it down. Power up the PLL after the change". But currently PLL setting is being updated without power-down it first. This may end up with improper output/gitches which prevents future operation. Signed-off-by: Jiada Wang Signed-off-by: Dirk Behme --- arch/arm/mach-imx/clk-pllv3.c | 53 +++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c index 36f2396..773c249 100644 --- a/arch/arm/mach-imx/clk-pllv3.c +++ b/arch/arm/mach-imx/clk-pllv3.c @@ -67,30 +67,41 @@ static int clk_pllv3_wait_lock(struct clk_pllv3 *pll) return readl_relaxed(pll->base) & BM_PLL_LOCK ? 0 : -ETIMEDOUT; } -static int clk_pllv3_prepare(struct clk_hw *hw) +static int __clk_pllv3_powerset(struct clk_pllv3 *pll, u32 newval) { - struct clk_pllv3 *pll = to_clk_pllv3(hw); u32 val; int ret; val = readl_relaxed(pll->base); - if (pll->powerup_set) - val |= BM_PLL_POWER; - else - val &= ~BM_PLL_POWER; + val &= ~BM_PLL_POWER; + val |= (newval & BM_PLL_POWER); writel_relaxed(val, pll->base); ret = clk_pllv3_wait_lock(pll); if (ret) return ret; + /* only if its locked we can switch back to the PLL */ val = readl_relaxed(pll->base); val &= ~BM_PLL_BYPASS; + val |= (newval & BM_PLL_BYPASS); writel_relaxed(val, pll->base); return 0; } +static int clk_pllv3_prepare(struct clk_hw *hw) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 power = 0; /* PLL_POWER == 0, PLL_BYPASS == 0 */ + + if (pll->powerup_set) + power = BM_PLL_POWER; + + /* power on, bypass disable */ + return __clk_pllv3_powerset(pll, power); +} + static void clk_pllv3_unprepare(struct clk_hw *hw) { struct clk_pllv3 *pll = to_clk_pllv3(hw); @@ -151,7 +162,7 @@ static int clk_pllv3_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_pllv3 *pll = to_clk_pllv3(hw); - u32 val, div; + u32 val, oldval, div; if (rate == parent_rate * 22) div = 1; @@ -160,12 +171,18 @@ static int clk_pllv3_set_rate(struct clk_hw *hw, unsigned long rate, else return -EINVAL; + oldval = readl_relaxed(pll->base); + + /* power down PLL first */ + clk_pllv3_unprepare(hw); + val = readl_relaxed(pll->base); val &= ~pll->div_mask; val |= div; writel_relaxed(val, pll->base); - return clk_pllv3_wait_lock(pll); + /* restore power & bypass bit */ + return __clk_pllv3_powerset(pll, oldval); } static const struct clk_ops clk_pllv3_ops = { @@ -210,18 +227,24 @@ static int clk_pllv3_sys_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_pllv3 *pll = to_clk_pllv3(hw); unsigned long min_rate = parent_rate * 54 / 2; unsigned long max_rate = parent_rate * 108 / 2; - u32 val, div; + u32 val, oldval, div; if (rate < min_rate || rate > max_rate) return -EINVAL; + oldval = readl_relaxed(pll->base); + + /* power down PLL first */ + clk_pllv3_unprepare(hw); + div = rate * 2 / parent_rate; val = readl_relaxed(pll->base); val &= ~pll->div_mask; val |= div; writel_relaxed(val, pll->base); - return clk_pllv3_wait_lock(pll); + /* restore power & bypass bit */ + return __clk_pllv3_powerset(pll, oldval); } static const struct clk_ops clk_pllv3_sys_ops = { @@ -275,13 +298,18 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_pllv3 *pll = to_clk_pllv3(hw); unsigned long min_rate = parent_rate * 27; unsigned long max_rate = parent_rate * 54; - u32 val, div; + u32 val, oldval, div; u32 mfn, mfd = 1000000; s64 temp64; if (rate < min_rate || rate > max_rate) return -EINVAL; + oldval = readl_relaxed(pll->base); + + /* power down PLL first */ + clk_pllv3_unprepare(hw); + div = rate / parent_rate; temp64 = (u64) (rate - div * parent_rate); temp64 *= mfd; @@ -295,7 +323,8 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate, writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET); writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET); - return clk_pllv3_wait_lock(pll); + /* restore power & bypass bit */ + return __clk_pllv3_powerset(pll, oldval); } static const struct clk_ops clk_pllv3_av_ops = {