From: Andrew Gaylard <ag@ffroot.co.za>
To: linux-clk@vger.kernel.org
Cc: qinjian@cqplus1.com, mturquette@baylibre.com, sboyd@kernel.org,
bmasney@redhat.com, linux-arm-kernel@lists.infradead.org,
Andrew Gaylard <ag@ffroot.co.za>
Subject: [PATCH] clk: sp7021: fix infrastructure clocks clobbering PLL provider entries
Date: Thu, 20 Aug 2026 15:02:24 +0200 [thread overview]
Message-ID: <20260820130224.1584902-1-ag@ffroot.co.za> (raw)
The sp_clk_gates[] array previously included 9 infrastructure gate
clocks (CLK_SYSTEM, CLK_IOCTL, etc.) appended after the 64 DT-visible
gate clocks. The registration loop used the array index directly as the
hws[] index, so infrastructure clocks at positions 64-72 overwrote
hws[PLL_A] through hws[PLL_SYS].
As a result, DT lookups for <&clkc PLL_E_25> (index 67), PLL_E_2P5
(66) and PLL_E_112P5 (68) silently resolved to CLK_RBUS, CLK_IOP and
CLK_SDCTRL0 respectively. The L2SW Ethernet driver believed it was
holding the PLLE outputs, but was actually double-referencing already-
critical infrastructure clocks. The real PLLE outputs remained at
enable_count=0 and were powered down by clk_disable_unused(), causing
an Ethernet hang on boards with fixed-link MAC-to-MAC connections.
Fix by splitting infrastructure clocks into a separate sp_clk_infra[]
array and registering them with a dedicated loop that uses a local hw
variable rather than an hws[] slot. Since these clocks have no DT
consumer they do not need to appear in the of_clk provider table.
With the provider table correct, the L2SW driver's devm_clk_get_enabled()
calls now hold the actual PLLE outputs, making CLK_IS_CRITICAL on plle
and its sub-outputs unnecessary. Remove it.
Signed-off-by: Andrew Gaylard <ag@ffroot.co.za>
---
drivers/clk/clk-sp7021.c | 42 +++++++++++++++++++++++++++++-----------
1 file changed, 31 insertions(+), 11 deletions(-)
diff --git a/drivers/clk/clk-sp7021.c b/drivers/clk/clk-sp7021.c
index 1d067b0af8a7..50c667cbb3dc 100644
--- a/drivers/clk/clk-sp7021.c
+++ b/drivers/clk/clk-sp7021.c
@@ -124,9 +124,14 @@ static const struct sp_clk_gate_info sp_clk_gates[] = {
{ 0x97 },
{ 0x98 }, /* CLK_ICM: Input Capture Module */
{ 0x99, 0, true }, /* CLK_AXI_GLOBAL: AXI interconnect, no driver consumer */
- /* Infrastructure clocks: all default to enabled in hardware but
- * have no driver consumer, so marked critical to prevent gating.
- */
+};
+
+/*
+ * Infrastructure clocks have no DT consumer so are not exposed
+ * through the of_clk provider. They are registered separately and
+ * marked CLK_IS_CRITICAL so clk_disable_unused() never gates them.
+ */
+static const struct sp_clk_gate_info sp_clk_infra[] = {
{ 0x00, 0, true }, /* CLK_SYSTEM: SYSTEM CLKEN mo_clken0 bit 0 */
{ 0x03, 0, true }, /* CLK_IOCTL: IOCTL CLKEN mo_clken0 bit 3 */
{ 0x04, 0, true }, /* CLK_IOP: IOP CLKEN mo_clken0 bit 4 */
@@ -644,25 +649,23 @@ static int sp7021_clk_probe(struct platform_device *pdev)
/*
* PLLE and all its sub-outputs are used by the L2SW Ethernet switch
* (50MHz RMII, 25MHz MII/100M, 2.5MHz MII/10M, 112.5MHz MAC fabric).
- * The L2SW driver explicitly claims these via clock-names in DTS, but
- * CLK_IS_CRITICAL is kept as a belt-and-suspenders guard in case the
- * driver consumer reference isn't sufficient on all board configurations.
+ * The L2SW driver explicitly claims these via clock-names in DTS.
*/
hws[PLL_E] = sp_pll_register(dev, "plle", &pd_ext, PLLE_CTL,
- 6, 2, 50000000, 0, 0, CLK_IS_CRITICAL);
+ 6, 2, 50000000, 0, 0, 0);
if (IS_ERR(hws[PLL_E]))
return PTR_ERR(hws[PLL_E]);
pd_e.hw = hws[PLL_E];
hws[PLL_E_2P5] = sp_pll_register(dev, "plle_2p5", &pd_e, PLLE_CTL,
- 13, -1, 2500000, 0, 0, CLK_IS_CRITICAL);
+ 13, -1, 2500000, 0, 0, 0);
if (IS_ERR(hws[PLL_E_2P5]))
return PTR_ERR(hws[PLL_E_2P5]);
hws[PLL_E_25] = sp_pll_register(dev, "plle_25", &pd_e, PLLE_CTL,
- 12, -1, 25000000, 0, 0, CLK_IS_CRITICAL);
+ 12, -1, 25000000, 0, 0, 0);
if (IS_ERR(hws[PLL_E_25]))
return PTR_ERR(hws[PLL_E_25]);
hws[PLL_E_112P5] = sp_pll_register(dev, "plle_112p5", &pd_e, PLLE_CTL,
- 11, -1, 112500000, 0, 0, CLK_IS_CRITICAL);
+ 11, -1, 112500000, 0, 0, 0);
if (IS_ERR(hws[PLL_E_112P5]))
return PTR_ERR(hws[PLL_E_112P5]);
@@ -689,7 +692,7 @@ static int sp7021_clk_probe(struct platform_device *pdev)
return PTR_ERR(hws[PLL_SYS]);
pd_sys.hw = hws[PLL_SYS];
- /* gates */
+ /* gates, directly mapped into hws[] for DT lookup */
for (i = 0; i < ARRAY_SIZE(sp_clk_gates); i++) {
char name[10];
u32 j = sp_clk_gates[i].reg;
@@ -706,6 +709,23 @@ static int sp7021_clk_probe(struct platform_device *pdev)
return PTR_ERR(hws[i]);
}
+ /* infrastructure gates, not in hws[] */
+ for (i = 0; i < ARRAY_SIZE(sp_clk_infra); i++) {
+ char name[14];
+ u32 j = sp_clk_infra[i].reg;
+ struct clk_hw *hw;
+
+ sprintf(name, "infra_0x%02x", j);
+ hw = devm_clk_hw_register_gate_parent_data(dev, name, &pd_sys,
+ CLK_IS_CRITICAL,
+ clk_base + (j >> 4) * 4,
+ j & 0x0f,
+ CLK_GATE_HIWORD_MASK,
+ NULL);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ }
+
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
}
--
2.53.0
reply other threads:[~2026-08-20 13:02 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260820130224.1584902-1-ag@ffroot.co.za \
--to=ag@ffroot.co.za \
--cc=bmasney@redhat.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-clk@vger.kernel.org \
--cc=mturquette@baylibre.com \
--cc=qinjian@cqplus1.com \
--cc=sboyd@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.