* Re: [PATCH v4 2/2] arm64: dts: qcom: lemans: Add eDP ref clock for eDP PHYs
From: Konrad Dybcio @ 2026-01-28 12:41 UTC (permalink / raw)
To: Ritesh Kumar, robin.clark, lumag, abhinav.kumar, sean,
marijn.suijten, maarten.lankhorst, mripard, tzimmermann, airlied,
simona, robh, krzk+dt, conor+dt, quic_mahap, andersson,
konradybcio, mani, James.Bottomley, martin.petersen, vkoul,
kishon, cros-qcom-dts-watchers
Cc: linux-phy, linux-arm-msm, dri-devel, freedreno, devicetree,
linux-kernel, linux-scsi, quic_vproddut
In-Reply-To: <20260128114853.2543416-3-quic_riteshk@quicinc.com>
On 1/28/26 12:48 PM, Ritesh Kumar wrote:
> The eDP PHY nodes on lemans were missing the reference clock voting.
> This initially went unnoticed because the clock was implicitly enabled
> by the UFS PHY driver, and the eDP PHY happened to rely on that.
>
> After commit 77d2fa54a945 ("scsi: ufs: qcom : Refactor phy_power_on/off
> calls"), the UFS driver no longer keeps the reference clock enabled.
> As a result, the eDP PHY fails to power on.
>
> To fix this, add eDP reference clock for eDP PHYs on lemans chipset
> ensuring reference clock is enabled.
>
> Fixes: e1e3e5673f8d7 ("arm64: dts: qcom: sa8775p: add DisplayPort device nodes")
> Signed-off-by: Ritesh Kumar <quic_riteshk@quicinc.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v4 1/2] dt-bindings: phy: qcom-edp: Add reference clock for sa8775p eDP PHY
From: Ritesh Kumar @ 2026-01-28 11:48 UTC (permalink / raw)
To: robin.clark, lumag, abhinav.kumar, sean, marijn.suijten,
maarten.lankhorst, mripard, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, quic_mahap, andersson, konradybcio, mani,
James.Bottomley, martin.petersen, vkoul, kishon,
cros-qcom-dts-watchers
Cc: Ritesh Kumar, linux-phy, linux-arm-msm, dri-devel, freedreno,
devicetree, linux-kernel, linux-scsi, quic_vproddut
In-Reply-To: <20260128114853.2543416-1-quic_riteshk@quicinc.com>
The initial sa8775p eDP PHY binding contribution missed adding support for
voting on the eDP reference clock. This went unnoticed because the UFS PHY
driver happened to enable the same clock.
After commit 77d2fa54a945 ("scsi: ufs: qcom : Refactor phy_power_on/off
calls"), the eDP reference clock is no longer kept enabled, which results
in the following PHY power-on failure:
phy phy-aec2a00.phy.10: phy poweron failed --> -110
To fix this, explicit voting for the eDP reference clock is required.
This patch adds the eDP reference clock for sa8775p eDP PHY and updates
the corresponding example node.
Signed-off-by: Ritesh Kumar <quic_riteshk@quicinc.com>
---
.../devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml | 6 ++++--
Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml | 1 +
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml
index e2730a2f25cf..6c827cf9692b 100644
--- a/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml
@@ -200,9 +200,11 @@ examples:
<0x0aec2000 0x1c8>;
clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>,
- <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>;
+ <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_EDP_REF_CLKREF_EN>;
clock-names = "aux",
- "cfg_ahb";
+ "cfg_ahb",
+ "ref";
#clock-cells = <1>;
#phy-cells = <0>;
diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml
index 4a1daae3d8d4..0bf8bf4f66ac 100644
--- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml
@@ -74,6 +74,7 @@ allOf:
compatible:
enum:
- qcom,glymur-dp-phy
+ - qcom,sa8775p-edp-phy
- qcom,x1e80100-dp-phy
then:
properties:
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v4 0/2] Add edp reference clock for lemans
From: Ritesh Kumar @ 2026-01-28 11:48 UTC (permalink / raw)
To: robin.clark, lumag, abhinav.kumar, sean, marijn.suijten,
maarten.lankhorst, mripard, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, quic_mahap, andersson, konradybcio, mani,
James.Bottomley, martin.petersen, vkoul, kishon,
cros-qcom-dts-watchers
Cc: Ritesh Kumar, linux-phy, linux-arm-msm, dri-devel, freedreno,
devicetree, linux-kernel, linux-scsi, quic_vproddut
On lemans chipset, edp reference clock is being voted by ufs mem phy
(ufs_mem_phy: phy@1d87000). But after commit 77d2fa54a945
("scsi: ufs: qcom : Refactor phy_power_on/off calls") edp reference
clock is getting turned off, leading to below phy poweron failure on
lemans edp phy.
[ 19.830220] phy phy-aec2a00.phy.10: phy poweron failed --> -110
[ 19.842112] mdss_0_disp_cc_mdss_dptx0_link_clk status stuck at 'off'
[ 19.842131] WARNING: CPU: 2 PID: 371 at drivers/clk/qcom/clk-branch.c:87 clk_branch_toggle+0x174/0x18c
[ 19.984356] Hardware name: Qualcomm QCS9100 Ride (DT)
[ 19.989548] pstate: 604000c5 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 19.996697] pc : clk_branch_toggle+0x174/0x18c
[ 20.001267] lr : clk_branch_toggle+0x174/0x18c
[ 20.005833] sp : ffff8000863ebbc0
[ 20.009251] x29: ffff8000863ebbd0 x28: 0000000000000000 x27: 0000000000000000
[ 20.016579] x26: 0000000000000000 x25: 0000000000000000 x24: 0000000000000001
[ 20.023915] x23: ffff0000c53de980 x22: 0000000000000001 x21: ffffb4b57fd8d710
[ 20.031245] x20: ffffb4b5bb238b88 x19: 0000000000000000 x18: ffffffffffff7198
[ 20.038584] x17: 0000000000000014 x16: ffffb4b5bb1e2330 x15: 0000000000000048
[ 20.045926] x14: 0000000000000000 x13: ffffb4b5bd386a48 x12: 0000000000000dfb
[ 20.053263] x11: 00000000000004a9 x10: ffffb4b5bd3e5a20 x9 : ffffb4b5bd386a48
[ 20.060600] x8 : 00000000ffffefff x7 : ffffb4b5bd3dea48 x6 : 00000000000004a9
[ 20.067934] x5 : ffff000eb7d38408 x4 : 40000000fffff4a9 x3 : ffff4b58fb2b7000
[ 20.075269] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff000ec4fc3480
[ 20.082601] Call trace:
[ 20.085127] clk_branch_toggle+0x174/0x18c (P)
[ 20.089705] clk_branch2_enable+0x1c/0x28
[ 20.093829] clk_core_enable+0x6c/0xac
[ 20.097687] clk_enable+0x2c/0x4c
[ 20.101104] clk_bulk_enable+0x4c/0xd8
[ 20.104964] msm_dp_ctrl_enable_mainlink_clocks+0x184/0x24c [msm]
[ 20.111294] msm_dp_ctrl_on_link+0xb0/0x400 [msm]
[ 20.116178] msm_dp_display_process_hpd_high+0x110/0x190 [msm]
[ 20.122209] msm_dp_hpd_plug_handle.isra.0+0xac/0x1c4 [msm]
[ 20.127983] hpd_event_thread+0x320/0x5cc [msm]
[ 20.132680] kthread+0x12c/0x204
[ 20.136011] ret_from_fork+0x10/0x20
[ 20.139699] ---[ end trace 0000000000000000 ]---
[ 20.144489] Failed to enable clk 'ctrl_link': -16
[ 20.149340] [drm:msm_dp_ctrl_enable_mainlink_clocks [msm]] *ERROR* Unable to start link clocks. ret=-16
This series adds support for voting the clock from lemans edp phy driver.
---
Change in v4:
- The dependent series is merged. Rebased to latest linux-next. Removed dependency in cover letter.
- Update commit message of dt-bindings patch. [Krzysztof]
- Update commit message of devicetree patch to give more detail. [Abel Vesa]
- Link to v3: https://lore.kernel.org/all/20251104114327.27842-1-riteshk@qti.qualcomm.com/
Change in v3:
- Rebase to latest linux-next and latest version 5 of dependency.
- Squash both DT binding patches together. [Dmitry, Rob]
- Add dt-binding change in sorted order. [Dmitry]
- Update commit message of bindings patch to give more detail of the problem. [Bjorn]
- Update commit message of devicetree patch and add Fixes tag. [Dmitry]
- Link to v2: https://lore.kernel.org/all/20251013104806.6599-1-quic_riteshk@quicinc.com/
Change in v2:
- Rebase on top of dependent series. [Krzysztof]
- Remove duplicate patches and make changes limited to lemans.
- Link to v1: https://lore.kernel.org/all/20251009071127.26026-1-quic_riteshk@quicinc.com/
---
Ritesh Kumar (2):
dt-bindings: phy: qcom-edp: Add reference clock for sa8775p eDP PHY
arm64: dts: qcom: lemans: Add eDP ref clock for eDP PHYs
.../bindings/display/msm/qcom,sa8775p-mdss.yaml | 6 ++++--
.../devicetree/bindings/phy/qcom,edp-phy.yaml | 1 +
arch/arm64/boot/dts/qcom/lemans.dtsi | 12 ++++++++----
3 files changed, 13 insertions(+), 6 deletions(-)
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v4 2/2] arm64: dts: qcom: lemans: Add eDP ref clock for eDP PHYs
From: Ritesh Kumar @ 2026-01-28 11:48 UTC (permalink / raw)
To: robin.clark, lumag, abhinav.kumar, sean, marijn.suijten,
maarten.lankhorst, mripard, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, quic_mahap, andersson, konradybcio, mani,
James.Bottomley, martin.petersen, vkoul, kishon,
cros-qcom-dts-watchers
Cc: Ritesh Kumar, linux-phy, linux-arm-msm, dri-devel, freedreno,
devicetree, linux-kernel, linux-scsi, quic_vproddut
In-Reply-To: <20260128114853.2543416-1-quic_riteshk@quicinc.com>
The eDP PHY nodes on lemans were missing the reference clock voting.
This initially went unnoticed because the clock was implicitly enabled
by the UFS PHY driver, and the eDP PHY happened to rely on that.
After commit 77d2fa54a945 ("scsi: ufs: qcom : Refactor phy_power_on/off
calls"), the UFS driver no longer keeps the reference clock enabled.
As a result, the eDP PHY fails to power on.
To fix this, add eDP reference clock for eDP PHYs on lemans chipset
ensuring reference clock is enabled.
Fixes: e1e3e5673f8d7 ("arm64: dts: qcom: sa8775p: add DisplayPort device nodes")
Signed-off-by: Ritesh Kumar <quic_riteshk@quicinc.com>
---
arch/arm64/boot/dts/qcom/lemans.dtsi | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index 808827b83553..1da8e7fb6775 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -5301,9 +5301,11 @@ mdss0_dp0_phy: phy@aec2a00 {
<0x0 0x0aec2000 0x0 0x1c8>;
clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK>,
- <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>;
+ <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_EDP_REF_CLKREF_EN>;
clock-names = "aux",
- "cfg_ahb";
+ "cfg_ahb",
+ "ref";
#clock-cells = <1>;
#phy-cells = <0>;
@@ -5320,9 +5322,11 @@ mdss0_dp1_phy: phy@aec5a00 {
<0x0 0x0aec5000 0x0 0x1c8>;
clocks = <&dispcc0 MDSS_DISP_CC_MDSS_DPTX1_AUX_CLK>,
- <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>;
+ <&dispcc0 MDSS_DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_EDP_REF_CLKREF_EN>;
clock-names = "aux",
- "cfg_ahb";
+ "cfg_ahb",
+ "ref";
#clock-cells = <1>;
#phy-cells = <0>;
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH] phy: PHY_GOOGLE_USB should depend on ARCH_GOOGLE
From: Geert Uytterhoeven @ 2026-01-27 19:12 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Peter Griffin, André Draszik,
Tudor Ambarus, Naveen Kumar, Roy Luo, Joy Chakraborty,
Arnd Bergmann
Cc: linux-phy, linux-arm-kernel, linux-samsung-soc, linux-kernel,
Geert Uytterhoeven
The Google Tensor SoC USB PHY is only present on Google Tensor G5
(Laguna) SoCs. Hence add a dependency on ARCH_GOOGLE, to prevent asking
the user about this driver when configuring a kernel without Google
Tensor SoC support.
Fixes: cbce66669c82ee9a ("phy: Add Google Tensor SoC USB PHY driver")
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
ARCH_GOOGLE is not yet upstream, but that doesn't hurt.
---
drivers/phy/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 142e7b0ef2efb920..3ceda9a20d571038 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -49,6 +49,7 @@ config GENERIC_PHY_MIPI_DPHY
config PHY_GOOGLE_USB
tristate "Google Tensor SoC USB PHY driver"
+ depends on ARCH_GOOGLE || COMPILE_TEST
select GENERIC_PHY
help
Enable support for the USB PHY on Google Tensor SoCs, starting with
--
2.43.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v6 8/8] MIPS: mobileye: eyeq5-epm: add two Cadence GEM Ethernet PHYs
From: Théo Lebrun @ 2026-01-27 17:09 UTC (permalink / raw)
To: Vladimir Kondratiev, Grégory Clement, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul,
Kishon Vijay Abraham I, Michael Turquette, Stephen Boyd,
Philipp Zabel, Thomas Bogendoerfer, Neil Armstrong
Cc: linux-mips, devicetree, linux-kernel, linux-phy, linux-clk,
Benoît Monin, Tawfik Bayouk, Thomas Petazzoni, Luca Ceresoli,
Théo Lebrun, Andrew Lunn
In-Reply-To: <20260127-macb-phy-v6-0-cdd840588188@bootlin.com>
The Mobileye EyeQ5 eval board (EPM) embeds two MDIO PHYs.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Acked-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
arch/mips/boot/dts/mobileye/eyeq5-epm5.dts | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/arch/mips/boot/dts/mobileye/eyeq5-epm5.dts b/arch/mips/boot/dts/mobileye/eyeq5-epm5.dts
index 9fc1a1b0a81b..babf52731ea6 100644
--- a/arch/mips/boot/dts/mobileye/eyeq5-epm5.dts
+++ b/arch/mips/boot/dts/mobileye/eyeq5-epm5.dts
@@ -29,3 +29,29 @@ temperature-sensor@48 {
label = "U60";
};
};
+
+&macb0 {
+ phy-mode = "sgmii";
+ phy-handle = <&macb0_phy>;
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ macb0_phy: ethernet-phy@e {
+ reg = <0xe>;
+ };
+ };
+};
+
+&macb1 {
+ phy-mode = "rgmii-id";
+ phy-handle = <&macb1_phy>;
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ macb1_phy: ethernet-phy@e {
+ reg = <0xe>;
+ };
+ };
+};
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v6 7/8] MIPS: mobileye: eyeq5: add two Cadence GEM Ethernet controllers
From: Théo Lebrun @ 2026-01-27 17:09 UTC (permalink / raw)
To: Vladimir Kondratiev, Grégory Clement, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul,
Kishon Vijay Abraham I, Michael Turquette, Stephen Boyd,
Philipp Zabel, Thomas Bogendoerfer, Neil Armstrong
Cc: linux-mips, devicetree, linux-kernel, linux-phy, linux-clk,
Benoît Monin, Tawfik Bayouk, Thomas Petazzoni, Luca Ceresoli,
Théo Lebrun
In-Reply-To: <20260127-macb-phy-v6-0-cdd840588188@bootlin.com>
Add both MACB/GEM instances found in the Mobileye EyeQ5 SoC.
Acked-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
arch/mips/boot/dts/mobileye/eyeq5.dtsi | 45 ++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/arch/mips/boot/dts/mobileye/eyeq5.dtsi b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
index 36a73e8a63a1..cec5ad875228 100644
--- a/arch/mips/boot/dts/mobileye/eyeq5.dtsi
+++ b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
@@ -77,6 +77,8 @@ aliases {
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
+ ethernet0 = &macb0;
+ ethernet1 = &macb1;
};
cpu_intc: interrupt-controller {
@@ -231,6 +233,7 @@ olb: system-controller@e00000 {
#clock-cells = <1>;
clocks = <&xtal>;
clock-names = "ref";
+ #phy-cells = <1>;
};
gic: interrupt-controller@140000 {
@@ -305,6 +308,48 @@ gpio1: gpio@1500000 {
#interrupt-cells = <2>;
resets = <&olb 0 26>;
};
+
+ iocu-bus {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ dma-coherent;
+ dma-ranges = <0x10 0x00000000 0x0 0x0 0x10 0>;
+
+ macb0: ethernet@2a00000 {
+ compatible = "mobileye,eyeq5-gem";
+ reg = <0x0 0x02a00000 0x0 0x4000>;
+ interrupt-parent = <&gic>;
+ /* One interrupt per queue */
+ interrupts = <GIC_SHARED 23 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SHARED 23 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SHARED 23 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SHARED 23 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "pclk", "hclk", "tsu_clk";
+ clocks = <&pclk>, <&pclk>, <&tsu_clk>;
+ nvmem-cells = <ð0_mac>;
+ nvmem-cell-names = "mac-address";
+ phys = <&olb 0>;
+ };
+
+ macb1: ethernet@2b00000 {
+ compatible = "mobileye,eyeq5-gem";
+ reg = <0x0 0x02b00000 0x0 0x4000>;
+ interrupt-parent = <&gic>;
+ /* One interrupt per queue */
+ interrupts = <GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "pclk", "hclk", "tsu_clk";
+ clocks = <&pclk>, <&pclk>, <&tsu_clk>;
+ nvmem-cells = <ð1_mac>;
+ nvmem-cell-names = "mac-address";
+ phys = <&olb 1>;
+ };
+ };
+
};
};
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v6 6/8] reset: eyeq: drop device_set_of_node_from_dev() done by parent
From: Théo Lebrun @ 2026-01-27 17:09 UTC (permalink / raw)
To: Vladimir Kondratiev, Grégory Clement, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul,
Kishon Vijay Abraham I, Michael Turquette, Stephen Boyd,
Philipp Zabel, Thomas Bogendoerfer, Neil Armstrong
Cc: linux-mips, devicetree, linux-kernel, linux-phy, linux-clk,
Benoît Monin, Tawfik Bayouk, Thomas Petazzoni, Luca Ceresoli,
Théo Lebrun, Jerome Brunet
In-Reply-To: <20260127-macb-phy-v6-0-cdd840588188@bootlin.com>
Our parent driver (clk-eyeq) now does the
device_set_of_node_from_dev(dev, dev->parent)
call through the newly introduced devm_auxiliary_device_create() helper.
Doing it again in the reset-eyeq probe would be redundant.
Drop both the WARN_ON() and the device_set_of_node_from_dev() call.
Also fix the following comment that talks about "our newfound OF node".
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
drivers/reset/reset-eyeq.c | 24 ++----------------------
1 file changed, 2 insertions(+), 22 deletions(-)
diff --git a/drivers/reset/reset-eyeq.c b/drivers/reset/reset-eyeq.c
index 2d3998368a1c..8018fa895427 100644
--- a/drivers/reset/reset-eyeq.c
+++ b/drivers/reset/reset-eyeq.c
@@ -410,13 +410,6 @@ static int eqr_of_xlate_twocells(struct reset_controller_dev *rcdev,
return eqr_of_xlate_internal(rcdev, reset_spec->args[0], reset_spec->args[1]);
}
-static void eqr_of_node_put(void *_dev)
-{
- struct device *dev = _dev;
-
- of_node_put(dev->of_node);
-}
-
static int eqr_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
@@ -427,21 +420,8 @@ static int eqr_probe(struct auxiliary_device *adev,
int ret;
/*
- * We are an auxiliary device of clk-eyeq. We do not have an OF node by
- * default; let's reuse our parent's OF node.
- */
- WARN_ON(dev->of_node);
- device_set_of_node_from_dev(dev, dev->parent);
- if (!dev->of_node)
- return -ENODEV;
-
- ret = devm_add_action_or_reset(dev, eqr_of_node_put, dev);
- if (ret)
- return ret;
-
- /*
- * Using our newfound OF node, we can get match data. We cannot use
- * device_get_match_data() because it does not match reused OF nodes.
+ * Get match data. We cannot use device_get_match_data() because it does
+ * not accept reused OF nodes; see device_set_of_node_from_dev().
*/
match = of_match_node(dev->driver->of_match_table, dev->of_node);
if (!match || !match->data)
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v6 5/8] clk: eyeq: add EyeQ5 children auxiliary device for generic PHYs
From: Théo Lebrun @ 2026-01-27 17:09 UTC (permalink / raw)
To: Vladimir Kondratiev, Grégory Clement, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul,
Kishon Vijay Abraham I, Michael Turquette, Stephen Boyd,
Philipp Zabel, Thomas Bogendoerfer, Neil Armstrong
Cc: linux-mips, devicetree, linux-kernel, linux-phy, linux-clk,
Benoît Monin, Tawfik Bayouk, Thomas Petazzoni, Luca Ceresoli,
Théo Lebrun
In-Reply-To: <20260127-macb-phy-v6-0-cdd840588188@bootlin.com>
Grow our clk-eyeq family; it knows how to spawn reset provider and pin
controller children. Expand with a generic PHY driver on EyeQ5.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
drivers/clk/clk-eyeq.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c
index 664ce7d7868d..a9de57315e48 100644
--- a/drivers/clk/clk-eyeq.c
+++ b/drivers/clk/clk-eyeq.c
@@ -109,6 +109,7 @@ struct eqc_match_data {
const char *reset_auxdev_name;
const char *pinctrl_auxdev_name;
+ const char *eth_phy_auxdev_name;
unsigned int early_clk_count;
};
@@ -361,6 +362,7 @@ static int eqc_probe(struct platform_device *pdev)
/* Init optional auxiliary devices. */
eqc_auxdev_create_optional(dev, base, data->reset_auxdev_name);
eqc_auxdev_create_optional(dev, base, data->pinctrl_auxdev_name);
+ eqc_auxdev_create_optional(dev, base, data->eth_phy_auxdev_name);
if (data->pll_count + data->div_count + data->fixed_factor_count == 0)
return 0; /* Zero clocks, we are done. */
@@ -521,6 +523,7 @@ static const struct eqc_match_data eqc_eyeq5_match_data = {
.reset_auxdev_name = "reset",
.pinctrl_auxdev_name = "pinctrl",
+ .eth_phy_auxdev_name = "phy",
.early_clk_count = ARRAY_SIZE(eqc_eyeq5_early_plls) +
ARRAY_SIZE(eqc_eyeq5_early_fixed_factors),
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v6 4/8] clk: eyeq: use the auxiliary device creation helper
From: Théo Lebrun @ 2026-01-27 17:09 UTC (permalink / raw)
To: Vladimir Kondratiev, Grégory Clement, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul,
Kishon Vijay Abraham I, Michael Turquette, Stephen Boyd,
Philipp Zabel, Thomas Bogendoerfer, Neil Armstrong
Cc: linux-mips, devicetree, linux-kernel, linux-phy, linux-clk,
Benoît Monin, Tawfik Bayouk, Thomas Petazzoni, Luca Ceresoli,
Théo Lebrun, Jerome Brunet
In-Reply-To: <20260127-macb-phy-v6-0-cdd840588188@bootlin.com>
From: Jerome Brunet <jbrunet@baylibre.com>
The auxiliary device creation of this driver is simple enough to
use the available auxiliary device creation helper.
Use it and remove some boilerplate code.
Tested-by: Théo Lebrun <theo.lebrun@bootlin.com> # On Mobileye EyeQ5
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
drivers/clk/clk-eyeq.c | 57 +++++++++++---------------------------------------
1 file changed, 12 insertions(+), 45 deletions(-)
diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c
index ea1c3d78e7cd..664ce7d7868d 100644
--- a/drivers/clk/clk-eyeq.c
+++ b/drivers/clk/clk-eyeq.c
@@ -322,38 +322,18 @@ static void eqc_probe_init_fixed_factors(struct device *dev,
}
}
-static void eqc_auxdev_release(struct device *dev)
-{
- struct auxiliary_device *adev = to_auxiliary_dev(dev);
-
- kfree(adev);
-}
-
-static int eqc_auxdev_create(struct device *dev, void __iomem *base,
- const char *name, u32 id)
+static void eqc_auxdev_create_optional(struct device *dev, void __iomem *base,
+ const char *name)
{
struct auxiliary_device *adev;
- int ret;
- adev = kzalloc(sizeof(*adev), GFP_KERNEL);
- if (!adev)
- return -ENOMEM;
-
- adev->name = name;
- adev->dev.parent = dev;
- adev->dev.platform_data = (void __force *)base;
- adev->dev.release = eqc_auxdev_release;
- adev->id = id;
-
- ret = auxiliary_device_init(adev);
- if (ret)
- return ret;
-
- ret = auxiliary_device_add(adev);
- if (ret)
- auxiliary_device_uninit(adev);
-
- return ret;
+ if (name) {
+ adev = devm_auxiliary_device_create(dev, name,
+ (void __force *)base);
+ if (!adev)
+ dev_warn(dev, "failed creating auxiliary device %s.%s\n",
+ KBUILD_MODNAME, name);
+ }
}
static int eqc_probe(struct platform_device *pdev)
@@ -365,7 +345,6 @@ static int eqc_probe(struct platform_device *pdev)
unsigned int i, clk_count;
struct resource *res;
void __iomem *base;
- int ret;
data = device_get_match_data(dev);
if (!data)
@@ -379,21 +358,9 @@ static int eqc_probe(struct platform_device *pdev)
if (!base)
return -ENOMEM;
- /* Init optional reset auxiliary device. */
- if (data->reset_auxdev_name) {
- ret = eqc_auxdev_create(dev, base, data->reset_auxdev_name, 0);
- if (ret)
- dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n",
- KBUILD_MODNAME, data->reset_auxdev_name, ret);
- }
-
- /* Init optional pinctrl auxiliary device. */
- if (data->pinctrl_auxdev_name) {
- ret = eqc_auxdev_create(dev, base, data->pinctrl_auxdev_name, 0);
- if (ret)
- dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n",
- KBUILD_MODNAME, data->pinctrl_auxdev_name, ret);
- }
+ /* Init optional auxiliary devices. */
+ eqc_auxdev_create_optional(dev, base, data->reset_auxdev_name);
+ eqc_auxdev_create_optional(dev, base, data->pinctrl_auxdev_name);
if (data->pll_count + data->div_count + data->fixed_factor_count == 0)
return 0; /* Zero clocks, we are done. */
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v6 3/8] phy: Add driver for EyeQ5 Ethernet PHY wrapper
From: Théo Lebrun @ 2026-01-27 17:09 UTC (permalink / raw)
To: Vladimir Kondratiev, Grégory Clement, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul,
Kishon Vijay Abraham I, Michael Turquette, Stephen Boyd,
Philipp Zabel, Thomas Bogendoerfer, Neil Armstrong
Cc: linux-mips, devicetree, linux-kernel, linux-phy, linux-clk,
Benoît Monin, Tawfik Bayouk, Thomas Petazzoni, Luca Ceresoli,
Théo Lebrun
In-Reply-To: <20260127-macb-phy-v6-0-cdd840588188@bootlin.com>
EyeQ5 embeds a system-controller called OLB. It features many unrelated
registers, and some of those are registers used to configure the
integration of the RGMII/SGMII Cadence PHY used by MACB/GEM instances.
Wrap in a neat generic PHY provider, exposing two PHYs with standard
phy_init() / phy_set_mode() / phy_power_on() operations.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
MAINTAINERS | 1 +
drivers/phy/Kconfig | 13 +++
drivers/phy/Makefile | 1 +
drivers/phy/phy-eyeq5-eth.c | 249 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 264 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 67db88b04537..2f77dc350706 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17621,6 +17621,7 @@ F: arch/mips/boot/dts/mobileye/
F: arch/mips/configs/eyeq5_defconfig
F: arch/mips/mobileye/board-epm5.its.S
F: drivers/clk/clk-eyeq.c
+F: drivers/phy/phy-eyeq5-eth.c
F: drivers/pinctrl/pinctrl-eyeq5.c
F: drivers/reset/reset-eyeq.c
F: include/dt-bindings/clock/mobileye,eyeq5-clk.h
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 4f1b1d7f5d20..b3c11cd0209a 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -45,6 +45,19 @@ config PHY_CAN_TRANSCEIVER
functional modes using gpios and sets the attribute max link
rate, for CAN drivers.
+config PHY_EYEQ5_ETH
+ tristate "Ethernet PHY Driver on EyeQ5"
+ depends on OF
+ depends on MACH_EYEQ5 || COMPILE_TEST
+ select AUXILIARY_BUS
+ select GENERIC_PHY
+ default MACH_EYEQ5
+ help
+ Enable this to support the Ethernet PHY integrated on EyeQ5.
+ It supports both RGMII and SGMII. Registers are located in a
+ shared register region called OLB. If M is selected, the
+ module will be called phy-eyeq5-eth.
+
config PHY_LPC18XX_USB_OTG
tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver"
depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 9943d742571d..c81ac7926e6b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o
obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o
obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o
+obj-$(CONFIG_PHY_EYEQ5_ETH) += phy-eyeq5-eth.o
obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
diff --git a/drivers/phy/phy-eyeq5-eth.c b/drivers/phy/phy-eyeq5-eth.c
new file mode 100644
index 000000000000..0c46359dad96
--- /dev/null
+++ b/drivers/phy/phy-eyeq5-eth.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/gfp_types.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define EQ5_PHY_COUNT 2
+
+#define EQ5_PHY0_GP 0x128
+#define EQ5_PHY1_GP 0x12c
+#define EQ5_PHY0_SGMII 0x134
+#define EQ5_PHY1_SGMII 0x138
+
+#define EQ5_GP_TX_SWRST_DIS BIT(0) // Tx SW reset
+#define EQ5_GP_TX_M_CLKE BIT(1) // Tx M clock enable
+#define EQ5_GP_SYS_SWRST_DIS BIT(2) // Sys SW reset
+#define EQ5_GP_SYS_M_CLKE BIT(3) // Sys clock enable
+#define EQ5_GP_SGMII_MODE BIT(4) // SGMII mode
+#define EQ5_GP_RGMII_DRV GENMASK(8, 5) // RGMII drive strength
+
+#define EQ5_SGMII_PWR_EN BIT(0)
+#define EQ5_SGMII_RST_DIS BIT(1)
+#define EQ5_SGMII_PLL_EN BIT(2)
+#define EQ5_SGMII_SIG_DET_SW BIT(3)
+#define EQ5_SGMII_PWR_STATE BIT(4)
+#define EQ5_SGMII_PLL_ACK BIT(18)
+#define EQ5_SGMII_PWR_STATE_ACK GENMASK(24, 20)
+
+struct eq5_phy_inst {
+ struct eq5_phy_private *priv;
+ struct phy *phy;
+ void __iomem *gp, *sgmii;
+ phy_interface_t phy_interface;
+};
+
+struct eq5_phy_private {
+ struct device *dev;
+ struct eq5_phy_inst phys[EQ5_PHY_COUNT];
+};
+
+static int eq5_phy_init(struct phy *phy)
+{
+ struct eq5_phy_inst *inst = phy_get_drvdata(phy);
+ struct eq5_phy_private *priv = inst->priv;
+ struct device *dev = priv->dev;
+ u32 reg;
+
+ dev_dbg(dev, "phy_init(inst=%td)\n", inst - priv->phys);
+
+ writel(0, inst->gp);
+ writel(0, inst->sgmii);
+
+ udelay(5);
+
+ reg = readl(inst->gp) | EQ5_GP_TX_SWRST_DIS | EQ5_GP_TX_M_CLKE |
+ EQ5_GP_SYS_SWRST_DIS | EQ5_GP_SYS_M_CLKE |
+ FIELD_PREP(EQ5_GP_RGMII_DRV, 0x9);
+ writel(reg, inst->gp);
+
+ return 0;
+}
+
+static int eq5_phy_exit(struct phy *phy)
+{
+ struct eq5_phy_inst *inst = phy_get_drvdata(phy);
+ struct eq5_phy_private *priv = inst->priv;
+ struct device *dev = priv->dev;
+
+ dev_dbg(dev, "phy_exit(inst=%td)\n", inst - priv->phys);
+
+ writel(0, inst->gp);
+ writel(0, inst->sgmii);
+ udelay(5);
+
+ return 0;
+}
+
+static int eq5_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ struct eq5_phy_inst *inst = phy_get_drvdata(phy);
+ struct eq5_phy_private *priv = inst->priv;
+ struct device *dev = priv->dev;
+
+ dev_dbg(dev, "phy_set_mode(inst=%td, mode=%d, submode=%d)\n",
+ inst - priv->phys, mode, submode);
+
+ if (mode != PHY_MODE_ETHERNET)
+ return -EOPNOTSUPP;
+
+ if (!phy_interface_mode_is_rgmii(submode) &&
+ submode != PHY_INTERFACE_MODE_SGMII)
+ return -EOPNOTSUPP;
+
+ inst->phy_interface = submode;
+ return 0;
+}
+
+static int eq5_phy_power_on(struct phy *phy)
+{
+ struct eq5_phy_inst *inst = phy_get_drvdata(phy);
+ struct eq5_phy_private *priv = inst->priv;
+ struct device *dev = priv->dev;
+ u32 reg;
+
+ dev_dbg(dev, "phy_power_on(inst=%td)\n", inst - priv->phys);
+
+ if (inst->phy_interface == PHY_INTERFACE_MODE_SGMII) {
+ writel(readl(inst->gp) | EQ5_GP_SGMII_MODE, inst->gp);
+
+ reg = EQ5_SGMII_PWR_EN | EQ5_SGMII_RST_DIS | EQ5_SGMII_PLL_EN;
+ writel(reg, inst->sgmii);
+
+ if (readl_poll_timeout(inst->sgmii, reg,
+ reg & EQ5_SGMII_PLL_ACK, 1, 100)) {
+ dev_err(dev, "PLL timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ reg = readl(inst->sgmii);
+ reg |= EQ5_SGMII_PWR_STATE | EQ5_SGMII_SIG_DET_SW;
+ writel(reg, inst->sgmii);
+ } else {
+ writel(readl(inst->gp) & ~EQ5_GP_SGMII_MODE, inst->gp);
+ writel(0, inst->sgmii);
+ }
+
+ return 0;
+}
+
+static int eq5_phy_power_off(struct phy *phy)
+{
+ struct eq5_phy_inst *inst = phy_get_drvdata(phy);
+ struct eq5_phy_private *priv = inst->priv;
+ struct device *dev = priv->dev;
+
+ dev_dbg(dev, "phy_power_off(inst=%td)\n", inst - priv->phys);
+
+ writel(readl(inst->gp) & ~EQ5_GP_SGMII_MODE, inst->gp);
+ writel(0, inst->sgmii);
+
+ return 0;
+}
+
+static const struct phy_ops eq5_phy_ops = {
+ .init = eq5_phy_init,
+ .exit = eq5_phy_exit,
+ .set_mode = eq5_phy_set_mode,
+ .power_on = eq5_phy_power_on,
+ .power_off = eq5_phy_power_off,
+};
+
+static struct phy *eq5_phy_xlate(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ struct eq5_phy_private *priv = dev_get_drvdata(dev);
+
+ if (args->args_count != 1 || args->args[0] >= EQ5_PHY_COUNT)
+ return ERR_PTR(-EINVAL);
+
+ return priv->phys[args->args[0]].phy;
+}
+
+static int eq5_phy_probe_phy(struct eq5_phy_private *priv, unsigned int index,
+ void __iomem *base, unsigned int gp,
+ unsigned int sgmii)
+{
+ struct eq5_phy_inst *inst = &priv->phys[index];
+ struct device *dev = priv->dev;
+ struct phy *phy;
+
+ phy = devm_phy_create(dev, dev->of_node, &eq5_phy_ops);
+ if (IS_ERR(phy))
+ return dev_err_probe(dev, PTR_ERR(phy),
+ "failed to create PHY %u\n", index);
+
+ inst->priv = priv;
+ inst->phy = phy;
+ inst->gp = base + gp;
+ inst->sgmii = base + sgmii;
+ inst->phy_interface = PHY_INTERFACE_MODE_NA;
+ phy_set_drvdata(phy, inst);
+
+ return 0;
+}
+
+static int eq5_phy_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct device *dev = &adev->dev;
+ struct phy_provider *provider;
+ struct eq5_phy_private *priv;
+ void __iomem *base;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ dev_set_drvdata(dev, priv);
+
+ base = dev_get_platdata(dev);
+
+ ret = eq5_phy_probe_phy(priv, 0, base, EQ5_PHY0_GP, EQ5_PHY0_SGMII);
+ if (ret)
+ return ret;
+
+ ret = eq5_phy_probe_phy(priv, 1, base, EQ5_PHY1_GP, EQ5_PHY1_SGMII);
+ if (ret)
+ return ret;
+
+ provider = devm_of_phy_provider_register(dev, eq5_phy_xlate);
+ if (IS_ERR(provider))
+ return dev_err_probe(dev, PTR_ERR(provider),
+ "registering provider failed\n");
+
+ return 0;
+}
+
+static const struct auxiliary_device_id eq5_phy_id_table[] = {
+ { .name = "clk_eyeq.phy" },
+ {}
+};
+MODULE_DEVICE_TABLE(auxiliary, eq5_phy_id_table);
+
+static struct auxiliary_driver eq5_phy_driver = {
+ .probe = eq5_phy_probe,
+ .id_table = eq5_phy_id_table,
+};
+module_auxiliary_driver(eq5_phy_driver);
+
+MODULE_DESCRIPTION("EyeQ5 Ethernet PHY driver");
+MODULE_AUTHOR("Théo Lebrun <theo.lebrun@bootlin.com>");
+MODULE_LICENSE("GPL");
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v6 1/8] dt-bindings: soc: mobileye: OLB is an Ethernet PHY provider on EyeQ5
From: Théo Lebrun @ 2026-01-27 17:09 UTC (permalink / raw)
To: Vladimir Kondratiev, Grégory Clement, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul,
Kishon Vijay Abraham I, Michael Turquette, Stephen Boyd,
Philipp Zabel, Thomas Bogendoerfer, Neil Armstrong
Cc: linux-mips, devicetree, linux-kernel, linux-phy, linux-clk,
Benoît Monin, Tawfik Bayouk, Thomas Petazzoni, Luca Ceresoli,
Théo Lebrun, Conor Dooley
In-Reply-To: <20260127-macb-phy-v6-0-cdd840588188@bootlin.com>
OLB on EyeQ5 ("mobileye,eyeq5-olb" compatible) is now declared as a
generic PHY provider. Under the hood, it provides Ethernet RGMII/SGMII
PHY support for both MAC instances.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
.../devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
index 6d11472ba5a7..56401d76a9b5 100644
--- a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
+++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
@@ -51,6 +51,9 @@ properties:
clock-names:
const: ref
+ '#phy-cells':
+ const: 1
+
patternProperties:
'-pins?$':
type: object
@@ -310,7 +313,7 @@ allOf:
properties:
'#reset-cells': false
- # Only EyeQ5 has pinctrl in OLB.
+ # Only EyeQ5 has pinctrl and PHY in OLB.
- if:
not:
properties:
@@ -320,6 +323,8 @@ allOf:
then:
patternProperties:
'-pins?$': false
+ properties:
+ '#phy-cells': false
examples:
- |
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v6 0/8] Add generic PHY driver used by MACB/GEM on EyeQ5
From: Théo Lebrun @ 2026-01-27 17:09 UTC (permalink / raw)
To: Vladimir Kondratiev, Grégory Clement, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul,
Kishon Vijay Abraham I, Michael Turquette, Stephen Boyd,
Philipp Zabel, Thomas Bogendoerfer, Neil Armstrong
Cc: linux-mips, devicetree, linux-kernel, linux-phy, linux-clk,
Benoît Monin, Tawfik Bayouk, Thomas Petazzoni, Luca Ceresoli,
Théo Lebrun, Conor Dooley, Jerome Brunet, Andrew Lunn
EyeQ5 SoCs integrate two GEM instances. A system-controller register
region named "OLB" has some control over the Ethernet PHY integration.
Past iterations [0] touched those syscon registers directly from MACB.
It was a bad idea. Extend the current OLB ecosystem with a new generic
PHY driver.
- OLB is carried by one main platform driver: clk-eyeq.
- It instantiates auxiliary devices: reset-eyeq & pinctrl-eyeq5.
- We add a new one: phy-eyeq5-eth.
I always find devicetree the simplest way to understand device
interactions, so here is a DT overview:
olb: system-controller@e00000 {
compatible = "mobileye,eyeq5-olb", "syscon";
reg = <0 0xe00000 0x0 0x400>;
// ...
#reset-cells = <2>;
#clock-cells = <1>;
#phy-cells = <1>; // <- this is new
};
macb0: ethernet@2a00000 {
compatible = "mobileye,eyeq5-gem";
phys = <&olb 0>; // <- GEM device consumes the PHY
// ...
};
macb1: ethernet@2b00000 {
compatible = "mobileye,eyeq5-gem";
phys = <&olb 1>; // <- same thing for the second instance
// ...
};
The Linux MACB driver already consumes a generic PHY for some other
compatibles, this is nothing new. The MACB series [1] has been merged
in v6.19-rc1.
--
About merging, Philipp Zabel gave his ACK for [5/7] to go into
linux-clk. The split is:
- [PATCH 1/7] dt-bindings: soc: mobileye: OLB is an Ethernet PHY provider on EyeQ5
[PATCH 6/7] MIPS: mobileye: eyeq5: add two Cadence GEM Ethernet controllers
[PATCH 7/7] MIPS: mobileye: eyeq5-epm: add two Cadence GEM Ethernet PHYs
=> linux-mips
- [PATCH 2/7] phy: Add driver for EyeQ5 Ethernet PHY wrapper
=> linux-phy
- [PATCH 3/7] clk: eyeq: use the auxiliary device creation helper
[PATCH 4/7] clk: eyeq: add EyeQ5 children auxiliary device for generic PHYs
[PATCH 5/7] reset: eyeq: drop device_set_of_node_from_dev() done by parent
=> linux-clk
Any objections to get it in before the next merge window?
The new PHY driver has only seen tiny changes since V1.
Have a nice day,
Thanks!
Théo
[0]: https://lore.kernel.org/lkml/20250627-macb-v2-15-ff8207d0bb77@bootlin.com/
[1]: https://lore.kernel.org/lkml/20251022-macb-eyeq5-v2-0-7c140abb0581@bootlin.com/
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
Changes in v6:
- Rebase upon v6.19-rc7; nothing to report.
- Add new patch "phy: sort Kconfig and Makefile".
- phy-eyeq5-eth: drop useless explicit __iomem cast to
dev_get_platdata() return value.
- I did *not* drop the Kconfig `default MACH_EYEQ5` nor driver
`dev_dbg()`. I think both are useful and should be kept. See
last revision discussion here:
https://lore.kernel.org/lkml/DFGSMN8268O0.33TYCQDBVHUHZ@bootlin.com/
- Link to v5: https://lore.kernel.org/r/20251215-macb-phy-v5-0-a9dfea39da34@bootlin.com
Changes in v5:
- phy-eyeq5-eth:
- fix #includes: add delay, gfp_types, module and drop array_size,
bug, cleanup, container_of, lockdep, mutex.
- eq5_phy_xlate(): avoid magic value, use EQ5_PHY_COUNT.
- use dev_err_probe() in error cases of devm_phy_create() and
devm_of_phy_provider_register().
- 3x Reviewed-by: Luca Ceresoli.
- Add Neil Armstrong to Cc as new PHY subsystem reviewer.
- Rebase on v6.19-rc1, tested on hardware, no changes.
- Link to v4: https://lore.kernel.org/r/20251124-macb-phy-v4-0-955c625a81a7@bootlin.com
Changes in v4:
- Append my SoB to Jerome's patch:
[PATCH v4 3/7] clk: eyeq: use the auxiliary device creation helper
- Rebase on net-next & linux-{clk,mips,phy}. Nothing to report.
- Link to v3: https://lore.kernel.org/r/20251119-macb-phy-v3-0-e9a7be186a33@bootlin.com
Changes in v3:
- Take Philipp Zabel's Reviewed-by & Acked-by trailers on reset patch.
- Take Thomas Bogendoerfer's two Acked-by trailers on DT patches.
- Rebase on net-next & test on target. Nothing to report.
- Link to v2: https://lore.kernel.org/r/20251101-macb-phy-v2-0-c1519eef16d3@bootlin.com
Changes in v2:
- Take Acked-by: Conor Dooley on dt-bindings-patch.
- s/%ld/%tu/ for printing ptrdiff_t; warnings on 32-bit archs.
Reported by NIPA's netdev/build_32bit test.
https://patchwork.kernel.org/project/netdevbpf/patch/20251021-macb-eyeq5-v1-7-3b0b5a9d2f85@bootlin.com/
https://netdev.bots.linux.dev/static/nipa/1014126/14277857/build_32bit/stderr
- Link to v1: https://lore.kernel.org/r/20251022-macb-phy-v1-0-f29f28fae721@bootlin.com
Changes since MACB V1:
- Drop the old "mobileye,olb" properties from DT patches; found while
running dtbs_check and dt_binding_check.
- Drop all patches targeting net-next. That is MACB dt-bindings patch
and MACB driver code. See there here [1].
- Link to v1: https://lore.kernel.org/lkml/20251021-macb-eyeq5-v1-0-3b0b5a9d2f85@bootlin.com/
Past versions of MACB patches:
- March 2025: [PATCH net-next 00/13] Support the Cadence MACB/GEM
instances on Mobileye EyeQ5 SoCs
https://lore.kernel.org/lkml/20250321-macb-v1-0-537b7e37971d@bootlin.com/
- June 2025: [PATCH net-next v2 00/18] Support the Cadence MACB/GEM
instances on Mobileye EyeQ5 SoCs
https://lore.kernel.org/lkml/20250627-macb-v2-0-ff8207d0bb77@bootlin.com/
- August 2025: [PATCH net v3 00/16] net: macb: various fixes & cleanup
https://lore.kernel.org/lkml/20250808-macb-fixes-v3-0-08f1fcb5179f@bootlin.com/
---
Jerome Brunet (1):
clk: eyeq: use the auxiliary device creation helper
Théo Lebrun (7):
dt-bindings: soc: mobileye: OLB is an Ethernet PHY provider on EyeQ5
phy: sort Kconfig and Makefile
phy: Add driver for EyeQ5 Ethernet PHY wrapper
clk: eyeq: add EyeQ5 children auxiliary device for generic PHYs
reset: eyeq: drop device_set_of_node_from_dev() done by parent
MIPS: mobileye: eyeq5: add two Cadence GEM Ethernet controllers
MIPS: mobileye: eyeq5-epm: add two Cadence GEM Ethernet PHYs
.../bindings/soc/mobileye/mobileye,eyeq5-olb.yaml | 7 +-
MAINTAINERS | 1 +
arch/mips/boot/dts/mobileye/eyeq5-epm5.dts | 26 +++
arch/mips/boot/dts/mobileye/eyeq5.dtsi | 45 ++++
drivers/clk/clk-eyeq.c | 60 ++---
drivers/phy/Kconfig | 75 ++++---
drivers/phy/Makefile | 7 +-
drivers/phy/phy-eyeq5-eth.c | 249 +++++++++++++++++++++
drivers/reset/reset-eyeq.c | 24 +-
9 files changed, 392 insertions(+), 102 deletions(-)
---
base-commit: aaae99475aaae1373d8bbdef6105e8ad2d4c75af
change-id: 20251022-macb-phy-21bc4e1dfbb7
Best regards,
--
Théo Lebrun <theo.lebrun@bootlin.com>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v6 2/8] phy: sort Kconfig and Makefile
From: Théo Lebrun @ 2026-01-27 17:09 UTC (permalink / raw)
To: Vladimir Kondratiev, Grégory Clement, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul,
Kishon Vijay Abraham I, Michael Turquette, Stephen Boyd,
Philipp Zabel, Thomas Bogendoerfer, Neil Armstrong
Cc: linux-mips, devicetree, linux-kernel, linux-phy, linux-clk,
Benoît Monin, Tawfik Bayouk, Thomas Petazzoni, Luca Ceresoli,
Théo Lebrun
In-Reply-To: <20260127-macb-phy-v6-0-cdd840588188@bootlin.com>
Neither Kconfig nor Makefile are sorted; reorder them.
$ diff -U100 <(grep ^config drivers/phy/Kconfig) \
<(grep ^config drivers/phy/Kconfig | sort)
$ diff -U100 <(grep ^obj-\\$ drivers/phy/Makefile) \
<(grep ^obj-\\$ drivers/phy/Makefile | sort)
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
drivers/phy/Kconfig | 62 ++++++++++++++++++++++++++--------------------------
drivers/phy/Makefile | 6 ++---
2 files changed, 34 insertions(+), 34 deletions(-)
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 678dd0452f0a..4f1b1d7f5d20 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -25,6 +25,26 @@ config GENERIC_PHY_MIPI_DPHY
Provides a number of helpers a core functions for MIPI D-PHY
drivers to us.
+config PHY_AIROHA_PCIE
+ tristate "Airoha PCIe-PHY Driver"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ depends on OF
+ select GENERIC_PHY
+ help
+ Say Y here to add support for Airoha PCIe PHY driver.
+ This driver create the basic PHY instance and provides initialize
+ callback for PCIe GEN3 port.
+
+config PHY_CAN_TRANSCEIVER
+ tristate "CAN transceiver PHY"
+ select GENERIC_PHY
+ select MULTIPLEXER
+ help
+ This option enables support for CAN transceivers as a PHY. This
+ driver provides function for putting the transceivers in various
+ functional modes using gpios and sets the attribute max link
+ rate, for CAN drivers.
+
config PHY_LPC18XX_USB_OTG
tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver"
depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
@@ -36,6 +56,17 @@ config PHY_LPC18XX_USB_OTG
This driver is need for USB0 support on LPC18xx/43xx and takes
care of enabling and clock setup.
+config PHY_NXP_PTN3222
+ tristate "NXP PTN3222 1-port eUSB2 to USB2 redriver"
+ depends on I2C
+ depends on OF
+ select GENERIC_PHY
+ help
+ Enable this to support NXP PTN3222 1-port eUSB2 to USB2 Redriver.
+ This redriver performs translation between eUSB2 and USB2 signalling
+ schemes. It supports all three USB 2.0 data rates: Low Speed, Full
+ Speed and High Speed.
+
config PHY_PISTACHIO_USB
tristate "IMG Pistachio USB2.0 PHY driver"
depends on MIPS || COMPILE_TEST
@@ -70,37 +101,6 @@ config USB_LGM_PHY
interface to interact with USB GEN-II and USB 3.x PHY that is part
of the Intel network SOC.
-config PHY_CAN_TRANSCEIVER
- tristate "CAN transceiver PHY"
- select GENERIC_PHY
- select MULTIPLEXER
- help
- This option enables support for CAN transceivers as a PHY. This
- driver provides function for putting the transceivers in various
- functional modes using gpios and sets the attribute max link
- rate, for CAN drivers.
-
-config PHY_AIROHA_PCIE
- tristate "Airoha PCIe-PHY Driver"
- depends on ARCH_AIROHA || COMPILE_TEST
- depends on OF
- select GENERIC_PHY
- help
- Say Y here to add support for Airoha PCIe PHY driver.
- This driver create the basic PHY instance and provides initialize
- callback for PCIe GEN3 port.
-
-config PHY_NXP_PTN3222
- tristate "NXP PTN3222 1-port eUSB2 to USB2 redriver"
- depends on I2C
- depends on OF
- select GENERIC_PHY
- help
- Enable this to support NXP PTN3222 1-port eUSB2 to USB2 Redriver.
- This redriver performs translation between eUSB2 and USB2 signalling
- schemes. It supports all three USB 2.0 data rates: Low Speed, Full
- Speed and High Speed.
-
source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/amlogic/Kconfig"
source "drivers/phy/broadcom/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index bfb27fb5a494..9943d742571d 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -5,14 +5,14 @@
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o
+obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o
obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o
obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
-obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
+obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o
+obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o
-obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o
-obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o
obj-y += allwinner/ \
amlogic/ \
broadcom/ \
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* Re: [PATCH net-next v2 00/14] net: stmmac: SerDes, PCS, BASE-X, and inband goodies
From: Russell King (Oracle) @ 2026-01-27 15:42 UTC (permalink / raw)
To: Mohd Ayaan Anwar
Cc: Andrew Lunn, Heiner Kallweit, Alexandre Torgue, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Konrad Dybcio,
linux-arm-kernel, linux-arm-msm, linux-phy, linux-stm32,
Maxime Coquelin, Neil Armstrong, netdev, Paolo Abeni, Vinod Koul
In-Reply-To: <aXjSbu6L6ICYOPiJ@oss.qualcomm.com>
On Tue, Jan 27, 2026 at 08:27:50PM +0530, Mohd Ayaan Anwar wrote:
> It is using the same SerDes PHY (qcom_dwmac_sgmii_phy_driver).
>
> I added additional debug prints, and I think the crash is due to
> BMSR_ESTATEN not being set in GMAC_AN_STATUS.
I'm going to submit a patch which fixes the phylink crash - it should
be able to cope with pcs being NULL at the oops site.
> During pcs_init, BIT(8) of GMAC_AN_STATUS is 0:
> [ 7.985913] [DBG] GMAC_AN_STATUS = 8
Hmm. This means that your hardware doesn't support TBI or RTBI modes
(which is what the dwmac core uses for BASE-X) and what it's actually
offering is an up-clocked Cisco SGMII implementation.
With AN disabled, this is compatible with 2500BASE-X implementations
that do not require AN.
> Therefore, this check:
> if (readl(spcs->base + GMAC_AN_STATUS) & BMSR_ESTATEN) {
> __set_bit(PHY_INTERFACE_MODE_1000BASEX,
> spcs->pcs.supported_interfaces);
>
> /* Only allow 2500Base-X if the SerDes has support. */
> ret = dwmac_serdes_validate(priv, PHY_INTERFACE_MODE_2500BASEX);
> if (ret == 0)
> __set_bit(PHY_INTERFACE_MODE_2500BASEX,
> spcs->pcs.supported_interfaces);
> }
> fails, and PHY_INTERFACE_MODE_2500BASEX never gets set in
> pcs.supported_interfaces. Pardon my naivete, but does the
> BMSR_ESTATEN bit not being set break some standard?
BMSR_ESTATEN means that the PHY supports register 15, MII_ESTATUS.
This register indicates, for 1G speeds, which medium (BASE-T or BASE-X)
and duplexes are supported by the PHY.
Given that SGMII isn't an 802.3 standard, but an extension to BASE-X,
technically it should still, but given that these are not actually a
PHY, it's not a big problem.
However, what it does mean is that we could handle this differently.
We could remove the check here, and set 1000BASE-X and, if the SerDes
supports it, 2500BASE-X, but we would need
dwmac_integrated_pcs_inband_caps() to indicate that inband is not
supported in these unless ESTATEN is set.
> I also tried enabling comma detect during dwmac_integrated_pcs_config,
> but I am still seeing the Tx timeouts. I remember that when I had
> tested the patches in October (without the SerDes driver changes),
> the link state used to flap, but the data path became functional
> after the link stabilized.
I wonder whether the SerDes needs to be calibrated after the link has
come up and the clocks configured. phy_calibdate() will re-invoke the
programming of the SerDes, so you could try adding that at the bottom
of ethqos_configure_sgmii():
return phy_calibrate(priv->plat->serdes);
which will do the calibration after the clocks have been set, and see
whether that stabilises the link.
Thanks.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH net-next v2 00/14] net: stmmac: SerDes, PCS, BASE-X, and inband goodies
From: Andrew Lunn @ 2026-01-27 15:17 UTC (permalink / raw)
To: Mohd Ayaan Anwar
Cc: Russell King (Oracle), Heiner Kallweit, Alexandre Torgue,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Konrad Dybcio, linux-arm-kernel, linux-arm-msm, linux-phy,
linux-stm32, Maxime Coquelin, Neil Armstrong, netdev, Paolo Abeni,
Vinod Koul
In-Reply-To: <aXjSbu6L6ICYOPiJ@oss.qualcomm.com>
> I added additional debug prints, and I think the crash is due to
> BMSR_ESTATEN not being set in GMAC_AN_STATUS.
>
> During pcs_init, BIT(8) of GMAC_AN_STATUS is 0:
> [ 7.985913] [DBG] GMAC_AN_STATUS = 8
>
> Therefore, this check:
> if (readl(spcs->base + GMAC_AN_STATUS) & BMSR_ESTATEN) {
> __set_bit(PHY_INTERFACE_MODE_1000BASEX,
> spcs->pcs.supported_interfaces);
>
> /* Only allow 2500Base-X if the SerDes has support. */
> ret = dwmac_serdes_validate(priv, PHY_INTERFACE_MODE_2500BASEX);
> if (ret == 0)
> __set_bit(PHY_INTERFACE_MODE_2500BASEX,
> spcs->pcs.supported_interfaces);
> }
> fails, and PHY_INTERFACE_MODE_2500BASEX never gets set in
> pcs.supported_interfaces. Pardon my naivete, but does the
> BMSR_ESTATEN bit not being set break some standard?
You might want to check the IEEE 802.3 standard. It is free to
download from IEEE.
The original C22 register definitions only supported 10 and
100Mbps. In order to support 1G, more registers are needed. The
BMSR_ESTATEN bit indicate the PHY supports having more status bits in
register 15. Register 15 then indicates if 1000BaseX, 1000Base-T is
supported.
If the SERDES supports 1000BaseX, it should have BMSR_ESTATEN set, and
register 15 should indicate 1000BASE-X.
Andrew
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH] phy: marvell: phy-mvebu-cp110-comphy: Remove unnecessary NULL check before clk_disable_unprepare()
From: Markus Elfring @ 2026-01-27 15:16 UTC (permalink / raw)
To: Chen Ni, linux-phy, Neil Armstrong, Vinod Koul; +Cc: LKML
In-Reply-To: <20260126035551.1615453-1-nichen@iscas.ac.cn>
> clk_disable_unprepare() already checks NULL by using IS_ERR_OR_NULL.
This function calls further functions which perform known input parameter validation.
> Remove unneeded NULL check for clk here.
May two blank lines be omitted accordingly?
Regards,
Markus
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v2 5/6] phy: tegra: xusb: Move .set_mode() to a shared location
From: Diogo Ivo @ 2026-01-27 15:11 UTC (permalink / raw)
To: Mathias Nyman, Greg Kroah-Hartman, Thierry Reding,
Jonathan Hunter, JC Kuo, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong
Cc: linux-usb, linux-tegra, linux-kernel, linux-phy, devicetree,
Diogo Ivo
In-Reply-To: <20260127-diogo-tegra_phy-v2-0-787b9eed3ed5@tecnico.ulisboa.pt>
As both Tegra210 and Tegra186 can have a common XUSB .set_mode()
implementation move it to a location where it can be used by both
platforms. Move Tegra210 to this common implementation.
While at it fix a typo in a comment.
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
v1->v2:
- New patch
---
drivers/phy/tegra/xusb-tegra210.c | 43 +--------------------------------------
drivers/phy/tegra/xusb.c | 40 ++++++++++++++++++++++++++++++++++++
drivers/phy/tegra/xusb.h | 2 ++
3 files changed, 43 insertions(+), 42 deletions(-)
diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
index be03a17afd7e..14e24296641b 100644
--- a/drivers/phy/tegra/xusb-tegra210.c
+++ b/drivers/phy/tegra/xusb-tegra210.c
@@ -1910,47 +1910,6 @@ static int tegra210_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
return 0;
}
-static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode,
- int submode)
-{
- struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
- struct tegra_xusb_padctl *padctl = lane->pad->padctl;
- struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
- lane->index);
- int err = 0;
-
- mutex_lock(&padctl->lock);
-
- dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
-
- if (mode == PHY_MODE_USB_OTG) {
- if (submode == USB_ROLE_HOST) {
- tegra210_xusb_padctl_id_override(padctl, true);
-
- err = regulator_enable(port->supply);
- } else if (submode == USB_ROLE_DEVICE) {
- tegra210_xusb_padctl_vbus_override(padctl, true);
- } else if (submode == USB_ROLE_NONE) {
- /*
- * When port is peripheral only or role transitions to
- * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
- * be enabled.
- */
- if (port->role == USB_ROLE_HOST)
- regulator_disable(port->supply);
-
- tegra210_xusb_padctl_id_override(padctl, false);
- tegra210_xusb_padctl_vbus_override(padctl, false);
- }
-
- port->role = submode;
- }
-
- mutex_unlock(&padctl->lock);
-
- return err;
-}
-
static int tegra210_usb2_phy_power_on(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
@@ -2174,7 +2133,7 @@ static const struct phy_ops tegra210_usb2_phy_ops = {
.exit = tegra210_usb2_phy_exit,
.power_on = tegra210_usb2_phy_power_on,
.power_off = tegra210_usb2_phy_power_off,
- .set_mode = tegra210_usb2_phy_set_mode,
+ .set_mode = tegra_xusb_usb2_phy_set_mode,
.owner = THIS_MODULE,
};
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index 0443465bcf50..2327275740f8 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -770,6 +770,46 @@ bool tegra_xusb_usb2_port_wait_role_none(struct tegra_xusb_padctl *padctl, int i
}
EXPORT_SYMBOL_GPL(tegra_xusb_usb2_port_wait_role_none);
+int tegra_xusb_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
+ lane->index);
+ int err = 0;
+
+ mutex_lock(&padctl->lock);
+
+ dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
+
+ if (mode == PHY_MODE_USB_OTG) {
+ if (submode == USB_ROLE_HOST) {
+ tegra_xusb_padctl_set_id_override(padctl, true);
+
+ err = regulator_enable(port->supply);
+ } else if (submode == USB_ROLE_DEVICE) {
+ tegra_xusb_padctl_set_vbus_override(padctl, true);
+ } else if (submode == USB_ROLE_NONE) {
+ /*
+ * When port is peripheral only or role transitions to
+ * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
+ * enabled.
+ */
+ if (port->role == USB_ROLE_HOST)
+ regulator_disable(port->supply);
+
+ tegra_xusb_padctl_set_id_override(padctl, false);
+ tegra_xusb_padctl_set_vbus_override(padctl, false);
+ }
+
+ port->role = submode;
+ }
+
+ mutex_unlock(&padctl->lock);
+
+ return err;
+}
+
static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
{
struct tegra_xusb_port *port = &usb2->base;
diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h
index 08053a730d54..36cc87ae757e 100644
--- a/drivers/phy/tegra/xusb.h
+++ b/drivers/phy/tegra/xusb.h
@@ -501,6 +501,8 @@ struct tegra_xusb_lane *tegra_xusb_find_lane(struct tegra_xusb_padctl *padctl,
const char *name,
unsigned int index);
+int tegra_xusb_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode);
+
#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
extern const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc;
#endif
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 6/6] phy: tegra: xusb: Move T186 .set_mode() to common implementation
From: Diogo Ivo @ 2026-01-27 15:11 UTC (permalink / raw)
To: Mathias Nyman, Greg Kroah-Hartman, Thierry Reding,
Jonathan Hunter, JC Kuo, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong
Cc: linux-usb, linux-tegra, linux-kernel, linux-phy, devicetree,
Diogo Ivo
In-Reply-To: <20260127-diogo-tegra_phy-v2-0-787b9eed3ed5@tecnico.ulisboa.pt>
Move the Tegra186 PHY .set_mode() callback to a common implementation.
In order to do this first revert cefc1caee9dd.
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
v1->v2:
- New patch
---
drivers/phy/tegra/xusb-tegra186.c | 73 ++++++---------------------------------
1 file changed, 10 insertions(+), 63 deletions(-)
diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c
index bec9616c4a2e..bf678829245d 100644
--- a/drivers/phy/tegra/xusb-tegra186.c
+++ b/drivers/phy/tegra/xusb-tegra186.c
@@ -786,15 +786,13 @@ static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
}
static int tegra186_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
- struct tegra_xusb_usb2_port *port, bool status)
+ bool status)
{
- u32 value, id_override;
- int err = 0;
+ u32 value;
dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
value = padctl_readl(padctl, USB2_VBUS_ID);
- id_override = value & ID_OVERRIDE(~0);
if (status) {
if (value & VBUS_OVERRIDE) {
@@ -805,68 +803,16 @@ static int tegra186_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
value = padctl_readl(padctl, USB2_VBUS_ID);
}
- if (id_override != ID_OVERRIDE_GROUNDED) {
- value &= ~ID_OVERRIDE(~0);
- value |= ID_OVERRIDE_GROUNDED;
- padctl_writel(padctl, value, USB2_VBUS_ID);
-
- err = regulator_enable(port->supply);
- if (err) {
- dev_err(padctl->dev, "Failed to enable regulator: %d\n", err);
- return err;
- }
- }
+ value &= ~ID_OVERRIDE(~0);
+ value |= ID_OVERRIDE_GROUNDED;
} else {
- if (id_override == ID_OVERRIDE_GROUNDED) {
- /*
- * The regulator is disabled only when the role transitions
- * from USB_ROLE_HOST to USB_ROLE_NONE.
- */
- err = regulator_disable(port->supply);
- if (err) {
- dev_err(padctl->dev, "Failed to disable regulator: %d\n", err);
- return err;
- }
-
- value &= ~ID_OVERRIDE(~0);
- value |= ID_OVERRIDE_FLOATING;
- padctl_writel(padctl, value, USB2_VBUS_ID);
- }
+ value &= ~ID_OVERRIDE(~0);
+ value |= ID_OVERRIDE_FLOATING;
}
- return 0;
-}
-
-static int tegra186_utmi_phy_set_mode(struct phy *phy, enum phy_mode mode,
- int submode)
-{
- struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
- struct tegra_xusb_padctl *padctl = lane->pad->padctl;
- struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
- lane->index);
- int err = 0;
-
- mutex_lock(&padctl->lock);
+ padctl_writel(padctl, value, USB2_VBUS_ID);
- dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
-
- if (mode == PHY_MODE_USB_OTG) {
- if (submode == USB_ROLE_HOST) {
- err = tegra186_xusb_padctl_id_override(padctl, port, true);
- if (err)
- goto out;
- } else if (submode == USB_ROLE_DEVICE) {
- tegra186_xusb_padctl_vbus_override(padctl, true);
- } else if (submode == USB_ROLE_NONE) {
- err = tegra186_xusb_padctl_id_override(padctl, port, false);
- if (err)
- goto out;
- tegra186_xusb_padctl_vbus_override(padctl, false);
- }
- }
-out:
- mutex_unlock(&padctl->lock);
- return err;
+ return 0;
}
static int tegra186_utmi_phy_power_on(struct phy *phy)
@@ -1017,7 +963,7 @@ static const struct phy_ops utmi_phy_ops = {
.exit = tegra186_utmi_phy_exit,
.power_on = tegra186_utmi_phy_power_on,
.power_off = tegra186_utmi_phy_power_off,
- .set_mode = tegra186_utmi_phy_set_mode,
+ .set_mode = tegra_xusb_usb2_phy_set_mode,
.owner = THIS_MODULE,
};
@@ -1578,6 +1524,7 @@ static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = {
.suspend_noirq = tegra186_xusb_padctl_suspend_noirq,
.resume_noirq = tegra186_xusb_padctl_resume_noirq,
.vbus_override = tegra186_xusb_padctl_vbus_override,
+ .id_override = tegra186_xusb_padctl_id_override,
.utmi_pad_power_on = tegra186_utmi_pad_power_on,
.utmi_pad_power_down = tegra186_utmi_pad_power_down,
};
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 4/6] phy: tegra: xusb: Add ID override support to padctl
From: Diogo Ivo @ 2026-01-27 15:11 UTC (permalink / raw)
To: Mathias Nyman, Greg Kroah-Hartman, Thierry Reding,
Jonathan Hunter, JC Kuo, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong
Cc: linux-usb, linux-tegra, linux-kernel, linux-phy, devicetree,
Diogo Ivo
In-Reply-To: <20260127-diogo-tegra_phy-v2-0-787b9eed3ed5@tecnico.ulisboa.pt>
In preparation to move the XUSB PHY .set_mode() callback into a common
implementation introduce a generic id_override callback in
tegra_xusb_padctl_ops that delegates to a SoC-specific implementation
and register Tegra210 with the new callback.
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
v1->v2:
- New patch
---
drivers/phy/tegra/xusb-tegra210.c | 1 +
drivers/phy/tegra/xusb.c | 10 ++++++++++
drivers/phy/tegra/xusb.h | 1 +
include/linux/phy/tegra/xusb.h | 2 ++
4 files changed, 14 insertions(+)
diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
index 3abdf0182d67..be03a17afd7e 100644
--- a/drivers/phy/tegra/xusb-tegra210.c
+++ b/drivers/phy/tegra/xusb-tegra210.c
@@ -3262,6 +3262,7 @@ static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = {
.usb3_set_lfps_detect = tegra210_usb3_set_lfps_detect,
.hsic_set_idle = tegra210_hsic_set_idle,
.vbus_override = tegra210_xusb_padctl_vbus_override,
+ .id_override = tegra210_xusb_padctl_id_override,
.utmi_port_reset = tegra210_utmi_port_reset,
};
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index 03fd6269fdbe..0443465bcf50 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -1498,6 +1498,16 @@ int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl,
}
EXPORT_SYMBOL_GPL(tegra_xusb_padctl_set_vbus_override);
+int tegra_xusb_padctl_set_id_override(struct tegra_xusb_padctl *padctl,
+ bool val)
+{
+ if (padctl->soc->ops->id_override)
+ return padctl->soc->ops->id_override(padctl, val);
+
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(tegra_xusb_padctl_set_id_override);
+
int tegra_phy_xusb_utmi_port_reset(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h
index 273af147dfd3..08053a730d54 100644
--- a/drivers/phy/tegra/xusb.h
+++ b/drivers/phy/tegra/xusb.h
@@ -411,6 +411,7 @@ struct tegra_xusb_padctl_ops {
int (*usb3_set_lfps_detect)(struct tegra_xusb_padctl *padctl,
unsigned int index, bool enable);
int (*vbus_override)(struct tegra_xusb_padctl *padctl, bool set);
+ int (*id_override)(struct tegra_xusb_padctl *padctl, bool set);
int (*utmi_port_reset)(struct phy *phy);
void (*utmi_pad_power_on)(struct phy *phy);
void (*utmi_pad_power_down)(struct phy *phy);
diff --git a/include/linux/phy/tegra/xusb.h b/include/linux/phy/tegra/xusb.h
index a0d3d5b7cf33..116d0c6609cb 100644
--- a/include/linux/phy/tegra/xusb.h
+++ b/include/linux/phy/tegra/xusb.h
@@ -21,6 +21,8 @@ int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
unsigned int port, bool enable);
int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl,
bool val);
+int tegra_xusb_padctl_set_id_override(struct tegra_xusb_padctl *padctl,
+ bool val);
void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy);
void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy);
int tegra_phy_xusb_utmi_port_reset(struct phy *phy);
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 3/6] phy: tegra: xusb: Fix ordering issue when switching roles on USB2 ports
From: Diogo Ivo @ 2026-01-27 15:11 UTC (permalink / raw)
To: Mathias Nyman, Greg Kroah-Hartman, Thierry Reding,
Jonathan Hunter, JC Kuo, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong
Cc: linux-usb, linux-tegra, linux-kernel, linux-phy, devicetree,
Diogo Ivo
In-Reply-To: <20260127-diogo-tegra_phy-v2-0-787b9eed3ed5@tecnico.ulisboa.pt>
The current implementation of USB2 role switching on Tegra relies on
whichever the previous USB controller driver was using the PHY to first
"yield" it back to USB_ROLE_NONE before the next controller configures
it for the new role. However, no mechanism to guarantee this ordering
was implemented, and currently, in the general case, the configuration
functions tegra_xhci_id_work() and tegra_xudc_usb_role_sw_work() end up
running in the same order regardless of the transition being HOST->DEVICE
or DEVICE->HOST, leading to one of these transitions ending up in a
non-working state due to the new configuration being clobbered by the
previous controller driver setting USB_ROLE_NONE after the fact.
Fix this by introducing a helper that waits for the USB2 port’s current
role to become USB_ROLE_NONE and add it in the configuration functions
above before setting the role to either USB_ROLE_HOST or
USB_ROLE_DEVICE.
The specific parameters of the helper function were determined based on
my testing on a Tegra210 platform, Smaug, with some extra slack added in.
With these parameters I never observed any timeout in role switching.
As mentioned, this was tested on a Tegra210 platform. However, due to the
similar approach in Tegra186 it is likely that not only this problem exists
there but that this patch also fixes it.
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
v1->v2:
- Edit commit message and add code comment explaining origin of wait
parameters in tegra_xusb_usb2_port_wait_role_none()
- Export tegra_xusb_usb2_port_wait_role_none()
- Fix NULL pointer dereference in error message
- Remove extra blank line
---
drivers/phy/tegra/xusb.c | 30 ++++++++++++++++++++++++++++++
drivers/usb/gadget/udc/tegra-xudc.c | 4 ++++
drivers/usb/host/xhci-tegra.c | 14 ++++++++++----
include/linux/phy/tegra/xusb.h | 1 +
4 files changed, 45 insertions(+), 4 deletions(-)
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index c89df95aa6ca..03fd6269fdbe 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -740,6 +740,36 @@ static void tegra_xusb_parse_usb_role_default_mode(struct tegra_xusb_port *port)
}
}
+/*
+ * Helper function that waits for the port's role to become USB_ROLE_NONE. As the
+ * TRMs do not specify how long the transition is expected to take the sleep duration
+ * and number of retries were determined empirically on a Tegra210 platform, with some
+ * extra slack added in.
+ */
+bool tegra_xusb_usb2_port_wait_role_none(struct tegra_xusb_padctl *padctl, int index)
+{
+ struct tegra_xusb_usb2_port *usb2 = tegra_xusb_find_usb2_port(padctl,
+ index);
+ int retries = 5;
+
+ if (!usb2) {
+ dev_err(padctl->dev, "no port found for USB2 lane %u\n", index);
+ return false;
+ }
+
+ do {
+ if (usb2->role == USB_ROLE_NONE)
+ return true;
+
+ usleep_range(50, 60);
+ } while (retries--);
+
+ dev_err(&usb2->base.dev, "timed out waiting for USB_ROLE_NONE");
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(tegra_xusb_usb2_port_wait_role_none);
+
static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
{
struct tegra_xusb_port *port = &usb2->base;
diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c
index 9d2007f448c0..24b0a9ce75d9 100644
--- a/drivers/usb/gadget/udc/tegra-xudc.c
+++ b/drivers/usb/gadget/udc/tegra-xudc.c
@@ -698,8 +698,12 @@ static void tegra_xudc_restore_port_speed(struct tegra_xudc *xudc)
static void tegra_xudc_device_mode_on(struct tegra_xudc *xudc)
{
+ int port = tegra_xusb_padctl_get_port_number(xudc->curr_utmi_phy);
int err;
+ if (!tegra_xusb_usb2_port_wait_role_none(xudc->padctl, port))
+ return;
+
pm_runtime_get_sync(xudc->dev);
tegra_phy_xusb_utmi_pad_power_on(xudc->curr_utmi_phy);
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index 927861ca14f2..b51afb4036b5 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -1352,15 +1352,21 @@ static void tegra_xhci_id_work(struct work_struct *work)
struct tegra_xusb_mbox_msg msg;
struct phy *phy = tegra_xusb_get_phy(tegra, "usb2",
tegra->otg_usb2_port);
+ enum usb_role role = USB_ROLE_NONE;
u32 status;
int ret;
dev_dbg(tegra->dev, "host mode %s\n", str_on_off(tegra->host_mode));
- if (tegra->host_mode)
- phy_set_mode_ext(phy, PHY_MODE_USB_OTG, USB_ROLE_HOST);
- else
- phy_set_mode_ext(phy, PHY_MODE_USB_OTG, USB_ROLE_NONE);
+ if (tegra->host_mode) {
+ if (!tegra_xusb_usb2_port_wait_role_none(tegra->padctl,
+ tegra->otg_usb2_port))
+ return;
+
+ role = USB_ROLE_HOST;
+ }
+
+ phy_set_mode_ext(phy, PHY_MODE_USB_OTG, role);
tegra->otg_usb3_port = tegra_xusb_padctl_get_usb3_companion(tegra->padctl,
tegra->otg_usb2_port);
diff --git a/include/linux/phy/tegra/xusb.h b/include/linux/phy/tegra/xusb.h
index 6ca51e0080ec..a0d3d5b7cf33 100644
--- a/include/linux/phy/tegra/xusb.h
+++ b/include/linux/phy/tegra/xusb.h
@@ -33,5 +33,6 @@ int tegra_xusb_padctl_disable_phy_sleepwalk(struct tegra_xusb_padctl *padctl, st
int tegra_xusb_padctl_enable_phy_wake(struct tegra_xusb_padctl *padctl, struct phy *phy);
int tegra_xusb_padctl_disable_phy_wake(struct tegra_xusb_padctl *padctl, struct phy *phy);
bool tegra_xusb_padctl_remote_wake_detected(struct tegra_xusb_padctl *padctl, struct phy *phy);
+bool tegra_xusb_usb2_port_wait_role_none(struct tegra_xusb_padctl *padctl, int index);
#endif /* PHY_TEGRA_XUSB_H */
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 1/6] phy: tegra: xusb: Fix USB2 port regulator disable logic
From: Diogo Ivo @ 2026-01-27 15:11 UTC (permalink / raw)
To: Mathias Nyman, Greg Kroah-Hartman, Thierry Reding,
Jonathan Hunter, JC Kuo, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong
Cc: linux-usb, linux-tegra, linux-kernel, linux-phy, devicetree,
Diogo Ivo, stable
In-Reply-To: <20260127-diogo-tegra_phy-v2-0-787b9eed3ed5@tecnico.ulisboa.pt>
The USB2 PHY mode handling on Tegra210 incorrectly relied on
regulator_is_enabled() when determining whether the VBUS supply should
be disabled during role changes. This is because regulator_is_enabled()
reports exactly what is states and not if there is an unbalanced number
of calls between regulator_enable() and regulator_disable(). For
example, regulator_is_enabled() always reports true on a fixed-regulator
with no enable gpio, which is the case on the Pixel C.
This then leads to the PHY driver wrongfully calling regulator_disable()
when transitioning from USB_ROLE_DEVICE to USB_ROLE_NONE since the driver
did not previously call the corresponding regulator_enable().
Fix this by keeping track of the current role and updating the logic to
disable the regulator only when the previous role was USB_ROLE_HOST.
Cc: stable@vger.kernel.org
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
v1->v2:
- Do not fix typo in comment
---
drivers/phy/tegra/xusb-tegra210.c | 4 +++-
drivers/phy/tegra/xusb.h | 1 +
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
index 3409924498e9..3abdf0182d67 100644
--- a/drivers/phy/tegra/xusb-tegra210.c
+++ b/drivers/phy/tegra/xusb-tegra210.c
@@ -1936,12 +1936,14 @@ static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode,
* USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
* be enabled.
*/
- if (regulator_is_enabled(port->supply))
+ if (port->role == USB_ROLE_HOST)
regulator_disable(port->supply);
tegra210_xusb_padctl_id_override(padctl, false);
tegra210_xusb_padctl_vbus_override(padctl, false);
}
+
+ port->role = submode;
}
mutex_unlock(&padctl->lock);
diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h
index d2b5f9565132..273af147dfd3 100644
--- a/drivers/phy/tegra/xusb.h
+++ b/drivers/phy/tegra/xusb.h
@@ -317,6 +317,7 @@ struct tegra_xusb_usb2_port {
enum usb_dr_mode mode;
bool internal;
int usb3_port_fake;
+ enum usb_role role;
};
static inline struct tegra_xusb_usb2_port *
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 0/6] Fixes to Tegra USB role switching and phy handling
From: Diogo Ivo @ 2026-01-27 15:11 UTC (permalink / raw)
To: Mathias Nyman, Greg Kroah-Hartman, Thierry Reding,
Jonathan Hunter, JC Kuo, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong
Cc: linux-usb, linux-tegra, linux-kernel, linux-phy, devicetree,
Diogo Ivo, stable
Hello,
This patch series contains fixes/improvements for USB role switching on the
Tegra210 and Tegra186 SoCs.
The first patch addresses a wrong check on the logic that disables the
VBUS regulator.
The second patch removes a redundant mutex lock when setting the PHY
mode.
The third patch guarantees proper ordering of events when switching PHY
roles.
The remaining patches are included to standardize the PHY .set_mode()
callback between Tegra186 and Tegra210.
With this patch series this feature can only be controlled from userspace,
by writing the desired role to sysfs as
echo "role" > /sys/class/usb_role/usb2-0-role-switch/role
with role being one of {device, host, none}.
Further patches will enable automatic role switching via the 'cros_ec_typec'
driver which is currently broken on Smaug.
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
Changes in v2:
- Remove DT patches already taken to be upstreamed
- Add standardization between Tegra210 and Tegra186
- Address review comments from v1, detailed descriptions in each patch
- Link to v1: https://lore.kernel.org/r/20251204-diogo-tegra_phy-v1-0-51a2016d0be8@tecnico.ulisboa.pt
---
Diogo Ivo (6):
phy: tegra: xusb: Fix USB2 port regulator disable logic
usb: xhci: tegra: Remove redundant mutex when setting phy mode
phy: tegra: xusb: Fix ordering issue when switching roles on USB2 ports
phy: tegra: xusb: Add ID override support to padctl
phy: tegra: xusb: Move .set_mode() to a shared location
phy: tegra: xusb: Move T186 .set_mode() to common implementation
drivers/phy/tegra/xusb-tegra186.c | 73 +++++----------------------------
drivers/phy/tegra/xusb-tegra210.c | 42 +------------------
drivers/phy/tegra/xusb.c | 80 +++++++++++++++++++++++++++++++++++++
drivers/phy/tegra/xusb.h | 4 ++
drivers/usb/gadget/udc/tegra-xudc.c | 4 ++
drivers/usb/host/xhci-tegra.c | 14 ++++---
include/linux/phy/tegra/xusb.h | 3 ++
7 files changed, 111 insertions(+), 109 deletions(-)
---
base-commit: b02a5530af8abe0d3cd4852ba48990716e962934
change-id: 20251201-diogo-tegra_phy-86c89cab7377
Best regards,
--
Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v2 2/6] usb: xhci: tegra: Remove redundant mutex when setting phy mode
From: Diogo Ivo @ 2026-01-27 15:11 UTC (permalink / raw)
To: Mathias Nyman, Greg Kroah-Hartman, Thierry Reding,
Jonathan Hunter, JC Kuo, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong
Cc: linux-usb, linux-tegra, linux-kernel, linux-phy, devicetree,
Diogo Ivo
In-Reply-To: <20260127-diogo-tegra_phy-v2-0-787b9eed3ed5@tecnico.ulisboa.pt>
As the PHY subsystem already synchronizes concurrent accesses to a PHY
instance with a core-internal mutex remove the driver specific mutex
synchronization.
Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
---
v1->v2:
- New patch
---
drivers/usb/host/xhci-tegra.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index 8b492871d21d..927861ca14f2 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -1357,15 +1357,11 @@ static void tegra_xhci_id_work(struct work_struct *work)
dev_dbg(tegra->dev, "host mode %s\n", str_on_off(tegra->host_mode));
- mutex_lock(&tegra->lock);
-
if (tegra->host_mode)
phy_set_mode_ext(phy, PHY_MODE_USB_OTG, USB_ROLE_HOST);
else
phy_set_mode_ext(phy, PHY_MODE_USB_OTG, USB_ROLE_NONE);
- mutex_unlock(&tegra->lock);
-
tegra->otg_usb3_port = tegra_xusb_padctl_get_usb3_companion(tegra->padctl,
tegra->otg_usb2_port);
--
2.52.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* Re: [PATCH net-next v2 00/14] net: stmmac: SerDes, PCS, BASE-X, and inband goodies
From: Mohd Ayaan Anwar @ 2026-01-27 14:57 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: Andrew Lunn, Heiner Kallweit, Alexandre Torgue, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Konrad Dybcio,
linux-arm-kernel, linux-arm-msm, linux-phy, linux-stm32,
Maxime Coquelin, Neil Armstrong, netdev, Paolo Abeni, Vinod Koul
In-Reply-To: <aXPo5R1Q-qWG3r3l@shell.armlinux.org.uk>
On Fri, Jan 23, 2026 at 09:32:21PM +0000, Russell King (Oracle) wrote:
>
> and the failing store is the one for that last line of C code - in
> other words, pcs = NULL.
>
> This means that mac_select_pcs() returned NULL when being asked
> "which PCS should be used for 2500base-X" ?
>
> This suggests that the SerDes detection of support for 2500BASE-X
> isn't working, meaning that stmmac_mac_select_pcs() ends up returning
> NULL, rather than &priv->integrated_pcs->pcs.
>
> That would only happen if:
>
> /* Only allow 2500Base-X if the SerDes has support. */
> ret = dwmac_serdes_validate(priv, PHY_INTERFACE_MODE_2500BASEX);
> if (ret == 0)
> __set_bit(PHY_INTERFACE_MODE_2500BASEX,
> spcs->pcs.supported_interfaces);
>
> fails, meaning we don't set that interface mode for the PCS.
> dwmac_serdes_validate() calls phy_validate() for PHY_MODE_ETHERNET
> with the PHY interface mode as the sub mode.
>
> Patch 3 adds the required methods to phy-qcom-sgmii-eth.c to allow
> phy_validate() to indicate whether this is supported or not:
>
> .validate = qcom_dwmac_sgmii_phy_validate,
>
> and its implementation is:
>
> int ret = qcom_dwmac_sgmii_phy_speed(mode, submode);
>
> return ret < 0 ? ret : 0;
>
> where qcom_dwmac_sgmii_phy_speed() is:
>
> if (mode != PHY_MODE_ETHERNET)
> return -EINVAL;
>
> if (submode == PHY_INTERFACE_MODE_SGMII ||
> submode == PHY_INTERFACE_MODE_1000BASEX)
> return SPEED_1000;
>
> if (submode == PHY_INTERFACE_MODE_2500BASEX)
> return SPEED_2500;
>
> return -EINVAL;
>
> So, this should be returning a positive integer (SPEED_2500), which
> should cause phy_validate(serdes, PHY_MODE_ETHERNET,
> PHY_INTERFACE_MODE_2500BASEX, NULL) to return success (zero). That
> should result in PHY_INTERFACE_MODE_2500BASEX being set in
> spcs->pcs.supported_interfaces, and thus &priv->integrated_pcs->pcs
> being returned for PHY_INTERFACE_MODE_2500BASEX.
>
> Is the particular hardware you're running this oopsing test on not
> using a SerDes PHY? If that's the case, how does it switch between
> 2.5Gbps and 1Gbps data rate on the SerDes?
>
It is using the same SerDes PHY (qcom_dwmac_sgmii_phy_driver).
I added additional debug prints, and I think the crash is due to
BMSR_ESTATEN not being set in GMAC_AN_STATUS.
During pcs_init, BIT(8) of GMAC_AN_STATUS is 0:
[ 7.985913] [DBG] GMAC_AN_STATUS = 8
Therefore, this check:
if (readl(spcs->base + GMAC_AN_STATUS) & BMSR_ESTATEN) {
__set_bit(PHY_INTERFACE_MODE_1000BASEX,
spcs->pcs.supported_interfaces);
/* Only allow 2500Base-X if the SerDes has support. */
ret = dwmac_serdes_validate(priv, PHY_INTERFACE_MODE_2500BASEX);
if (ret == 0)
__set_bit(PHY_INTERFACE_MODE_2500BASEX,
spcs->pcs.supported_interfaces);
}
fails, and PHY_INTERFACE_MODE_2500BASEX never gets set in
pcs.supported_interfaces. Pardon my naivete, but does the
BMSR_ESTATEN bit not being set break some standard?
If I remove the check, the NULL pointer dereference is not observed
anymore. Although the SerDes link is still unstable.
I also tried enabling comma detect during dwmac_integrated_pcs_config,
but I am still seeing the Tx timeouts. I remember that when I had
tested the patches in October (without the SerDes driver changes),
the link state used to flap, but the data path became functional
after the link stabilized.
Ayaan
---
Full Logs (Speed Change: 1G -> 2.5G)
[ 244.817499] qcom-ethqos 23040000.ethernet eth1: pcs link down
[ 257.066210] dwmac: PCS configuration changed from phylink by glue, please report: 0x00040000 -> 0x00041000
[ 257.076143] dwmac: ANE 0 -> 1
[ 257.079668] qcom-ethqos 23040000.ethernet eth1: Link is Up - 1Gbps/Full - flow control off
[ 264.260852] qcom-ethqos 23040000.ethernet eth1: NETDEV WATCHDOG: CPU: 7: transmit queue 3 timed out 5472 ms
[ 264.271394] qcom-ethqos 23040000.ethernet eth1: Reset adapter.
[ 264.280493] qcom-ethqos 23040000.ethernet eth1: phy link down 2500base-x/Unknown/Unknown/none/off/nolpi
[ 264.842309] qcom-ethqos 23040000.ethernet eth1: Timeout accessing MAC_VLAN_Tag_Filter
[ 264.850391] qcom-ethqos 23040000.ethernet eth1: failed to kill vid 0081/0
[ 264.857547] qcom-ethqos 23040000.ethernet eth1: Register MEM_TYPE_PAGE_POOL RxQ-0
[ 264.865795] qcom-ethqos 23040000.ethernet eth1: Register MEM_TYPE_PAGE_POOL RxQ-1
[ 264.873939] qcom-ethqos 23040000.ethernet eth1: Register MEM_TYPE_PAGE_POOL RxQ-2
[ 264.882111] qcom-ethqos 23040000.ethernet eth1: Register MEM_TYPE_PAGE_POOL RxQ-3
[ 265.792807] qcom-ethqos 23040000.ethernet eth1: PHY stmmac-0:08 uses interfaces 4,23,27, validating 23
[ 265.802389] [DBG] stmmac_mac_select_pcs - testing for 23 (2500base-x) on priv->integrated_pcs->pcs.supported_interfaces = 4
[ 265.802399] qcom-ethqos 23040000.ethernet eth1: interface 23 (2500base-x) rate match pause supports 0-7,9,13-14,47
[ 265.824572] qcom-ethqos 23040000.ethernet eth1: PHY [stmmac-0:08] driver [Aquantia AQR115C] (irq=334)
[ 265.834055] qcom-ethqos 23040000.ethernet eth1: phy: sgmii setting supported 00000000,00000000,00008000,000062ff advertising 00000000,00000000,00008000,000062ff
[ 265.852828] [DBG] qcom_dwmac_sgmii_phy_speed called with mode=15, submode=4
[ 265.852837] [DBG] qcom_dwmac_sgmii_phy_validate - qcom_dwmac_sgmii_phy_speed returned 1000
[ 265.868580] qcom-ethqos 23040000.ethernet eth1: Enabling Safety Features
[ 265.884237] qcom-ethqos 23040000.ethernet eth1: IEEE 1588-2008 Advanced Timestamp supported
[ 265.893946] qcom-ethqos 23040000.ethernet eth1: registered PTP clock
[ 265.900561] qcom-ethqos 23040000.ethernet eth1: configuring for phy/sgmii link mode
[ 265.908451] qcom-ethqos 23040000.ethernet eth1: major config, requested phy/sgmii
[ 265.916159] [DBG] stmmac_mac_select_pcs - testing for 4 (sgmii) on priv->integrated_pcs->pcs.supported_interfaces = 4
[ 265.916166] qcom-ethqos 23040000.ethernet eth1: interface sgmii inband modes: pcs=03 phy=03
[ 265.935652] qcom-ethqos 23040000.ethernet eth1: major config, active phy/outband/sgmii
[ 265.943795] qcom-ethqos 23040000.ethernet eth1: phylink_mac_config: mode=phy/sgmii/none adv=00000000,00000000,00000000,00000000 pause=00
[ 265.956407] [DBG] qcom_dwmac_sgmii_phy_speed called with mode=15, submode=4
[ 265.956408] [DBG] qcom_dwmac_sgmii_phy_set_mode - qcom_dwmac_sgmii_phy_speed returned 1000
[ 265.976997] qcom-ethqos 23040000.ethernet eth1: phy link down 2500base-x/Unknown/Unknown/none/off/nolpi
[ 270.556001] qcom-ethqos 23040000.ethernet eth1: phy link up 2500base-x/2.5Gbps/Full/none/off/nolpi
[ 270.567649] qcom-ethqos 23040000.ethernet eth1: major config, requested phy/2500base-x
[ 270.575823] [DBG] stmmac_mac_select_pcs - testing for 23 (2500base-x) on priv->integrated_pcs->pcs.supported_interfaces = 4
[ 270.575831] qcom-ethqos 23040000.ethernet eth1: mac_select_pcs returned NULL
[ 270.594521] qcom-ethqos 23040000.ethernet eth1: interface 2500base-x inband modes: pcs=00 phy=00
[ 270.603554] qcom-ethqos 23040000.ethernet eth1: major config, active phy/outband/2500base-x
[ 270.612286] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000010
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox