Devicetree
 help / color / mirror / Atom feed
* [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess
@ 2026-07-10 16:44 Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 01/36] dt-bindings: phy: rockchip-usbdp: add improved ports scheme Sebastian Reichel
                   ` (35 more replies)
  0 siblings, 36 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, Sashiko, William Wu

This series does a major overhaul of the Rockchip USBDP driver. The
initial main goal was to add USB-C DP AltMode support to the RK3576
and RK3588 and this series still prepares the PHY driver for exactly
that. But in addition to that I uncovered a huge amount of issues,
that are fixed along the way. Some of the more interesting ones are:

 * Currently the driver might trigger a fatal SError on USB-C hotplug,
   since re-initializing the PHY stops the clocks going to DWC3. If
   the DWC3 driver tries to access its registers at the same time the
   system will crash.
 * The DWC3 hardware can get into a buggy state when the PHY is
   disabled, which results in the PHY not coming up properly again.
 * Swithcing the USB-C connector orientation during hotplug breaks
   USB3 speed, as the PHY is not being re-initialized.
 * The code always enables DP mode when USB-C is involved.
 * The driver has some locking issues uncovered by Sashiko.

In addition to these bigger ones, Sashiko also found a bunch of
minor problems, which are mostly harmless, but were fixed while
going at it.

I've tested the v12 code changes with dozens of replugs of different
devices (2 different USB-C hubs with USB3 + HDMI via DP AltMode, 1 USB-C
to HDMI adapter [4 lanes DP AltMode], 1 USB-C to DP adapter [4 lanes DP
AltMode], 1 USB-C to NVMe adapter [no DP AltMode] as well as a direct
USB-C connection to a Dell display) on a Sige 5 board and haven't run
into any issues. I've also tested with DWC3 runtime PM being enabled
manually via sysfs in this round and did not notice any issues. Apart
from that the series is boot tested via CI on Rock 5B and Rock 4D.

Technically some of the later patches are fixes, that one would
expect at the beginning of the series, but they are only possible
after the big cleanups.

Changes in v12:
- Link to v11: https://lore.kernel.org/r/20260709-rockchip-usbdp-cleanup-v11-0-a149ac60f76c@collabora.com
- Add missing U3 port re-enable in Avoid xHCI SErrors patch (Sashiko)
- Mention possible deadlock issues in phy_notify_state() function
  documentation (Sashiko)
- Avoid runtime resume in dwc3 reset handler, which would result in
  a deadlock, if dwc3 is suspended (Sashiko)
- In patch adding reset notifications to USBDP PHY, also send the
  POST reset notification if rk_udphy_setup fails (Sashiko)
- Rework 'Fix power state handling' patch to adapt to these changes and
  avoid calling rk_udphy_u3_port_disable() when the USB3 PHY side is not
  requested by software (which means the USB power-domain being enabled,
  which is needed for the USB GRF). Previously this was guranteed by the
  runtime PM in the reset handler. The new version is better anyways as
  the old version would run into an SError when DWC3 was not loaded.
  (myself)
- I've not fixed various "pre-existing issues" reported by Sashiko to
  avoid further exploding this series. Also most of them are already
  fixed by later patches in this series anyways.

Changes in v11:
- Link to v10: https://lore.kernel.org/r/20260703-rockchip-usbdp-cleanup-v10-0-a392711ca8a9@collabora.com
- Fix depreated -> deprecated typo in DT binding (Sashiko)
- dwc3 patch: (un)register PHY notifier in probe/remove instead of
  phy_init/exit to avoid AB-BA deadlock (Sashiko)
- dwc3 patch: replace pm_runtime_get_sync by pm_runtime_resume_and_get
  and add error handling (Sashiko)
- implement error handling for PRE_RESET in USBDP driver to match
  this (me)
- dwc3 patch: add reset counter to have balanced runtime PM count if
  dwc3 is removed during an active reset (Sashiko)
- Keep code to disable USB3 in highspeed-only mode in phy_init (Sashiko)
- Always set lane mux in last patch to make sure orientation
  changes are handled properly (Sashiko)
- Update commit message of last patch to mention USB reconnections
  happening during PD state negotiation (Sashiko)

Changes in v10:
- Link to v9: https://lore.kernel.org/r/20260702-rockchip-usbdp-cleanup-v9-0-e31efbb62d2e@collabora.com
- Add 'deprecated: true' to port in DT binding, since ports replaces it (Sashiko)
- In 'Drop seamless DP takeover' simply remove any handling for
  pre-enabled PHY as there is no known bootloader doing that and
  Sashiko keeps finding things, which I cannot test. (Sashiko, myself)
- Use on/off instead of enabled/disabled in PHY reinit message,
  which is shorter (myself)
- Use notifier_to_errno() in "add notifier infrastructure" (Sashiko)
- Rework DWC3 PHY reset notifier patch, so that it works correctly
  for multiple ports (Rockchip is single-port) and keep a runtime
  reference while the PHY reset is going on to massively simplify
  the locking logic. (Sashiko)
- Drop patch renaming phy_needs_reinit keep the existing logic to
  set it whenever the lane configuration changes (Sashiko)
- Update "Simplify power state handling" patch, to mostly depend
  on the DT configured or TypeC negotiated modes to avoid
  data stream disconnections when DP is hotplugged in a dock or
  USB is used with runtime PM (Sashiko)
- Ensure sw_mode is not set when the PHY enablement function fails
  (Sashiko)
- Add new patch adding USB-only mode as USB-C state, which results
  in proper powering off the DP side when the remote hardware is
  not capable of DP AltMode. (myself)

Changes in v9:
- Link to v8: https://lore.kernel.org/r/20260626-rockchip-usbdp-cleanup-v8-0-47f682987895@collabora.com
- Update DT binding to explicitly mention that port@3 is for the
  DP aux channel and not DP in general (Sashiko got this wrong)
- Add a 100ms cooldown sleep in "Drop seamless DP takeover" after HPD
  is force disabled (Sashiko)
- Update comment in "Register DP aux bridge" to explain why port@3 is
  checked, but port@0 is used (Sashiko)
- Check for high-speed only mode in "Support going from DP-only mode to
  USB mode" (Sashiko)
- Add new patch for rk_udphy_reset_deassert error handling (Sashiko)
- Add new patch to avoid enabling USB3 in high-speed only mode during
  PHY reinit (Sashiko)
- Add 3 more patches to handle the LCPLL lock issue mentioned in the v8
  cover letter after feedback from Rockchip. Apparently the DWC3 does
  not cope very well with the PHY disappearing resulting in the PIPE
  interface misbehaving, which in turn results in the LCPLL not locking.
  The new patches avoid this by asserting DWC3_GUSB3PIPECTL_PHYSOFTRST.
  As this assert needs to be done when the PHY wants to reset, a new
  notifier system has been implemented to support triggering this from
  the PHY driver. This also means, that this version now also involves
  the USB subsystem.
- Drop old patch trying to solve the DP-only -> USB mode switch in
  favour of 5 new patches completely rewriting and simplifying the
  power status handling. The new code ensures that the PHY always
  has the right modes enabled and also makes sure a re-init happens
  on an orientation change.
- rebased on v7.2-rc1

Changes in v8:
- Link to v7: https://lore.kernel.org/r/20260625-rockchip-usbdp-cleanup-v7-0-38eb3cf654fd@collabora.com
- Move patch "Limit DP lane count to muxed lanes" after single lane
  support, which introduces dp_lanes variable to make sure series
  is bi-sectable (Sashiko)
- Force disable HPD in "Drop seamless DP takeover" patch and update
  patch description to mention potential issues with SErrors for
  bootloaders really keeping the DW-DP on. As mentioned in the new
  commit message this is untested as I'm not aware of such a
  bootloader anyways; this also means we need to keep the HPD GRF
  register defines in the 'Drop DP HPD handling' patch (Sashiko)
- Fix mode logic in "Properly handle TYPEC_STATE_SAFE and
  TYPEC_STATE_USB" patch; I blame the heat (Sashiko)
- Improve "Support going from DP-only mode to USB mode" patch to
  better handle starting in DP only mode; due to TypeC logic
  starting delayed this does not really happen, though (Sashiko)
- Improve "Support going from DP-only mode to USB mode" to avoid
  checking previous state and instead power on USB state based
  on previous requested state to avoid effects from the flip
  callback (Sashiko)
- Update the debug message patch to include some more info
- Ad one more patch, which disables USB3 at startup and drops
  the -EPROBE_DEFER logic

Changes in v7:
- Link to v6: https://lore.kernel.org/r/20260619-rockchip-usbdp-cleanup-v6-0-3bb1f54b3f35@collabora.com
- Add new patch handling missing clock-names in DT gracefully (Sashiko)
- Add new patch handling rk_udphy_reset_deassert_all errors in init check (Sashiko)
- Add new patch to handle Properly handle TYPEC_STATE_SAFE and TYPEC_STATE_USB (Sashiko)
- Add new patch to avoid xHCI SErrors

Changes in v6:
- Link to v5: https://lore.kernel.org/r/20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com
- Add explicit <linux/string_choices.h> include in last patch (Sashiko)
- Add new patch moving mode_change update after error handling (Sashiko)
- Add new patch fixing error masking of devm_clk_bulk_get_all() (Sashiko)
- Add new patch dropping seamless DP takeover as it is non-functional and buggy (Sashiko) 
- Add new patch limiting DP lane count to muxed lanes (Sashiko)
- Add error handling in the patch that keeps clocks running on PHY re-init (Sashiko)
- Also look for DP being configured to second lane for the flip config
  in DP single-lane mode, which should at least keep USB working for
  this super unusual config (Sashiko)
- Drop useless ret variable in patch introducing guard() for the mutex
- Add error handling for PHY re-enablement in the patch fixing support for
  DP-only -> USB mode (Sashiko)

Changes in v5:
- Link to v4: https://lore.kernel.org/r/20260428-rockchip-usbdp-cleanup-v4-0-7775671ece22@collabora.com
- Picked up Acked-by from Rob Herring for DT binding
- Fix typos in commit messages/comments
- Add Fixes tag to "Do not looe USB3 PHY status" patch
- Collect Reviewed-by: Neil Armstrong for multiple patches
- Drop now unused code from "Drop DP HPD handling" patch (Sashiko)
- Ignore mux events not involving DP AltMode (Sashiko)
- Add new patch to support going back from DP only mode to USB combo
  mode; technically this is a fix, but DP mode does not yet work
  upstream, so it does not matter (Sashiko)
- Add new patch adding a few debug messages, which are useful
  to investigate potential hotplug issues in the future
- Sashiko comments about the DT binding and property usage
  are wrong as the first port is for the superspeed lanes
  used for DP and USB, while the last port is just about
  DP aux. I ignored them.
- There is a pre-existing bug, that can already be hit with the
  upstream kernel and that the series doesn't fix properly:
  Accessing the USB3 controller registers requires the USB PHY
  running, since it provides a clock. Re-initializing the PHY
  means there is a race-condition - if the system tries to access
  the USB3 controller in parallel to the re-init, the system will
  hang and/or fail with an SError. By keeping the clocks running
  and only asserting the resets this time is minimized by this
  series. A proper fix for this will be looked into independently
  from this series.
- I used v7.1-rc6 as base, but the driver has no changes since
  6.18 even in linux-next and there are no pending patches for
  it on the mailinglist either, so it applies to *any* recent
  kernel branch.

Changes in v4:
- Link to v3: https://lore.kernel.org/r/20260313-rockchip-usbdp-cleanup-v3-0-3e8fe89a35b5@collabora.com
- rebased to v7.1-rc1 (no changes)
- Update DRM bridge registration patch to avoid registration when DP aux
  port is not connected to anything, since this results in errors and some
  boards use USBDP instances for USB3 only.
- Add patch renaming mode_change into phy_needs_reinit
- Add patch to re-init PHY on orientation change
- Add patch to factor out lane_mux_sel setup
- Add patch to handle mutex via guard functions

Changes in v3:
- Link to v2: https://lore.kernel.org/r/20260213-rockchip-usbdp-cleanup-v2-0-b67ec225f96e@collabora.com
- Add patch to register the USBDP PHY as DRM bridge
- Add patch to describe ports in DT binding (used by the DRM bridge)
- Add patch to drop HPD handling from the PHY

Changes in v2:
- Link to v1: https://lore.kernel.org/r/20260203-rockchip-usbdp-cleanup-v1-0-16a6f92ed176@collabora.com
- Added new patches to fix USB3 SError

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
Frank Wang (1):
      phy: rockchip: usbdp: Amend SSC modulation deviation

Sebastian Reichel (33):
      dt-bindings: phy: rockchip-usbdp: add improved ports scheme
      phy: rockchip: usbdp: Update mode_change after error handling
      phy: rockchip: usbdp: Do not lose USB3 PHY status
      phy: rockchip: usbdp: Fix devm_clk_bulk_get_all check
      phy: rockchip: usbdp: Handle missing clock-names DT property gracefully
      phy: rockchip: usbdp: Drop seamless DP takeover
      phy: rockchip: usbdp: Keep clocks running on PHY re-init
      phy: rockchip: usbdp: Add missing mode_change update
      phy: rockchip: usbdp: Limit DP lane count to muxed lanes
      phy: rockchip: usbdp: Rename DP lane functions
      phy: rockchip: usbdp: Use FIELD_PREP_WM16_CONST
      phy: rockchip: usbdp: Cleanup DP lane selection function
      phy: rockchip: usbdp: Register DP aux bridge
      phy: rockchip: usbdp: Drop DP HPD handling
      phy: rockchip: usbdp: Rename mode_change to phy_needs_reinit
      phy: rockchip: usbdp: Re-init the PHY on orientation change
      phy: rockchip: usbdp: Factor out lane_mux_sel setup
      phy: rockchip: usbdp: Properly handle TYPEC_STATE_SAFE and TYPEC_STATE_USB
      phy: rockchip: usbdp: Use guard functions for mutex
      phy: rockchip: usbdp: Clear USB status on PHY exit
      phy: rockchip: usbdp: Hold mutex in DP PHY configure
      phy: rockchip: usbdp: Add some extra debug messages
      phy: rockchip: usbdp: Avoid xHCI SErrors
      phy: rockchip: usbdp: Handle rk_udphy_reset_deassert errors
      phy: rockchip: usbdp: Only enable USB3 when not in high-speed mode
      phy: core: add notifier infrastructure
      usb: dwc3: core: support PHY reset notifications
      phy: rockchip: usbdp: Add phy reset notification support
      phy: rockchip: usbdp: Drop -EPROBE_DEFER hack
      phy: rockchip: usbdp: Rename mode to hw_mode
      phy: rockchip: usbdp: Fix power state handling
      phy: rockchip: usbdp: Re-init PHY on mux change
      phy: rockchip: usbdp: Add USB-C state without DP enabled

William Wu (1):
      phy: rockchip: usbdp: Fix LFPS detect threshold control

Zhang Yubing (1):
      phy: rockchip: usbdp: Support single-lane DP

 .../bindings/phy/phy-rockchip-usbdp.yaml           |  24 +
 drivers/phy/phy-core.c                             |  65 +++
 drivers/phy/rockchip/Kconfig                       |   2 +
 drivers/phy/rockchip/phy-rockchip-usbdp.c          | 583 ++++++++++-----------
 drivers/usb/dwc3/core.c                            |  88 ++++
 drivers/usb/dwc3/core.h                            |  18 +
 include/linux/phy/phy.h                            |  40 ++
 7 files changed, 523 insertions(+), 297 deletions(-)
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260203-rockchip-usbdp-cleanup-5b59dfb561a3

Best regards,
-- 
Sebastian Reichel <sebastian.reichel@collabora.com>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v12 01/36] dt-bindings: phy: rockchip-usbdp: add improved ports scheme
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 02/36] phy: rockchip: usbdp: Update mode_change after error handling Sebastian Reichel
                   ` (34 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Currently the Rockchip USBDP PHY is missing a documented port scheme.
Meanwhile upstream RK3588 DTS files are a bit messy and use different
port schemes. The upstream USBDP PHY Linux kernel driver does not yet
parse the ports at all and thus does not create any implicit ABI either.

But with the current mess it is not possible to properly support USB-C
DP AltMode. Thus this introduces a proper port scheme following roughly
the ports design of the Qualcomm QMP USB4-USB3-DP PHY controller binding
with a slight difference that there is an additional port for the
USB-C SBU port as the Rockchip USB-DP PHY also contains the SBU mux.

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 .../bindings/phy/phy-rockchip-usbdp.yaml           | 24 ++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml
index 8b7059d5b182..89efaf005a7b 100644
--- a/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml
+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml
@@ -110,10 +110,34 @@ properties:
 
   port:
     $ref: /schemas/graph.yaml#/properties/port
+    deprecated: true
     description:
       A port node to link the PHY to a TypeC controller for the purpose of
       handling orientation switching.
 
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    properties:
+      port@0:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Output endpoint of the PHY for USB (or DP when configured into 4 lane
+          mode), which should point to the superspeed port of a USB connector.
+
+      port@1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Incoming endpoint from the USB controller
+
+      port@2:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Incoming endpoint from the DisplayPort controller
+
+      port@3:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Output endpoint of the PHY for DP Auxiliary, which should either point to
+          the SBU port of a USB-C connector or a DisplayPort connector input port.
+
 required:
   - compatible
   - reg

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 02/36] phy: rockchip: usbdp: Update mode_change after error handling
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 01/36] dt-bindings: phy: rockchip-usbdp: add improved ports scheme Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 21:15   ` sashiko-bot
  2026-07-10 16:44 ` [PATCH v12 03/36] phy: rockchip: usbdp: Do not lose USB3 PHY status Sebastian Reichel
                   ` (33 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, Sashiko

If rk_udphy_init() or rk_udphy_setup() fails, the reinit will not be
tried again. Fix this by only updating the variable after all potential
errors have been handled.

Note, that no errors have been seen on real hardware and failures would
most likely be fatal and require at least a full reboot as the function
already asserts the PHY reset lines. So this is more of a theoretical
issue.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/linux-phy/20260612163835.8D5471F000E9@smtp.kernel.org/
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index fba35510d88c..a5ffdf7a6e76 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1000,15 +1000,14 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 	}
 
 	if (udphy->status == UDPHY_MODE_NONE) {
-		udphy->mode_change = false;
 		ret = rk_udphy_setup(udphy);
 		if (ret)
 			return ret;
 
 		if (udphy->mode & UDPHY_MODE_USB)
 			rk_udphy_u3_port_disable(udphy, false);
-	} else if (udphy->mode_change) {
 		udphy->mode_change = false;
+	} else if (udphy->mode_change) {
 		udphy->status = UDPHY_MODE_NONE;
 		if (udphy->mode == UDPHY_MODE_DP)
 			rk_udphy_u3_port_disable(udphy, true);
@@ -1017,6 +1016,7 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 		ret = rk_udphy_setup(udphy);
 		if (ret)
 			return ret;
+		udphy->mode_change = false;
 	}
 
 	udphy->status |= mode;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 03/36] phy: rockchip: usbdp: Do not lose USB3 PHY status
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 01/36] dt-bindings: phy: rockchip-usbdp: add improved ports scheme Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 02/36] phy: rockchip: usbdp: Update mode_change after error handling Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 21:07   ` sashiko-bot
  2026-07-10 16:44 ` [PATCH v12 04/36] phy: rockchip: usbdp: Fix devm_clk_bulk_get_all check Sebastian Reichel
                   ` (32 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

By default (i.e. without manually enabling runtime PM) DWC3 requests the
USB3 PHY once and keeps it enabled all the time. When DisplayPort is
being requested later on, a mode change is needed. This re-initializes
the PHY. During re-initialization the status variable has incorrectly
been cleared, which means the tracking information for USB3 is lost.

This is not an immediate problem, since the DP side keeps the PHY
enabled. But once DP is toggled off, the whole PHY will be disabled.
This is a problem, because the USB side still needs it powered.

Fix things by not clearing the status flags.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index a5ffdf7a6e76..12dfdd470a78 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1008,7 +1008,6 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 			rk_udphy_u3_port_disable(udphy, false);
 		udphy->mode_change = false;
 	} else if (udphy->mode_change) {
-		udphy->status = UDPHY_MODE_NONE;
 		if (udphy->mode == UDPHY_MODE_DP)
 			rk_udphy_u3_port_disable(udphy, true);
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 04/36] phy: rockchip: usbdp: Fix devm_clk_bulk_get_all check
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (2 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 03/36] phy: rockchip: usbdp: Do not lose USB3 PHY status Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 05/36] phy: rockchip: usbdp: Handle missing clock-names DT property gracefully Sebastian Reichel
                   ` (31 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, Sashiko

If devm_clk_bulk_get_all() returns -EPROBE_DEFER, it is replaced with
-ENODEV, permanently failing the driver probe instead of allowing it to
defer. Avoid masking the error code to fix the issue.

This effectively drops returning -ENODEV in case no clocks are being
described in DT. This special case will now be handled by the follow-up
check searching for "refclk" and exit with -EINVAL.

None of this will be hit in practice, since the driver is only used by
RK3588 and RK3576 - on these platforms the DT is validated to contain
the clocks and the clock driver is force probed early. Thus there is
no need to backport this.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/linux-phy/20260612164107.C7DB21F000E9@smtp.kernel.org/
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 12dfdd470a78..2845a012eafc 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -427,8 +427,8 @@ static int rk_udphy_clk_init(struct rk_udphy *udphy, struct device *dev)
 	int i;
 
 	udphy->num_clks = devm_clk_bulk_get_all(dev, &udphy->clks);
-	if (udphy->num_clks < 1)
-		return -ENODEV;
+	if (udphy->num_clks < 0)
+		return udphy->num_clks;
 
 	/* used for configure phy reference clock frequency */
 	for (i = 0; i < udphy->num_clks; i++) {

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 05/36] phy: rockchip: usbdp: Handle missing clock-names DT property gracefully
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (3 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 04/36] phy: rockchip: usbdp: Fix devm_clk_bulk_get_all check Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 21:07   ` sashiko-bot
  2026-07-10 16:44 ` [PATCH v12 06/36] phy: rockchip: usbdp: Drop seamless DP takeover Sebastian Reichel
                   ` (30 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, Sashiko

The rk_udphy_clk_init() function would currently try to do a strncmp for
a NULL pointer, if DT specifies 'clocks' property, but no 'clock-names'
property. Fix this by making sure the clock has an id string set.

Note that DT binding requires setting clock-names, so this is only a
problem when booting a non-compliant device tree.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/message/20260619154349.071321F000E9%40smtp.kernel.org
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 2845a012eafc..3fc8222fcaec 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -432,6 +432,9 @@ static int rk_udphy_clk_init(struct rk_udphy *udphy, struct device *dev)
 
 	/* used for configure phy reference clock frequency */
 	for (i = 0; i < udphy->num_clks; i++) {
+		if (!udphy->clks[i].id)
+			continue;
+
 		if (!strncmp(udphy->clks[i].id, "refclk", 6)) {
 			udphy->refclk = udphy->clks[i].clk;
 			break;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 06/36] phy: rockchip: usbdp: Drop seamless DP takeover
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (4 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 05/36] phy: rockchip: usbdp: Handle missing clock-names DT property gracefully Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 21:08   ` sashiko-bot
  2026-07-10 16:44 ` [PATCH v12 07/36] phy: rockchip: usbdp: Keep clocks running on PHY re-init Sebastian Reichel
                   ` (29 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, Sashiko

Right now the DRM drivers do not support seamless DP takeover and I'm
I'm not aware of any bootloader implementing this feature either.

In any case this feature would be limited to boards using the USBDP PHY
for a DP or eDP connection instead of the more commonly USB-C connector.
With USB-C's DP AltMode a seamless DP takeover requires handing over the
state of the TCPM state machine from the bootloader to the kernel. This
in turn requires a huge amount of work to keep the state machine
implementations synchronized. It's very unlikely we will see somebody
implementing that in the foreseeable future.

As the current code is obviously buggy and untested, let's simply drop
support for seamless DP takeover. It can be re-implemented cleanly once
somebody adds all missing bits.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/linux-phy/20260612164107.C7DB21F000E9@smtp.kernel.org/
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 31 -------------------------------
 1 file changed, 31 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 3fc8222fcaec..6cb9f6b4dbf6 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -452,11 +452,6 @@ static int rk_udphy_reset_assert_all(struct rk_udphy *udphy)
 	return reset_control_bulk_assert(udphy->num_rsts, udphy->rsts);
 }
 
-static int rk_udphy_reset_deassert_all(struct rk_udphy *udphy)
-{
-	return reset_control_bulk_deassert(udphy->num_rsts, udphy->rsts);
-}
-
 static int rk_udphy_reset_deassert(struct rk_udphy *udphy, char *name)
 {
 	struct reset_control_bulk_data *list = udphy->rsts;
@@ -924,28 +919,6 @@ static int rk_udphy_parse_lane_mux_data(struct rk_udphy *udphy)
 	return 0;
 }
 
-static int rk_udphy_get_initial_status(struct rk_udphy *udphy)
-{
-	int ret;
-	u32 value;
-
-	ret = clk_bulk_prepare_enable(udphy->num_clks, udphy->clks);
-	if (ret) {
-		dev_err(udphy->dev, "failed to enable clk\n");
-		return ret;
-	}
-
-	rk_udphy_reset_deassert_all(udphy);
-
-	regmap_read(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, &value);
-	if (FIELD_GET(CMN_DP_LANE_MUX_ALL, value) && FIELD_GET(CMN_DP_LANE_EN_ALL, value))
-		udphy->status = UDPHY_MODE_DP;
-	else
-		rk_udphy_disable(udphy);
-
-	return 0;
-}
-
 static int rk_udphy_parse_dt(struct rk_udphy *udphy)
 {
 	struct device *dev = udphy->dev;
@@ -1495,10 +1468,6 @@ static int rk_udphy_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	ret = rk_udphy_get_initial_status(udphy);
-	if (ret)
-		return ret;
-
 	mutex_init(&udphy->mutex);
 	platform_set_drvdata(pdev, udphy);
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 07/36] phy: rockchip: usbdp: Keep clocks running on PHY re-init
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (5 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 06/36] phy: rockchip: usbdp: Drop seamless DP takeover Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 08/36] phy: rockchip: usbdp: Amend SSC modulation deviation Sebastian Reichel
                   ` (28 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

When a mode change is required rk_udphy_power_on() disables
the clocks and then calls rk_udphy_setup(), which then enables
all the clocks again before continuing with rk_udphy_init().

Considering that rk_udphy_init() does assert the reset lines,
re-enabling the clocks is just delaying things. Avoid it by
directly calling rk_udphy_init().

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 6cb9f6b4dbf6..e3f5a26c876a 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -987,8 +987,7 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 		if (udphy->mode == UDPHY_MODE_DP)
 			rk_udphy_u3_port_disable(udphy, true);
 
-		rk_udphy_disable(udphy);
-		ret = rk_udphy_setup(udphy);
+		ret = rk_udphy_init(udphy);
 		if (ret)
 			return ret;
 		udphy->mode_change = false;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 08/36] phy: rockchip: usbdp: Amend SSC modulation deviation
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (6 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 07/36] phy: rockchip: usbdp: Keep clocks running on PHY re-init Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 09/36] phy: rockchip: usbdp: Fix LFPS detect threshold control Sebastian Reichel
                   ` (27 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

From: Frank Wang <frank.wang@rock-chips.com>

Move SSC modulation deviation into private config of clock

 - 24M: 0x00d4[5:0] = 0x30
 - 26M: 0x00d4[5:0] = 0x33

Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
[Taken over from rockchip's kernel tree; register 0x00d4 is not
described in the TRM]
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index e3f5a26c876a..cb6acadfbccf 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -350,7 +350,8 @@ static const struct reg_sequence rk_udphy_24m_refclk_cfg[] = {
 	{0x0a64, 0xa8}, {0x1a3c, 0xd0},
 	{0x1a44, 0xd0}, {0x1a48, 0x01},
 	{0x1a4c, 0x0d}, {0x1a54, 0xe0},
-	{0x1a5c, 0xe0}, {0x1a64, 0xa8}
+	{0x1a5c, 0xe0}, {0x1a64, 0xa8},
+	{0x00d4, 0x30}
 };
 
 static const struct reg_sequence rk_udphy_26m_refclk_cfg[] = {
@@ -377,7 +378,7 @@ static const struct reg_sequence rk_udphy_26m_refclk_cfg[] = {
 	{0x0c30, 0x0e}, {0x0c48, 0x06},
 	{0x1c30, 0x0e}, {0x1c48, 0x06},
 	{0x028c, 0x18}, {0x0af0, 0x00},
-	{0x1af0, 0x00}
+	{0x1af0, 0x00}, {0x00d4, 0x33}
 };
 
 static const struct reg_sequence rk_udphy_init_sequence[] = {
@@ -412,8 +413,7 @@ static const struct reg_sequence rk_udphy_init_sequence[] = {
 	{0x0070, 0x7d}, {0x0074, 0x68},
 	{0x0af4, 0x1a}, {0x1af4, 0x1a},
 	{0x0440, 0x3f}, {0x10d4, 0x08},
-	{0x20d4, 0x08}, {0x00d4, 0x30},
-	{0x0024, 0x6e},
+	{0x20d4, 0x08}, {0x0024, 0x6e}
 };
 
 static inline int rk_udphy_grfreg_write(struct regmap *base,

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 09/36] phy: rockchip: usbdp: Fix LFPS detect threshold control
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (7 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 08/36] phy: rockchip: usbdp: Amend SSC modulation deviation Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 10/36] phy: rockchip: usbdp: Add missing mode_change update Sebastian Reichel
                   ` (26 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, William Wu

From: William Wu <william.wu@rock-chips.com>

According to the LFPS Tx Low Power/LFPS Rx Detect Threshold [1],
the device under test(DUT) must not respond if LFPS below the
minimum LFPS Rx Detect Threshold 100mV. Test fail on Rockchip
platforms, because the default LFPS detect threshold is set to
65mV.

The USBDP PHY LFPS detect threshold voltage could be set to
30mV ~ 140mV, and since there could be 10-20% PVT variation,
we set LFPS detect threshold voltage to 110mV.

[1] https://compliance.usb.org/resources/LFPS_Rx_Tx_Low_Power_Compliance_Update_Rev5.pdf

Signed-off-by: William Wu <william.wu@rock-chips.com>
[Taken over from rockchip's kernel tree; the registers are not described
in the TRM]
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index cb6acadfbccf..982315535caf 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -413,7 +413,8 @@ static const struct reg_sequence rk_udphy_init_sequence[] = {
 	{0x0070, 0x7d}, {0x0074, 0x68},
 	{0x0af4, 0x1a}, {0x1af4, 0x1a},
 	{0x0440, 0x3f}, {0x10d4, 0x08},
-	{0x20d4, 0x08}, {0x0024, 0x6e}
+	{0x20d4, 0x08}, {0x0024, 0x6e},
+	{0x09c0, 0x0a}, {0x19c0, 0x0a}
 };
 
 static inline int rk_udphy_grfreg_write(struct regmap *base,

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 10/36] phy: rockchip: usbdp: Add missing mode_change update
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (8 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 09/36] phy: rockchip: usbdp: Fix LFPS detect threshold control Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 21:13   ` sashiko-bot
  2026-07-10 16:44 ` [PATCH v12 11/36] phy: rockchip: usbdp: Support single-lane DP Sebastian Reichel
                   ` (25 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

rk_udphy_set_typec_default_mapping() updates the available modes,
but does not set the mode_change as required. This results in
missing re-initialization and thus non-working DisplayPort.

Fix this issue by introducing a new helper to update the available
modes.

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 982315535caf..7540c897dde1 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -617,6 +617,15 @@ static void rk_udphy_dp_hpd_event_trigger(struct rk_udphy *udphy, bool hpd)
 	rk_udphy_grfreg_write(udphy->vogrf, &cfg->vogrfcfg[udphy->id].hpd_trigger, hpd);
 }
 
+static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 mode)
+{
+	if (udphy->mode == mode)
+		return;
+
+	udphy->mode_change = true;
+	udphy->mode = mode;
+}
+
 static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 {
 	if (udphy->flip) {
@@ -647,7 +656,7 @@ static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 		gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 1);
 	}
 
-	udphy->mode = UDPHY_MODE_DP_USB;
+	rk_udphy_mode_set(udphy, UDPHY_MODE_DP_USB);
 }
 
 static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
@@ -1361,10 +1370,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 			usleep_range(750, 800);
 			rk_udphy_dp_hpd_event_trigger(udphy, true);
 		} else if (data->status & DP_STATUS_HPD_STATE) {
-			if (udphy->mode != mode) {
-				udphy->mode = mode;
-				udphy->mode_change = true;
-			}
+			rk_udphy_mode_set(udphy, mode);
 			rk_udphy_dp_hpd_event_trigger(udphy, true);
 		} else {
 			rk_udphy_dp_hpd_event_trigger(udphy, false);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 11/36] phy: rockchip: usbdp: Support single-lane DP
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (9 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 10/36] phy: rockchip: usbdp: Add missing mode_change update Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 12/36] phy: rockchip: usbdp: Limit DP lane count to muxed lanes Sebastian Reichel
                   ` (24 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

From: Zhang Yubing <yubing.zhang@rock-chips.com>

Implement support for using just a single DisplayPort line.

Signed-off-by: Zhang Yubing <yubing.zhang@rock-chips.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 64 +++++++++++++------------------
 1 file changed, 27 insertions(+), 37 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 7540c897dde1..c4d62b234ea8 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -193,6 +193,7 @@ struct rk_udphy {
 	int id;
 
 	bool dp_in_use;
+	int dp_lanes;
 
 	/* PHY const config */
 	const struct rk_udphy_cfg *cfgs;
@@ -535,6 +536,13 @@ static void rk_udphy_usb_bvalid_enable(struct rk_udphy *udphy, u8 enable)
  * <0 1>                  dpln0         dpln1       usbrx         usbtx
  * <2 3>                  usbrx         usbtx       dpln0         dpln1
  * ---------------------------------------------------------------------------
+ * if 1 lane for dp function, 2 lane for usb function, define rockchip,dp-lane-mux = <x>;
+ * sample as follow:
+ * ---------------------------------------------------------------------------
+ *                        B11-B10       A2-A3       A11-A10       B2-B3
+ * rockchip,dp-lane-mux   ln0(tx/rx)    ln1(tx)     ln2(tx/rx)    ln3(tx)
+ * <0>                    dpln0         \           usbrx         usbtx
+ * ---------------------------------------------------------------------------
  */
 
 static void rk_udphy_dplane_select(struct rk_udphy *udphy)
@@ -542,18 +550,18 @@ static void rk_udphy_dplane_select(struct rk_udphy *udphy)
 	const struct rk_udphy_cfg *cfg = udphy->cfgs;
 	u32 value = 0;
 
-	switch (udphy->mode) {
-	case UDPHY_MODE_DP:
-		value |= 2 << udphy->dp_lane_sel[2] * 2;
+	switch (udphy->dp_lanes) {
+	case 4:
 		value |= 3 << udphy->dp_lane_sel[3] * 2;
+		value |= 2 << udphy->dp_lane_sel[2] * 2;
 		fallthrough;
 
-	case UDPHY_MODE_DP_USB:
-		value |= 0 << udphy->dp_lane_sel[0] * 2;
+	case 2:
 		value |= 1 << udphy->dp_lane_sel[1] * 2;
-		break;
+		fallthrough;
 
-	case UDPHY_MODE_USB:
+	case 1:
+		value |= 0 << udphy->dp_lane_sel[0] * 2;
 		break;
 
 	default:
@@ -566,28 +574,6 @@ static void rk_udphy_dplane_select(struct rk_udphy *udphy)
 		     FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value);
 }
 
-static int rk_udphy_dplane_get(struct rk_udphy *udphy)
-{
-	int dp_lanes;
-
-	switch (udphy->mode) {
-	case UDPHY_MODE_DP:
-		dp_lanes = 4;
-		break;
-
-	case UDPHY_MODE_DP_USB:
-		dp_lanes = 2;
-		break;
-
-	case UDPHY_MODE_USB:
-	default:
-		dp_lanes = 0;
-		break;
-	}
-
-	return dp_lanes;
-}
-
 static void rk_udphy_dplane_enable(struct rk_udphy *udphy, int dp_lanes)
 {
 	u32 val = 0;
@@ -657,6 +643,7 @@ static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 	}
 
 	rk_udphy_mode_set(udphy, UDPHY_MODE_DP_USB);
+	udphy->dp_lanes = 2;
 }
 
 static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
@@ -895,7 +882,7 @@ static int rk_udphy_parse_lane_mux_data(struct rk_udphy *udphy)
 		return 0;
 	}
 
-	if (num_lanes != 2 && num_lanes != 4)
+	if (num_lanes != 1 && num_lanes != 2 && num_lanes != 4)
 		return dev_err_probe(udphy->dev, -EINVAL,
 				     "invalid number of lane mux\n");
 
@@ -921,9 +908,11 @@ static int rk_udphy_parse_lane_mux_data(struct rk_udphy *udphy)
 	}
 
 	udphy->mode = UDPHY_MODE_DP;
-	if (num_lanes == 2) {
+	udphy->dp_lanes = num_lanes;
+	if (num_lanes == 1 || num_lanes == 2) {
 		udphy->mode |= UDPHY_MODE_USB;
-		udphy->flip = (udphy->lane_mux_sel[0] == PHY_LANE_MUX_DP);
+		udphy->flip = (udphy->lane_mux_sel[0] == PHY_LANE_MUX_DP) ||
+			      (udphy->lane_mux_sel[1] == PHY_LANE_MUX_DP);
 	}
 
 	return 0;
@@ -1050,18 +1039,17 @@ static int rk_udphy_dp_phy_exit(struct phy *phy)
 static int rk_udphy_dp_phy_power_on(struct phy *phy)
 {
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
-	int ret, dp_lanes;
+	int ret;
 
 	mutex_lock(&udphy->mutex);
 
-	dp_lanes = rk_udphy_dplane_get(udphy);
-	phy_set_bus_width(phy, dp_lanes);
+	phy_set_bus_width(phy, udphy->dp_lanes);
 
 	ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP);
 	if (ret)
 		goto unlock;
 
-	rk_udphy_dplane_enable(udphy, dp_lanes);
+	rk_udphy_dplane_enable(udphy, udphy->dp_lanes);
 
 	rk_udphy_dplane_select(udphy);
 
@@ -1341,6 +1329,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 		udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
 		udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
 		mode = UDPHY_MODE_DP;
+		udphy->dp_lanes = 4;
 		break;
 
 	case TYPEC_DP_STATE_D:
@@ -1357,6 +1346,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 			udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
 		}
 		mode = UDPHY_MODE_DP_USB;
+		udphy->dp_lanes = 2;
 		break;
 	}
 
@@ -1501,7 +1491,7 @@ static int rk_udphy_probe(struct platform_device *pdev)
 		ret = PTR_ERR(udphy->phy_dp);
 		return dev_err_probe(dev, ret, "failed to create DP phy\n");
 	}
-	phy_set_bus_width(udphy->phy_dp, rk_udphy_dplane_get(udphy));
+	phy_set_bus_width(udphy->phy_dp, udphy->dp_lanes);
 	udphy->phy_dp->attrs.max_link_rate = 8100;
 	phy_set_drvdata(udphy->phy_dp, udphy);
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 12/36] phy: rockchip: usbdp: Limit DP lane count to muxed lanes
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (10 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 11/36] phy: rockchip: usbdp: Support single-lane DP Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 21:08   ` sashiko-bot
  2026-07-10 16:44 ` [PATCH v12 13/36] phy: rockchip: usbdp: Rename DP lane functions Sebastian Reichel
                   ` (23 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, Sashiko

In theory the DP controller could request 4 lanes when the PHY is
restricted to 2 lanes as the other half is used by USB3.

With the current user (DW-DP) this cannot happen, but as the check is
cheap and users might change in the future protect things accordingly.
Not doing so would corrupt USB3 usage by the following code configuring
the voltages.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/linux-phy/20260612165546.98E1F1F000E9@smtp.kernel.org/
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index c4d62b234ea8..b172ce6a722e 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1099,6 +1099,9 @@ static int rk_udphy_dp_phy_verify_link_rate(struct rk_udphy *udphy,
 static int rk_udphy_dp_phy_verify_lanes(struct rk_udphy *udphy,
 					struct phy_configure_opts_dp *dp)
 {
+	if (dp->lanes > udphy->dp_lanes)
+		return -EINVAL;
+
 	switch (dp->lanes) {
 	case 1:
 	case 2:

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 13/36] phy: rockchip: usbdp: Rename DP lane functions
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (11 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 12/36] phy: rockchip: usbdp: Limit DP lane count to muxed lanes Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 14/36] phy: rockchip: usbdp: Use FIELD_PREP_WM16_CONST Sebastian Reichel
                   ` (22 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

The common prefix for DisplayPort related functions is rk_udphy_dp_
(with a final _), so update the two DP lane functions to follow that
scheme.

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index b172ce6a722e..7fb864a1486c 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -545,7 +545,7 @@ static void rk_udphy_usb_bvalid_enable(struct rk_udphy *udphy, u8 enable)
  * ---------------------------------------------------------------------------
  */
 
-static void rk_udphy_dplane_select(struct rk_udphy *udphy)
+static void rk_udphy_dp_lane_select(struct rk_udphy *udphy)
 {
 	const struct rk_udphy_cfg *cfg = udphy->cfgs;
 	u32 value = 0;
@@ -574,7 +574,7 @@ static void rk_udphy_dplane_select(struct rk_udphy *udphy)
 		     FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value);
 }
 
-static void rk_udphy_dplane_enable(struct rk_udphy *udphy, int dp_lanes)
+static void rk_udphy_dp_lane_enable(struct rk_udphy *udphy, int dp_lanes)
 {
 	u32 val = 0;
 	int i;
@@ -1049,9 +1049,9 @@ static int rk_udphy_dp_phy_power_on(struct phy *phy)
 	if (ret)
 		goto unlock;
 
-	rk_udphy_dplane_enable(udphy, udphy->dp_lanes);
+	rk_udphy_dp_lane_enable(udphy, udphy->dp_lanes);
 
-	rk_udphy_dplane_select(udphy);
+	rk_udphy_dp_lane_select(udphy);
 
 unlock:
 	mutex_unlock(&udphy->mutex);
@@ -1069,7 +1069,7 @@ static int rk_udphy_dp_phy_power_off(struct phy *phy)
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
 
 	mutex_lock(&udphy->mutex);
-	rk_udphy_dplane_enable(udphy, 0);
+	rk_udphy_dp_lane_enable(udphy, 0);
 	rk_udphy_power_off(udphy, UDPHY_MODE_DP);
 	mutex_unlock(&udphy->mutex);
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 14/36] phy: rockchip: usbdp: Use FIELD_PREP_WM16_CONST
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (12 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 13/36] phy: rockchip: usbdp: Rename DP lane functions Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 15/36] phy: rockchip: usbdp: Cleanup DP lane selection function Sebastian Reichel
                   ` (21 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Cleanup code by replacing open-coded version of FIELD_PREP_WM16_CONST
with the existing helper macro.

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 7fb864a1486c..05593e98c16d 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -12,6 +12,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
+#include <linux/hw_bitfield.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
@@ -75,7 +76,6 @@
 #define TRSV_LN2_MON_RX_CDR_DONE_OFFSET		0x1b84	/* trsv_reg06E1 */
 #define TRSV_LN2_MON_RX_CDR_LOCK_DONE		BIT(0)
 
-#define BIT_WRITEABLE_SHIFT			16
 #define PHY_AUX_DP_DATA_POL_NORMAL		0
 #define PHY_AUX_DP_DATA_POL_INVERT		1
 #define PHY_LANE_MUX_USB			0
@@ -104,8 +104,8 @@ struct rk_udphy_grf_reg {
 #define _RK_UDPHY_GEN_GRF_REG(offset, mask, disable, enable) \
 {\
 	offset, \
-	FIELD_PREP_CONST(mask, disable) | (mask << BIT_WRITEABLE_SHIFT), \
-	FIELD_PREP_CONST(mask, enable) | (mask << BIT_WRITEABLE_SHIFT), \
+	FIELD_PREP_WM16_CONST(mask, disable), \
+	FIELD_PREP_WM16_CONST(mask, enable), \
 }
 
 #define RK_UDPHY_GEN_GRF_REG(offset, bitend, bitstart, disable, enable) \

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 15/36] phy: rockchip: usbdp: Cleanup DP lane selection function
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (13 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 14/36] phy: rockchip: usbdp: Use FIELD_PREP_WM16_CONST Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 16/36] phy: rockchip: usbdp: Register DP aux bridge Sebastian Reichel
                   ` (20 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Use FIELD_PREP_WM16() helpers to simplify the DP lane selection
logic.

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 28 +++++++---------------------
 1 file changed, 7 insertions(+), 21 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 05593e98c16d..eda3f7a1e267 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -548,30 +548,16 @@ static void rk_udphy_usb_bvalid_enable(struct rk_udphy *udphy, u8 enable)
 static void rk_udphy_dp_lane_select(struct rk_udphy *udphy)
 {
 	const struct rk_udphy_cfg *cfg = udphy->cfgs;
-	u32 value = 0;
-
-	switch (udphy->dp_lanes) {
-	case 4:
-		value |= 3 << udphy->dp_lane_sel[3] * 2;
-		value |= 2 << udphy->dp_lane_sel[2] * 2;
-		fallthrough;
-
-	case 2:
-		value |= 1 << udphy->dp_lane_sel[1] * 2;
-		fallthrough;
+	u32 value = FIELD_PREP_WM16(DP_LANE_SEL_ALL, 0);
+	int i;
 
-	case 1:
-		value |= 0 << udphy->dp_lane_sel[0] * 2;
-		break;
+	for (i = 0; i < udphy->dp_lanes; i++)
+		value |= field_prep(DP_LANE_SEL_N(udphy->dp_lane_sel[i]), i);
 
-	default:
-		break;
-	}
+	value |= FIELD_PREP_WM16(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel);
+	value |= FIELD_PREP_WM16(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel);
 
-	regmap_write(udphy->vogrf, cfg->vogrfcfg[udphy->id].dp_lane_reg,
-		     ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16) |
-		     FIELD_PREP(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel) |
-		     FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value);
+	regmap_write(udphy->vogrf, cfg->vogrfcfg[udphy->id].dp_lane_reg, value);
 }
 
 static void rk_udphy_dp_lane_enable(struct rk_udphy *udphy, int dp_lanes)

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 16/36] phy: rockchip: usbdp: Register DP aux bridge
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (14 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 15/36] phy: rockchip: usbdp: Cleanup DP lane selection function Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 17/36] phy: rockchip: usbdp: Drop DP HPD handling Sebastian Reichel
                   ` (19 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Add support to use USB-C connectors with the DP altmode helper code on
devicetree based platforms. To get this working there must be a DRM
bridge chain from the DisplayPort controller to the USB-C connector.
E.g. on Rockchip RK3576:

root@rk3576 # cat /sys/kernel/debug/dri/0/encoder-0/bridges
bridge[0]: dw_dp_bridge_funcs
        refcount: 7
        type: [10] DP
        OF: /soc/dp@27e40000:rockchip,rk3576-dp
        ops: [0x47] detect edid hpd
bridge[1]: drm_aux_bridge_funcs
        refcount: 4
        type: [0] Unknown
        OF: /soc/phy@2b010000:rockchip,rk3576-usbdp-phy
        ops: [0x0]
bridge[2]: drm_aux_hpd_bridge_funcs
        refcount: 5
        type: [10] DP
        OF: /soc/i2c@2ac50000/typec-portc@22/connector:usb-c-connector
        ops: [0x4] hpd

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/Kconfig              |  2 ++
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 17 +++++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index 14698571b607..39759bb2fa1d 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -136,8 +136,10 @@ config PHY_ROCKCHIP_USBDP
 	tristate "Rockchip USBDP COMBO PHY Driver"
 	depends on ARCH_ROCKCHIP && OF
 	depends on TYPEC
+	depends on DRM || DRM=n
 	select GENERIC_PHY
 	select USB_COMMON
+	select DRM_AUX_BRIDGE if DRM_BRIDGE
 	help
 	  Enable this to support the Rockchip USB3.0/DP combo PHY with
 	  Samsung IP block. This is required for USB3 support on RK3588.
diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index eda3f7a1e267..8ac6a83b0b2a 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2024 Collabora Ltd
  */
 
+#include <drm/bridge/aux-bridge.h>
 #include <dt-bindings/phy/phy.h>
 #include <linux/bitfield.h>
 #include <linux/bits.h>
@@ -1414,6 +1415,7 @@ static int rk_udphy_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct phy_provider *phy_provider;
+	struct fwnode_handle *dp_aux_ep;
 	struct resource *res;
 	struct rk_udphy *udphy;
 	void __iomem *base;
@@ -1468,6 +1470,21 @@ static int rk_udphy_probe(struct platform_device *pdev)
 			return ret;
 	}
 
+	/*
+	 * Only register the DRM bridge, if the DP aux channel is connected.
+	 * Some boards use the USBDP PHY only for its USB3 capabilities. The
+	 * aux bridge itself will be registered using port 0, endpoint 0, which
+	 * is fine as that is the actual superspeed data connection shared by
+	 * USB3 and DP based on the mux config.
+	 */
+	dp_aux_ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 3, 0, 0);
+	if (dp_aux_ep) {
+		ret = drm_aux_bridge_register(dev);
+		fwnode_handle_put(dp_aux_ep);
+		if (ret)
+			return ret;
+	}
+
 	udphy->phy_u3 = devm_phy_create(dev, dev->of_node, &rk_udphy_usb3_phy_ops);
 	if (IS_ERR(udphy->phy_u3)) {
 		ret = PTR_ERR(udphy->phy_u3);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 17/36] phy: rockchip: usbdp: Drop DP HPD handling
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (15 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 16/36] phy: rockchip: usbdp: Register DP aux bridge Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 16:44 ` [PATCH v12 18/36] phy: rockchip: usbdp: Rename mode_change to phy_needs_reinit Sebastian Reichel
                   ` (18 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Drop the HPD handling logic from the USBDP PHY. The registers involved
require the display controller power domain being enabled and thus the
HPD signal should be handled by the displayport controller itself.
Apart from that the HPD handling as it is done here is incorrect and
misses hotplug events happening after the USB-C connector (e.g. when
a USB-C to HDMI adapter is involved and the HDMI cable is replugged).

Proper USB-C DP HPD support requires some restructuring of the DP
controller driver, which will happen independent of this patch. The
mainline kernel does not yet support USB-C DP AltMode on RK3588 and
RK3576, so it is fine to drop this code without adding the counterpart
in the DRM in an atomic change.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 85 ++++---------------------------
 1 file changed, 9 insertions(+), 76 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 8ac6a83b0b2a..24108816e3b9 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -128,7 +128,6 @@ struct rk_udphy_grf_cfg {
 
 struct rk_udphy_vogrf_cfg {
 	/* vo-grf */
-	struct rk_udphy_grf_reg hpd_trigger;
 	u32 dp_lane_reg;
 };
 
@@ -186,14 +185,11 @@ struct rk_udphy {
 	u32 dp_lane_sel[4];
 	u32 dp_aux_dout_sel;
 	u32 dp_aux_din_sel;
-	bool dp_sink_hpd_sel;
-	bool dp_sink_hpd_cfg;
 	unsigned int link_rate;
 	unsigned int lanes;
 	u8 bw;
 	int id;
 
-	bool dp_in_use;
 	int dp_lanes;
 
 	/* PHY const config */
@@ -577,19 +573,6 @@ static void rk_udphy_dp_lane_enable(struct rk_udphy *udphy, int dp_lanes)
 				   CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0));
 }
 
-static void rk_udphy_dp_hpd_event_trigger(struct rk_udphy *udphy, bool hpd)
-{
-	const struct rk_udphy_cfg *cfg = udphy->cfgs;
-
-	udphy->dp_sink_hpd_sel = true;
-	udphy->dp_sink_hpd_cfg = hpd;
-
-	if (!udphy->dp_in_use)
-		return;
-
-	rk_udphy_grfreg_write(udphy->vogrf, &cfg->vogrfcfg[udphy->id].hpd_trigger, hpd);
-}
-
 static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 mode)
 {
 	if (udphy->mode == mode)
@@ -1000,29 +983,6 @@ static void rk_udphy_power_off(struct rk_udphy *udphy, u8 mode)
 		rk_udphy_disable(udphy);
 }
 
-static int rk_udphy_dp_phy_init(struct phy *phy)
-{
-	struct rk_udphy *udphy = phy_get_drvdata(phy);
-
-	mutex_lock(&udphy->mutex);
-
-	udphy->dp_in_use = true;
-
-	mutex_unlock(&udphy->mutex);
-
-	return 0;
-}
-
-static int rk_udphy_dp_phy_exit(struct phy *phy)
-{
-	struct rk_udphy *udphy = phy_get_drvdata(phy);
-
-	mutex_lock(&udphy->mutex);
-	udphy->dp_in_use = false;
-	mutex_unlock(&udphy->mutex);
-	return 0;
-}
-
 static int rk_udphy_dp_phy_power_on(struct phy *phy)
 {
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
@@ -1254,8 +1214,6 @@ static int rk_udphy_dp_phy_configure(struct phy *phy,
 }
 
 static const struct phy_ops rk_udphy_dp_phy_ops = {
-	.init		= rk_udphy_dp_phy_init,
-	.exit		= rk_udphy_dp_phy_exit,
 	.power_on	= rk_udphy_dp_phy_power_on,
 	.power_off	= rk_udphy_dp_phy_power_off,
 	.configure	= rk_udphy_dp_phy_configure,
@@ -1309,6 +1267,14 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 	struct rk_udphy *udphy = typec_mux_get_drvdata(mux);
 	u8 mode;
 
+	/*
+	 * Ignore mux events not involving DP AltMode, because
+	 * the mode field is being reused, e.g. state->mode == 4
+	 * could be either TYPEC_MODE_USB4 or TYPEC_DP_STATE_C.
+	 */
+	if (!state->alt || state->alt->svid != USB_TYPEC_DP_SID)
+		return 0;
+
 	mutex_lock(&udphy->mutex);
 
 	switch (state->mode) {
@@ -1340,22 +1306,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 		break;
 	}
 
-	if (state->alt && state->alt->svid == USB_TYPEC_DP_SID) {
-		struct typec_displayport_data *data = state->data;
-
-		if (!data) {
-			rk_udphy_dp_hpd_event_trigger(udphy, false);
-		} else if (data->status & DP_STATUS_IRQ_HPD) {
-			rk_udphy_dp_hpd_event_trigger(udphy, false);
-			usleep_range(750, 800);
-			rk_udphy_dp_hpd_event_trigger(udphy, true);
-		} else if (data->status & DP_STATUS_HPD_STATE) {
-			rk_udphy_mode_set(udphy, mode);
-			rk_udphy_dp_hpd_event_trigger(udphy, true);
-		} else {
-			rk_udphy_dp_hpd_event_trigger(udphy, false);
-		}
-	}
+	rk_udphy_mode_set(udphy, mode);
 
 	mutex_unlock(&udphy->mutex);
 	return 0;
@@ -1510,20 +1461,6 @@ static int rk_udphy_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int __maybe_unused rk_udphy_resume(struct device *dev)
-{
-	struct rk_udphy *udphy = dev_get_drvdata(dev);
-
-	if (udphy->dp_sink_hpd_sel)
-		rk_udphy_dp_hpd_event_trigger(udphy, udphy->dp_sink_hpd_cfg);
-
-	return 0;
-}
-
-static const struct dev_pm_ops rk_udphy_pm_ops = {
-	SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, rk_udphy_resume)
-};
-
 static const char * const rk_udphy_rst_list[] = {
 	"init", "cmn", "lane", "pcs_apb", "pma_apb"
 };
@@ -1547,7 +1484,6 @@ static const struct rk_udphy_cfg rk3576_udphy_cfgs = {
 	},
 	.vogrfcfg = {
 		{
-			.hpd_trigger	= RK_UDPHY_GEN_GRF_REG(0x0000, 11, 10, 1, 3),
 			.dp_lane_reg    = 0x0000,
 		},
 	},
@@ -1588,11 +1524,9 @@ static const struct rk_udphy_cfg rk3588_udphy_cfgs = {
 	},
 	.vogrfcfg = {
 		{
-			.hpd_trigger	= RK_UDPHY_GEN_GRF_REG(0x0000, 11, 10, 1, 3),
 			.dp_lane_reg	= 0x0000,
 		},
 		{
-			.hpd_trigger	= RK_UDPHY_GEN_GRF_REG(0x0008, 11, 10, 1, 3),
 			.dp_lane_reg	= 0x0008,
 		},
 	},
@@ -1628,7 +1562,6 @@ static struct platform_driver rk_udphy_driver = {
 	.driver		= {
 		.name	= "rockchip-usbdp-phy",
 		.of_match_table = rk_udphy_dt_match,
-		.pm = &rk_udphy_pm_ops,
 	},
 };
 module_platform_driver(rk_udphy_driver);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 18/36] phy: rockchip: usbdp: Rename mode_change to phy_needs_reinit
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (16 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 17/36] phy: rockchip: usbdp: Drop DP HPD handling Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 21:10   ` sashiko-bot
  2026-07-10 16:44 ` [PATCH v12 19/36] phy: rockchip: usbdp: Re-init the PHY on orientation change Sebastian Reichel
                   ` (17 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Right now the mode_change property is set whenever the mode changes
between USB-only, DP-only and USB-DP. It is needed, because on any
mode change the PHY needs to be re-initialized. Apparently at least
DP also requires a re-init when the cable orientation is changed,
which is currently not being done (except when the orientation switch
also involves a mode change). Prepare for this by renaming mode_change
to phy_needs_reinit.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 24108816e3b9..e44d19c9d119 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -171,7 +171,7 @@ struct rk_udphy {
 
 	/* PHY status management */
 	bool flip;
-	bool mode_change;
+	bool phy_needs_reinit;
 	u8 mode;
 	u8 status;
 
@@ -578,7 +578,7 @@ static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 mode)
 	if (udphy->mode == mode)
 		return;
 
-	udphy->mode_change = true;
+	udphy->phy_needs_reinit = true;
 	udphy->mode = mode;
 }
 
@@ -951,15 +951,15 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 
 		if (udphy->mode & UDPHY_MODE_USB)
 			rk_udphy_u3_port_disable(udphy, false);
-		udphy->mode_change = false;
-	} else if (udphy->mode_change) {
+		udphy->phy_needs_reinit = false;
+	} else if (udphy->phy_needs_reinit) {
 		if (udphy->mode == UDPHY_MODE_DP)
 			rk_udphy_u3_port_disable(udphy, true);
 
 		ret = rk_udphy_init(udphy);
 		if (ret)
 			return ret;
-		udphy->mode_change = false;
+		udphy->phy_needs_reinit = false;
 	}
 
 	udphy->status |= mode;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 19/36] phy: rockchip: usbdp: Re-init the PHY on orientation change
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (17 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 18/36] phy: rockchip: usbdp: Rename mode_change to phy_needs_reinit Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 21:15   ` sashiko-bot
  2026-07-10 16:44 ` [PATCH v12 20/36] phy: rockchip: usbdp: Factor out lane_mux_sel setup Sebastian Reichel
                   ` (16 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Changing the cable orientation reconfigures the lane muxing, which
requires re-initializing the PHY. Without this DP functionality
breaks, if the cable is re-plugged with swapped orientation.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index e44d19c9d119..4b454798c4ed 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -620,6 +620,7 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
 				 enum typec_orientation orien)
 {
 	struct rk_udphy *udphy = typec_switch_get_drvdata(sw);
+	bool flipped = orien == TYPEC_ORIENTATION_REVERSE;
 
 	mutex_lock(&udphy->mutex);
 
@@ -631,7 +632,10 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
 		goto unlock_ret;
 	}
 
-	udphy->flip = orien == TYPEC_ORIENTATION_REVERSE;
+	if (udphy->flip != flipped)
+		udphy->phy_needs_reinit = true;
+
+	udphy->flip = flipped;
 	rk_udphy_set_typec_default_mapping(udphy);
 	rk_udphy_usb_bvalid_enable(udphy, true);
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 20/36] phy: rockchip: usbdp: Factor out lane_mux_sel setup
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (18 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 19/36] phy: rockchip: usbdp: Re-init the PHY on orientation change Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 21:16   ` sashiko-bot
  2026-07-10 16:44 ` [PATCH v12 21/36] phy: rockchip: usbdp: Properly handle TYPEC_STATE_SAFE and TYPEC_STATE_USB Sebastian Reichel
                   ` (15 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Avoid describing the USB+DP lane_mux_sel logic twice by introducing
a helper function to reduce code duplication.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 81 +++++++++++++++----------------
 1 file changed, 40 insertions(+), 41 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 4b454798c4ed..4e54020d1755 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -582,6 +582,42 @@ static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 mode)
 	udphy->mode = mode;
 }
 
+static void rk_udphy_set_typec_state(struct rk_udphy *udphy, unsigned long state)
+{
+	u8 mode;
+
+	switch (state) {
+	case TYPEC_DP_STATE_C:
+	case TYPEC_DP_STATE_E:
+		udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
+		udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
+		udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
+		udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
+		mode = UDPHY_MODE_DP;
+		udphy->dp_lanes = 4;
+		break;
+
+	case TYPEC_DP_STATE_D:
+	default:
+		if (udphy->flip) {
+			udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
+			udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
+			udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB;
+			udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB;
+		} else {
+			udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB;
+			udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB;
+			udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
+			udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
+		}
+		mode = UDPHY_MODE_DP_USB;
+		udphy->dp_lanes = 2;
+		break;
+	}
+
+	rk_udphy_mode_set(udphy, mode);
+}
+
 static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 {
 	if (udphy->flip) {
@@ -589,10 +625,6 @@ static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 		udphy->dp_lane_sel[1] = 1;
 		udphy->dp_lane_sel[2] = 3;
 		udphy->dp_lane_sel[3] = 2;
-		udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB;
-		udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB;
 		udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_INVERT;
 		udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_INVERT;
 		gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 1);
@@ -602,18 +634,14 @@ static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 		udphy->dp_lane_sel[1] = 3;
 		udphy->dp_lane_sel[2] = 1;
 		udphy->dp_lane_sel[3] = 0;
-		udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB;
-		udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB;
-		udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
 		udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_NORMAL;
 		udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_NORMAL;
 		gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0);
 		gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 1);
 	}
 
-	rk_udphy_mode_set(udphy, UDPHY_MODE_DP_USB);
-	udphy->dp_lanes = 2;
+	/* default to USB3 + DP as 4 lane USB is not supported */
+	rk_udphy_set_typec_state(udphy, TYPEC_DP_STATE_D);
 }
 
 static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
@@ -1269,7 +1297,6 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 				  struct typec_mux_state *state)
 {
 	struct rk_udphy *udphy = typec_mux_get_drvdata(mux);
-	u8 mode;
 
 	/*
 	 * Ignore mux events not involving DP AltMode, because
@@ -1281,38 +1308,10 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 
 	mutex_lock(&udphy->mutex);
 
-	switch (state->mode) {
-	case TYPEC_DP_STATE_C:
-	case TYPEC_DP_STATE_E:
-		udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
-		mode = UDPHY_MODE_DP;
-		udphy->dp_lanes = 4;
-		break;
-
-	case TYPEC_DP_STATE_D:
-	default:
-		if (udphy->flip) {
-			udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
-			udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
-			udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB;
-			udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB;
-		} else {
-			udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB;
-			udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB;
-			udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
-			udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
-		}
-		mode = UDPHY_MODE_DP_USB;
-		udphy->dp_lanes = 2;
-		break;
-	}
-
-	rk_udphy_mode_set(udphy, mode);
+	rk_udphy_set_typec_state(udphy, state->mode);
 
 	mutex_unlock(&udphy->mutex);
+
 	return 0;
 }
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 21/36] phy: rockchip: usbdp: Properly handle TYPEC_STATE_SAFE and TYPEC_STATE_USB
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (19 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 20/36] phy: rockchip: usbdp: Factor out lane_mux_sel setup Sebastian Reichel
@ 2026-07-10 16:44 ` Sebastian Reichel
  2026-07-10 21:18   ` sashiko-bot
  2026-07-10 16:45 ` [PATCH v12 22/36] phy: rockchip: usbdp: Use guard functions for mutex Sebastian Reichel
                   ` (14 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:44 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, Sashiko

Handle TYPEC_STATE_SAFE and TYPEC_STATE_USB Type-C state events,
so that the muxing is properly updated when exiting DP AltMode.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/message/20260619155020.CC7361F000E9%40smtp.kernel.org
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 4e54020d1755..0399cbf96e19 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1293,17 +1293,26 @@ static const struct phy_ops rk_udphy_usb3_phy_ops = {
 	.owner		= THIS_MODULE,
 };
 
+static bool rk_udphy_is_supported_mode(struct typec_mux_state *state)
+{
+	/* Handle Safe State and USB State */
+	if (state->mode < TYPEC_STATE_MODAL)
+		return true;
+
+	/* Handle DP AltMode */
+	if (state->alt && state->alt->svid == USB_TYPEC_DP_SID)
+		return true;
+
+	return false;
+}
+
 static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 				  struct typec_mux_state *state)
 {
 	struct rk_udphy *udphy = typec_mux_get_drvdata(mux);
 
-	/*
-	 * Ignore mux events not involving DP AltMode, because
-	 * the mode field is being reused, e.g. state->mode == 4
-	 * could be either TYPEC_MODE_USB4 or TYPEC_DP_STATE_C.
-	 */
-	if (!state->alt || state->alt->svid != USB_TYPEC_DP_SID)
+	/* Ignore mux events not involving USB or DP */
+	if (!rk_udphy_is_supported_mode(state))
 		return 0;
 
 	mutex_lock(&udphy->mutex);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 22/36] phy: rockchip: usbdp: Use guard functions for mutex
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (20 preceding siblings ...)
  2026-07-10 16:44 ` [PATCH v12 21/36] phy: rockchip: usbdp: Properly handle TYPEC_STATE_SAFE and TYPEC_STATE_USB Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 21:18   ` sashiko-bot
  2026-07-10 16:45 ` [PATCH v12 23/36] phy: rockchip: usbdp: Clear USB status on PHY exit Sebastian Reichel
                   ` (13 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Convert the driver to use guard functions for mutex handling as
a small cleanup. There is a small functional change in the DP PHY
power up function, which no longer sleeps if the internal powerup
code returns an error. This is not a problem as the sleep is only
relevant for successful power-up.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 54 +++++++++++++------------------
 1 file changed, 23 insertions(+), 31 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 0399cbf96e19..8c165bcab796 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -10,6 +10,7 @@
 #include <dt-bindings/phy/phy.h>
 #include <linux/bitfield.h>
 #include <linux/bits.h>
+#include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
@@ -650,14 +651,15 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
 	struct rk_udphy *udphy = typec_switch_get_drvdata(sw);
 	bool flipped = orien == TYPEC_ORIENTATION_REVERSE;
 
-	mutex_lock(&udphy->mutex);
+	guard(mutex)(&udphy->mutex);
 
 	if (orien == TYPEC_ORIENTATION_NONE) {
 		gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0);
 		gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 0);
 		/* unattached */
 		rk_udphy_usb_bvalid_enable(udphy, false);
-		goto unlock_ret;
+
+		return 0;
 	}
 
 	if (udphy->flip != flipped)
@@ -667,8 +669,6 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
 	rk_udphy_set_typec_default_mapping(udphy);
 	rk_udphy_usb_bvalid_enable(udphy, true);
 
-unlock_ret:
-	mutex_unlock(&udphy->mutex);
 	return 0;
 }
 
@@ -1020,26 +1020,25 @@ static int rk_udphy_dp_phy_power_on(struct phy *phy)
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
 	int ret;
 
-	mutex_lock(&udphy->mutex);
+	scoped_guard(mutex, &udphy->mutex) {
+		phy_set_bus_width(phy, udphy->dp_lanes);
 
-	phy_set_bus_width(phy, udphy->dp_lanes);
-
-	ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP);
-	if (ret)
-		goto unlock;
+		ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP);
+		if (ret)
+			return ret;
 
-	rk_udphy_dp_lane_enable(udphy, udphy->dp_lanes);
+		rk_udphy_dp_lane_enable(udphy, udphy->dp_lanes);
 
-	rk_udphy_dp_lane_select(udphy);
+		rk_udphy_dp_lane_select(udphy);
+	}
 
-unlock:
-	mutex_unlock(&udphy->mutex);
 	/*
 	 * If data send by aux channel too fast after phy power on,
 	 * the aux may be not ready which will cause aux error. Adding
 	 * delay to avoid this issue.
 	 */
 	usleep_range(10000, 11000);
+
 	return ret;
 }
 
@@ -1047,10 +1046,10 @@ static int rk_udphy_dp_phy_power_off(struct phy *phy)
 {
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
 
-	mutex_lock(&udphy->mutex);
+	guard(mutex)(&udphy->mutex);
+
 	rk_udphy_dp_lane_enable(udphy, 0);
 	rk_udphy_power_off(udphy, UDPHY_MODE_DP);
-	mutex_unlock(&udphy->mutex);
 
 	return 0;
 }
@@ -1255,35 +1254,30 @@ static const struct phy_ops rk_udphy_dp_phy_ops = {
 static int rk_udphy_usb3_phy_init(struct phy *phy)
 {
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
-	int ret = 0;
 
-	mutex_lock(&udphy->mutex);
+	guard(mutex)(&udphy->mutex);
+
 	/* DP only or high-speed, disable U3 port */
 	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) {
 		rk_udphy_u3_port_disable(udphy, true);
-		goto unlock;
+		return 0;
 	}
 
-	ret = rk_udphy_power_on(udphy, UDPHY_MODE_USB);
-
-unlock:
-	mutex_unlock(&udphy->mutex);
-	return ret;
+	return rk_udphy_power_on(udphy, UDPHY_MODE_USB);
 }
 
 static int rk_udphy_usb3_phy_exit(struct phy *phy)
 {
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
 
-	mutex_lock(&udphy->mutex);
+	guard(mutex)(&udphy->mutex);
+
 	/* DP only or high-speed */
 	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs)
-		goto unlock;
+		return 0;
 
 	rk_udphy_power_off(udphy, UDPHY_MODE_USB);
 
-unlock:
-	mutex_unlock(&udphy->mutex);
 	return 0;
 }
 
@@ -1315,12 +1309,10 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 	if (!rk_udphy_is_supported_mode(state))
 		return 0;
 
-	mutex_lock(&udphy->mutex);
+	guard(mutex)(&udphy->mutex);
 
 	rk_udphy_set_typec_state(udphy, state->mode);
 
-	mutex_unlock(&udphy->mutex);
-
 	return 0;
 }
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 23/36] phy: rockchip: usbdp: Clear USB status on PHY exit
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (21 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 22/36] phy: rockchip: usbdp: Use guard functions for mutex Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 21:17   ` sashiko-bot
  2026-07-10 16:45 ` [PATCH v12 24/36] phy: rockchip: usbdp: Hold mutex in DP PHY configure Sebastian Reichel
                   ` (12 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, Sashiko

Ensure the USB status flag is cleared when the USB3 PHY is
exited while the system is in DP-only mode. This can happen
if the USB3 controller device is unbound while a DP-only
adapter is plugged into the USB-C port.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/message/20260625-rockchip-usbdp-cleanup-v7-24-38eb3cf654fd%40collabora.com
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 8c165bcab796..a742bde7155b 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1273,8 +1273,10 @@ static int rk_udphy_usb3_phy_exit(struct phy *phy)
 	guard(mutex)(&udphy->mutex);
 
 	/* DP only or high-speed */
-	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs)
+	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) {
+		udphy->status &= ~UDPHY_MODE_USB;
 		return 0;
+	}
 
 	rk_udphy_power_off(udphy, UDPHY_MODE_USB);
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 24/36] phy: rockchip: usbdp: Hold mutex in DP PHY configure
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (22 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 23/36] phy: rockchip: usbdp: Clear USB status on PHY exit Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 16:45 ` [PATCH v12 25/36] phy: rockchip: usbdp: Add some extra debug messages Sebastian Reichel
                   ` (11 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, Sashiko

rk_udphy_dp_phy_configure() accesses some variables from the struct
rk_udphy, which are updated independently from the USB-C framework.

The USB-C mux/orientation switch functions already hold a mutex to
ensure mutual exclusive access to the struct rk_udphy states, so
simply hold the same one in the DP PHY configuration function.

Reproducing problems due to this on real hardware would be really hard,
but could be possible when quickly re-connecting the USB-C connector.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/linux-phy/20260612164627.23D391F000E9@smtp.kernel.org/
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index a742bde7155b..cd79c5da566a 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1154,6 +1154,8 @@ static int rk_udphy_dp_phy_configure(struct phy *phy,
 	u32 i, val, lane;
 	int ret;
 
+	guard(mutex)(&udphy->mutex);
+
 	if (dp->set_rate) {
 		ret = rk_udphy_dp_phy_verify_link_rate(udphy, dp);
 		if (ret)

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 25/36] phy: rockchip: usbdp: Add some extra debug messages
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (23 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 24/36] phy: rockchip: usbdp: Hold mutex in DP PHY configure Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 16:45 ` [PATCH v12 26/36] phy: rockchip: usbdp: Avoid xHCI SErrors Sebastian Reichel
                   ` (10 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

It's useful to log PHY reinit to ease debugging issues around
USB-C hotplugging.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index cd79c5da566a..edee27933d89 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -24,6 +24,7 @@
 #include <linux/property.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
+#include <linux/string_choices.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/typec_dp.h>
 #include <linux/usb/typec_mux.h>
@@ -462,6 +463,8 @@ static int rk_udphy_reset_deassert(struct rk_udphy *udphy, char *name)
 			return reset_control_deassert(list[idx].rstc);
 	}
 
+	dev_err(udphy->dev, "failed to de-assert missing reset line: %s\n", name);
+
 	return -EINVAL;
 }
 
@@ -488,6 +491,8 @@ static void rk_udphy_u3_port_disable(struct rk_udphy *udphy, u8 disable)
 	const struct rk_udphy_cfg *cfg = udphy->cfgs;
 	const struct rk_udphy_grf_reg *preg;
 
+	dev_dbg(udphy->dev, "USB3 port %s\n", str_on_off(!disable));
+
 	preg = udphy->id ? &cfg->grfcfg.usb3otg1_cfg : &cfg->grfcfg.usb3otg0_cfg;
 	rk_udphy_grfreg_write(udphy->usbgrf, preg, disable);
 }
@@ -662,8 +667,10 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
 		return 0;
 	}
 
-	if (udphy->flip != flipped)
+	if (udphy->flip != flipped) {
+		dev_dbg(udphy->dev, "cable orientation changed, PHY re-init required.\n");
 		udphy->phy_needs_reinit = true;
+	}
 
 	udphy->flip = flipped;
 	rk_udphy_set_typec_default_mapping(udphy);
@@ -781,6 +788,11 @@ static int rk_udphy_init(struct rk_udphy *udphy)
 	const struct rk_udphy_cfg *cfg = udphy->cfgs;
 	int ret;
 
+	dev_dbg(udphy->dev, "reinit PHY with USB3=%s and DP=%s (%u lanes) flipped=%s\n",
+		str_on_off(udphy->mode & UDPHY_MODE_USB),
+		str_on_off(udphy->mode & UDPHY_MODE_DP),
+		udphy->dp_lanes, str_yes_no(udphy->flip));
+
 	rk_udphy_reset_assert_all(udphy);
 	usleep_range(10000, 11000);
 
@@ -851,6 +863,8 @@ static int rk_udphy_setup(struct rk_udphy *udphy)
 {
 	int ret;
 
+	dev_dbg(udphy->dev, "enable PHY\n");
+
 	ret = clk_bulk_prepare_enable(udphy->num_clks, udphy->clks);
 	if (ret) {
 		dev_err(udphy->dev, "failed to enable clk\n");
@@ -869,6 +883,7 @@ static int rk_udphy_setup(struct rk_udphy *udphy)
 
 static void rk_udphy_disable(struct rk_udphy *udphy)
 {
+	dev_dbg(udphy->dev, "disable PHY\n");
 	clk_bulk_disable_unprepare(udphy->num_clks, udphy->clks);
 	rk_udphy_reset_assert_all(udphy);
 }
@@ -1310,8 +1325,12 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 	struct rk_udphy *udphy = typec_mux_get_drvdata(mux);
 
 	/* Ignore mux events not involving USB or DP */
-	if (!rk_udphy_is_supported_mode(state))
+	if (!rk_udphy_is_supported_mode(state)) {
+		dev_dbg(udphy->dev, "ignore mux event with mode=%lu\n", state->mode);
 		return 0;
+	}
+
+	dev_dbg(udphy->dev, "new mode: %lu\n", state->mode);
 
 	guard(mutex)(&udphy->mutex);
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 26/36] phy: rockchip: usbdp: Avoid xHCI SErrors
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (24 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 25/36] phy: rockchip: usbdp: Add some extra debug messages Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 21:20   ` sashiko-bot
  2026-07-10 16:45 ` [PATCH v12 27/36] phy: rockchip: usbdp: Handle rk_udphy_reset_deassert errors Sebastian Reichel
                   ` (9 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

The USBDP PHY provides the PIPE clock to the USB3 controller, which
means the PHY must be fully running when anything tries to access
the xHCI registers.

When switching between USB3-only, USB3 + DP and DP-only mode, the
PHY must be re-initialized resulting in a short period of the PHY
being disabled. If the DWC3 driver decides to access the xHCI at
this point the system will fail with an SError.

This patch avoids the problems by disabling the USB3 port before
re-initializing it. This does a couple of things:

- forces phystatus to 0 from GRF (not from PHY)
- switches PIPE clock source from PHY to UTMI (safe fallback clock)
- num_u3_port=0

The last part will be ignored, as DWC3 already probed, but the
clock re-routing will avoid the SError. There is a small delay
afterwards to make sure the mux happened. The datasheet gives
no hints how long it takes, so delay time is a guess.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index edee27933d89..ff768e5b43ca 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1000,12 +1000,15 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 			rk_udphy_u3_port_disable(udphy, false);
 		udphy->phy_needs_reinit = false;
 	} else if (udphy->phy_needs_reinit) {
-		if (udphy->mode == UDPHY_MODE_DP)
-			rk_udphy_u3_port_disable(udphy, true);
+		rk_udphy_u3_port_disable(udphy, true);
+		udelay(10);
 
 		ret = rk_udphy_init(udphy);
 		if (ret)
 			return ret;
+
+		if (udphy->mode & UDPHY_MODE_USB)
+			rk_udphy_u3_port_disable(udphy, false);
 		udphy->phy_needs_reinit = false;
 	}
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 27/36] phy: rockchip: usbdp: Handle rk_udphy_reset_deassert errors
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (25 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 26/36] phy: rockchip: usbdp: Avoid xHCI SErrors Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 21:17   ` sashiko-bot
  2026-07-10 16:45 ` [PATCH v12 28/36] phy: rockchip: usbdp: Only enable USB3 when not in high-speed mode Sebastian Reichel
                   ` (8 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, Sashiko

Handle rk_udphy_reset_deassert returning errors to avoid theoretical
(Rockchip reset controller driver does not return errors) SError.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/message/20260626211151.2332F1F000E9%40smtp.kernel.org
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index ff768e5b43ca..2099ae2e51d1 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -803,8 +803,12 @@ static int rk_udphy_init(struct rk_udphy *udphy)
 	/* Step 1: power on pma and deassert apb rstn */
 	rk_udphy_grfreg_write(udphy->udphygrf, &cfg->grfcfg.low_pwrn, true);
 
-	rk_udphy_reset_deassert(udphy, "pma_apb");
-	rk_udphy_reset_deassert(udphy, "pcs_apb");
+	ret = rk_udphy_reset_deassert(udphy, "pma_apb");
+	if (ret)
+		goto assert_resets;
+	ret = rk_udphy_reset_deassert(udphy, "pcs_apb");
+	if (ret)
+		goto assert_resets;
 
 	/* Step 2: set init sequence and phy refclk */
 	ret = regmap_multi_reg_write(udphy->pma_regmap, rk_udphy_init_sequence,
@@ -830,8 +834,11 @@ static int rk_udphy_init(struct rk_udphy *udphy)
 			   FIELD_PREP(CMN_DP_LANE_EN_ALL, 0));
 
 	/* Step 4: deassert init rstn and wait for 200ns from datasheet */
-	if (udphy->mode & UDPHY_MODE_USB)
-		rk_udphy_reset_deassert(udphy, "init");
+	if (udphy->mode & UDPHY_MODE_USB) {
+		ret = rk_udphy_reset_deassert(udphy, "init");
+		if (ret)
+			goto assert_resets;
+	}
 
 	if (udphy->mode & UDPHY_MODE_DP) {
 		regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET,
@@ -843,8 +850,14 @@ static int rk_udphy_init(struct rk_udphy *udphy)
 
 	/*  Step 5: deassert cmn/lane rstn */
 	if (udphy->mode & UDPHY_MODE_USB) {
-		rk_udphy_reset_deassert(udphy, "cmn");
-		rk_udphy_reset_deassert(udphy, "lane");
+		ret = rk_udphy_reset_deassert(udphy, "cmn");
+		if (ret)
+			goto assert_resets;
+
+		ret = rk_udphy_reset_deassert(udphy, "lane");
+		if (ret)
+			goto assert_resets;
+
 	}
 
 	/*  Step 6: wait for lock done of pll */

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 28/36] phy: rockchip: usbdp: Only enable USB3 when not in high-speed mode
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (26 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 27/36] phy: rockchip: usbdp: Handle rk_udphy_reset_deassert errors Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 21:26   ` sashiko-bot
  2026-07-10 16:45 ` [PATCH v12 29/36] phy: core: add notifier infrastructure Sebastian Reichel
                   ` (7 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel, Sashiko

Ensure that USB3 mode is not accidently enabled during PHY re-init
for systems that are configured as high-speed only via DT.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/message/20260626212424.C215E1F000E9%40smtp.kernel.org
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 2099ae2e51d1..af915cc37727 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1009,7 +1009,7 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 		if (ret)
 			return ret;
 
-		if (udphy->mode & UDPHY_MODE_USB)
+		if (!udphy->hs && udphy->mode & UDPHY_MODE_USB)
 			rk_udphy_u3_port_disable(udphy, false);
 		udphy->phy_needs_reinit = false;
 	} else if (udphy->phy_needs_reinit) {

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 29/36] phy: core: add notifier infrastructure
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (27 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 28/36] phy: rockchip: usbdp: Only enable USB3 when not in high-speed mode Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 16:45 ` [PATCH v12 30/36] usb: dwc3: core: support PHY reset notifications Sebastian Reichel
                   ` (6 subsequent siblings)
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Some PHY devices with multiple ports (e.g. USB3 and DP) require a reset
if the configuration changes or cable orientation changes. This is a
problem, as the consumer device will run into undefined behavior.

With the new PHY notifier API introduced in this patch, the consumer
driver can hook into reset events coming from a PHY device to handle the
PHY going down gracefully.

Note that this uses -ENOSYS instead of the more sensible -ENOTSUP for
the stub functions when GENERIC_PHY is disabled to stay consistent with
the existing ones.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/phy-core.c  | 65 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/phy/phy.h | 40 ++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 21aaf2f76e53..51d261daae7a 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -542,6 +542,70 @@ int phy_notify_state(struct phy *phy, union phy_notify state)
 }
 EXPORT_SYMBOL_GPL(phy_notify_state);
 
+/**
+ * phy_register_notifier() - register a notifier for PHY events
+ * @phy: the phy returned by phy_get()
+ * @nb: notifier block to register
+ *
+ * Allows PHY consumers to receive notifications about PHY reset events.
+ * PHY providers can signal these events using phy_notify_reset().
+ *
+ * Returns: %0 if successful, a negative error code otherwise
+ */
+int phy_register_notifier(struct phy *phy, struct notifier_block *nb)
+{
+	if (!phy)
+		return 0;
+
+	return blocking_notifier_chain_register(&phy->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(phy_register_notifier);
+
+/**
+ * phy_unregister_notifier() - unregister a notifier for PHY events
+ * @phy: the phy returned by phy_get()
+ * @nb: notifier block to unregister
+ *
+ * Returns: %0 if successful, a negative error code otherwise
+ */
+int phy_unregister_notifier(struct phy *phy, struct notifier_block *nb)
+{
+	if (!phy)
+		return 0;
+
+	return blocking_notifier_chain_unregister(&phy->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(phy_unregister_notifier);
+
+/**
+ * phy_notify_reset() - notify consumers of a PHY reset event
+ * @phy: the phy that is being reset
+ * @event: the notification event (PRE_RESET or POST_RESET)
+ *
+ * Called by PHY providers to notify consumers that the PHY is about to
+ * be reset or has completed a reset. This allows consumers to quiesce
+ * hardware before the PHY becomes unavailable.
+ *
+ * This may be called from within PHY provider callbacks (e.g. set_mode,
+ * power_on) where phy->mutex is held. Consumer notification handlers must
+ * therefore NOT call back into the PHY framework (e.g. phy_power_off,
+ * phy_exit) on the same PHY, as this would result in a deadlock.
+ *
+ * Returns: %0 if successful or no notifiers registered, a negative error
+ * code if a notifier returns an error (for PRE_RESET only)
+ */
+int phy_notify_reset(struct phy *phy, enum phy_notification event)
+{
+	int ret;
+
+	if (!phy)
+		return 0;
+
+	ret = blocking_notifier_call_chain(&phy->notifier, event, phy);
+	return notifier_to_errno(ret);
+}
+EXPORT_SYMBOL_GPL(phy_notify_reset);
+
 /**
  * phy_configure() - Changes the phy parameters
  * @phy: the phy returned by phy_get()
@@ -1018,6 +1082,7 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
 	device_initialize(&phy->dev);
 	lockdep_register_key(&phy->lockdep_key);
 	mutex_init_with_key(&phy->mutex, &phy->lockdep_key);
+	BLOCKING_INIT_NOTIFIER_HEAD(&phy->notifier);
 
 	phy->dev.class = &phy_class;
 	phy->dev.parent = dev;
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index ea47975e288a..3779a4d0a02c 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -11,6 +11,7 @@
 #define __DRIVERS_PHY_H
 
 #include <linux/err.h>
+#include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
@@ -53,6 +54,16 @@ enum phy_media {
 	PHY_MEDIA_DAC,
 };
 
+/**
+ * enum phy_notification - PHY notification events
+ * @PHY_NOTIFY_PRE_RESET: PHY is about to be reset, consumers should quiesce
+ * @PHY_NOTIFY_POST_RESET: PHY reset is complete, consumers may resume
+ */
+enum phy_notification {
+	PHY_NOTIFY_PRE_RESET,
+	PHY_NOTIFY_POST_RESET,
+};
+
 enum phy_ufs_state {
 	PHY_UFS_HIBERN8_ENTER,
 	PHY_UFS_HIBERN8_EXIT,
@@ -170,6 +181,7 @@ struct phy_attrs {
  * @power_count: used to protect when the PHY is used by multiple consumers
  * @attrs: used to specify PHY specific attributes
  * @pwr: power regulator associated with the phy
+ * @notifier: notifier head for PHY reset events
  * @debugfs: debugfs directory
  */
 struct phy {
@@ -182,6 +194,7 @@ struct phy {
 	int			power_count;
 	struct phy_attrs	attrs;
 	struct regulator	*pwr;
+	struct blocking_notifier_head notifier;
 	struct dentry		*debugfs;
 };
 
@@ -267,6 +280,9 @@ int phy_calibrate(struct phy *phy);
 int phy_notify_connect(struct phy *phy, int port);
 int phy_notify_disconnect(struct phy *phy, int port);
 int phy_notify_state(struct phy *phy, union phy_notify state);
+int phy_register_notifier(struct phy *phy, struct notifier_block *nb);
+int phy_unregister_notifier(struct phy *phy, struct notifier_block *nb);
+int phy_notify_reset(struct phy *phy, enum phy_notification event);
 static inline int phy_get_bus_width(struct phy *phy)
 {
 	return phy->attrs.bus_width;
@@ -428,6 +444,30 @@ static inline int phy_notify_state(struct phy *phy, union phy_notify state)
 	return -ENOSYS;
 }
 
+static inline int phy_register_notifier(struct phy *phy,
+					struct notifier_block *nb)
+{
+	if (!phy)
+		return 0;
+	return -ENOSYS;
+}
+
+static inline int phy_unregister_notifier(struct phy *phy,
+					  struct notifier_block *nb)
+{
+	if (!phy)
+		return 0;
+	return -ENOSYS;
+}
+
+static inline int phy_notify_reset(struct phy *phy,
+				   enum phy_notification event)
+{
+	if (!phy)
+		return 0;
+	return -ENOSYS;
+}
+
 static inline int phy_configure(struct phy *phy,
 				union phy_configure_opts *opts)
 {

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 30/36] usb: dwc3: core: support PHY reset notifications
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (28 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 29/36] phy: core: add notifier infrastructure Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 21:20   ` sashiko-bot
  2026-07-10 16:45 ` [PATCH v12 31/36] phy: rockchip: usbdp: Add phy reset notification support Sebastian Reichel
                   ` (5 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

On recent Rockchip platforms (at least RK3588 & RK3576), DWC3 IP is used
with a USBDP PHY providing USB3 and DP. This PHY needs to be reset when
the mode changes, which may happen when plugging in different USB-C
devices.

If the USBDP PHY resets with the DWC3 IP running, its internal state
corrupts resulting in the USBDP PHY not being able to lock some PLL
clocks, which effectively renders USB3 unusable.

To fix the issue this adds handling for the new PHY framework reset
notifications, which will assert PHYSOFTRST before the actual PHY
is disabled and will deassert it once the PHY returns.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/usb/dwc3/core.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/dwc3/core.h | 18 ++++++++++
 2 files changed, 106 insertions(+)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 517aa7f1486d..4d0b4c1c73f1 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -30,6 +30,7 @@
 #include <linux/pinctrl/devinfo.h>
 #include <linux/reset.h>
 #include <linux/bitfield.h>
+#include <linux/phy/phy.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -880,6 +881,90 @@ static int dwc3_phy_init(struct dwc3 *dwc)
 	return ret;
 }
 
+static int dwc3_usb3_phy_notify(struct notifier_block *nb,
+				unsigned long action, void *data)
+{
+	struct dwc3_phy_nb *pnb = container_of(nb, struct dwc3_phy_nb, nb);
+	struct dwc3 *dwc = pnb->dwc;
+	int port = pnb->port_index;
+	unsigned long flags;
+	u32 reg;
+
+	switch (action) {
+	case PHY_NOTIFY_PRE_RESET:
+		/*
+		 * If already suspended, the resume path will reinit GUSB3PIPECTL
+		 * via dwc3_core_init(). A forced resume is not possible as that
+		 * would call phy_init() resulting in a deadlock. Due to the
+		 * phy_init() in the resume path there is also no need to block
+		 * async RPM resume on our side, since the PHY synchronizes it
+		 * for us.
+		 */
+		if (pm_runtime_get_if_active(dwc->dev) <= 0)
+			return NOTIFY_OK;
+
+		atomic_inc(&dwc->phy_reset_count);
+
+		/*
+		 * Assert USB3 PHY soft reset within DWC3 before the external
+		 * PHY resets. This disconnects the PIPE interface, preventing
+		 * the DWC3 from interfering with PHY reinitialization and
+		 * avoiding LCPLL lock failures.
+		 */
+		spin_lock_irqsave(&dwc->lock, flags);
+		reg = dwc3_readl(dwc, DWC3_GUSB3PIPECTL(port));
+		reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
+		dwc3_writel(dwc, DWC3_GUSB3PIPECTL(port), reg);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		break;
+
+	case PHY_NOTIFY_POST_RESET:
+		if (!atomic_read(&dwc->phy_reset_count))
+			return NOTIFY_OK;
+		/*
+		 * Deassert PHY soft reset to reconnect the PIPE interface
+		 * after PHY reinitialization.
+		 */
+		spin_lock_irqsave(&dwc->lock, flags);
+		reg = dwc3_readl(dwc, DWC3_GUSB3PIPECTL(port));
+		reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
+		dwc3_writel(dwc, DWC3_GUSB3PIPECTL(port), reg);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+
+		pm_runtime_put_autosuspend(dwc->dev);
+		atomic_dec(&dwc->phy_reset_count);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static void dwc3_phy_register_notifiers(struct dwc3 *dwc)
+{
+	int i;
+
+	for (i = 0; i < dwc->num_usb3_ports; i++) {
+		dwc->usb3_phy_nb[i].nb.notifier_call = dwc3_usb3_phy_notify;
+		dwc->usb3_phy_nb[i].dwc = dwc;
+		dwc->usb3_phy_nb[i].port_index = i;
+		phy_register_notifier(dwc->usb3_generic_phy[i],
+				      &dwc->usb3_phy_nb[i].nb);
+	}
+}
+
+static void dwc3_phy_unregister_notifiers(struct dwc3 *dwc)
+{
+	int i;
+
+	for (i = 0; i < dwc->num_usb3_ports; i++)
+		phy_unregister_notifier(dwc->usb3_generic_phy[i],
+					&dwc->usb3_phy_nb[i].nb);
+
+	for (i = atomic_read(&dwc->phy_reset_count); i > 0; i--)
+		pm_runtime_put_autosuspend(dwc->dev);
+	atomic_set(&dwc->phy_reset_count, 0);
+}
+
 static void dwc3_phy_exit(struct dwc3 *dwc)
 {
 	int i;
@@ -2341,6 +2426,7 @@ int dwc3_core_probe(const struct dwc3_probe_data *data)
 
 	dwc3_check_params(dwc);
 	dwc3_debugfs_init(dwc);
+	dwc3_phy_register_notifiers(dwc);
 
 	if (!data->skip_core_init_mode) {
 		ret = dwc3_core_init_mode(dwc);
@@ -2355,6 +2441,7 @@ int dwc3_core_probe(const struct dwc3_probe_data *data)
 	return 0;
 
 err_exit_debugfs:
+	dwc3_phy_unregister_notifiers(dwc);
 	dwc3_debugfs_exit(dwc);
 	dwc3_event_buffers_cleanup(dwc);
 	dwc3_phy_power_off(dwc);
@@ -2412,6 +2499,7 @@ void dwc3_core_remove(struct dwc3 *dwc)
 
 	dwc3_core_exit_mode(dwc);
 	dwc3_debugfs_exit(dwc);
+	dwc3_phy_unregister_notifiers(dwc);
 
 	dwc3_core_exit(dwc);
 	dwc3_ulpi_exit(dwc);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index e0dee9d28740..a7a2baf85015 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -11,6 +11,7 @@
 #ifndef __DRIVERS_USB_DWC3_CORE_H
 #define __DRIVERS_USB_DWC3_CORE_H
 
+#include <linux/atomic.h>
 #include <linux/device.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
@@ -1002,6 +1003,20 @@ struct dwc3_glue_ops {
 	void	(*pre_run_stop)(struct dwc3 *dwc, bool is_on);
 };
 
+struct dwc3;
+
+/**
+ * struct dwc3_phy_nb - wrapper for PHY notifier block
+ * @nb: notifier block
+ * @dwc: back-pointer to the DWC3 controller
+ * @port_index: USB3 port index this notifier is registered for
+ */
+struct dwc3_phy_nb {
+	struct notifier_block	nb;
+	struct dwc3		*dwc;
+	u8			port_index;
+};
+
 /**
  * struct dwc3 - representation of our controller
  * @drd_work: workqueue used for role swapping
@@ -1065,6 +1080,7 @@ struct dwc3_glue_ops {
  * @usb3_phy: pointer to USB3 PHY
  * @usb2_generic_phy: pointer to array of USB2 PHYs
  * @usb3_generic_phy: pointer to array of USB3 PHYs
+ * @usb3_phy_nb: notifier blocks for USB3 PHY reset events
  * @num_usb2_ports: number of USB2 ports
  * @num_usb3_ports: number of USB3 ports
  * @phys_ready: flag to indicate that PHYs are ready
@@ -1229,6 +1245,8 @@ struct dwc3 {
 
 	struct phy		*usb2_generic_phy[DWC3_USB2_MAX_PORTS];
 	struct phy		*usb3_generic_phy[DWC3_USB3_MAX_PORTS];
+	struct dwc3_phy_nb	usb3_phy_nb[DWC3_USB3_MAX_PORTS];
+	atomic_t		phy_reset_count;
 
 	u8			num_usb2_ports;
 	u8			num_usb3_ports;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 31/36] phy: rockchip: usbdp: Add phy reset notification support
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (29 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 30/36] usb: dwc3: core: support PHY reset notifications Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 21:26   ` sashiko-bot
  2026-07-10 16:45 ` [PATCH v12 32/36] phy: rockchip: usbdp: Drop -EPROBE_DEFER hack Sebastian Reichel
                   ` (4 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

To resolve issues with running into permanent "cmn ana lcpll lock
timeout" errors after a few device replugs, add support for reset
notifications, which will be handled by the DWC3 driver to gracefully
handle the PHY being disabled. This avoids corrupting the controller's
internal state and the PIPE interface between the USB3 controller and
the PHY, thus fixing the issue.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index af915cc37727..0333e846ce34 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1005,24 +1005,39 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 	}
 
 	if (udphy->status == UDPHY_MODE_NONE) {
+		phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_PRE_RESET);
+
+		rk_udphy_u3_port_disable(udphy, true);
+		udelay(10);
+
 		ret = rk_udphy_setup(udphy);
-		if (ret)
+		if (ret) {
+			phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_POST_RESET);
 			return ret;
+		}
 
 		if (!udphy->hs && udphy->mode & UDPHY_MODE_USB)
 			rk_udphy_u3_port_disable(udphy, false);
 		udphy->phy_needs_reinit = false;
+
+		phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_POST_RESET);
 	} else if (udphy->phy_needs_reinit) {
+		phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_PRE_RESET);
+
 		rk_udphy_u3_port_disable(udphy, true);
 		udelay(10);
 
 		ret = rk_udphy_init(udphy);
-		if (ret)
+		if (ret) {
+			phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_POST_RESET);
 			return ret;
+		}
 
 		if (udphy->mode & UDPHY_MODE_USB)
 			rk_udphy_u3_port_disable(udphy, false);
 		udphy->phy_needs_reinit = false;
+
+		phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_POST_RESET);
 	}
 
 	udphy->status |= mode;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 32/36] phy: rockchip: usbdp: Drop -EPROBE_DEFER hack
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (30 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 31/36] phy: rockchip: usbdp: Add phy reset notification support Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 21:28   ` sashiko-bot
  2026-07-10 16:45 ` [PATCH v12 33/36] phy: rockchip: usbdp: Rename mode to hw_mode Sebastian Reichel
                   ` (3 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

The hack to return -EPROBE_DEFER when the lcpll lock timeouts is no
longer needed. The driver now does a reset during its probe routine
marking everything as off and later on does a re-init, which avoids
the problem.

Apart from that rk_udphy_status_check() is called after the probe,
so it should not return -EPROBE_DEFER.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 0333e846ce34..cf173276bfc0 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -750,17 +750,7 @@ static int rk_udphy_status_check(struct rk_udphy *udphy)
 					       (val & CMN_ANA_LCPLL_LOCK_DONE), 200, 100000);
 		if (ret) {
 			dev_err(udphy->dev, "cmn ana lcpll lock timeout\n");
-			/*
-			 * If earlier software (U-Boot) enabled USB once already
-			 * the PLL may have problems locking on the first try.
-			 * It will be successful on the second try, so for the
-			 * time being a -EPROBE_DEFER will solve the issue.
-			 *
-			 * This requires further investigation to understand the
-			 * root cause, especially considering that the driver is
-			 * asserting all reset lines at probe time.
-			 */
-			return -EPROBE_DEFER;
+			return ret;
 		}
 
 		if (!udphy->flip) {

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 33/36] phy: rockchip: usbdp: Rename mode to hw_mode
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (31 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 32/36] phy: rockchip: usbdp: Drop -EPROBE_DEFER hack Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 21:23   ` sashiko-bot
  2026-07-10 16:45 ` [PATCH v12 34/36] phy: rockchip: usbdp: Fix power state handling Sebastian Reichel
                   ` (2 subsequent siblings)
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Rename mode field to hw_mode to make clear that this is the modes
currently supported by the hardware, but not necessarily requested
by software. I.e. it is only set by either the USB-C state machine
or device-tree if the PHY is used in a fixed routing setup.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 46 +++++++++++++++----------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index cf173276bfc0..7bce642f1e96 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -174,7 +174,7 @@ struct rk_udphy {
 	/* PHY status management */
 	bool flip;
 	bool phy_needs_reinit;
-	u8 mode;
+	u8 hw_mode; /* modes currently supported by hardware */
 	u8 status;
 
 	/* utilized for USB */
@@ -579,18 +579,18 @@ static void rk_udphy_dp_lane_enable(struct rk_udphy *udphy, int dp_lanes)
 				   CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0));
 }
 
-static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 mode)
+static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 hw_mode)
 {
-	if (udphy->mode == mode)
+	if (udphy->hw_mode == hw_mode)
 		return;
 
 	udphy->phy_needs_reinit = true;
-	udphy->mode = mode;
+	udphy->hw_mode = hw_mode;
 }
 
 static void rk_udphy_set_typec_state(struct rk_udphy *udphy, unsigned long state)
 {
-	u8 mode;
+	u8 hw_mode;
 
 	switch (state) {
 	case TYPEC_DP_STATE_C:
@@ -599,7 +599,7 @@ static void rk_udphy_set_typec_state(struct rk_udphy *udphy, unsigned long state
 		udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
 		udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
 		udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
-		mode = UDPHY_MODE_DP;
+		hw_mode = UDPHY_MODE_DP;
 		udphy->dp_lanes = 4;
 		break;
 
@@ -616,12 +616,12 @@ static void rk_udphy_set_typec_state(struct rk_udphy *udphy, unsigned long state
 			udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
 			udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
 		}
-		mode = UDPHY_MODE_DP_USB;
+		hw_mode = UDPHY_MODE_DP_USB;
 		udphy->dp_lanes = 2;
 		break;
 	}
 
-	rk_udphy_mode_set(udphy, mode);
+	rk_udphy_mode_set(udphy, hw_mode);
 }
 
 static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
@@ -744,7 +744,7 @@ static int rk_udphy_status_check(struct rk_udphy *udphy)
 	int ret;
 
 	/* LCPLL check */
-	if (udphy->mode & UDPHY_MODE_USB) {
+	if (udphy->hw_mode & UDPHY_MODE_USB) {
 		ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_LCPLL_DONE_OFFSET,
 					       val, (val & CMN_ANA_LCPLL_AFC_DONE) &&
 					       (val & CMN_ANA_LCPLL_LOCK_DONE), 200, 100000);
@@ -779,15 +779,15 @@ static int rk_udphy_init(struct rk_udphy *udphy)
 	int ret;
 
 	dev_dbg(udphy->dev, "reinit PHY with USB3=%s and DP=%s (%u lanes) flipped=%s\n",
-		str_on_off(udphy->mode & UDPHY_MODE_USB),
-		str_on_off(udphy->mode & UDPHY_MODE_DP),
+		str_on_off(udphy->hw_mode & UDPHY_MODE_USB),
+		str_on_off(udphy->hw_mode & UDPHY_MODE_DP),
 		udphy->dp_lanes, str_yes_no(udphy->flip));
 
 	rk_udphy_reset_assert_all(udphy);
 	usleep_range(10000, 11000);
 
 	/* enable rx lfps for usb */
-	if (udphy->mode & UDPHY_MODE_USB)
+	if (udphy->hw_mode & UDPHY_MODE_USB)
 		rk_udphy_grfreg_write(udphy->udphygrf, &cfg->grfcfg.rx_lfps, true);
 
 	/* Step 1: power on pma and deassert apb rstn */
@@ -824,13 +824,13 @@ static int rk_udphy_init(struct rk_udphy *udphy)
 			   FIELD_PREP(CMN_DP_LANE_EN_ALL, 0));
 
 	/* Step 4: deassert init rstn and wait for 200ns from datasheet */
-	if (udphy->mode & UDPHY_MODE_USB) {
+	if (udphy->hw_mode & UDPHY_MODE_USB) {
 		ret = rk_udphy_reset_deassert(udphy, "init");
 		if (ret)
 			goto assert_resets;
 	}
 
-	if (udphy->mode & UDPHY_MODE_DP) {
+	if (udphy->hw_mode & UDPHY_MODE_DP) {
 		regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET,
 				   CMN_DP_INIT_RSTN,
 				   FIELD_PREP(CMN_DP_INIT_RSTN, 0x1));
@@ -839,7 +839,7 @@ static int rk_udphy_init(struct rk_udphy *udphy)
 	udelay(1);
 
 	/*  Step 5: deassert cmn/lane rstn */
-	if (udphy->mode & UDPHY_MODE_USB) {
+	if (udphy->hw_mode & UDPHY_MODE_USB) {
 		ret = rk_udphy_reset_deassert(udphy, "cmn");
 		if (ret)
 			goto assert_resets;
@@ -898,7 +898,7 @@ static int rk_udphy_parse_lane_mux_data(struct rk_udphy *udphy)
 	num_lanes = device_property_count_u32(udphy->dev, "rockchip,dp-lane-mux");
 	if (num_lanes < 0) {
 		dev_dbg(udphy->dev, "no dp-lane-mux, following dp alt mode\n");
-		udphy->mode = UDPHY_MODE_USB;
+		udphy->hw_mode = UDPHY_MODE_USB;
 		return 0;
 	}
 
@@ -927,10 +927,10 @@ static int rk_udphy_parse_lane_mux_data(struct rk_udphy *udphy)
 		}
 	}
 
-	udphy->mode = UDPHY_MODE_DP;
+	udphy->hw_mode = UDPHY_MODE_DP;
 	udphy->dp_lanes = num_lanes;
 	if (num_lanes == 1 || num_lanes == 2) {
-		udphy->mode |= UDPHY_MODE_USB;
+		udphy->hw_mode |= UDPHY_MODE_USB;
 		udphy->flip = (udphy->lane_mux_sel[0] == PHY_LANE_MUX_DP) ||
 			      (udphy->lane_mux_sel[1] == PHY_LANE_MUX_DP);
 	}
@@ -989,7 +989,7 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 {
 	int ret;
 
-	if (!(udphy->mode & mode)) {
+	if (!(udphy->hw_mode & mode)) {
 		dev_info(udphy->dev, "mode 0x%02x is not support\n", mode);
 		return 0;
 	}
@@ -1006,7 +1006,7 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 			return ret;
 		}
 
-		if (!udphy->hs && udphy->mode & UDPHY_MODE_USB)
+		if (!udphy->hs && udphy->hw_mode & UDPHY_MODE_USB)
 			rk_udphy_u3_port_disable(udphy, false);
 		udphy->phy_needs_reinit = false;
 
@@ -1037,7 +1037,7 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 
 static void rk_udphy_power_off(struct rk_udphy *udphy, u8 mode)
 {
-	if (!(udphy->mode & mode)) {
+	if (!(udphy->hw_mode & mode)) {
 		dev_info(udphy->dev, "mode 0x%02x is not support\n", mode);
 		return;
 	}
@@ -1296,7 +1296,7 @@ static int rk_udphy_usb3_phy_init(struct phy *phy)
 	guard(mutex)(&udphy->mutex);
 
 	/* DP only or high-speed, disable U3 port */
-	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) {
+	if (!(udphy->hw_mode & UDPHY_MODE_USB) || udphy->hs) {
 		rk_udphy_u3_port_disable(udphy, true);
 		return 0;
 	}
@@ -1311,7 +1311,7 @@ static int rk_udphy_usb3_phy_exit(struct phy *phy)
 	guard(mutex)(&udphy->mutex);
 
 	/* DP only or high-speed */
-	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) {
+	if (!(udphy->hw_mode & UDPHY_MODE_USB) || udphy->hs) {
 		udphy->status &= ~UDPHY_MODE_USB;
 		return 0;
 	}

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 34/36] phy: rockchip: usbdp: Fix power state handling
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (32 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 33/36] phy: rockchip: usbdp: Rename mode to hw_mode Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 16:45 ` [PATCH v12 35/36] phy: rockchip: usbdp: Re-init PHY on mux change Sebastian Reichel
  2026-07-10 16:45 ` [PATCH v12 36/36] phy: rockchip: usbdp: Add USB-C state without DP enabled Sebastian Reichel
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Restructure power state handling by introducing sw_mode in addition
to the hw_mode field, so that the PHY knows about the currently
supported modes from the hardware perspective, the current modes
requested by software and the actual hardware status.

Now anything updating either the hardware or software state can simply
update the status field and call rk_udphy_update_power_state().

This makes it a lot more obvious what is going on and also fixes a few
potential resource leaks identified by Sashiko as a side-effect. For
example if USB3 is requested by software while the USB-C is in DP-only
mode, things are decently handled after this.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 142 ++++++++++++++++++------------
 1 file changed, 84 insertions(+), 58 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 7bce642f1e96..c5ad300620a6 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -173,9 +173,10 @@ struct rk_udphy {
 
 	/* PHY status management */
 	bool flip;
-	bool phy_needs_reinit;
+	bool phy_needs_reinit; /* lane mux changed */
 	u8 hw_mode; /* modes currently supported by hardware */
-	u8 status;
+	u8 sw_mode; /* modes currently requested */
+	u8 status; /* current PHY power state */
 
 	/* utilized for USB */
 	bool hs; /* flag for high-speed */
@@ -985,70 +986,86 @@ static int rk_udphy_parse_dt(struct rk_udphy *udphy)
 	return rk_udphy_reset_init(udphy, dev);
 }
 
-static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
+static int rk_udphy_update_power_state(struct rk_udphy *udphy)
 {
+	u8 target_mode;
 	int ret;
 
-	if (!(udphy->hw_mode & mode)) {
-		dev_info(udphy->dev, "mode 0x%02x is not support\n", mode);
+	/*
+	 * Initialize PHY mode according to the hardware setup (either described
+	 * in DT or negotiated via the Type-C controller) instead of requesting
+	 * only the needed PHY side, because that would break the USB/DP data
+	 * streams when the other PHY is being requested. This is not an issue
+	 * during the Type-C negotiation as that happens during the hotplug phase
+	 * and not during normal operation. Also disable everything if the
+	 * software has not requested anything, as there shouldn't be any active
+	 * data streams in that case.
+	 */
+	target_mode = udphy->hw_mode;
+	if (udphy->sw_mode == UDPHY_MODE_NONE)
+		target_mode = UDPHY_MODE_NONE;
+
+	if (!udphy->phy_needs_reinit && udphy->status == target_mode)
 		return 0;
-	}
 
-	if (udphy->status == UDPHY_MODE_NONE) {
-		phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_PRE_RESET);
+	/* Avoid to re-init disabled PHY */
+	if (udphy->status == target_mode && target_mode == UDPHY_MODE_NONE)
+		return 0;
 
-		rk_udphy_u3_port_disable(udphy, true);
-		udelay(10);
+	/*
+	 * Inform DWC3 driver, that we are about to reset the PHY, so that it can
+	 * assert its PIPE reset lines and avoid DWC3 getting into a buggy state.
+	 * This is intentionally done for a PHY disable, since that also changes
+	 * the clocks routed to the PHY.
+	 */
+	ret = phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_PRE_RESET);
+	if (ret)
+		return ret;
+
+	/*
+	 * Disable USB3 port, which among other things re-routes a DWC3 clock to
+	 * avoid SErrors when the DWC3 registers are accessed while the PHY is
+	 * disabled.
+	 */
+	rk_udphy_u3_port_disable(udphy, true);
+	udelay(10);
 
+	if (udphy->status == UDPHY_MODE_NONE) {
+		/* Power up (incl. clocks) */
 		ret = rk_udphy_setup(udphy);
 		if (ret) {
 			phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_POST_RESET);
 			return ret;
 		}
-
-		if (!udphy->hs && udphy->hw_mode & UDPHY_MODE_USB)
-			rk_udphy_u3_port_disable(udphy, false);
-		udphy->phy_needs_reinit = false;
-
-		phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_POST_RESET);
-	} else if (udphy->phy_needs_reinit) {
-		phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_PRE_RESET);
-
-		rk_udphy_u3_port_disable(udphy, true);
-		udelay(10);
-
+	} else if (target_mode == UDPHY_MODE_NONE) {
+		/* Power down (incl. clocks) */
+		rk_udphy_disable(udphy);
+	} else {
+		/* Mode change => re-init */
 		ret = rk_udphy_init(udphy);
 		if (ret) {
 			phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_POST_RESET);
 			return ret;
 		}
-
-		if (udphy->mode & UDPHY_MODE_USB)
-			rk_udphy_u3_port_disable(udphy, false);
-		udphy->phy_needs_reinit = false;
-
-		phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_POST_RESET);
 	}
 
-	udphy->status |= mode;
-
-	return 0;
-}
-
-static void rk_udphy_power_off(struct rk_udphy *udphy, u8 mode)
-{
-	if (!(udphy->hw_mode & mode)) {
-		dev_info(udphy->dev, "mode 0x%02x is not support\n", mode);
-		return;
-	}
+	/* Ensure USB3 support is enabled when supported */
+	if (!udphy->hs && target_mode & UDPHY_MODE_USB)
+		rk_udphy_u3_port_disable(udphy, false);
 
-	if (!udphy->status)
-		return;
+	/*
+	 * Inform DWC3, that we are done with the reset, so that it can deassert
+	 * its PIPE reset line. This is sent in pair with a PRE_RESET allowing
+	 * consumer driver to do paired resource requests (e.g. clocks) in their
+	 * notification handlers. As we reroute the clocks, its also fine to
+	 * send this after completely disabling the PHY.
+	 */
+	phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_POST_RESET);
 
-	udphy->status &= ~mode;
+	udphy->status = target_mode;
+	udphy->phy_needs_reinit = false;
 
-	if (udphy->status == UDPHY_MODE_NONE)
-		rk_udphy_disable(udphy);
+	return 0;
 }
 
 static int rk_udphy_dp_phy_power_on(struct phy *phy)
@@ -1057,11 +1074,15 @@ static int rk_udphy_dp_phy_power_on(struct phy *phy)
 	int ret;
 
 	scoped_guard(mutex, &udphy->mutex) {
+		udphy->sw_mode |= UDPHY_MODE_DP;
+
 		phy_set_bus_width(phy, udphy->dp_lanes);
 
-		ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP);
-		if (ret)
+		ret = rk_udphy_update_power_state(udphy);
+		if (ret) {
+			udphy->sw_mode &= ~UDPHY_MODE_DP;
 			return ret;
+		}
 
 		rk_udphy_dp_lane_enable(udphy, udphy->dp_lanes);
 
@@ -1084,10 +1105,10 @@ static int rk_udphy_dp_phy_power_off(struct phy *phy)
 
 	guard(mutex)(&udphy->mutex);
 
-	rk_udphy_dp_lane_enable(udphy, 0);
-	rk_udphy_power_off(udphy, UDPHY_MODE_DP);
+	udphy->sw_mode &= ~UDPHY_MODE_DP;
 
-	return 0;
+	rk_udphy_dp_lane_enable(udphy, 0);
+	return rk_udphy_update_power_state(udphy);
 }
 
 /*
@@ -1292,16 +1313,24 @@ static const struct phy_ops rk_udphy_dp_phy_ops = {
 static int rk_udphy_usb3_phy_init(struct phy *phy)
 {
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
+	int ret;
 
 	guard(mutex)(&udphy->mutex);
 
-	/* DP only or high-speed, disable U3 port */
-	if (!(udphy->hw_mode & UDPHY_MODE_USB) || udphy->hs) {
+	if (udphy->hs) {
 		rk_udphy_u3_port_disable(udphy, true);
 		return 0;
 	}
 
-	return rk_udphy_power_on(udphy, UDPHY_MODE_USB);
+	udphy->sw_mode |= UDPHY_MODE_USB;
+
+	ret = rk_udphy_update_power_state(udphy);
+	if (ret) {
+		udphy->sw_mode &= ~UDPHY_MODE_USB;
+		return ret;
+	}
+
+	return 0;
 }
 
 static int rk_udphy_usb3_phy_exit(struct phy *phy)
@@ -1310,15 +1339,12 @@ static int rk_udphy_usb3_phy_exit(struct phy *phy)
 
 	guard(mutex)(&udphy->mutex);
 
-	/* DP only or high-speed */
-	if (!(udphy->hw_mode & UDPHY_MODE_USB) || udphy->hs) {
-		udphy->status &= ~UDPHY_MODE_USB;
+	if (udphy->hs)
 		return 0;
-	}
 
-	rk_udphy_power_off(udphy, UDPHY_MODE_USB);
+	udphy->sw_mode &= ~UDPHY_MODE_USB;
 
-	return 0;
+	return rk_udphy_update_power_state(udphy);
 }
 
 static const struct phy_ops rk_udphy_usb3_phy_ops = {

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 35/36] phy: rockchip: usbdp: Re-init PHY on mux change
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (33 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 34/36] phy: rockchip: usbdp: Fix power state handling Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  2026-07-10 21:27   ` sashiko-bot
  2026-07-10 16:45 ` [PATCH v12 36/36] phy: rockchip: usbdp: Add USB-C state without DP enabled Sebastian Reichel
  35 siblings, 1 reply; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

Ensure that the right part of the PHY are powered up when the
mode changes. This ensures the PHY is re-initialized in the
following two scenarios, which are currently broken:

 - cable orientation changes without DP being involved
 - switching from DP-only into a mode with USB support

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index c5ad300620a6..ecf0ed0139f6 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1383,7 +1383,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 
 	rk_udphy_set_typec_state(udphy, state->mode);
 
-	return 0;
+	return rk_udphy_update_power_state(udphy);
 }
 
 static void rk_udphy_typec_mux_unregister(void *data)

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v12 36/36] phy: rockchip: usbdp: Add USB-C state without DP enabled
  2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
                   ` (34 preceding siblings ...)
  2026-07-10 16:45 ` [PATCH v12 35/36] phy: rockchip: usbdp: Re-init PHY on mux change Sebastian Reichel
@ 2026-07-10 16:45 ` Sebastian Reichel
  35 siblings, 0 replies; 57+ messages in thread
From: Sebastian Reichel @ 2026-07-10 16:45 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Heiko Stuebner, Frank Wang,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thinh Nguyen,
	Greg Kroah-Hartman, Philipp Zabel
  Cc: Andy Yan, Dmitry Baryshkov, Yubing Zhang, Alexey Charkov,
	linux-phy, linux-arm-kernel, linux-rockchip, linux-kernel, kernel,
	devicetree, linux-usb, Sebastian Reichel

The driver currently only differs between 4 lanes DP mode or combined DP
+ USB3 mode. This makes sense from a lane routing point of view, as the
hardware only has 2 lanes of USB3.

But adding a separate state for USB-only helps with power management,
since we always power up all PHY parts according to the current hardware
setup to avoid data stream interruptions. Even if some lanes are muxed
to the DP controller there is no need to keep the DP side enabled if
something without DP AltMode is plugged into USB-C.

This potentially triggers some more USB reconnections during the PD
AltMode negotiation when switching from USB-only to combined USB+DP
mode. This should be fine, as the cable is freshly plugged at this
point.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 57 ++++++++++++++++++-------------
 1 file changed, 33 insertions(+), 24 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index ecf0ed0139f6..bca096abb076 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -580,32 +580,14 @@ static void rk_udphy_dp_lane_enable(struct rk_udphy *udphy, int dp_lanes)
 				   CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0));
 }
 
-static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 hw_mode)
+static void rk_udphy_set_lane_mux(struct rk_udphy *udphy)
 {
-	if (udphy->hw_mode == hw_mode)
-		return;
-
-	udphy->phy_needs_reinit = true;
-	udphy->hw_mode = hw_mode;
-}
-
-static void rk_udphy_set_typec_state(struct rk_udphy *udphy, unsigned long state)
-{
-	u8 hw_mode;
-
-	switch (state) {
-	case TYPEC_DP_STATE_C:
-	case TYPEC_DP_STATE_E:
+	if (udphy->dp_lanes == 4) {
 		udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
 		udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
 		udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
 		udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
-		hw_mode = UDPHY_MODE_DP;
-		udphy->dp_lanes = 4;
-		break;
-
-	case TYPEC_DP_STATE_D:
-	default:
+	} else {
 		if (udphy->flip) {
 			udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
 			udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
@@ -617,12 +599,39 @@ static void rk_udphy_set_typec_state(struct rk_udphy *udphy, unsigned long state
 			udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
 			udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
 		}
-		hw_mode = UDPHY_MODE_DP_USB;
-		udphy->dp_lanes = 2;
+	}
+}
+
+static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 hw_mode, u8 dp_lanes)
+{
+	if (udphy->hw_mode == hw_mode && udphy->dp_lanes == dp_lanes)
+		return;
+
+	udphy->phy_needs_reinit = true;
+	udphy->hw_mode = hw_mode;
+	udphy->dp_lanes = dp_lanes;
+}
+
+static void rk_udphy_set_typec_state(struct rk_udphy *udphy, unsigned long state)
+{
+	switch (state) {
+	case TYPEC_DP_STATE_C:
+	case TYPEC_DP_STATE_E:
+		rk_udphy_mode_set(udphy, UDPHY_MODE_DP, 4);
+		break;
+
+	case TYPEC_DP_STATE_D:
+		rk_udphy_mode_set(udphy, UDPHY_MODE_DP_USB, 2);
+		break;
+
+	case TYPEC_STATE_SAFE:
+	case TYPEC_STATE_USB:
+	default:
+		rk_udphy_mode_set(udphy, UDPHY_MODE_USB, 0);
 		break;
 	}
 
-	rk_udphy_mode_set(udphy, hw_mode);
+	rk_udphy_set_lane_mux(udphy);
 }
 
 static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 03/36] phy: rockchip: usbdp: Do not lose USB3 PHY status
  2026-07-10 16:44 ` [PATCH v12 03/36] phy: rockchip: usbdp: Do not lose USB3 PHY status Sebastian Reichel
@ 2026-07-10 21:07   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:07 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: linux-phy, olteanv, devicetree, conor+dt, robh, vkoul,
	neil.armstrong

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

New issues:
- [High] Removing the clearance of `udphy->status` introduces unbalanced clock disables and repeated hardware teardowns on the `rk_udphy_setup()` error path.

Pre-existing issues:
- [High] Missing mutex acquisition in `rk_udphy_dp_phy_configure` leads to data races on shared driver state.
- [High] Incomplete handling of mode transitions causes DWC3 SErrors and permanently breaks the USB3 data stream.
--

--- Patch [3]: [PATCH v12 03/36] phy: rockchip: usbdp: Do not lose USB3 PHY status ---
commit efe9bcb0d6328640e43461f982816e45f55f9a36
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Do not lose USB3 PHY status

By default (i.e. without manually enabling runtime PM) DWC3 requests the
USB3 PHY once and keeps it enabled all the time. When DisplayPort is
being requested later on, a mode change is needed. This re-initializes
the PHY. During re-initialization the status variable has incorrectly
been cleared, which means the tracking information for USB3 is lost.

This is not an immediate problem, since the DP side keeps the PHY
enabled. But once DP is toggled off, the whole PHY will be disabled.
This is a problem, because the USB side still needs it powered.

Fix things by not clearing the status flags.

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index a5ffdf7a6e76b..12dfdd470a782 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -1008,7 +1008,6 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
>  			rk_udphy_u3_port_disable(udphy, false);
>  		udphy->mode_change = false;
>  	} else if (udphy->mode_change) {

[Severity: High]
This is a pre-existing issue, but I have a question about how the mode
transitions are handled here in rk_udphy_power_on().

When Type-C negotiation changes the mode to UDPHY_MODE_DP_USB, the driver
skips calling rk_udphy_u3_port_disable(udphy, true). It then cuts the PHY
clocks via rk_udphy_disable() while the DWC3 controller might still be
active. Can this cause System Errors (SErrors) from the DWC3 controller?

Additionally, if the old mode was UDPHY_MODE_DP, the USB3 port is disabled
but never re-enabled after rk_udphy_setup() succeeds. Does this leave the
USB3 data stream permanently broken in the GRF registers?

> -		udphy->status = UDPHY_MODE_NONE;
>  		if (udphy->mode == UDPHY_MODE_DP)
>  			rk_udphy_u3_port_disable(udphy, true);
>  
>  		rk_udphy_disable(udphy);
>  		ret = rk_udphy_setup(udphy);
>  		if (ret)
>  			return ret;

[Severity: High]
Since this clearance is removed, what happens if rk_udphy_setup() fails
immediately after this block?

If rk_udphy_setup() returns an error, the function exits without updating
udphy->status to reflect that the hardware was actually disabled by
rk_udphy_disable() just above.

Could this lead to unbalanced clock disables and repeated resets later when
phy_power_off() or phy_power_on() is called, since the driver still assumes
the PHY is active?

[ ... ]

[Severity: High]
This is a pre-existing issue, but does rk_udphy_dp_phy_configure() need to
hold udphy->mutex when accessing shared driver state?

Looking at drivers/phy/rockchip/phy-rockchip-usbdp.c:

rk_udphy_dp_phy_configure() {
	struct rk_udphy *udphy = phy_get_drvdata(phy);
	...
	if (dp->set_voltages) {
		for (i = 0; i < udphy->lanes; i++) {
			lane = udphy->dp_lane_sel[i];
...

This function reads udphy->dp_lane_sel, udphy->lanes, and
udphy->lane_mux_sel without acquiring the mutex.

Meanwhile, if a Type-C orientation flip occurs, rk_udphy_orien_sw_set()
acquires the mutex and mutates this exact state:

rk_udphy_orien_sw_set() {
	...
	mutex_lock(&udphy->mutex);
	...
	udphy->flip = orien == TYPEC_ORIENTATION_REVERSE;
	rk_udphy_set_typec_default_mapping(udphy);
...

Can this data race cause voltages to be programmed to the wrong PHY lanes,
leading to DP link training failures if a cable is flipped during active
DisplayPort use?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=3

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 05/36] phy: rockchip: usbdp: Handle missing clock-names DT property gracefully
  2026-07-10 16:44 ` [PATCH v12 05/36] phy: rockchip: usbdp: Handle missing clock-names DT property gracefully Sebastian Reichel
@ 2026-07-10 21:07   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:07 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: devicetree, linux-phy, conor+dt, robh, vkoul, neil.armstrong,
	olteanv

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing NULL check for clock IDs when iterating over clocks, leading to a NULL pointer dereference with non-compliant device trees.
- [Medium] Resource leak of clock enable counts on probe error paths and upon driver unbinding due to missing `.remove` callback.
--

--- Patch [5]: [PATCH v12 05/36] phy: rockchip: usbdp: Handle missing clock-names DT property gracefully ---
commit a11924d81c315e2223d2b7de676184666d98b48a
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Handle missing clock-names DT property gracefully

This commit fixes a NULL pointer dereference in rk_udphy_clk_init() by
ensuring the clock ID is not NULL before calling strncmp(). This gracefully
handles cases where the device tree specifies 'clocks' but misses the required
'clock-names' property.

Closes: https://sashiko.dev/#/message/20260619154349.071321F000E9%40smtp.kernel.org

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index 2845a012eafcc..3fc8222fcaec2 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -432,6 +432,9 @@ static int rk_udphy_clk_init(struct rk_udphy *udphy, struct device *dev)
>  
>  	/* used for configure phy reference clock frequency */
>  	for (i = 0; i < udphy->num_clks; i++) {
> +		if (!udphy->clks[i].id)
> +			continue;
> +

[Severity: High]
This is a pre-existing issue, but does the same NULL pointer dereference
exist in other rockchip PHY drivers when 'clock-names' is missing?

For example, looking at rockchip_usb2phy_clk480m_register() in
phy-rockchip-inno-usb2.c:

	for (i = 0; i < rphy->num_clks; i++) {
		if (!strncmp(rphy->clks[i].id, "phyclk", 6)) {
			refclk = rphy->clks[i].clk;

And similarly in rockchip_combphy_parse_dt() in phy-rockchip-naneng-combphy.c:

	for (i = 0; i < priv->num_clks; i++) {
		if (!strncmp(priv->clks[i].id, "ref", 3)) {
			priv->refclk = priv->clks[i].clk;

Do these drivers also need similar checks before calling strncmp() to avoid
crashing with non-compliant device trees?

>  		if (!strncmp(udphy->clks[i].id, "refclk", 6)) {
>  			udphy->refclk = udphy->clks[i].clk;
>  			break;

[Severity: Medium]
This is a pre-existing issue, but does this driver leak clock enable counts
during probe failures or upon unbinding?

Looking at rk_udphy_probe(), if rk_udphy_get_initial_status() detects that
the hardware was already enabled, it leaves the clocks manually enabled.
However, if a subsequent step fails, such as the orientation-switch setup:

	if (device_property_present(dev, "orientation-switch")) {
		ret = rk_udphy_setup_orien_switch(udphy);
		if (ret)
			return ret;
	}

The error path returns directly without disabling the clocks. If this fails
with -EPROBE_DEFER, will the leaked clock enable count increment on each
retry?

Additionally, the driver appears to lack a .remove callback entirely:

static struct platform_driver rk_udphy_driver = {
	.probe		= rk_udphy_probe,
	.driver		= {
		.name	= "rockchip-usbdp-phy",

Does unbinding the driver while the PHY is active leave the clocks
permanently enabled and reset states deasserted?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=5

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 06/36] phy: rockchip: usbdp: Drop seamless DP takeover
  2026-07-10 16:44 ` [PATCH v12 06/36] phy: rockchip: usbdp: Drop seamless DP takeover Sebastian Reichel
@ 2026-07-10 21:08   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:08 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: linux-phy, devicetree, vkoul, robh, neil.armstrong, olteanv,
	conor+dt

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Missing hardware reset at probe leads to system lockups if bootloader leaves PHY active
--

--- Patch [6]: [PATCH v12 06/36] phy: rockchip: usbdp: Drop seamless DP takeover ---
commit 871e6d2aea7ac2c888b4917f93fff1eda368209d
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Drop seamless DP takeover

This patch removes support for seamless DP takeover from the bootloader,
noting that the current DRM drivers do not support it and the code is
untested. It removes the initial status check and corresponding reset logic.

Closes: https://lore.kernel.org/linux-phy/20260612164107.C7DB21F000E9@smtp.kernel.org/

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index 3fc8222fcaec2..6cb9f6b4dbf6d 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c

[ ... ]

> @@ -1495,10 +1468,6 @@ static int rk_udphy_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> -	ret = rk_udphy_get_initial_status(udphy);
> -	if (ret)
> -		return ret;
> -

[Severity: High]
Does removing this initial status check leave the PHY hardware in an unmanaged
state if the bootloader enabled it?

Without this initialization step, the driver no longer explicitly manages the
PHY resets or increments the clock enable count during probe. If a bootloader
leaves the PHY active (such as for a display splash screen or USB fastboot),
and the consumer driver is not loaded or defers probing, the clock framework's
clk_disable_unused will execute at late_initcall and cut the unclaimed PHY
clocks.

On Rockchip SoCs, cutting clocks to an un-reset, active peripheral frequently
causes an AXI bus hang or prevents the power domain from safely shutting down.
Is an explicit reset still needed in rk_udphy_probe() to ensure the hardware
is put into a quiescent state during boot?

>  	mutex_init(&udphy->mutex);
>  	platform_set_drvdata(pdev, udphy);
>

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=6

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 12/36] phy: rockchip: usbdp: Limit DP lane count to muxed lanes
  2026-07-10 16:44 ` [PATCH v12 12/36] phy: rockchip: usbdp: Limit DP lane count to muxed lanes Sebastian Reichel
@ 2026-07-10 21:08   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:08 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: robh, devicetree, neil.armstrong, conor+dt, linux-phy, olteanv,
	vkoul

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing lock / data race on shared driver state during PHY configuration
- [High] Incomplete fix: DP lane bounds check is bypassed during voltage-only configurations
--

--- Patch [12]: [PATCH v12 12/36] phy: rockchip: usbdp: Limit DP lane count to muxed lanes ---
commit f343affd6c4a3599ea8955fa27e07174fef51eb5
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Limit DP lane count to muxed lanes

This patch adds a check to ensure the DP controller does not request more
lanes than the PHY is configured to support. This protects against USB3
usage corruption.

Link: https://lore.kernel.org/linux-phy/20260612165546.98E1F1F000E9@smtp.kernel.org/

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index c4d62b234ea80..b172ce6a722ee 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -1099,6 +1099,9 @@ static int rk_udphy_dp_phy_verify_link_rate(struct rk_udphy *udphy,
>  static int rk_udphy_dp_phy_verify_lanes(struct rk_udphy *udphy,
>  					struct phy_configure_opts_dp *dp)
>  {
> +	if (dp->lanes > udphy->dp_lanes)
> +		return -EINVAL;
> +

[Severity: High]
This is a pre-existing issue, but is there a data race when accessing
udphy->dp_lanes here?

It appears this lockless read creates a TOCTOU vulnerability against
concurrent Type-C mode switches. The dw-dp driver invokes link training
concurrently with TCPM Type-C events invoking rk_udphy_typec_mux_set().

Since rk_udphy_dp_phy_configure() and rk_udphy_dp_phy_verify_lanes()
read and write shared variables without acquiring udphy->mutex (only the
generic phy->mutex is held):

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_dp_phy_configure() {
        ...
        if (dp->set_voltages) {
                for (i = 0; i < udphy->lanes; i++) {
                        lane = udphy->dp_lane_sel[i];
        ...
}

Can this lead to hardware PHY corruption if DRM and TCPM use independent
workqueues with no common lock?

[Severity: High]
This isn't a bug introduced by this patch, but does this new check fully
protect the voltage configuration path?

If the dw-dp driver splits link training and first calls phy_configure()
with set_lanes = true, it caches dp->lanes into udphy->lanes. 

If it later calls it with set_voltages = true and set_lanes = false, this
bounds check in rk_udphy_dp_phy_verify_lanes() is bypassed.

If a Type-C event reduces the available udphy->dp_lanes before the second
call, the set_voltages block iterates up to the cached udphy->lanes:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_dp_phy_configure() {
        ...
        if (dp->set_voltages) {
                for (i = 0; i < udphy->lanes; i++) {
                        lane = udphy->dp_lane_sel[i];
        ...
}

Could this override active USB3 lanes and corrupt the USB3 PHY state?

>  	switch (dp->lanes) {
>  	case 1:
>  	case 2:

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=12

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 18/36] phy: rockchip: usbdp: Rename mode_change to phy_needs_reinit
  2026-07-10 16:44 ` [PATCH v12 18/36] phy: rockchip: usbdp: Rename mode_change to phy_needs_reinit Sebastian Reichel
@ 2026-07-10 21:10   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:10 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: robh, vkoul, neil.armstrong, linux-phy, devicetree, conor+dt,
	olteanv

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Hardware hang due to unclocked memory-mapped register access.
--

--- Patch [18]: [PATCH v12 18/36] phy: rockchip: usbdp: Rename mode_change to phy_needs_reinit ---
commit 879ba283150f41ae77236ca40a0536af8b8e8236
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Rename mode_change to phy_needs_reinit

This patch renames the mode_change property to phy_needs_reinit to better
reflect that the PHY requires re-initialization not just on mode changes, but
also on cable orientation switches. This prepares the driver to handle DP
re-init properly on orientation changes.

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index 24108816e3b95..e44d19c9d1193 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
[ ... ]
> @@ -951,15 +951,15 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)

[Severity: High]
This is a pre-existing issue, but can this lead to a system hang when the PHY
is unsupported?

Looking at rk_udphy_power_on(), if the requested mode is unsupported,
it returns 0 early without enabling the clocks:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_power_on() {
	if (!(udphy->mode & mode)) {
		dev_info(udphy->dev, "mode 0x%02x is not support\n", mode);
		return 0;
	}
...
}

Because this returns 0 instead of an error code, rk_udphy_dp_phy_power_on()
assumes the PHY is clocked and proceeds to call rk_udphy_dp_lane_enable():

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_dp_phy_power_on() {
...
	ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP);
	if (ret)
		goto unlock;

	rk_udphy_dp_lane_enable(udphy, udphy->dp_lanes);
...
}

This results in accessing memory-mapped PHY registers via pma_regmap when the
corresponding PHY clocks are gated. Could this trigger a synchronous external
abort and a kernel panic?

Additionally, this same sequence appears in rk_udphy_dp_phy_power_off()
which calls rk_udphy_dp_lane_enable(udphy, 0) unconditionally without checking
if the PHY was successfully powered on:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_dp_phy_power_off() {
	mutex_lock(&udphy->mutex);
	rk_udphy_dp_lane_enable(udphy, 0);
	rk_udphy_power_off(udphy, UDPHY_MODE_DP);
...
}

Should rk_udphy_power_on() return an error like -EINVAL when the mode is not
supported, and should rk_udphy_dp_phy_power_off() avoid calling
rk_udphy_dp_lane_enable() if the PHY is not powered on?

>  
>  		if (udphy->mode & UDPHY_MODE_USB)
>  			rk_udphy_u3_port_disable(udphy, false);
> -		udphy->mode_change = false;
> -	} else if (udphy->mode_change) {
> +		udphy->phy_needs_reinit = false;
> +	} else if (udphy->phy_needs_reinit) {
>  		if (udphy->mode == UDPHY_MODE_DP)
>  			rk_udphy_u3_port_disable(udphy, true);
>  
>  		ret = rk_udphy_init(udphy);
>  		if (ret)
>  			return ret;
> -		udphy->mode_change = false;
> +		udphy->phy_needs_reinit = false;
>  	}
>  
>  	udphy->status |= mode;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=18

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 10/36] phy: rockchip: usbdp: Add missing mode_change update
  2026-07-10 16:44 ` [PATCH v12 10/36] phy: rockchip: usbdp: Add missing mode_change update Sebastian Reichel
@ 2026-07-10 21:13   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:13 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: olteanv, linux-phy, vkoul, neil.armstrong, robh, conor+dt,
	devicetree

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

Pre-existing issues:
- [High] PHY mode updates in `rk_udphy_typec_mux_set` are incorrectly gated by DP Alt Mode and HPD status, breaking USB lane restoration when exiting Alt Mode.
- [High] The USB3 port remains permanently disabled in the GRF after dynamically returning from 4-lane DP mode.
- [High] HPD events received from the Type-C TCPM before the DisplayPort controller initializes the PHY are cached but never flushed, dropping the hot-plug event.
- [High] The driver leaks the `UDPHY_MODE_USB` bit in `udphy->status` when dynamically switching from DP+USB mode to DP-only mode.
--

--- Patch [10]: [PATCH v12 10/36] phy: rockchip: usbdp: Add missing mode_change update ---
commit 1907d9e7af04f2c28df8bf00ded6a9b5a290664a
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Add missing mode_change update

rk_udphy_set_typec_default_mapping() updates the available modes,
but does not set the mode_change as required. This results in
missing re-initialization and thus non-working DisplayPort.

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index 982315535caf7..7540c897dde13 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c

[ ... ]

> @@ -1361,10 +1370,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
>  			usleep_range(750, 800);
>  			rk_udphy_dp_hpd_event_trigger(udphy, true);
>  		} else if (data->status & DP_STATUS_HPD_STATE) {
> -			if (udphy->mode != mode) {
> -				udphy->mode = mode;
> -				udphy->mode_change = true;
> -			}
> +			rk_udphy_mode_set(udphy, mode);

[Severity: High]
This is a pre-existing issue, but are PHY mode updates incorrectly gated by
DP Alt Mode and HPD status here?

When the Type-C manager tears down DP Alt Mode, it calls typec_mux_set()
with state->mode = TYPEC_STATE_SAFE and state->alt = NULL. The function
computes mode = UDPHY_MODE_DP_USB, but this rk_udphy_mode_set() call is
nested inside:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_typec_mux_set() {
    ...
    if (state->alt && state->alt->svid == USB_TYPEC_DP_SID) {
    ...
        } else if (data->status & DP_STATUS_HPD_STATE) {
            rk_udphy_mode_set(udphy, mode);
    ...
}

Does this incorrectly restrict PHY mode updates to DP Alt Mode, completely
missing state teardown paths where state->alt is NULL? This appears to break
USB lane restoration when exiting Alt Mode, causing USB to fail after
unplugging a DisplayPort adapter or exiting Alt Mode without a replug.

>  			rk_udphy_dp_hpd_event_trigger(udphy, true);
>  		} else {
>  			rk_udphy_dp_hpd_event_trigger(udphy, false);

[Severity: High]
This isn't a bug introduced by this patch, but does the USB3 port remain
permanently disabled in the GRF after dynamically returning from 4-lane DP
mode?

When dynamically switching from 4-lane DP mode back to DP+USB mode,
rk_udphy_power_on() executes the following block to reinitialize the PHY:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_power_on() {
    ...
    } else if (udphy->mode_change) {
        if (udphy->mode == UDPHY_MODE_DP)
            rk_udphy_u3_port_disable(udphy, true);

        ret = rk_udphy_init(udphy);
    ...
}

While this block correctly disables the U3 port for DP-only mode via
rk_udphy_u3_port_disable(udphy, true), it lacks the inverse
rk_udphy_u3_port_disable(udphy, false) call for restoring DP+USB mode.

Could this prevent the DWC3 controller from communicating with the USB3 PHY
when returning to DP+USB mode, resulting in non-working USB3?

[Severity: High]
This is a pre-existing issue, but are HPD events dropped if they are received
from the Type-C TCPM before the DisplayPort controller initializes the PHY?

If the TCPM fires an HPD event before the DP consumer probes and calls
rk_udphy_dp_phy_init(), rk_udphy_dp_hpd_event_trigger() caches the state in
udphy->dp_sink_hpd_cfg because udphy->dp_in_use is false.

When the DP consumer finally initializes the PHY, dp_in_use is set to true:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_dp_phy_init() {
    ...
    mutex_lock(&udphy->mutex);

    udphy->dp_in_use = true;

    mutex_unlock(&udphy->mutex);
    ...
}

However, the cached dp_sink_hpd_cfg is never written to the hardware
registers via rk_udphy_grfreg_write(). Can this drop the hot-plug event
and cause the display to remain completely undetected until the cable is
replugged?

[Severity: High]
This is a pre-existing issue, but does the driver leak the UDPHY_MODE_USB bit
in udphy->status when dynamically switching from DP+USB mode to DP-only mode?

When the type-c mux switches mode from UDPHY_MODE_DP_USB to UDPHY_MODE_DP,
udphy->mode is updated immediately. Later, when the USB subsystem processes
the disconnect and calls rk_udphy_usb3_phy_exit(), it checks the new mux mode
rather than the currently active status:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_usb3_phy_exit() {
    ...
    /* DP only or high-speed */
    if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs)
        goto unlock;

    rk_udphy_power_off(udphy, UDPHY_MODE_USB);
    ...
}

This condition evaluates to true because the mode was already changed,
skipping rk_udphy_power_off(udphy, UDPHY_MODE_USB).

Furthermore, the overarching rk_udphy_power_off() shares this identical
flawed check:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_power_off() {
    ...
    if (!(udphy->mode & mode)) {
        dev_info(udphy->dev, "mode 0x%02x is not support\n", mode);
        return;
    }
    ...
}

Could this secondary check return early if the new mode lacks the bit the
caller is legitimately trying to power off, preventing the mode bit from ever
being cleared from udphy->status? This appears to leave PHY resources
(clocks, resets) unreleased on teardown, corrupting state tracking and
leaking power.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=10

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 02/36] phy: rockchip: usbdp: Update mode_change after error handling
  2026-07-10 16:44 ` [PATCH v12 02/36] phy: rockchip: usbdp: Update mode_change after error handling Sebastian Reichel
@ 2026-07-10 21:15   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:15 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: conor+dt, olteanv, neil.armstrong, linux-phy, vkoul, robh,
	devicetree

Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:

Pre-existing issues:
- [Critical] Asynchronous PHY mode changes while USB is active cause fatal SErrors (kernel panics) because PHY clocks are disabled without notifying the active DWC3 controller.
- [High] `rk_udphy_power_on()` incorrectly drops active consumer tracking in `udphy->status` during a mode change, potentially causing the PHY to be disabled while still in use.
- [High] The U3 (USB3) port is not re-enabled when transitioning from DP-only mode to DP+USB mode, causing USB3 to remain broken.
- [High] `rk_udphy_clk_init()` shadows the error code from `devm_clk_bulk_get_all()`, breaking deferred probing.
- [High] The driver leaks clock enable counts and hardware reset states on probe error paths if the initial hardware status is active.
- [High] The `rk_udphy_dp_phy_configure` function accesses shared arrays and modifies hardware registers without acquiring `udphy->mutex`, leading to race conditions.
- [High] Non-DP Alternate Mode events corrupt the PHY lane mux configuration, silently breaking USB3 functionality.
- [High] DisplayPort HPD (Hot Plug Detect) events received before the DP PHY is initialized are permanently lost, preventing display detection.
--

--- Patch [2]: [PATCH v12 02/36] phy: rockchip: usbdp: Update mode_change after error handling ---
commit 44a3e651748d53a497e7bb21061bf3cb86d67fbd
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Update mode_change after error handling

If rk_udphy_init() or rk_udphy_setup() fails, the reinit will not be
tried again. Fix this by only updating the variable after all potential
errors have been handled.

Link: https://lore.kernel.org/linux-phy/20260612163835.8D5471F000E9@smtp.kernel.org/

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index fba35510d88ce..a5ffdf7a6e76b 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -1000,15 +1000,14 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
>  	}
>  
>  	if (udphy->status == UDPHY_MODE_NONE) {
> -		udphy->mode_change = false;
>  		ret = rk_udphy_setup(udphy);
>  		if (ret)
>  			return ret;
>  
>  		if (udphy->mode & UDPHY_MODE_USB)
>  			rk_udphy_u3_port_disable(udphy, false);
> -	} else if (udphy->mode_change) {
>  		udphy->mode_change = false;
> +	} else if (udphy->mode_change) {

[Severity: High]
This isn't a bug introduced by this patch, but does this mode change block
neglect to conditionally re-enable the U3 port for USB modes?

If the PHY is active in DP-only mode and transitions to DP+USB, this
else if (udphy->mode_change) block is taken. Unlike the initialization
block, it fails to evaluate if (udphy->mode & UDPHY_MODE_USB) and call
rk_udphy_u3_port_disable(udphy, false).

Does this cause USB 3.0 to fail to initialize when plugged into an already
active DisplayPort?

>  		udphy->status = UDPHY_MODE_NONE;

[Severity: High]
This is a pre-existing issue, but does this forcefully erase the tracking
of all currently active consumers without transferring them to the new
state?

If DP is active, udphy->status holds UDPHY_MODE_DP. When a USB device is
plugged in, rk_udphy_power_on is called for UDPHY_MODE_USB with mode_change
true. The code clears udphy->status to UDPHY_MODE_NONE here.

Does this permanently lose the previously active UDPHY_MODE_DP bit? When
USB is later unplugged, power_off clears the USB bit, dropping status to 0,
which might prematurely disable the PHY despite DP still needing it.

>  		if (udphy->mode == UDPHY_MODE_DP)
>  			rk_udphy_u3_port_disable(udphy, true);

[Severity: Critical]
This isn't a bug introduced by this patch, but does the asynchronous
disabling of PHY bulk clocks around here cause fatal SErrors?

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_power_on() {
    ...
    } else if (udphy->mode_change) {
        udphy->status = UDPHY_MODE_NONE;
        if (udphy->mode == UDPHY_MODE_DP)
            rk_udphy_u3_port_disable(udphy, true);
        rk_udphy_disable(udphy);
    ...
}

If DWC3 is actively transferring USB data and a DisplayPort Alternate Mode
event arrives, rk_udphy_typec_mux_set triggers a mode change. The code
unconditionally calls rk_udphy_disable(udphy) which abruptly severs the
PHY clocks.

Since the DWC3 driver isn't notified, could its next register access hang
the system bus?

[ ... ]

> @@ -1017,6 +1016,7 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
>  		ret = rk_udphy_setup(udphy);
>  		if (ret)
>  			return ret;
> +		udphy->mode_change = false;
>  	}
>  
>  	udphy->status |= mode;

[Severity: High]
This is a pre-existing issue, but does setting the status bit here only
register the consumer that triggered the function call, leaving previous
consumers untracked?


There are a few other pre-existing issues in this file that might be worth
looking into:

[Severity: High]
This isn't a bug introduced by this patch, but does this logic shadow the
error code from devm_clk_bulk_get_all and break deferred probing?

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_clk_init() {
    ...
    if (udphy->num_clks < 1)
        return -ENODEV;
    ...
}

If devm_clk_bulk_get_all returns -EPROBE_DEFER when clock providers aren't
ready yet, this explicitly checks if udphy->num_clks < 1 and returns a
hardcoded -ENODEV. Will this cause the PHY driver to fail to probe
permanently if clocks are not immediately available during early boot?


[Severity: High]
This is a pre-existing issue, but does the driver leak clock enable counts
and hardware reset states on probe error paths if the initial hardware
status is active?

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_probe() {
    ...
    udphy->phy_u3 = devm_phy_create(dev, dev->of_node, &rk_udphy_usb3_phy_ops);
    if (IS_ERR(udphy->phy_u3)) {
        ret = PTR_ERR(udphy->phy_u3);
        return dev_err_probe(dev, ret, "failed to create USB3 phy\n");
    }
    ...
}

rk_udphy_get_initial_status calls clk_bulk_prepare_enable. If it detects
active DP hardware, it leaves the clocks enabled and sets udphy->status to
UDPHY_MODE_DP.

If any subsequent step in rk_udphy_probe fails, the driver returns the error
without disabling the clocks. Without a devm-action registered to clean this
up, does this clock enable refcount leak prevent the system from ever
powering down the clock?


[Severity: High]
This isn't a bug introduced by this patch, but does rk_udphy_dp_phy_configure
access shared arrays and modify hardware registers without acquiring
udphy->mutex, leading to race conditions?

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_dp_phy_configure() {
    ...
    lane = udphy->dp_lane_sel[i];
    ...
}

This reads a shared array that is actively modified by Type-C event
handlers. At the same time, Type-C orientation switch callbacks like
rk_udphy_typec_mux_set or USB initialization can modify these exact same
structures or registers.

Could this concurrent access corrupt hardware registers or result in
inconsistent lane mappings?


[Severity: High]
This is a pre-existing issue, but do non-DP Alternate Mode events corrupt
the PHY lane mux configuration and silently break USB3 functionality?

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_typec_mux_set() {
    ...
    switch (state->mode) {
    case TYPEC_DP_STATE_C:
    case TYPEC_DP_STATE_E:
        udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
    ...
}

This executes the switch block and overwrites udphy->lane_mux_sel before
verifying state->alt->svid == USB_TYPEC_DP_SID.

Because TYPEC_DP_STATE_C is defined as TYPEC_STATE_MODAL, any other
Alternate Mode that transitions into its modal state will inadvertently
match this case. Will this erroneously route all PHY lanes to DisplayPort
if a non-DP Type-C Alternate Mode device is attached?


[Severity: High]
This isn't a bug introduced by this patch, but are DisplayPort HPD events
received before the DP PHY is initialized permanently lost, preventing
display detection?

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_dp_phy_init() {
    ...
    udphy->dp_in_use = true;
    ...
}

rk_udphy_dp_hpd_event_trigger caches the HPD state in
udphy->dp_sink_hpd_cfg if udphy->dp_in_use is false. Later, when the DP
DRM driver calls rk_udphy_dp_phy_init, udphy->dp_in_use is set to true.

However, the function fails to write the cached HPD configuration out to
the hardware registers. Does this result in an attached DisplayPort monitor
not being detected by the system?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=2

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 19/36] phy: rockchip: usbdp: Re-init the PHY on orientation change
  2026-07-10 16:44 ` [PATCH v12 19/36] phy: rockchip: usbdp: Re-init the PHY on orientation change Sebastian Reichel
@ 2026-07-10 21:15   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:15 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: robh, vkoul, conor+dt, olteanv, linux-phy, neil.armstrong,
	devicetree

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Deferred hardware initialization via `phy_needs_reinit` fixes DisplayPort but leaves USB-only replugs broken if the USB PHY remains powered on.
- [Medium] The function `rk_udphy_dp_phy_configure` accesses shared states locklessly, leading to a data race with concurrent orientation switches.
--

--- Patch [19]: [PATCH v12 19/36] phy: rockchip: usbdp: Re-init the PHY on orientation change ---
commit c45d3419a6f4b9509b416ffd7965a918e7fad8e4
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Re-init the PHY on orientation change

Changing the cable orientation reconfigures the lane muxing, which requires
re-initializing the PHY. The patch introduces a flag to trigger PHY
re-initialization upon orientation change.

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index e44d19c9d1193..4b454798c4ed4 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -620,6 +620,7 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
>  				 enum typec_orientation orien)
>  {
>  	struct rk_udphy *udphy = typec_switch_get_drvdata(sw);
> +	bool flipped = orien == TYPEC_ORIENTATION_REVERSE;
>  
>  	mutex_lock(&udphy->mutex);
>  

[ ... ]

> @@ -631,7 +632,10 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
>  		goto unlock_ret;
>  	}
>  
> -	udphy->flip = orien == TYPEC_ORIENTATION_REVERSE;
> +	if (udphy->flip != flipped)
> +		udphy->phy_needs_reinit = true;

[Severity: High]
This is a pre-existing issue, but does this deferred initialization handle
USB-only replugs correctly if the USB PHY remains powered on?

When a user unplugs and replugs a Type-C cable, this sets
udphy->phy_needs_reinit = true. However, in configurations where the DWC3
controller remains active (e.g., fixed host mode) or during rapid replugs,
the USB controller doesn't restart and thus never calls phy_init() again.

Because rk_udphy_usb3_phy_ops only implements .init and has no .power_on
callback, rk_udphy_power_on() is never invoked to process the deferred
initialization flag:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_power_on() {
    ...
	} else if (udphy->phy_needs_reinit) {
		...
		ret = rk_udphy_init(udphy);
    ...
}

Will this cause the USB SuperSpeed connection to fail to train if the
cable is inserted in reverse orientation?

> +
> +	udphy->flip = flipped;
>  	rk_udphy_set_typec_default_mapping(udphy);

[Severity: Medium]
This is a pre-existing issue, but can this lead to a data race with concurrent
orientation switches?

While rk_udphy_orien_sw_set() acquires udphy->mutex and updates the shared lane
and mux selections here via rk_udphy_set_typec_default_mapping(),
rk_udphy_dp_phy_configure() iterates over and accesses the shared lane state
locklessly:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_dp_phy_configure() {
    ...
		for (i = 0; i < udphy->lanes; i++) {
			lane = udphy->dp_lane_sel[i];
    ...
						   udphy->lane_mux_sel[lane]));
    ...
}

Could this cause rk_udphy_dp_phy_configure() to read partially updated arrays
if the DP controller triggers link training concurrently with an orientation
change?

>  	rk_udphy_usb_bvalid_enable(udphy, true);
>

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=19

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 20/36] phy: rockchip: usbdp: Factor out lane_mux_sel setup
  2026-07-10 16:44 ` [PATCH v12 20/36] phy: rockchip: usbdp: Factor out lane_mux_sel setup Sebastian Reichel
@ 2026-07-10 21:16   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:16 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: olteanv, linux-phy, robh, conor+dt, vkoul, neil.armstrong,
	devicetree

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Type-C states TYPEC_STATE_SAFE and TYPEC_STATE_USB incorrectly fall through to TYPEC_DP_STATE_D configuration, leaving the PHY in UDPHY_MODE_DP_USB mode.
- [High] The `rk_udphy_dp_phy_configure()` callback accesses and modifies shared PHY state without holding the `udphy->mutex`, leading to a race condition with concurrent Type-C events.
--

--- Patch [20]: [PATCH v12 20/36] phy: rockchip: usbdp: Factor out lane_mux_sel setup ---
commit 3727c9684937e2c6c25ea6548ada704fecefa99a
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Factor out lane_mux_sel setup
    
Avoid describing the USB+DP lane_mux_sel logic twice by introducing
a helper function to reduce code duplication.

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index 4b454798c4ed4..4e54020d17551 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -582,6 +582,42 @@ static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 mode)
>  	udphy->mode = mode;
>  }
>  
> +static void rk_udphy_set_typec_state(struct rk_udphy *udphy, unsigned long state)
> +{
> +	u8 mode;
> +
> +	switch (state) {
> +	case TYPEC_DP_STATE_C:
> +	case TYPEC_DP_STATE_E:
> +		udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
> +		udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
> +		udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
> +		udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
> +		mode = UDPHY_MODE_DP;
> +		udphy->dp_lanes = 4;
> +		break;
> +
> +	case TYPEC_DP_STATE_D:
> +	default:

[Severity: High]
This is a pre-existing issue, but does this default case correctly handle
TYPEC_STATE_SAFE and TYPEC_STATE_USB?

When the Type-C subsystem exits DP AltMode or transitions to a safe state,
the mux callback rk_udphy_typec_mux_set() receives state->mode set to
TYPEC_STATE_SAFE (0).

Because rk_udphy_set_typec_state() does not explicitly handle 0, it falls
into the default case here, incorrectly setting udphy->dp_lanes = 2 and
mode = UDPHY_MODE_DP_USB.

Should TYPEC_STATE_SAFE and TYPEC_STATE_USB explicitly disable the DP lanes
instead of defaulting to DP_USB mode?

[ ... ]

[Severity: High]
This isn't a bug introduced by this patch, but is there a missing lock in
rk_udphy_dp_phy_configure() that could race with Type-C events?

Looking at rk_udphy_dp_phy_configure() in
drivers/phy/rockchip/phy-rockchip-usbdp.c:

    static int rk_udphy_dp_phy_configure(struct phy *phy,
                                         union phy_configure_opts *opts)
    {
        struct rk_udphy *udphy = phy_get_drvdata(phy);
        struct phy_configure_opts_dp *dp = &opts->dp;
        u32 i, val, lane;
        int ret;
    
        if (dp->set_rate) {

It appears to access and modify shared PHY state without holding udphy->mutex.

Concurrently, a Type-C event such as rk_udphy_typec_mux_set() running in a
workqueue modifies udphy->dp_lane_sel and udphy->dp_lanes while holding
udphy->mutex.

Could rk_udphy_dp_phy_configure() read inconsistent values and cause
out-of-bounds register writes if it gets an invalid index from dp_lane_sel?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=20

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 27/36] phy: rockchip: usbdp: Handle rk_udphy_reset_deassert errors
  2026-07-10 16:45 ` [PATCH v12 27/36] phy: rockchip: usbdp: Handle rk_udphy_reset_deassert errors Sebastian Reichel
@ 2026-07-10 21:17   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:17 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: robh, olteanv, linux-phy, devicetree, vkoul, conor+dt,
	neil.armstrong

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [Medium] If PHY re-initialization fails during a mode change, the U3 port is left permanently disabled and in reset, but the software state incorrectly remains active.
--

--- Patch [27]: [PATCH v12 27/36] phy: rockchip: usbdp: Handle rk_udphy_reset_deassert errors ---
commit 00e32198a00a3780b193e546b8f16d2218cefb74
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Handle rk_udphy_reset_deassert errors

This commit modifies the initialization sequence to handle errors returned
by reset deassertion, avoiding a theoretical SError.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/message/20260626211151.2332F1F000E9%40smtp.kernel.org

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -803,8 +803,12 @@ static int rk_udphy_init(struct rk_udphy *udphy)
>  	/* Step 1: power on pma and deassert apb rstn */
>  	rk_udphy_grfreg_write(udphy->udphygrf, &cfg->grfcfg.low_pwrn, true);
>  
> -	rk_udphy_reset_deassert(udphy, "pma_apb");
> -	rk_udphy_reset_deassert(udphy, "pcs_apb");
> +	ret = rk_udphy_reset_deassert(udphy, "pma_apb");
> +	if (ret)
> +		goto assert_resets;

[Severity: Medium]
This is a pre-existing issue, but returning an error here propagates up to
rk_udphy_power_on(). Does this leave the U3 port in a permanently disabled
state?

When USB3 is active and a new mode is enabled, rk_udphy_power_on() triggers
re-initialization. It disables the U3 port and calls rk_udphy_init(). If
rk_udphy_init() fails and returns an error here, the caller propagates it
immediately:

rk_udphy_power_on() {
        ...
        ret = rk_udphy_init(udphy);
        if (ret)
                return ret;

        if (udphy->mode & UDPHY_MODE_USB)
                rk_udphy_u3_port_disable(udphy, false);
        ...
}

If this path is taken, the U3 port is left permanently disabled and in reset,
but the software state (udphy->status) incorrectly remains active. The USB3
controller is unaware that the PHY has been forced into reset. 

Could this result in a silently dropped USB3 connection, potentially causing
I/O errors for active storage devices? 

While a previous patch in the series mitigates the SError by safely routing
the PIPE clock to UTMI, the state inconsistency and dead USB connection seem
to remain.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=27

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 23/36] phy: rockchip: usbdp: Clear USB status on PHY exit
  2026-07-10 16:45 ` [PATCH v12 23/36] phy: rockchip: usbdp: Clear USB status on PHY exit Sebastian Reichel
@ 2026-07-10 21:17   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:17 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: robh, conor+dt, olteanv, linux-phy, devicetree, vkoul,
	neil.armstrong

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [High] Clearing the USB status flag without checking if the PHY should be completely disabled leads to a clock reference and PHY power leak.

Pre-existing issues:
- [High] The `rk_udphy_dp_phy_configure` function accesses and modifies shared PHY driver state without holding the proper subsystem lock (`udphy->mutex`).
--

--- Patch [23]: [PATCH v12 23/36] phy: rockchip: usbdp: Clear USB status on PHY exit ---
commit 87780d47b4da4078adb1684ca9ebb6fc0529d86c
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Clear USB status on PHY exit
    
Ensure the USB status flag is cleared when the USB3 PHY is
exited while the system is in DP-only mode.

Closes: https://sashiko.dev/#/message/20260625-rockchip-usbdp-cleanup-v7-24-38eb3cf654fd%40collabora.com

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index 8c165bcab7968..a742bde7155be 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -1273,8 +1273,10 @@ static int rk_udphy_usb3_phy_exit(struct phy *phy)
>  	guard(mutex)(&udphy->mutex);
>  
>  	/* DP only or high-speed */
> -	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs)
> +	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) {
> +		udphy->status &= ~UDPHY_MODE_USB;
>  		return 0;
> +	}

[Severity: High]
Does this early return bypass rk_udphy_disable() if the PHY should be completely
disabled?

If the DP side is not active, udphy->status drops to UDPHY_MODE_NONE (0) here.
Because the function returns early, it bypasses rk_udphy_power_off() and fails
to call rk_udphy_disable(udphy).

Will this leave the PHY hardware permanently powered on and the clock counts
unbalanced?

The next time the PHY is powered on, status == 0 would cause another call to
rk_udphy_setup(), which calls clk_bulk_prepare_enable() again, causing a
cumulative clock reference leak.

>  
>  	rk_udphy_power_off(udphy, UDPHY_MODE_USB);

[ ... ]

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_dp_phy_configure() {
    ...
    struct rk_udphy *udphy = phy_get_drvdata(phy);
    struct phy_configure_opts_dp *dp = &opts->dp;
    u32 i, val, lane;
    int ret;

    if (dp->set_rate) {
    ...
}

[Severity: High]
This is a pre-existing issue, but does rk_udphy_dp_phy_configure() access and
modify shared PHY driver state without holding the proper subsystem lock?

The PHY core framework calls .configure which reads udphy->dp_lanes and
udphy->dp_lane_sel, and writes udphy->lanes without acquiring udphy->mutex.

Concurrently, a Type-C event handled by rk_udphy_typec_mux_set() or
rk_udphy_orien_sw_set() might alter those shared fields while holding the mutex.

Could this race condition lead to the hardware being programmed with
inconsistent lane mappings during normal Type-C hotplug and DP modesetting?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=23

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 21/36] phy: rockchip: usbdp: Properly handle TYPEC_STATE_SAFE and TYPEC_STATE_USB
  2026-07-10 16:44 ` [PATCH v12 21/36] phy: rockchip: usbdp: Properly handle TYPEC_STATE_SAFE and TYPEC_STATE_USB Sebastian Reichel
@ 2026-07-10 21:18   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:18 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: vkoul, linux-phy, robh, olteanv, devicetree, conor+dt,
	neil.armstrong

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Incomplete handling of TYPEC_STATE_USB and TYPEC_STATE_SAFE leaves the PHY stuck in DP mode, breaking USB3 recovery.
--

--- Patch [21]: [PATCH v12 21/36] phy: rockchip: usbdp: Properly handle TYPEC_STATE_SAFE and TYPEC_STATE_USB ---
commit 92ff6f90dbbc1f6a2eb9a05f21ddd0b835b0116d
Author: Sebastian Reichel <sebastian.reichel@collabora.com>
Subject: phy: rockchip: usbdp: Properly handle TYPEC_STATE_SAFE and TYPEC_STATE_USB

This commit modifies the typec mux handler to process TYPEC_STATE_SAFE
and TYPEC_STATE_USB modes. It removes the condition that ignored mux
events not involving DP AltMode to allow muxing to be updated when
exiting DP AltMode.

Closes: https://sashiko.dev/#/message/20260619155020.CC7361F000E9%40smtp.kernel.org

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index 4e54020d17551..0399cbf96e195 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -1293,17 +1293,26 @@ static const struct phy_ops rk_udphy_usb3_phy_ops = {
>  	.owner		= THIS_MODULE,
>  };
>  
> +static bool rk_udphy_is_supported_mode(struct typec_mux_state *state)
> +{
> +	/* Handle Safe State and USB State */
> +	if (state->mode < TYPEC_STATE_MODAL)
> +		return true;
> +
> +	/* Handle DP AltMode */
> +	if (state->alt && state->alt->svid == USB_TYPEC_DP_SID)
> +		return true;
> +
> +	return false;
> +}
> +
>  static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
>  				  struct typec_mux_state *state)
>  {
>  	struct rk_udphy *udphy = typec_mux_get_drvdata(mux);
>  
> -	/*
> -	 * Ignore mux events not involving DP AltMode, because
> -	 * the mode field is being reused, e.g. state->mode == 4
> -	 * could be either TYPEC_MODE_USB4 or TYPEC_DP_STATE_C.
> -	 */
> -	if (!state->alt || state->alt->svid != USB_TYPEC_DP_SID)
> +	/* Ignore mux events not involving USB or DP */
> +	if (!rk_udphy_is_supported_mode(state))
>  		return 0;
>  
>  	mutex_lock(&udphy->mutex);

[Severity: High]
This is a pre-existing issue, but since this patch explicitly aims to
fix muxing when exiting DP AltMode, is a hardware update missing here?

When exiting DP AltMode, TCPM sends a TYPEC_STATE_USB or TYPEC_STATE_SAFE
mux event. rk_udphy_typec_mux_set() updates the software state by calling
rk_udphy_set_typec_state() which sets udphy->phy_needs_reinit = true.

However, because the USB controller (DWC3) is already powered on, it
doesn't call phy_power_on() again. The DP controller calls phy_power_off()
when disabled, but rk_udphy_dp_phy_power_off() only clears the DP status
bit and doesn't re-evaluate phy_needs_reinit.

Because of this, rk_udphy_init() is never called and the hardware
CMN_LANE_MUX_AND_EN_OFFSET is never reprogrammed. Does this leave the PHY
stuck in 4-lane DP mode and break USB3 recovery?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=21

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 22/36] phy: rockchip: usbdp: Use guard functions for mutex
  2026-07-10 16:45 ` [PATCH v12 22/36] phy: rockchip: usbdp: Use guard functions for mutex Sebastian Reichel
@ 2026-07-10 21:18   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:18 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: linux-phy, neil.armstrong, robh, conor+dt, devicetree, vkoul,
	olteanv

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but `rk_udphy_dp_phy_configure` accesses shared PHY state without holding `udphy->mutex`.
--

--- Patch [22]: [PATCH v12 22/36] phy: rockchip: usbdp: Use guard functions for mutex ---
commit f4715c1e8ea1ff2794633378980dbaf55d276684
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Use guard functions for mutex

Convert the driver to use guard functions for mutex handling as
a small cleanup. There is a small functional change in the DP PHY
power up function, which no longer sleeps if the internal powerup
code returns an error.

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index 0399cbf96e195..8c165bcab7968 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c

[ ... ]

> @@ -1255,35 +1254,30 @@ static const struct phy_ops rk_udphy_dp_phy_ops = {
>  static int rk_udphy_usb3_phy_init(struct phy *phy)
>  {

[Severity: High]
This isn't a bug introduced by this patch, but rk_udphy_dp_phy_configure()
accesses shared PHY state without holding udphy->mutex.

Could this create a data race with Type-C orientation changes?

The function iterates over the udphy->dp_lane_sel array and writes to the
hardware PHY registers based on the mapped lanes:

    for (i = 0; i < udphy->lanes; i++) {
        lane = udphy->dp_lane_sel[i];
        switch (udphy->link_rate) {
        ...

Because phy_configure is called by the DRM bridge without udphy->mutex held,
and concurrent Type-C orientation switch events handled in
rk_udphy_orien_sw_set() hold udphy->mutex while modifying udphy->dp_lane_sel
and udphy->lane_mux_sel, they might run at the same time.

If a cable is flipped exactly during a display bring-up, could this cause a
torn read that applies settings to the same lane twice while omitting others,
leaving the hardware incorrectly configured and DP alt mode output broken?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=22

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 30/36] usb: dwc3: core: support PHY reset notifications
  2026-07-10 16:45 ` [PATCH v12 30/36] usb: dwc3: core: support PHY reset notifications Sebastian Reichel
@ 2026-07-10 21:20   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:20 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: devicetree, olteanv, linux-phy, vkoul, robh, neil.armstrong,
	conor+dt

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The global `phy_reset_count` atomic variable is incorrectly used to track the reset state of multiple independent USB3 ports, and is read non-atomically, leading to cross-port state corruption, TOCTOU race conditions, and unbalanced PM usage counters.
- [High] The PHY reset workaround is completely bypassed if Runtime PM is disabled in the kernel configuration or via sysfs, causing the very hardware corruption the patch intends to fix.
--

--- Patch [30]: [PATCH v12 30/36] usb: dwc3: core: support PHY reset notifications ---
commit 9e1e85d93d9ab9e98188f6d4d342fd431f334513
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

usb: dwc3: core: support PHY reset notifications

This commit handles external PHY reset notifications on Rockchip platforms
by asserting PHYSOFTRST before the PHY disables and deasserting it when the
PHY returns. This prevents the DWC3 IP from corrupting the PHY's internal
state and failing to lock PLL clocks.

> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 517aa7f1486da..4d0b4c1c73f11 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c

[ ... ]

> @@ -880,6 +881,90 @@ static int dwc3_phy_init(struct dwc3 *dwc)
>  	return ret;
>  }
>  
> +static int dwc3_usb3_phy_notify(struct notifier_block *nb,
> +				unsigned long action, void *data)
> +{
> +	struct dwc3_phy_nb *pnb = container_of(nb, struct dwc3_phy_nb, nb);
> +	struct dwc3 *dwc = pnb->dwc;
> +	int port = pnb->port_index;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	switch (action) {
> +	case PHY_NOTIFY_PRE_RESET:
> +		/*
> +		 * If already suspended, the resume path will reinit GUSB3PIPECTL
> +		 * via dwc3_core_init(). A forced resume is not possible as that
> +		 * would call phy_init() resulting in a deadlock. Due to the
> +		 * phy_init() in the resume path there is also no need to block
> +		 * async RPM resume on our side, since the PHY synchronizes it
> +		 * for us.
> +		 */
> +		if (pm_runtime_get_if_active(dwc->dev) <= 0)
> +			return NOTIFY_OK;

[Severity: High]
If CONFIG_PM is disabled, or runtime PM is disabled for this device via
sysfs, pm_runtime_get_if_active() returns -EINVAL.

Will this check treat the -EINVAL error code as suspended and bypass the
workaround completely, even though the DWC3 IP is actively running?

Also, if the check is later modified to proceed on -EINVAL, would the
POST_RESET path underflow the PM counter? pm_runtime_get_if_active()
doesn't increment the usage count when returning -EINVAL, but POST_RESET
unconditionally calls pm_runtime_put_autosuspend().

> +
> +		atomic_inc(&dwc->phy_reset_count);
> +
> +		/*
> +		 * Assert USB3 PHY soft reset within DWC3 before the external
> +		 * PHY resets. This disconnects the PIPE interface, preventing
> +		 * the DWC3 from interfering with PHY reinitialization and
> +		 * avoiding LCPLL lock failures.
> +		 */
> +		spin_lock_irqsave(&dwc->lock, flags);
> +		reg = dwc3_readl(dwc, DWC3_GUSB3PIPECTL(port));
> +		reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
> +		dwc3_writel(dwc, DWC3_GUSB3PIPECTL(port), reg);
> +		spin_unlock_irqrestore(&dwc->lock, flags);
> +		break;
> +
> +	case PHY_NOTIFY_POST_RESET:
> +		if (!atomic_read(&dwc->phy_reset_count))
> +			return NOTIFY_OK;

[Severity: High]
Can this global count cause state corruption on multi-port systems if
notifications interleave with PM state changes?

For example, if Port 0 starts a reset while suspended, it skips the PRE_RESET
workaround and doesn't increment phy_reset_count.

If the controller resumes and Port 1 starts a reset, it increments the
global phy_reset_count to 1.

When Port 0 finishes its reset and hits POST_RESET, it sees phy_reset_count
as 1. Won't it erroneously clear PHYSOFTRST for Port 0 (which was never set),
call pm_runtime_put_autosuspend() unbalanced, and decrement the count to 0?

If Port 1 then finishes its reset, won't it see phy_reset_count at 0 and
skip its cleanup, leaving Port 1 permanently stuck in PHYSOFTRST?

> +		/*
> +		 * Deassert PHY soft reset to reconnect the PIPE interface
> +		 * after PHY reinitialization.
> +		 */
> +		spin_lock_irqsave(&dwc->lock, flags);
> +		reg = dwc3_readl(dwc, DWC3_GUSB3PIPECTL(port));
> +		reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
> +		dwc3_writel(dwc, DWC3_GUSB3PIPECTL(port), reg);
> +		spin_unlock_irqrestore(&dwc->lock, flags);
> +
> +		pm_runtime_put_autosuspend(dwc->dev);
> +		atomic_dec(&dwc->phy_reset_count);
> +		break;
> +	}
> +
> +	return NOTIFY_OK;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=30

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 26/36] phy: rockchip: usbdp: Avoid xHCI SErrors
  2026-07-10 16:45 ` [PATCH v12 26/36] phy: rockchip: usbdp: Avoid xHCI SErrors Sebastian Reichel
@ 2026-07-10 21:20   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:20 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: olteanv, robh, conor+dt, linux-phy, vkoul, devicetree,
	neil.armstrong

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

New issues:
- [High] Clock and power leak in `rk_udphy_usb3_phy_exit` when Type-C mode drops USB support.
- [High] The patch unconditionally re-enables the SuperSpeed U3 port during PHY initialization and re-initialization, ignoring the high-speed restriction (`udphy->hs`).

Pre-existing issues:
- [High] When a Type-C device is unplugged, the PHY re-initialization is flagged but never executed, leaving the USB3 port physically disabled and breaking subsequent USB3 connections.
--

--- Patch [26]: [PATCH v12 26/36] phy: rockchip: usbdp: Avoid xHCI SErrors ---
commit 66857e87fceaec79fad3845d46dbfd48c9340977
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Avoid xHCI SErrors

This commit addresses an SError caused by the dwc3 driver accessing xHCI
registers while the USBDP PHY is temporarily disabled during a mode switch.
It resolves this by disabling the USB3 port prior to re-initialization, which
safely re-routes the PIPE clock to the UTMI fallback clock.

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index edee27933d890..ff768e5b43ca0 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -1000,12 +1000,15 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
>  			rk_udphy_u3_port_disable(udphy, false);
>  		udphy->phy_needs_reinit = false;
>  	} else if (udphy->phy_needs_reinit) {
> -		if (udphy->mode == UDPHY_MODE_DP)
> -			rk_udphy_u3_port_disable(udphy, true);
> +		rk_udphy_u3_port_disable(udphy, true);
> +		udelay(10);
>  
>  		ret = rk_udphy_init(udphy);
>  		if (ret)
>  			return ret;
> +
> +		if (udphy->mode & UDPHY_MODE_USB)
> +			rk_udphy_u3_port_disable(udphy, false);

[Severity: High]
Does this code unconditionally re-enable the SuperSpeed U3 port purely based on
the mode?

During rk_udphy_usb3_phy_init(), the U3 port is kept disabled if udphy->hs is
true. However, when a mode switch or DP power-on triggers a PHY
re-initialization in rk_udphy_power_on(), this new logic executes without
checking !udphy->hs.

Could this result in misconfiguring the hardware by enabling the SuperSpeed U3
port on boards that explicitly restricted the PHY to high-speed
(maximum-speed = "high-speed")?

>  		udphy->phy_needs_reinit = false;

[Severity: High]
This is a pre-existing issue, but does the phy_needs_reinit state machine get
stuck when a Type-C device is unplugged?

If a DP-only cable is unplugged after a standard USB3 cable was active,
typec_mux_set() reverts to UDPHY_MODE_DP_USB and flags
phy_needs_reinit = true. The DP framework calls rk_udphy_dp_phy_power_off(),
which clears the DP bit from udphy->status:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_dp_phy_power_off() {
    rk_udphy_dp_lane_enable(udphy, 0);
    rk_udphy_power_off(udphy, UDPHY_MODE_DP);
}

Because the USB3 controller never suspended, udphy->status remains non-zero
(set to UDPHY_MODE_USB), so the PHY isn't disabled. Crucially, no driver calls
rk_udphy_power_on() to process the pending phy_needs_reinit state.

Will this strand the active USB3 PHY in a disabled physical state, breaking
subsequent USB3 connections?

>  	}

[Severity: High]
Regarding the related commit in this series that clears USB status on PHY exit,
is there a clock and power leak in rk_udphy_usb3_phy_exit() when the Type-C
mode drops USB support?

In rk_udphy_usb3_phy_exit():

	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) {
		udphy->status &= ~UDPHY_MODE_USB;
		return 0;
	}

When the Type-C mode dynamically changes to a state without USB support (e.g.,
a DP-only cable is connected), udphy->mode becomes UDPHY_MODE_DP. If the USB
controller then suspends and calls phy_exit(), rk_udphy_usb3_phy_exit()
executes this early return.

This clears the UDPHY_MODE_USB bit from udphy->status, but misses checking if
udphy->status == UDPHY_MODE_NONE. Could this completely fail to call
rk_udphy_disable(), wasting power and potentially blocking system suspend?

Additionally, rk_udphy_power_off() inappropriately refuses to turn off active
hardware features if the negotiated Type-C udphy->mode has already shifted
away from the requested mode:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_power_off() {
	if (!(udphy->mode & mode)) {
		dev_info(udphy->dev, "mode 0x%02x is not support\n", mode);
		return;
	}
    ...
}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=26

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 33/36] phy: rockchip: usbdp: Rename mode to hw_mode
  2026-07-10 16:45 ` [PATCH v12 33/36] phy: rockchip: usbdp: Rename mode to hw_mode Sebastian Reichel
@ 2026-07-10 21:23   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:23 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: conor+dt, linux-phy, devicetree, neil.armstrong, vkoul, olteanv,
	robh

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Compilation failure due to an incomplete rename of `udphy->mode` to `udphy->hw_mode` in `rk_udphy_power_on()`.
--

--- Patch [33]: [PATCH v12 33/36] phy: rockchip: usbdp: Rename mode to hw_mode ---
commit e122bf8f901705d3a0997d20cdd65f61c58d31c9
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Rename mode to hw_mode

This commit renames the mode field in struct rk_udphy to hw_mode. It
updates references across the driver to clarify that this represents the
hardware-supported modes.

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index cf173276bfc01..7bce642f1e968 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c

[ ... ]

> @@ -1006,7 +1006,7 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
>  			return ret;
>  		}
>  
> -		if (!udphy->hs && udphy->mode & UDPHY_MODE_USB)
> +		if (!udphy->hs && udphy->hw_mode & UDPHY_MODE_USB)
>  			rk_udphy_u3_port_disable(udphy, false);
>  		udphy->phy_needs_reinit = false;
>  

[Severity: Low]
Does this code miss another rename of the mode field slightly further down in
rk_udphy_power_on()?

Looking at the else if (udphy->phy_needs_reinit) branch in the same function,
there is another reference to the old mode field:

		if (udphy->mode & UDPHY_MODE_USB)
			rk_udphy_u3_port_disable(udphy, false);

Will this cause a compilation failure since the mode field was removed from
struct rk_udphy?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=33

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 28/36] phy: rockchip: usbdp: Only enable USB3 when not in high-speed mode
  2026-07-10 16:45 ` [PATCH v12 28/36] phy: rockchip: usbdp: Only enable USB3 when not in high-speed mode Sebastian Reichel
@ 2026-07-10 21:26   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:26 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: robh, conor+dt, linux-phy, vkoul, devicetree, neil.armstrong,
	olteanv

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] rk_udphy_power_on returns 0 (success) for unsupported modes, tricking callers into accessing unclocked PHY registers
--

--- Patch [28]: [PATCH v12 28/36] phy: rockchip: usbdp: Only enable USB3 when not in high-speed mode ---
commit fac8dba407b679ba8fc75d417de958451d90f46f
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Only enable USB3 when not in high-speed mode

Ensure that USB3 mode is not accidently enabled during PHY re-init
for systems that are configured as high-speed only via DT.

Closes: https://sashiko.dev/#/message/20260626212424.C215E1F000E9%40smtp.kernel.org

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index 2099ae2e51d1c..af915cc377275 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -1009,7 +1009,7 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
>  		if (ret)
>  			return ret;
>  

[Severity: High]
This is a pre-existing issue, but I noticed a potential problem in how
rk_udphy_power_on() handles unsupported modes.

At the beginning of rk_udphy_power_on(), if the hardware isn't configured
for the requested mode, the function logs an info message and returns 0:

	if (!(udphy->mode & mode)) {
		dev_info(udphy->dev, "mode 0x%02x is not support\n", mode);
		return 0;
	}

Because it returns success, callers might assume the PHY was successfully
powered up and clocked. For example, if we look at rk_udphy_dp_phy_power_on():

	ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP);
	if (ret)
		return ret;

	rk_udphy_dp_lane_enable(udphy, udphy->dp_lanes);

If UDPHY_MODE_DP is requested but not supported (for instance, if the
device tree configures it as USB-only), rk_udphy_power_on() will skip
the setup sequence and return 0.

Would the caller then proceed to access unclocked memory-mapped registers
in rk_udphy_dp_lane_enable() and trigger a kernel panic (SError)?

Should rk_udphy_power_on() return an error code like -EOPNOTSUPP instead
of 0 when an unsupported mode is requested?

> -		if (udphy->mode & UDPHY_MODE_USB)
> +		if (!udphy->hs && udphy->mode & UDPHY_MODE_USB)
>  			rk_udphy_u3_port_disable(udphy, false);
>  		udphy->phy_needs_reinit = false;
>  	} else if (udphy->phy_needs_reinit) {

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=28

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 31/36] phy: rockchip: usbdp: Add phy reset notification support
  2026-07-10 16:45 ` [PATCH v12 31/36] phy: rockchip: usbdp: Add phy reset notification support Sebastian Reichel
@ 2026-07-10 21:26   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:26 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: neil.armstrong, conor+dt, linux-phy, vkoul, olteanv, robh,
	devicetree

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Shared `phy_reset_count` across multiple USB3 ports in DWC3 notifier causes stuck `PHYSOFTRST` and unbalanced PM runtime refcounts.
--

--- Patch [31]: [PATCH v12 31/36] phy: rockchip: usbdp: Add phy reset notification support ---
commit a652d5b92503989cfd858925aecf81d1ed290bb7
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Add phy reset notification support
    
This commit adds support for reset notifications to gracefully handle
the PHY being disabled. It is intended to prevent corrupting the
controller's internal state and resolve "cmn ana lcpll lock timeout"
errors after device replugs.

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index af915cc377275..0333e846ce343 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -1005,24 +1005,39 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
>  	}
>  
>  	if (udphy->status == UDPHY_MODE_NONE) {
> +		phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_PRE_RESET);
> +

[Severity: High]
Can this cause a port to become permanently stuck in reset due to how the
DWC3 core tracks reset notifications?

Looking at the DWC3 notifier callback in dwc3_usb3_phy_notify(), it uses a
single controller-wide atomic counter (phy_reset_count) rather than tracking
the state on a per-port basis:

drivers/usb/dwc3/core.c:dwc3_usb3_phy_notify() {
    ...
    atomic_inc(&dwc->phy_reset_count);
    ...
}

If this PHY notification is triggered concurrently across multiple USB3 ports,
could the shared counter lead to unbalanced state? For example, if Port 0
executes PHY_NOTIFY_PRE_RESET while the controller is suspended
(pm_runtime_get_if_active <= 0), it skips the sequence and does not increment
the counter.

If the controller then wakes up and Port 1 concurrently executes
PHY_NOTIFY_PRE_RESET, it increments the shared counter to 1 and asserts
Port 1's reset.

When Port 0 later finishes its PHY setup and executes PHY_NOTIFY_POST_RESET,
it sees the shared counter is 1. Does it incorrectly process the post-reset,
decrementing the counter to 0 and dropping a PM refcount?

If so, when Port 1 finally executes PHY_NOTIFY_POST_RESET, it would see the
shared counter is 0 and abort early, potentially leaving Port 1 permanently
stuck with PHYSOFTRST asserted and unbalanced PM runtime refcounts.

Does the state need to be tracked on a per-port basis in the DWC3 core before
enabling these notifications for multi-port controllers?

> +		rk_udphy_u3_port_disable(udphy, true);
> +		udelay(10);
> +
>  		ret = rk_udphy_setup(udphy);
> -		if (ret)
> +		if (ret) {
> +			phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_POST_RESET);
>  			return ret;
> +		}
>  
>  		if (!udphy->hs && udphy->mode & UDPHY_MODE_USB)
>  			rk_udphy_u3_port_disable(udphy, false);
>  		udphy->phy_needs_reinit = false;
> +
> +		phy_notify_reset(udphy->phy_u3, PHY_NOTIFY_POST_RESET);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=31

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 35/36] phy: rockchip: usbdp: Re-init PHY on mux change
  2026-07-10 16:45 ` [PATCH v12 35/36] phy: rockchip: usbdp: Re-init PHY on mux change Sebastian Reichel
@ 2026-07-10 21:27   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:27 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: robh, devicetree, olteanv, linux-phy, vkoul, conor+dt,
	neil.armstrong

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Uncoordinated PHY reset during Type-C mode change pulls the rug out from under the active DisplayPort controller, leading to lost DP configuration, race conditions with DRM, and potential hardware SErrors.
--

--- Patch [35]: [PATCH v12 35/36] phy: rockchip: usbdp: Re-init PHY on mux change ---
commit 94db902f39e3cb43921400824c3bb5833e6b7bf2
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Re-init PHY on mux change

Ensure that the right part of the PHY are powered up when the
mode changes. This ensures the PHY is re-initialized in the
following two scenarios, which are currently broken:
cable orientation changes without DP being involved and
switching from DP-only into a mode with USB support.

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index c5ad300620a65..ecf0ed0139f69 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -1383,7 +1383,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
>  
>  	rk_udphy_set_typec_state(udphy, state->mode);
>  
> -	return 0;
> +	return rk_udphy_update_power_state(udphy);

[Severity: High]
Will this cause an uncoordinated PHY reset that breaks the active DisplayPort
controller?

When rk_udphy_update_power_state() detects a mode change, it calls
rk_udphy_init(), which forcefully resets the PHY and disables the DP lanes:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_init() {
    ...
	/* Step 3: configure lane mux */
	regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET,
			   CMN_DP_LANE_MUX_ALL | CMN_DP_LANE_EN_ALL,
			   FIELD_PREP(CMN_DP_LANE_MUX_N(3), udphy->lane_mux_sel[3]) |
               ...
			   FIELD_PREP(CMN_DP_LANE_EN_ALL, 0));
    ...
}

If TCPM synchronously calls rk_udphy_typec_mux_set() during an altmode
renegotiation (such as switching from DP-only to DP+USB), the DP controller
might still be active because DRM handles the associated HPD disconnect
asynchronously on a different workqueue.

Could resetting the PHY while the DP controller is still active and its clock
is stopped trigger an SError or leave the display link permanently broken?

>  }
>  
>  static void rk_udphy_typec_mux_unregister(void *data)

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=35

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v12 32/36] phy: rockchip: usbdp: Drop -EPROBE_DEFER hack
  2026-07-10 16:45 ` [PATCH v12 32/36] phy: rockchip: usbdp: Drop -EPROBE_DEFER hack Sebastian Reichel
@ 2026-07-10 21:28   ` sashiko-bot
  0 siblings, 0 replies; 57+ messages in thread
From: sashiko-bot @ 2026-07-10 21:28 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: linux-phy, olteanv, devicetree, neil.armstrong, vkoul, robh,
	conor+dt

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Removal of -EPROBE_DEFER fallback causes permanent initialization failures due to missing probe-time reset
--

--- Patch [32]: [PATCH v12 32/36] phy: rockchip: usbdp: Drop -EPROBE_DEFER hack ---
commit 98ed05cf436c46697d07d16fcc060eda63439bf7
Author: Sebastian Reichel <sebastian.reichel@collabora.com>

phy: rockchip: usbdp: Drop -EPROBE_DEFER hack

This commit removes the -EPROBE_DEFER fallback for LCPLL lock timeouts in
rk_udphy_status_check(). It states that a reset during the probe routine
now avoids the problem.

>     The hack to return -EPROBE_DEFER when the lcpll lock timeouts is no
>     longer needed. The driver now does a reset during its probe routine
>     marking everything as off and later on does a re-init, which avoids
>     the problem.

[Severity: High]
Is this description accurate? Looking at rk_udphy_probe(), it appears the
probe-time reset was removed in a prior patch, meaning the driver does not
actually perform a reset during probe:

drivers/phy/rockchip/phy-rockchip-usbdp.c:rk_udphy_probe() {
    ...
	udphy->dev = dev;
	ret = rk_udphy_parse_dt(udphy);
	if (ret)
		return ret;

	mutex_init(&udphy->mutex);
	platform_set_drvdata(pdev, udphy);
    ...
}

> diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> index 0333e846ce343..cf173276bfc01 100644
> --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
> +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
> @@ -750,17 +750,7 @@ static int rk_udphy_status_check(struct rk_udphy *udphy)
>  					       (val & CMN_ANA_LCPLL_LOCK_DONE), 200, 100000);
>  		if (ret) {
>  			dev_err(udphy->dev, "cmn ana lcpll lock timeout\n");
> -			/*
> -			 * If earlier software (U-Boot) enabled USB once already
> -			 * the PLL may have problems locking on the first try.
> -			 * It will be successful on the second try, so for the
> -			 * time being a -EPROBE_DEFER will solve the issue.
> -			 *
> -			 * This requires further investigation to understand the
> -			 * root cause, especially considering that the driver is
> -			 * asserting all reset lines at probe time.
> -			 */
> -			return -EPROBE_DEFER;
> +			return ret;
>  		}

[Severity: High]
Does returning the actual error code instead of -EPROBE_DEFER cause a permanent
initialization failure here?

Since the probe routine lacks the hardware reset assertion, if the bootloader
leaves the DWC3 controller running, it can corrupt the PHY state when the PHY
is later reset.

If another consumer like DisplayPort probes first, or DWC3 is not loaded,
phy_power_on() will assert the PHY reset.

Because DWC3 wouldn't have registered its pre-reset notifier to isolate the
PIPE interface, the PHY LCPLL will fail to lock. Without the -EPROBE_DEFER
fallback, this lock timeout becomes a fatal -ETIMEDOUT error and permanently
breaks the driver.

>  
>  		if (!udphy->flip) {

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260710-rockchip-usbdp-cleanup-v12-0-8b41a9a9bef0@collabora.com?part=32

^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2026-07-10 21:28 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-10 16:44 [PATCH v12 00/36] phy: rockchip: usbdp: Clean up the mess Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 01/36] dt-bindings: phy: rockchip-usbdp: add improved ports scheme Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 02/36] phy: rockchip: usbdp: Update mode_change after error handling Sebastian Reichel
2026-07-10 21:15   ` sashiko-bot
2026-07-10 16:44 ` [PATCH v12 03/36] phy: rockchip: usbdp: Do not lose USB3 PHY status Sebastian Reichel
2026-07-10 21:07   ` sashiko-bot
2026-07-10 16:44 ` [PATCH v12 04/36] phy: rockchip: usbdp: Fix devm_clk_bulk_get_all check Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 05/36] phy: rockchip: usbdp: Handle missing clock-names DT property gracefully Sebastian Reichel
2026-07-10 21:07   ` sashiko-bot
2026-07-10 16:44 ` [PATCH v12 06/36] phy: rockchip: usbdp: Drop seamless DP takeover Sebastian Reichel
2026-07-10 21:08   ` sashiko-bot
2026-07-10 16:44 ` [PATCH v12 07/36] phy: rockchip: usbdp: Keep clocks running on PHY re-init Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 08/36] phy: rockchip: usbdp: Amend SSC modulation deviation Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 09/36] phy: rockchip: usbdp: Fix LFPS detect threshold control Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 10/36] phy: rockchip: usbdp: Add missing mode_change update Sebastian Reichel
2026-07-10 21:13   ` sashiko-bot
2026-07-10 16:44 ` [PATCH v12 11/36] phy: rockchip: usbdp: Support single-lane DP Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 12/36] phy: rockchip: usbdp: Limit DP lane count to muxed lanes Sebastian Reichel
2026-07-10 21:08   ` sashiko-bot
2026-07-10 16:44 ` [PATCH v12 13/36] phy: rockchip: usbdp: Rename DP lane functions Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 14/36] phy: rockchip: usbdp: Use FIELD_PREP_WM16_CONST Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 15/36] phy: rockchip: usbdp: Cleanup DP lane selection function Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 16/36] phy: rockchip: usbdp: Register DP aux bridge Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 17/36] phy: rockchip: usbdp: Drop DP HPD handling Sebastian Reichel
2026-07-10 16:44 ` [PATCH v12 18/36] phy: rockchip: usbdp: Rename mode_change to phy_needs_reinit Sebastian Reichel
2026-07-10 21:10   ` sashiko-bot
2026-07-10 16:44 ` [PATCH v12 19/36] phy: rockchip: usbdp: Re-init the PHY on orientation change Sebastian Reichel
2026-07-10 21:15   ` sashiko-bot
2026-07-10 16:44 ` [PATCH v12 20/36] phy: rockchip: usbdp: Factor out lane_mux_sel setup Sebastian Reichel
2026-07-10 21:16   ` sashiko-bot
2026-07-10 16:44 ` [PATCH v12 21/36] phy: rockchip: usbdp: Properly handle TYPEC_STATE_SAFE and TYPEC_STATE_USB Sebastian Reichel
2026-07-10 21:18   ` sashiko-bot
2026-07-10 16:45 ` [PATCH v12 22/36] phy: rockchip: usbdp: Use guard functions for mutex Sebastian Reichel
2026-07-10 21:18   ` sashiko-bot
2026-07-10 16:45 ` [PATCH v12 23/36] phy: rockchip: usbdp: Clear USB status on PHY exit Sebastian Reichel
2026-07-10 21:17   ` sashiko-bot
2026-07-10 16:45 ` [PATCH v12 24/36] phy: rockchip: usbdp: Hold mutex in DP PHY configure Sebastian Reichel
2026-07-10 16:45 ` [PATCH v12 25/36] phy: rockchip: usbdp: Add some extra debug messages Sebastian Reichel
2026-07-10 16:45 ` [PATCH v12 26/36] phy: rockchip: usbdp: Avoid xHCI SErrors Sebastian Reichel
2026-07-10 21:20   ` sashiko-bot
2026-07-10 16:45 ` [PATCH v12 27/36] phy: rockchip: usbdp: Handle rk_udphy_reset_deassert errors Sebastian Reichel
2026-07-10 21:17   ` sashiko-bot
2026-07-10 16:45 ` [PATCH v12 28/36] phy: rockchip: usbdp: Only enable USB3 when not in high-speed mode Sebastian Reichel
2026-07-10 21:26   ` sashiko-bot
2026-07-10 16:45 ` [PATCH v12 29/36] phy: core: add notifier infrastructure Sebastian Reichel
2026-07-10 16:45 ` [PATCH v12 30/36] usb: dwc3: core: support PHY reset notifications Sebastian Reichel
2026-07-10 21:20   ` sashiko-bot
2026-07-10 16:45 ` [PATCH v12 31/36] phy: rockchip: usbdp: Add phy reset notification support Sebastian Reichel
2026-07-10 21:26   ` sashiko-bot
2026-07-10 16:45 ` [PATCH v12 32/36] phy: rockchip: usbdp: Drop -EPROBE_DEFER hack Sebastian Reichel
2026-07-10 21:28   ` sashiko-bot
2026-07-10 16:45 ` [PATCH v12 33/36] phy: rockchip: usbdp: Rename mode to hw_mode Sebastian Reichel
2026-07-10 21:23   ` sashiko-bot
2026-07-10 16:45 ` [PATCH v12 34/36] phy: rockchip: usbdp: Fix power state handling Sebastian Reichel
2026-07-10 16:45 ` [PATCH v12 35/36] phy: rockchip: usbdp: Re-init PHY on mux change Sebastian Reichel
2026-07-10 21:27   ` sashiko-bot
2026-07-10 16:45 ` [PATCH v12 36/36] phy: rockchip: usbdp: Add USB-C state without DP enabled Sebastian Reichel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox