From patchwork Wed Apr 15 14:26:38 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dong Aisheng X-Patchwork-Id: 6221031 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.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 31E61BF4A6 for ; Wed, 15 Apr 2015 14:33:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 093FF201FA for ; Wed, 15 Apr 2015 14:33:23 +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 DBA49201F2 for ; Wed, 15 Apr 2015 14:33:21 +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 1YiOLL-00046a-8N; Wed, 15 Apr 2015 14:31:07 +0000 Received: from mail-bn1on0113.outbound.protection.outlook.com ([157.56.110.113] helo=na01-bn1-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1YiOKJ-0002OL-CX for linux-arm-kernel@lists.infradead.org; Wed, 15 Apr 2015 14:30:05 +0000 Received: from BN3PR03MB1352.namprd03.prod.outlook.com (0.163.34.150) by BN3PR03MB1511.namprd03.prod.outlook.com (0.163.35.15) with Microsoft SMTP Server (TLS) id 15.1.136.25; Wed, 15 Apr 2015 14:29:40 +0000 Received: from DM2PR03CA0051.namprd03.prod.outlook.com (10.141.96.50) by BN3PR03MB1352.namprd03.prod.outlook.com (0.163.34.150) with Microsoft SMTP Server (TLS) id 15.1.136.25; Wed, 15 Apr 2015 14:29:39 +0000 Received: from BN1BFFO11FD044.protection.gbl (2a01:111:f400:7c10::1:107) by DM2PR03CA0051.outlook.office365.com (2a01:111:e400:2428::50) with Microsoft SMTP Server (TLS) id 15.1.136.25 via Frontend Transport; Wed, 15 Apr 2015 14:29:39 +0000 Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=freescale.com; freescale.mail.onmicrosoft.com; dkim=none (message not signed) header.d=none; Received-SPF: Fail (protection.outlook.com: domain of freescale.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Received: from tx30smr01.am.freescale.net (192.88.168.50) by BN1BFFO11FD044.mail.protection.outlook.com (10.58.144.107) with Microsoft SMTP Server (TLS) id 15.1.142.12 via Frontend Transport; Wed, 15 Apr 2015 14:29:38 +0000 Received: from shlinux2.ap.freescale.net (shlinux2.ap.freescale.net [10.192.224.44]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id t3FETK17031785; Wed, 15 Apr 2015 07:29:35 -0700 From: Dong Aisheng To: Subject: [PATCH RFC v1 4/5] clk: core: add CLK_SET_PARENT_ON flags to support clocks require parent on Date: Wed, 15 Apr 2015 22:26:38 +0800 Message-ID: <1429107999-24413-5-git-send-email-aisheng.dong@freescale.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1429107999-24413-1-git-send-email-aisheng.dong@freescale.com> References: <1429107999-24413-1-git-send-email-aisheng.dong@freescale.com> X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:192.88.168.50; CTRY:US; IPV:NLI; EFV:NLI; BMV:1; SFV:NSPM; SFS:(10019020)(6009001)(339900001)(199003)(189002)(2351001)(77156002)(62966003)(2950100001)(77096005)(46102003)(50466002)(48376002)(50226001)(36756003)(105606002)(229853001)(87936001)(104016003)(110136001)(106466001)(92566002)(86362001)(76176999)(47776003)(19580395003)(85426001)(19580405001)(6806004)(33646002)(50986999)(4001430100001)(217873001); DIR:OUT; SFP:1102; SCL:1; SRVR:BN3PR03MB1352; H:tx30smr01.am.freescale.net; FPR:; SPF:Fail; MLV:sfv; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:; SRVR:BN3PR03MB1352; UriScan:; BCL:0; PCL:0; RULEID:; SRVR:BN3PR03MB1511; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(5002010)(5005006); SRVR:BN3PR03MB1352; BCL:0; PCL:0; RULEID:; SRVR:BN3PR03MB1352; X-Forefront-PRVS: 0547116B72 X-MS-Exchange-CrossTenant-OriginalArrivalTime: 15 Apr 2015 14:29:38.9403 (UTC) X-MS-Exchange-CrossTenant-Id: 710a03f5-10f6-4d38-9ff4-a80b81da590d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=710a03f5-10f6-4d38-9ff4-a80b81da590d; Ip=[192.88.168.50]; Helo=[tx30smr01.am.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN3PR03MB1352 X-OriginatorOrg: freescale.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150415_073003_744477_5F80A898 X-CRM114-Status: GOOD ( 14.29 ) X-Spam-Score: 1.3 (+) Cc: Ranjani.Vaidyanathan@freescale.com, b20596@freescale.com, mturquette@linaro.org, sboyd@codeaurora.org, linux-kernel@vger.kernel.org, r64343@freescale.com, b20788@freescale.com, shawn.guo@linaro.org, b29396@freescale.com, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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.9 required=5.0 tests=BAYES_00,RCVD_ILLEGAL_IP, RCVD_IN_DNSWL_MED,T_RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=ham 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 On Freescale i.MX7D platform, all clocks operations, including enable/disable, rate change and re-parent, requires its parent clock on. Current clock core can not support it well. This patch introduce a new flag CLK_SET_PARENT_ON to handle this special case in clock core that enable its parent clock firstly for each operation and disable it later after operation complete. The most special case is for set_parent() operation which requires both parent, old one and new one, to be enabled at the same time during the operation. Cc: Mike Turquette Cc: Stephen Boyd Signed-off-by: Dong Aisheng --- drivers/clk/clk.c | 99 ++++++++++++++++++++++++++++++++++++++++---- include/linux/clk-provider.h | 5 +++ 2 files changed, 95 insertions(+), 9 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 7af553d..f2470e5 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -43,6 +43,11 @@ static int clk_core_get_phase(struct clk_core *clk); static bool clk_core_is_prepared(struct clk_core *clk); static bool clk_core_is_enabled(struct clk_core *clk); static struct clk_core *clk_core_lookup(const char *name); +static struct clk *clk_core_get_parent(struct clk_core *clk); +static int clk_core_prepare(struct clk_core *clk); +static void clk_core_unprepare(struct clk_core *clk); +static int clk_core_enable(struct clk_core *clk); +static void clk_core_disable(struct clk_core *clk); /*** private data structures ***/ @@ -508,6 +513,7 @@ static void clk_unprepare_unused_subtree(struct clk_core *clk) static void clk_disable_unused_subtree(struct clk_core *clk) { struct clk_core *child; + struct clk *parent = clk_core_get_parent(clk); unsigned long flags; lockdep_assert_held(&prepare_lock); @@ -515,6 +521,13 @@ static void clk_disable_unused_subtree(struct clk_core *clk) hlist_for_each_entry(child, &clk->children, child_node) clk_disable_unused_subtree(child); + if (clk->flags & CLK_SET_PARENT_ON && parent) { + clk_core_prepare(parent->core); + flags = clk_enable_lock(); + clk_core_enable(parent->core); + clk_enable_unlock(flags); + } + flags = clk_enable_lock(); if (clk->enable_count) @@ -539,6 +552,12 @@ static void clk_disable_unused_subtree(struct clk_core *clk) unlock_out: clk_enable_unlock(flags); + if (clk->flags & CLK_SET_PARENT_ON && parent) { + flags = clk_enable_lock(); + clk_core_disable(parent->core); + clk_enable_unlock(flags); + clk_core_unprepare(parent->core); + } } static bool clk_ignore_unused; @@ -608,6 +627,14 @@ struct clk *__clk_get_parent(struct clk *clk) } EXPORT_SYMBOL_GPL(__clk_get_parent); +static struct clk *clk_core_get_parent(struct clk_core *clk) +{ + if (!clk) + return NULL; + + return !clk->parent ? NULL : clk->parent->hw->clk; +} + static struct clk_core *clk_core_get_parent_by_index(struct clk_core *clk, u8 index) { @@ -1441,7 +1468,7 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *clk, struct clk_core *old_parent = clk->parent; /* - * Migrate prepare state between parents and prevent race with + * 1. Migrate prepare state between parents and prevent race with * clk_enable(). * * If the clock is not prepared, then a race with @@ -1456,13 +1483,27 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *clk, * hardware and software states. * * See also: Comment for clk_set_parent() below. + * + * 2. enable two parents clock for .set_parent() operation if finding + * flag CLK_SET_PARENT_ON */ - if (clk->prepare_count) { + if (clk->prepare_count || clk->flags & CLK_SET_PARENT_ON) { clk_core_prepare(parent); flags = clk_enable_lock(); clk_core_enable(parent); - clk_core_enable(clk); clk_enable_unlock(flags); + + if (clk->prepare_count) { + flags = clk_enable_lock(); + clk_core_enable(clk); + clk_enable_unlock(flags); + } else { + + clk_core_prepare(old_parent); + flags = clk_enable_lock(); + clk_core_enable(old_parent); + clk_enable_unlock(flags); + } } /* update the clk tree topology */ @@ -1483,12 +1524,22 @@ static void __clk_set_parent_after(struct clk_core *clk, * Finish the migration of prepare state and undo the changes done * for preventing a race with clk_enable(). */ - if (clk->prepare_count) { + if (clk->prepare_count || clk->flags & CLK_SET_PARENT_ON) { flags = clk_enable_lock(); - clk_core_disable(clk); clk_core_disable(old_parent); clk_enable_unlock(flags); clk_core_unprepare(old_parent); + + if (clk->prepare_count) { + flags = clk_enable_lock(); + clk_core_disable(clk); + clk_enable_unlock(flags); + } else { + flags = clk_enable_lock(); + clk_core_disable(parent); + clk_enable_unlock(flags); + clk_core_unprepare(parent); + } } } @@ -1514,12 +1565,23 @@ static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent, clk_reparent(clk, old_parent); clk_enable_unlock(flags); - if (clk->prepare_count) { + if (clk->prepare_count || clk->flags & CLK_SET_PARENT_ON) { flags = clk_enable_lock(); - clk_core_disable(clk); clk_core_disable(parent); clk_enable_unlock(flags); clk_core_unprepare(parent); + + if (clk->prepare_count) { + flags = clk_enable_lock(); + clk_core_disable(clk); + clk_enable_unlock(flags); + } else { + flags = clk_enable_lock(); + clk_core_disable(old_parent); + clk_enable_unlock(flags); + clk_core_unprepare(old_parent); + } + } return ret; } @@ -1735,13 +1797,18 @@ static void clk_change_rate(struct clk_core *clk) unsigned long best_parent_rate = 0; bool skip_set_rate = false; struct clk_core *old_parent; + struct clk_core *parent = NULL; + unsigned long flags; old_rate = clk->rate; - if (clk->new_parent) + if (clk->new_parent) { + parent = clk->new_parent; best_parent_rate = clk->new_parent->rate; - else if (clk->parent) + } else if (clk->parent) { + parent = clk->parent; best_parent_rate = clk->parent->rate; + } if (clk->new_parent && clk->new_parent != clk->parent) { old_parent = __clk_set_parent_before(clk, clk->new_parent); @@ -1762,6 +1829,13 @@ static void clk_change_rate(struct clk_core *clk) trace_clk_set_rate(clk, clk->new_rate); + if (clk->flags & CLK_SET_PARENT_ON && parent) { + clk_core_prepare(parent); + flags = clk_enable_lock(); + clk_core_enable(parent); + clk_enable_unlock(flags); + } + if (!skip_set_rate && clk->ops->set_rate) clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate); @@ -1769,6 +1843,13 @@ static void clk_change_rate(struct clk_core *clk) clk->rate = clk_recalc(clk, best_parent_rate); + if (clk->flags & CLK_SET_PARENT_ON && parent) { + flags = clk_enable_lock(); + clk_core_disable(parent); + clk_enable_unlock(flags); + clk_core_unprepare(parent); + } + if (clk->notifier_count && old_rate != clk->rate) __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index df69531..242b966 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -31,6 +31,11 @@ #define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */ #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */ #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */ +/* + * parent clock must be on across any operation including + * clock gate/ungate, rate change and re-parent + */ +#define CLK_SET_PARENT_ON BIT(9) struct clk_hw; struct clk_core;