* [PATCH 0/2] clk: en7523: Add support for selecting SCU serdes
@ 2026-07-24 18:43 Christian Marangi
2026-07-24 18:43 ` [PATCH 1/2] dt-bindings: clock: airoha: Add PHY binding for Serdes port Christian Marangi
2026-07-24 18:43 ` [PATCH 2/2] clk: en7523: Add support for selecting the Serdes port in SCU Christian Marangi
0 siblings, 2 replies; 5+ messages in thread
From: Christian Marangi @ 2026-07-24 18:43 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Marangi,
Felix Fietkau, linux-clk, devicetree, linux-kernel
This small series is a split from the Airoha AN7581 USB PHY series [1].
[1] https://lore.kernel.org/all/20260702093812.15918-1-ansuelsmth@gmail.com/
Christian Marangi (2):
dt-bindings: clock: airoha: Add PHY binding for Serdes port
clk: en7523: Add support for selecting the Serdes port in SCU
.../bindings/clock/airoha,en7523-scu.yaml | 24 +-
drivers/clk/Kconfig | 1 +
drivers/clk/clk-en7523.c | 218 +++++++++++++++++-
include/dt-bindings/soc/airoha,scu-ssr.h | 11 +
4 files changed, 248 insertions(+), 6 deletions(-)
create mode 100644 include/dt-bindings/soc/airoha,scu-ssr.h
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] dt-bindings: clock: airoha: Add PHY binding for Serdes port
2026-07-24 18:43 [PATCH 0/2] clk: en7523: Add support for selecting SCU serdes Christian Marangi
@ 2026-07-24 18:43 ` Christian Marangi
2026-07-24 18:49 ` sashiko-bot
2026-07-24 18:43 ` [PATCH 2/2] clk: en7523: Add support for selecting the Serdes port in SCU Christian Marangi
1 sibling, 1 reply; 5+ messages in thread
From: Christian Marangi @ 2026-07-24 18:43 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Marangi,
Felix Fietkau, linux-clk, devicetree, linux-kernel
Add PHY cell property for Serdes port selection. Currently supported only
for Airoha AN7581 SoC, that support up to 4 Serdes port.
The Serdes port can support both PCIe, USB3 or Ethernet mode.
- PCIe1 Serdes can support PCIe or Ethernet mode.
- PCIe2 Serdes can support PCIe or Ethernet mode.
- USB1 Serdes can support USB3 or HSGMII mode.
- USB2 Serdes can support USB3 or PCIe mode.
Add bindings to permit correct reference of the Serdes ports in DT.
Values are just symbolic and enumerates the Serdes port with a specific
number for precise reference.
The available Serdes port can be selected following the dt-binding header
in [2].
[2] <include/dt-bindings/soc/airoha,scu-ssr.h>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
.../bindings/clock/airoha,en7523-scu.yaml | 24 ++++++++++++++++---
include/dt-bindings/soc/airoha,scu-ssr.h | 11 +++++++++
2 files changed, 32 insertions(+), 3 deletions(-)
create mode 100644 include/dt-bindings/soc/airoha,scu-ssr.h
diff --git a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
index eb24a5687639..fc37786ac7ed 100644
--- a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
+++ b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
@@ -23,6 +23,7 @@ description: |
All these identifiers can be found in:
[1]: <include/dt-bindings/clock/en7523-clk.h>.
+ [2]: <include/dt-bindings/soc/airoha,scu-ssr.h>.
The clocks are provided inside a system controller node.
@@ -50,6 +51,12 @@ properties:
description: ID of the controller reset line
const: 1
+ '#phy-cells':
+ description:
+ The first cell indicates the serdes phy number, see [2] for the
+ available serdes port.
+ const: 1
+
required:
- compatible
- reg
@@ -65,12 +72,23 @@ allOf:
reg:
minItems: 2
+ '#phy-cells': false
+
+ - if:
+ properties:
+ compatible:
+ const: econet,en751221-scu
+ then:
+ properties:
+ reg:
+ maxItems: 1
+
+ '#phy-cells': false
+
- if:
properties:
compatible:
- enum:
- - airoha,en7581-scu
- - econet,en751221-scu
+ const: airoha,en7581-scu
then:
properties:
reg:
diff --git a/include/dt-bindings/soc/airoha,scu-ssr.h b/include/dt-bindings/soc/airoha,scu-ssr.h
new file mode 100644
index 000000000000..33c64844ada3
--- /dev/null
+++ b/include/dt-bindings/soc/airoha,scu-ssr.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef __DT_BINDINGS_AIROHA_SCU_SSR_H
+#define __DT_BINDINGS_AIROHA_SCU_SSR_H
+
+#define AIROHA_SCU_SERDES_PCIE1 0
+#define AIROHA_SCU_SERDES_PCIE2 1
+#define AIROHA_SCU_SERDES_USB1 2
+#define AIROHA_SCU_SERDES_USB2 3
+
+#endif /* __DT_BINDINGS_AIROHA_SCU_SSR_H */
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] clk: en7523: Add support for selecting the Serdes port in SCU
2026-07-24 18:43 [PATCH 0/2] clk: en7523: Add support for selecting SCU serdes Christian Marangi
2026-07-24 18:43 ` [PATCH 1/2] dt-bindings: clock: airoha: Add PHY binding for Serdes port Christian Marangi
@ 2026-07-24 18:43 ` Christian Marangi
2026-07-24 18:57 ` sashiko-bot
1 sibling, 1 reply; 5+ messages in thread
From: Christian Marangi @ 2026-07-24 18:43 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Marangi,
Felix Fietkau, linux-clk, devicetree, linux-kernel
In the SCU register for clock and reset, there are also some register to
select the Serdes port mode. The Airoha AN7581 SoC have 4 different Serdes
that can switch between PCIe, USB or Ethernet mode.
Add a simple PHY provider that expose the .set_mode OP to toggle the
requested mode for the Serdes port.
Reviewed-by: Brian Masney <bmasney@redhat.com>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/clk/Kconfig | 1 +
drivers/clk/clk-en7523.c | 218 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 216 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1717ce75a907..4d58c35d88bc 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -221,6 +221,7 @@ config COMMON_CLK_EN7523
bool "Clock driver for Airoha/EcoNet SoC system clocks"
depends on OF
depends on ARCH_AIROHA || ECONET || COMPILE_TEST
+ select GENERIC_PHY
default ARCH_AIROHA
help
This driver provides the fixed clocks and gates present on Airoha
diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c
index 1ab0e2eca5d3..183cf7fe4bda 100644
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -6,14 +6,18 @@
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
#include <dt-bindings/clock/en7523-clk.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>
#include <dt-bindings/reset/econet,en751221-scu.h>
+#include <dt-bindings/soc/airoha,scu-ssr.h>
#define RST_NR_PER_BANK 32
@@ -40,9 +44,22 @@
#define REG_HIR_MASK GENMASK(31, 16)
/* EN7581 */
#define REG_NP_SCU_PCIC 0x88
+#define REG_NP_SCU_SSR3 0x94
+#define REG_SSUSB_HSGMII_SEL_MASK BIT(29)
+#define REG_SSUSB_HSGMII_SEL_HSGMII FIELD_PREP_CONST(REG_SSUSB_HSGMII_SEL_MASK, 0x0)
+#define REG_SSUSB_HSGMII_SEL_USB FIELD_PREP_CONST(REG_SSUSB_HSGMII_SEL_MASK, 0x1)
#define REG_NP_SCU_SSTR 0x9c
#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
+#define REG_PCIE_XSI0_SEL_PCIE FIELD_PREP_CONST(REG_PCIE_XSI0_SEL_MASK, 0x0)
+#define REG_PCIE_XSI0_SEL_XFI FIELD_PREP_CONST(REG_PCIE_XSI0_SEL_MASK, 0x1)
+#define REG_PCIE_XSI0_SEL_HSGMII FIELD_PREP_CONST(REG_PCIE_XSI0_SEL_MASK, 0x2)
#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
+#define REG_PCIE_XSI1_SEL_PCIE FIELD_PREP_CONST(REG_PCIE_XSI1_SEL_MASK, 0x0)
+#define REG_PCIE_XSI1_SEL_XFI FIELD_PREP_CONST(REG_PCIE_XSI1_SEL_MASK, 0x1)
+#define REG_PCIE_XSI1_SEL_HSGMII FIELD_PREP_CONST(REG_PCIE_XSI1_SEL_MASK, 0x2)
+#define REG_USB_PCIE_SEL_MASK BIT(3)
+#define REG_USB_PCIE_SEL_PCIE FIELD_PREP_CONST(REG_USB_PCIE_SEL_MASK, 0x0)
+#define REG_USB_PCIE_SEL_USB FIELD_PREP_CONST(REG_USB_PCIE_SEL_MASK, 0x1)
#define REG_CRYPTO_CLKSRC2 0x20c
/* EN751221 */
#define EN751221_REG_SPI_DIV 0x0cc
@@ -81,6 +98,8 @@ enum en_hir {
HIR_MAX = 14,
};
+#define EN_SERDES_PHY_NUM 4
+
struct en_clk_desc {
int id;
const char *name;
@@ -113,6 +132,18 @@ struct en_rst_data {
struct reset_controller_dev rcdev;
};
+struct en_serdes_phy_instance {
+ struct phy *phy;
+ unsigned int serdes_port;
+};
+
+struct en_clk_priv {
+ void __iomem *base;
+ /* protect SCU register */
+ spinlock_t lock;
+ struct en_serdes_phy_instance *serdes_phys[EN_SERDES_PHY_NUM];
+};
+
struct en_clk_soc_data {
u32 num_clocks;
const struct clk_ops pcie_ops;
@@ -830,12 +861,179 @@ static int en7581_reset_register(struct device *dev, void __iomem *base,
return devm_reset_controller_register(dev, &rst_data->rcdev);
}
+static int en7581_serdes_phy_set_mode(struct phy *phy, enum phy_mode mode,
+ int submode)
+{
+ struct en_serdes_phy_instance *instance = phy_get_drvdata(phy);
+ struct en_clk_priv *priv = dev_get_drvdata(phy->dev.parent);
+ u32 reg, mask, sel, val;
+ unsigned long flags;
+
+ switch (instance->serdes_port) {
+ case AIROHA_SCU_SERDES_PCIE1:
+ reg = REG_NP_SCU_SSTR;
+ mask = REG_PCIE_XSI0_SEL_MASK;
+
+ if (mode != PHY_MODE_ETHERNET && mode != PHY_MODE_PCIE)
+ return -EINVAL;
+
+ if (mode == PHY_MODE_ETHERNET) {
+ switch (submode) {
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_10GBASER:
+ sel = REG_PCIE_XSI0_SEL_XFI;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ sel = REG_PCIE_XSI0_SEL_HSGMII;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ sel = REG_PCIE_XSI0_SEL_PCIE;
+ }
+
+ break;
+ case AIROHA_SCU_SERDES_PCIE2:
+ reg = REG_NP_SCU_SSTR;
+ mask = REG_PCIE_XSI1_SEL_MASK;
+
+ if (mode != PHY_MODE_ETHERNET && mode != PHY_MODE_PCIE)
+ return -EINVAL;
+
+ if (mode == PHY_MODE_ETHERNET) {
+ switch (submode) {
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_10GBASER:
+ sel = REG_PCIE_XSI1_SEL_XFI;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ sel = REG_PCIE_XSI1_SEL_HSGMII;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ sel = REG_PCIE_XSI1_SEL_PCIE;
+ }
+
+ break;
+ case AIROHA_SCU_SERDES_USB1:
+ reg = REG_NP_SCU_SSR3;
+ mask = REG_SSUSB_HSGMII_SEL_MASK;
+
+ if (mode != PHY_MODE_ETHERNET && mode != PHY_MODE_USB_DEVICE &&
+ mode != PHY_MODE_USB_DEVICE_SS)
+ return -EINVAL;
+
+ if (mode == PHY_MODE_ETHERNET)
+ sel = REG_SSUSB_HSGMII_SEL_HSGMII;
+ else
+ sel = REG_SSUSB_HSGMII_SEL_USB;
+
+ break;
+ case AIROHA_SCU_SERDES_USB2:
+ reg = REG_NP_SCU_SSTR;
+ mask = REG_USB_PCIE_SEL_MASK;
+
+ if (mode != PHY_MODE_PCIE && mode != PHY_MODE_USB_DEVICE &&
+ mode != PHY_MODE_USB_DEVICE_SS)
+ return -EINVAL;
+
+ if (mode == PHY_MODE_PCIE)
+ sel = REG_USB_PCIE_SEL_PCIE;
+ else
+ sel = REG_USB_PCIE_SEL_USB;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ val = readl(priv->base + reg);
+ val &= ~mask;
+ val |= sel;
+ writel(val, priv->base + reg);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static const struct phy_ops en7581_serdes_phy_ops = {
+ .set_mode = en7581_serdes_phy_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *en7581_serdes_phy_xlate(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ struct en_clk_priv *priv = dev_get_drvdata(dev);
+ struct en_serdes_phy_instance *instance;
+ unsigned int serdes_port;
+
+ if (args->args_count != 1) {
+ dev_err(dev, "invalid number of cells in 'phy' property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ serdes_port = args->args[0];
+ if (serdes_port >= EN_SERDES_PHY_NUM) {
+ dev_err(dev, "invalid serdes port: %d\n", serdes_port);
+ return ERR_PTR(-EINVAL);
+ }
+
+ instance = priv->serdes_phys[serdes_port];
+ if (!instance) {
+ dev_err(dev, "failed to find appropriate serdes phy\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return instance->phy;
+}
+
+static int en7581_serdes_phy_register(struct device *dev)
+{
+ struct en_clk_priv *priv = dev_get_drvdata(dev);
+ struct phy_provider *phy_provider;
+ int i;
+
+ for (i = 0; i < EN_SERDES_PHY_NUM; i++) {
+ struct en_serdes_phy_instance *instance;
+
+ instance = devm_kzalloc(dev, sizeof(*instance),
+ GFP_KERNEL);
+ if (!instance)
+ return -ENOMEM;
+
+ instance->phy = devm_phy_create(dev, NULL,
+ &en7581_serdes_phy_ops);
+ if (IS_ERR(instance->phy))
+ return dev_err_probe(dev, PTR_ERR(instance->phy), "failed to create phy\n");
+
+ instance->serdes_port = i;
+ priv->serdes_phys[i] = instance;
+
+ phy_set_drvdata(instance->phy, instance);
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev, en7581_serdes_phy_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
static int en7581_clk_hw_init(struct platform_device *pdev,
struct clk_hw_onecell_data *clk_data)
{
+ struct en_clk_priv *priv = platform_get_drvdata(pdev);
struct regmap *map;
void __iomem *base;
u32 val;
+ int ret;
map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu");
if (IS_ERR(map))
@@ -845,6 +1043,8 @@ static int en7581_clk_hw_init(struct platform_device *pdev,
if (IS_ERR(base))
return PTR_ERR(base);
+ priv->base = base;
+
en7581_register_clocks(&pdev->dev, clk_data, map, base);
val = readl(base + REG_NP_SCU_SSTR);
@@ -853,9 +1053,12 @@ static int en7581_clk_hw_init(struct platform_device *pdev,
val = readl(base + REG_NP_SCU_PCIC);
writel(val | 3, base + REG_NP_SCU_PCIC);
- return en7581_reset_register(&pdev->dev, base, en7581_rst_map,
- ARRAY_SIZE(en7581_rst_map),
- en7581_rst_ofs);
+ ret = en7581_reset_register(&pdev->dev, base, en7581_rst_map,
+ ARRAY_SIZE(en7581_rst_map), en7581_rst_ofs);
+ if (ret)
+ return ret;
+
+ return en7581_serdes_phy_register(&pdev->dev);
}
static enum en_hir get_hw_id(void __iomem *np_base)
@@ -962,16 +1165,25 @@ static int en7523_clk_probe(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node;
const struct en_clk_soc_data *soc_data;
struct clk_hw_onecell_data *clk_data;
+ struct en_clk_priv *priv;
int r;
soc_data = device_get_match_data(&pdev->dev);
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ spin_lock_init(&priv->lock);
+
clk_data = devm_kzalloc(&pdev->dev,
struct_size(clk_data, hws, soc_data->num_clocks),
GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
+ platform_set_drvdata(pdev, priv);
+
clk_data->num = soc_data->num_clocks;
r = soc_data->hw_init(pdev, clk_data);
if (r)
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] dt-bindings: clock: airoha: Add PHY binding for Serdes port
2026-07-24 18:43 ` [PATCH 1/2] dt-bindings: clock: airoha: Add PHY binding for Serdes port Christian Marangi
@ 2026-07-24 18:49 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-07-24 18:49 UTC (permalink / raw)
To: Christian Marangi; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The patch introduces PHY provider capabilities for the `airoha,en7581-scu` variant by adding the `#phy-cells` property, but fails to make it a required property for its compatible string and does not update the example.
--
--- Patch [1]: [PATCH 1/2] dt-bindings: clock: airoha: Add PHY binding for Serdes port ---
commit 5719603a01527297dc730214337f813a27ac01a3
Author: Christian Marangi <ansuelsmth@gmail.com>
dt-bindings: clock: airoha: Add PHY binding for Serdes port
This commit introduces a #phy-cells property for the airoha,en7581-scu
compatible string to support Serdes port selection. It also defines the
available Serdes ports in a new dt-bindings header file.
> diff --git a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
> index eb24a5687639e..fc37786ac7ed8 100644
> --- a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
> +++ b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
[ ... ]
> - if:
> properties:
> compatible:
> - enum:
> - - airoha,en7581-scu
> - - econet,en751221-scu
> + const: airoha,en7581-scu
> then:
> properties:
> reg:
[Severity: Medium]
Should #phy-cells be added to a required list in this conditional block?
If the property is omitted for the airoha,en7581-scu hardware, device trees
will silently pass schema validation despite being incomplete, which can lead
to runtime failures when dependent drivers attempt to use the PHY functionality.
Additionally, does the airoha,en7581-scu example further down in the file need
to be updated with #phy-cells = <1>; to satisfy validation once the property
is required?
Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml:examples
scuclk: clock-controller@1fb00000 {
compatible = "airoha,en7581-scu";
reg = <0x0 0x1fb00000 0x0 0x970>;
#clock-cells = <1>;
#reset-cells = <1>;
};
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724184304.192962-1-ansuelsmth@gmail.com?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] clk: en7523: Add support for selecting the Serdes port in SCU
2026-07-24 18:43 ` [PATCH 2/2] clk: en7523: Add support for selecting the Serdes port in SCU Christian Marangi
@ 2026-07-24 18:57 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-07-24 18:57 UTC (permalink / raw)
To: Christian Marangi; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] The PHY set_mode callback incorrectly rejects USB host and OTG modes, breaking USB host functionality.
Pre-existing issues:
- [High] Missing spinlock in reset operations allows concurrent reset assertions to corrupt shared reset control registers.
- [High] Probe failure leaves unregistered clocks in the clock core, causing a Use-After-Free and memory leak when devres frees the clock structures.
--
--- Patch [2]: [PATCH 2/2] clk: en7523: Add support for selecting the Serdes port in SCU ---
commit e81bbf2efd265f6528ea23e2f2c71e904963fc17
Author: Christian Marangi <ansuelsmth@gmail.com>
clk: en7523: Add support for selecting the Serdes port in SCU
In the SCU register for clock and reset, there are also some register to
select the Serdes port mode. The Airoha AN7581 SoC have 4 different Serdes
that can switch between PCIe, USB or Ethernet mode.
Add a simple PHY provider that expose the .set_mode OP to toggle the
requested mode for the Serdes port.
> diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c
> index 1ab0e2eca5d32..183cf7fe4bda6 100644
> --- a/drivers/clk/clk-en7523.c
> +++ b/drivers/clk/clk-en7523.c
[ ... ]
> @@ -830,12 +861,179 @@ static int en7581_reset_register(struct device *dev, void __iomem *base,
> return devm_reset_controller_register(dev, &rst_data->rcdev);
> }
>
> +static int en7581_serdes_phy_set_mode(struct phy *phy, enum phy_mode mode,
> + int submode)
> +{
[ ... ]
> + case AIROHA_SCU_SERDES_USB1:
> + reg = REG_NP_SCU_SSR3;
> + mask = REG_SSUSB_HSGMII_SEL_MASK;
> +
> + if (mode != PHY_MODE_ETHERNET && mode != PHY_MODE_USB_DEVICE &&
> + mode != PHY_MODE_USB_DEVICE_SS)
> + return -EINVAL;
[Severity: High]
Does this validation block USB host and OTG operations for the USB1 port?
If a USB controller driver calls phy_set_mode(phy, PHY_MODE_USB_HOST) or
PHY_MODE_USB_OTG during initialization, it appears this check will reject
it and return -EINVAL, bypassing the register write and leaving the Serdes
lanes uninitialized.
> +
> + if (mode == PHY_MODE_ETHERNET)
> + sel = REG_SSUSB_HSGMII_SEL_HSGMII;
> + else
> + sel = REG_SSUSB_HSGMII_SEL_USB;
> +
> + break;
> + case AIROHA_SCU_SERDES_USB2:
> + reg = REG_NP_SCU_SSTR;
> + mask = REG_USB_PCIE_SEL_MASK;
> +
> + if (mode != PHY_MODE_PCIE && mode != PHY_MODE_USB_DEVICE &&
> + mode != PHY_MODE_USB_DEVICE_SS)
> + return -EINVAL;
[Severity: High]
Similarly, does this logic improperly reject PHY_MODE_USB_HOST and
PHY_MODE_USB_OTG for the USB2 Serdes port?
[ ... ]
> @@ -853,9 +1053,12 @@ static int en7581_clk_hw_init(struct platform_device *pdev,
> val = readl(base + REG_NP_SCU_PCIC);
> writel(val | 3, base + REG_NP_SCU_PCIC);
>
> - return en7581_reset_register(&pdev->dev, base, en7581_rst_map,
> - ARRAY_SIZE(en7581_rst_map),
> - en7581_rst_ofs);
> + ret = en7581_reset_register(&pdev->dev, base, en7581_rst_map,
> + ARRAY_SIZE(en7581_rst_map), en7581_rst_ofs);
[Severity: High]
This is a pre-existing issue, but does the lack of a spinlock in the reset
operations allow concurrent reset assertions to corrupt shared registers?
If multiple driver probes (e.g., PCIe, USB, Ethernet) call
en7523_reset_update() or en7523_pci_prepare() concurrently, both functions
perform unlocked read-modify-write sequences on REG_RESET_CONTROL1:
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);
}
Could a race condition here cause one IP block to be wedged in reset because
its update was lost?
> + if (ret)
> + return ret;
> +
> + return en7581_serdes_phy_register(&pdev->dev);
[Severity: High]
This is a pre-existing issue, but does this new error path expose a memory
leak and use-after-free of struct en_clk_gate in the clock core?
The clocks are allocated with devres but registered with unmanaged APIs:
en7523_register_pcie_clk() {
...
cg = devm_kzalloc(dev, sizeof(*cg), GFP_KERNEL);
...
err = clk_hw_register(dev, hw);
}
If en7581_serdes_phy_register() returns an error here, the probe fails and
devres will automatically free cg. However, because clk_hw_register() was
used, the clock remains registered in CCF.
Would this leave a dangling pointer in the clock core that causes a crash
on subsequent access to /sys/kernel/debug/clk?
> }
>
> static enum en_hir get_hw_id(void __iomem *np_base)
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724184304.192962-1-ansuelsmth@gmail.com?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-24 18:57 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-24 18:43 [PATCH 0/2] clk: en7523: Add support for selecting SCU serdes Christian Marangi
2026-07-24 18:43 ` [PATCH 1/2] dt-bindings: clock: airoha: Add PHY binding for Serdes port Christian Marangi
2026-07-24 18:49 ` sashiko-bot
2026-07-24 18:43 ` [PATCH 2/2] clk: en7523: Add support for selecting the Serdes port in SCU Christian Marangi
2026-07-24 18:57 ` sashiko-bot
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.