* [PATCH v10 0/5] clk: add support for Airoha AN7583 clock
@ 2026-11-05 12:10 Christian Marangi
2026-11-05 12:10 ` [PATCH v10 1/5] dt-bindings: clock: airoha: Document support for " Christian Marangi
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Christian Marangi @ 2026-11-05 12:10 UTC (permalink / raw)
To: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, Felix Fietkau,
linux-clk, devicetree, linux-kernel
Cc: Christian Marangi
This small series introduce some cleanup and support for
clock and reset of Airoha AN7583.
The implementation is similar to EN7581 but AN7583 introduce
new reset and more clock divisor support.
Changes v10:
- Fix whitespace in include patch
- Add reset and phy cell as required
- Add additional patch for devm variant
- Add additional patch for lock for clock and reset access
Changes v9:
- Fix compilation error for priv (again) (this time fixed)
Changes v8:
- Add ACK tag by Connor
- Fix missing priv->base assign
Changes v7:
- Add further info for DT patch
- Add serdes selection support
- Rebase on top of linux-next
Link: https://lore.kernel.org/all/20261009070725.13196-1-ansuelsmth@gmail.com/
Changes v6:
- Address bot suggestion for DT patch
- Add further information on chip-scu phandle
- Add dedicated PERSTOUT reset and PCIE_HB reset
Link: https://lore.kernel.org/all/20260819221458.30040-1-ansuelsmth@gmail.com/
Changes v5:
- Rebase on top of linux-next
- Drop even more patch to reduce patch delta
- Make chip-scu specific to AN7583
Link: https://lore.kernel.org/all/20260528190000.9164-1-ansuelsmth@gmail.com
Changes v4:
- Add review tag for DT patch
- Fix clock patch to use en7581-chip-scu compatible
- Drop PCIE SCU SSR write
Changes v3:
- Drop .set_rate patch (will be proposed later)
- Drop chip-scu binding and related patch
Link: https://lore.kernel.org/all/20251106195935.1767696-1-ansuelsmth@gmail.com
Changes v2:
- Add .set_rate support
- Rework DT to EN7581 implementation (clock driver is parent)
- Add additional cleanup patch
- Merge binding with schema patch
- Add chip_scu phandle
Christian Marangi (5):
dt-bindings: clock: airoha: Document support for AN7583 clock
clk: en7523: use devm variant for clk_hw_register and fixed clock
clk: en7523: protect concurrent access to reset and PCI register
clk: en7523: generalize register clocks function
clk: en7523: add support for Airoha AN7583 clock
.../bindings/clock/airoha,en7523-scu.yaml | 25 ++
drivers/clk/clk-en7523.c | 332 +++++++++++++++++-
include/dt-bindings/clock/en7523-clk.h | 3 +
.../dt-bindings/reset/airoha,an7583-reset.h | 65 ++++
4 files changed, 418 insertions(+), 7 deletions(-)
create mode 100644 include/dt-bindings/reset/airoha,an7583-reset.h
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v10 1/5] dt-bindings: clock: airoha: Document support for AN7583 clock
2026-11-05 12:10 [PATCH v10 0/5] clk: add support for Airoha AN7583 clock Christian Marangi
@ 2026-11-05 12:10 ` Christian Marangi
2026-11-05 12:10 ` [PATCH v10 2/5] clk: en7523: use devm variant for clk_hw_register and fixed clock Christian Marangi
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Christian Marangi @ 2026-11-05 12:10 UTC (permalink / raw)
To: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, Felix Fietkau,
linux-clk, devicetree, linux-kernel
Cc: Christian Marangi, Conor Dooley
Document support for Airoha AN7583 clock. This is based on the EN7523
clock schema with the new requirement of the "airoha,chip-scu".
The register for clock and reset for normal system and PCIe are scattered
between the "SCU" and "chip SCU" registers (they are 2 different register
block, the name is taken from the programming guide)
- Chip SCU provide register access to some clk gate and clk rate
- SCU provide register for reset, PCIe clock, other clock gate and PHY
SERDES.
Upcoming and current airoha clock driver all follow this pattern of
declaring one of the 2 register and use a sysconf for the other as the 2
register block are tighlty coupled.
EN7581 internally handle the syscon with a direct reference by the use of
syscon_regmap_lookup_by_compatible while AN7583 wants to make this
explicit in DT with the new "airoha,chip-scu" phandle.
Similar to EN7581, also AN7583 permit the selection of the serdes line.
Add additional binding for additional clock and reset lines.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
.../bindings/clock/airoha,en7523-scu.yaml | 25 +++++++
include/dt-bindings/clock/en7523-clk.h | 3 +
.../dt-bindings/reset/airoha,an7583-reset.h | 65 +++++++++++++++++++
3 files changed, 93 insertions(+)
create mode 100644 include/dt-bindings/reset/airoha,an7583-reset.h
diff --git a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
index fc37786ac7ed..05cd20ce3ab9 100644
--- a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
+++ b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
@@ -31,6 +31,7 @@ properties:
compatible:
items:
- enum:
+ - airoha,an7583-scu
- airoha,en7523-scu
- airoha,en7581-scu
- econet,en751221-scu
@@ -57,12 +58,36 @@ properties:
available serdes port.
const: 1
+ airoha,chip-scu:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: phandle to the Chip SCU providing the registers required
+ for configuring the PCIe related clocks and resets.
+
required:
- compatible
- reg
- '#clock-cells'
allOf:
+ - if:
+ properties:
+ compatible:
+ const: airoha,an7583-scu
+
+ then:
+ properties:
+ reg:
+ maxItems: 1
+
+ required:
+ - airoha,chip-scu
+ - '#reset-cells'
+ - '#phy-cells'
+
+ else:
+ properties:
+ airoha,chip-scu: false
+
- if:
properties:
compatible:
diff --git a/include/dt-bindings/clock/en7523-clk.h b/include/dt-bindings/clock/en7523-clk.h
index edfa64045f52..0fbbcb7b1b25 100644
--- a/include/dt-bindings/clock/en7523-clk.h
+++ b/include/dt-bindings/clock/en7523-clk.h
@@ -14,4 +14,7 @@
#define EN7581_CLK_EMMC 8
+#define AN7583_CLK_MDIO0 9
+#define AN7583_CLK_MDIO1 10
+
#endif /* _DT_BINDINGS_CLOCK_AIROHA_EN7523_H_ */
diff --git a/include/dt-bindings/reset/airoha,an7583-reset.h b/include/dt-bindings/reset/airoha,an7583-reset.h
new file mode 100644
index 000000000000..433a5c6180bf
--- /dev/null
+++ b/include/dt-bindings/reset/airoha,an7583-reset.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2024 AIROHA Inc
+ * Author: Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#ifndef __DT_BINDINGS_RESET_CONTROLLER_AIROHA_AN7583_H_
+#define __DT_BINDINGS_RESET_CONTROLLER_AIROHA_AN7583_H_
+
+/* RST_CTRL2 */
+#define AN7583_XPON_PHY_RST 0
+#define AN7583_GPON_OLT_RST 1
+#define AN7583_CPU_TIMER2_RST 2
+#define AN7583_HSUART_RST 3
+#define AN7583_UART4_RST 4
+#define AN7583_UART5_RST 5
+#define AN7583_I2C2_RST 6
+#define AN7583_XSI_MAC_RST 7
+#define AN7583_XSI_PHY_RST 8
+#define AN7583_NPU_RST 9
+#define AN7583_TRNG_MSTART_RST 10
+#define AN7583_DUAL_HSI0_RST 11
+#define AN7583_DUAL_HSI1_RST 12
+#define AN7583_DUAL_HSI0_MAC_RST 13
+#define AN7583_DUAL_HSI1_MAC_RST 14
+#define AN7583_XPON_XFI_RST 15
+#define AN7583_WDMA_RST 16
+#define AN7583_WOE0_RST 17
+#define AN7583_HSDMA_RST 18
+#define AN7583_TDMA_RST 19
+#define AN7583_EMMC_RST 20
+#define AN7583_SOE_RST 21
+#define AN7583_XFP_MAC_RST 22
+#define AN7583_MDIO0_RST 23
+#define AN7583_MDIO1_RST 24
+/* RST_CTRL1 */
+#define AN7583_PCM1_ZSI_ISI_RST 25
+#define AN7583_FE_PDMA_RST 26
+#define AN7583_FE_QDMA_RST 27
+#define AN7583_PCM_SPIWP_RST 28
+#define AN7583_CRYPTO_RST 29
+#define AN7583_TIMER_RST 30
+#define AN7583_PCM1_RST 31
+#define AN7583_UART_RST 32
+#define AN7583_GPIO_RST 33
+#define AN7583_GDMA_RST 34
+#define AN7583_I2C_MASTER_RST 35
+#define AN7583_PCM2_ZSI_ISI_RST 36
+#define AN7583_SFC_RST 37
+#define AN7583_UART2_RST 38
+#define AN7583_GDMP_RST 39
+#define AN7583_FE_RST 40
+#define AN7583_USB_HOST_P0_RST 41
+#define AN7583_GSW_RST 42
+#define AN7583_SFC2_PCM_RST 43
+#define AN7583_PCIE0_RST 44
+#define AN7583_PCIE1_RST 45
+#define AN7583_CPU_TIMER_RST 46
+#define AN7583_PCIE_HB_RST 47
+#define AN7583_XPON_MAC_RST 48
+/* RST_PCIC */
+#define AN7583_PCIC_PERSTOUT0_RST 49
+#define AN7583_PCIC_PERSTOUT1_RST 50
+
+#endif /* __DT_BINDINGS_RESET_CONTROLLER_AIROHA_AN7583_H_ */
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v10 2/5] clk: en7523: use devm variant for clk_hw_register and fixed clock
2026-11-05 12:10 [PATCH v10 0/5] clk: add support for Airoha AN7583 clock Christian Marangi
2026-11-05 12:10 ` [PATCH v10 1/5] dt-bindings: clock: airoha: Document support for " Christian Marangi
@ 2026-11-05 12:10 ` Christian Marangi
2026-11-05 12:10 ` [PATCH v10 3/5] clk: en7523: protect concurrent access to reset and PCI register Christian Marangi
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Christian Marangi @ 2026-11-05 12:10 UTC (permalink / raw)
To: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, Felix Fietkau,
linux-clk, devicetree, linux-kernel
Cc: Christian Marangi
Use devm variant for clk_hw_register and clk_hw_register_fixed_rate
to correctly unregister the clocks on probe fails.
This should never happen under normal condition but it's better to
handle these cleanup.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/clk/clk-en7523.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c
index 24fdec2e6198..2baec734df9f 100644
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -651,7 +651,7 @@ static struct clk_hw *en7523_register_pcie_clk(struct device *dev,
if (init.ops->unprepare)
init.ops->unprepare(&cg->hw);
- if (clk_hw_register(dev, &cg->hw))
+ if (devm_clk_hw_register(dev, &cg->hw))
return NULL;
return &cg->hw;
@@ -708,7 +708,7 @@ static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_dat
val = readl(base + reg);
rate /= en7523_get_div(desc, val);
- hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
+ hw = devm_clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
if (IS_ERR(hw)) {
pr_err("Failed to register clk %s: %ld\n",
desc->name, PTR_ERR(hw));
@@ -770,7 +770,7 @@ static void en7581_register_clocks(struct device *dev, struct clk_hw_onecell_dat
}
rate /= en7523_get_div(desc, val);
- hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
+ hw = devm_clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
if (IS_ERR(hw)) {
pr_err("Failed to register clk %s: %ld\n",
desc->name, PTR_ERR(hw));
@@ -1105,7 +1105,7 @@ static void en751221_try_register_clk(struct device *dev, int key,
if (WARN_ON_ONCE(key >= EN751221_MAX_CLKS))
return;
- hw = clk_hw_register_fixed_rate(dev, name, NULL, 0, rate);
+ hw = devm_clk_hw_register_fixed_rate(dev, name, NULL, 0, rate);
if (IS_ERR(hw))
pr_err("Failed to register clk %s: %pe\n", name, hw);
else
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v10 3/5] clk: en7523: protect concurrent access to reset and PCI register
2026-11-05 12:10 [PATCH v10 0/5] clk: add support for Airoha AN7583 clock Christian Marangi
2026-11-05 12:10 ` [PATCH v10 1/5] dt-bindings: clock: airoha: Document support for " Christian Marangi
2026-11-05 12:10 ` [PATCH v10 2/5] clk: en7523: use devm variant for clk_hw_register and fixed clock Christian Marangi
@ 2026-11-05 12:10 ` Christian Marangi
2026-11-05 12:22 ` sashiko-bot
2026-11-05 12:10 ` [PATCH v10 4/5] clk: en7523: generalize register clocks function Christian Marangi
2026-11-05 12:10 ` [PATCH v10 5/5] clk: en7523: add support for Airoha AN7583 clock Christian Marangi
4 siblings, 1 reply; 8+ messages in thread
From: Christian Marangi @ 2026-11-05 12:10 UTC (permalink / raw)
To: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, Felix Fietkau,
linux-clk, devicetree, linux-kernel
Cc: Christian Marangi
Use spinlock for concurrent access to reset and PCI register to catch case
when clock is enabled/disabled while a reset is also operated at the same
time.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/clk/clk-en7523.c | 66 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 65 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c
index 2baec734df9f..c05d0bfa2340 100644
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -123,6 +123,8 @@ struct en_clk_desc {
struct en_clk_gate {
void __iomem *base;
+ /* protect SCU register */
+ spinlock_t lock;
struct clk_hw hw;
};
@@ -130,6 +132,8 @@ struct en_rst_data {
const u16 *bank_ofs;
const u16 *idx_map;
void __iomem *base;
+ /* protect SCU register */
+ spinlock_t lock;
struct reset_controller_dev rcdev;
};
@@ -577,44 +581,78 @@ static u32 en7523_get_div(const struct en_clk_desc *desc, u32 val)
static int en7523_pci_is_enabled(struct clk_hw *hw)
{
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&cg->lock, flags);
+ val = readl(cg->base + REG_PCI_CONTROL);
+ spin_unlock_irqrestore(&cg->lock, flags);
- return !!(readl(cg->base + REG_PCI_CONTROL) & REG_PCI_CONTROL_REFCLK_EN1);
+ return !!(val & REG_PCI_CONTROL_REFCLK_EN1);
}
static int en7523_pci_prepare(struct clk_hw *hw)
{
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
void __iomem *np_base = cg->base;
+ unsigned long flags;
u32 val, mask;
/* Need to pull device low before reset */
+ spin_lock_irqsave(&cg->lock, flags);
val = readl(np_base + REG_PCI_CONTROL);
val &= ~(REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT);
writel(val, np_base + REG_PCI_CONTROL);
+ spin_unlock_irqrestore(&cg->lock, flags);
+
usleep_range(1000, 2000);
/* Enable PCIe port 1 */
+ spin_lock_irqsave(&cg->lock, flags);
val |= REG_PCI_CONTROL_REFCLK_EN1;
writel(val, np_base + REG_PCI_CONTROL);
+ spin_unlock_irqrestore(&cg->lock, flags);
+
usleep_range(1000, 2000);
/* Reset to default */
+ spin_lock_irqsave(&cg->lock, flags);
val = readl(np_base + REG_RESET_CONTROL1);
mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 |
REG_RESET_CONTROL_PCIEHB;
writel(val & ~mask, np_base + REG_RESET_CONTROL1);
+ spin_unlock_irqrestore(&cg->lock, flags);
+
usleep_range(1000, 2000);
+
+ spin_lock_irqsave(&cg->lock, flags);
+ val = readl(np_base + REG_RESET_CONTROL1);
writel(val | mask, np_base + REG_RESET_CONTROL1);
+ spin_unlock_irqrestore(&cg->lock, flags);
+
msleep(100);
+
+ spin_lock_irqsave(&cg->lock, flags);
+ val = readl(np_base + REG_RESET_CONTROL1);
writel(val & ~mask, np_base + REG_RESET_CONTROL1);
+ spin_unlock_irqrestore(&cg->lock, flags);
+
usleep_range(5000, 10000);
/* Release device */
+ spin_lock_irqsave(&cg->lock, flags);
mask = REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT;
val = readl(np_base + REG_PCI_CONTROL);
writel(val & ~mask, np_base + REG_PCI_CONTROL);
+ spin_unlock_irqrestore(&cg->lock, flags);
+
usleep_range(1000, 2000);
+
+ spin_lock_irqsave(&cg->lock, flags);
+ val = readl(np_base + REG_PCI_CONTROL);
writel(val | mask, np_base + REG_PCI_CONTROL);
+ spin_unlock_irqrestore(&cg->lock, flags);
+
msleep(250);
return 0;
@@ -624,11 +662,14 @@ static void en7523_pci_unprepare(struct clk_hw *hw)
{
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
void __iomem *np_base = cg->base;
+ unsigned long flags;
u32 val;
+ spin_lock_irqsave(&cg->lock, flags);
val = readl(np_base + REG_PCI_CONTROL);
val &= ~REG_PCI_CONTROL_REFCLK_EN1;
writel(val, np_base + REG_PCI_CONTROL);
+ spin_unlock_irqrestore(&cg->lock, flags);
}
static struct clk_hw *en7523_register_pcie_clk(struct device *dev,
@@ -646,6 +687,7 @@ static struct clk_hw *en7523_register_pcie_clk(struct device *dev,
return NULL;
cg->base = np_base;
+ spin_lock_init(&cg->lock);
cg->hw.init = &init;
if (init.ops->unprepare)
@@ -660,10 +702,15 @@ static struct clk_hw *en7523_register_pcie_clk(struct device *dev,
static int en7581_pci_is_enabled(struct clk_hw *hw)
{
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
+ unsigned long flags;
u32 val, mask;
mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1;
+
+ spin_lock_irqsave(&cg->lock, flags);
val = readl(cg->base + REG_PCI_CONTROL);
+ spin_unlock_irqrestore(&cg->lock, flags);
+
return (val & mask) == mask;
}
@@ -671,11 +718,15 @@ static int en7581_pci_enable(struct clk_hw *hw)
{
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
void __iomem *np_base = cg->base;
+ unsigned long flags;
u32 val, mask;
mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1;
+
+ spin_lock_irqsave(&cg->lock, flags);
val = readl(np_base + REG_PCI_CONTROL);
writel(val | mask, np_base + REG_PCI_CONTROL);
+ spin_unlock_irqrestore(&cg->lock, flags);
return 0;
}
@@ -684,11 +735,16 @@ static void en7581_pci_disable(struct clk_hw *hw)
{
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
void __iomem *np_base = cg->base;
+ unsigned long flags;
u32 val, mask;
mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1;
+
+ spin_lock_irqsave(&cg->lock, flags);
val = readl(np_base + REG_PCI_CONTROL);
writel(val & ~mask, np_base + REG_PCI_CONTROL);
+ spin_unlock_irqrestore(&cg->lock, flags);
+
usleep_range(1000, 2000);
}
@@ -791,18 +847,21 @@ static int en7523_reset_update(struct reset_controller_dev *rcdev,
u32 offset = rst_data->bank_ofs[id / RST_NR_PER_BANK];
void __iomem *addr = rst_data->base + offset;
bool inverted = false;
+ unsigned long flags;
u32 val;
/* For PCIC reset logic is inverted, 0:assert 1:deassert */
if (offset == REG_NP_SCU_PCIC)
inverted = true;
+ spin_lock_irqsave(&rst_data->lock, flags);
val = readl(addr);
if (assert ^ inverted)
val |= BIT(id % RST_NR_PER_BANK);
else
val &= ~BIT(id % RST_NR_PER_BANK);
writel(val, addr);
+ spin_unlock_irqrestore(&rst_data->lock, flags);
return 0;
}
@@ -826,13 +885,17 @@ static int en7523_reset_status(struct reset_controller_dev *rcdev,
u32 offset = rst_data->bank_ofs[id / RST_NR_PER_BANK];
void __iomem *addr = rst_data->base + offset;
bool inverted = false;
+ unsigned long flags;
u32 val;
/* For PCIC reset logic is inverted, 0:assert 1:deassert */
if (offset == REG_NP_SCU_PCIC)
inverted = true;
+ spin_lock_irqsave(&rst_data->lock, flags);
val = readl(addr) & BIT(id % RST_NR_PER_BANK);
+ spin_unlock_irqrestore(&rst_data->lock, flags);
+
return inverted ? !val : !!val;
}
@@ -866,6 +929,7 @@ static int en7581_reset_register(struct device *dev, void __iomem *base,
rst_data->bank_ofs = rst_reg_ofs;
rst_data->idx_map = rst_map;
rst_data->base = base;
+ spin_lock_init(&rst_data->lock);
rst_data->rcdev.nr_resets = nr_resets;
rst_data->rcdev.of_xlate = en7523_reset_xlate;
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v10 4/5] clk: en7523: generalize register clocks function
2026-11-05 12:10 [PATCH v10 0/5] clk: add support for Airoha AN7583 clock Christian Marangi
` (2 preceding siblings ...)
2026-11-05 12:10 ` [PATCH v10 3/5] clk: en7523: protect concurrent access to reset and PCI register Christian Marangi
@ 2026-11-05 12:10 ` Christian Marangi
2026-11-05 12:10 ` [PATCH v10 5/5] clk: en7523: add support for Airoha AN7583 clock Christian Marangi
4 siblings, 0 replies; 8+ messages in thread
From: Christian Marangi @ 2026-11-05 12:10 UTC (permalink / raw)
To: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, Felix Fietkau,
linux-clk, devicetree, linux-kernel
Cc: Christian Marangi
Airoha AN7583 SoC will use the same logic used by Airoha EN7581 SoC to
register clocks. Generalize it to register clocks defined in soc_data.
Add the clocks definition in EN7581 SoC to support this new implementation.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/clk/clk-en7523.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c
index c05d0bfa2340..979dd9c20a4f 100644
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -151,6 +151,7 @@ struct en_clk_priv {
struct en_clk_soc_data {
u32 num_clocks;
+ const struct en_clk_desc *base_clks;
const struct clk_ops pcie_ops;
int (*hw_init)(struct platform_device *pdev,
struct clk_hw_onecell_data *clk_data);
@@ -801,12 +802,15 @@ static int en7523_clk_hw_init(struct platform_device *pdev,
static void en7581_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
struct regmap *map, void __iomem *base)
{
+ const struct en_clk_soc_data *soc_data;
struct clk_hw *hw;
u32 rate;
int i;
- for (i = 0; i < ARRAY_SIZE(en7581_base_clks); i++) {
- const struct en_clk_desc *desc = &en7581_base_clks[i];
+ soc_data = device_get_match_data(dev);
+
+ for (i = 0; i < soc_data->num_clocks - 1; i++) {
+ const struct en_clk_desc *desc = &soc_data->base_clks[i];
u32 val, reg = desc->div_reg ? desc->div_reg : desc->base_reg;
int err;
@@ -1290,6 +1294,7 @@ static const struct en_clk_soc_data en7523_data = {
};
static const struct en_clk_soc_data en7581_data = {
+ .base_clks = en7581_base_clks,
/* We increment num_clocks by 1 to account for additional PCIe clock */
.num_clocks = ARRAY_SIZE(en7581_base_clks) + 1,
.pcie_ops = {
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v10 5/5] clk: en7523: add support for Airoha AN7583 clock
2026-11-05 12:10 [PATCH v10 0/5] clk: add support for Airoha AN7583 clock Christian Marangi
` (3 preceding siblings ...)
2026-11-05 12:10 ` [PATCH v10 4/5] clk: en7523: generalize register clocks function Christian Marangi
@ 2026-11-05 12:10 ` Christian Marangi
2026-11-05 12:25 ` sashiko-bot
4 siblings, 1 reply; 8+ messages in thread
From: Christian Marangi @ 2026-11-05 12:10 UTC (permalink / raw)
To: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, Felix Fietkau,
linux-clk, devicetree, linux-kernel
Cc: Christian Marangi
Add support for Airoha AN7583 clock and reset.
Airoha AN7583 SoC have the same register address of EN7581 but implement
different bits and additional base clocks. Also reset are different with
the introduction of 2 dedicated MDIO line and drop of some reset lines.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/clk/clk-en7523.c | 249 +++++++++++++++++++++++++++++++++++++++
1 file changed, 249 insertions(+)
diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c
index 979dd9c20a4f..c1cc6fbc3c01 100644
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -13,6 +13,7 @@
#include <linux/reset-controller.h>
#include <linux/spinlock.h>
#include <dt-bindings/clock/en7523-clk.h>
+#include <dt-bindings/reset/airoha,an7583-reset.h>
#include <dt-bindings/reset/airoha,en7523-reset.h>
#include <dt-bindings/reset/airoha,en7581-reset.h>
#include <dt-bindings/clock/econet,en751221-scu.h>
@@ -170,6 +171,14 @@ static const u32 crypto_base[] = { 540000000, 480000000 };
static const u32 emmc7581_base[] = { 200000000, 150000000 };
/* EN751221 */
static const u32 gsw751221_base[] = { 500000000, 250000000, 400000000, 200000000 };
+/* AN7583 */
+static const u32 gsw7583_base[] = { 540672000, 270336000, 400000000, 200000000 };
+static const u32 emi7583_base[] = { 540672000, 480000000, 400000000, 300000000 };
+static const u32 bus7583_base[] = { 600000000, 540672000, 480000000, 400000000 };
+static const u32 spi7583_base[] = { 400000000, 12500000 };
+static const u32 npu7583_base[] = { 666000000, 800000000, 720000000, 600000000 };
+static const u32 crypto7583_base[] = { 540672000, 400000000 };
+static const u32 emmc7583_base[] = { 150000000, 200000000 };
static const struct en_clk_desc en7523_base_clks[] = {
{
@@ -372,6 +381,138 @@ static const struct en_clk_desc en7581_base_clks[] = {
}
};
+static const struct en_clk_desc an7583_base_clks[] = {
+ {
+ .id = EN7523_CLK_GSW,
+ .name = "gsw",
+
+ .base_reg = REG_GSW_CLK_DIV_SEL,
+ .base_bits = 2,
+ .base_shift = 8,
+ .base_values = gsw7583_base,
+ .n_base_values = ARRAY_SIZE(gsw7583_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ }, {
+ .id = EN7523_CLK_EMI,
+ .name = "emi",
+
+ .base_reg = REG_EMI_CLK_DIV_SEL,
+ .base_bits = 2,
+ .base_shift = 8,
+ .base_values = emi7583_base,
+ .n_base_values = ARRAY_SIZE(emi7583_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ }, {
+ .id = EN7523_CLK_BUS,
+ .name = "bus",
+
+ .base_reg = REG_BUS_CLK_DIV_SEL,
+ .base_bits = 2,
+ .base_shift = 8,
+ .base_values = bus7583_base,
+ .n_base_values = ARRAY_SIZE(bus7583_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ }, {
+ .id = EN7523_CLK_SLIC,
+ .name = "slic",
+
+ .base_reg = REG_SPI_CLK_FREQ_SEL,
+ .base_bits = 1,
+ .base_shift = 1,
+ .base_values = slic_base,
+ .n_base_values = ARRAY_SIZE(slic_base),
+
+ .div_reg = REG_SPI_CLK_DIV_SEL,
+ .div_bits = 5,
+ .div_shift = 24,
+ .div_val0 = 20,
+ .div_step = 2,
+ }, {
+ .id = EN7523_CLK_SPI,
+ .name = "spi",
+
+ .base_reg = REG_SPI_CLK_FREQ_SEL,
+ .base_bits = 1,
+ .base_shift = 0,
+ .base_values = spi7583_base,
+ .n_base_values = ARRAY_SIZE(spi7583_base),
+
+ .div_reg = REG_SPI_CLK_DIV_SEL,
+ .div_bits = 5,
+ .div_shift = 8,
+ .div_val0 = 40,
+ .div_step = 2,
+ }, {
+ .id = EN7523_CLK_NPU,
+ .name = "npu",
+
+ .base_reg = REG_NPU_CLK_DIV_SEL,
+ .base_bits = 2,
+ .base_shift = 9,
+ .base_values = npu7583_base,
+ .n_base_values = ARRAY_SIZE(npu7583_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ }, {
+ .id = EN7523_CLK_CRYPTO,
+ .name = "crypto",
+
+ .base_reg = REG_CRYPTO_CLKSRC2,
+ .base_bits = 1,
+ .base_shift = 0,
+ .base_values = crypto7583_base,
+ .n_base_values = ARRAY_SIZE(crypto7583_base),
+ }, {
+ .id = EN7581_CLK_EMMC,
+ .name = "emmc",
+
+ .base_reg = REG_CRYPTO_CLKSRC2,
+ .base_bits = 1,
+ .base_shift = 13,
+ .base_values = emmc7583_base,
+ .n_base_values = ARRAY_SIZE(emmc7583_base),
+ }, {
+ .id = AN7583_CLK_MDIO0,
+ .name = "mdio0",
+
+ .base_reg = REG_CRYPTO_CLKSRC2,
+
+ .base_value = 25000000,
+
+ .div_bits = 4,
+ .div_shift = 15,
+ .div_step = 1,
+ .div_offset = 1,
+ }, {
+ .id = AN7583_CLK_MDIO1,
+ .name = "mdio1",
+
+ .base_reg = REG_CRYPTO_CLKSRC2,
+
+ .base_value = 25000000,
+
+ .div_bits = 4,
+ .div_shift = 19,
+ .div_step = 1,
+ .div_offset = 1,
+ }
+};
+
static const u16 en7581_rst_ofs[] = {
REG_RST_CTRL2,
REG_RST_CTRL1,
@@ -547,6 +688,64 @@ static const u16 en751221_rst_map[] = {
[EN751221_USB_PHY_P1_RST] = 3 * RST_NR_PER_BANK + 7,
};
+static const u16 an7583_rst_map[] = {
+ /* RST_CTRL2 */
+ [AN7583_XPON_PHY_RST] = 0,
+ [AN7583_GPON_OLT_RST] = 1,
+ [AN7583_CPU_TIMER2_RST] = 2,
+ [AN7583_HSUART_RST] = 3,
+ [AN7583_UART4_RST] = 4,
+ [AN7583_UART5_RST] = 5,
+ [AN7583_I2C2_RST] = 6,
+ [AN7583_XSI_MAC_RST] = 7,
+ [AN7583_XSI_PHY_RST] = 8,
+ [AN7583_NPU_RST] = 9,
+ [AN7583_TRNG_MSTART_RST] = 12,
+ [AN7583_DUAL_HSI0_RST] = 13,
+ [AN7583_DUAL_HSI1_RST] = 14,
+ [AN7583_DUAL_HSI0_MAC_RST] = 16,
+ [AN7583_DUAL_HSI1_MAC_RST] = 17,
+ [AN7583_XPON_XFI_RST] = 18,
+ [AN7583_WDMA_RST] = 19,
+ [AN7583_WOE0_RST] = 20,
+ [AN7583_HSDMA_RST] = 22,
+ [AN7583_TDMA_RST] = 24,
+ [AN7583_EMMC_RST] = 25,
+ [AN7583_SOE_RST] = 26,
+ [AN7583_XFP_MAC_RST] = 28,
+ [AN7583_MDIO0_RST] = 30,
+ [AN7583_MDIO1_RST] = 31,
+ /* RST_CTRL1 */
+ [AN7583_PCM1_ZSI_ISI_RST] = RST_NR_PER_BANK + 0,
+ [AN7583_FE_PDMA_RST] = RST_NR_PER_BANK + 1,
+ [AN7583_FE_QDMA_RST] = RST_NR_PER_BANK + 2,
+ [AN7583_PCM_SPIWP_RST] = RST_NR_PER_BANK + 4,
+ [AN7583_CRYPTO_RST] = RST_NR_PER_BANK + 6,
+ [AN7583_TIMER_RST] = RST_NR_PER_BANK + 8,
+ [AN7583_PCM1_RST] = RST_NR_PER_BANK + 11,
+ [AN7583_UART_RST] = RST_NR_PER_BANK + 12,
+ [AN7583_GPIO_RST] = RST_NR_PER_BANK + 13,
+ [AN7583_GDMA_RST] = RST_NR_PER_BANK + 14,
+ [AN7583_I2C_MASTER_RST] = RST_NR_PER_BANK + 16,
+ [AN7583_PCM2_ZSI_ISI_RST] = RST_NR_PER_BANK + 17,
+ [AN7583_SFC_RST] = RST_NR_PER_BANK + 18,
+ [AN7583_UART2_RST] = RST_NR_PER_BANK + 19,
+ [AN7583_GDMP_RST] = RST_NR_PER_BANK + 20,
+ [AN7583_FE_RST] = RST_NR_PER_BANK + 21,
+ [AN7583_USB_HOST_P0_RST] = RST_NR_PER_BANK + 22,
+ [AN7583_GSW_RST] = RST_NR_PER_BANK + 23,
+ [AN7583_SFC2_PCM_RST] = RST_NR_PER_BANK + 25,
+ [AN7583_PCIE0_RST] = RST_NR_PER_BANK + 26,
+ [AN7583_PCIE1_RST] = RST_NR_PER_BANK + 27,
+ [AN7583_CPU_TIMER_RST] = RST_NR_PER_BANK + 28,
+ [AN7583_PCIE_HB_RST] = RST_NR_PER_BANK + 29,
+ [AN7583_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
+
+ /* RST_PCIC */
+ [AN7583_PCIC_PERSTOUT0_RST] = 2 * RST_NR_PER_BANK + 29,
+ [AN7583_PCIC_PERSTOUT1_RST] = 2 * RST_NR_PER_BANK + 26,
+};
+
static int en7581_reset_register(struct device *dev, void __iomem *base,
const u16 *rst_map, int nr_resets,
const u16 *rst_reg_ofs);
@@ -1152,6 +1351,43 @@ static int en7581_clk_hw_init(struct platform_device *pdev,
return en7581_serdes_phy_register(&pdev->dev);
}
+static int an7583_clk_hw_init(struct platform_device *pdev,
+ struct clk_hw_onecell_data *clk_data)
+{
+ struct en_clk_priv *priv = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+ struct regmap *map;
+ void __iomem *base;
+ u32 val;
+ int ret;
+
+ map = syscon_regmap_lookup_by_phandle(dev->of_node, "airoha,chip-scu");
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->base = base;
+
+ en7581_register_clocks(dev, clk_data, map, base);
+
+ val = readl(base + REG_RST_CTRL1);
+ val |= REG_PCIE_HB_RST;
+ writel(val, base + REG_RST_CTRL1);
+ val &= ~REG_PCIE_HB_RST;
+ writel(val, base + REG_RST_CTRL1);
+
+ ret = en7581_reset_register(dev, base, an7583_rst_map,
+ ARRAY_SIZE(an7583_rst_map),
+ en7581_rst_ofs);
+ if (ret)
+ return ret;
+
+ return en7581_serdes_phy_register(dev);
+}
+
static enum en_hir get_hw_id(void __iomem *np_base)
{
u32 val = FIELD_GET(REG_HIR_MASK, readl(np_base + REG_HIR));
@@ -1305,6 +1541,18 @@ static const struct en_clk_soc_data en7581_data = {
.hw_init = en7581_clk_hw_init,
};
+static const struct en_clk_soc_data an7583_data = {
+ .base_clks = an7583_base_clks,
+ /* We increment num_clocks by 1 to account for additional PCIe clock */
+ .num_clocks = ARRAY_SIZE(an7583_base_clks) + 1,
+ .pcie_ops = {
+ .is_enabled = en7581_pci_is_enabled,
+ .enable = en7581_pci_enable,
+ .disable = en7581_pci_disable,
+ },
+ .hw_init = an7583_clk_hw_init,
+};
+
static const struct en_clk_soc_data en751221_data = {
.num_clocks = EN751221_MAX_CLKS,
.pcie_ops = {
@@ -1318,6 +1566,7 @@ static const struct en_clk_soc_data en751221_data = {
static const struct of_device_id of_match_clk_en7523[] = {
{ .compatible = "airoha,en7523-scu", .data = &en7523_data },
{ .compatible = "airoha,en7581-scu", .data = &en7581_data },
+ { .compatible = "airoha,an7583-scu", .data = &an7583_data },
{ .compatible = "econet,en751221-scu", .data = &en751221_data },
{ /* sentinel */ }
};
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v10 3/5] clk: en7523: protect concurrent access to reset and PCI register
2026-11-05 12:10 ` [PATCH v10 3/5] clk: en7523: protect concurrent access to reset and PCI register Christian Marangi
@ 2026-11-05 12:22 ` sashiko-bot
0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-11-05 12:22 UTC (permalink / raw)
To: Christian Marangi, linux-clk, devicetree; +Cc: robh, conor+dt
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] clk: en7523: separate spinlocks fail to serialize shared SCU registers
- [Medium] clk: en7523: stale REG_PCI_CONTROL write after sleep in en7523_pci_prepare()
--
commit 5b2603a4978075ae29e211f7115d7f39dfefbc9e
Author: Christian Marangi <ansuelsmth@gmail.com>
clk: en7523: protect concurrent access to reset and PCI register
This commit adds spinlocks to struct en_clk_gate and struct en_rst_data to
serialize concurrent read-modify-write accesses to the PCI control and reset
registers.
> diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c
> index 2baec734df9fe..c05d0bfa23400 100644
> --- a/drivers/clk/clk-en7523.c
> +++ b/drivers/clk/clk-en7523.c
> @@ -123,6 +123,8 @@ struct en_clk_desc {
>
> struct en_clk_gate {
> void __iomem *base;
> + /* protect SCU register */
> + spinlock_t lock;
> struct clk_hw hw;
> };
>
> @@ -130,6 +132,8 @@ struct en_rst_data {
> const u16 *bank_ofs;
> const u16 *idx_map;
> void __iomem *base;
> + /* protect SCU register */
> + spinlock_t lock;
> struct reset_controller_dev rcdev;
> };
[Severity: High]
Since struct en_clk_gate and struct en_rst_data each embed their own separate
spinlock_t instance (initialized independently in en7523_register_pcie_clk()
and en7581_reset_register()), do PCIe clock operations and reset controller
operations still race with each other on the shared SCU registers?
Specifically, both structures point at the same SCU MMIO base and perform
read-modify-write updates on the same physical registers:
- Offset 0x88 (REG_PCI_CONTROL / REG_NP_SCU_PCIC) is modified under
&cg->lock in en7523_pci_prepare(), en7523_pci_unprepare(),
en7581_pci_enable(), and en7581_pci_disable(), while
en7523_reset_update() modifies the same register under &rst_data->lock.
- Offset 0x834 (REG_RESET_CONTROL1 / REG_RST_CTRL1) is modified under
&cg->lock in en7523_pci_prepare(), while en7523_reset_update() modifies
the same register under &rst_data->lock.
Should struct en_clk_gate and struct en_rst_data share a single spinlock (or
a pointer to one) so that concurrent clock and reset operations actually
exclude each other when accessing these shared registers?
> @@ -577,44 +581,78 @@ static u32 en7523_get_div(const struct en_clk_desc *desc, u32 val)
[ ... ]
> static int en7523_pci_prepare(struct clk_hw *hw)
> {
> struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
> void __iomem *np_base = cg->base;
> + unsigned long flags;
> u32 val, mask;
>
> /* Need to pull device low before reset */
> + spin_lock_irqsave(&cg->lock, flags);
> val = readl(np_base + REG_PCI_CONTROL);
> val &= ~(REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT);
> writel(val, np_base + REG_PCI_CONTROL);
> + spin_unlock_irqrestore(&cg->lock, flags);
> +
> usleep_range(1000, 2000);
>
> /* Enable PCIe port 1 */
> + spin_lock_irqsave(&cg->lock, flags);
> val |= REG_PCI_CONTROL_REFCLK_EN1;
> writel(val, np_base + REG_PCI_CONTROL);
> + spin_unlock_irqrestore(&cg->lock, flags);
[Severity: Medium]
In en7523_pci_prepare(), after dropping &cg->lock across usleep_range(1000,
2000) and reacquiring it to set REG_PCI_CONTROL_REFCLK_EN1, could reusing the
cached val without re-reading np_base + REG_PCI_CONTROL overwrite concurrent
changes made to REG_PCI_CONTROL while the lock was released?
The subsequent critical sections in en7523_pci_prepare() re-read the register
after reacquiring &cg->lock, but this block still modifies the local val read
before the sleep.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261105121059.11201-1-ansuelsmth@gmail.com?part=3
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v10 5/5] clk: en7523: add support for Airoha AN7583 clock
2026-11-05 12:10 ` [PATCH v10 5/5] clk: en7523: add support for Airoha AN7583 clock Christian Marangi
@ 2026-11-05 12:25 ` sashiko-bot
0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-11-05 12:25 UTC (permalink / raw)
To: Christian Marangi, linux-clk, devicetree; +Cc: robh, conor+dt
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] clk: en7523: sleeping in atomic context in en7581_pci_disable()
- [High] clk: en7523: separate spinlocks fail to serialize shared SCU registers
- [High] clk: en7523: AN7583 MDIO clocks registered as fixed-rate clocks
--
commit 0c38944a68dcbbf6c296bc45b4d9669bdee653fb
Author: Christian Marangi <ansuelsmth@gmail.com>
clk: en7523: add support for Airoha AN7583 clock
This commit adds clock and reset controller support for the Airoha AN7583
SoC, including its base clock descriptors, MDIO clocks, and reset line
mappings.
> diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c
> index 979dd9c20a4f2..c1cc6fbc3c019 100644
> --- a/drivers/clk/clk-en7523.c
> +++ b/drivers/clk/clk-en7523.c
[ ... ]
> @@ -372,6 +381,138 @@ static const struct en_clk_desc en7581_base_clks[] = {
> }
> };
>
> +static const struct en_clk_desc an7583_base_clks[] = {
[ ... ]
> + }, {
> + .id = AN7583_CLK_MDIO0,
> + .name = "mdio0",
> +
> + .base_reg = REG_CRYPTO_CLKSRC2,
> +
> + .base_value = 25000000,
> +
> + .div_bits = 4,
> + .div_shift = 15,
> + .div_step = 1,
> + .div_offset = 1,
> + }, {
> + .id = AN7583_CLK_MDIO1,
> + .name = "mdio1",
> +
> + .base_reg = REG_CRYPTO_CLKSRC2,
> +
> + .base_value = 25000000,
> +
> + .div_bits = 4,
> + .div_shift = 19,
> + .div_step = 1,
> + .div_offset = 1,
> + }
> +};
[Severity: High]
Can AN7583_CLK_MDIO0 and AN7583_CLK_MDIO1 work as intended when registered
via en7581_register_clocks()?
In drivers/clk/clk-en7523.c, an7583_clk_hw_init() calls
en7581_register_clocks(), which reads the initial hardware register value
at probe time and registers every clock in soc_data->base_clks with
devm_clk_hw_register_fixed_rate():
hw = devm_clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
However, in drivers/net/mdio/mdio-airoha.c, airoha_mdio_probe() calls
clk_set_rate(priv->clk, freq) to divide the 25 MHz default MDIO clock down
to 2.5 MHz. Since clk_fixed_rate_ops does not implement .set_rate,
.round_rate, or .determine_rate, clk_set_rate() will return 0 without
programming the 4-bit divider in REG_CRYPTO_CLKSRC2, leaving the MDIO bus
clock running at its 25 MHz boot default. Should the MDIO clocks implement
clockops that support setting the divider rate?
> static const u16 en7581_rst_ofs[] = {
[ ... ]
> @@ -1152,6 +1351,43 @@ static int en7581_clk_hw_init(struct platform_device *pdev,
> return en7581_serdes_phy_register(&pdev->dev);
> }
>
> +static int an7583_clk_hw_init(struct platform_device *pdev,
> + struct clk_hw_onecell_data *clk_data)
> +{
[ ... ]
> + en7581_register_clocks(dev, clk_data, map, base);
> +
> + val = readl(base + REG_RST_CTRL1);
> + val |= REG_PCIE_HB_RST;
> + writel(val, base + REG_RST_CTRL1);
> + val &= ~REG_PCIE_HB_RST;
> + writel(val, base + REG_RST_CTRL1);
> +
> + ret = en7581_reset_register(dev, base, an7583_rst_map,
> + ARRAY_SIZE(an7583_rst_map),
> + en7581_rst_ofs);
> + if (ret)
> + return ret;
[Severity: High]
As reported by Sashiko on v6 [1], do cg->lock and rst_data->lock fail to
serialize concurrent read-modify-write accesses to the shared SCU registers?
In drivers/clk/clk-en7523.c, an7583_clk_hw_init() registers the PCIe clock
via en7581_register_clocks() -> en7523_register_pcie_clk() (which allocates
struct en_clk_gate with its own cg->lock) and registers the reset controller
via en7581_reset_register() (which allocates struct en_rst_data with a
separate rst_data->lock) over the same MMIO base.
In an7583_rst_map, AN7583_PCIC_PERSTOUT0_RST and AN7583_PCIC_PERSTOUT1_RST
map to bank 2 of en7581_rst_ofs, which is REG_NP_SCU_PCIC (offset 0x88).
Asserting or deasserting these resets in en7523_reset_update() performs a
readl()/writel() read-modify-write on base + 0x88 under rst_data->lock:
spin_lock_irqsave(&rst_data->lock, flags);
val = readl(addr);
if (assert ^ inverted)
val |= BIT(id % RST_NR_PER_BANK);
else
val &= ~BIT(id % RST_NR_PER_BANK);
writel(val, addr);
spin_unlock_irqrestore(&rst_data->lock, flags);
At the same time, en7581_pci_enable() and en7581_pci_disable() perform a
readl()/writel() read-modify-write on the same physical register
REG_PCI_CONTROL (offset 0x88) under cg->lock:
spin_lock_irqsave(&cg->lock, flags);
val = readl(np_base + REG_PCI_CONTROL);
writel(val | mask, np_base + REG_PCI_CONTROL);
spin_unlock_irqrestore(&cg->lock, flags);
Similarly, on EN7523 and EN751221, en7523_pci_prepare() modifies
REG_RESET_CONTROL1 (offset 0x834) and REG_PCI_CONTROL (offset 0x88) under
cg->lock, while en7523_reset_update() modifies REG_RST_CTRL1 (offset 0x834)
under rst_data->lock. In addition, in en7523_pci_prepare(), after releasing
cg->lock and sleeping in usleep_range(1000, 2000), the code re-acquires
cg->lock and writes back the cached val without re-reading REG_PCI_CONTROL:
spin_lock_irqsave(&cg->lock, flags);
val |= REG_PCI_CONTROL_REFCLK_EN1;
writel(val, np_base + REG_PCI_CONTROL);
spin_unlock_irqrestore(&cg->lock, flags);
Because cg->lock and rst_data->lock are separate spinlock_t instances, can
concurrent clock and reset operations race and overwrite each other's bit
updates in 0x88 and 0x834?
[ ... ]
> @@ -1305,6 +1541,18 @@ static const struct en_clk_soc_data en7581_data = {
> .hw_init = en7581_clk_hw_init,
> };
>
> +static const struct en_clk_soc_data an7583_data = {
> + .base_clks = an7583_base_clks,
> + /* We increment num_clocks by 1 to account for additional PCIe clock */
> + .num_clocks = ARRAY_SIZE(an7583_base_clks) + 1,
> + .pcie_ops = {
> + .is_enabled = en7581_pci_is_enabled,
> + .enable = en7581_pci_enable,
> + .disable = en7581_pci_disable,
> + },
> + .hw_init = an7583_clk_hw_init,
> +};
[Severity: High]
As reported by Sashiko on v6 [1], does wiring en7581_pci_disable() to
.disable in an7583_data cause sleeping in atomic context when the PCIe
clock is disabled?
When a consumer calls clk_disable() or clk_disable_unprepare() on
EN7523_CLK_PCIE, the Common Clock Framework holds enable_lock via
spin_lock_irqsave() in clk_core_disable_lock() and calls
core->ops->disable(core->hw).
In drivers/clk/clk-en7523.c, en7581_pci_disable() calls usleep_range()
while enable_lock is held with interrupts disabled:
spin_lock_irqsave(&cg->lock, flags);
val = readl(np_base + REG_PCI_CONTROL);
writel(val & ~mask, np_base + REG_PCI_CONTROL);
spin_unlock_irqrestore(&cg->lock, flags);
usleep_range(1000, 2000);
Should this sleep be moved to an .unprepare callback (which runs under the
sleepable prepare_lock mutex, as in en7523_data and en751221_data), or use
a non-sleeping delay such as udelay()?
[1] https://lore.kernel.org/r/20260819222743.5044F1F000E9@smtp.kernel.org
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261105121059.11201-1-ansuelsmth@gmail.com?part=5
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-11-05 12:25 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-05 12:10 [PATCH v10 0/5] clk: add support for Airoha AN7583 clock Christian Marangi
2026-11-05 12:10 ` [PATCH v10 1/5] dt-bindings: clock: airoha: Document support for " Christian Marangi
2026-11-05 12:10 ` [PATCH v10 2/5] clk: en7523: use devm variant for clk_hw_register and fixed clock Christian Marangi
2026-11-05 12:10 ` [PATCH v10 3/5] clk: en7523: protect concurrent access to reset and PCI register Christian Marangi
2026-11-05 12:22 ` sashiko-bot
2026-11-05 12:10 ` [PATCH v10 4/5] clk: en7523: generalize register clocks function Christian Marangi
2026-11-05 12:10 ` [PATCH v10 5/5] clk: en7523: add support for Airoha AN7583 clock Christian Marangi
2026-11-05 12:25 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox