From patchwork Wed May 14 09:36:37 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wang, Jiada" X-Patchwork-Id: 4173781 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 2231ABFF02 for ; Wed, 14 May 2014 09:39:32 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 419EC2037E for ; Wed, 14 May 2014 09:39:31 +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 327B82037D for ; Wed, 14 May 2014 09:39:30 +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 1WkVcg-0004v0-8d; Wed, 14 May 2014 09:37:14 +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 1WkVcd-0004sU-AV for linux-arm-kernel@lists.infradead.org; Wed, 14 May 2014 09:37:12 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1WkVcC-0001T5-BQ from Jiada_Wang@mentor.com ; Wed, 14 May 2014 02:36:44 -0700 Received: from NA1-MAIL.mgc.mentorg.com ([147.34.98.181]) by svr-orw-fem-01.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Wed, 14 May 2014 02:36:44 -0700 Received: from jiwang-OptiPlex-980.tokyo.mentorg.com ([134.86.192.150]) by NA1-MAIL.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.3959); Wed, 14 May 2014 02:36:43 -0700 From: Jiada Wang To: shawn.guo@linaro.org, dirk.behme@de.bosch.com, rmk+kernel@arm.linux.org.uk Subject: [PATCH] ARM: imx: powerdown PLL before changing of its setting Date: Wed, 14 May 2014 18:36:37 +0900 Message-Id: <1400060197-706-1-git-send-email-jiada_wang@mentor.com> X-Mailer: git-send-email 1.9.3 X-OriginalArrivalTime: 14 May 2014 09:36:43.0786 (UTC) FILETIME=[045A36A0:01CF6F58] X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140514_023711_383693_957F03A0 X-CRM114-Status: GOOD ( 11.14 ) 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 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 furture operation. Signed-off-by: Jiada Wang --- arch/arm/mach-imx/clk-pllv3.c | 72 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c index 6136405..f77edd6 100644 --- a/arch/arm/mach-imx/clk-pllv3.c +++ b/arch/arm/mach-imx/clk-pllv3.c @@ -67,6 +67,42 @@ static int clk_pllv3_wait_lock(struct clk_pllv3 *pll) return readl_relaxed(pll->base) & BM_PLL_LOCK ? 0 : -ETIMEDOUT; } +static void clk_pllv3_powerdown(struct clk_pllv3 *pll) +{ + u32 val; + + val = readl_relaxed(pll->base); + val |= BM_PLL_BYPASS; + writel_relaxed(val, pll->base); + + if (pll->powerup_set) + val &= ~BM_PLL_POWER; + else + val |= BM_PLL_POWER; + writel_relaxed(val, pll->base); +} + +static int clk_pllv3_powerrestore(struct clk_pllv3 *pll, u32 power, u32 bypass) +{ + u32 val; + int ret; + + val = readl_relaxed(pll->base); + val &= ~BM_PLL_POWER; + val |= power; + writel_relaxed(val, pll->base); + + ret = clk_pllv3_wait_lock(pll); + if (ret == 0) { + /* only if it locked can we switch back to the PLL */ + val &= ~BM_PLL_BYPASS; + val |= bypass; + writel_relaxed(val, pll->base); + } + + return ret; +} + static int clk_pllv3_prepare(struct clk_hw *hw) { struct clk_pllv3 *pll = to_clk_pllv3(hw); @@ -149,7 +185,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, powerval, bypassval, div; if (rate == parent_rate * 22) div = 1; @@ -159,11 +195,19 @@ static int clk_pllv3_set_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; val = readl_relaxed(pll->base); + powerval = val & BM_PLL_POWER; + bypassval = val & BM_PLL_BYPASS; + + /* power down PLL first */ + clk_pllv3_powerdown(pll); + + 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_powerrestore(pll, powerval, bypassval); } static const struct clk_ops clk_pllv3_ops = { @@ -208,18 +252,26 @@ 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, powerval, bypassval, div; if (rate < min_rate || rate > max_rate) return -EINVAL; + val = readl_relaxed(pll->base); + powerval = val & BM_PLL_POWER; + bypassval = val & BM_PLL_BYPASS; + + /* power down PLL first */ + clk_pllv3_powerdown(pll); + 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_powerrestore(pll, powerval, bypassval); } static const struct clk_ops clk_pllv3_sys_ops = { @@ -273,13 +325,20 @@ 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, powerval, bypassval, div; u32 mfn, mfd = 1000000; s64 temp64; if (rate < min_rate || rate > max_rate) return -EINVAL; + val = readl_relaxed(pll->base); + powerval = val & BM_PLL_POWER; + bypassval = val & BM_PLL_BYPASS; + + /* power down PLL first */ + clk_pllv3_powerdown(pll); + div = rate / parent_rate; temp64 = (u64) (rate - div * parent_rate); temp64 *= mfd; @@ -293,7 +352,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_powerrestore(pll, powerval, bypassval); } static const struct clk_ops clk_pllv3_av_ops = {