[PATCH v5 1/2] dt-bindings: usb: snps,dwc3: tighten the two-connector shared HS bus

From: Qianhui Xu

Date: Sat Oct 31 2026 - 11:02:25 EST


Two connectors behind one controller only take the mux path when the
controller node itself carries "usb-role-switch": dwc3_get_dr_mode()
otherwise forces dr_mode back to peripheral, dwc3_get_extcon() skips the
role-switch branch and dwc3_drd_init() never calls dwc3_role_mux_init().
The binding accepted such a DT, so a DT that passed the schema check did
not describe a DT the driver could act on. Require the property whenever
port-select-gpios is present.

Two more holes in the endpoint schema are fixed at the same time:

- the hs-port patternProperties only covered endpoint@0 and endpoint@1,
so an unnumbered endpoint or endpoint@2+ escaped the
unevaluatedProperties: false rule of the graph endpoint. Use the same
endpoint name pattern as graph.yaml so every endpoint is validated.

- the mux-state complementarity was expressed with two independent "if
const: 0" blocks, which only rejected two zeroes; two endpoints both
claiming mux-state = <1> passed validation. Express the pair as oneOf
so exactly one of the two assignments is accepted.

Signed-off-by: Qianhui Xu <xiaqinghuan@xxxxxxxxxxxxxxxx>
---
.../bindings/usb/snps,dwc3-common.yaml | 105 +++++++++---------
1 file changed, 55 insertions(+), 50 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml
index 6b06b0027b..b23d5d8d74 100644
--- a/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml
+++ b/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml
@@ -31,7 +31,9 @@ $defs:
enum: [0, 1]
description:
Logical level of the port-select GPIO which connects this
- connector to the shared High Speed data bus.
+ connector to the shared High Speed data bus. The two connectors of
+ one controller must use different levels; the driver rejects a
+ device tree where two connectors claim the same one.

dependentRequired:
usb-role-switch: [mux-state]
@@ -42,7 +44,7 @@ $defs:
unevaluatedProperties: false

patternProperties:
- '^endpoint@[01]$':
+ '^endpoint(@[0-9a-f]+)?$':
$ref: '#/$defs/hs-endpoint'

allOf:
@@ -61,70 +63,74 @@ allOf:
- if:
required: [port-select-gpios]
then:
- required: [dr_mode, ports]
+ # The mux path is only taken when the controller itself carries
+ # "usb-role-switch": dwc3_get_dr_mode() forces dr_mode back to
+ # peripheral, dwc3_get_extcon() skips the role-switch branch and
+ # dwc3_drd_init() never calls dwc3_role_mux_init() without it.
+ required: [dr_mode, ports, usb-role-switch]
properties:
dr_mode:
const: otg
ports:
- required: [port@0]
+ # Each connector is one port with a single endpoint: the mux-state
+ # property on that endpoint says which level of the port-select GPIO
+ # reaches it, so two connectors are two ports, not two endpoints of
+ # one port. port@1 is the SuperSpeed lane of the PHY and is already
+ # described by snps,dwc3.yaml, so the second High Speed connector
+ # lands on port@2.
+ required: [port@0, port@2]
properties:
port@0:
- required: ['#address-cells', '#size-cells', endpoint@0, endpoint@1]
+ $ref: '#/$defs/hs-port'
+ port@2:
+ $ref: '#/$defs/hs-port'
+
+ # The two connectors must claim opposite levels of the port-select
+ # GPIO; requiring both ports in every branch is what makes the two
+ # cases mutually exclusive for oneOf.
+ oneOf:
+ - required: [port@0, port@2]
properties:
- endpoint@0:
- required: [usb-role-switch, mux-state]
- endpoint@1:
- required: [usb-role-switch, mux-state]
- else:
- properties:
- ports:
- properties:
- port@0:
- patternProperties:
- '^endpoint@[01]$':
+ port@0:
+ $ref: '#/$defs/hs-port'
properties:
- usb-role-switch: false
- mux-state: false
- - if:
- properties:
- ports:
- properties:
- port@0:
- properties:
- endpoint@0:
+ endpoint:
+ properties:
+ mux-state:
+ const: 0
+ port@2:
+ $ref: '#/$defs/hs-port'
properties:
- mux-state:
- const: 0
- then:
- properties:
- ports:
- properties:
- port@0:
+ endpoint:
+ properties:
+ mux-state:
+ const: 1
+ - required: [port@0, port@2]
properties:
- endpoint@1:
+ port@0:
+ $ref: '#/$defs/hs-port'
properties:
- mux-state:
- const: 1
- - if:
- properties:
- ports:
- properties:
- port@0:
- properties:
- endpoint@1:
+ endpoint:
+ properties:
+ mux-state:
+ const: 1
+ port@2:
+ $ref: '#/$defs/hs-port'
properties:
- mux-state:
- const: 0
- then:
+ endpoint:
+ properties:
+ mux-state:
+ const: 0
+ else:
properties:
ports:
properties:
port@0:
- properties:
- endpoint@0:
+ patternProperties:
+ '^endpoint(@[0-9a-f]+)?$':
properties:
- mux-state:
- const: 1
+ usb-role-switch: false
+ mux-state: false

properties:
port-select-gpios:
@@ -536,4 +542,3 @@ required:

additionalProperties: true
...
-
base-commit: fd69bd54e328c407b1853378b25d15803d3453fa
--
2.53.0