clk: add support for Airoha AN7583 clock
Subsystems (3)
v6 cover clk: add support for Airoha AN7583 clock
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 v6:
- Address bot suggestion for DT patch
- Add further information on chip-scu phandle
- Add dedicated PERSTOUT reset and PCIE_HB reset
Changes v5:
- Rebase on top of linux-next
- Drop even more patch to reduce patch delta
- Make chip-scu specific to AN7583
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
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 (3):
dt-bindings: clock: airoha: Document support for AN7583 clock
clk: en7523: generalize register clocks function
clk: en7523: add support for Airoha AN7583 clock
.../bindings/clock/airoha,en7523-scu.yaml | 20 ++ drivers/clk/clk-en7523.c | 250 +++++++++++++++++- include/dt-bindings/clock/en7523-clk.h | 3 + .../dt-bindings/reset/airoha,an7583-reset.h | 65 +++++ 4 files changed, 336 insertions(+), 2 deletions(-) create mode 100644 include/dt-bindings/reset/airoha,an7583-reset.h
Signature · 1 line
2.53.0
PATCH v6 1/3 dt-bindings: clock: airoha: Document support for AN7583 clock
Document support for Airoha AN7583 clock. This is based on the EN7523 clock schema with the new requirement of the "airoha,chip-scu".
Add additional binding for additional clock and reset lines.
--- .../bindings/clock/airoha,en7523-scu.yaml | 20 ++++++ include/dt-bindings/clock/en7523-clk.h | 3 + .../dt-bindings/reset/airoha,an7583-reset.h | 65 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 include/dt-bindings/reset/airoha,an7583-reset.h
Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +20 -0
@@ -30,6 +30,7 @@ properties: compatible: items: - enum: + - airoha,an7583-scu - airoha,en7523-scu - airoha,en7581-scu - econet,en751221-scu
@@ -50,12 +51,30 @@ properties: description: ID of the controller reset line 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: + required: + - airoha,chip-scu + + else: + properties: + airoha,chip-scu: false + - if: properties: compatible:
@@ -69,6 +88,7 @@ allOf: properties: compatible: enum: + - airoha,an7583-scu - airoha,en7581-scu - econet,en751221-scu then:
include/dt-bindings/clock/en7523-clk.h +3 -0
@@ -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_ */
include/dt-bindings/reset/airoha,an7583-reset.h new file +65 -0
65 lines not on this page · raw message
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v6 1/3] dt-bindings: clock: airoha: Document support for AN7583 clock
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Medium] The device tree binding defines the SCU as a reset provider but omits #reset-cells from the required properties list. --
--- Patch [1]: [PATCH v6 1/3] dt-bindings: clock: airoha: Document support for AN7583 clock --- commit d5f1a3bf6c2e7155e5e00666d8f07ae07a173ed5
Author: Christian Marangi <[email protected]>
dt-bindings: clock: airoha: Document support for AN7583 clock
This commit documents support for the Airoha AN7583 clock, building upon the EN7523 clock schema. It introduces a new requirement for airoha,chip-scu and adds supplementary bindings for additional clock and reset lines.
Quoted 4 lines
Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +0
-0
[ ... ]
Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml properties: · line 62
Quoted 13 lines
Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +5
-0@@ -50,12 +51,30 @@ properties: description: ID of the controller reset line 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'
[Severity: Medium]
This is a pre-existing issue, but since the binding defines the SCU as a reset provider and this patch adds dedicated reset definitions, should #reset-cells be included in this global required list?
Without it, device tree nodes using the airoha,an7583-scu compatible string (or other variants in this binding) that omit #reset-cells will incorrectly pass schema validation, potentially allowing incomplete device trees to cause runtime failures in dependent drivers.
Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml properties: · line 72
Quoted 10 lines
Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +8
-0allOf: + - if: + properties: + compatible: + const: airoha,an7583-scu + + then: + required: + - airoha,chip-scu
[Severity: Medium]
This is a pre-existing issue regarding reset providers in this file, but if #reset-cells is not meant to be globally required for all compatibles, should it be added to this conditional required list specifically for airoha,an7583-scu alongside airoha,chip-scu?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Re: [PATCH v6 1/3] dt-bindings: clock: airoha: Document support for AN7583 clock
In reply to Christian MarangiQuoted 26 lines · Christian Marangi
Document support for Airoha AN7583 clock. This is based on the EN7523 clock schema with the new requirement of the "airoha,chip-scu".
Add additional binding for additional clock and reset lines.
Signed-off-by Christian Marangi <[email protected]>--- .../bindings/clock/airoha,en7523-scu.yaml | 20 ++++++ include/dt-bindings/clock/en7523-clk.h | 3 + .../dt-bindings/reset/airoha,an7583-reset.h | 65 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 include/dt-bindings/reset/airoha,an7583-reset.hDocumentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +1
-0@@ -30,6 +30,7 @@ properties: compatible: items: - enum: + - airoha,an7583-scu - airoha,en7523-scu - airoha,en7581-scu - econet,en751221-scu
Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml properties: · line 57
Quoted 7 lines
Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +4
-0@@ -50,12 +51,30 @@ properties: description: ID of the controller reset line 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.
This is the clock provider. Clock provider should not be accessing registers of other device to configure its clocks. Either you misrepresented clock hierarchy or devices.
I did search for DTS to try to understand the big pictuer - nothing, no results, no upstream submission to Linux kernel.
Best regards,
Krzysztof
Re: [PATCH v6 1/3] dt-bindings: clock: airoha: Document support for AN7583 clock
Quoted 39 lines · Krzysztof Kozlowski
Quoted 26 lines · Christian Marangi
Document support for Airoha AN7583 clock. This is based on the EN7523 clock schema with the new requirement of the "airoha,chip-scu".
Add additional binding for additional clock and reset lines.
Signed-off-by Christian Marangi <[email protected]>--- .../bindings/clock/airoha,en7523-scu.yaml | 20 ++++++ include/dt-bindings/clock/en7523-clk.h | 3 + .../dt-bindings/reset/airoha,an7583-reset.h | 65 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 include/dt-bindings/reset/airoha,an7583-reset.hDocumentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +1
-0@@ -30,6 +30,7 @@ properties: compatible: items: - enum: + - airoha,an7583-scu - airoha,en7523-scu - airoha,en7581-scu - econet,en751221-scuDocumentation/devicetree/bindings/clock/airoha,en7523-scu.yaml properties: · line 57
Quoted 7 lines
Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +4
-0@@ -50,12 +51,30 @@ properties: description: ID of the controller reset line 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.This is the clock provider. Clock provider should not be accessing registers of other device to configure its clocks. Either you misrepresented clock hierarchy or devices.
Quoted 3 lines
I did search for DTS to try to understand the big pictuer - nothing, no results, no upstream submission to Linux kernel.
Hi, you can use en7581 as an example as the implementation is exactly the same register wise.
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.
There was a similar phandle in another series adding support for pinctrl for econet EN7528.
This phandle is not present for en7581 just because it's hidden by a direct call to the syscon with syscon_regmap_lookup_by_compatible API.
With AN7583 I'm trying to fix this by making it more explicit.
Does this makes the situation more clear?
Signature · 1 line
Ansuel
Re: [PATCH v6 1/3] dt-bindings: clock: airoha: Document support for AN7583 clock
Quoted 62 lines · Christian Marangi
Quoted 39 lines · Krzysztof Kozlowski
Quoted 26 lines · Christian Marangi
Document support for Airoha AN7583 clock. This is based on the EN7523 clock schema with the new requirement of the "airoha,chip-scu".
Add additional binding for additional clock and reset lines.
Signed-off-by Christian Marangi <[email protected]>--- .../bindings/clock/airoha,en7523-scu.yaml | 20 ++++++ include/dt-bindings/clock/en7523-clk.h | 3 + .../dt-bindings/reset/airoha,an7583-reset.h | 65 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 include/dt-bindings/reset/airoha,an7583-reset.hDocumentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +1
-0@@ -30,6 +30,7 @@ properties: compatible: items: - enum: + - airoha,an7583-scu - airoha,en7523-scu - airoha,en7581-scu - econet,en751221-scuDocumentation/devicetree/bindings/clock/airoha,en7523-scu.yaml properties: · line 57
Quoted 7 lines
Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +4
-0@@ -50,12 +51,30 @@ properties: description: ID of the controller reset line 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.This is the clock provider. Clock provider should not be accessing registers of other device to configure its clocks. Either you misrepresented clock hierarchy or devices.
Quoted 3 lines
I did search for DTS to try to understand the big pictuer - nothing, no results, no upstream submission to Linux kernel.
Hi, you can use en7581 as an example as the implementation is exactly the same register wise.
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.
There was a similar phandle in another series adding support for pinctrl for econet EN7528.
Quoted 7 lines
This phandle is not present for en7581 just because it's hidden by a direct call to the syscon with
syscon_regmap_lookup_by_compatibleAPI.With AN7583 I'm trying to fix this by making it more explicit.
Does this makes the situation more clear?
Hi, I would like to send a new revision of this since the clock driver needs to be rebased.
Any hint on this, is the syscon phandle OK after the above explainations?
Signature · 1 line
Ansuel
PATCH v6 2/3 clk: en7523: generalize register clocks function
In reply to Christian MarangiAiroha 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.
--- drivers/clk/clk-en7523.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/clk/clk-en7523.c +7 -2
@@ -116,6 +116,7 @@ struct en_rst_data {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);
@@ -714,12 +715,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;
@@ -1014,6 +1018,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 = {
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v6 2/3] clk: en7523: generalize register clocks function
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [Medium] Fragile loop boundary logic using num_clocks - 1 risks out-of-bounds array access.
Pre-existing issues:
- [High] The PCIe clock gate is registered with an unmanaged API, leading to a Use-After-Free if probe fails.
- [High] Missing spinlock in reset controller update leads to data races and lost writes. --
--- Patch [2]: [PATCH v6 2/3] clk: en7523: generalize register clocks function --- commit c89fd9565e1664803408c338e740e001e5bb4ff0
Author: Christian Marangi <[email protected]>
clk: en7523: generalize register clocks function
This commit generalizes the clock registration logic for the EN7581 SoC so it can be reused by the upcoming AN7583 SoC. It achieves this by moving the base clocks array definition into the soc_data structure.
Quoted 4 lines
drivers/clk/clk-en7523.c +0
-0
[ ... ]
Quoted 5 lines
drivers/clk/clk-en7523.c +1
-0@@ -711,12 +712,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;
drivers/clk/clk-en7523.c static int en7523_clk_hw_init(struct platform_device *pdev, · line 723
Quoted 10 lines
drivers/clk/clk-en7523.c +4
-2struct 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];
[Severity: Medium]
If a future SoC defines a clock provider count (num_clocks) that doesn't exactly equal the number of elements in base_clks plus one, could this loop iterate past the end of the base_clks array?
It seems this loop derives the base_clks array length from soc_data->num_clocks - 1, mathematically conflating the total clock count with the base clock array size.
While reviewing this, I noticed a couple of pre-existing issues in the same file:
drivers/clk/clk-en7523.c:en7523_register_pcie_clk() {
...
cg = devm_kzalloc(dev, sizeof(*cg), GFP_KERNEL);
if (!cg)
return NULL;
...
if (clk_hw_register(dev, &cg->hw))
return NULL;
...
}[Severity: High]
This is a pre-existing issue, but since the clock gate structure is allocated using devres, won't it be automatically freed if probe fails?
Because the clock is registered with the non-managed clk_hw_register() API, if a downstream operation during probe fails, the driver's probe will return an error and trigger devres cleanup. Could this leave a dangling pointer inside the Common Clock Framework and lead to a Use-After-Free?
drivers/clk/clk-en7523.c:en7523_reset_update() {
...
val = readl(addr);
if (assert)
val |= BIT(id % RST_NR_PER_BANK);
else
val &= ~BIT(id % RST_NR_PER_BANK);
writel(val, addr);
...
}[Severity: High]
This isn't a bug introduced by this patch, but is it safe to perform this read-modify-write operation on a shared register without a spinlock?
The reset core does not serialize .assert and .deassert operations, so if multiple consumer drivers concurrently assert or deassert resets within the same 32-bit register bank, it seems this unprotected read-modify-write could lead to data races and lost writes.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Re: [PATCH v6 2/3] clk: en7523: generalize register clocks function
In reply to Christian MarangiHi Christian,
Quoted 15 lines · 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 <[email protected]>--- drivers/clk/clk-en7523.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)drivers/clk/clk-en7523.c +0
-0
drivers/clk/clk-en7523.c struct en_rst_data { · line 119
Quoted 4 lines
drivers/clk/clk-en7523.c +1
-0@@ -116,6 +116,7 @@ struct en_rst_data {struct en_clk_soc_data {u32 num_clocks; +const struct en_clk_desc *base_clks;
What do you think about adding a num_base_clks member as well to avoid the soc_data->num_clocks - 1 below?
Brian
Quoted 32 lines
drivers/clk/clk-en7523.c +6
-2const struct clk_ops pcie_ops;int (*hw_init)(struct platform_device *pdev,struct clk_hw_onecell_data *clk_data);@@ -714,12 +715,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;@@ -1014,6 +1018,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 = {Signature · 1 line
2.53.0
PATCH v6 3/3 clk: en7523: add support for Airoha AN7583 clock
In reply to Christian MarangiAdd 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.
--- drivers/clk/clk-en7523.c | 241 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+)
drivers/clk/clk-en7523.c +241 -0
@@ -10,6 +10,7 @@#include <linux/regmap.h> #include <linux/reset-controller.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>
@@ -135,6 +136,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[] = { {
@@ -337,6 +346,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 ,
@@ -512,6 +653,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);
@@ -885,6 +1084,35 @@ static int en7581_clk_hw_init(struct platform_device *pdev, en7581_rst_ofs); } +static int an7583_clk_hw_init (struct platform_device *pdev, +struct clk_hw_onecell_data *clk_data) +{ +struct device *dev = &pdev->dev; +struct regmap *map; +void __iomem *base; +u32 val; + + 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); + +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 ); + +return en7581_reset_register (dev, base, an7583_rst_map, +ARRAY_SIZE (an7583_rst_map), + en7581_rst_ofs); +} +static enum en_hir get_hw_id (void __iomem *np_base) {u32 val =FIELD_GET (REG_HIR_MASK ,readl (np_base +REG_HIR ));
@@ -1029,6 +1257,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 = {
@@ -1042,6 +1282,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 */ } };
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v6 3/3] clk: en7523: add support for Airoha AN7583 clock
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [Critical] The macro REG_PCIE_HB_RST is used but never defined, causing a build failure.
- [High] Requesting PCIC resets on AN7583 causes an out-of-bounds read on the en7581_rst_ofs array, leading to undefined hardware behavior or memory corruption.
Pre-existing issues:
- [High] Probe error paths cause a use-after-free by mixing devm_kzalloc with non-devres clk_hw_register() for the PCIe clock.
- [High] Read-modify-write operations on shared registers in the reset and clock controllers lack spinlocks, causing data races and lost writes.
- [High] The clock .disable callback calls usleep_range(), which sleeps while holding an IRQ-disabled spinlock.
--
--- Patch [3]: [PATCH v6 3/3] clk: en7523: add support for Airoha AN7583 clock --- commit e4983d60cb386b35f51bc20a5f0912039bf92780
Author: Christian Marangi <[email protected]>
clk: en7523: add support for Airoha AN7583 clock
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.
Quoted 12 lines
drivers/clk/clk-en7523.c +4
-0@@ -505,6 +646,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 ,
[ ... ]
drivers/clk/clk-en7523.c static const u16 en751221_rst_map[] = { · line 712
Quoted 4 lines
drivers/clk/clk-en7523.c +4
-0+ /* RST_PCIC */ + [AN7583_PCIC_PERSTOUT0_RST] = 2 * RST_NR_PER_BANK + 29, + [AN7583_PCIC_PERSTOUT1_RST] = 2 * RST_NR_PER_BANK + 26, +};
[Severity: High]
Does this out-of-bounds array access corrupt memory when requesting PCIC resets?
The an7583_rst_map defines these PCIC resets in bank index 2.
When en7581_reset_register() is called later in this patch, it is passed the en7581_rst_ofs array:
static const u16 en7581_rst_ofs[] = {
REG_RST_CTRL2,
REG_RST_CTRL1,
};Since en7581_rst_ofs only has 2 elements, when en7523_reset_update() dynamically calculates the bank index via id / RST_NR_PER_BANK, it evaluates to 2. Accessing bank_ofs[2] will read out of bounds.
[ ... ]
Quoted 7 lines
drivers/clk/clk-en7523.c +7
-0+static int an7583_clk_hw_init (struct platform_device *pdev, +struct clk_hw_onecell_data *clk_data) +{ +struct device *dev = &pdev->dev; +struct regmap *map; +void __iomem *base; +u32 val;
drivers/clk/clk-en7523.c static int en7581_clk_hw_init(struct platform_device *pdev, · line 1103
Quoted 10 lines
drivers/clk/clk-en7523.c +10
-0+ + 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); + +en7581_register_clocks (dev, clk_data, map, base);
[Severity: High]
This isn't a bug introduced by this patch, but does the probe error path leave us with a use-after-free for the PCIe clock?
In en7523_register_pcie_clk() which is called by en7581_register_clocks(), the clk_hw structure is allocated via devm_kzalloc(), but registered with the non-devres clk_hw_register():
cg = devm_kzalloc(dev, sizeof(*cg), GFP_KERNEL); ... if (clk_hw_register(dev, &cg->hw))
If a subsequent initialization step fails in en7523_clk_probe() (like hw_init returning an error), the driver core automatically frees the memory via devres, but the clock framework retains dangling pointers to the freed clk_hw.
drivers/clk/clk-en7523.c static int en7581_clk_hw_init(struct platform_device *pdev, · line 1106
Quoted 3 lines
drivers/clk/clk-en7523.c +3
-0+ + val =readl (base +REG_RST_CTRL1 ); + val |=REG_PCIE_HB_RST ;
[Severity: Critical]
Will this break the build due to an undefined macro?
The REG_PCIE_HB_RST macro is not defined anywhere. The existing code seems to use REG_RESET_CONTROL_PCIEHB for this bit instead.
[Severity: High]
This is a pre-existing issue, but could this unlocked read-modify-write race with the reset framework?
en7523_pci_prepare() modifies REG_RESET_CONTROL1 (0x834) without any locks:
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);
Concurrently, en7523_reset_update() performs an unlocked read-modify-write on the same register (REG_RST_CTRL1 is also 0x834):
val = readl(addr); if (assert) val |= BIT(id % RST_NR_PER_BANK); ... writel(val, addr);
Since .prepare() runs in process context and resets can be triggered by other probing devices concurrently, this seems likely to cause lost writes.
Quoted 8 lines
drivers/clk/clk-en7523.c +8
-0+writel (val, base +REG_RST_CTRL1 ); + val &= ~REG_PCIE_HB_RST ; +writel (val, base +REG_RST_CTRL1 ); + +return en7581_reset_register (dev, base, an7583_rst_map, +ARRAY_SIZE (an7583_rst_map), + en7581_rst_ofs); +}
[ ... ]
drivers/clk/clk-en7523.c static const struct en_clk_soc_data en7581_data = { · line 1268
Quoted 9 lines
drivers/clk/clk-en7523.c +9
-0+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, + },
[Severity: High]
This isn't a bug introduced by this patch, but does mapping en7581_pci_disable to the .disable callback result in sleeping while in an atomic context?
The core clock framework invokes .disable callbacks with the enable_lock spinlock held and hardware interrupts disabled.
However, en7581_pci_disable() explicitly yields and sleeps:
writel(val & ~mask, np_base + REG_PCI_CONTROL); usleep_range(1000, 2000);
Could this cause a scheduling while atomic panic when the PCIe clock is disabled?
Quoted 2 lines
drivers/clk/clk-en7523.c +2
-0+ .hw_init = an7583_clk_hw_init, +};
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Re: [PATCH v6 3/3] clk: en7523: add support for Airoha AN7583 clock
Quoted 6 lines · On Wed, Aug 19, 2026 at 10:27:42PM +0000, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [Critical] The macroREG_PCIE_HB_RSTis used but never defined, causing a build failure.
- [High] Requesting PCIC resets on AN7583 causes an out-of-bounds read on theen7581_rst_ofsarray, leading to undefined hardware behavior or memory corruption.
For reference, it seems the bot applied the patch to the wrong branch. The reported problems from the bot are not valid as those changes were introduced by the last 2 patch present in linux-next and clk-next.
Code was compiled and tested with those 2 changes included.
Quoted 160 lines
Pre-existing issues:
- [High] Probe error paths cause a use-after-free by mixingdevm_kzallocwith non-devresclk_hw_register()for the PCIe clock.
- [High] Read-modify-write operations on shared registers in the reset and clock controllers lack spinlocks, causing data races and lost writes.
- [High] The clock.disablecallback callsusleep_range(), which sleeps while holding an IRQ-disabled spinlock.
----- Patch [3]: [PATCH v6 3/3] clk: en7523: add support for Airoha AN7583 clock --- commit
e4983d60cb386b35f51bc20a5f0912039bf92780
Author: Christian Marangi <[email protected]>clk: en7523: add support for Airoha AN7583 clock
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.
Quoted 12 lines
drivers/clk/clk-en7523.c +4
-0@@ -505,6 +646,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 ,[ ... ]
drivers/clk/clk-en7523.c static const u16 en751221_rst_map[] = { · line 712
Quoted 4 lines
drivers/clk/clk-en7523.c +4
-0+ /* RST_PCIC */ + [AN7583_PCIC_PERSTOUT0_RST] = 2 * RST_NR_PER_BANK + 29, + [AN7583_PCIC_PERSTOUT1_RST] = 2 * RST_NR_PER_BANK + 26, +};[Severity: High]
Does this out-of-bounds array access corrupt memory when requesting PCIC resets?The
an7583_rst_mapdefines these PCIC resets in bank index 2.When
en7581_reset_register()is called later in this patch, it is passed theen7581_rst_ofsarray:static const u16 en7581_rst_ofs[] = { REG_RST_CTRL2, REG_RST_CTRL1, };Since
en7581_rst_ofsonly has 2 elements, whenen7523_reset_update()dynamically calculates the bank index via id /RST_NR_PER_BANK, it evaluates to 2. Accessing bank_ofs[2] will read out of bounds.[ ... ]
Quoted 7 lines
drivers/clk/clk-en7523.c +7
-0+static int an7583_clk_hw_init (struct platform_device *pdev, +struct clk_hw_onecell_data *clk_data) +{ +struct device *dev = &pdev->dev; +struct regmap *map; +void __iomem *base; +u32 val;drivers/clk/clk-en7523.c static int en7581_clk_hw_init(struct platform_device *pdev, · line 1103
Quoted 10 lines
drivers/clk/clk-en7523.c +10
-0+ + 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); + +en7581_register_clocks (dev, clk_data, map, base);[Severity: High]
This isn't a bug introduced by this patch, but does the probe error path leave us with a use-after-free for the PCIe clock?In
en7523_register_pcie_clk()which is called byen7581_register_clocks(), theclk_hwstructure is allocated viadevm_kzalloc(), but registered with the non-devresclk_hw_register():cg = devm_kzalloc(dev, sizeof(*cg), GFP_KERNEL); ... if (clk_hw_register(dev, &cg->hw))If a subsequent initialization step fails in
en7523_clk_probe()(likehw_initreturning an error), the driver core automatically frees the memory via devres, but the clock framework retains dangling pointers to the freedclk_hw.drivers/clk/clk-en7523.c static int en7581_clk_hw_init(struct platform_device *pdev, · line 1106
Quoted 3 lines
drivers/clk/clk-en7523.c +3
-0+ + val =readl (base +REG_RST_CTRL1 ); + val |=REG_PCIE_HB_RST ;[Severity: Critical]
Will this break the build due to an undefined macro?The
REG_PCIE_HB_RSTmacro is not defined anywhere. The existing code seems to useREG_RESET_CONTROL_PCIEHBfor this bit instead.[Severity: High]
This is a pre-existing issue, but could this unlocked read-modify-write race with the reset framework?
en7523_pci_prepare()modifiesREG_RESET_CONTROL1(0x834) without any locks: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);Concurrently,
en7523_reset_update()performs an unlocked read-modify-write on the same register (REG_RST_CTRL1is also0x834):val = readl(addr); if (assert) val |= BIT(id % RST_NR_PER_BANK); ... writel(val, addr);Since .prepare() runs in process context and resets can be triggered by other probing devices concurrently, this seems likely to cause lost writes.
Quoted 8 lines
drivers/clk/clk-en7523.c +8
-0+writel (val, base +REG_RST_CTRL1 ); + val &= ~REG_PCIE_HB_RST ; +writel (val, base +REG_RST_CTRL1 ); + +return en7581_reset_register (dev, base, an7583_rst_map, +ARRAY_SIZE (an7583_rst_map), + en7581_rst_ofs); +}[ ... ]
drivers/clk/clk-en7523.c static const struct en_clk_soc_data en7581_data = { · line 1268
Quoted 9 lines
drivers/clk/clk-en7523.c +9
-0+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, + },[Severity: High]
This isn't a bug introduced by this patch, but does mappingen7581_pci_disableto the .disable callback result in sleeping while in an atomic context?The core clock framework invokes .disable callbacks with the
enable_lockspinlock held and hardware interrupts disabled.However,
en7581_pci_disable()explicitly yields and sleeps:writel(val & ~mask, np_base + REG_PCI_CONTROL); usleep_range(1000, 2000);Could this cause a scheduling while atomic panic when the PCIe clock is disabled?
Quoted 2 lines
drivers/clk/clk-en7523.c +2
-0+ .hw_init = an7583_clk_hw_init, +};Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Signature · 1 line
Ansuel