From patchwork Thu Feb 28 04:49:28 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Turquette X-Patchwork-Id: 2195441 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 77EFFDF2A2 for ; Thu, 28 Feb 2013 04:54:45 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UAvTE-0003rn-UA; Thu, 28 Feb 2013 04:51:52 +0000 Received: from mail-da0-f53.google.com ([209.85.210.53]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UAvRv-0003SQ-3K for linux-arm-kernel@lists.infradead.org; Thu, 28 Feb 2013 04:50:32 +0000 Received: by mail-da0-f53.google.com with SMTP id n34so657216dal.26 for ; Wed, 27 Feb 2013 20:50:29 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:x-gm-message-state; bh=XQnZTN7E6dvFpOx6ODRT0zVM7Db9bPHnWW7ZBxy/s4c=; b=jEyzsxbsrilbQSYT241B1tkNqclSfN+86TvGuGcKiLfSoSDRPefjFagCmiMrvBnWBb ODRNZ5SwtAebT5ExgugY/8j/KvCohccyV1PID9CJMJLflwb1MlirPsqs7MTLB5JAVH1k bMfQcV5aWGOIeMhlPmnqc/MlljrrQkNBsjDOCzrMsMQl08THWp0xzodEpFL5j/5LehoU 4vqUV6XHDuQQ3FLY3jlO9J2sotceScfLcCJNmeWsfWfh5ljqQ9pLSy/NMJoyGPeh5zx4 yP/smTATO2zoW24NmaHFuTCevgscWROQC0bls9oIcPetzn7+T6NTlqH2lXz6XiqCogLt lg4w== X-Received: by 10.68.219.133 with SMTP id po5mr7277210pbc.36.1362027029569; Wed, 27 Feb 2013 20:50:29 -0800 (PST) Received: from quantum.gateway.2wire.net (adsl-69-228-86-207.dsl.pltn13.pacbell.net. [69.228.86.207]) by mx.google.com with ESMTPS id y9sm7799811paw.1.2013.02.27.20.50.26 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 27 Feb 2013 20:50:28 -0800 (PST) From: Mike Turquette To: linux-kernel@vger.kernel.org Subject: [PATCH 4/5] HACK: set_parent callback for OMAP4 non-core DPLLs Date: Wed, 27 Feb 2013 20:49:28 -0800 Message-Id: <1362026969-11457-5-git-send-email-mturquette@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1362026969-11457-1-git-send-email-mturquette@linaro.org> References: <1362026969-11457-1-git-send-email-mturquette@linaro.org> X-Gm-Message-State: ALoCoQk9eVz9yjlz3B0dF9ei/ZHMA2gUWjNkq/kCgUkJwvqZ4huhnkboqs3PiFnbLqbzGtLIi1Ta X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130227_235031_315826_91197DF9 X-CRM114-Status: GOOD ( 20.39 ) X-Spam-Score: -0.1 (/) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-0.1 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.210.53 listed in list.dnswl.org] 2.5 SUSPICIOUS_RECIPS Similar addresses in recipient list -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Mike Turquette , linaro-dev@lists.linaro.org, linux-arm-kernel@lists.infradead.org, patches@linaro.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 This is a silly patch that demonstrates calling clk_set_parent from within a .set_rate callback, which itself was called by clk_set_rate. It may make your board burst into flames or otherwise void various warrantees. I do not suggest that the OMAP folks take this approach in unless they really want to. Instead it was a way for me to increase code coverage while testing the reentrancy changes to the core clock framework. Changes in this patch include removing __clk_prepare and __clk_unprepare from omap3_noncore_dpll_set_rate and using the (now reentrant) clk_prepare & clk_unprepare versions. Most importantly this patch introduces omap3_noncore_dpll_set_parent and adds it to the clk_ops for all OMAP3+ DPLLs. The net gain is that on OMAP4 platforms it is now possible to call clk_set_parent(some_dpll_ck, ...) in order to change the PLL input from the reference clock to the bypass clock, and vice versa. omap3_noncore_dpll_set_rate is modified to call clk_set_parent when appropriate as a way to test reentrancy. Not-signed-off-by: Mike Turquette --- arch/arm/mach-omap2/cclock44xx_data.c | 1 + arch/arm/mach-omap2/clock.h | 1 + arch/arm/mach-omap2/dpll3xxx.c | 107 +++++++++++++++++++++++++-------- 3 files changed, 84 insertions(+), 25 deletions(-) diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c index 5789a5e..df5da7f 100644 --- a/arch/arm/mach-omap2/cclock44xx_data.c +++ b/arch/arm/mach-omap2/cclock44xx_data.c @@ -386,6 +386,7 @@ static const struct clk_ops dpll_ck_ops = { .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, .get_parent = &omap2_init_dpll_parent, + .set_parent = &omap3_noncore_dpll_set_parent, }; static struct clk_hw_omap dpll_iva_ck_hw = { diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index b402048..1cf43a5 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -367,6 +367,7 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); int omap3_noncore_dpll_enable(struct clk_hw *hw); void omap3_noncore_dpll_disable(struct clk_hw *hw); +int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index); int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate); u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk); diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index 0a02aab5..bae123e 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -450,6 +450,76 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw) clkdm_clk_disable(clk->clkdm, hw->clk); } +/* Non-CORE DPLL set parent code */ + +/** + * omap3_noncore_dpll_set_parent - set non-core DPLL input + * @hw: hardware object for this clock/dpll + * @index: parent to switch to in the array of possible parents + * + * Sets the input to the DPLL to either the reference clock or bypass + * clock. Returns error code upon failure or 0 upon success. + */ +int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + u16 freqsel = 0; + struct dpll_data *dd; + int ret; + + if (!hw) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + clk_prepare(dd->clk_bypass); + clk_enable(dd->clk_bypass); + clk_prepare(dd->clk_ref); + clk_enable(dd->clk_ref); + + /* FIXME hard coded magic numbers are gross */ + switch (index) { + /* dpll input is the reference clock */ + case 0: + if (dd->last_rounded_rate == 0) + return -EINVAL; + + /* No freqsel on OMAP4 and OMAP3630 */ + if (!cpu_is_omap44xx() && !cpu_is_omap3630()) { + freqsel = _omap3_dpll_compute_freqsel(clk, + dd->last_rounded_n); + WARN_ON(!freqsel); + } + + pr_debug("%s: %s: set rate: locking rate to %lu.\n", + __func__, __clk_get_name(hw->clk), dd->last_rounded_rate); + + ret = omap3_noncore_dpll_program(clk, freqsel); + break; + + /* dpll input is the bypass clock */ + case 1: + pr_debug("%s: %s: set rate: entering bypass.\n", + __func__, __clk_get_name(hw->clk)); + + ret = _omap3_noncore_dpll_bypass(clk); + break; + + default: + pr_warn("%s: %s: set parent: invalid parent\n", + __func__, __clk_get_name(hw->clk)); + return -EINVAL; + } + + clk_disable(dd->clk_ref); + clk_unprepare(dd->clk_ref); + clk_disable(dd->clk_bypass); + clk_unprepare(dd->clk_bypass); + + return 0; +} /* Non-CORE DPLL rate set code */ @@ -468,7 +538,6 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); - struct clk *new_parent = NULL; u16 freqsel = 0; struct dpll_data *dd; int ret; @@ -480,22 +549,18 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, if (!dd) return -EINVAL; - __clk_prepare(dd->clk_bypass); + clk_prepare(dd->clk_bypass); clk_enable(dd->clk_bypass); - __clk_prepare(dd->clk_ref); + clk_prepare(dd->clk_ref); clk_enable(dd->clk_ref); - if (__clk_get_rate(dd->clk_bypass) == rate && + /* FIXME below block should call clk_set_parent */ + if (clk_get_rate(dd->clk_bypass) == rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - pr_debug("%s: %s: set rate: entering bypass.\n", - __func__, __clk_get_name(hw->clk)); - - ret = _omap3_noncore_dpll_bypass(clk); - if (!ret) - new_parent = dd->clk_bypass; + clk_set_parent(hw->clk, dd->clk_bypass); } else { if (dd->last_rounded_rate != rate) - rate = __clk_round_rate(hw->clk, rate); + rate = clk_round_rate(hw->clk, rate); if (dd->last_rounded_rate == 0) return -EINVAL; @@ -510,24 +575,16 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__, __clk_get_name(hw->clk), rate); - ret = omap3_noncore_dpll_program(clk, freqsel); - if (!ret) - new_parent = dd->clk_ref; + if (clk_get_parent(hw->clk) == dd->clk_bypass) + clk_set_parent(hw->clk, dd->clk_ref); + else + ret = omap3_noncore_dpll_program(clk, freqsel); } - /* - * FIXME - this is all wrong. common code handles reparenting and - * migrating prepare/enable counts. dplls should be a multiplexer - * clock and this should be a set_parent operation so that all of that - * stuff is inherited for free - */ - - if (!ret) - __clk_reparent(hw->clk, new_parent); clk_disable(dd->clk_ref); - __clk_unprepare(dd->clk_ref); + clk_unprepare(dd->clk_ref); clk_disable(dd->clk_bypass); - __clk_unprepare(dd->clk_bypass); + clk_unprepare(dd->clk_bypass); return 0; }