From patchwork Wed Aug 19 13:06:55 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heiko Stuebner X-Patchwork-Id: 7037341 Return-Path: X-Original-To: patchwork-linux-rockchip@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 ABE3CC05AC for ; Wed, 19 Aug 2015 13:07:41 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B071720605 for ; Wed, 19 Aug 2015 13:07:40 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A098E205F9 for ; Wed, 19 Aug 2015 13:07:36 +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 1ZS35a-0004iK-K1; Wed, 19 Aug 2015 13:07:34 +0000 Received: from gloria.sntech.de ([95.129.55.99]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZS35U-0004g2-UY; Wed, 19 Aug 2015 13:07:32 +0000 Received: from ip545477c2.speed.planet.nl ([84.84.119.194] helo=phil.localnet) by gloria.sntech.de with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.80) (envelope-from ) id 1ZS352-0007Jj-QV; Wed, 19 Aug 2015 15:07:00 +0200 From: Heiko Stuebner To: mturquette@baylibre.com, sboyd@codeaurora.org Subject: [PATCH] clk: rockchip: register pll mux before pll itself Date: Wed, 19 Aug 2015 15:06:55 +0200 Message-ID: <7060610.CC2Q1RMG2L@phil> User-Agent: KMail/4.14.1 (Linux/4.1.0-1-amd64; KDE/4.14.2; x86_64; ; ) MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150819_060729_161839_AD17CC9D X-CRM114-Status: GOOD ( 14.19 ) X-Spam-Score: -3.2 (---) X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-rockchip@lists.infradead.org, linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, 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 The structure is xin24m -> pll -> pll-mux (xin24m,pll,xin32k). The pll does have an init callback to make sure the boot-selected frequency is using the expected pll settings and resets the same frequency using the values provided in the driver if necessary. The setting itself also involves remuxing the pll-mux temporarily to the xin24m source to let the new pll rate settle. Until now this worked flawlessly, even when it had the flaw of accessing the mux settings before the mux actually got registered. With the recent clock-core conversions this flaw became apparent in null pointer dereference in [] (clk_hw_get_num_parents) from [] (clk_mux_get_parent+0x14/0xc8) [] (clk_mux_get_parent) from [] (rockchip_rk3066_pll_set_rate+0xd8/0x320) So to fix that, simply register the pll-mux before the pll, so that it will be fully initialized when the pll clock executes its init- callback and possibly touches the pll-mux clock. Signed-off-by: Heiko Stuebner Tested-by: Douglas Anderson Tested-by: Kevin Hilman --- This only surfaced with the clk_core changes for 4.3, so should probably just go on top. drivers/clk/rockchip/clk-pll.c | 63 +++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index eab4304..7737a1d 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -353,6 +353,35 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, if (!pll) return ERR_PTR(-ENOMEM); + /* create the mux on top of the real pll */ + pll->pll_mux_ops = &clk_mux_ops; + pll_mux = &pll->pll_mux; + pll_mux->reg = base + mode_offset; + pll_mux->shift = mode_shift; + pll_mux->mask = PLL_MODE_MASK; + pll_mux->flags = 0; + pll_mux->lock = lock; + pll_mux->hw.init = &init; + + if (pll_type == pll_rk3066) + pll_mux->flags |= CLK_MUX_HIWORD_MASK; + + /* the actual muxing is xin24m, pll-output, xin32k */ + pll_parents[0] = parent_names[0]; + pll_parents[1] = pll_name; + pll_parents[2] = parent_names[1]; + + init.name = name; + init.flags = CLK_SET_RATE_PARENT; + init.ops = pll->pll_mux_ops; + init.parent_names = pll_parents; + init.num_parents = ARRAY_SIZE(pll_parents); + + mux_clk = clk_register(NULL, &pll_mux->hw); + if (IS_ERR(mux_clk)) + goto err_mux; + + /* now create the actual pll */ init.name = pll_name; /* keep all plls untouched for now */ @@ -398,47 +427,19 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, pll->flags = clk_pll_flags; pll->lock = lock; - /* create the mux on top of the real pll */ - pll->pll_mux_ops = &clk_mux_ops; - pll_mux = &pll->pll_mux; - pll_mux->reg = base + mode_offset; - pll_mux->shift = mode_shift; - pll_mux->mask = PLL_MODE_MASK; - pll_mux->flags = 0; - pll_mux->lock = lock; - pll_mux->hw.init = &init; - - if (pll_type == pll_rk3066) - pll_mux->flags |= CLK_MUX_HIWORD_MASK; - pll_clk = clk_register(NULL, &pll->hw); if (IS_ERR(pll_clk)) { pr_err("%s: failed to register pll clock %s : %ld\n", __func__, name, PTR_ERR(pll_clk)); - mux_clk = pll_clk; goto err_pll; } - /* the actual muxing is xin24m, pll-output, xin32k */ - pll_parents[0] = parent_names[0]; - pll_parents[1] = pll_name; - pll_parents[2] = parent_names[1]; - - init.name = name; - init.flags = CLK_SET_RATE_PARENT; - init.ops = pll->pll_mux_ops; - init.parent_names = pll_parents; - init.num_parents = ARRAY_SIZE(pll_parents); - - mux_clk = clk_register(NULL, &pll_mux->hw); - if (IS_ERR(mux_clk)) - goto err_mux; - return mux_clk; -err_mux: - clk_unregister(pll_clk); err_pll: + clk_unregister(mux_clk); + mux_clk = pll_clk; +err_mux: kfree(pll); return mux_clk; }