* [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure
@ 2024-08-12 3:11 Bjorn Andersson
2024-08-12 3:11 ` [PATCH v2 1/7] dt-bindings: usb: snps,dwc3: Split core description Bjorn Andersson
` (7 more replies)
0 siblings, 8 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-12 3:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Bjorn Andersson, Konrad Dybcio
Cc: linux-usb, devicetree, linux-kernel, linux-arm-msm,
Bjorn Andersson
The USB IP-block found in most Qualcomm platforms is modelled in the
Linux kernel as 3 different independent device drivers, but as shown by
the already existing layering violations in the Qualcomm glue driver
they can not be operated independently.
With the current implementation, the glue driver registers the core and
has no way to know when this is done. As a result, e.g. the suspend
callbacks needs to guard against NULL pointer dereferences when trying
to peek into the struct dwc3 found in the drvdata of the child.
Missing from the upstream Qualcomm USB support is handling of role
switching, in which the glue needs to be notified upon DRD mode changes.
Several attempts has been made through the years to register callbacks
etc, but they always fall short when it comes to handling of the core's
probe deferral on resources etc.
Furhtermore, the DeviceTree binding is a direct representation of the
Linux driver model, and doesn't necessarily describe "the USB IP-block".
This series therefor attempts to flatten the driver split, and operate
the glue and core out of the same platform_device instance. And in order
to do this, the DeviceTree representation of the IP block is flattened.
---
Changes in v2:
- Rewrite after ACPI removal, multiport support and interrupt fixes
- Completely changed strategy for DeviceTree binding, as previous idea
of using snps,dwc3 as a generic fallback required unreasonable changes
to that binding.
- Abandoned idea of supporting both flattened and unflattened device
model in the one driver. As Johan pointed out, it will leave the race
condition holes and will make the code harder to understand.
Furthermore, the role switching logic that we intend to introduce
following this would have depended on the user updating their
DeviceTree blobs.
- Per above, introduced the dynamic DeviceTree rewrite
- Link to v1: https://lore.kernel.org/all/20231016-dwc3-refactor-v1-0-ab4a84165470@quicinc.com/
---
Bjorn Andersson (7):
dt-bindings: usb: snps,dwc3: Split core description
dt-bindings: usb: Introduce qcom,snps-dwc3
of: dynamic: Don't discard children upon node attach
usb: dwc3: core: Expose core driver as library
usb: dwc3: qcom: Don't reply on drvdata during probe
usb: dwc3: qcom: Transition to flattened model
arm64: dts: qcom: sc8280x: Flatten the USB nodes
.../devicetree/bindings/usb/qcom,dwc3.yaml | 13 +-
.../devicetree/bindings/usb/qcom,snps-dwc3.yaml | 608 +++++++++++++++++++++
.../devicetree/bindings/usb/snps,dwc3-common.yaml | 417 ++++++++++++++
.../devicetree/bindings/usb/snps,dwc3.yaml | 391 +------------
arch/arm64/boot/dts/qcom/sa8295p-adp.dts | 12 +-
arch/arm64/boot/dts/qcom/sa8540p-ride.dts | 5 +-
arch/arm64/boot/dts/qcom/sc8280xp-crd.dts | 12 +-
.../dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts | 11 +-
arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 138 +++--
drivers/of/dynamic.c | 1 -
drivers/usb/dwc3/core.c | 169 ++++--
drivers/usb/dwc3/core.h | 3 +
drivers/usb/dwc3/dwc3-qcom.c | 323 ++++++++---
13 files changed, 1483 insertions(+), 620 deletions(-)
---
base-commit: 864b1099d16fc7e332c3ad7823058c65f890486c
change-id: 20231016-dwc3-refactor-931e3b08a8b9
Best regards,
--
Bjorn Andersson <quic_bjorande@quicinc.com>
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH v2 1/7] dt-bindings: usb: snps,dwc3: Split core description
2024-08-12 3:11 [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Bjorn Andersson
@ 2024-08-12 3:11 ` Bjorn Andersson
2024-08-18 14:33 ` Rob Herring
2024-08-12 3:11 ` [PATCH v2 2/7] dt-bindings: usb: Introduce qcom,snps-dwc3 Bjorn Andersson
` (6 subsequent siblings)
7 siblings, 1 reply; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-12 3:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Bjorn Andersson, Konrad Dybcio
Cc: linux-usb, devicetree, linux-kernel, linux-arm-msm,
Bjorn Andersson
From: Bjorn Andersson <quic_bjorande@quicinc.com>
The Synopsys DWC3 core is found either as a standard block or integrated
with vendor glue logic. So far the latter has been described as two
separate IP blocks in DeviceTree, but the two parts are not separate.
In the case where the core is integrated together with vendor glue,
resources such as clock and resets are often customized by the vendor,
such that the standard properties doesn't make sense.
Split the snps,dwc3 binding in a description of the core properties and
the standard "glue" properties, in order to allow vendor bindings to
inherit the core properties.
Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
---
.../devicetree/bindings/usb/snps,dwc3-common.yaml | 417 +++++++++++++++++++++
.../devicetree/bindings/usb/snps,dwc3.yaml | 391 +------------------
2 files changed, 418 insertions(+), 390 deletions(-)
diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml
new file mode 100644
index 000000000000..65e7900f904a
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml
@@ -0,0 +1,417 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/snps,dwc3-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys DesignWare USB3 Controller common properties
+
+select: false
+
+maintainers:
+ - Felipe Balbi <balbi@kernel.org>
+
+description:
+ Defines the properties of the DWC3 core as being embedded in either an
+ vendor-specific implementation or as a standalone component.
+
+allOf:
+ - $ref: usb-drd.yaml#
+ - if:
+ properties:
+ dr_mode:
+ const: peripheral
+
+ required:
+ - dr_mode
+ then:
+ $ref: usb.yaml#
+ else:
+ $ref: usb-xhci.yaml#
+
+properties:
+ extcon:
+ maxItems: 1
+ deprecated: true
+
+ usb-phy:
+ minItems: 1
+ items:
+ - description: USB2/HS PHY
+ - description: USB3/SS PHY
+
+ phys:
+ minItems: 1
+ maxItems: 19
+
+ phy-names:
+ minItems: 1
+ maxItems: 19
+ oneOf:
+ - items:
+ enum: [ usb2-phy, usb3-phy ]
+ - items:
+ pattern: "^usb(2-([0-9]|1[0-4])|3-[0-3])$"
+
+ snps,usb2-lpm-disable:
+ description: Indicate if we don't want to enable USB2 HW LPM for host
+ mode.
+ type: boolean
+
+ snps,usb3_lpm_capable:
+ description: Determines if platform is USB3 LPM capable
+ type: boolean
+
+ snps,usb2-gadget-lpm-disable:
+ description: Indicate if we don't want to enable USB2 HW LPM for gadget
+ mode.
+ type: boolean
+
+ snps,dis-start-transfer-quirk:
+ description:
+ When set, disable isoc START TRANSFER command failure SW work-around
+ for DWC_usb31 version 1.70a-ea06 and prior.
+ type: boolean
+
+ snps,disable_scramble_quirk:
+ description:
+ True when SW should disable data scrambling. Only really useful for FPGA
+ builds.
+ type: boolean
+
+ snps,has-lpm-erratum:
+ description: True when DWC3 was configured with LPM Erratum enabled
+ type: boolean
+
+ snps,lpm-nyet-threshold:
+ description: LPM NYET threshold
+ $ref: /schemas/types.yaml#/definitions/uint8
+
+ snps,u2exit_lfps_quirk:
+ description: Set if we want to enable u2exit lfps quirk
+ type: boolean
+
+ snps,u2ss_inp3_quirk:
+ description: Set if we enable P3 OK for U2/SS Inactive quirk
+ type: boolean
+
+ snps,req_p1p2p3_quirk:
+ description:
+ When set, the core will always request for P1/P2/P3 transition sequence.
+ type: boolean
+
+ snps,del_p1p2p3_quirk:
+ description:
+ When set core will delay P1/P2/P3 until a certain amount of 8B10B errors
+ occur.
+ type: boolean
+
+ snps,del_phy_power_chg_quirk:
+ description: When set core will delay PHY power change from P0 to P1/P2/P3.
+ type: boolean
+
+ snps,lfps_filter_quirk:
+ description: When set core will filter LFPS reception.
+ type: boolean
+
+ snps,rx_detect_poll_quirk:
+ description:
+ when set core will disable a 400us delay to start Polling LFPS after
+ RX.Detect.
+ type: boolean
+
+ snps,tx_de_emphasis_quirk:
+ description: When set core will set Tx de-emphasis value
+ type: boolean
+
+ snps,tx_de_emphasis:
+ description:
+ The value driven to the PHY is controlled by the LTSSM during USB3
+ Compliance mode.
+ $ref: /schemas/types.yaml#/definitions/uint8
+ enum:
+ - 0 # -6dB de-emphasis
+ - 1 # -3.5dB de-emphasis
+ - 2 # No de-emphasis
+
+ snps,dis_u3_susphy_quirk:
+ description: When set core will disable USB3 suspend phy
+ type: boolean
+
+ snps,dis_u2_susphy_quirk:
+ description: When set core will disable USB2 suspend phy
+ type: boolean
+
+ snps,dis_enblslpm_quirk:
+ description:
+ When set clears the enblslpm in GUSB2PHYCFG, disabling the suspend signal
+ to the PHY.
+ type: boolean
+
+ snps,dis-u1-entry-quirk:
+ description: Set if link entering into U1 needs to be disabled
+ type: boolean
+
+ snps,dis-u2-entry-quirk:
+ description: Set if link entering into U2 needs to be disabled
+ type: boolean
+
+ snps,dis_rxdet_inp3_quirk:
+ description:
+ When set core will disable receiver detection in PHY P3 power state.
+ type: boolean
+
+ snps,dis-u2-freeclk-exists-quirk:
+ description:
+ When set, clear the u2_freeclk_exists in GUSB2PHYCFG, specify that USB2
+ PHY doesn't provide a free-running PHY clock.
+ type: boolean
+
+ snps,dis-del-phy-power-chg-quirk:
+ description:
+ When set core will change PHY power from P0 to P1/P2/P3 without delay.
+ type: boolean
+
+ snps,dis-tx-ipgap-linecheck-quirk:
+ description: When set, disable u2mac linestate check during HS transmit
+ type: boolean
+
+ snps,parkmode-disable-ss-quirk:
+ description:
+ When set, all SuperSpeed bus instances in park mode are disabled.
+ type: boolean
+
+ snps,parkmode-disable-hs-quirk:
+ description:
+ When set, all HighSpeed bus instances in park mode are disabled.
+ type: boolean
+
+ snps,dis_metastability_quirk:
+ description:
+ When set, disable metastability workaround. CAUTION! Use only if you are
+ absolutely sure of it.
+ type: boolean
+
+ snps,dis-split-quirk:
+ description:
+ When set, change the way URBs are handled by the driver. Needed to
+ avoid -EPROTO errors with usbhid on some devices (Hikey 970).
+ type: boolean
+
+ snps,gfladj-refclk-lpm-sel-quirk:
+ description:
+ When set, run the SOF/ITP counter based on ref_clk.
+ type: boolean
+
+ snps,resume-hs-terminations:
+ description:
+ Fix the issue of HS terminations CRC error on resume by enabling this
+ quirk. When set, all the termsel, xcvrsel, opmode becomes 0 during end
+ of resume. This option is to support certain legacy ULPI PHYs.
+ type: boolean
+
+ snps,ulpi-ext-vbus-drv:
+ description:
+ Some ULPI USB PHY does not support internal VBUS supply, and driving
+ the CPEN pin, requires the configuration of the ulpi DRVVBUSEXTERNAL
+ bit. When set, the xhci host will configure the USB2 PHY drives VBUS
+ with an external supply.
+ type: boolean
+
+ snps,is-utmi-l1-suspend:
+ description:
+ True when DWC3 asserts output signal utmi_l1_suspend_n, false when
+ asserts utmi_sleep_n.
+ type: boolean
+
+ snps,hird-threshold:
+ description: HIRD threshold
+ $ref: /schemas/types.yaml#/definitions/uint8
+
+ snps,hsphy_interface:
+ description:
+ High-Speed PHY interface selection between UTMI+ and ULPI when the
+ DWC_USB3_HSPHY_INTERFACE has value 3.
+ $ref: /schemas/types.yaml#/definitions/string
+ enum: [utmi, ulpi]
+
+ snps,quirk-frame-length-adjustment:
+ description:
+ Value for GFLADJ_30MHZ field of GFLADJ register for post-silicon frame
+ length adjustment when the fladj_30mhz_sdbnd signal is invalid or
+ incorrect.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 0x3f
+
+ snps,ref-clock-period-ns:
+ description:
+ Value for REFCLKPER field of GUCTL register for reference clock period in
+ nanoseconds, when the hardware set default does not match the actual
+ clock.
+
+ This binding is deprecated. Instead, provide an appropriate reference clock.
+ minimum: 8
+ maximum: 62
+ deprecated: true
+
+ snps,rx-thr-num-pkt:
+ description:
+ USB RX packet threshold count. In host mode, this field specifies
+ the space that must be available in the RX FIFO before the core can
+ start the corresponding USB RX transaction (burst).
+ In device mode, this field specifies the space that must be
+ available in the RX FIFO before the core can send ERDY for a
+ flow-controlled endpoint. It is only used for SuperSpeed.
+ The valid values for this field are from 1 to 15. (DWC3 SuperSpeed
+ USB 3.0 Controller Databook)
+ $ref: /schemas/types.yaml#/definitions/uint8
+ minimum: 1
+ maximum: 15
+
+ snps,rx-max-burst:
+ description:
+ Max USB RX burst size. In host mode, this field specifies the
+ Maximum Bulk IN burst the DWC_usb3 core can perform. When the system
+ bus is slower than the USB, RX FIFO can overrun during a long burst.
+ You can program a smaller value to this field to limit the RX burst
+ size that the core can perform. It only applies to SS Bulk,
+ Isochronous, and Interrupt IN endpoints in the host mode.
+ In device mode, this field specifies the NUMP value that is sent in
+ ERDY for an OUT endpoint.
+ The valid values for this field are from 1 to 16. (DWC3 SuperSpeed
+ USB 3.0 Controller Databook)
+ $ref: /schemas/types.yaml#/definitions/uint8
+ minimum: 1
+ maximum: 16
+
+ snps,tx-thr-num-pkt:
+ description:
+ USB TX packet threshold count. This field specifies the number of
+ packets that must be in the TXFIFO before the core can start
+ transmission for the corresponding USB transaction (burst).
+ This count is valid in both host and device modes. It is only used
+ for SuperSpeed operation.
+ Valid values are from 1 to 15. (DWC3 SuperSpeed USB 3.0 Controller
+ Databook)
+ $ref: /schemas/types.yaml#/definitions/uint8
+ minimum: 1
+ maximum: 15
+
+ snps,tx-max-burst:
+ description:
+ Max USB TX burst size. When the system bus is slower than the USB,
+ TX FIFO can underrun during a long burst. Program a smaller value
+ to this field to limit the TX burst size that the core can execute.
+ In Host mode, it only applies to SS Bulk, Isochronous, and Interrupt
+ OUT endpoints. This value is not used in device mode.
+ Valid values are from 1 to 16. (DWC3 SuperSpeed USB 3.0 Controller
+ Databook)
+ $ref: /schemas/types.yaml#/definitions/uint8
+ minimum: 1
+ maximum: 16
+
+ snps,rx-thr-num-pkt-prd:
+ description:
+ Periodic ESS RX packet threshold count (host mode only). Set this and
+ snps,rx-max-burst-prd to a valid, non-zero value 1-16 (DWC_usb31
+ programming guide section 1.2.4) to enable periodic ESS RX threshold.
+ $ref: /schemas/types.yaml#/definitions/uint8
+ minimum: 1
+ maximum: 16
+
+ snps,rx-max-burst-prd:
+ description:
+ Max periodic ESS RX burst size (host mode only). Set this and
+ snps,rx-thr-num-pkt-prd to a valid, non-zero value 1-16 (DWC_usb31
+ programming guide section 1.2.4) to enable periodic ESS RX threshold.
+ $ref: /schemas/types.yaml#/definitions/uint8
+ minimum: 1
+ maximum: 16
+
+ snps,tx-thr-num-pkt-prd:
+ description:
+ Periodic ESS TX packet threshold count (host mode only). Set this and
+ snps,tx-max-burst-prd to a valid, non-zero value 1-16 (DWC_usb31
+ programming guide section 1.2.3) to enable periodic ESS TX threshold.
+ $ref: /schemas/types.yaml#/definitions/uint8
+ minimum: 1
+ maximum: 16
+
+ snps,tx-max-burst-prd:
+ description:
+ Max periodic ESS TX burst size (host mode only). Set this and
+ snps,tx-thr-num-pkt-prd to a valid, non-zero value 1-16 (DWC_usb31
+ programming guide section 1.2.3) to enable periodic ESS TX threshold.
+ $ref: /schemas/types.yaml#/definitions/uint8
+ minimum: 1
+ maximum: 16
+
+ tx-fifo-resize:
+ description: Determines if the TX fifos can be dynamically resized depending
+ on the number of IN endpoints used and if bursting is supported. This
+ may help improve bandwidth on platforms with higher system latencies, as
+ increased fifo space allows for the controller to prefetch data into its
+ internal memory.
+ type: boolean
+
+ tx-fifo-max-num:
+ description: Specifies the max number of packets the txfifo resizing logic
+ can account for when higher endpoint bursting is used. (bMaxBurst > 6) The
+ higher the number, the more fifo space the txfifo resizing logic will
+ allocate for that endpoint.
+ $ref: /schemas/types.yaml#/definitions/uint8
+ minimum: 3
+
+ snps,incr-burst-type-adjustment:
+ description:
+ Value for INCR burst type of GSBUSCFG0 register, undefined length INCR
+ burst type enable and INCRx type. A single value means INCRX burst mode
+ enabled. If more than one value specified, undefined length INCR burst
+ type will be enabled with burst lengths utilized up to the maximum
+ of the values passed in this property.
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ minItems: 1
+ maxItems: 8
+ uniqueItems: true
+ items:
+ enum: [1, 4, 8, 16, 32, 64, 128, 256]
+
+ num-hc-interrupters:
+ maximum: 8
+ default: 1
+
+ port:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ This port is used with the 'usb-role-switch' property to connect the
+ dwc3 to type C connector.
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+ description:
+ Those ports should be used with any connector to the data bus of this
+ controller using the OF graph bindings specified if the "usb-role-switch"
+ property is used.
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: High Speed (HS) data bus.
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Super Speed (SS) data bus.
+
+ wakeup-source:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description:
+ Enable USB remote wakeup.
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: true
+...
+
diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml
index 1cd0ca90127d..4380bb6fa2f0 100644
--- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml
@@ -15,18 +15,7 @@ description:
compatible string.
allOf:
- - $ref: usb-drd.yaml#
- - if:
- properties:
- dr_mode:
- const: peripheral
-
- required:
- - dr_mode
- then:
- $ref: usb.yaml#
- else:
- $ref: usb-xhci.yaml#
+ - $ref: snps,dwc3-common.yaml#
properties:
compatible:
@@ -70,32 +59,9 @@ properties:
dma-coherent: true
- extcon:
- maxItems: 1
- deprecated: true
-
iommus:
maxItems: 1
- usb-phy:
- minItems: 1
- items:
- - description: USB2/HS PHY
- - description: USB3/SS PHY
-
- phys:
- minItems: 1
- maxItems: 19
-
- phy-names:
- minItems: 1
- maxItems: 19
- oneOf:
- - items:
- enum: [ usb2-phy, usb3-phy ]
- - items:
- pattern: "^usb(2-([0-9]|1[0-4])|3-[0-3])$"
-
power-domains:
description:
The DWC3 has 2 power-domains. The power management unit (PMU) and
@@ -109,361 +75,6 @@ properties:
resets:
minItems: 1
- snps,usb2-lpm-disable:
- description: Indicate if we don't want to enable USB2 HW LPM for host
- mode.
- type: boolean
-
- snps,usb3_lpm_capable:
- description: Determines if platform is USB3 LPM capable
- type: boolean
-
- snps,usb2-gadget-lpm-disable:
- description: Indicate if we don't want to enable USB2 HW LPM for gadget
- mode.
- type: boolean
-
- snps,dis-start-transfer-quirk:
- description:
- When set, disable isoc START TRANSFER command failure SW work-around
- for DWC_usb31 version 1.70a-ea06 and prior.
- type: boolean
-
- snps,disable_scramble_quirk:
- description:
- True when SW should disable data scrambling. Only really useful for FPGA
- builds.
- type: boolean
-
- snps,has-lpm-erratum:
- description: True when DWC3 was configured with LPM Erratum enabled
- type: boolean
-
- snps,lpm-nyet-threshold:
- description: LPM NYET threshold
- $ref: /schemas/types.yaml#/definitions/uint8
-
- snps,u2exit_lfps_quirk:
- description: Set if we want to enable u2exit lfps quirk
- type: boolean
-
- snps,u2ss_inp3_quirk:
- description: Set if we enable P3 OK for U2/SS Inactive quirk
- type: boolean
-
- snps,req_p1p2p3_quirk:
- description:
- When set, the core will always request for P1/P2/P3 transition sequence.
- type: boolean
-
- snps,del_p1p2p3_quirk:
- description:
- When set core will delay P1/P2/P3 until a certain amount of 8B10B errors
- occur.
- type: boolean
-
- snps,del_phy_power_chg_quirk:
- description: When set core will delay PHY power change from P0 to P1/P2/P3.
- type: boolean
-
- snps,lfps_filter_quirk:
- description: When set core will filter LFPS reception.
- type: boolean
-
- snps,rx_detect_poll_quirk:
- description:
- when set core will disable a 400us delay to start Polling LFPS after
- RX.Detect.
- type: boolean
-
- snps,tx_de_emphasis_quirk:
- description: When set core will set Tx de-emphasis value
- type: boolean
-
- snps,tx_de_emphasis:
- description:
- The value driven to the PHY is controlled by the LTSSM during USB3
- Compliance mode.
- $ref: /schemas/types.yaml#/definitions/uint8
- enum:
- - 0 # -6dB de-emphasis
- - 1 # -3.5dB de-emphasis
- - 2 # No de-emphasis
-
- snps,dis_u3_susphy_quirk:
- description: When set core will disable USB3 suspend phy
- type: boolean
-
- snps,dis_u2_susphy_quirk:
- description: When set core will disable USB2 suspend phy
- type: boolean
-
- snps,dis_enblslpm_quirk:
- description:
- When set clears the enblslpm in GUSB2PHYCFG, disabling the suspend signal
- to the PHY.
- type: boolean
-
- snps,dis-u1-entry-quirk:
- description: Set if link entering into U1 needs to be disabled
- type: boolean
-
- snps,dis-u2-entry-quirk:
- description: Set if link entering into U2 needs to be disabled
- type: boolean
-
- snps,dis_rxdet_inp3_quirk:
- description:
- When set core will disable receiver detection in PHY P3 power state.
- type: boolean
-
- snps,dis-u2-freeclk-exists-quirk:
- description:
- When set, clear the u2_freeclk_exists in GUSB2PHYCFG, specify that USB2
- PHY doesn't provide a free-running PHY clock.
- type: boolean
-
- snps,dis-del-phy-power-chg-quirk:
- description:
- When set core will change PHY power from P0 to P1/P2/P3 without delay.
- type: boolean
-
- snps,dis-tx-ipgap-linecheck-quirk:
- description: When set, disable u2mac linestate check during HS transmit
- type: boolean
-
- snps,parkmode-disable-ss-quirk:
- description:
- When set, all SuperSpeed bus instances in park mode are disabled.
- type: boolean
-
- snps,parkmode-disable-hs-quirk:
- description:
- When set, all HighSpeed bus instances in park mode are disabled.
- type: boolean
-
- snps,dis_metastability_quirk:
- description:
- When set, disable metastability workaround. CAUTION! Use only if you are
- absolutely sure of it.
- type: boolean
-
- snps,dis-split-quirk:
- description:
- When set, change the way URBs are handled by the driver. Needed to
- avoid -EPROTO errors with usbhid on some devices (Hikey 970).
- type: boolean
-
- snps,gfladj-refclk-lpm-sel-quirk:
- description:
- When set, run the SOF/ITP counter based on ref_clk.
- type: boolean
-
- snps,resume-hs-terminations:
- description:
- Fix the issue of HS terminations CRC error on resume by enabling this
- quirk. When set, all the termsel, xcvrsel, opmode becomes 0 during end
- of resume. This option is to support certain legacy ULPI PHYs.
- type: boolean
-
- snps,ulpi-ext-vbus-drv:
- description:
- Some ULPI USB PHY does not support internal VBUS supply, and driving
- the CPEN pin, requires the configuration of the ulpi DRVVBUSEXTERNAL
- bit. When set, the xhci host will configure the USB2 PHY drives VBUS
- with an external supply.
- type: boolean
-
- snps,is-utmi-l1-suspend:
- description:
- True when DWC3 asserts output signal utmi_l1_suspend_n, false when
- asserts utmi_sleep_n.
- type: boolean
-
- snps,hird-threshold:
- description: HIRD threshold
- $ref: /schemas/types.yaml#/definitions/uint8
-
- snps,hsphy_interface:
- description:
- High-Speed PHY interface selection between UTMI+ and ULPI when the
- DWC_USB3_HSPHY_INTERFACE has value 3.
- $ref: /schemas/types.yaml#/definitions/string
- enum: [utmi, ulpi]
-
- snps,quirk-frame-length-adjustment:
- description:
- Value for GFLADJ_30MHZ field of GFLADJ register for post-silicon frame
- length adjustment when the fladj_30mhz_sdbnd signal is invalid or
- incorrect.
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 0
- maximum: 0x3f
-
- snps,ref-clock-period-ns:
- description:
- Value for REFCLKPER field of GUCTL register for reference clock period in
- nanoseconds, when the hardware set default does not match the actual
- clock.
-
- This binding is deprecated. Instead, provide an appropriate reference clock.
- minimum: 8
- maximum: 62
- deprecated: true
-
- snps,rx-thr-num-pkt:
- description:
- USB RX packet threshold count. In host mode, this field specifies
- the space that must be available in the RX FIFO before the core can
- start the corresponding USB RX transaction (burst).
- In device mode, this field specifies the space that must be
- available in the RX FIFO before the core can send ERDY for a
- flow-controlled endpoint. It is only used for SuperSpeed.
- The valid values for this field are from 1 to 15. (DWC3 SuperSpeed
- USB 3.0 Controller Databook)
- $ref: /schemas/types.yaml#/definitions/uint8
- minimum: 1
- maximum: 15
-
- snps,rx-max-burst:
- description:
- Max USB RX burst size. In host mode, this field specifies the
- Maximum Bulk IN burst the DWC_usb3 core can perform. When the system
- bus is slower than the USB, RX FIFO can overrun during a long burst.
- You can program a smaller value to this field to limit the RX burst
- size that the core can perform. It only applies to SS Bulk,
- Isochronous, and Interrupt IN endpoints in the host mode.
- In device mode, this field specifies the NUMP value that is sent in
- ERDY for an OUT endpoint.
- The valid values for this field are from 1 to 16. (DWC3 SuperSpeed
- USB 3.0 Controller Databook)
- $ref: /schemas/types.yaml#/definitions/uint8
- minimum: 1
- maximum: 16
-
- snps,tx-thr-num-pkt:
- description:
- USB TX packet threshold count. This field specifies the number of
- packets that must be in the TXFIFO before the core can start
- transmission for the corresponding USB transaction (burst).
- This count is valid in both host and device modes. It is only used
- for SuperSpeed operation.
- Valid values are from 1 to 15. (DWC3 SuperSpeed USB 3.0 Controller
- Databook)
- $ref: /schemas/types.yaml#/definitions/uint8
- minimum: 1
- maximum: 15
-
- snps,tx-max-burst:
- description:
- Max USB TX burst size. When the system bus is slower than the USB,
- TX FIFO can underrun during a long burst. Program a smaller value
- to this field to limit the TX burst size that the core can execute.
- In Host mode, it only applies to SS Bulk, Isochronous, and Interrupt
- OUT endpoints. This value is not used in device mode.
- Valid values are from 1 to 16. (DWC3 SuperSpeed USB 3.0 Controller
- Databook)
- $ref: /schemas/types.yaml#/definitions/uint8
- minimum: 1
- maximum: 16
-
- snps,rx-thr-num-pkt-prd:
- description:
- Periodic ESS RX packet threshold count (host mode only). Set this and
- snps,rx-max-burst-prd to a valid, non-zero value 1-16 (DWC_usb31
- programming guide section 1.2.4) to enable periodic ESS RX threshold.
- $ref: /schemas/types.yaml#/definitions/uint8
- minimum: 1
- maximum: 16
-
- snps,rx-max-burst-prd:
- description:
- Max periodic ESS RX burst size (host mode only). Set this and
- snps,rx-thr-num-pkt-prd to a valid, non-zero value 1-16 (DWC_usb31
- programming guide section 1.2.4) to enable periodic ESS RX threshold.
- $ref: /schemas/types.yaml#/definitions/uint8
- minimum: 1
- maximum: 16
-
- snps,tx-thr-num-pkt-prd:
- description:
- Periodic ESS TX packet threshold count (host mode only). Set this and
- snps,tx-max-burst-prd to a valid, non-zero value 1-16 (DWC_usb31
- programming guide section 1.2.3) to enable periodic ESS TX threshold.
- $ref: /schemas/types.yaml#/definitions/uint8
- minimum: 1
- maximum: 16
-
- snps,tx-max-burst-prd:
- description:
- Max periodic ESS TX burst size (host mode only). Set this and
- snps,tx-thr-num-pkt-prd to a valid, non-zero value 1-16 (DWC_usb31
- programming guide section 1.2.3) to enable periodic ESS TX threshold.
- $ref: /schemas/types.yaml#/definitions/uint8
- minimum: 1
- maximum: 16
-
- tx-fifo-resize:
- description: Determines if the TX fifos can be dynamically resized depending
- on the number of IN endpoints used and if bursting is supported. This
- may help improve bandwidth on platforms with higher system latencies, as
- increased fifo space allows for the controller to prefetch data into its
- internal memory.
- type: boolean
-
- tx-fifo-max-num:
- description: Specifies the max number of packets the txfifo resizing logic
- can account for when higher endpoint bursting is used. (bMaxBurst > 6) The
- higher the number, the more fifo space the txfifo resizing logic will
- allocate for that endpoint.
- $ref: /schemas/types.yaml#/definitions/uint8
- minimum: 3
-
- snps,incr-burst-type-adjustment:
- description:
- Value for INCR burst type of GSBUSCFG0 register, undefined length INCR
- burst type enable and INCRx type. A single value means INCRX burst mode
- enabled. If more than one value specified, undefined length INCR burst
- type will be enabled with burst lengths utilized up to the maximum
- of the values passed in this property.
- $ref: /schemas/types.yaml#/definitions/uint32-array
- minItems: 1
- maxItems: 8
- uniqueItems: true
- items:
- enum: [1, 4, 8, 16, 32, 64, 128, 256]
-
- num-hc-interrupters:
- maximum: 8
- default: 1
-
- port:
- $ref: /schemas/graph.yaml#/properties/port
- description:
- This port is used with the 'usb-role-switch' property to connect the
- dwc3 to type C connector.
-
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
- description:
- Those ports should be used with any connector to the data bus of this
- controller using the OF graph bindings specified if the "usb-role-switch"
- property is used.
-
- properties:
- port@0:
- $ref: /schemas/graph.yaml#/properties/port
- description: High Speed (HS) data bus.
-
- port@1:
- $ref: /schemas/graph.yaml#/properties/port
- description: Super Speed (SS) data bus.
-
- wakeup-source:
- $ref: /schemas/types.yaml#/definitions/flag
- description:
- Enable USB remote wakeup.
-
unevaluatedProperties: false
required:
--
2.45.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH v2 2/7] dt-bindings: usb: Introduce qcom,snps-dwc3
2024-08-12 3:11 [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Bjorn Andersson
2024-08-12 3:11 ` [PATCH v2 1/7] dt-bindings: usb: snps,dwc3: Split core description Bjorn Andersson
@ 2024-08-12 3:11 ` Bjorn Andersson
2024-08-12 4:32 ` Rob Herring (Arm)
2024-08-12 3:12 ` [PATCH v2 3/7] of: dynamic: Don't discard children upon node attach Bjorn Andersson
` (5 subsequent siblings)
7 siblings, 1 reply; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-12 3:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Bjorn Andersson, Konrad Dybcio
Cc: linux-usb, devicetree, linux-kernel, linux-arm-msm,
Bjorn Andersson
From: Bjorn Andersson <quic_bjorande@quicinc.com>
The Qualcomm USB glue is not separate of the Synopsys DWC3 core and
several of the snps,dwc3 properties (such as clocks and reset) conflicts
in expectation with the Qualcomm integration.
Using the newly split out Synopsys DWC3 core properties, describe the
Qualcomm USB block in a single block. The new binding is a copy of
qcom,dwc3 with the needed modifications.
It would have been convenient to retain the two structures with the same
compatibles, but as there exist no way to select a binding based on the
absence of a subnode/patternProperty, a new generic compatible is
introduced to describe this binding.
To avoid redefining all the platform-specific compatibles, "select" is
used to tell the DeviceTree validator which binding to use solely on the
generic compatible. (Otherwise if the specific compatible matches during
validation, the generic one must match as well)
Mark qcom,dwc3 deprecated, to favor expressing future platforms using
the new combined binding.
Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
---
.../devicetree/bindings/usb/qcom,dwc3.yaml | 13 +-
.../devicetree/bindings/usb/qcom,snps-dwc3.yaml | 608 +++++++++++++++++++++
2 files changed, 620 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
index efde47a5b145..739195ade20f 100644
--- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
@@ -4,11 +4,22 @@
$id: http://devicetree.org/schemas/usb/qcom,dwc3.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Qualcomm SuperSpeed DWC3 USB SoC controller
+title: Legacy Qualcomm SuperSpeed DWC3 USB SoC controller
maintainers:
- Wesley Cheng <quic_wcheng@quicinc.com>
+# Use the combined qcom,snps-dwc3 instead
+deprecated: true
+
+select:
+ properties:
+ compatible:
+ contains:
+ const: qcom,dwc3
+ required:
+ - compatible
+
properties:
compatible:
items:
diff --git a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml
new file mode 100644
index 000000000000..331f63a7ef4a
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml
@@ -0,0 +1,608 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/qcom,snps-dwc3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SuperSpeed DWC3 USB SoC controller
+
+maintainers:
+ - Wesley Cheng <quic_wcheng@quicinc.com>
+
+description:
+ Describes the Qualcomm USB block, based on Synopsys DWC3.
+
+select:
+ properties:
+ compatible:
+ contains:
+ const: qcom,snps-dwc3
+ required:
+ - compatible
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - qcom,ipq4019-dwc3
+ - qcom,ipq5018-dwc3
+ - qcom,ipq5332-dwc3
+ - qcom,ipq6018-dwc3
+ - qcom,ipq8064-dwc3
+ - qcom,ipq8074-dwc3
+ - qcom,ipq9574-dwc3
+ - qcom,msm8953-dwc3
+ - qcom,msm8994-dwc3
+ - qcom,msm8996-dwc3
+ - qcom,msm8998-dwc3
+ - qcom,qcm2290-dwc3
+ - qcom,qcs404-dwc3
+ - qcom,qdu1000-dwc3
+ - qcom,sa8775p-dwc3
+ - qcom,sc7180-dwc3
+ - qcom,sc7280-dwc3
+ - qcom,sc8180x-dwc3
+ - qcom,sc8180x-dwc3-mp
+ - qcom,sc8280xp-dwc3
+ - qcom,sc8280xp-dwc3-mp
+ - qcom,sdm660-dwc3
+ - qcom,sdm670-dwc3
+ - qcom,sdm845-dwc3
+ - qcom,sdx55-dwc3
+ - qcom,sdx65-dwc3
+ - qcom,sdx75-dwc3
+ - qcom,sm4250-dwc3
+ - qcom,sm6115-dwc3
+ - qcom,sm6125-dwc3
+ - qcom,sm6350-dwc3
+ - qcom,sm6375-dwc3
+ - qcom,sm8150-dwc3
+ - qcom,sm8250-dwc3
+ - qcom,sm8350-dwc3
+ - qcom,sm8450-dwc3
+ - qcom,sm8550-dwc3
+ - qcom,sm8650-dwc3
+ - qcom,x1e80100-dwc3
+ - const: qcom,snps-dwc3
+
+ reg:
+ description: Offset and length of register set for QSCRATCH wrapper
+ maxItems: 1
+
+ power-domains:
+ description: specifies a phandle to PM domain provider node
+ maxItems: 1
+
+ required-opps:
+ maxItems: 1
+
+ clocks:
+ description: |
+ Several clocks are used, depending on the variant. Typical ones are::
+ - cfg_noc:: System Config NOC clock.
+ - core:: Master/Core clock, has to be >= 125 MHz for SS operation and >=
+ 60MHz for HS operation.
+ - iface:: System bus AXI clock.
+ - sleep:: Sleep clock, used for wakeup when USB3 core goes into low
+ power mode (U3).
+ - mock_utmi:: Mock utmi clock needed for ITP/SOF generation in host
+ mode. Its frequency should be 19.2MHz.
+ minItems: 1
+ maxItems: 9
+
+ clock-names:
+ minItems: 1
+ maxItems: 9
+
+ iommus:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ interconnects:
+ maxItems: 2
+
+ interconnect-names:
+ items:
+ - const: usb-ddr
+ - const: apps-usb
+
+ interrupts:
+ description: |
+ Different types of interrupts are used based on HS PHY used on target:
+ - dwc_usb3: Core DWC3 interrupt
+ - pwr_event: Used for wakeup based on other power events.
+ - hs_phy_irq: Apart from DP/DM/QUSB2 PHY interrupts, there is
+ hs_phy_irq which is not triggered by default and its
+ functionality is mutually exclusive to that of
+ {dp/dm}_hs_phy_irq and qusb2_phy_irq.
+ - qusb2_phy: SoCs with QUSB2 PHY do not have separate DP/DM IRQs and
+ expose only a single IRQ whose behavior can be modified
+ by the QUSB2PHY_INTR_CTRL register. The required DPSE/
+ DMSE configuration is done in QUSB2PHY_INTR_CTRL register
+ of PHY address space.
+ - {dp/dm}_hs_phy_irq: These IRQ's directly reflect changes on the DP/
+ DM pads of the SoC. These are used for wakeup
+ only on SoCs with non-QUSB2 targets with
+ exception of SDM670/SDM845/SM6350.
+ - ss_phy_irq: Used for remote wakeup in Super Speed mode of operation.
+ minItems: 3
+ maxItems: 19
+
+ interrupt-names:
+ minItems: 3
+ maxItems: 19
+
+ qcom,select-utmi-as-pipe-clk:
+ description:
+ If present, disable USB3 pipe_clk requirement.
+ Used when dwc3 operates without SSPHY and only
+ HS/FS/LS modes are supported.
+ type: boolean
+
+ wakeup-source: true
+
+# Required child node:
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - interrupts
+ - interrupt-names
+
+allOf:
+ - $ref: snps,dwc3-common.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,ipq4019-dwc3
+ - qcom,ipq5332-dwc3
+ then:
+ properties:
+ clocks:
+ maxItems: 3
+ clock-names:
+ items:
+ - const: core
+ - const: sleep
+ - const: mock_utmi
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,ipq8064-dwc3
+ then:
+ properties:
+ clocks:
+ items:
+ - description: Master/Core clock, has to be >= 125 MHz
+ for SS operation and >= 60MHz for HS operation.
+ clock-names:
+ items:
+ - const: core
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,ipq9574-dwc3
+ - qcom,msm8953-dwc3
+ - qcom,msm8996-dwc3
+ - qcom,msm8998-dwc3
+ - qcom,sa8775p-dwc3
+ - qcom,sc7180-dwc3
+ - qcom,sc7280-dwc3
+ - qcom,sdm670-dwc3
+ - qcom,sdm845-dwc3
+ - qcom,sdx55-dwc3
+ - qcom,sdx65-dwc3
+ - qcom,sdx75-dwc3
+ - qcom,sm6350-dwc3
+ then:
+ properties:
+ clocks:
+ maxItems: 5
+ clock-names:
+ items:
+ - const: cfg_noc
+ - const: core
+ - const: iface
+ - const: sleep
+ - const: mock_utmi
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,ipq6018-dwc3
+ then:
+ properties:
+ clocks:
+ minItems: 3
+ maxItems: 4
+ clock-names:
+ oneOf:
+ - items:
+ - const: core
+ - const: sleep
+ - const: mock_utmi
+ - items:
+ - const: cfg_noc
+ - const: core
+ - const: sleep
+ - const: mock_utmi
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,ipq8074-dwc3
+ - qcom,qdu1000-dwc3
+ then:
+ properties:
+ clocks:
+ maxItems: 4
+ clock-names:
+ items:
+ - const: cfg_noc
+ - const: core
+ - const: sleep
+ - const: mock_utmi
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,ipq5018-dwc3
+ - qcom,msm8994-dwc3
+ - qcom,qcs404-dwc3
+ then:
+ properties:
+ clocks:
+ maxItems: 4
+ clock-names:
+ items:
+ - const: core
+ - const: iface
+ - const: sleep
+ - const: mock_utmi
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,sc8280xp-dwc3
+ - qcom,sc8280xp-dwc3-mp
+ - qcom,x1e80100-dwc3
+ then:
+ properties:
+ clocks:
+ maxItems: 9
+ clock-names:
+ items:
+ - const: cfg_noc
+ - const: core
+ - const: iface
+ - const: sleep
+ - const: mock_utmi
+ - const: noc_aggr
+ - const: noc_aggr_north
+ - const: noc_aggr_south
+ - const: noc_sys
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,sdm660-dwc3
+ then:
+ properties:
+ clocks:
+ minItems: 4
+ maxItems: 5
+ clock-names:
+ oneOf:
+ - items:
+ - const: cfg_noc
+ - const: core
+ - const: iface
+ - const: sleep
+ - const: mock_utmi
+ - items:
+ - const: cfg_noc
+ - const: core
+ - const: sleep
+ - const: mock_utmi
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,qcm2290-dwc3
+ - qcom,sc8180x-dwc3
+ - qcom,sc8180x-dwc3-mp
+ - qcom,sm6115-dwc3
+ - qcom,sm6125-dwc3
+ - qcom,sm8150-dwc3
+ - qcom,sm8250-dwc3
+ - qcom,sm8450-dwc3
+ - qcom,sm8550-dwc3
+ - qcom,sm8650-dwc3
+ then:
+ properties:
+ clocks:
+ minItems: 6
+ clock-names:
+ items:
+ - const: cfg_noc
+ - const: core
+ - const: iface
+ - const: sleep
+ - const: mock_utmi
+ - const: xo
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,sm8350-dwc3
+ then:
+ properties:
+ clocks:
+ minItems: 5
+ maxItems: 6
+ clock-names:
+ minItems: 5
+ items:
+ - const: cfg_noc
+ - const: core
+ - const: iface
+ - const: sleep
+ - const: mock_utmi
+ - const: xo
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,ipq5018-dwc3
+ - qcom,ipq6018-dwc3
+ - qcom,ipq8074-dwc3
+ - qcom,msm8953-dwc3
+ - qcom,msm8998-dwc3
+ then:
+ properties:
+ interrupts:
+ minItems: 3
+ maxItems: 4
+ interrupt-names:
+ items:
+ - const: dwc_usb3
+ - const: pwr_event
+ - const: qusb2_phy
+ - const: ss_phy_irq
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,msm8996-dwc3
+ - qcom,qcs404-dwc3
+ - qcom,sdm660-dwc3
+ - qcom,sm6115-dwc3
+ - qcom,sm6125-dwc3
+ then:
+ properties:
+ interrupts:
+ minItems: 4
+ maxItems: 5
+ interrupt-names:
+ items:
+ - const: dwc_usb3
+ - const: pwr_event
+ - const: qusb2_phy
+ - const: hs_phy_irq
+ - const: ss_phy_irq
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,ipq5332-dwc3
+ then:
+ properties:
+ interrupts:
+ maxItems: 4
+ interrupt-names:
+ items:
+ - const: dwc_usb3
+ - const: pwr_event
+ - const: dp_hs_phy_irq
+ - const: dm_hs_phy_irq
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,x1e80100-dwc3
+ then:
+ properties:
+ interrupts:
+ maxItems: 5
+ interrupt-names:
+ items:
+ - const: dwc_usb3
+ - const: pwr_event
+ - const: dp_hs_phy_irq
+ - const: dm_hs_phy_irq
+ - const: ss_phy_irq
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,ipq4019-dwc3
+ - qcom,ipq8064-dwc3
+ - qcom,msm8994-dwc3
+ - qcom,qdu1000-dwc3
+ - qcom,sa8775p-dwc3
+ - qcom,sc7180-dwc3
+ - qcom,sc7280-dwc3
+ - qcom,sc8180x-dwc3
+ - qcom,sc8280xp-dwc3
+ - qcom,sdm670-dwc3
+ - qcom,sdm845-dwc3
+ - qcom,sdx55-dwc3
+ - qcom,sdx65-dwc3
+ - qcom,sdx75-dwc3
+ - qcom,sm4250-dwc3
+ - qcom,sm6350-dwc3
+ - qcom,sm8150-dwc3
+ - qcom,sm8250-dwc3
+ - qcom,sm8350-dwc3
+ - qcom,sm8450-dwc3
+ - qcom,sm8550-dwc3
+ - qcom,sm8650-dwc3
+ then:
+ properties:
+ interrupts:
+ minItems: 5
+ maxItems: 6
+ interrupt-names:
+ items:
+ - const: dwc_usb3
+ - const: pwr_event
+ - const: hs_phy_irq
+ - const: dp_hs_phy_irq
+ - const: dm_hs_phy_irq
+ - const: ss_phy_irq
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,sc8180x-dwc3-mp
+ then:
+ properties:
+ interrupts:
+ minItems: 11
+ maxItems: 11
+ interrupt-names:
+ items:
+ - const: dwc_usb3
+ - const: pwr_event_1
+ - const: pwr_event_2
+ - const: hs_phy_1
+ - const: hs_phy_2
+ - const: dp_hs_phy_1
+ - const: dm_hs_phy_1
+ - const: dp_hs_phy_2
+ - const: dm_hs_phy_2
+ - const: ss_phy_1
+ - const: ss_phy_2
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,sc8280xp-dwc3-mp
+ then:
+ properties:
+ interrupts:
+ minItems: 19
+ maxItems: 19
+ interrupt-names:
+ items:
+ - const: dwc_usb3
+ - const: pwr_event_1
+ - const: pwr_event_2
+ - const: pwr_event_3
+ - const: pwr_event_4
+ - const: hs_phy_1
+ - const: hs_phy_2
+ - const: hs_phy_3
+ - const: hs_phy_4
+ - const: dp_hs_phy_1
+ - const: dm_hs_phy_1
+ - const: dp_hs_phy_2
+ - const: dm_hs_phy_2
+ - const: dp_hs_phy_3
+ - const: dm_hs_phy_3
+ - const: dp_hs_phy_4
+ - const: dm_hs_phy_4
+ - const: ss_phy_1
+ - const: ss_phy_2
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,gcc-sdm845.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ usb@a600000 {
+ compatible = "qcom,sdm845-dwc3", "qcom,snps-dwc3";
+ reg = <0 0x0a600000 0 0x100000>;
+
+ clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>,
+ <&gcc GCC_USB30_PRIM_MASTER_CLK>,
+ <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>,
+ <&gcc GCC_USB30_PRIM_SLEEP_CLK>,
+ <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>;
+ clock-names = "cfg_noc",
+ "core",
+ "iface",
+ "sleep",
+ "mock_utmi";
+
+ assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
+ <&gcc GCC_USB30_PRIM_MASTER_CLK>;
+ assigned-clock-rates = <19200000>, <150000000>;
+
+ interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 489 IRQ_TYPE_EDGE_BOTH>,
+ <GIC_SPI 488 IRQ_TYPE_EDGE_BOTH>,
+ <GIC_SPI 486 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "dwc_usb3", "pwr_event", "hs_phy_irq",
+ "dp_hs_phy_irq", "dm_hs_phy_irq", "ss_phy_irq";
+
+ power-domains = <&gcc USB30_PRIM_GDSC>;
+
+ resets = <&gcc GCC_USB30_PRIM_BCR>;
+
+ iommus = <&apps_smmu 0x740 0>;
+ snps,dis_u2_susphy_quirk;
+ snps,dis_enblslpm_quirk;
+ phys = <&usb_1_hsphy>, <&usb_1_ssphy>;
+ phy-names = "usb2-phy", "usb3-phy";
+ };
+ };
+...
--
2.45.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH v2 3/7] of: dynamic: Don't discard children upon node attach
2024-08-12 3:11 [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Bjorn Andersson
2024-08-12 3:11 ` [PATCH v2 1/7] dt-bindings: usb: snps,dwc3: Split core description Bjorn Andersson
2024-08-12 3:11 ` [PATCH v2 2/7] dt-bindings: usb: Introduce qcom,snps-dwc3 Bjorn Andersson
@ 2024-08-12 3:12 ` Bjorn Andersson
2024-08-12 20:24 ` Rob Herring
2024-08-12 3:12 ` [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library Bjorn Andersson
` (4 subsequent siblings)
7 siblings, 1 reply; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-12 3:12 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Bjorn Andersson, Konrad Dybcio
Cc: linux-usb, devicetree, linux-kernel, linux-arm-msm,
Bjorn Andersson
From: Bjorn Andersson <quic_bjorande@quicinc.com>
When dynamically modifying DeviceTree it's useful to be able to reparent
nodes, but of_attach_node() clear the child pointer and hence discards
any child nodes.
Retain the child pointer upon attach, so that the client code doesn't
need to manually rebuild the tree.
Current users of of_attach_node() either avoids attaching nodes with
children or explicitly attaches nodes without children, so no impact is
expected to current users.
Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
---
drivers/of/dynamic.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 110104a936d9..32e1dffd9f96 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -221,7 +221,6 @@ static void __of_attach_node(struct device_node *np)
np->phandle = 0;
}
- np->child = NULL;
np->sibling = np->parent->child;
np->parent->child = np;
of_node_clear_flag(np, OF_DETACHED);
--
2.45.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-12 3:11 [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Bjorn Andersson
` (2 preceding siblings ...)
2024-08-12 3:12 ` [PATCH v2 3/7] of: dynamic: Don't discard children upon node attach Bjorn Andersson
@ 2024-08-12 3:12 ` Bjorn Andersson
2024-08-12 12:21 ` kernel test robot
` (5 more replies)
2024-08-12 3:12 ` [PATCH v2 5/7] usb: dwc3: qcom: Don't reply on drvdata during probe Bjorn Andersson
` (3 subsequent siblings)
7 siblings, 6 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-12 3:12 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Bjorn Andersson, Konrad Dybcio
Cc: linux-usb, devicetree, linux-kernel, linux-arm-msm,
Bjorn Andersson
From: Bjorn Andersson <quic_bjorande@quicinc.com>
The DWC3 IP block is handled by three distinct device drivers: XHCI,
DWC3 core and a platform specific (optional) DWC3 glue driver.
This has resulted in, at least in the case of the Qualcomm glue, the
presence of a number of layering violations, where the glue code either
can't handle, or has to work around, the fact that core might not probe
deterministically.
An example of this is that the suspend path should operate slightly
different depending on the device operating in host or peripheral mode,
and the only way to determine the operating state is to peek into the
core's drvdata.
The Qualcomm glue driver is expected to make updates in the qscratch
register region (the "glue" region) during role switch events, but with
the glue and core split using the driver model, there is no reasonable
way to introduce listeners for mode changes.
Split the dwc3 core platform_driver callbacks and their implementation
and export the implementation, to make it possible to deterministically
instantiate the dwc3 core as part of the dwc3 glue drivers and to
allow flattening of the DeviceTree representation.
Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
---
drivers/usb/dwc3/core.c | 169 +++++++++++++++++++++++++++++++-----------------
drivers/usb/dwc3/core.h | 3 +
2 files changed, 114 insertions(+), 58 deletions(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 734de2a8bd21..6addb3c367e6 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -36,6 +36,7 @@
#include "core.h"
#include "gadget.h"
+#include "glue.h"
#include "io.h"
#include "debug.h"
@@ -2076,10 +2077,11 @@ static int dwc3_get_num_ports(struct dwc3 *dwc)
return 0;
}
-static int dwc3_probe(struct platform_device *pdev)
+struct dwc3 *dwc3_probe(struct platform_device *pdev, struct resource *res,
+ bool ignore_clocks_and_resets, void *glue)
{
struct device *dev = &pdev->dev;
- struct resource *res, dwc_res;
+ struct resource dwc_res;
unsigned int hw_mode;
void __iomem *regs;
struct dwc3 *dwc;
@@ -2087,15 +2089,10 @@ static int dwc3_probe(struct platform_device *pdev)
dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
if (!dwc)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
dwc->dev = dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "missing memory resource\n");
- return -ENODEV;
- }
+ dwc->glue = glue;
dwc->xhci_resources[0].start = res->start;
dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
@@ -2123,7 +2120,7 @@ static int dwc3_probe(struct platform_device *pdev)
regs = devm_ioremap_resource(dev, &dwc_res);
if (IS_ERR(regs))
- return PTR_ERR(regs);
+ return ERR_CAST(regs);
dwc->regs = regs;
dwc->regs_size = resource_size(&dwc_res);
@@ -2132,15 +2129,17 @@ static int dwc3_probe(struct platform_device *pdev)
dwc3_get_software_properties(dwc);
- dwc->reset = devm_reset_control_array_get_optional_shared(dev);
- if (IS_ERR(dwc->reset)) {
- ret = PTR_ERR(dwc->reset);
- goto err_put_psy;
- }
+ if (!ignore_clocks_and_resets) {
+ dwc->reset = devm_reset_control_array_get_optional_shared(dev);
+ if (IS_ERR(dwc->reset)) {
+ ret = PTR_ERR(dwc->reset);
+ goto err_put_psy;
+ }
- ret = dwc3_get_clocks(dwc);
- if (ret)
- goto err_put_psy;
+ ret = dwc3_get_clocks(dwc);
+ if (ret)
+ goto err_put_psy;
+ }
ret = reset_control_deassert(dwc->reset);
if (ret)
@@ -2225,7 +2224,7 @@ static int dwc3_probe(struct platform_device *pdev)
dma_set_max_seg_size(dev, UINT_MAX);
- return 0;
+ return dwc;
err_exit_debugfs:
dwc3_debugfs_exit(dwc);
@@ -2249,14 +2248,33 @@ static int dwc3_probe(struct platform_device *pdev)
if (dwc->usb_psy)
power_supply_put(dwc->usb_psy);
- return ret;
+ return ERR_PTR(ret);
}
+EXPORT_SYMBOL_GPL(dwc3_probe);
-static void dwc3_remove(struct platform_device *pdev)
+static int dwc3_plat_probe(struct platform_device *pdev)
{
- struct dwc3 *dwc = platform_get_drvdata(pdev);
+ struct resource *res;
+ struct dwc3 *dwc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing memory resource\n");
+ return -ENODEV;
+ }
- pm_runtime_get_sync(&pdev->dev);
+ dwc = dwc3_probe(pdev, res, false, NULL);
+ if (IS_ERR(dwc))
+ return PTR_ERR(dwc);
+
+ platform_set_drvdata(pdev, dwc);
+
+ return 0;
+}
+
+void dwc3_remove(struct dwc3 *dwc)
+{
+ pm_runtime_get_sync(dwc->dev);
dwc3_core_exit_mode(dwc);
dwc3_debugfs_exit(dwc);
@@ -2264,22 +2282,28 @@ static void dwc3_remove(struct platform_device *pdev)
dwc3_core_exit(dwc);
dwc3_ulpi_exit(dwc);
- pm_runtime_allow(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- pm_runtime_dont_use_autosuspend(&pdev->dev);
- pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_allow(dwc->dev);
+ pm_runtime_disable(dwc->dev);
+ pm_runtime_dont_use_autosuspend(dwc->dev);
+ pm_runtime_put_noidle(dwc->dev);
/*
* HACK: Clear the driver data, which is currently accessed by parent
* glue drivers, before allowing the parent to suspend.
*/
- platform_set_drvdata(pdev, NULL);
- pm_runtime_set_suspended(&pdev->dev);
+ dev_set_drvdata(dwc->dev, NULL);
+ pm_runtime_set_suspended(dwc->dev);
dwc3_free_event_buffers(dwc);
if (dwc->usb_psy)
power_supply_put(dwc->usb_psy);
}
+EXPORT_SYMBOL_GPL(dwc3_remove);
+
+static void dwc3_plat_remove(struct platform_device *pdev)
+{
+ dwc3_remove(platform_get_drvdata(pdev));
+}
#ifdef CONFIG_PM
static int dwc3_core_init_for_resume(struct dwc3 *dwc)
@@ -2450,9 +2474,8 @@ static int dwc3_runtime_checks(struct dwc3 *dwc)
return 0;
}
-static int dwc3_runtime_suspend(struct device *dev)
+int dwc3_runtime_suspend(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
int ret;
if (dwc3_runtime_checks(dwc))
@@ -2464,10 +2487,10 @@ static int dwc3_runtime_suspend(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(dwc3_runtime_suspend);
-static int dwc3_runtime_resume(struct device *dev)
+int dwc3_runtime_resume(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
int ret;
ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
@@ -2484,15 +2507,14 @@ static int dwc3_runtime_resume(struct device *dev)
break;
}
- pm_runtime_mark_last_busy(dev);
+ pm_runtime_mark_last_busy(dwc->dev);
return 0;
}
+EXPORT_SYMBOL_GPL(dwc3_runtime_resume);
-static int dwc3_runtime_idle(struct device *dev)
+int dwc3_runtime_idle(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
-
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
if (dwc3_runtime_checks(dwc))
@@ -2504,52 +2526,67 @@ static int dwc3_runtime_idle(struct device *dev)
break;
}
- pm_runtime_mark_last_busy(dev);
- pm_runtime_autosuspend(dev);
+ pm_runtime_mark_last_busy(dwc->dev);
+ pm_runtime_autosuspend(dwc->dev);
return 0;
}
+EXPORT_SYMBOL_GPL(dwc3_runtime_idle);
+
+static int dwc3_plat_runtime_suspend(struct device *dev)
+{
+ return dwc3_runtime_suspend(dev_get_drvdata(dev));
+}
+
+static int dwc3_plat_runtime_resume(struct device *dev)
+{
+ return dwc3_runtime_resume(dev_get_drvdata(dev));
+}
+
+static int dwc3_plat_runtime_idle(struct device *dev)
+{
+ return dwc3_runtime_idle(dev_get_drvdata(dev));
+}
#endif /* CONFIG_PM */
#ifdef CONFIG_PM_SLEEP
-static int dwc3_suspend(struct device *dev)
+int dwc3_suspend(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
int ret;
ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
if (ret)
return ret;
- pinctrl_pm_select_sleep_state(dev);
+ pinctrl_pm_select_sleep_state(dwc->dev);
return 0;
}
+EXPORT_SYMBOL_GPL(dwc3_suspend);
-static int dwc3_resume(struct device *dev)
+int dwc3_resume(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
int ret;
- pinctrl_pm_select_default_state(dev);
+ pinctrl_pm_select_default_state(dwc->dev);
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
+ pm_runtime_disable(dwc->dev);
+ pm_runtime_set_active(dwc->dev);
ret = dwc3_resume_common(dwc, PMSG_RESUME);
if (ret) {
- pm_runtime_set_suspended(dev);
+ pm_runtime_set_suspended(dwc->dev);
return ret;
}
- pm_runtime_enable(dev);
+ pm_runtime_enable(dwc->dev);
return 0;
}
+EXPORT_SYMBOL_GPL(dwc3_resume);
-static void dwc3_complete(struct device *dev)
+void dwc3_complete(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
u32 reg;
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
@@ -2559,15 +2596,31 @@ static void dwc3_complete(struct device *dev)
dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
}
}
+EXPORT_SYMBOL_GPL(dwc3_complete);
+
+static int dwc3_plat_suspend(struct device *dev)
+{
+ return dwc3_suspend(dev_get_drvdata(dev));
+}
+
+static int dwc3_plat_resume(struct device *dev)
+{
+ return dwc3_resume(dev_get_drvdata(dev));
+}
+
+static void dwc3_plat_complete(struct device *dev)
+{
+ dwc3_complete(dev_get_drvdata(dev));
+}
#else
-#define dwc3_complete NULL
+#define dwc3_plat_complete NULL
#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops dwc3_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
- .complete = dwc3_complete,
- SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
- dwc3_runtime_idle)
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_plat_suspend, dwc3_plat_resume)
+ .complete = dwc3_plat_complete,
+ SET_RUNTIME_PM_OPS(dwc3_plat_runtime_suspend, dwc3_plat_runtime_resume,
+ dwc3_plat_runtime_idle)
};
#ifdef CONFIG_OF
@@ -2595,8 +2648,8 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
#endif
static struct platform_driver dwc3_driver = {
- .probe = dwc3_probe,
- .remove_new = dwc3_remove,
+ .probe = dwc3_plat_probe,
+ .remove_new = dwc3_plat_remove,
.driver = {
.name = "dwc3",
.of_match_table = of_match_ptr(of_dwc3_match),
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 1e561fd8b86e..4a0ee9ef72e2 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1160,6 +1160,7 @@ struct dwc3_scratchpad_array {
* @gsbuscfg0_reqinfo: store GSBUSCFG0.DATRDREQINFO, DESRDREQINFO,
* DATWRREQINFO, and DESWRREQINFO value passed from
* glue driver.
+ * @glue: private reference to any glue context
*/
struct dwc3 {
struct work_struct drd_work;
@@ -1388,6 +1389,8 @@ struct dwc3 {
int num_ep_resized;
struct dentry *debug_root;
u32 gsbuscfg0_reqinfo;
+
+ void *glue;
};
#define INCRX_BURST_MODE 0
--
2.45.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH v2 5/7] usb: dwc3: qcom: Don't reply on drvdata during probe
2024-08-12 3:11 [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Bjorn Andersson
` (3 preceding siblings ...)
2024-08-12 3:12 ` [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library Bjorn Andersson
@ 2024-08-12 3:12 ` Bjorn Andersson
2024-08-13 18:18 ` Frank Li
2024-09-12 22:21 ` Masahiro Yamada
2024-08-12 3:12 ` [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model Bjorn Andersson
` (2 subsequent siblings)
7 siblings, 2 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-12 3:12 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Bjorn Andersson, Konrad Dybcio
Cc: linux-usb, devicetree, linux-kernel, linux-arm-msm,
Bjorn Andersson
From: Bjorn Andersson <quic_bjorande@quicinc.com>
With the upcoming transition to a model where DWC3 core and glue operate
on a single struct device the drvdata datatype will change to be owned
by the core.
The drvdata is however used by the Qualcomm DWC3 glue to pass the qcom
glue context around before the core is allocated.
Remove this problem, and clean up the code, by passing the dwc3_qcom
struct around during probe, instead of acquiring it from the drvdata.
Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
---
drivers/usb/dwc3/dwc3-qcom.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index 88fb6706a18d..33de03f2d782 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -546,9 +546,10 @@ static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq,
return ret;
}
-static int dwc3_qcom_setup_port_irq(struct platform_device *pdev, int port_index, bool is_multiport)
+static int dwc3_qcom_setup_port_irq(struct dwc3_qcom *qcom,
+ struct platform_device *pdev,
+ int port_index, bool is_multiport)
{
- struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
const char *irq_name;
int irq;
int ret;
@@ -633,9 +634,8 @@ static int dwc3_qcom_find_num_ports(struct platform_device *pdev)
return DWC3_QCOM_MAX_PORTS;
}
-static int dwc3_qcom_setup_irq(struct platform_device *pdev)
+static int dwc3_qcom_setup_irq(struct dwc3_qcom *qcom, struct platform_device *pdev)
{
- struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
bool is_multiport;
int ret;
int i;
@@ -644,7 +644,7 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
is_multiport = (qcom->num_ports > 1);
for (i = 0; i < qcom->num_ports; i++) {
- ret = dwc3_qcom_setup_port_irq(pdev, i, is_multiport);
+ ret = dwc3_qcom_setup_port_irq(qcom, pdev, i, is_multiport);
if (ret)
return ret;
}
@@ -699,9 +699,8 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
return 0;
}
-static int dwc3_qcom_of_register_core(struct platform_device *pdev)
+static int dwc3_qcom_of_register_core(struct dwc3_qcom *qcom, struct platform_device *pdev)
{
- struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node, *dwc3_np;
struct device *dev = &pdev->dev;
int ret;
@@ -782,7 +781,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
goto clk_disable;
}
- ret = dwc3_qcom_setup_irq(pdev);
+ ret = dwc3_qcom_setup_irq(qcom, pdev);
if (ret) {
dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
goto clk_disable;
@@ -797,7 +796,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
if (ignore_pipe_clk)
dwc3_qcom_select_utmi_clk(qcom);
- ret = dwc3_qcom_of_register_core(pdev);
+ ret = dwc3_qcom_of_register_core(qcom, pdev);
if (ret) {
dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
goto clk_disable;
--
2.45.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model
2024-08-12 3:11 [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Bjorn Andersson
` (4 preceding siblings ...)
2024-08-12 3:12 ` [PATCH v2 5/7] usb: dwc3: qcom: Don't reply on drvdata during probe Bjorn Andersson
@ 2024-08-12 3:12 ` Bjorn Andersson
2024-08-12 13:33 ` kernel test robot
` (2 more replies)
2024-08-12 3:12 ` [PATCH v2 7/7] arm64: dts: qcom: sc8280x: Flatten the USB nodes Bjorn Andersson
2024-08-13 18:07 ` [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Frank Li
7 siblings, 3 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-12 3:12 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Bjorn Andersson, Konrad Dybcio
Cc: linux-usb, devicetree, linux-kernel, linux-arm-msm,
Bjorn Andersson
From: Bjorn Andersson <quic_bjorande@quicinc.com>
The USB IP-block found in most Qualcomm platforms is modelled in the
Linux kernel as 3 different independent device drivers, but as shown by
the already existing layering violations in the Qualcomm glue driver
they can not be operated independently.
With the current implementation, the glue driver registers the core and
has no way to know when this is done. As a result, e.g. the suspend
callbacks needs to guard against NULL pointer dereferences when trying
to peek into the struct dwc3 found in the drvdata of the child.
Even with these checks, there are no way to fully protect ourselves from
the race conditions that occur if the DWC3 is unbound.
Missing from the upstream Qualcomm USB support is handling of role
switching, in which the glue needs to be notified upon DRD mode changes.
Several attempts has been made through the years to register callbacks
etc, but they always fall short when it comes to handling of the core's
probe deferral on resources etc.
Moving to a model where the DWC3 core is instantiated in a synchronous
fashion avoids above described race conditions.
It is however not feasible to do so without also flattening the
DeviceTree binding, as assumptions are made in the DWC3 core and
frameworks used that the device's associated of_node will the that of
the core. Furthermore, the DeviceTree binding is a direct
representation of the Linux driver model, and doesn't necessarily
describe "the USB IP-block".
The Qualcomm DWC3 glue driver is therefor transitioned to initialize and
operate the DWC3 within the one device context, in synchronous fashion.
To handle backwards compatibility, and to remove the two-device model,
of_nodes of the old compatible are converted to the new one, early
during probe.
This happens in the event that a DWC3 core child node is present, the
content of the reg and interrupt properties of this node are merged into
the shared properties, all remaining properties are copied and the core
node is dropped. Effectively transitioning the node from qcom,dwc3 to
qcom,snps-dwc3.
Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
---
drivers/usb/dwc3/dwc3-qcom.c | 310 +++++++++++++++++++++++++++++++++++--------
1 file changed, 251 insertions(+), 59 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index 33de03f2d782..27b5013cd411 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -6,6 +6,7 @@
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/of_clk.h>
@@ -13,6 +14,8 @@
#include <linux/kernel.h>
#include <linux/extcon.h>
#include <linux/interconnect.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
@@ -22,6 +25,7 @@
#include <linux/usb/hcd.h>
#include <linux/usb.h>
#include "core.h"
+#include "glue.h"
/* USB QSCRATCH Hardware registers */
#define QSCRATCH_HS_PHY_CTRL 0x10
@@ -72,7 +76,7 @@ struct dwc3_qcom_port {
struct dwc3_qcom {
struct device *dev;
void __iomem *qscratch_base;
- struct platform_device *dwc3;
+ struct dwc3 *dwc;
struct clk **clks;
int num_clocks;
struct reset_control *resets;
@@ -259,7 +263,7 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
goto put_path_ddr;
}
- max_speed = usb_get_maximum_speed(&qcom->dwc3->dev);
+ max_speed = usb_get_maximum_speed(qcom->dwc->dev);
if (max_speed >= USB_SPEED_SUPER || max_speed == USB_SPEED_UNKNOWN) {
ret = icc_set_bw(qcom->icc_path_ddr,
USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
@@ -302,25 +306,16 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
/* Only usable in contexts where the role can not change. */
static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
{
- struct dwc3 *dwc;
-
- /*
- * FIXME: Fix this layering violation.
- */
- dwc = platform_get_drvdata(qcom->dwc3);
-
- /* Core driver may not have probed yet. */
- if (!dwc)
- return false;
+ struct dwc3 *dwc = qcom->dwc;
return dwc->xhci;
}
static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom, int port_index)
{
- struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
struct usb_device *udev;
struct usb_hcd __maybe_unused *hcd;
+ struct dwc3 *dwc = qcom->dwc;
/*
* FIXME: Fix this layering violation.
@@ -497,7 +492,7 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data)
{
struct dwc3_qcom *qcom = data;
- struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
+ struct dwc3 *dwc = qcom->dwc;
/* If pm_suspended then let pm_resume take care of resuming h/w */
if (qcom->pm_suspended)
@@ -699,34 +694,198 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
return 0;
}
-static int dwc3_qcom_of_register_core(struct dwc3_qcom *qcom, struct platform_device *pdev)
+static struct property *dwc3_qcom_legacy_prop_concat(const char *name,
+ const void *a, size_t a_len,
+ const void *b, size_t b_len)
{
- struct device_node *np = pdev->dev.of_node, *dwc3_np;
- struct device *dev = &pdev->dev;
- int ret;
+ size_t len = a_len + b_len;
- dwc3_np = of_get_compatible_child(np, "snps,dwc3");
- if (!dwc3_np) {
- dev_err(dev, "failed to find dwc3 core child\n");
- return -ENODEV;
- }
+ struct property *prop __free(kfree) = kzalloc(sizeof(*prop), GFP_KERNEL);
+ char *prop_name __free(kfree) = kstrdup(name, GFP_KERNEL);
+ void *value __free(kfree) = kzalloc(len, GFP_KERNEL);
+ if (!prop || !prop_name || !value)
+ return NULL;
- ret = of_platform_populate(np, NULL, NULL, dev);
- if (ret) {
- dev_err(dev, "failed to register dwc3 core - %d\n", ret);
- goto node_put;
+ prop->name = no_free_ptr(prop_name);
+ prop->value = no_free_ptr(value);
+ prop->length = len;
+
+ memcpy(prop->value, a, a_len);
+ memcpy(prop->value + a_len, b, b_len);
+
+ return_ptr(prop);
+}
+
+/* Replace reg property with base address from dwc3 node and fixed length */
+static int dwc3_qcom_legacy_update_reg(struct device_node *qcom,
+ struct device_node *dwc3)
+{
+ int addr_cells;
+ int size_cells;
+ u64 dwc3_addr;
+ int ret;
+
+ ret = of_property_read_reg(dwc3, 0, &dwc3_addr, NULL);
+ if (ret < 0)
+ return ret;
+
+ addr_cells = of_n_addr_cells(qcom);
+ size_cells = of_n_addr_cells(qcom);
+
+ __be32 *reg __free(kfree) = kcalloc(addr_cells + size_cells, sizeof(__be32), GFP_KERNEL);
+ if (!reg)
+ return -ENOMEM;
+
+ reg[addr_cells - 1] = cpu_to_be32(dwc3_addr);
+ reg[addr_cells + size_cells - 1] = cpu_to_be32(SDM845_QSCRATCH_BASE_OFFSET + SDM845_QSCRATCH_SIZE);
+
+ struct property *prop __free(kfree) = kzalloc(sizeof(*prop), GFP_KERNEL);
+ char *name __free(kfree) = kstrdup("reg", GFP_KERNEL);
+ if (!prop || !name)
+ return -ENOMEM;
+
+ prop->name = no_free_ptr(name);
+ prop->value = no_free_ptr(reg);
+ prop->length = (addr_cells + size_cells) * sizeof(__be32);
+
+ return of_update_property(qcom, no_free_ptr(prop));
+}
+
+/* Prepend dwc_usb3 interrupt to relevant interrupt properties */
+static int dwc3_qcom_legacy_convert_interrupts(struct device_node *qcom,
+ struct property *dwc3_irq)
+{
+ const __be32 *interrupts;
+ struct property *new;
+ const void *names;
+ int interrupts_len;
+ int names_len;
+ int ret;
+
+ if ((interrupts = of_get_property(qcom, "interrupts-extended", &interrupts_len)) != NULL) {
+ struct device_node *parent __free(device_node) = of_irq_find_parent(qcom);
+ if (!parent)
+ return -EINVAL;
+
+ __be32 *value __free(kfree) = kzalloc(sizeof(__be32) + dwc3_irq->length, GFP_KERNEL);
+ if (!value)
+ return -ENOMEM;
+ value[0] = cpu_to_be32(parent->phandle);
+ memcpy(&value[1], dwc3_irq->value, dwc3_irq->length);
+
+ new = dwc3_qcom_legacy_prop_concat("interrupts-extended",
+ value, sizeof(__be32) + dwc3_irq->length,
+ interrupts, interrupts_len);
+ } else if ((interrupts = of_get_property(qcom, "interrupts", &interrupts_len)) != NULL) {
+ new = dwc3_qcom_legacy_prop_concat("interrupts",
+ dwc3_irq->value, dwc3_irq->length,
+ interrupts, interrupts_len);
+ } else {
+ return -EINVAL;
}
- qcom->dwc3 = of_find_device_by_node(dwc3_np);
- if (!qcom->dwc3) {
- ret = -ENODEV;
- dev_err(dev, "failed to get dwc3 platform device\n");
- of_platform_depopulate(dev);
+ if (!new)
+ return -ENOMEM;
+
+ ret = of_update_property(qcom, new);
+ if (ret < 0)
+ return ret;
+
+ names = of_get_property(qcom, "interrupt-names", &names_len);
+ if (!names)
+ return -EINVAL;
+
+ new = dwc3_qcom_legacy_prop_concat("interrupt-names",
+ "dwc_usb3", strlen("dwc_usb3") + 1,
+ names, names_len);
+ if (!new)
+ return -ENOMEM;
+
+ return of_update_property(qcom, new);
+}
+
+/* Copy property to qcom node */
+static int dwc3_qcom_legacy_migrate_prop(struct device_node *qcom,
+ struct property *prop)
+{
+ struct property *new __free(kfree) = kzalloc(sizeof(*new), GFP_KERNEL);
+ char *name __free(kfree) = kstrdup(prop->name, GFP_KERNEL);
+ void *value __free(kfree) = kmemdup(prop->value, prop->length, GFP_KERNEL);
+
+ if (!new || !name || !value)
+ return -ENOMEM;
+
+ new->name = no_free_ptr(name);
+ new->value = no_free_ptr(value);
+ new->length = prop->length;
+
+ return of_update_property(qcom, no_free_ptr(new));
+}
+
+/* Move a child node, with it's properties and children, from dwc3 to qcom node */
+static int dwc3_qcom_legacy_migrate_child(struct device_node *qcom,
+ struct device_node *dwc3,
+ const char *name)
+{
+ struct device_node *child;
+
+ child = of_get_child_by_name(dwc3, name);
+ if (!child)
+ return 0;
+
+ of_detach_node(child);
+ child->parent = qcom;
+ of_attach_node(child);
+ of_node_put(child);
+
+ return 0;
+}
+
+/* Convert dev's DeviceTree representation from qcom,dwc3 to qcom,snps-dwc3 binding */
+static int dwc3_qcom_convert_legacy_dt(struct device *dev)
+{
+ struct device_node *qcom = dev->of_node;
+ struct device_node *dwc3;
+ struct property *prop;
+ int ret = 0;
+
+ dwc3 = of_get_compatible_child(qcom, "snps,dwc3");
+ if (!dwc3)
+ return 0;
+
+ /* We have a child node, but no support for dynamic OF */
+ if (!IS_ENABLED(CONFIG_OF_DYNAMIC))
+ return -EINVAL;
+
+ for_each_property_of_node(dwc3, prop) {
+ if (!strcmp(prop->name, "compatible"))
+ ;
+ else if (!strcmp(prop->name, "reg"))
+ ret = dwc3_qcom_legacy_update_reg(qcom, dwc3);
+ else if (!strcmp(prop->name, "interrupts"))
+ ret = dwc3_qcom_legacy_convert_interrupts(qcom, prop);
+ else
+ ret = dwc3_qcom_legacy_migrate_prop(qcom, prop);
}
-node_put:
- of_node_put(dwc3_np);
+ if (ret < 0)
+ goto err_node_put;
+
+ ret = dwc3_qcom_legacy_migrate_child(qcom, dwc3, "port");
+ if (ret)
+ goto err_node_put;
+
+ ret = dwc3_qcom_legacy_migrate_child(qcom, dwc3, "ports");
+ if (ret)
+ goto err_node_put;
+
+ of_detach_node(dwc3);
+ of_node_put(dwc3);
+ return 0;
+
+err_node_put:
+ of_node_put(dwc3);
return ret;
}
@@ -735,16 +894,21 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct dwc3_qcom *qcom;
- struct resource *res;
+ struct resource res;
int ret, i;
bool ignore_pipe_clk;
bool wakeup_source;
+ ret = dwc3_qcom_convert_legacy_dt(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to convert legacy OF node\n");
+ return ret;
+ }
+
qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL);
if (!qcom)
return -ENOMEM;
- platform_set_drvdata(pdev, qcom);
qcom->dev = &pdev->dev;
qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
@@ -773,10 +937,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
goto reset_assert;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret < 0)
+ goto clk_disable;
+ res.end = res.start + SDM845_QSCRATCH_BASE_OFFSET;
- qcom->qscratch_base = devm_ioremap_resource(dev, res);
+ qcom->qscratch_base = devm_ioremap(dev, res.end, SDM845_QSCRATCH_SIZE);
if (IS_ERR(qcom->qscratch_base)) {
+ dev_err(dev, "failed to map qscratch region: %pe\n", qcom->qscratch_base);
ret = PTR_ERR(qcom->qscratch_base);
goto clk_disable;
}
@@ -796,17 +964,17 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
if (ignore_pipe_clk)
dwc3_qcom_select_utmi_clk(qcom);
- ret = dwc3_qcom_of_register_core(qcom, pdev);
- if (ret) {
- dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
+ qcom->dwc = dwc3_probe(pdev, &res, true, qcom);
+ if (IS_ERR(qcom->dwc)) {
+ ret = dev_err_probe(dev, PTR_ERR(qcom->dwc), "failed to register DWC3 Core\n");
goto clk_disable;
}
ret = dwc3_qcom_interconnect_init(qcom);
if (ret)
- goto depopulate;
+ goto remove_core;
- qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev);
+ qcom->mode = usb_get_dr_mode(dev);
/* enable vbus override for device mode */
if (qcom->mode != USB_DR_MODE_HOST)
@@ -819,20 +987,15 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source");
device_init_wakeup(&pdev->dev, wakeup_source);
- device_init_wakeup(&qcom->dwc3->dev, wakeup_source);
qcom->is_suspended = false;
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- pm_runtime_forbid(dev);
return 0;
interconnect_exit:
dwc3_qcom_interconnect_exit(qcom);
-depopulate:
- of_platform_depopulate(&pdev->dev);
- platform_device_put(qcom->dwc3);
+remove_core:
+ dwc3_remove(qcom->dwc);
clk_disable:
for (i = qcom->num_clocks - 1; i >= 0; i--) {
clk_disable_unprepare(qcom->clks[i]);
@@ -846,13 +1009,11 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
static void dwc3_qcom_remove(struct platform_device *pdev)
{
- struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+ struct dwc3 *dwc = platform_get_drvdata(pdev);
+ struct dwc3_qcom *qcom = dwc->glue;
struct device *dev = &pdev->dev;
int i;
- of_platform_depopulate(&pdev->dev);
- platform_device_put(qcom->dwc3);
-
for (i = qcom->num_clocks - 1; i >= 0; i--) {
clk_disable_unprepare(qcom->clks[i]);
clk_put(qcom->clks[i]);
@@ -868,10 +1029,15 @@ static void dwc3_qcom_remove(struct platform_device *pdev)
static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
{
- struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct dwc3_qcom *qcom = dwc->glue;
bool wakeup = device_may_wakeup(dev);
int ret;
+ ret = dwc3_suspend(qcom->dwc);
+ if (ret)
+ return ret;
+
ret = dwc3_qcom_suspend(qcom, wakeup);
if (ret)
return ret;
@@ -883,7 +1049,8 @@ static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
{
- struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct dwc3_qcom *qcom = dwc->glue;
bool wakeup = device_may_wakeup(dev);
int ret;
@@ -893,31 +1060,56 @@ static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
qcom->pm_suspended = false;
+ ret = dwc3_suspend(qcom->dwc);
+ if (ret)
+ return ret;
+
return 0;
}
static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev)
{
- struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct dwc3_qcom *qcom = dwc->glue;
+ int ret;
+
+ ret = dwc3_runtime_suspend(qcom->dwc);
+ if (ret)
+ return ret;
return dwc3_qcom_suspend(qcom, true);
}
+static void __maybe_unused dwc3_qcom_complete(struct device *dev)
+{
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+
+ dwc3_complete(dwc);
+}
+
static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev)
{
- struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct dwc3_qcom *qcom = dwc->glue;
+ int ret;
+
+ ret = dwc3_qcom_resume(qcom, true);
+ if (ret)
+ return ret;
- return dwc3_qcom_resume(qcom, true);
+ return dwc3_runtime_resume(qcom->dwc);
}
static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume)
SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume,
NULL)
+ .complete = dwc3_qcom_complete,
};
static const struct of_device_id dwc3_qcom_of_match[] = {
{ .compatible = "qcom,dwc3" },
+ { .compatible = "qcom,snps-dwc3" },
{ }
};
MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
--
2.45.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH v2 7/7] arm64: dts: qcom: sc8280x: Flatten the USB nodes
2024-08-12 3:11 [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Bjorn Andersson
` (5 preceding siblings ...)
2024-08-12 3:12 ` [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model Bjorn Andersson
@ 2024-08-12 3:12 ` Bjorn Andersson
2024-08-13 18:07 ` [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Frank Li
7 siblings, 0 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-12 3:12 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Bjorn Andersson, Konrad Dybcio
Cc: linux-usb, devicetree, linux-kernel, linux-arm-msm,
Bjorn Andersson
From: Bjorn Andersson <quic_bjorande@quicinc.com>
Transition the three USB controllers found in sc8280xp to the newly
introduced, flattened representation of the Qualcomm USB block, i.e.
qcom,snps-dwc3, to show the end result.
The reg and interrupts properties from the usb child node are merged
with their counterpart in the outer node, remaining properties and child
nodes are simply moved.
Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
---
arch/arm64/boot/dts/qcom/sa8295p-adp.dts | 12 +-
arch/arm64/boot/dts/qcom/sa8540p-ride.dts | 5 +-
arch/arm64/boot/dts/qcom/sc8280xp-crd.dts | 12 +-
.../dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts | 11 +-
arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 138 +++++++++------------
5 files changed, 74 insertions(+), 104 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/sa8295p-adp.dts b/arch/arm64/boot/dts/qcom/sa8295p-adp.dts
index 78e933c42c31..f19c39a34607 100644
--- a/arch/arm64/boot/dts/qcom/sa8295p-adp.dts
+++ b/arch/arm64/boot/dts/qcom/sa8295p-adp.dts
@@ -590,12 +590,10 @@ &ufs_card_phy {
};
&usb_0 {
- status = "okay";
-};
-
-&usb_0_dwc3 {
/* TODO: Define USB-C connector properly */
dr_mode = "peripheral";
+
+ status = "okay";
};
&usb_0_hsphy {
@@ -614,12 +612,10 @@ &usb_0_qmpphy {
};
&usb_1 {
- status = "okay";
-};
-
-&usb_1_dwc3 {
/* TODO: Define USB-C connector properly */
dr_mode = "host";
+
+ status = "okay";
};
&usb_1_hsphy {
diff --git a/arch/arm64/boot/dts/qcom/sa8540p-ride.dts b/arch/arm64/boot/dts/qcom/sa8540p-ride.dts
index 177b9dad6ff7..7be803fb7cbe 100644
--- a/arch/arm64/boot/dts/qcom/sa8540p-ride.dts
+++ b/arch/arm64/boot/dts/qcom/sa8540p-ride.dts
@@ -466,11 +466,8 @@ &ufs_mem_phy {
};
&usb_0 {
- status = "okay";
-};
-
-&usb_0_dwc3 {
dr_mode = "peripheral";
+ status = "okay";
};
&usb_0_hsphy {
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts
index b98b2f7752b5..c910c7096e11 100644
--- a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts
+++ b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts
@@ -668,11 +668,9 @@ &ufs_mem_phy {
};
&usb_0 {
- status = "okay";
-};
-
-&usb_0_dwc3 {
dr_mode = "host";
+
+ status = "okay";
};
&usb_0_dwc3_hs {
@@ -705,11 +703,9 @@ &usb_0_qmpphy_out {
};
&usb_1 {
- status = "okay";
-};
-
-&usb_1_dwc3 {
dr_mode = "host";
+
+ status = "okay";
};
&usb_1_dwc3_hs {
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts
index b27143f81867..f66c87e0c10c 100644
--- a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts
+++ b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts
@@ -1225,11 +1225,9 @@ bluetooth {
};
&usb_0 {
- status = "okay";
-};
-
-&usb_0_dwc3 {
dr_mode = "host";
+
+ status = "okay";
};
&usb_0_dwc3_hs {
@@ -1262,11 +1260,8 @@ &usb_0_qmpphy_out {
};
&usb_1 {
- status = "okay";
-};
-
-&usb_1_dwc3 {
dr_mode = "host";
+ status = "okay";
};
&usb_1_dwc3_hs {
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
index 80a57aa22839..f4c8f76c0bea 100644
--- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
@@ -3439,12 +3439,9 @@ system-cache-controller@9200000 {
interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
};
- usb_2: usb@a4f8800 {
- compatible = "qcom,sc8280xp-dwc3-mp", "qcom,dwc3";
- reg = <0 0x0a4f8800 0 0x400>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
+ usb_2: usb@a400000 {
+ compatible = "qcom,sc8280xp-dwc3-mp", "qcom,snps-dwc3";
+ reg = <0 0x0a400000 0 0x10000>;
clocks = <&gcc GCC_CFG_NOC_USB3_MP_AXI_CLK>,
<&gcc GCC_USB30_MP_MASTER_CLK>,
@@ -3462,7 +3459,8 @@ usb_2: usb@a4f8800 {
<&gcc GCC_USB30_MP_MASTER_CLK>;
assigned-clock-rates = <19200000>, <200000000>;
- interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+ interrupts-extended = <&intc GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
<&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
<&intc GIC_SPI 857 IRQ_TYPE_LEVEL_HIGH>,
<&intc GIC_SPI 856 IRQ_TYPE_LEVEL_HIGH>,
@@ -3481,7 +3479,8 @@ usb_2: usb@a4f8800 {
<&pdc 16 IRQ_TYPE_LEVEL_HIGH>,
<&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "pwr_event_1", "pwr_event_2",
+ interrupt-names = "dwc_usb3",
+ "pwr_event_1", "pwr_event_2",
"pwr_event_3", "pwr_event_4",
"hs_phy_1", "hs_phy_2",
"hs_phy_3", "hs_phy_4",
@@ -3491,6 +3490,7 @@ usb_2: usb@a4f8800 {
"dp_hs_phy_4", "dm_hs_phy_4",
"ss_phy_1", "ss_phy_2";
+ iommus = <&apps_smmu 0x800 0x0>;
power-domains = <&gcc USB30_MP_GDSC>;
required-opps = <&rpmhpd_opp_nom>;
@@ -3500,33 +3500,25 @@ usb_2: usb@a4f8800 {
<&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_MP 0>;
interconnect-names = "usb-ddr", "apps-usb";
+ phys = <&usb_2_hsphy0>, <&usb_2_qmpphy0>,
+ <&usb_2_hsphy1>, <&usb_2_qmpphy1>,
+ <&usb_2_hsphy2>,
+ <&usb_2_hsphy3>;
+ phy-names = "usb2-0", "usb3-0",
+ "usb2-1", "usb3-1",
+ "usb2-2",
+ "usb2-3";
+
wakeup-source;
- status = "disabled";
+ dr_mode = "host";
- usb_2_dwc3: usb@a400000 {
- compatible = "snps,dwc3";
- reg = <0 0x0a400000 0 0xcd00>;
- interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
- iommus = <&apps_smmu 0x800 0x0>;
- phys = <&usb_2_hsphy0>, <&usb_2_qmpphy0>,
- <&usb_2_hsphy1>, <&usb_2_qmpphy1>,
- <&usb_2_hsphy2>,
- <&usb_2_hsphy3>;
- phy-names = "usb2-0", "usb3-0",
- "usb2-1", "usb3-1",
- "usb2-2",
- "usb2-3";
- dr_mode = "host";
- };
+ status = "disabled";
};
- usb_0: usb@a6f8800 {
- compatible = "qcom,sc8280xp-dwc3", "qcom,dwc3";
- reg = <0 0x0a6f8800 0 0x400>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
+ usb_0: usb@a600000 {
+ compatible = "qcom,sc8280xp-dwc3", "qcom,snps-dwc3";
+ reg = <0 0x0a600000 0 0x20000>;
clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>,
<&gcc GCC_USB30_PRIM_MASTER_CLK>,
@@ -3544,17 +3536,20 @@ usb_0: usb@a6f8800 {
<&gcc GCC_USB30_PRIM_MASTER_CLK>;
assigned-clock-rates = <19200000>, <200000000>;
- interrupts-extended = <&intc GIC_SPI 804 IRQ_TYPE_LEVEL_HIGH>,
+ interrupts-extended = <&intc GIC_SPI 803 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 804 IRQ_TYPE_LEVEL_HIGH>,
<&intc GIC_SPI 805 IRQ_TYPE_LEVEL_HIGH>,
<&pdc 14 IRQ_TYPE_EDGE_BOTH>,
<&pdc 15 IRQ_TYPE_EDGE_BOTH>,
<&pdc 138 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "pwr_event",
+ interrupt-names = "dwc_usb3",
+ "pwr_event",
"hs_phy_irq",
"dp_hs_phy_irq",
"dm_hs_phy_irq",
"ss_phy_irq";
+ iommus = <&apps_smmu 0x820 0x0>;
power-domains = <&gcc USB30_PRIM_GDSC>;
required-opps = <&rpmhpd_opp_nom>;
@@ -3564,43 +3559,37 @@ usb_0: usb@a6f8800 {
<&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_0 0>;
interconnect-names = "usb-ddr", "apps-usb";
+ phys = <&usb_0_hsphy>, <&usb_0_qmpphy QMP_USB43DP_USB3_PHY>;
+ phy-names = "usb2-phy", "usb3-phy";
+
wakeup-source;
status = "disabled";
- usb_0_dwc3: usb@a600000 {
- compatible = "snps,dwc3";
- reg = <0 0x0a600000 0 0xcd00>;
- interrupts = <GIC_SPI 803 IRQ_TYPE_LEVEL_HIGH>;
- iommus = <&apps_smmu 0x820 0x0>;
- phys = <&usb_0_hsphy>, <&usb_0_qmpphy QMP_USB43DP_USB3_PHY>;
- phy-names = "usb2-phy", "usb3-phy";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
- port@0 {
- reg = <0>;
+ port@0 {
+ reg = <0>;
- usb_0_dwc3_hs: endpoint {
- };
+ usb_0_dwc3_hs: endpoint {
};
+ };
- port@1 {
- reg = <1>;
+ port@1 {
+ reg = <1>;
- usb_0_dwc3_ss: endpoint {
- remote-endpoint = <&usb_0_qmpphy_usb_ss_in>;
- };
+ usb_0_dwc3_ss: endpoint {
+ remote-endpoint = <&usb_0_qmpphy_usb_ss_in>;
};
};
};
};
- usb_1: usb@a8f8800 {
+ usb_1: usb@a800000 {
compatible = "qcom,sc8280xp-dwc3", "qcom,dwc3";
- reg = <0 0x0a8f8800 0 0x400>;
+ reg = <0 0x0a800000 0 0x10000>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
@@ -3621,17 +3610,20 @@ usb_1: usb@a8f8800 {
<&gcc GCC_USB30_SEC_MASTER_CLK>;
assigned-clock-rates = <19200000>, <200000000>;
- interrupts-extended = <&intc GIC_SPI 811 IRQ_TYPE_LEVEL_HIGH>,
+ interrupts-extended = <&intc GIC_SPI 810 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 811 IRQ_TYPE_LEVEL_HIGH>,
<&intc GIC_SPI 790 IRQ_TYPE_LEVEL_HIGH>,
<&pdc 12 IRQ_TYPE_EDGE_BOTH>,
<&pdc 13 IRQ_TYPE_EDGE_BOTH>,
<&pdc 136 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "pwr_event",
+ interrupt-names = "dwc_usb3",
+ "pwr_event",
"hs_phy_irq",
"dp_hs_phy_irq",
"dm_hs_phy_irq",
"ss_phy_irq";
+ iommus = <&apps_smmu 0x860 0x0>;
power-domains = <&gcc USB30_SEC_GDSC>;
required-opps = <&rpmhpd_opp_nom>;
@@ -3641,35 +3633,29 @@ usb_1: usb@a8f8800 {
<&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_1 0>;
interconnect-names = "usb-ddr", "apps-usb";
+ phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>;
+ phy-names = "usb2-phy", "usb3-phy";
+
wakeup-source;
status = "disabled";
- usb_1_dwc3: usb@a800000 {
- compatible = "snps,dwc3";
- reg = <0 0x0a800000 0 0xcd00>;
- interrupts = <GIC_SPI 810 IRQ_TYPE_LEVEL_HIGH>;
- iommus = <&apps_smmu 0x860 0x0>;
- phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>;
- phy-names = "usb2-phy", "usb3-phy";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
- port@0 {
- reg = <0>;
+ port@0 {
+ reg = <0>;
- usb_1_dwc3_hs: endpoint {
- };
+ usb_1_dwc3_hs: endpoint {
};
+ };
- port@1 {
- reg = <1>;
+ port@1 {
+ reg = <1>;
- usb_1_dwc3_ss: endpoint {
- remote-endpoint = <&usb_1_qmpphy_usb_ss_in>;
- };
+ usb_1_dwc3_ss: endpoint {
+ remote-endpoint = <&usb_1_qmpphy_usb_ss_in>;
};
};
};
--
2.45.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH v2 2/7] dt-bindings: usb: Introduce qcom,snps-dwc3
2024-08-12 3:11 ` [PATCH v2 2/7] dt-bindings: usb: Introduce qcom,snps-dwc3 Bjorn Andersson
@ 2024-08-12 4:32 ` Rob Herring (Arm)
0 siblings, 0 replies; 37+ messages in thread
From: Rob Herring (Arm) @ 2024-08-12 4:32 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Krzysztof Kozlowski, Konrad Dybcio, Thinh Nguyen,
Greg Kroah-Hartman, Felipe Balbi, devicetree, linux-kernel,
Wesley Cheng, Saravana Kannan, Conor Dooley, linux-usb,
linux-arm-msm, Philipp Zabel, Bjorn Andersson
On Sun, 11 Aug 2024 20:11:59 -0700, Bjorn Andersson wrote:
> From: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> The Qualcomm USB glue is not separate of the Synopsys DWC3 core and
> several of the snps,dwc3 properties (such as clocks and reset) conflicts
> in expectation with the Qualcomm integration.
>
> Using the newly split out Synopsys DWC3 core properties, describe the
> Qualcomm USB block in a single block. The new binding is a copy of
> qcom,dwc3 with the needed modifications.
>
> It would have been convenient to retain the two structures with the same
> compatibles, but as there exist no way to select a binding based on the
> absence of a subnode/patternProperty, a new generic compatible is
> introduced to describe this binding.
>
> To avoid redefining all the platform-specific compatibles, "select" is
> used to tell the DeviceTree validator which binding to use solely on the
> generic compatible. (Otherwise if the specific compatible matches during
> validation, the generic one must match as well)
>
> Mark qcom,dwc3 deprecated, to favor expressing future platforms using
> the new combined binding.
>
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> ---
> .../devicetree/bindings/usb/qcom,dwc3.yaml | 13 +-
> .../devicetree/bindings/usb/qcom,snps-dwc3.yaml | 608 +++++++++++++++++++++
> 2 files changed, 620 insertions(+), 1 deletion(-)
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.example.dtb: usb@a600000: False schema does not allow {'compatible': ['qcom,sdm845-dwc3', 'qcom,snps-dwc3'], 'reg': [[0, 174063616, 0, 1048576]], 'clocks': [[4294967295, 12], [4294967295, 141], [4294967295, 3], [4294967295, 145], [4294967295, 143]], 'clock-names': ['cfg_noc', 'core', 'iface', 'sleep', 'mock_utmi'], 'assigned-clocks': [[4294967295, 143], [4294967295, 141]], 'assigned-clock-rates': [19200000, 150000000], 'interrupts': [[0, 133, 4], [0, 130, 4], [0, 131, 4], [0, 489, 3], [0, 488, 3], [0, 486, 4]], 'interrupt-names': ['dwc_usb3', 'pwr_event', 'hs_phy_irq', 'dp_hs_phy_irq', 'dm_hs_phy_irq', 'ss_phy_irq'], 'power-domains': [[4294967295, 4]], 'resets': [[4294967295, 15]], 'iommus': [[4294967295, 1856, 0]], 'snps,dis_u2_susphy_quirk': True, 'snps,dis_enblslpm_quirk': True, 'phys': [[4294967295], [4294967295]], 'phy-names': ['usb2-phy', 'usb3-phy'], '$nodename': ['usb@a600000']}
from schema $id: http://devicetree.org/schemas/usb/qcom,snps-dwc3.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.example.dtb: usb@a600000: Unevaluated properties are not allowed ('phy-names', 'phys', 'snps,dis_enblslpm_quirk', 'snps,dis_u2_susphy_quirk' were unexpected)
from schema $id: http://devicetree.org/schemas/usb/qcom,snps-dwc3.yaml#
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20240811-dwc3-refactor-v2-2-91f370d61ad2@quicinc.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-12 3:12 ` [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library Bjorn Andersson
@ 2024-08-12 12:21 ` kernel test robot
2024-08-12 19:00 ` Bjorn Andersson
2024-08-12 12:21 ` kernel test robot
` (4 subsequent siblings)
5 siblings, 1 reply; 37+ messages in thread
From: kernel test robot @ 2024-08-12 12:21 UTC (permalink / raw)
To: Bjorn Andersson, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Felipe Balbi, Wesley Cheng,
Saravana Kannan, Thinh Nguyen, Philipp Zabel, Konrad Dybcio
Cc: oe-kbuild-all, linux-usb, devicetree, linux-kernel, linux-arm-msm
Hi Bjorn,
kernel test robot noticed the following build errors:
[auto build test ERROR on 864b1099d16fc7e332c3ad7823058c65f890486c]
url: https://github.com/intel-lab-lkp/linux/commits/Bjorn-Andersson/dt-bindings-usb-snps-dwc3-Split-core-description/20240812-111102
base: 864b1099d16fc7e332c3ad7823058c65f890486c
patch link: https://lore.kernel.org/r/20240811-dwc3-refactor-v2-4-91f370d61ad2%40quicinc.com
patch subject: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
config: i386-buildonly-randconfig-005-20240812 (https://download.01.org/0day-ci/archive/20240812/202408122011.adSQGOUp-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240812/202408122011.adSQGOUp-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408122011.adSQGOUp-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/usb/dwc3/core.c:39:10: fatal error: glue.h: No such file or directory
39 | #include "glue.h"
| ^~~~~~~~
compilation terminated.
vim +39 drivers/usb/dwc3/core.c
36
37 #include "core.h"
38 #include "gadget.h"
> 39 #include "glue.h"
40 #include "io.h"
41
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-12 3:12 ` [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library Bjorn Andersson
2024-08-12 12:21 ` kernel test robot
@ 2024-08-12 12:21 ` kernel test robot
2024-08-13 18:15 ` Frank Li
` (3 subsequent siblings)
5 siblings, 0 replies; 37+ messages in thread
From: kernel test robot @ 2024-08-12 12:21 UTC (permalink / raw)
To: Bjorn Andersson, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Felipe Balbi, Wesley Cheng,
Saravana Kannan, Thinh Nguyen, Philipp Zabel, Konrad Dybcio
Cc: llvm, oe-kbuild-all, linux-usb, devicetree, linux-kernel,
linux-arm-msm
Hi Bjorn,
kernel test robot noticed the following build errors:
[auto build test ERROR on 864b1099d16fc7e332c3ad7823058c65f890486c]
url: https://github.com/intel-lab-lkp/linux/commits/Bjorn-Andersson/dt-bindings-usb-snps-dwc3-Split-core-description/20240812-111102
base: 864b1099d16fc7e332c3ad7823058c65f890486c
patch link: https://lore.kernel.org/r/20240811-dwc3-refactor-v2-4-91f370d61ad2%40quicinc.com
patch subject: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
config: i386-buildonly-randconfig-002-20240812 (https://download.01.org/0day-ci/archive/20240812/202408122054.h09BWBT2-lkp@intel.com/config)
compiler: clang version 18.1.5 (https://github.com/llvm/llvm-project 617a15a9eac96088ae5e9134248d8236e34b91b1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240812/202408122054.h09BWBT2-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408122054.h09BWBT2-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/usb/dwc3/core.c:39:10: fatal error: 'glue.h' file not found
39 | #include "glue.h"
| ^~~~~~~~
1 error generated.
vim +39 drivers/usb/dwc3/core.c
36
37 #include "core.h"
38 #include "gadget.h"
> 39 #include "glue.h"
40 #include "io.h"
41
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model
2024-08-12 3:12 ` [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model Bjorn Andersson
@ 2024-08-12 13:33 ` kernel test robot
2024-08-12 21:21 ` Rob Herring
2024-08-13 18:33 ` Frank Li
2 siblings, 0 replies; 37+ messages in thread
From: kernel test robot @ 2024-08-12 13:33 UTC (permalink / raw)
To: Bjorn Andersson, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Felipe Balbi, Wesley Cheng,
Saravana Kannan, Thinh Nguyen, Philipp Zabel, Konrad Dybcio
Cc: llvm, oe-kbuild-all, linux-usb, devicetree, linux-kernel,
linux-arm-msm
Hi Bjorn,
kernel test robot noticed the following build errors:
[auto build test ERROR on 864b1099d16fc7e332c3ad7823058c65f890486c]
url: https://github.com/intel-lab-lkp/linux/commits/Bjorn-Andersson/dt-bindings-usb-snps-dwc3-Split-core-description/20240812-111102
base: 864b1099d16fc7e332c3ad7823058c65f890486c
patch link: https://lore.kernel.org/r/20240811-dwc3-refactor-v2-6-91f370d61ad2%40quicinc.com
patch subject: [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model
config: i386-buildonly-randconfig-002-20240812 (https://download.01.org/0day-ci/archive/20240812/202408122114.xvZqrjZ7-lkp@intel.com/config)
compiler: clang version 18.1.5 (https://github.com/llvm/llvm-project 617a15a9eac96088ae5e9134248d8236e34b91b1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240812/202408122114.xvZqrjZ7-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408122114.xvZqrjZ7-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/usb/dwc3/dwc3-qcom.c:28:10: fatal error: 'glue.h' file not found
28 | #include "glue.h"
| ^~~~~~~~
1 error generated.
vim +28 drivers/usb/dwc3/dwc3-qcom.c
> 28 #include "glue.h"
29
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-12 12:21 ` kernel test robot
@ 2024-08-12 19:00 ` Bjorn Andersson
0 siblings, 0 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-12 19:00 UTC (permalink / raw)
To: kernel test robot
Cc: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio, oe-kbuild-all,
linux-usb, devicetree, linux-kernel, linux-arm-msm
On Mon, Aug 12, 2024 at 08:21:54PM GMT, kernel test robot wrote:
> Hi Bjorn,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on 864b1099d16fc7e332c3ad7823058c65f890486c]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Bjorn-Andersson/dt-bindings-usb-snps-dwc3-Split-core-description/20240812-111102
> base: 864b1099d16fc7e332c3ad7823058c65f890486c
> patch link: https://lore.kernel.org/r/20240811-dwc3-refactor-v2-4-91f370d61ad2%40quicinc.com
> patch subject: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
> config: i386-buildonly-randconfig-005-20240812 (https://download.01.org/0day-ci/archive/20240812/202408122011.adSQGOUp-lkp@intel.com/config)
> compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240812/202408122011.adSQGOUp-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202408122011.adSQGOUp-lkp@intel.com/
>
> All errors (new ones prefixed by >>):
>
> >> drivers/usb/dwc3/core.c:39:10: fatal error: glue.h: No such file or directory
> 39 | #include "glue.h"
> | ^~~~~~~~
> compilation terminated.
Sorry about that, seems I missed the git add on the header file where I
declare the exported symbols.
Regards,
Bjorn
>
>
> vim +39 drivers/usb/dwc3/core.c
>
> 36
> 37 #include "core.h"
> 38 #include "gadget.h"
> > 39 #include "glue.h"
> 40 #include "io.h"
> 41
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 3/7] of: dynamic: Don't discard children upon node attach
2024-08-12 3:12 ` [PATCH v2 3/7] of: dynamic: Don't discard children upon node attach Bjorn Andersson
@ 2024-08-12 20:24 ` Rob Herring
2024-08-12 21:21 ` Bjorn Andersson
0 siblings, 1 reply; 37+ messages in thread
From: Rob Herring @ 2024-08-12 20:24 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Greg Kroah-Hartman, Krzysztof Kozlowski, Conor Dooley,
Felipe Balbi, Wesley Cheng, Saravana Kannan, Thinh Nguyen,
Philipp Zabel, Konrad Dybcio, linux-usb, devicetree, linux-kernel,
linux-arm-msm, Bjorn Andersson
On Sun, Aug 11, 2024 at 9:07 PM Bjorn Andersson <andersson@kernel.org> wrote:
>
> From: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> When dynamically modifying DeviceTree it's useful to be able to reparent
> nodes, but of_attach_node() clear the child pointer and hence discards
> any child nodes.
of_attach_node() is kind of the legacy API. You should be using
changeset API. But I guess you really mean __of_attach_node() here
which both use.
> Retain the child pointer upon attach, so that the client code doesn't
> need to manually rebuild the tree.
>
> Current users of of_attach_node() either avoids attaching nodes with
> children or explicitly attaches nodes without children, so no impact is
> expected to current users.
>
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> ---
> drivers/of/dynamic.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
> index 110104a936d9..32e1dffd9f96 100644
> --- a/drivers/of/dynamic.c
> +++ b/drivers/of/dynamic.c
> @@ -221,7 +221,6 @@ static void __of_attach_node(struct device_node *np)
> np->phandle = 0;
> }
>
> - np->child = NULL;
> np->sibling = np->parent->child;
> np->parent->child = np;
> of_node_clear_flag(np, OF_DETACHED);
Before OF_DETACHED had a clear meaning. Now, are child nodes detached
or not? If it means not attached to the root tree, then it is
redundant having it per node. If it means parent and sibling aren't
set, then what's the point as we can just check for NULL ptrs.
This all seems fragile on top of what's already fragile.
Rob
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model
2024-08-12 3:12 ` [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model Bjorn Andersson
2024-08-12 13:33 ` kernel test robot
@ 2024-08-12 21:21 ` Rob Herring
2024-08-12 22:16 ` Bjorn Andersson
2024-08-13 18:33 ` Frank Li
2 siblings, 1 reply; 37+ messages in thread
From: Rob Herring @ 2024-08-12 21:21 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Greg Kroah-Hartman, Krzysztof Kozlowski, Conor Dooley,
Felipe Balbi, Wesley Cheng, Saravana Kannan, Thinh Nguyen,
Philipp Zabel, Konrad Dybcio, linux-usb, devicetree, linux-kernel,
linux-arm-msm, Bjorn Andersson
On Sun, Aug 11, 2024 at 08:12:03PM -0700, Bjorn Andersson wrote:
> From: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> The USB IP-block found in most Qualcomm platforms is modelled in the
> Linux kernel as 3 different independent device drivers, but as shown by
> the already existing layering violations in the Qualcomm glue driver
> they can not be operated independently.
>
> With the current implementation, the glue driver registers the core and
> has no way to know when this is done. As a result, e.g. the suspend
> callbacks needs to guard against NULL pointer dereferences when trying
> to peek into the struct dwc3 found in the drvdata of the child.
> Even with these checks, there are no way to fully protect ourselves from
> the race conditions that occur if the DWC3 is unbound.
>
> Missing from the upstream Qualcomm USB support is handling of role
> switching, in which the glue needs to be notified upon DRD mode changes.
> Several attempts has been made through the years to register callbacks
> etc, but they always fall short when it comes to handling of the core's
> probe deferral on resources etc.
>
> Moving to a model where the DWC3 core is instantiated in a synchronous
> fashion avoids above described race conditions.
>
> It is however not feasible to do so without also flattening the
> DeviceTree binding, as assumptions are made in the DWC3 core and
> frameworks used that the device's associated of_node will the that of
> the core. Furthermore, the DeviceTree binding is a direct
> representation of the Linux driver model, and doesn't necessarily
> describe "the USB IP-block".
>
> The Qualcomm DWC3 glue driver is therefor transitioned to initialize and
> operate the DWC3 within the one device context, in synchronous fashion.
>
> To handle backwards compatibility, and to remove the two-device model,
> of_nodes of the old compatible are converted to the new one, early
> during probe.
>
> This happens in the event that a DWC3 core child node is present, the
> content of the reg and interrupt properties of this node are merged into
> the shared properties, all remaining properties are copied and the core
> node is dropped. Effectively transitioning the node from qcom,dwc3 to
> qcom,snps-dwc3.
In the past we've done this old binding to new binding with an overlay
embedded in the kernel. The overlay would just be the .dts change you've
made (we should have a tool that takes 2 DTs and generates an overlay as
the diff). I suppose it's a few platforms here, but then it is just data
and easily deleted when no longer needed (I think the cases I'm
remembering did just that because they are gone now. It was TI display
and Renesas media stuff IIRC).
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> ---
> drivers/usb/dwc3/dwc3-qcom.c | 310 +++++++++++++++++++++++++++++++++++--------
> 1 file changed, 251 insertions(+), 59 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
> index 33de03f2d782..27b5013cd411 100644
> --- a/drivers/usb/dwc3/dwc3-qcom.c
> +++ b/drivers/usb/dwc3/dwc3-qcom.c
> @@ -6,6 +6,7 @@
>
> #include <linux/io.h>
> #include <linux/of.h>
> +#include <linux/cleanup.h>
> #include <linux/clk.h>
> #include <linux/irq.h>
> #include <linux/of_clk.h>
> @@ -13,6 +14,8 @@
> #include <linux/kernel.h>
> #include <linux/extcon.h>
> #include <linux/interconnect.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
Not a good sign when these are needed...
> #include <linux/of_platform.h>
Probably don't need this one.
> #include <linux/platform_device.h>
> #include <linux/phy/phy.h>
> @@ -22,6 +25,7 @@
> #include <linux/usb/hcd.h>
> #include <linux/usb.h>
> #include "core.h"
> +#include "glue.h"
>
> /* USB QSCRATCH Hardware registers */
> #define QSCRATCH_HS_PHY_CTRL 0x10
> @@ -72,7 +76,7 @@ struct dwc3_qcom_port {
> struct dwc3_qcom {
> struct device *dev;
> void __iomem *qscratch_base;
> - struct platform_device *dwc3;
> + struct dwc3 *dwc;
> struct clk **clks;
> int num_clocks;
> struct reset_control *resets;
> @@ -259,7 +263,7 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
> goto put_path_ddr;
> }
>
> - max_speed = usb_get_maximum_speed(&qcom->dwc3->dev);
> + max_speed = usb_get_maximum_speed(qcom->dwc->dev);
> if (max_speed >= USB_SPEED_SUPER || max_speed == USB_SPEED_UNKNOWN) {
> ret = icc_set_bw(qcom->icc_path_ddr,
> USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
> @@ -302,25 +306,16 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
> /* Only usable in contexts where the role can not change. */
> static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
> {
> - struct dwc3 *dwc;
> -
> - /*
> - * FIXME: Fix this layering violation.
> - */
> - dwc = platform_get_drvdata(qcom->dwc3);
> -
> - /* Core driver may not have probed yet. */
> - if (!dwc)
> - return false;
> + struct dwc3 *dwc = qcom->dwc;
>
> return dwc->xhci;
> }
>
> static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom, int port_index)
> {
> - struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
> struct usb_device *udev;
> struct usb_hcd __maybe_unused *hcd;
> + struct dwc3 *dwc = qcom->dwc;
>
> /*
> * FIXME: Fix this layering violation.
> @@ -497,7 +492,7 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
> static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data)
> {
> struct dwc3_qcom *qcom = data;
> - struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
> + struct dwc3 *dwc = qcom->dwc;
>
> /* If pm_suspended then let pm_resume take care of resuming h/w */
> if (qcom->pm_suspended)
> @@ -699,34 +694,198 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
> return 0;
> }
>
> -static int dwc3_qcom_of_register_core(struct dwc3_qcom *qcom, struct platform_device *pdev)
> +static struct property *dwc3_qcom_legacy_prop_concat(const char *name,
> + const void *a, size_t a_len,
> + const void *b, size_t b_len)
> {
> - struct device_node *np = pdev->dev.of_node, *dwc3_np;
> - struct device *dev = &pdev->dev;
> - int ret;
> + size_t len = a_len + b_len;
>
> - dwc3_np = of_get_compatible_child(np, "snps,dwc3");
> - if (!dwc3_np) {
> - dev_err(dev, "failed to find dwc3 core child\n");
> - return -ENODEV;
> - }
> + struct property *prop __free(kfree) = kzalloc(sizeof(*prop), GFP_KERNEL);
> + char *prop_name __free(kfree) = kstrdup(name, GFP_KERNEL);
> + void *value __free(kfree) = kzalloc(len, GFP_KERNEL);
> + if (!prop || !prop_name || !value)
> + return NULL;
>
> - ret = of_platform_populate(np, NULL, NULL, dev);
> - if (ret) {
> - dev_err(dev, "failed to register dwc3 core - %d\n", ret);
> - goto node_put;
> + prop->name = no_free_ptr(prop_name);
> + prop->value = no_free_ptr(value);
> + prop->length = len;
We're trying to make struct property opaque or even internal to DT core.
Exposing it leaks pointers and then we can't ever free things. This is
not helping. The changeset API avoids mucking with struct property.
> +
> + memcpy(prop->value, a, a_len);
> + memcpy(prop->value + a_len, b, b_len);
> +
> + return_ptr(prop);
> +}
> +
> +/* Replace reg property with base address from dwc3 node and fixed length */
> +static int dwc3_qcom_legacy_update_reg(struct device_node *qcom,
> + struct device_node *dwc3)
> +{
> + int addr_cells;
> + int size_cells;
> + u64 dwc3_addr;
> + int ret;
> +
> + ret = of_property_read_reg(dwc3, 0, &dwc3_addr, NULL);
> + if (ret < 0)
> + return ret;
> +
> + addr_cells = of_n_addr_cells(qcom);
> + size_cells = of_n_addr_cells(qcom);
> +
> + __be32 *reg __free(kfree) = kcalloc(addr_cells + size_cells, sizeof(__be32), GFP_KERNEL);
> + if (!reg)
> + return -ENOMEM;
> +
> + reg[addr_cells - 1] = cpu_to_be32(dwc3_addr);
Assuming dwc3_addr fits in 32-bit or that the upper 32-bits matches?
> + reg[addr_cells + size_cells - 1] = cpu_to_be32(SDM845_QSCRATCH_BASE_OFFSET + SDM845_QSCRATCH_SIZE);
> +
> + struct property *prop __free(kfree) = kzalloc(sizeof(*prop), GFP_KERNEL);
> + char *name __free(kfree) = kstrdup("reg", GFP_KERNEL);
> + if (!prop || !name)
> + return -ENOMEM;
> +
> + prop->name = no_free_ptr(name);
> + prop->value = no_free_ptr(reg);
> + prop->length = (addr_cells + size_cells) * sizeof(__be32);
> +
> + return of_update_property(qcom, no_free_ptr(prop));
> +}
> +
> +/* Prepend dwc_usb3 interrupt to relevant interrupt properties */
> +static int dwc3_qcom_legacy_convert_interrupts(struct device_node *qcom,
> + struct property *dwc3_irq)
> +{
> + const __be32 *interrupts;
> + struct property *new;
> + const void *names;
> + int interrupts_len;
> + int names_len;
> + int ret;
> +
> + if ((interrupts = of_get_property(qcom, "interrupts-extended", &interrupts_len)) != NULL) {
> + struct device_node *parent __free(device_node) = of_irq_find_parent(qcom);
> + if (!parent)
> + return -EINVAL;
> +
> + __be32 *value __free(kfree) = kzalloc(sizeof(__be32) + dwc3_irq->length, GFP_KERNEL);
> + if (!value)
> + return -ENOMEM;
> + value[0] = cpu_to_be32(parent->phandle);
> + memcpy(&value[1], dwc3_irq->value, dwc3_irq->length);
> +
> + new = dwc3_qcom_legacy_prop_concat("interrupts-extended",
> + value, sizeof(__be32) + dwc3_irq->length,
> + interrupts, interrupts_len);
> + } else if ((interrupts = of_get_property(qcom, "interrupts", &interrupts_len)) != NULL) {
> + new = dwc3_qcom_legacy_prop_concat("interrupts",
> + dwc3_irq->value, dwc3_irq->length,
> + interrupts, interrupts_len);
> + } else {
> + return -EINVAL;
> }
>
> - qcom->dwc3 = of_find_device_by_node(dwc3_np);
> - if (!qcom->dwc3) {
> - ret = -ENODEV;
> - dev_err(dev, "failed to get dwc3 platform device\n");
> - of_platform_depopulate(dev);
> + if (!new)
> + return -ENOMEM;
> +
> + ret = of_update_property(qcom, new);
> + if (ret < 0)
> + return ret;
> +
> + names = of_get_property(qcom, "interrupt-names", &names_len);
> + if (!names)
> + return -EINVAL;
> +
> + new = dwc3_qcom_legacy_prop_concat("interrupt-names",
> + "dwc_usb3", strlen("dwc_usb3") + 1,
> + names, names_len);
> + if (!new)
> + return -ENOMEM;
> +
> + return of_update_property(qcom, new);
> +}
> +
> +/* Copy property to qcom node */
> +static int dwc3_qcom_legacy_migrate_prop(struct device_node *qcom,
> + struct property *prop)
> +{
> + struct property *new __free(kfree) = kzalloc(sizeof(*new), GFP_KERNEL);
> + char *name __free(kfree) = kstrdup(prop->name, GFP_KERNEL);
> + void *value __free(kfree) = kmemdup(prop->value, prop->length, GFP_KERNEL);
> +
> + if (!new || !name || !value)
> + return -ENOMEM;
> +
> + new->name = no_free_ptr(name);
> + new->value = no_free_ptr(value);
> + new->length = prop->length;
> +
> + return of_update_property(qcom, no_free_ptr(new));
> +}
> +
> +/* Move a child node, with it's properties and children, from dwc3 to qcom node */
> +static int dwc3_qcom_legacy_migrate_child(struct device_node *qcom,
> + struct device_node *dwc3,
> + const char *name)
> +{
> + struct device_node *child;
> +
> + child = of_get_child_by_name(dwc3, name);
> + if (!child)
> + return 0;
> +
> + of_detach_node(child);
> + child->parent = qcom;
> + of_attach_node(child);
> + of_node_put(child);
> +
> + return 0;
> +}
> +
> +/* Convert dev's DeviceTree representation from qcom,dwc3 to qcom,snps-dwc3 binding */
> +static int dwc3_qcom_convert_legacy_dt(struct device *dev)
> +{
> + struct device_node *qcom = dev->of_node;
> + struct device_node *dwc3;
> + struct property *prop;
> + int ret = 0;
> +
> + dwc3 = of_get_compatible_child(qcom, "snps,dwc3");
> + if (!dwc3)
> + return 0;
> +
> + /* We have a child node, but no support for dynamic OF */
> + if (!IS_ENABLED(CONFIG_OF_DYNAMIC))
> + return -EINVAL;
> +
> + for_each_property_of_node(dwc3, prop) {
> + if (!strcmp(prop->name, "compatible"))
> + ;
> + else if (!strcmp(prop->name, "reg"))
> + ret = dwc3_qcom_legacy_update_reg(qcom, dwc3);
> + else if (!strcmp(prop->name, "interrupts"))
> + ret = dwc3_qcom_legacy_convert_interrupts(qcom, prop);
> + else
> + ret = dwc3_qcom_legacy_migrate_prop(qcom, prop);
> }
>
> -node_put:
> - of_node_put(dwc3_np);
> + if (ret < 0)
> + goto err_node_put;
> +
> + ret = dwc3_qcom_legacy_migrate_child(qcom, dwc3, "port");
> + if (ret)
> + goto err_node_put;
> +
> + ret = dwc3_qcom_legacy_migrate_child(qcom, dwc3, "ports");
> + if (ret)
> + goto err_node_put;
> +
> + of_detach_node(dwc3);
> + of_node_put(dwc3);
>
> + return 0;
> +
> +err_node_put:
> + of_node_put(dwc3);
> return ret;
> }
>
> @@ -735,16 +894,21 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> struct device_node *np = pdev->dev.of_node;
> struct device *dev = &pdev->dev;
> struct dwc3_qcom *qcom;
> - struct resource *res;
> + struct resource res;
> int ret, i;
> bool ignore_pipe_clk;
> bool wakeup_source;
>
> + ret = dwc3_qcom_convert_legacy_dt(dev);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to convert legacy OF node\n");
> + return ret;
> + }
> +
> qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL);
> if (!qcom)
> return -ENOMEM;
>
> - platform_set_drvdata(pdev, qcom);
> qcom->dev = &pdev->dev;
>
> qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
> @@ -773,10 +937,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> goto reset_assert;
> }
>
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + ret = of_address_to_resource(np, 0, &res);
So we just leave the platform device resources stale? The right solution
is probably to make platform_get_resource() work on demand. That's what
we did for IRQ resources years ago (since those had irqchip driver
dependencies).
Rob
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 3/7] of: dynamic: Don't discard children upon node attach
2024-08-12 20:24 ` Rob Herring
@ 2024-08-12 21:21 ` Bjorn Andersson
0 siblings, 0 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-12 21:21 UTC (permalink / raw)
To: Rob Herring
Cc: Bjorn Andersson, Greg Kroah-Hartman, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio, linux-usb, devicetree,
linux-kernel, linux-arm-msm
On Mon, Aug 12, 2024 at 02:24:21PM -0600, Rob Herring wrote:
> On Sun, Aug 11, 2024 at 9:07 PM Bjorn Andersson <andersson@kernel.org> wrote:
> >
> > From: Bjorn Andersson <quic_bjorande@quicinc.com>
> >
> > When dynamically modifying DeviceTree it's useful to be able to reparent
> > nodes, but of_attach_node() clear the child pointer and hence discards
> > any child nodes.
>
> of_attach_node() is kind of the legacy API. You should be using
> changeset API. But I guess you really mean __of_attach_node() here
> which both use.
>
I failed to spot the changeset part of the API, that does indeed look
like a more robust solution. I will look into this, thanks.
> > Retain the child pointer upon attach, so that the client code doesn't
> > need to manually rebuild the tree.
> >
> > Current users of of_attach_node() either avoids attaching nodes with
> > children or explicitly attaches nodes without children, so no impact is
> > expected to current users.
> >
> > Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> > ---
> > drivers/of/dynamic.c | 1 -
> > 1 file changed, 1 deletion(-)
> >
> > diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
> > index 110104a936d9..32e1dffd9f96 100644
> > --- a/drivers/of/dynamic.c
> > +++ b/drivers/of/dynamic.c
> > @@ -221,7 +221,6 @@ static void __of_attach_node(struct device_node *np)
> > np->phandle = 0;
> > }
> >
> > - np->child = NULL;
> > np->sibling = np->parent->child;
> > np->parent->child = np;
> > of_node_clear_flag(np, OF_DETACHED);
>
> Before OF_DETACHED had a clear meaning. Now, are child nodes detached
> or not?
As far as I understood, the detached node will have children and as I
re-attach it, those children will just be leaked. The current (few)
clients are then making sure not to detach nodes with cihldren.
Perhaps the expectation is that the client will have traversed and
detached the children, and will then reattach them here?
Or perhaps the intention was to never allow detaching and reattaching a
node with children?
> If it means not attached to the root tree, then it is
> redundant having it per node. If it means parent and sibling aren't
> set, then what's the point as we can just check for NULL ptrs.
>
In practice, my goal is to detach the "ports" node from one parent and
attach it to another node, without breaking the graph.
In patch 6 this is used as:
of_node_detach(child);
child->parent = new;
of_node_attach(child);
> This all seems fragile on top of what's already fragile.
>
No concerns with that statement, I will start investigate the changeset
API.
I appreciate any guidance related to reparenting my graph node.
> Rob
Thank you,
Bjorn
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model
2024-08-12 21:21 ` Rob Herring
@ 2024-08-12 22:16 ` Bjorn Andersson
2024-08-13 15:06 ` Rob Herring
0 siblings, 1 reply; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-12 22:16 UTC (permalink / raw)
To: Rob Herring
Cc: Bjorn Andersson, Greg Kroah-Hartman, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio, linux-usb, devicetree,
linux-kernel, linux-arm-msm
On Mon, Aug 12, 2024 at 03:21:39PM -0600, Rob Herring wrote:
> On Sun, Aug 11, 2024 at 08:12:03PM -0700, Bjorn Andersson wrote:
> > From: Bjorn Andersson <quic_bjorande@quicinc.com>
> >
> > The USB IP-block found in most Qualcomm platforms is modelled in the
> > Linux kernel as 3 different independent device drivers, but as shown by
> > the already existing layering violations in the Qualcomm glue driver
> > they can not be operated independently.
> >
> > With the current implementation, the glue driver registers the core and
> > has no way to know when this is done. As a result, e.g. the suspend
> > callbacks needs to guard against NULL pointer dereferences when trying
> > to peek into the struct dwc3 found in the drvdata of the child.
> > Even with these checks, there are no way to fully protect ourselves from
> > the race conditions that occur if the DWC3 is unbound.
> >
> > Missing from the upstream Qualcomm USB support is handling of role
> > switching, in which the glue needs to be notified upon DRD mode changes.
> > Several attempts has been made through the years to register callbacks
> > etc, but they always fall short when it comes to handling of the core's
> > probe deferral on resources etc.
> >
> > Moving to a model where the DWC3 core is instantiated in a synchronous
> > fashion avoids above described race conditions.
> >
> > It is however not feasible to do so without also flattening the
> > DeviceTree binding, as assumptions are made in the DWC3 core and
> > frameworks used that the device's associated of_node will the that of
> > the core. Furthermore, the DeviceTree binding is a direct
> > representation of the Linux driver model, and doesn't necessarily
> > describe "the USB IP-block".
> >
> > The Qualcomm DWC3 glue driver is therefor transitioned to initialize and
> > operate the DWC3 within the one device context, in synchronous fashion.
> >
> > To handle backwards compatibility, and to remove the two-device model,
> > of_nodes of the old compatible are converted to the new one, early
> > during probe.
> >
> > This happens in the event that a DWC3 core child node is present, the
> > content of the reg and interrupt properties of this node are merged into
> > the shared properties, all remaining properties are copied and the core
> > node is dropped. Effectively transitioning the node from qcom,dwc3 to
> > qcom,snps-dwc3.
>
> In the past we've done this old binding to new binding with an overlay
> embedded in the kernel. The overlay would just be the .dts change you've
> made (we should have a tool that takes 2 DTs and generates an overlay as
> the diff). I suppose it's a few platforms here, but then it is just data
> and easily deleted when no longer needed (I think the cases I'm
> remembering did just that because they are gone now. It was TI display
> and Renesas media stuff IIRC).
>
Where and how do you apply this overlay?
If I can avoid doing the dynamic translation, I'd be happy to do so.
>
> > Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> > ---
> > drivers/usb/dwc3/dwc3-qcom.c | 310 +++++++++++++++++++++++++++++++++++--------
> > 1 file changed, 251 insertions(+), 59 deletions(-)
> >
> > diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
[..]
> > -static int dwc3_qcom_of_register_core(struct dwc3_qcom *qcom, struct platform_device *pdev)
> > +static struct property *dwc3_qcom_legacy_prop_concat(const char *name,
> > + const void *a, size_t a_len,
> > + const void *b, size_t b_len)
> > {
> > - struct device_node *np = pdev->dev.of_node, *dwc3_np;
> > - struct device *dev = &pdev->dev;
> > - int ret;
> > + size_t len = a_len + b_len;
> >
> > - dwc3_np = of_get_compatible_child(np, "snps,dwc3");
> > - if (!dwc3_np) {
> > - dev_err(dev, "failed to find dwc3 core child\n");
> > - return -ENODEV;
> > - }
> > + struct property *prop __free(kfree) = kzalloc(sizeof(*prop), GFP_KERNEL);
> > + char *prop_name __free(kfree) = kstrdup(name, GFP_KERNEL);
> > + void *value __free(kfree) = kzalloc(len, GFP_KERNEL);
> > + if (!prop || !prop_name || !value)
> > + return NULL;
> >
> > - ret = of_platform_populate(np, NULL, NULL, dev);
> > - if (ret) {
> > - dev_err(dev, "failed to register dwc3 core - %d\n", ret);
> > - goto node_put;
> > + prop->name = no_free_ptr(prop_name);
> > + prop->value = no_free_ptr(value);
> > + prop->length = len;
>
> We're trying to make struct property opaque or even internal to DT core.
> Exposing it leaks pointers and then we can't ever free things. This is
> not helping. The changeset API avoids mucking with struct property.
>
I will review the changeset API!
> > +
> > + memcpy(prop->value, a, a_len);
> > + memcpy(prop->value + a_len, b, b_len);
> > +
> > + return_ptr(prop);
> > +}
> > +
> > +/* Replace reg property with base address from dwc3 node and fixed length */
> > +static int dwc3_qcom_legacy_update_reg(struct device_node *qcom,
> > + struct device_node *dwc3)
> > +{
> > + int addr_cells;
> > + int size_cells;
> > + u64 dwc3_addr;
> > + int ret;
> > +
> > + ret = of_property_read_reg(dwc3, 0, &dwc3_addr, NULL);
> > + if (ret < 0)
> > + return ret;
> > +
> > + addr_cells = of_n_addr_cells(qcom);
> > + size_cells = of_n_addr_cells(qcom);
> > +
> > + __be32 *reg __free(kfree) = kcalloc(addr_cells + size_cells, sizeof(__be32), GFP_KERNEL);
> > + if (!reg)
> > + return -ENOMEM;
> > +
> > + reg[addr_cells - 1] = cpu_to_be32(dwc3_addr);
>
> Assuming dwc3_addr fits in 32-bit or that the upper 32-bits matches?
>
The core resides in the lower 32 bits on all existing targets, and I
expect any new targets that possibly changes that assumption would not
take the path through this translation (or would need to correct my
assumption).
> > + reg[addr_cells + size_cells - 1] = cpu_to_be32(SDM845_QSCRATCH_BASE_OFFSET + SDM845_QSCRATCH_SIZE);
> > +
[..]
> > @@ -773,10 +937,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> > goto reset_assert;
> > }
> >
> > - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + ret = of_address_to_resource(np, 0, &res);
>
> So we just leave the platform device resources stale? The right solution
> is probably to make platform_get_resource() work on demand.
I did consider updating the resource, only in the case that we rewrite
the information, as it would be slightly cleaner not to leave that
dangling. But this was cleaner code wise.
> That's what
> we did for IRQ resources years ago (since those had irqchip driver
> dependencies).
>
Right, for platform_get_irq(), but I presume for platform_get_resource()
we would end up with the union of the different resource-specific lookup
mechanisms?
Regards,
Bjorn
> Rob
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model
2024-08-12 22:16 ` Bjorn Andersson
@ 2024-08-13 15:06 ` Rob Herring
0 siblings, 0 replies; 37+ messages in thread
From: Rob Herring @ 2024-08-13 15:06 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Bjorn Andersson, Greg Kroah-Hartman, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio, linux-usb, devicetree,
linux-kernel, linux-arm-msm
On Mon, Aug 12, 2024 at 4:16 PM Bjorn Andersson
<quic_bjorande@quicinc.com> wrote:
>
> On Mon, Aug 12, 2024 at 03:21:39PM -0600, Rob Herring wrote:
> > On Sun, Aug 11, 2024 at 08:12:03PM -0700, Bjorn Andersson wrote:
> > > From: Bjorn Andersson <quic_bjorande@quicinc.com>
> > >
> > > The USB IP-block found in most Qualcomm platforms is modelled in the
> > > Linux kernel as 3 different independent device drivers, but as shown by
> > > the already existing layering violations in the Qualcomm glue driver
> > > they can not be operated independently.
> > >
> > > With the current implementation, the glue driver registers the core and
> > > has no way to know when this is done. As a result, e.g. the suspend
> > > callbacks needs to guard against NULL pointer dereferences when trying
> > > to peek into the struct dwc3 found in the drvdata of the child.
> > > Even with these checks, there are no way to fully protect ourselves from
> > > the race conditions that occur if the DWC3 is unbound.
> > >
> > > Missing from the upstream Qualcomm USB support is handling of role
> > > switching, in which the glue needs to be notified upon DRD mode changes.
> > > Several attempts has been made through the years to register callbacks
> > > etc, but they always fall short when it comes to handling of the core's
> > > probe deferral on resources etc.
> > >
> > > Moving to a model where the DWC3 core is instantiated in a synchronous
> > > fashion avoids above described race conditions.
> > >
> > > It is however not feasible to do so without also flattening the
> > > DeviceTree binding, as assumptions are made in the DWC3 core and
> > > frameworks used that the device's associated of_node will the that of
> > > the core. Furthermore, the DeviceTree binding is a direct
> > > representation of the Linux driver model, and doesn't necessarily
> > > describe "the USB IP-block".
> > >
> > > The Qualcomm DWC3 glue driver is therefor transitioned to initialize and
> > > operate the DWC3 within the one device context, in synchronous fashion.
> > >
> > > To handle backwards compatibility, and to remove the two-device model,
> > > of_nodes of the old compatible are converted to the new one, early
> > > during probe.
> > >
> > > This happens in the event that a DWC3 core child node is present, the
> > > content of the reg and interrupt properties of this node are merged into
> > > the shared properties, all remaining properties are copied and the core
> > > node is dropped. Effectively transitioning the node from qcom,dwc3 to
> > > qcom,snps-dwc3.
> >
> > In the past we've done this old binding to new binding with an overlay
> > embedded in the kernel. The overlay would just be the .dts change you've
> > made (we should have a tool that takes 2 DTs and generates an overlay as
> > the diff). I suppose it's a few platforms here, but then it is just data
> > and easily deleted when no longer needed (I think the cases I'm
> > remembering did just that because they are gone now. It was TI display
> > and Renesas media stuff IIRC).
> >
>
> Where and how do you apply this overlay?
With "git log -S of_overlay_ drivers/", I found the prior cases. See
841281fe52a7 ("drm: rcar-du: Drop LVDS device tree backward
compatibility") and 739acd85ffdb ("drm/tilcdc: Remove obsolete
"ti,tilcdc,slave" dts binding support")
I would consider putting them in drivers/of/ as well. Then we could
better control the order of applying the overlay and creating devices.
It avoids a lot of the complexity if the overlay is applied first.
> If I can avoid doing the dynamic translation, I'd be happy to do so.
>
> >
> > > Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> > > ---
> > > drivers/usb/dwc3/dwc3-qcom.c | 310 +++++++++++++++++++++++++++++++++++--------
> > > 1 file changed, 251 insertions(+), 59 deletions(-)
> > >
> > > diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
> [..]
> > > -static int dwc3_qcom_of_register_core(struct dwc3_qcom *qcom, struct platform_device *pdev)
> > > +static struct property *dwc3_qcom_legacy_prop_concat(const char *name,
> > > + const void *a, size_t a_len,
> > > + const void *b, size_t b_len)
> > > {
> > > - struct device_node *np = pdev->dev.of_node, *dwc3_np;
> > > - struct device *dev = &pdev->dev;
> > > - int ret;
> > > + size_t len = a_len + b_len;
> > >
> > > - dwc3_np = of_get_compatible_child(np, "snps,dwc3");
> > > - if (!dwc3_np) {
> > > - dev_err(dev, "failed to find dwc3 core child\n");
> > > - return -ENODEV;
> > > - }
> > > + struct property *prop __free(kfree) = kzalloc(sizeof(*prop), GFP_KERNEL);
> > > + char *prop_name __free(kfree) = kstrdup(name, GFP_KERNEL);
> > > + void *value __free(kfree) = kzalloc(len, GFP_KERNEL);
> > > + if (!prop || !prop_name || !value)
> > > + return NULL;
> > >
> > > - ret = of_platform_populate(np, NULL, NULL, dev);
> > > - if (ret) {
> > > - dev_err(dev, "failed to register dwc3 core - %d\n", ret);
> > > - goto node_put;
> > > + prop->name = no_free_ptr(prop_name);
> > > + prop->value = no_free_ptr(value);
> > > + prop->length = len;
> >
> > We're trying to make struct property opaque or even internal to DT core.
> > Exposing it leaks pointers and then we can't ever free things. This is
> > not helping. The changeset API avoids mucking with struct property.
> >
>
> I will review the changeset API!
>
> > > +
> > > + memcpy(prop->value, a, a_len);
> > > + memcpy(prop->value + a_len, b, b_len);
> > > +
> > > + return_ptr(prop);
> > > +}
> > > +
> > > +/* Replace reg property with base address from dwc3 node and fixed length */
> > > +static int dwc3_qcom_legacy_update_reg(struct device_node *qcom,
> > > + struct device_node *dwc3)
> > > +{
> > > + int addr_cells;
> > > + int size_cells;
> > > + u64 dwc3_addr;
> > > + int ret;
> > > +
> > > + ret = of_property_read_reg(dwc3, 0, &dwc3_addr, NULL);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + addr_cells = of_n_addr_cells(qcom);
> > > + size_cells = of_n_addr_cells(qcom);
> > > +
> > > + __be32 *reg __free(kfree) = kcalloc(addr_cells + size_cells, sizeof(__be32), GFP_KERNEL);
> > > + if (!reg)
> > > + return -ENOMEM;
> > > +
> > > + reg[addr_cells - 1] = cpu_to_be32(dwc3_addr);
> >
> > Assuming dwc3_addr fits in 32-bit or that the upper 32-bits matches?
> >
>
> The core resides in the lower 32 bits on all existing targets, and I
> expect any new targets that possibly changes that assumption would not
> take the path through this translation (or would need to correct my
> assumption).
>
> > > + reg[addr_cells + size_cells - 1] = cpu_to_be32(SDM845_QSCRATCH_BASE_OFFSET + SDM845_QSCRATCH_SIZE);
> > > +
> [..]
> > > @@ -773,10 +937,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> > > goto reset_assert;
> > > }
> > >
> > > - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > + ret = of_address_to_resource(np, 0, &res);
> >
> > So we just leave the platform device resources stale? The right solution
> > is probably to make platform_get_resource() work on demand.
>
> I did consider updating the resource, only in the case that we rewrite
> the information, as it would be slightly cleaner not to leave that
> dangling. But this was cleaner code wise.
>
> > That's what
> > we did for IRQ resources years ago (since those had irqchip driver
> > dependencies).
> >
>
> Right, for platform_get_irq(), but I presume for platform_get_resource()
> we would end up with the union of the different resource-specific lookup
> mechanisms?
You'd just make platform_get_resource() call of_address_to_resource()
internally if there's a node pointer. There could be drivers that
break and it would be slower if we defer probe since it would parse
the DT every probe. But really, an overlay applied earlier is a better
approach IMO.
Rob
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure
2024-08-12 3:11 [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Bjorn Andersson
` (6 preceding siblings ...)
2024-08-12 3:12 ` [PATCH v2 7/7] arm64: dts: qcom: sc8280x: Flatten the USB nodes Bjorn Andersson
@ 2024-08-13 18:07 ` Frank Li
2024-10-08 20:09 ` Frank Li
7 siblings, 1 reply; 37+ messages in thread
From: Frank Li @ 2024-08-13 18:07 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio, linux-usb, devicetree,
linux-kernel, linux-arm-msm, Bjorn Andersson
On Sun, Aug 11, 2024 at 08:11:57PM -0700, Bjorn Andersson wrote:
> The USB IP-block found in most Qualcomm platforms is modelled in the
> Linux kernel as 3 different independent device drivers, but as shown by
> the already existing layering violations in the Qualcomm glue driver
> they can not be operated independently.
>
> With the current implementation, the glue driver registers the core and
> has no way to know when this is done. As a result, e.g. the suspend
> callbacks needs to guard against NULL pointer dereferences when trying
> to peek into the struct dwc3 found in the drvdata of the child.
>
> Missing from the upstream Qualcomm USB support is handling of role
> switching, in which the glue needs to be notified upon DRD mode changes.
> Several attempts has been made through the years to register callbacks
> etc, but they always fall short when it comes to handling of the core's
> probe deferral on resources etc.
>
> Furhtermore, the DeviceTree binding is a direct representation of the
> Linux driver model, and doesn't necessarily describe "the USB IP-block".
>
> This series therefor attempts to flatten the driver split, and operate
> the glue and core out of the same platform_device instance. And in order
> to do this, the DeviceTree representation of the IP block is flattened.
Thanks, we faced the same problem. Can you cc me next time?
Frank
>
> ---
> Changes in v2:
> - Rewrite after ACPI removal, multiport support and interrupt fixes
> - Completely changed strategy for DeviceTree binding, as previous idea
> of using snps,dwc3 as a generic fallback required unreasonable changes
> to that binding.
> - Abandoned idea of supporting both flattened and unflattened device
> model in the one driver. As Johan pointed out, it will leave the race
> condition holes and will make the code harder to understand.
> Furthermore, the role switching logic that we intend to introduce
> following this would have depended on the user updating their
> DeviceTree blobs.
> - Per above, introduced the dynamic DeviceTree rewrite
> - Link to v1: https://lore.kernel.org/all/20231016-dwc3-refactor-v1-0-ab4a84165470@quicinc.com/
>
> ---
> Bjorn Andersson (7):
> dt-bindings: usb: snps,dwc3: Split core description
> dt-bindings: usb: Introduce qcom,snps-dwc3
> of: dynamic: Don't discard children upon node attach
> usb: dwc3: core: Expose core driver as library
> usb: dwc3: qcom: Don't reply on drvdata during probe
> usb: dwc3: qcom: Transition to flattened model
> arm64: dts: qcom: sc8280x: Flatten the USB nodes
>
> .../devicetree/bindings/usb/qcom,dwc3.yaml | 13 +-
> .../devicetree/bindings/usb/qcom,snps-dwc3.yaml | 608 +++++++++++++++++++++
> .../devicetree/bindings/usb/snps,dwc3-common.yaml | 417 ++++++++++++++
> .../devicetree/bindings/usb/snps,dwc3.yaml | 391 +------------
> arch/arm64/boot/dts/qcom/sa8295p-adp.dts | 12 +-
> arch/arm64/boot/dts/qcom/sa8540p-ride.dts | 5 +-
> arch/arm64/boot/dts/qcom/sc8280xp-crd.dts | 12 +-
> .../dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts | 11 +-
> arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 138 +++--
> drivers/of/dynamic.c | 1 -
> drivers/usb/dwc3/core.c | 169 ++++--
> drivers/usb/dwc3/core.h | 3 +
> drivers/usb/dwc3/dwc3-qcom.c | 323 ++++++++---
> 13 files changed, 1483 insertions(+), 620 deletions(-)
> ---
> base-commit: 864b1099d16fc7e332c3ad7823058c65f890486c
> change-id: 20231016-dwc3-refactor-931e3b08a8b9
>
> Best regards,
> --
> Bjorn Andersson <quic_bjorande@quicinc.com>
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-12 3:12 ` [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library Bjorn Andersson
2024-08-12 12:21 ` kernel test robot
2024-08-12 12:21 ` kernel test robot
@ 2024-08-13 18:15 ` Frank Li
2024-08-14 1:01 ` Thinh Nguyen
2024-08-19 21:35 ` Bjorn Andersson
2024-08-14 0:56 ` Thinh Nguyen
` (2 subsequent siblings)
5 siblings, 2 replies; 37+ messages in thread
From: Frank Li @ 2024-08-13 18:15 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio, linux-usb, devicetree,
linux-kernel, linux-arm-msm, Bjorn Andersson
On Sun, Aug 11, 2024 at 08:12:01PM -0700, Bjorn Andersson wrote:
> From: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> The DWC3 IP block is handled by three distinct device drivers: XHCI,
> DWC3 core and a platform specific (optional) DWC3 glue driver.
>
> This has resulted in, at least in the case of the Qualcomm glue, the
> presence of a number of layering violations, where the glue code either
> can't handle, or has to work around, the fact that core might not probe
> deterministically.
>
> An example of this is that the suspend path should operate slightly
> different depending on the device operating in host or peripheral mode,
> and the only way to determine the operating state is to peek into the
> core's drvdata.
>
> The Qualcomm glue driver is expected to make updates in the qscratch
> register region (the "glue" region) during role switch events, but with
> the glue and core split using the driver model, there is no reasonable
> way to introduce listeners for mode changes.
>
> Split the dwc3 core platform_driver callbacks and their implementation
> and export the implementation, to make it possible to deterministically
> instantiate the dwc3 core as part of the dwc3 glue drivers and to
> allow flattening of the DeviceTree representation.
>
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> ---
> drivers/usb/dwc3/core.c | 169 +++++++++++++++++++++++++++++++-----------------
> drivers/usb/dwc3/core.h | 3 +
> 2 files changed, 114 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 734de2a8bd21..6addb3c367e6 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -36,6 +36,7 @@
>
> #include "core.h"
> #include "gadget.h"
> +#include "glue.h"
> #include "io.h"
>
> #include "debug.h"
> @@ -2076,10 +2077,11 @@ static int dwc3_get_num_ports(struct dwc3 *dwc)
> return 0;
> }
>
> -static int dwc3_probe(struct platform_device *pdev)
> +struct dwc3 *dwc3_probe(struct platform_device *pdev, struct resource *res,
> + bool ignore_clocks_and_resets, void *glue)
> {
> struct device *dev = &pdev->dev;
> - struct resource *res, dwc_res;
> + struct resource dwc_res;
> unsigned int hw_mode;
> void __iomem *regs;
> struct dwc3 *dwc;
> @@ -2087,15 +2089,10 @@ static int dwc3_probe(struct platform_device *pdev)
>
> dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
> if (!dwc)
> - return -ENOMEM;
> + return ERR_PTR(-ENOMEM);
>
> dwc->dev = dev;
> -
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - if (!res) {
> - dev_err(dev, "missing memory resource\n");
> - return -ENODEV;
> - }
> + dwc->glue = glue;
>
> dwc->xhci_resources[0].start = res->start;
> dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
> @@ -2123,7 +2120,7 @@ static int dwc3_probe(struct platform_device *pdev)
>
> regs = devm_ioremap_resource(dev, &dwc_res);
> if (IS_ERR(regs))
> - return PTR_ERR(regs);
> + return ERR_CAST(regs);
>
> dwc->regs = regs;
> dwc->regs_size = resource_size(&dwc_res);
> @@ -2132,15 +2129,17 @@ static int dwc3_probe(struct platform_device *pdev)
>
> dwc3_get_software_properties(dwc);
>
> - dwc->reset = devm_reset_control_array_get_optional_shared(dev);
> - if (IS_ERR(dwc->reset)) {
> - ret = PTR_ERR(dwc->reset);
> - goto err_put_psy;
> - }
> + if (!ignore_clocks_and_resets) {
> + dwc->reset = devm_reset_control_array_get_optional_shared(dev);
> + if (IS_ERR(dwc->reset)) {
> + ret = PTR_ERR(dwc->reset);
> + goto err_put_psy;
> + }
>
> - ret = dwc3_get_clocks(dwc);
> - if (ret)
> - goto err_put_psy;
> + ret = dwc3_get_clocks(dwc);
> + if (ret)
> + goto err_put_psy;
> + }
>
> ret = reset_control_deassert(dwc->reset);
> if (ret)
> @@ -2225,7 +2224,7 @@ static int dwc3_probe(struct platform_device *pdev)
>
> dma_set_max_seg_size(dev, UINT_MAX);
>
> - return 0;
> + return dwc;
>
> err_exit_debugfs:
> dwc3_debugfs_exit(dwc);
> @@ -2249,14 +2248,33 @@ static int dwc3_probe(struct platform_device *pdev)
> if (dwc->usb_psy)
> power_supply_put(dwc->usb_psy);
>
> - return ret;
> + return ERR_PTR(ret);
> }
> +EXPORT_SYMBOL_GPL(dwc3_probe);
>
> -static void dwc3_remove(struct platform_device *pdev)
> +static int dwc3_plat_probe(struct platform_device *pdev)
> {
> - struct dwc3 *dwc = platform_get_drvdata(pdev);
> + struct resource *res;
> + struct dwc3 *dwc;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "missing memory resource\n");
> + return -ENODEV;
> + }
>
> - pm_runtime_get_sync(&pdev->dev);
> + dwc = dwc3_probe(pdev, res, false, NULL);
> + if (IS_ERR(dwc))
> + return PTR_ERR(dwc);
> +
> + platform_set_drvdata(pdev, dwc);
> +
> + return 0;
> +}
> +
> +void dwc3_remove(struct dwc3 *dwc)
> +{
> + pm_runtime_get_sync(dwc->dev);
>
> dwc3_core_exit_mode(dwc);
> dwc3_debugfs_exit(dwc);
> @@ -2264,22 +2282,28 @@ static void dwc3_remove(struct platform_device *pdev)
> dwc3_core_exit(dwc);
> dwc3_ulpi_exit(dwc);
>
> - pm_runtime_allow(&pdev->dev);
> - pm_runtime_disable(&pdev->dev);
> - pm_runtime_dont_use_autosuspend(&pdev->dev);
> - pm_runtime_put_noidle(&pdev->dev);
> + pm_runtime_allow(dwc->dev);
> + pm_runtime_disable(dwc->dev);
> + pm_runtime_dont_use_autosuspend(dwc->dev);
> + pm_runtime_put_noidle(dwc->dev);
> /*
> * HACK: Clear the driver data, which is currently accessed by parent
> * glue drivers, before allowing the parent to suspend.
> */
> - platform_set_drvdata(pdev, NULL);
> - pm_runtime_set_suspended(&pdev->dev);
> + dev_set_drvdata(dwc->dev, NULL);
> + pm_runtime_set_suspended(dwc->dev);
>
> dwc3_free_event_buffers(dwc);
>
> if (dwc->usb_psy)
> power_supply_put(dwc->usb_psy);
> }
> +EXPORT_SYMBOL_GPL(dwc3_remove);
> +
> +static void dwc3_plat_remove(struct platform_device *pdev)
> +{
> + dwc3_remove(platform_get_drvdata(pdev));
> +}
>
> #ifdef CONFIG_PM
> static int dwc3_core_init_for_resume(struct dwc3 *dwc)
> @@ -2450,9 +2474,8 @@ static int dwc3_runtime_checks(struct dwc3 *dwc)
> return 0;
> }
>
> -static int dwc3_runtime_suspend(struct device *dev)
> +int dwc3_runtime_suspend(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> if (dwc3_runtime_checks(dwc))
> @@ -2464,10 +2487,10 @@ static int dwc3_runtime_suspend(struct device *dev)
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_runtime_suspend);
>
> -static int dwc3_runtime_resume(struct device *dev)
> +int dwc3_runtime_resume(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
> @@ -2484,15 +2507,14 @@ static int dwc3_runtime_resume(struct device *dev)
> break;
> }
>
> - pm_runtime_mark_last_busy(dev);
> + pm_runtime_mark_last_busy(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_runtime_resume);
>
> -static int dwc3_runtime_idle(struct device *dev)
> +int dwc3_runtime_idle(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> -
> switch (dwc->current_dr_role) {
> case DWC3_GCTL_PRTCAP_DEVICE:
> if (dwc3_runtime_checks(dwc))
> @@ -2504,52 +2526,67 @@ static int dwc3_runtime_idle(struct device *dev)
> break;
> }
>
> - pm_runtime_mark_last_busy(dev);
> - pm_runtime_autosuspend(dev);
> + pm_runtime_mark_last_busy(dwc->dev);
> + pm_runtime_autosuspend(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_runtime_idle);
> +
> +static int dwc3_plat_runtime_suspend(struct device *dev)
> +{
> + return dwc3_runtime_suspend(dev_get_drvdata(dev));
> +}
> +
> +static int dwc3_plat_runtime_resume(struct device *dev)
> +{
> + return dwc3_runtime_resume(dev_get_drvdata(dev));
> +}
> +
> +static int dwc3_plat_runtime_idle(struct device *dev)
> +{
> + return dwc3_runtime_idle(dev_get_drvdata(dev));
> +}
> #endif /* CONFIG_PM */
>
> #ifdef CONFIG_PM_SLEEP
> -static int dwc3_suspend(struct device *dev)
> +int dwc3_suspend(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
> if (ret)
> return ret;
>
> - pinctrl_pm_select_sleep_state(dev);
> + pinctrl_pm_select_sleep_state(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_suspend);
>
> -static int dwc3_resume(struct device *dev)
> +int dwc3_resume(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> - pinctrl_pm_select_default_state(dev);
> + pinctrl_pm_select_default_state(dwc->dev);
>
> - pm_runtime_disable(dev);
> - pm_runtime_set_active(dev);
> + pm_runtime_disable(dwc->dev);
> + pm_runtime_set_active(dwc->dev);
>
> ret = dwc3_resume_common(dwc, PMSG_RESUME);
> if (ret) {
> - pm_runtime_set_suspended(dev);
> + pm_runtime_set_suspended(dwc->dev);
> return ret;
> }
>
> - pm_runtime_enable(dev);
> + pm_runtime_enable(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_resume);
>
> -static void dwc3_complete(struct device *dev)
> +void dwc3_complete(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> u32 reg;
>
> if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
> @@ -2559,15 +2596,31 @@ static void dwc3_complete(struct device *dev)
> dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
> }
> }
> +EXPORT_SYMBOL_GPL(dwc3_complete);
> +
> +static int dwc3_plat_suspend(struct device *dev)
> +{
> + return dwc3_suspend(dev_get_drvdata(dev));
> +}
> +
> +static int dwc3_plat_resume(struct device *dev)
> +{
> + return dwc3_resume(dev_get_drvdata(dev));
> +}
> +
> +static void dwc3_plat_complete(struct device *dev)
> +{
> + dwc3_complete(dev_get_drvdata(dev));
> +}
> #else
> -#define dwc3_complete NULL
> +#define dwc3_plat_complete NULL
> #endif /* CONFIG_PM_SLEEP */
>
> static const struct dev_pm_ops dwc3_dev_pm_ops = {
> - SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
> - .complete = dwc3_complete,
> - SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
> - dwc3_runtime_idle)
> + SET_SYSTEM_SLEEP_PM_OPS(dwc3_plat_suspend, dwc3_plat_resume)
since you touch this line,
suggest use new SYSTEM_SLEEP_PM_OPS() and RUNTIME_PM_OPS() help macro.
also CONFIG_PM_SLEEP can be removed.
Frank
> + .complete = dwc3_plat_complete,
> + SET_RUNTIME_PM_OPS(dwc3_plat_runtime_suspend, dwc3_plat_runtime_resume,
> + dwc3_plat_runtime_idle)
> };
>
> #ifdef CONFIG_OF
> @@ -2595,8 +2648,8 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
> #endif
>
> static struct platform_driver dwc3_driver = {
> - .probe = dwc3_probe,
> - .remove_new = dwc3_remove,
> + .probe = dwc3_plat_probe,
> + .remove_new = dwc3_plat_remove,
> .driver = {
> .name = "dwc3",
> .of_match_table = of_match_ptr(of_dwc3_match),
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index 1e561fd8b86e..4a0ee9ef72e2 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -1160,6 +1160,7 @@ struct dwc3_scratchpad_array {
> * @gsbuscfg0_reqinfo: store GSBUSCFG0.DATRDREQINFO, DESRDREQINFO,
> * DATWRREQINFO, and DESWRREQINFO value passed from
> * glue driver.
> + * @glue: private reference to any glue context
> */
> struct dwc3 {
> struct work_struct drd_work;
> @@ -1388,6 +1389,8 @@ struct dwc3 {
> int num_ep_resized;
> struct dentry *debug_root;
> u32 gsbuscfg0_reqinfo;
> +
> + void *glue;
> };
>
> #define INCRX_BURST_MODE 0
>
> --
> 2.45.2
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 5/7] usb: dwc3: qcom: Don't reply on drvdata during probe
2024-08-12 3:12 ` [PATCH v2 5/7] usb: dwc3: qcom: Don't reply on drvdata during probe Bjorn Andersson
@ 2024-08-13 18:18 ` Frank Li
2024-08-19 21:17 ` Bjorn Andersson
2024-09-12 22:21 ` Masahiro Yamada
1 sibling, 1 reply; 37+ messages in thread
From: Frank Li @ 2024-08-13 18:18 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio, linux-usb, devicetree,
linux-kernel, linux-arm-msm, Bjorn Andersson
On Sun, Aug 11, 2024 at 08:12:02PM -0700, Bjorn Andersson wrote:
> From: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> With the upcoming transition to a model where DWC3 core and glue operate
> on a single struct device the drvdata datatype will change to be owned
> by the core.
>
> The drvdata is however used by the Qualcomm DWC3 glue to pass the qcom
> glue context around before the core is allocated.
>
> Remove this problem, and clean up the code, by passing the dwc3_qcom
> struct around during probe, instead of acquiring it from the drvdata.
>
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> ---
> drivers/usb/dwc3/dwc3-qcom.c | 17 ++++++++---------
> 1 file changed, 8 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
> index 88fb6706a18d..33de03f2d782 100644
> --- a/drivers/usb/dwc3/dwc3-qcom.c
> +++ b/drivers/usb/dwc3/dwc3-qcom.c
> @@ -546,9 +546,10 @@ static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq,
> return ret;
> }
>
> -static int dwc3_qcom_setup_port_irq(struct platform_device *pdev, int port_index, bool is_multiport)
> +static int dwc3_qcom_setup_port_irq(struct dwc3_qcom *qcom,
If pass "qcom", do you need "pdev"? generaly, qcom should have pdev information.
Frank
> + struct platform_device *pdev,
> + int port_index, bool is_multiport)
> {
> - struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
> const char *irq_name;
> int irq;
> int ret;
> @@ -633,9 +634,8 @@ static int dwc3_qcom_find_num_ports(struct platform_device *pdev)
> return DWC3_QCOM_MAX_PORTS;
> }
>
> -static int dwc3_qcom_setup_irq(struct platform_device *pdev)
> +static int dwc3_qcom_setup_irq(struct dwc3_qcom *qcom, struct platform_device *pdev)
> {
> - struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
> bool is_multiport;
> int ret;
> int i;
> @@ -644,7 +644,7 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
> is_multiport = (qcom->num_ports > 1);
>
> for (i = 0; i < qcom->num_ports; i++) {
> - ret = dwc3_qcom_setup_port_irq(pdev, i, is_multiport);
> + ret = dwc3_qcom_setup_port_irq(qcom, pdev, i, is_multiport);
> if (ret)
> return ret;
> }
> @@ -699,9 +699,8 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
> return 0;
> }
>
> -static int dwc3_qcom_of_register_core(struct platform_device *pdev)
> +static int dwc3_qcom_of_register_core(struct dwc3_qcom *qcom, struct platform_device *pdev)
> {
> - struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
> struct device_node *np = pdev->dev.of_node, *dwc3_np;
> struct device *dev = &pdev->dev;
> int ret;
> @@ -782,7 +781,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> goto clk_disable;
> }
>
> - ret = dwc3_qcom_setup_irq(pdev);
> + ret = dwc3_qcom_setup_irq(qcom, pdev);
> if (ret) {
> dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
> goto clk_disable;
> @@ -797,7 +796,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> if (ignore_pipe_clk)
> dwc3_qcom_select_utmi_clk(qcom);
>
> - ret = dwc3_qcom_of_register_core(pdev);
> + ret = dwc3_qcom_of_register_core(qcom, pdev);
> if (ret) {
> dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
> goto clk_disable;
>
> --
> 2.45.2
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model
2024-08-12 3:12 ` [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model Bjorn Andersson
2024-08-12 13:33 ` kernel test robot
2024-08-12 21:21 ` Rob Herring
@ 2024-08-13 18:33 ` Frank Li
2024-08-19 21:28 ` Bjorn Andersson
2 siblings, 1 reply; 37+ messages in thread
From: Frank Li @ 2024-08-13 18:33 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio, linux-usb, devicetree,
linux-kernel, linux-arm-msm, Bjorn Andersson
On Sun, Aug 11, 2024 at 08:12:03PM -0700, Bjorn Andersson wrote:
> From: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> The USB IP-block found in most Qualcomm platforms is modelled in the
> Linux kernel as 3 different independent device drivers, but as shown by
> the already existing layering violations in the Qualcomm glue driver
> they can not be operated independently.
>
> With the current implementation, the glue driver registers the core and
> has no way to know when this is done. As a result, e.g. the suspend
> callbacks needs to guard against NULL pointer dereferences when trying
> to peek into the struct dwc3 found in the drvdata of the child.
> Even with these checks, there are no way to fully protect ourselves from
> the race conditions that occur if the DWC3 is unbound.
>
> Missing from the upstream Qualcomm USB support is handling of role
> switching, in which the glue needs to be notified upon DRD mode changes.
> Several attempts has been made through the years to register callbacks
> etc, but they always fall short when it comes to handling of the core's
> probe deferral on resources etc.
>
> Moving to a model where the DWC3 core is instantiated in a synchronous
> fashion avoids above described race conditions.
>
> It is however not feasible to do so without also flattening the
> DeviceTree binding, as assumptions are made in the DWC3 core and
> frameworks used that the device's associated of_node will the that of
> the core. Furthermore, the DeviceTree binding is a direct
> representation of the Linux driver model, and doesn't necessarily
> describe "the USB IP-block".
>
> The Qualcomm DWC3 glue driver is therefor transitioned to initialize and
> operate the DWC3 within the one device context, in synchronous fashion.
>
> To handle backwards compatibility, and to remove the two-device model,
> of_nodes of the old compatible are converted to the new one, early
> during probe.
>
> This happens in the event that a DWC3 core child node is present, the
> content of the reg and interrupt properties of this node are merged into
> the shared properties, all remaining properties are copied and the core
> node is dropped. Effectively transitioning the node from qcom,dwc3 to
> qcom,snps-dwc3.
>
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> ---
> drivers/usb/dwc3/dwc3-qcom.c | 310 +++++++++++++++++++++++++++++++++++--------
> 1 file changed, 251 insertions(+), 59 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
> index 33de03f2d782..27b5013cd411 100644
> --- a/drivers/usb/dwc3/dwc3-qcom.c
> +++ b/drivers/usb/dwc3/dwc3-qcom.c
> @@ -6,6 +6,7 @@
>
> #include <linux/io.h>
> #include <linux/of.h>
> +#include <linux/cleanup.h>
> #include <linux/clk.h>
> #include <linux/irq.h>
> #include <linux/of_clk.h>
> @@ -13,6 +14,8 @@
> #include <linux/kernel.h>
> #include <linux/extcon.h>
> #include <linux/interconnect.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> #include <linux/of_platform.h>
> #include <linux/platform_device.h>
> #include <linux/phy/phy.h>
> @@ -22,6 +25,7 @@
> #include <linux/usb/hcd.h>
> #include <linux/usb.h>
> #include "core.h"
> +#include "glue.h"
>
> /* USB QSCRATCH Hardware registers */
> #define QSCRATCH_HS_PHY_CTRL 0x10
> @@ -72,7 +76,7 @@ struct dwc3_qcom_port {
> struct dwc3_qcom {
> struct device *dev;
> void __iomem *qscratch_base;
> - struct platform_device *dwc3;
> + struct dwc3 *dwc;
> struct clk **clks;
> int num_clocks;
> struct reset_control *resets;
> @@ -259,7 +263,7 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
> goto put_path_ddr;
> }
>
> - max_speed = usb_get_maximum_speed(&qcom->dwc3->dev);
> + max_speed = usb_get_maximum_speed(qcom->dwc->dev);
> if (max_speed >= USB_SPEED_SUPER || max_speed == USB_SPEED_UNKNOWN) {
> ret = icc_set_bw(qcom->icc_path_ddr,
> USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
> @@ -302,25 +306,16 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
> /* Only usable in contexts where the role can not change. */
> static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
> {
> - struct dwc3 *dwc;
> -
> - /*
> - * FIXME: Fix this layering violation.
> - */
> - dwc = platform_get_drvdata(qcom->dwc3);
> -
> - /* Core driver may not have probed yet. */
> - if (!dwc)
> - return false;
> + struct dwc3 *dwc = qcom->dwc;
>
> return dwc->xhci;
dwc only use once.
return qcom->dwc->xhci?
> }
>
> static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom, int port_index)
> {
> - struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
> struct usb_device *udev;
> struct usb_hcd __maybe_unused *hcd;
> + struct dwc3 *dwc = qcom->dwc;
>
> /*
> * FIXME: Fix this layering violation.
> @@ -497,7 +492,7 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
> static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data)
> {
> struct dwc3_qcom *qcom = data;
> - struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
> + struct dwc3 *dwc = qcom->dwc;
>
> /* If pm_suspended then let pm_resume take care of resuming h/w */
> if (qcom->pm_suspended)
> @@ -699,34 +694,198 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
> return 0;
> }
>
> -static int dwc3_qcom_of_register_core(struct dwc3_qcom *qcom, struct platform_device *pdev)
> +static struct property *dwc3_qcom_legacy_prop_concat(const char *name,
> + const void *a, size_t a_len,
> + const void *b, size_t b_len)
> {
> - struct device_node *np = pdev->dev.of_node, *dwc3_np;
> - struct device *dev = &pdev->dev;
> - int ret;
> + size_t len = a_len + b_len;
>
> - dwc3_np = of_get_compatible_child(np, "snps,dwc3");
> - if (!dwc3_np) {
> - dev_err(dev, "failed to find dwc3 core child\n");
> - return -ENODEV;
> - }
> + struct property *prop __free(kfree) = kzalloc(sizeof(*prop), GFP_KERNEL);
> + char *prop_name __free(kfree) = kstrdup(name, GFP_KERNEL);
> + void *value __free(kfree) = kzalloc(len, GFP_KERNEL);
> + if (!prop || !prop_name || !value)
> + return NULL;
>
> - ret = of_platform_populate(np, NULL, NULL, dev);
> - if (ret) {
> - dev_err(dev, "failed to register dwc3 core - %d\n", ret);
> - goto node_put;
> + prop->name = no_free_ptr(prop_name);
> + prop->value = no_free_ptr(value);
> + prop->length = len;
> +
> + memcpy(prop->value, a, a_len);
> + memcpy(prop->value + a_len, b, b_len);
> +
> + return_ptr(prop);
> +}
> +
> +/* Replace reg property with base address from dwc3 node and fixed length */
> +static int dwc3_qcom_legacy_update_reg(struct device_node *qcom,
> + struct device_node *dwc3)
> +{
> + int addr_cells;
> + int size_cells;
> + u64 dwc3_addr;
> + int ret;
> +
> + ret = of_property_read_reg(dwc3, 0, &dwc3_addr, NULL);
> + if (ret < 0)
> + return ret;
> +
> + addr_cells = of_n_addr_cells(qcom);
> + size_cells = of_n_addr_cells(qcom);
> +
> + __be32 *reg __free(kfree) = kcalloc(addr_cells + size_cells, sizeof(__be32), GFP_KERNEL);
> + if (!reg)
> + return -ENOMEM;
> +
> + reg[addr_cells - 1] = cpu_to_be32(dwc3_addr);
> + reg[addr_cells + size_cells - 1] = cpu_to_be32(SDM845_QSCRATCH_BASE_OFFSET + SDM845_QSCRATCH_SIZE);
> +
> + struct property *prop __free(kfree) = kzalloc(sizeof(*prop), GFP_KERNEL);
> + char *name __free(kfree) = kstrdup("reg", GFP_KERNEL);
> + if (!prop || !name)
> + return -ENOMEM;
> +
> + prop->name = no_free_ptr(name);
> + prop->value = no_free_ptr(reg);
> + prop->length = (addr_cells + size_cells) * sizeof(__be32);
> +
> + return of_update_property(qcom, no_free_ptr(prop));
> +}
> +
> +/* Prepend dwc_usb3 interrupt to relevant interrupt properties */
> +static int dwc3_qcom_legacy_convert_interrupts(struct device_node *qcom,
> + struct property *dwc3_irq)
> +{
> + const __be32 *interrupts;
> + struct property *new;
> + const void *names;
> + int interrupts_len;
> + int names_len;
> + int ret;
> +
> + if ((interrupts = of_get_property(qcom, "interrupts-extended", &interrupts_len)) != NULL) {
> + struct device_node *parent __free(device_node) = of_irq_find_parent(qcom);
> + if (!parent)
> + return -EINVAL;
> +
> + __be32 *value __free(kfree) = kzalloc(sizeof(__be32) + dwc3_irq->length, GFP_KERNEL);
> + if (!value)
> + return -ENOMEM;
> + value[0] = cpu_to_be32(parent->phandle);
> + memcpy(&value[1], dwc3_irq->value, dwc3_irq->length);
> +
> + new = dwc3_qcom_legacy_prop_concat("interrupts-extended",
> + value, sizeof(__be32) + dwc3_irq->length,
> + interrupts, interrupts_len);
> + } else if ((interrupts = of_get_property(qcom, "interrupts", &interrupts_len)) != NULL) {
> + new = dwc3_qcom_legacy_prop_concat("interrupts",
> + dwc3_irq->value, dwc3_irq->length,
> + interrupts, interrupts_len);
> + } else {
> + return -EINVAL;
> }
>
> - qcom->dwc3 = of_find_device_by_node(dwc3_np);
> - if (!qcom->dwc3) {
> - ret = -ENODEV;
> - dev_err(dev, "failed to get dwc3 platform device\n");
> - of_platform_depopulate(dev);
> + if (!new)
> + return -ENOMEM;
> +
> + ret = of_update_property(qcom, new);
> + if (ret < 0)
> + return ret;
> +
> + names = of_get_property(qcom, "interrupt-names", &names_len);
> + if (!names)
> + return -EINVAL;
> +
> + new = dwc3_qcom_legacy_prop_concat("interrupt-names",
> + "dwc_usb3", strlen("dwc_usb3") + 1,
> + names, names_len);
> + if (!new)
> + return -ENOMEM;
> +
> + return of_update_property(qcom, new);
> +}
> +
> +/* Copy property to qcom node */
> +static int dwc3_qcom_legacy_migrate_prop(struct device_node *qcom,
> + struct property *prop)
> +{
> + struct property *new __free(kfree) = kzalloc(sizeof(*new), GFP_KERNEL);
> + char *name __free(kfree) = kstrdup(prop->name, GFP_KERNEL);
> + void *value __free(kfree) = kmemdup(prop->value, prop->length, GFP_KERNEL);
> +
> + if (!new || !name || !value)
> + return -ENOMEM;
> +
> + new->name = no_free_ptr(name);
> + new->value = no_free_ptr(value);
> + new->length = prop->length;
> +
> + return of_update_property(qcom, no_free_ptr(new));
> +}
> +
> +/* Move a child node, with it's properties and children, from dwc3 to qcom node */
> +static int dwc3_qcom_legacy_migrate_child(struct device_node *qcom,
> + struct device_node *dwc3,
> + const char *name)
> +{
> + struct device_node *child;
> +
> + child = of_get_child_by_name(dwc3, name);
> + if (!child)
> + return 0;
> +
> + of_detach_node(child);
> + child->parent = qcom;
> + of_attach_node(child);
> + of_node_put(child);
> +
> + return 0;
> +}
> +
> +/* Convert dev's DeviceTree representation from qcom,dwc3 to qcom,snps-dwc3 binding */
> +static int dwc3_qcom_convert_legacy_dt(struct device *dev)
> +{
> + struct device_node *qcom = dev->of_node;
> + struct device_node *dwc3;
> + struct property *prop;
> + int ret = 0;
> +
> + dwc3 = of_get_compatible_child(qcom, "snps,dwc3");
> + if (!dwc3)
> + return 0;
> +
> + /* We have a child node, but no support for dynamic OF */
> + if (!IS_ENABLED(CONFIG_OF_DYNAMIC))
> + return -EINVAL;
> +
> + for_each_property_of_node(dwc3, prop) {
> + if (!strcmp(prop->name, "compatible"))
> + ;
> + else if (!strcmp(prop->name, "reg"))
> + ret = dwc3_qcom_legacy_update_reg(qcom, dwc3);
> + else if (!strcmp(prop->name, "interrupts"))
> + ret = dwc3_qcom_legacy_convert_interrupts(qcom, prop);
> + else
> + ret = dwc3_qcom_legacy_migrate_prop(qcom, prop);
> }
>
> -node_put:
> - of_node_put(dwc3_np);
> + if (ret < 0)
> + goto err_node_put;
> +
> + ret = dwc3_qcom_legacy_migrate_child(qcom, dwc3, "port");
> + if (ret)
> + goto err_node_put;
> +
> + ret = dwc3_qcom_legacy_migrate_child(qcom, dwc3, "ports");
> + if (ret)
> + goto err_node_put;
> +
> + of_detach_node(dwc3);
> + of_node_put(dwc3);
>
> + return 0;
> +
> +err_node_put:
> + of_node_put(dwc3);
> return ret;
> }
Look like you copy children dwc3's property into current glue node.
Can you passdown dwc3's node into dwc3_probe(), let dwc3_probe to handle
these, Or move it into dwc3-core. otherwise, if imx want to do the same
thing, the the same code will be dupicated.
>
> @@ -735,16 +894,21 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> struct device_node *np = pdev->dev.of_node;
> struct device *dev = &pdev->dev;
> struct dwc3_qcom *qcom;
> - struct resource *res;
> + struct resource res;
> int ret, i;
> bool ignore_pipe_clk;
> bool wakeup_source;
>
> + ret = dwc3_qcom_convert_legacy_dt(dev);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to convert legacy OF node\n");
> + return ret;
> + }
> +
> qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL);
> if (!qcom)
> return -ENOMEM;
>
> - platform_set_drvdata(pdev, qcom);
> qcom->dev = &pdev->dev;
>
> qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
> @@ -773,10 +937,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> goto reset_assert;
> }
>
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + ret = of_address_to_resource(np, 0, &res);
> + if (ret < 0)
> + goto clk_disable;
> + res.end = res.start + SDM845_QSCRATCH_BASE_OFFSET;
>
> - qcom->qscratch_base = devm_ioremap_resource(dev, res);
> + qcom->qscratch_base = devm_ioremap(dev, res.end, SDM845_QSCRATCH_SIZE);
> if (IS_ERR(qcom->qscratch_base)) {
> + dev_err(dev, "failed to map qscratch region: %pe\n", qcom->qscratch_base);
dev_err_probe()?
> ret = PTR_ERR(qcom->qscratch_base);
> goto clk_disable;
> }
> @@ -796,17 +964,17 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> if (ignore_pipe_clk)
> dwc3_qcom_select_utmi_clk(qcom);
>
> - ret = dwc3_qcom_of_register_core(qcom, pdev);
> - if (ret) {
> - dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
> + qcom->dwc = dwc3_probe(pdev, &res, true, qcom);
> + if (IS_ERR(qcom->dwc)) {
> + ret = dev_err_probe(dev, PTR_ERR(qcom->dwc), "failed to register DWC3 Core\n");
> goto clk_disable;
> }
>
> ret = dwc3_qcom_interconnect_init(qcom);
> if (ret)
> - goto depopulate;
> + goto remove_core;
>
> - qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev);
> + qcom->mode = usb_get_dr_mode(dev);
>
> /* enable vbus override for device mode */
> if (qcom->mode != USB_DR_MODE_HOST)
> @@ -819,20 +987,15 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
>
> wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source");
> device_init_wakeup(&pdev->dev, wakeup_source);
> - device_init_wakeup(&qcom->dwc3->dev, wakeup_source);
>
> qcom->is_suspended = false;
> - pm_runtime_set_active(dev);
> - pm_runtime_enable(dev);
> - pm_runtime_forbid(dev);
>
> return 0;
>
> interconnect_exit:
> dwc3_qcom_interconnect_exit(qcom);
> -depopulate:
> - of_platform_depopulate(&pdev->dev);
> - platform_device_put(qcom->dwc3);
> +remove_core:
> + dwc3_remove(qcom->dwc);
> clk_disable:
> for (i = qcom->num_clocks - 1; i >= 0; i--) {
> clk_disable_unprepare(qcom->clks[i]);
> @@ -846,13 +1009,11 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
>
> static void dwc3_qcom_remove(struct platform_device *pdev)
> {
> - struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
> + struct dwc3 *dwc = platform_get_drvdata(pdev);
> + struct dwc3_qcom *qcom = dwc->glue;
> struct device *dev = &pdev->dev;
> int i;
>
> - of_platform_depopulate(&pdev->dev);
> - platform_device_put(qcom->dwc3);
> -
> for (i = qcom->num_clocks - 1; i >= 0; i--) {
> clk_disable_unprepare(qcom->clks[i]);
> clk_put(qcom->clks[i]);
> @@ -868,10 +1029,15 @@ static void dwc3_qcom_remove(struct platform_device *pdev)
>
> static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
> {
> - struct dwc3_qcom *qcom = dev_get_drvdata(dev);
> + struct dwc3 *dwc = dev_get_drvdata(dev);
> + struct dwc3_qcom *qcom = dwc->glue;
> bool wakeup = device_may_wakeup(dev);
> int ret;
>
> + ret = dwc3_suspend(qcom->dwc);
> + if (ret)
> + return ret;
> +
> ret = dwc3_qcom_suspend(qcom, wakeup);
> if (ret)
> return ret;
> @@ -883,7 +1049,8 @@ static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
>
> static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
> {
> - struct dwc3_qcom *qcom = dev_get_drvdata(dev);
> + struct dwc3 *dwc = dev_get_drvdata(dev);
> + struct dwc3_qcom *qcom = dwc->glue;
> bool wakeup = device_may_wakeup(dev);
> int ret;
>
> @@ -893,31 +1060,56 @@ static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
>
> qcom->pm_suspended = false;
>
> + ret = dwc3_suspend(qcom->dwc);
> + if (ret)
> + return ret;
> +
> return 0;
> }
>
> static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev)
> {
> - struct dwc3_qcom *qcom = dev_get_drvdata(dev);
> + struct dwc3 *dwc = dev_get_drvdata(dev);
> + struct dwc3_qcom *qcom = dwc->glue;
> + int ret;
> +
> + ret = dwc3_runtime_suspend(qcom->dwc);
> + if (ret)
> + return ret;
>
> return dwc3_qcom_suspend(qcom, true);
> }
>
> +static void __maybe_unused dwc3_qcom_complete(struct device *dev)
> +{
> + struct dwc3 *dwc = dev_get_drvdata(dev);
> +
> + dwc3_complete(dwc);
> +}
> +
> static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev)
> {
> - struct dwc3_qcom *qcom = dev_get_drvdata(dev);
> + struct dwc3 *dwc = dev_get_drvdata(dev);
> + struct dwc3_qcom *qcom = dwc->glue;
> + int ret;
> +
> + ret = dwc3_qcom_resume(qcom, true);
> + if (ret)
> + return ret;
>
> - return dwc3_qcom_resume(qcom, true);
> + return dwc3_runtime_resume(qcom->dwc);
> }
>
> static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
> SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume)
> SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume,
> NULL)
> + .complete = dwc3_qcom_complete,
> };
>
> static const struct of_device_id dwc3_qcom_of_match[] = {
> { .compatible = "qcom,dwc3" },
> + { .compatible = "qcom,snps-dwc3" },
> { }
> };
> MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
>
> --
> 2.45.2
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-12 3:12 ` [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library Bjorn Andersson
` (2 preceding siblings ...)
2024-08-13 18:15 ` Frank Li
@ 2024-08-14 0:56 ` Thinh Nguyen
2024-08-19 21:14 ` Bjorn Andersson
2024-08-19 17:48 ` Krishna Kurapati
2024-09-12 22:21 ` Masahiro Yamada
5 siblings, 1 reply; 37+ messages in thread
From: Thinh Nguyen @ 2024-08-14 0:56 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio,
linux-usb@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
Bjorn Andersson
On Sun, Aug 11, 2024, Bjorn Andersson wrote:
> From: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> The DWC3 IP block is handled by three distinct device drivers: XHCI,
> DWC3 core and a platform specific (optional) DWC3 glue driver.
>
> This has resulted in, at least in the case of the Qualcomm glue, the
> presence of a number of layering violations, where the glue code either
> can't handle, or has to work around, the fact that core might not probe
> deterministically.
>
> An example of this is that the suspend path should operate slightly
> different depending on the device operating in host or peripheral mode,
> and the only way to determine the operating state is to peek into the
> core's drvdata.
>
> The Qualcomm glue driver is expected to make updates in the qscratch
> register region (the "glue" region) during role switch events, but with
> the glue and core split using the driver model, there is no reasonable
> way to introduce listeners for mode changes.
>
> Split the dwc3 core platform_driver callbacks and their implementation
> and export the implementation, to make it possible to deterministically
> instantiate the dwc3 core as part of the dwc3 glue drivers and to
> allow flattening of the DeviceTree representation.
>
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> ---
> drivers/usb/dwc3/core.c | 169 +++++++++++++++++++++++++++++++-----------------
> drivers/usb/dwc3/core.h | 3 +
> 2 files changed, 114 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 734de2a8bd21..6addb3c367e6 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -36,6 +36,7 @@
>
> #include "core.h"
> #include "gadget.h"
> +#include "glue.h"
> #include "io.h"
>
> #include "debug.h"
> @@ -2076,10 +2077,11 @@ static int dwc3_get_num_ports(struct dwc3 *dwc)
> return 0;
> }
>
> -static int dwc3_probe(struct platform_device *pdev)
> +struct dwc3 *dwc3_probe(struct platform_device *pdev, struct resource *res,
> + bool ignore_clocks_and_resets, void *glue)
Perhaps create a wrapper struct to hold the parameters above. I can see
we may expand this in the future.
> {
> struct device *dev = &pdev->dev;
> - struct resource *res, dwc_res;
> + struct resource dwc_res;
> unsigned int hw_mode;
> void __iomem *regs;
> struct dwc3 *dwc;
> @@ -2087,15 +2089,10 @@ static int dwc3_probe(struct platform_device *pdev)
>
> dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
> if (!dwc)
> - return -ENOMEM;
> + return ERR_PTR(-ENOMEM);
>
> dwc->dev = dev;
> -
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - if (!res) {
> - dev_err(dev, "missing memory resource\n");
> - return -ENODEV;
> - }
> + dwc->glue = glue;
>
> dwc->xhci_resources[0].start = res->start;
> dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
> @@ -2123,7 +2120,7 @@ static int dwc3_probe(struct platform_device *pdev)
>
> regs = devm_ioremap_resource(dev, &dwc_res);
> if (IS_ERR(regs))
> - return PTR_ERR(regs);
> + return ERR_CAST(regs);
>
> dwc->regs = regs;
> dwc->regs_size = resource_size(&dwc_res);
> @@ -2132,15 +2129,17 @@ static int dwc3_probe(struct platform_device *pdev)
>
> dwc3_get_software_properties(dwc);
>
> - dwc->reset = devm_reset_control_array_get_optional_shared(dev);
> - if (IS_ERR(dwc->reset)) {
> - ret = PTR_ERR(dwc->reset);
> - goto err_put_psy;
> - }
> + if (!ignore_clocks_and_resets) {
This seems to be specific change for your platform. Let's keep this
change separated from this patch.
Thanks,
Thinh
> + dwc->reset = devm_reset_control_array_get_optional_shared(dev);
> + if (IS_ERR(dwc->reset)) {
> + ret = PTR_ERR(dwc->reset);
> + goto err_put_psy;
> + }
>
> - ret = dwc3_get_clocks(dwc);
> - if (ret)
> - goto err_put_psy;
> + ret = dwc3_get_clocks(dwc);
> + if (ret)
> + goto err_put_psy;
> + }
>
> ret = reset_control_deassert(dwc->reset);
> if (ret)
> @@ -2225,7 +2224,7 @@ static int dwc3_probe(struct platform_device *pdev)
>
> dma_set_max_seg_size(dev, UINT_MAX);
>
> - return 0;
> + return dwc;
>
> err_exit_debugfs:
> dwc3_debugfs_exit(dwc);
> @@ -2249,14 +2248,33 @@ static int dwc3_probe(struct platform_device *pdev)
> if (dwc->usb_psy)
> power_supply_put(dwc->usb_psy);
>
> - return ret;
> + return ERR_PTR(ret);
> }
> +EXPORT_SYMBOL_GPL(dwc3_probe);
>
> -static void dwc3_remove(struct platform_device *pdev)
> +static int dwc3_plat_probe(struct platform_device *pdev)
> {
> - struct dwc3 *dwc = platform_get_drvdata(pdev);
> + struct resource *res;
> + struct dwc3 *dwc;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "missing memory resource\n");
> + return -ENODEV;
> + }
>
> - pm_runtime_get_sync(&pdev->dev);
> + dwc = dwc3_probe(pdev, res, false, NULL);
> + if (IS_ERR(dwc))
> + return PTR_ERR(dwc);
> +
> + platform_set_drvdata(pdev, dwc);
> +
> + return 0;
> +}
> +
> +void dwc3_remove(struct dwc3 *dwc)
> +{
> + pm_runtime_get_sync(dwc->dev);
>
> dwc3_core_exit_mode(dwc);
> dwc3_debugfs_exit(dwc);
> @@ -2264,22 +2282,28 @@ static void dwc3_remove(struct platform_device *pdev)
> dwc3_core_exit(dwc);
> dwc3_ulpi_exit(dwc);
>
> - pm_runtime_allow(&pdev->dev);
> - pm_runtime_disable(&pdev->dev);
> - pm_runtime_dont_use_autosuspend(&pdev->dev);
> - pm_runtime_put_noidle(&pdev->dev);
> + pm_runtime_allow(dwc->dev);
> + pm_runtime_disable(dwc->dev);
> + pm_runtime_dont_use_autosuspend(dwc->dev);
> + pm_runtime_put_noidle(dwc->dev);
> /*
> * HACK: Clear the driver data, which is currently accessed by parent
> * glue drivers, before allowing the parent to suspend.
> */
> - platform_set_drvdata(pdev, NULL);
> - pm_runtime_set_suspended(&pdev->dev);
> + dev_set_drvdata(dwc->dev, NULL);
> + pm_runtime_set_suspended(dwc->dev);
>
> dwc3_free_event_buffers(dwc);
>
> if (dwc->usb_psy)
> power_supply_put(dwc->usb_psy);
> }
> +EXPORT_SYMBOL_GPL(dwc3_remove);
> +
> +static void dwc3_plat_remove(struct platform_device *pdev)
> +{
> + dwc3_remove(platform_get_drvdata(pdev));
> +}
>
> #ifdef CONFIG_PM
> static int dwc3_core_init_for_resume(struct dwc3 *dwc)
> @@ -2450,9 +2474,8 @@ static int dwc3_runtime_checks(struct dwc3 *dwc)
> return 0;
> }
>
> -static int dwc3_runtime_suspend(struct device *dev)
> +int dwc3_runtime_suspend(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> if (dwc3_runtime_checks(dwc))
> @@ -2464,10 +2487,10 @@ static int dwc3_runtime_suspend(struct device *dev)
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_runtime_suspend);
>
> -static int dwc3_runtime_resume(struct device *dev)
> +int dwc3_runtime_resume(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
> @@ -2484,15 +2507,14 @@ static int dwc3_runtime_resume(struct device *dev)
> break;
> }
>
> - pm_runtime_mark_last_busy(dev);
> + pm_runtime_mark_last_busy(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_runtime_resume);
>
> -static int dwc3_runtime_idle(struct device *dev)
> +int dwc3_runtime_idle(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> -
> switch (dwc->current_dr_role) {
> case DWC3_GCTL_PRTCAP_DEVICE:
> if (dwc3_runtime_checks(dwc))
> @@ -2504,52 +2526,67 @@ static int dwc3_runtime_idle(struct device *dev)
> break;
> }
>
> - pm_runtime_mark_last_busy(dev);
> - pm_runtime_autosuspend(dev);
> + pm_runtime_mark_last_busy(dwc->dev);
> + pm_runtime_autosuspend(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_runtime_idle);
> +
> +static int dwc3_plat_runtime_suspend(struct device *dev)
> +{
> + return dwc3_runtime_suspend(dev_get_drvdata(dev));
> +}
> +
> +static int dwc3_plat_runtime_resume(struct device *dev)
> +{
> + return dwc3_runtime_resume(dev_get_drvdata(dev));
> +}
> +
> +static int dwc3_plat_runtime_idle(struct device *dev)
> +{
> + return dwc3_runtime_idle(dev_get_drvdata(dev));
> +}
> #endif /* CONFIG_PM */
>
> #ifdef CONFIG_PM_SLEEP
> -static int dwc3_suspend(struct device *dev)
> +int dwc3_suspend(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
> if (ret)
> return ret;
>
> - pinctrl_pm_select_sleep_state(dev);
> + pinctrl_pm_select_sleep_state(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_suspend);
>
> -static int dwc3_resume(struct device *dev)
> +int dwc3_resume(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> - pinctrl_pm_select_default_state(dev);
> + pinctrl_pm_select_default_state(dwc->dev);
>
> - pm_runtime_disable(dev);
> - pm_runtime_set_active(dev);
> + pm_runtime_disable(dwc->dev);
> + pm_runtime_set_active(dwc->dev);
>
> ret = dwc3_resume_common(dwc, PMSG_RESUME);
> if (ret) {
> - pm_runtime_set_suspended(dev);
> + pm_runtime_set_suspended(dwc->dev);
> return ret;
> }
>
> - pm_runtime_enable(dev);
> + pm_runtime_enable(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_resume);
>
> -static void dwc3_complete(struct device *dev)
> +void dwc3_complete(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> u32 reg;
>
> if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
> @@ -2559,15 +2596,31 @@ static void dwc3_complete(struct device *dev)
> dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
> }
> }
> +EXPORT_SYMBOL_GPL(dwc3_complete);
> +
> +static int dwc3_plat_suspend(struct device *dev)
> +{
> + return dwc3_suspend(dev_get_drvdata(dev));
> +}
> +
> +static int dwc3_plat_resume(struct device *dev)
> +{
> + return dwc3_resume(dev_get_drvdata(dev));
> +}
> +
> +static void dwc3_plat_complete(struct device *dev)
> +{
> + dwc3_complete(dev_get_drvdata(dev));
> +}
> #else
> -#define dwc3_complete NULL
> +#define dwc3_plat_complete NULL
> #endif /* CONFIG_PM_SLEEP */
>
> static const struct dev_pm_ops dwc3_dev_pm_ops = {
> - SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
> - .complete = dwc3_complete,
> - SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
> - dwc3_runtime_idle)
> + SET_SYSTEM_SLEEP_PM_OPS(dwc3_plat_suspend, dwc3_plat_resume)
> + .complete = dwc3_plat_complete,
> + SET_RUNTIME_PM_OPS(dwc3_plat_runtime_suspend, dwc3_plat_runtime_resume,
> + dwc3_plat_runtime_idle)
> };
>
> #ifdef CONFIG_OF
> @@ -2595,8 +2648,8 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
> #endif
>
> static struct platform_driver dwc3_driver = {
> - .probe = dwc3_probe,
> - .remove_new = dwc3_remove,
> + .probe = dwc3_plat_probe,
> + .remove_new = dwc3_plat_remove,
> .driver = {
> .name = "dwc3",
> .of_match_table = of_match_ptr(of_dwc3_match),
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index 1e561fd8b86e..4a0ee9ef72e2 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -1160,6 +1160,7 @@ struct dwc3_scratchpad_array {
> * @gsbuscfg0_reqinfo: store GSBUSCFG0.DATRDREQINFO, DESRDREQINFO,
> * DATWRREQINFO, and DESWRREQINFO value passed from
> * glue driver.
> + * @glue: private reference to any glue context
> */
> struct dwc3 {
> struct work_struct drd_work;
> @@ -1388,6 +1389,8 @@ struct dwc3 {
> int num_ep_resized;
> struct dentry *debug_root;
> u32 gsbuscfg0_reqinfo;
> +
> + void *glue;
> };
>
> #define INCRX_BURST_MODE 0
>
> --
> 2.45.2
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-13 18:15 ` Frank Li
@ 2024-08-14 1:01 ` Thinh Nguyen
2024-08-19 21:35 ` Bjorn Andersson
1 sibling, 0 replies; 37+ messages in thread
From: Thinh Nguyen @ 2024-08-14 1:01 UTC (permalink / raw)
To: Frank Li
Cc: Bjorn Andersson, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Felipe Balbi, Wesley Cheng,
Saravana Kannan, Thinh Nguyen, Philipp Zabel, Konrad Dybcio,
linux-usb@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
Bjorn Andersson
On Tue, Aug 13, 2024, Frank Li wrote:
> On Sun, Aug 11, 2024 at 08:12:01PM -0700, Bjorn Andersson wrote:
> > From: Bjorn Andersson <quic_bjorande@quicinc.com>
...
> > +{
> > + dwc3_complete(dev_get_drvdata(dev));
> > +}
> > #else
> > -#define dwc3_complete NULL
> > +#define dwc3_plat_complete NULL
> > #endif /* CONFIG_PM_SLEEP */
> >
> > static const struct dev_pm_ops dwc3_dev_pm_ops = {
> > - SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
> > - .complete = dwc3_complete,
> > - SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
> > - dwc3_runtime_idle)
> > + SET_SYSTEM_SLEEP_PM_OPS(dwc3_plat_suspend, dwc3_plat_resume)
>
> since you touch this line,
> suggest use new SYSTEM_SLEEP_PM_OPS() and RUNTIME_PM_OPS() help macro.
> also CONFIG_PM_SLEEP can be removed.
>
If we want to make that change, please keep that change separate from
this patch/series.
Thanks,
Thinh
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 1/7] dt-bindings: usb: snps,dwc3: Split core description
2024-08-12 3:11 ` [PATCH v2 1/7] dt-bindings: usb: snps,dwc3: Split core description Bjorn Andersson
@ 2024-08-18 14:33 ` Rob Herring
0 siblings, 0 replies; 37+ messages in thread
From: Rob Herring @ 2024-08-18 14:33 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Greg Kroah-Hartman, Krzysztof Kozlowski, Conor Dooley,
Felipe Balbi, Wesley Cheng, Saravana Kannan, Thinh Nguyen,
Philipp Zabel, Konrad Dybcio, linux-usb, devicetree, linux-kernel,
linux-arm-msm, Bjorn Andersson
On Sun, Aug 11, 2024 at 08:11:58PM -0700, Bjorn Andersson wrote:
> From: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> The Synopsys DWC3 core is found either as a standard block or integrated
> with vendor glue logic. So far the latter has been described as two
> separate IP blocks in DeviceTree, but the two parts are not separate.
>
> In the case where the core is integrated together with vendor glue,
> resources such as clock and resets are often customized by the vendor,
> such that the standard properties doesn't make sense.
>
> Split the snps,dwc3 binding in a description of the core properties and
> the standard "glue" properties, in order to allow vendor bindings to
> inherit the core properties.
>
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> ---
> .../devicetree/bindings/usb/snps,dwc3-common.yaml | 417 +++++++++++++++++++++
> .../devicetree/bindings/usb/snps,dwc3.yaml | 391 +------------------
> 2 files changed, 418 insertions(+), 390 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml
> new file mode 100644
> index 000000000000..65e7900f904a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/usb/snps,dwc3-common.yaml
> @@ -0,0 +1,417 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/usb/snps,dwc3-common.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Synopsys DesignWare USB3 Controller common properties
> +
> +select: false
You can drop this.
With that,
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-12 3:12 ` [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library Bjorn Andersson
` (3 preceding siblings ...)
2024-08-14 0:56 ` Thinh Nguyen
@ 2024-08-19 17:48 ` Krishna Kurapati
2024-08-19 21:36 ` Bjorn Andersson
2024-09-12 22:21 ` Masahiro Yamada
5 siblings, 1 reply; 37+ messages in thread
From: Krishna Kurapati @ 2024-08-19 17:48 UTC (permalink / raw)
To: Bjorn Andersson, Thinh Nguyen
Cc: linux-usb, devicetree, linux-kernel, Greg Kroah-Hartman,
Rob Herring, Wesley Cheng, linux-arm-msm, Krzysztof Kozlowski,
Bjorn Andersson, Conor Dooley, Konrad Dybcio, Philipp Zabel,
Saravana Kannan, Felipe Balbi
On 8/12/2024 8:42 AM, Bjorn Andersson wrote:
> From: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> The DWC3 IP block is handled by three distinct device drivers: XHCI,
> DWC3 core and a platform specific (optional) DWC3 glue driver.
>
> This has resulted in, at least in the case of the Qualcomm glue, the
> presence of a number of layering violations, where the glue code either
> can't handle, or has to work around, the fact that core might not probe
> deterministically.
>
> An example of this is that the suspend path should operate slightly
> different depending on the device operating in host or peripheral mode,
> and the only way to determine the operating state is to peek into the
> core's drvdata.
>
> The Qualcomm glue driver is expected to make updates in the qscratch
> register region (the "glue" region) during role switch events, but with
> the glue and core split using the driver model, there is no reasonable
> way to introduce listeners for mode changes.
>
> Split the dwc3 core platform_driver callbacks and their implementation
> and export the implementation, to make it possible to deterministically
> instantiate the dwc3 core as part of the dwc3 glue drivers and to
> allow flattening of the DeviceTree representation.
>
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
...
> -static int dwc3_probe(struct platform_device *pdev)
> +struct dwc3 *dwc3_probe(struct platform_device *pdev, struct resource *res,
> + bool ignore_clocks_and_resets, void *glue)
> {
> struct device *dev = &pdev->dev;
> - struct resource *res, dwc_res;
> + struct resource dwc_res;
> unsigned int hw_mode;
> void __iomem *regs;
> struct dwc3 *dwc;
> @@ -2087,15 +2089,10 @@ static int dwc3_probe(struct platform_device *pdev)
>
> dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
> if (!dwc)
> - return -ENOMEM;
> + return ERR_PTR(-ENOMEM);
>
> dwc->dev = dev;
> -
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - if (!res) {
> - dev_err(dev, "missing memory resource\n");
> - return -ENODEV;
> - }
...
> +static int dwc3_plat_probe(struct platform_device *pdev)
> {
> - struct dwc3 *dwc = platform_get_drvdata(pdev);
> + struct resource *res;
> + struct dwc3 *dwc;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "missing memory resource\n");
> + return -ENODEV;
> + }
>
> - pm_runtime_get_sync(&pdev->dev);
> + dwc = dwc3_probe(pdev, res, false, NULL);
> + if (IS_ERR(dwc))
> + return PTR_ERR(dwc);
> +
> + platform_set_drvdata(pdev, dwc);
This setting of platform drvdata is redundant I believe. We already do
it in dwc3_probe.
> +
> + return 0;
> +}
> +
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-14 0:56 ` Thinh Nguyen
@ 2024-08-19 21:14 ` Bjorn Andersson
0 siblings, 0 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-19 21:14 UTC (permalink / raw)
To: Thinh Nguyen
Cc: Bjorn Andersson, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Felipe Balbi, Wesley Cheng,
Saravana Kannan, Philipp Zabel, Konrad Dybcio,
linux-usb@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org
On Wed, Aug 14, 2024 at 12:56:44AM +0000, Thinh Nguyen wrote:
> On Sun, Aug 11, 2024, Bjorn Andersson wrote:
> > From: Bjorn Andersson <quic_bjorande@quicinc.com>
> > diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
[..]
> > @@ -2076,10 +2077,11 @@ static int dwc3_get_num_ports(struct dwc3 *dwc)
> > return 0;
> > }
> >
> > -static int dwc3_probe(struct platform_device *pdev)
> > +struct dwc3 *dwc3_probe(struct platform_device *pdev, struct resource *res,
> > + bool ignore_clocks_and_resets, void *glue)
>
> Perhaps create a wrapper struct to hold the parameters above. I can see
> we may expand this in the future.
>
Sounds good.
There are a few cases where e.g. the Qualcomm glue needs to react to
role switching in the core, so we already know that we want to add some
callbacks here.
> > {
> > struct device *dev = &pdev->dev;
> > - struct resource *res, dwc_res;
> > + struct resource dwc_res;
> > unsigned int hw_mode;
> > void __iomem *regs;
> > struct dwc3 *dwc;
> > @@ -2087,15 +2089,10 @@ static int dwc3_probe(struct platform_device *pdev)
> >
> > dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
> > if (!dwc)
> > - return -ENOMEM;
> > + return ERR_PTR(-ENOMEM);
> >
> > dwc->dev = dev;
> > -
> > - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > - if (!res) {
> > - dev_err(dev, "missing memory resource\n");
> > - return -ENODEV;
> > - }
> > + dwc->glue = glue;
> >
> > dwc->xhci_resources[0].start = res->start;
> > dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
> > @@ -2123,7 +2120,7 @@ static int dwc3_probe(struct platform_device *pdev)
> >
> > regs = devm_ioremap_resource(dev, &dwc_res);
> > if (IS_ERR(regs))
> > - return PTR_ERR(regs);
> > + return ERR_CAST(regs);
> >
> > dwc->regs = regs;
> > dwc->regs_size = resource_size(&dwc_res);
> > @@ -2132,15 +2129,17 @@ static int dwc3_probe(struct platform_device *pdev)
> >
> > dwc3_get_software_properties(dwc);
> >
> > - dwc->reset = devm_reset_control_array_get_optional_shared(dev);
> > - if (IS_ERR(dwc->reset)) {
> > - ret = PTR_ERR(dwc->reset);
> > - goto err_put_psy;
> > - }
> > + if (!ignore_clocks_and_resets) {
>
> This seems to be specific change for your platform. Let's keep this
> change separated from this patch.
>
The primary need here is that the glue code needs to be able to access
the hardware before the core's resume and after suspend. I'd expect
other glue implementations will have the same need.
But moving this change to a separate change allows us to reason about
that separately, so I like the suggestion.
Thanks,
Bjorn
> Thanks,
> Thinh
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 5/7] usb: dwc3: qcom: Don't reply on drvdata during probe
2024-08-13 18:18 ` Frank Li
@ 2024-08-19 21:17 ` Bjorn Andersson
0 siblings, 0 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-19 21:17 UTC (permalink / raw)
To: Frank Li
Cc: Bjorn Andersson, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Felipe Balbi, Wesley Cheng,
Saravana Kannan, Thinh Nguyen, Philipp Zabel, Konrad Dybcio,
linux-usb, devicetree, linux-kernel, linux-arm-msm
On Tue, Aug 13, 2024 at 02:18:44PM -0400, Frank Li wrote:
> On Sun, Aug 11, 2024 at 08:12:02PM -0700, Bjorn Andersson wrote:
> > From: Bjorn Andersson <quic_bjorande@quicinc.com>
> >
> > With the upcoming transition to a model where DWC3 core and glue operate
> > on a single struct device the drvdata datatype will change to be owned
> > by the core.
> >
> > The drvdata is however used by the Qualcomm DWC3 glue to pass the qcom
> > glue context around before the core is allocated.
> >
> > Remove this problem, and clean up the code, by passing the dwc3_qcom
> > struct around during probe, instead of acquiring it from the drvdata.
> >
> > Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> > ---
> > drivers/usb/dwc3/dwc3-qcom.c | 17 ++++++++---------
> > 1 file changed, 8 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
> > index 88fb6706a18d..33de03f2d782 100644
> > --- a/drivers/usb/dwc3/dwc3-qcom.c
> > +++ b/drivers/usb/dwc3/dwc3-qcom.c
> > @@ -546,9 +546,10 @@ static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq,
> > return ret;
> > }
> >
> > -static int dwc3_qcom_setup_port_irq(struct platform_device *pdev, int port_index, bool is_multiport)
> > +static int dwc3_qcom_setup_port_irq(struct dwc3_qcom *qcom,
>
> If pass "qcom", do you need "pdev"? generaly, qcom should have pdev information.
>
We're only carrying the struct device reference in the dwc3_qcom struct,
as we don't have a use for the platform_device reference beyond probe.
Regards,
Bjorn
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model
2024-08-13 18:33 ` Frank Li
@ 2024-08-19 21:28 ` Bjorn Andersson
0 siblings, 0 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-19 21:28 UTC (permalink / raw)
To: Frank Li
Cc: Bjorn Andersson, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Felipe Balbi, Wesley Cheng,
Saravana Kannan, Thinh Nguyen, Philipp Zabel, Konrad Dybcio,
linux-usb, devicetree, linux-kernel, linux-arm-msm
On Tue, Aug 13, 2024 at 02:33:56PM -0400, Frank Li wrote:
> On Sun, Aug 11, 2024 at 08:12:03PM -0700, Bjorn Andersson wrote:
> > From: Bjorn Andersson <quic_bjorande@quicinc.com>
> > drivers/usb/dwc3/dwc3-qcom.c | 310 +++++++++++++++++++++++++++++++++++--------
[..]
> > @@ -302,25 +306,16 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
> > /* Only usable in contexts where the role can not change. */
> > static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
> > {
> > - struct dwc3 *dwc;
> > -
> > - /*
> > - * FIXME: Fix this layering violation.
> > - */
> > - dwc = platform_get_drvdata(qcom->dwc3);
> > -
> > - /* Core driver may not have probed yet. */
> > - if (!dwc)
> > - return false;
> > + struct dwc3 *dwc = qcom->dwc;
> >
> > return dwc->xhci;
>
> dwc only use once.
>
> return qcom->dwc->xhci?
>
I like it, thanks for the suggestion.
> > }
> >
[..]
> > +/* Convert dev's DeviceTree representation from qcom,dwc3 to qcom,snps-dwc3 binding */
> > +static int dwc3_qcom_convert_legacy_dt(struct device *dev)
> > +{
> > + struct device_node *qcom = dev->of_node;
> > + struct device_node *dwc3;
> > + struct property *prop;
> > + int ret = 0;
> > +
> > + dwc3 = of_get_compatible_child(qcom, "snps,dwc3");
> > + if (!dwc3)
> > + return 0;
> > +
> > + /* We have a child node, but no support for dynamic OF */
> > + if (!IS_ENABLED(CONFIG_OF_DYNAMIC))
> > + return -EINVAL;
> > +
> > + for_each_property_of_node(dwc3, prop) {
> > + if (!strcmp(prop->name, "compatible"))
> > + ;
> > + else if (!strcmp(prop->name, "reg"))
> > + ret = dwc3_qcom_legacy_update_reg(qcom, dwc3);
> > + else if (!strcmp(prop->name, "interrupts"))
> > + ret = dwc3_qcom_legacy_convert_interrupts(qcom, prop);
> > + else
> > + ret = dwc3_qcom_legacy_migrate_prop(qcom, prop);
> > }
> >
> > -node_put:
> > - of_node_put(dwc3_np);
> > + if (ret < 0)
> > + goto err_node_put;
> > +
> > + ret = dwc3_qcom_legacy_migrate_child(qcom, dwc3, "port");
> > + if (ret)
> > + goto err_node_put;
> > +
> > + ret = dwc3_qcom_legacy_migrate_child(qcom, dwc3, "ports");
> > + if (ret)
> > + goto err_node_put;
> > +
> > + of_detach_node(dwc3);
> > + of_node_put(dwc3);
> >
> > + return 0;
> > +
> > +err_node_put:
> > + of_node_put(dwc3);
> > return ret;
> > }
>
> Look like you copy children dwc3's property into current glue node.
> Can you passdown dwc3's node into dwc3_probe(), let dwc3_probe to handle
> these, Or move it into dwc3-core. otherwise, if imx want to do the same
> thing, the the same code will be dupicated.
>
I tried that, as it would have saved me from having to do the dynamic
rewrite.
But the dwc3 core and host are full of device_property_read*(),
phy_get(), platform_get_irq() etc which operates on the dwc->dev.
I think it can be done, but this felt like a cleaner outcome, in
particular once we transition the DeviceTree source.
As you say, there should be a fair amount of room for duplication here,
so perhaps we can move that to a "glue.c" and share it?
[..]
> > @@ -773,10 +937,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> > goto reset_assert;
> > }
> >
> > - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + ret = of_address_to_resource(np, 0, &res);
> > + if (ret < 0)
> > + goto clk_disable;
> > + res.end = res.start + SDM845_QSCRATCH_BASE_OFFSET;
> >
> > - qcom->qscratch_base = devm_ioremap_resource(dev, res);
> > + qcom->qscratch_base = devm_ioremap(dev, res.end, SDM845_QSCRATCH_SIZE);
> > if (IS_ERR(qcom->qscratch_base)) {
> > + dev_err(dev, "failed to map qscratch region: %pe\n", qcom->qscratch_base);
>
> dev_err_probe()?
>
Sounds good.
Thank you,
Bjorn
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-13 18:15 ` Frank Li
2024-08-14 1:01 ` Thinh Nguyen
@ 2024-08-19 21:35 ` Bjorn Andersson
1 sibling, 0 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-19 21:35 UTC (permalink / raw)
To: Frank Li
Cc: Bjorn Andersson, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Felipe Balbi, Wesley Cheng,
Saravana Kannan, Thinh Nguyen, Philipp Zabel, Konrad Dybcio,
linux-usb, devicetree, linux-kernel, linux-arm-msm
On Tue, Aug 13, 2024 at 02:15:35PM -0400, Frank Li wrote:
> On Sun, Aug 11, 2024 at 08:12:01PM -0700, Bjorn Andersson wrote:
> > From: Bjorn Andersson <quic_bjorande@quicinc.com>
> > diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
[..]
> > static const struct dev_pm_ops dwc3_dev_pm_ops = {
> > - SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
> > - .complete = dwc3_complete,
> > - SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
> > - dwc3_runtime_idle)
> > + SET_SYSTEM_SLEEP_PM_OPS(dwc3_plat_suspend, dwc3_plat_resume)
>
> since you touch this line,
> suggest use new SYSTEM_SLEEP_PM_OPS() and RUNTIME_PM_OPS() help macro.
> also CONFIG_PM_SLEEP can be removed.
>
I'd be happy to follow up with such cleanups after we've concluded this,
I did spot a few other things that would benefit from some TLC.
Regards,
Bjorn
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-19 17:48 ` Krishna Kurapati
@ 2024-08-19 21:36 ` Bjorn Andersson
0 siblings, 0 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-08-19 21:36 UTC (permalink / raw)
To: Krishna Kurapati
Cc: Bjorn Andersson, Thinh Nguyen, linux-usb, devicetree,
linux-kernel, Greg Kroah-Hartman, Rob Herring, Wesley Cheng,
linux-arm-msm, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
Philipp Zabel, Saravana Kannan, Felipe Balbi
On Mon, Aug 19, 2024 at 11:18:15PM +0530, Krishna Kurapati wrote:
>
>
> On 8/12/2024 8:42 AM, Bjorn Andersson wrote:
> > From: Bjorn Andersson <quic_bjorande@quicinc.com>
> >
> > The DWC3 IP block is handled by three distinct device drivers: XHCI,
> > DWC3 core and a platform specific (optional) DWC3 glue driver.
> >
> > This has resulted in, at least in the case of the Qualcomm glue, the
> > presence of a number of layering violations, where the glue code either
> > can't handle, or has to work around, the fact that core might not probe
> > deterministically.
> >
> > An example of this is that the suspend path should operate slightly
> > different depending on the device operating in host or peripheral mode,
> > and the only way to determine the operating state is to peek into the
> > core's drvdata.
> >
> > The Qualcomm glue driver is expected to make updates in the qscratch
> > register region (the "glue" region) during role switch events, but with
> > the glue and core split using the driver model, there is no reasonable
> > way to introduce listeners for mode changes.
> >
> > Split the dwc3 core platform_driver callbacks and their implementation
> > and export the implementation, to make it possible to deterministically
> > instantiate the dwc3 core as part of the dwc3 glue drivers and to
> > allow flattening of the DeviceTree representation.
> >
> > Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> ...
>
> > -static int dwc3_probe(struct platform_device *pdev)
> > +struct dwc3 *dwc3_probe(struct platform_device *pdev, struct resource *res,
> > + bool ignore_clocks_and_resets, void *glue)
> > {
> > struct device *dev = &pdev->dev;
> > - struct resource *res, dwc_res;
> > + struct resource dwc_res;
> > unsigned int hw_mode;
> > void __iomem *regs;
> > struct dwc3 *dwc;
> > @@ -2087,15 +2089,10 @@ static int dwc3_probe(struct platform_device *pdev)
> > dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
> > if (!dwc)
> > - return -ENOMEM;
> > + return ERR_PTR(-ENOMEM);
> > dwc->dev = dev;
> > -
> > - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > - if (!res) {
> > - dev_err(dev, "missing memory resource\n");
> > - return -ENODEV;
> > - }
>
> ...
>
> > +static int dwc3_plat_probe(struct platform_device *pdev)
> > {
> > - struct dwc3 *dwc = platform_get_drvdata(pdev);
> > + struct resource *res;
> > + struct dwc3 *dwc;
> > +
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + if (!res) {
> > + dev_err(&pdev->dev, "missing memory resource\n");
> > + return -ENODEV;
> > + }
> > - pm_runtime_get_sync(&pdev->dev);
> > + dwc = dwc3_probe(pdev, res, false, NULL);
> > + if (IS_ERR(dwc))
> > + return PTR_ERR(dwc);
> > +
> > + platform_set_drvdata(pdev, dwc);
>
> This setting of platform drvdata is redundant I believe. We already do it in
> dwc3_probe.
>
Good catch, you're certainly right.
Regards,
Bjorn
> > +
> > + return 0;
> > +}
> > +
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-08-12 3:12 ` [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library Bjorn Andersson
` (4 preceding siblings ...)
2024-08-19 17:48 ` Krishna Kurapati
@ 2024-09-12 22:21 ` Masahiro Yamada
2024-09-13 2:34 ` Bjorn Andersson
5 siblings, 1 reply; 37+ messages in thread
From: Masahiro Yamada @ 2024-09-12 22:21 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio, linux-usb, devicetree,
linux-kernel, linux-arm-msm, Bjorn Andersson
[-- Attachment #1: Type: text/plain, Size: 13609 bytes --]
On Mon, Aug 12, 2024 at 12:07 PM Bjorn Andersson <andersson@kernel.org> wrote:
>
> From: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> The DWC3 IP block is handled by three distinct device drivers: XHCI,
> DWC3 core and a platform specific (optional) DWC3 glue driver.
>
> This has resulted in, at least in the case of the Qualcomm glue, the
> presence of a number of layering violations, where the glue code either
> can't handle, or has to work around, the fact that core might not probe
> deterministically.
>
> An example of this is that the suspend path should operate slightly
> different depending on the device operating in host or peripheral mode,
> and the only way to determine the operating state is to peek into the
> core's drvdata.
>
> The Qualcomm glue driver is expected to make updates in the qscratch
> register region (the "glue" region) during role switch events, but with
> the glue and core split using the driver model, there is no reasonable
> way to introduce listeners for mode changes.
>
> Split the dwc3 core platform_driver callbacks and their implementation
> and export the implementation, to make it possible to deterministically
> instantiate the dwc3 core as part of the dwc3 glue drivers and to
> allow flattening of the DeviceTree representation.
>
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> ---
> drivers/usb/dwc3/core.c | 169 +++++++++++++++++++++++++++++++-----------------
> drivers/usb/dwc3/core.h | 3 +
> 2 files changed, 114 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 734de2a8bd21..6addb3c367e6 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -36,6 +36,7 @@
>
> #include "core.h"
> #include "gadget.h"
> +#include "glue.h"
> #include "io.h"
>
> #include "debug.h"
> @@ -2076,10 +2077,11 @@ static int dwc3_get_num_ports(struct dwc3 *dwc)
> return 0;
> }
>
> -static int dwc3_probe(struct platform_device *pdev)
> +struct dwc3 *dwc3_probe(struct platform_device *pdev, struct resource *res,
> + bool ignore_clocks_and_resets, void *glue)
> {
> struct device *dev = &pdev->dev;
> - struct resource *res, dwc_res;
> + struct resource dwc_res;
> unsigned int hw_mode;
> void __iomem *regs;
> struct dwc3 *dwc;
> @@ -2087,15 +2089,10 @@ static int dwc3_probe(struct platform_device *pdev)
>
> dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
> if (!dwc)
> - return -ENOMEM;
> + return ERR_PTR(-ENOMEM);
>
> dwc->dev = dev;
> -
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - if (!res) {
> - dev_err(dev, "missing memory resource\n");
> - return -ENODEV;
> - }
> + dwc->glue = glue;
>
> dwc->xhci_resources[0].start = res->start;
> dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
> @@ -2123,7 +2120,7 @@ static int dwc3_probe(struct platform_device *pdev)
>
> regs = devm_ioremap_resource(dev, &dwc_res);
> if (IS_ERR(regs))
> - return PTR_ERR(regs);
> + return ERR_CAST(regs);
>
> dwc->regs = regs;
> dwc->regs_size = resource_size(&dwc_res);
> @@ -2132,15 +2129,17 @@ static int dwc3_probe(struct platform_device *pdev)
>
> dwc3_get_software_properties(dwc);
>
> - dwc->reset = devm_reset_control_array_get_optional_shared(dev);
> - if (IS_ERR(dwc->reset)) {
> - ret = PTR_ERR(dwc->reset);
> - goto err_put_psy;
> - }
> + if (!ignore_clocks_and_resets) {
> + dwc->reset = devm_reset_control_array_get_optional_shared(dev);
> + if (IS_ERR(dwc->reset)) {
> + ret = PTR_ERR(dwc->reset);
> + goto err_put_psy;
> + }
>
> - ret = dwc3_get_clocks(dwc);
> - if (ret)
> - goto err_put_psy;
> + ret = dwc3_get_clocks(dwc);
> + if (ret)
> + goto err_put_psy;
> + }
>
> ret = reset_control_deassert(dwc->reset);
> if (ret)
> @@ -2225,7 +2224,7 @@ static int dwc3_probe(struct platform_device *pdev)
>
> dma_set_max_seg_size(dev, UINT_MAX);
>
> - return 0;
> + return dwc;
>
> err_exit_debugfs:
> dwc3_debugfs_exit(dwc);
> @@ -2249,14 +2248,33 @@ static int dwc3_probe(struct platform_device *pdev)
> if (dwc->usb_psy)
> power_supply_put(dwc->usb_psy);
>
> - return ret;
> + return ERR_PTR(ret);
> }
> +EXPORT_SYMBOL_GPL(dwc3_probe);
>
> -static void dwc3_remove(struct platform_device *pdev)
> +static int dwc3_plat_probe(struct platform_device *pdev)
> {
> - struct dwc3 *dwc = platform_get_drvdata(pdev);
> + struct resource *res;
> + struct dwc3 *dwc;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "missing memory resource\n");
> + return -ENODEV;
> + }
>
> - pm_runtime_get_sync(&pdev->dev);
> + dwc = dwc3_probe(pdev, res, false, NULL);
> + if (IS_ERR(dwc))
> + return PTR_ERR(dwc);
> +
> + platform_set_drvdata(pdev, dwc);
> +
> + return 0;
> +}
> +
> +void dwc3_remove(struct dwc3 *dwc)
> +{
> + pm_runtime_get_sync(dwc->dev);
>
> dwc3_core_exit_mode(dwc);
> dwc3_debugfs_exit(dwc);
> @@ -2264,22 +2282,28 @@ static void dwc3_remove(struct platform_device *pdev)
> dwc3_core_exit(dwc);
> dwc3_ulpi_exit(dwc);
>
> - pm_runtime_allow(&pdev->dev);
> - pm_runtime_disable(&pdev->dev);
> - pm_runtime_dont_use_autosuspend(&pdev->dev);
> - pm_runtime_put_noidle(&pdev->dev);
> + pm_runtime_allow(dwc->dev);
> + pm_runtime_disable(dwc->dev);
> + pm_runtime_dont_use_autosuspend(dwc->dev);
> + pm_runtime_put_noidle(dwc->dev);
> /*
> * HACK: Clear the driver data, which is currently accessed by parent
> * glue drivers, before allowing the parent to suspend.
> */
> - platform_set_drvdata(pdev, NULL);
> - pm_runtime_set_suspended(&pdev->dev);
> + dev_set_drvdata(dwc->dev, NULL);
> + pm_runtime_set_suspended(dwc->dev);
>
> dwc3_free_event_buffers(dwc);
>
> if (dwc->usb_psy)
> power_supply_put(dwc->usb_psy);
> }
> +EXPORT_SYMBOL_GPL(dwc3_remove);
> +
> +static void dwc3_plat_remove(struct platform_device *pdev)
> +{
> + dwc3_remove(platform_get_drvdata(pdev));
> +}
>
> #ifdef CONFIG_PM
> static int dwc3_core_init_for_resume(struct dwc3 *dwc)
> @@ -2450,9 +2474,8 @@ static int dwc3_runtime_checks(struct dwc3 *dwc)
> return 0;
> }
>
> -static int dwc3_runtime_suspend(struct device *dev)
> +int dwc3_runtime_suspend(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> if (dwc3_runtime_checks(dwc))
> @@ -2464,10 +2487,10 @@ static int dwc3_runtime_suspend(struct device *dev)
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_runtime_suspend);
>
> -static int dwc3_runtime_resume(struct device *dev)
> +int dwc3_runtime_resume(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
> @@ -2484,15 +2507,14 @@ static int dwc3_runtime_resume(struct device *dev)
> break;
> }
>
> - pm_runtime_mark_last_busy(dev);
> + pm_runtime_mark_last_busy(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_runtime_resume);
>
> -static int dwc3_runtime_idle(struct device *dev)
> +int dwc3_runtime_idle(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> -
> switch (dwc->current_dr_role) {
> case DWC3_GCTL_PRTCAP_DEVICE:
> if (dwc3_runtime_checks(dwc))
> @@ -2504,52 +2526,67 @@ static int dwc3_runtime_idle(struct device *dev)
> break;
> }
>
> - pm_runtime_mark_last_busy(dev);
> - pm_runtime_autosuspend(dev);
> + pm_runtime_mark_last_busy(dwc->dev);
> + pm_runtime_autosuspend(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_runtime_idle);
> +
> +static int dwc3_plat_runtime_suspend(struct device *dev)
> +{
> + return dwc3_runtime_suspend(dev_get_drvdata(dev));
> +}
> +
> +static int dwc3_plat_runtime_resume(struct device *dev)
> +{
> + return dwc3_runtime_resume(dev_get_drvdata(dev));
> +}
> +
> +static int dwc3_plat_runtime_idle(struct device *dev)
> +{
> + return dwc3_runtime_idle(dev_get_drvdata(dev));
> +}
> #endif /* CONFIG_PM */
>
> #ifdef CONFIG_PM_SLEEP
> -static int dwc3_suspend(struct device *dev)
> +int dwc3_suspend(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
> if (ret)
> return ret;
>
> - pinctrl_pm_select_sleep_state(dev);
> + pinctrl_pm_select_sleep_state(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_suspend);
>
> -static int dwc3_resume(struct device *dev)
> +int dwc3_resume(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> int ret;
>
> - pinctrl_pm_select_default_state(dev);
> + pinctrl_pm_select_default_state(dwc->dev);
>
> - pm_runtime_disable(dev);
> - pm_runtime_set_active(dev);
> + pm_runtime_disable(dwc->dev);
> + pm_runtime_set_active(dwc->dev);
>
> ret = dwc3_resume_common(dwc, PMSG_RESUME);
> if (ret) {
> - pm_runtime_set_suspended(dev);
> + pm_runtime_set_suspended(dwc->dev);
> return ret;
> }
>
> - pm_runtime_enable(dev);
> + pm_runtime_enable(dwc->dev);
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(dwc3_resume);
>
> -static void dwc3_complete(struct device *dev)
> +void dwc3_complete(struct dwc3 *dwc)
> {
> - struct dwc3 *dwc = dev_get_drvdata(dev);
> u32 reg;
>
> if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
> @@ -2559,15 +2596,31 @@ static void dwc3_complete(struct device *dev)
> dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
> }
> }
> +EXPORT_SYMBOL_GPL(dwc3_complete);
> +
> +static int dwc3_plat_suspend(struct device *dev)
> +{
> + return dwc3_suspend(dev_get_drvdata(dev));
> +}
> +
> +static int dwc3_plat_resume(struct device *dev)
> +{
> + return dwc3_resume(dev_get_drvdata(dev));
> +}
> +
> +static void dwc3_plat_complete(struct device *dev)
> +{
> + dwc3_complete(dev_get_drvdata(dev));
> +}
> #else
> -#define dwc3_complete NULL
> +#define dwc3_plat_complete NULL
> #endif /* CONFIG_PM_SLEEP */
>
> static const struct dev_pm_ops dwc3_dev_pm_ops = {
> - SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
> - .complete = dwc3_complete,
> - SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
> - dwc3_runtime_idle)
> + SET_SYSTEM_SLEEP_PM_OPS(dwc3_plat_suspend, dwc3_plat_resume)
> + .complete = dwc3_plat_complete,
> + SET_RUNTIME_PM_OPS(dwc3_plat_runtime_suspend, dwc3_plat_runtime_resume,
> + dwc3_plat_runtime_idle)
> };
>
> #ifdef CONFIG_OF
> @@ -2595,8 +2648,8 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
> #endif
>
> static struct platform_driver dwc3_driver = {
> - .probe = dwc3_probe,
> - .remove_new = dwc3_remove,
> + .probe = dwc3_plat_probe,
> + .remove_new = dwc3_plat_remove,
> .driver = {
> .name = "dwc3",
> .of_match_table = of_match_ptr(of_dwc3_match),
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index 1e561fd8b86e..4a0ee9ef72e2 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -1160,6 +1160,7 @@ struct dwc3_scratchpad_array {
> * @gsbuscfg0_reqinfo: store GSBUSCFG0.DATRDREQINFO, DESRDREQINFO,
> * DATWRREQINFO, and DESWRREQINFO value passed from
> * glue driver.
> + * @glue: private reference to any glue context
> */
> struct dwc3 {
> struct work_struct drd_work;
> @@ -1388,6 +1389,8 @@ struct dwc3 {
> int num_ep_resized;
> struct dentry *debug_root;
> u32 gsbuscfg0_reqinfo;
> +
> + void *glue;
This is ugly.
'struct dwc3_qcom' can wrap 'struct dwc3'
instead of having two separate structures
pointing at each other.
You can use container_of() to
convert (struct dwc3 *) to (struct dwc3_qcom *).
I attached a diff to delete the reverse ->glue pointer.
I did not compile-test it (I cannot due to missing glue.h
anyway), but you will understand my suggestion.
--
Best Regards
Masahiro Yamada
[-- Attachment #2: remove-glue-pointer.diff --]
[-- Type: text/x-patch, Size: 5966 bytes --]
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 5b5f6831d9f3..9d1f7db937d0 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -2085,23 +2085,14 @@ static int dwc3_get_num_ports(struct dwc3 *dwc)
return 0;
}
-struct dwc3 *dwc3_probe(struct platform_device *pdev, struct resource *res,
- bool ignore_clocks_and_resets, void *glue)
+int dwc3_init(struct dwc3 *dwc, struct resource *res, bool ignore_clocks_and_resets)
{
- struct device *dev = &pdev->dev;
+ struct device *dev = dwc->dev;
struct resource dwc_res;
unsigned int hw_mode;
void __iomem *regs;
- struct dwc3 *dwc;
int ret;
- dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
- if (!dwc)
- return ERR_PTR(-ENOMEM);
-
- dwc->dev = dev;
- dwc->glue = glue;
-
dwc->xhci_resources[0].start = res->start;
dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
DWC3_XHCI_REGS_END;
@@ -2163,7 +2154,7 @@ struct dwc3 *dwc3_probe(struct platform_device *pdev, struct resource *res,
goto err_disable_clks;
}
- platform_set_drvdata(pdev, dwc);
+ dev_set_drvdata(dev, dwc);
dwc3_cache_hwparams(dwc);
if (!dwc->sysdev_is_parent &&
@@ -2271,16 +2262,20 @@ static int dwc3_plat_probe(struct platform_device *pdev)
return -ENODEV;
}
- dwc = dwc3_probe(pdev, res, false, NULL);
- if (IS_ERR(dwc))
- return PTR_ERR(dwc);
+ dwc = devm_kzalloc(&pdev->dev, sizeof(*dwc), GFP_KERNEL);
+ if (!dwc)
+ return ERR_PTR(-ENOMEM);
- platform_set_drvdata(pdev, dwc);
+ dwc->dev = &pdev->dev;
+
+ ret = dwc3_init(dwc, res, false);
+ if (ret)
+ return ret;
return 0;
}
-void dwc3_remove(struct dwc3 *dwc)
+void dwc3_uninit(struct dwc3 *dwc)
{
pm_runtime_get_sync(dwc->dev);
@@ -2306,11 +2301,11 @@ void dwc3_remove(struct dwc3 *dwc)
if (dwc->usb_psy)
power_supply_put(dwc->usb_psy);
}
-EXPORT_SYMBOL_GPL(dwc3_remove);
+EXPORT_SYMBOL_GPL(dwc3_uninit);
-static void dwc3_plat_remove(struct platform_device *pdev)
+static void dwc3_remove(struct platform_device *pdev)
{
- dwc3_remove(platform_get_drvdata(pdev));
+ dwc3_uninit(platform_get_drvdata(pdev));
}
#ifdef CONFIG_PM
@@ -2656,8 +2651,8 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
#endif
static struct platform_driver dwc3_driver = {
- .probe = dwc3_plat_probe,
- .remove_new = dwc3_plat_remove,
+ .probe = dwc3_probe,
+ .remove_new = dwc3_remove,
.driver = {
.name = "dwc3",
.of_match_table = of_match_ptr(of_dwc3_match),
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4a0ee9ef72e2..1e561fd8b86e 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1160,7 +1160,6 @@ struct dwc3_scratchpad_array {
* @gsbuscfg0_reqinfo: store GSBUSCFG0.DATRDREQINFO, DESRDREQINFO,
* DATWRREQINFO, and DESWRREQINFO value passed from
* glue driver.
- * @glue: private reference to any glue context
*/
struct dwc3 {
struct work_struct drd_work;
@@ -1389,8 +1388,6 @@ struct dwc3 {
int num_ep_resized;
struct dentry *debug_root;
u32 gsbuscfg0_reqinfo;
-
- void *glue;
};
#define INCRX_BURST_MODE 0
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index 27b5013cd411..e9088a8873a8 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -76,7 +76,7 @@ struct dwc3_qcom_port {
struct dwc3_qcom {
struct device *dev;
void __iomem *qscratch_base;
- struct dwc3 *dwc;
+ struct dwc3 dwc;
struct clk **clks;
int num_clocks;
struct reset_control *resets;
@@ -964,9 +964,11 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
if (ignore_pipe_clk)
dwc3_qcom_select_utmi_clk(qcom);
- qcom->dwc = dwc3_probe(pdev, &res, true, qcom);
- if (IS_ERR(qcom->dwc)) {
- ret = dev_err_probe(dev, PTR_ERR(qcom->dwc), "failed to register DWC3 Core\n");
+ qcom->dwc.dev = dev;
+
+ ret = dwc3_init(&qcom->dwc, &res, true);
+ if (ret) {
+ ret = dev_err_probe(dev, ret, "failed to register DWC3 Core\n");
goto clk_disable;
}
@@ -995,7 +997,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
interconnect_exit:
dwc3_qcom_interconnect_exit(qcom);
remove_core:
- dwc3_remove(qcom->dwc);
+ dwc3_uninit(qcom->dwc);
clk_disable:
for (i = qcom->num_clocks - 1; i >= 0; i--) {
clk_disable_unprepare(qcom->clks[i]);
@@ -1010,7 +1012,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
static void dwc3_qcom_remove(struct platform_device *pdev)
{
struct dwc3 *dwc = platform_get_drvdata(pdev);
- struct dwc3_qcom *qcom = dwc->glue;
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
struct device *dev = &pdev->dev;
int i;
@@ -1030,7 +1032,7 @@ static void dwc3_qcom_remove(struct platform_device *pdev)
static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
- struct dwc3_qcom *qcom = dwc->glue;
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
bool wakeup = device_may_wakeup(dev);
int ret;
@@ -1050,7 +1052,7 @@ static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
- struct dwc3_qcom *qcom = dwc->glue;
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
bool wakeup = device_may_wakeup(dev);
int ret;
@@ -1070,7 +1072,7 @@ static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
- struct dwc3_qcom *qcom = dwc->glue;
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
int ret;
ret = dwc3_runtime_suspend(qcom->dwc);
@@ -1090,7 +1092,7 @@ static void __maybe_unused dwc3_qcom_complete(struct device *dev)
static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
- struct dwc3_qcom *qcom = dwc->glue;
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
int ret;
ret = dwc3_qcom_resume(qcom, true);
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH v2 5/7] usb: dwc3: qcom: Don't reply on drvdata during probe
2024-08-12 3:12 ` [PATCH v2 5/7] usb: dwc3: qcom: Don't reply on drvdata during probe Bjorn Andersson
2024-08-13 18:18 ` Frank Li
@ 2024-09-12 22:21 ` Masahiro Yamada
1 sibling, 0 replies; 37+ messages in thread
From: Masahiro Yamada @ 2024-09-12 22:21 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio, linux-usb, devicetree,
linux-kernel, linux-arm-msm, Bjorn Andersson
Regarding the patch subject,
do you mean "Don't rely on drvdata" instead of
"Don't reply on drvdata"?
On Mon, Aug 12, 2024 at 12:07 PM Bjorn Andersson <andersson@kernel.org> wrote:
>
> From: Bjorn Andersson <quic_bjorande@quicinc.com>
>
> With the upcoming transition to a model where DWC3 core and glue operate
> on a single struct device the drvdata datatype will change to be owned
> by the core.
>
> The drvdata is however used by the Qualcomm DWC3 glue to pass the qcom
> glue context around before the core is allocated.
>
> Remove this problem, and clean up the code, by passing the dwc3_qcom
> struct around during probe, instead of acquiring it from the drvdata.
>
> Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
> ---
> drivers/usb/dwc3/dwc3-qcom.c | 17 ++++++++---------
> 1 file changed, 8 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
> index 88fb6706a18d..33de03f2d782 100644
> --- a/drivers/usb/dwc3/dwc3-qcom.c
> +++ b/drivers/usb/dwc3/dwc3-qcom.c
> @@ -546,9 +546,10 @@ static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq,
> return ret;
> }
>
> -static int dwc3_qcom_setup_port_irq(struct platform_device *pdev, int port_index, bool is_multiport)
> +static int dwc3_qcom_setup_port_irq(struct dwc3_qcom *qcom,
> + struct platform_device *pdev,
> + int port_index, bool is_multiport)
> {
> - struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
> const char *irq_name;
> int irq;
> int ret;
> @@ -633,9 +634,8 @@ static int dwc3_qcom_find_num_ports(struct platform_device *pdev)
> return DWC3_QCOM_MAX_PORTS;
> }
>
> -static int dwc3_qcom_setup_irq(struct platform_device *pdev)
> +static int dwc3_qcom_setup_irq(struct dwc3_qcom *qcom, struct platform_device *pdev)
> {
> - struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
> bool is_multiport;
> int ret;
> int i;
> @@ -644,7 +644,7 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
> is_multiport = (qcom->num_ports > 1);
>
> for (i = 0; i < qcom->num_ports; i++) {
> - ret = dwc3_qcom_setup_port_irq(pdev, i, is_multiport);
> + ret = dwc3_qcom_setup_port_irq(qcom, pdev, i, is_multiport);
> if (ret)
> return ret;
> }
> @@ -699,9 +699,8 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
> return 0;
> }
>
> -static int dwc3_qcom_of_register_core(struct platform_device *pdev)
> +static int dwc3_qcom_of_register_core(struct dwc3_qcom *qcom, struct platform_device *pdev)
> {
> - struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
> struct device_node *np = pdev->dev.of_node, *dwc3_np;
> struct device *dev = &pdev->dev;
> int ret;
> @@ -782,7 +781,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> goto clk_disable;
> }
>
> - ret = dwc3_qcom_setup_irq(pdev);
> + ret = dwc3_qcom_setup_irq(qcom, pdev);
> if (ret) {
> dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
> goto clk_disable;
> @@ -797,7 +796,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
> if (ignore_pipe_clk)
> dwc3_qcom_select_utmi_clk(qcom);
>
> - ret = dwc3_qcom_of_register_core(pdev);
> + ret = dwc3_qcom_of_register_core(qcom, pdev);
> if (ret) {
> dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
> goto clk_disable;
>
> --
> 2.45.2
>
>
--
Best Regards
Masahiro Yamada
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library
2024-09-12 22:21 ` Masahiro Yamada
@ 2024-09-13 2:34 ` Bjorn Andersson
0 siblings, 0 replies; 37+ messages in thread
From: Bjorn Andersson @ 2024-09-13 2:34 UTC (permalink / raw)
To: Masahiro Yamada
Cc: Bjorn Andersson, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Felipe Balbi, Wesley Cheng,
Saravana Kannan, Thinh Nguyen, Philipp Zabel, Konrad Dybcio,
linux-usb, devicetree, linux-kernel, linux-arm-msm
On Fri, Sep 13, 2024 at 07:21:35AM +0900, Masahiro Yamada wrote:
> On Mon, Aug 12, 2024 at 12:07 PM Bjorn Andersson <andersson@kernel.org> wrote:
[..]
> > diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> > index 1e561fd8b86e..4a0ee9ef72e2 100644
> > --- a/drivers/usb/dwc3/core.h
> > +++ b/drivers/usb/dwc3/core.h
> > @@ -1160,6 +1160,7 @@ struct dwc3_scratchpad_array {
> > * @gsbuscfg0_reqinfo: store GSBUSCFG0.DATRDREQINFO, DESRDREQINFO,
> > * DATWRREQINFO, and DESWRREQINFO value passed from
> > * glue driver.
> > + * @glue: private reference to any glue context
> > */
> > struct dwc3 {
> > struct work_struct drd_work;
> > @@ -1388,6 +1389,8 @@ struct dwc3 {
> > int num_ep_resized;
> > struct dentry *debug_root;
> > u32 gsbuscfg0_reqinfo;
> > +
> > + void *glue;
>
>
> This is ugly.
>
>
> 'struct dwc3_qcom' can wrap 'struct dwc3'
> instead of having two separate structures
> pointing at each other.
>
>
> You can use container_of() to
> convert (struct dwc3 *) to (struct dwc3_qcom *).
>
>
> I attached a diff to delete the reverse ->glue pointer.
>
> I did not compile-test it (I cannot due to missing glue.h
> anyway), but you will understand my suggestion.
>
Thanks for your suggestion, Yamada-san.
I agree, that will look better.
Regards,
Bjorn
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure
2024-08-13 18:07 ` [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Frank Li
@ 2024-10-08 20:09 ` Frank Li
2024-10-09 2:54 ` Bjorn Andersson
0 siblings, 1 reply; 37+ messages in thread
From: Frank Li @ 2024-10-08 20:09 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Felipe Balbi, Wesley Cheng, Saravana Kannan,
Thinh Nguyen, Philipp Zabel, Konrad Dybcio, linux-usb, devicetree,
linux-kernel, linux-arm-msm, Bjorn Andersson
On Tue, Aug 13, 2024 at 02:07:01PM -0400, Frank Li wrote:
> On Sun, Aug 11, 2024 at 08:11:57PM -0700, Bjorn Andersson wrote:
> > The USB IP-block found in most Qualcomm platforms is modelled in the
> > Linux kernel as 3 different independent device drivers, but as shown by
> > the already existing layering violations in the Qualcomm glue driver
> > they can not be operated independently.
> >
> > With the current implementation, the glue driver registers the core and
> > has no way to know when this is done. As a result, e.g. the suspend
> > callbacks needs to guard against NULL pointer dereferences when trying
> > to peek into the struct dwc3 found in the drvdata of the child.
> >
> > Missing from the upstream Qualcomm USB support is handling of role
> > switching, in which the glue needs to be notified upon DRD mode changes.
> > Several attempts has been made through the years to register callbacks
> > etc, but they always fall short when it comes to handling of the core's
> > probe deferral on resources etc.
> >
> > Furhtermore, the DeviceTree binding is a direct representation of the
> > Linux driver model, and doesn't necessarily describe "the USB IP-block".
> >
> > This series therefor attempts to flatten the driver split, and operate
> > the glue and core out of the same platform_device instance. And in order
> > to do this, the DeviceTree representation of the IP block is flattened.
>
Bjorn Andersson:
Any follow up on this thread?
Frank
> Thanks, we faced the same problem. Can you cc me next time?
>
> Frank
> >
> > ---
> > Changes in v2:
> > - Rewrite after ACPI removal, multiport support and interrupt fixes
> > - Completely changed strategy for DeviceTree binding, as previous idea
> > of using snps,dwc3 as a generic fallback required unreasonable changes
> > to that binding.
> > - Abandoned idea of supporting both flattened and unflattened device
> > model in the one driver. As Johan pointed out, it will leave the race
> > condition holes and will make the code harder to understand.
> > Furthermore, the role switching logic that we intend to introduce
> > following this would have depended on the user updating their
> > DeviceTree blobs.
> > - Per above, introduced the dynamic DeviceTree rewrite
> > - Link to v1: https://lore.kernel.org/all/20231016-dwc3-refactor-v1-0-ab4a84165470@quicinc.com/
> >
> > ---
> > Bjorn Andersson (7):
> > dt-bindings: usb: snps,dwc3: Split core description
> > dt-bindings: usb: Introduce qcom,snps-dwc3
> > of: dynamic: Don't discard children upon node attach
> > usb: dwc3: core: Expose core driver as library
> > usb: dwc3: qcom: Don't reply on drvdata during probe
> > usb: dwc3: qcom: Transition to flattened model
> > arm64: dts: qcom: sc8280x: Flatten the USB nodes
> >
> > .../devicetree/bindings/usb/qcom,dwc3.yaml | 13 +-
> > .../devicetree/bindings/usb/qcom,snps-dwc3.yaml | 608 +++++++++++++++++++++
> > .../devicetree/bindings/usb/snps,dwc3-common.yaml | 417 ++++++++++++++
> > .../devicetree/bindings/usb/snps,dwc3.yaml | 391 +------------
> > arch/arm64/boot/dts/qcom/sa8295p-adp.dts | 12 +-
> > arch/arm64/boot/dts/qcom/sa8540p-ride.dts | 5 +-
> > arch/arm64/boot/dts/qcom/sc8280xp-crd.dts | 12 +-
> > .../dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts | 11 +-
> > arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 138 +++--
> > drivers/of/dynamic.c | 1 -
> > drivers/usb/dwc3/core.c | 169 ++++--
> > drivers/usb/dwc3/core.h | 3 +
> > drivers/usb/dwc3/dwc3-qcom.c | 323 ++++++++---
> > 13 files changed, 1483 insertions(+), 620 deletions(-)
> > ---
> > base-commit: 864b1099d16fc7e332c3ad7823058c65f890486c
> > change-id: 20231016-dwc3-refactor-931e3b08a8b9
> >
> > Best regards,
> > --
> > Bjorn Andersson <quic_bjorande@quicinc.com>
> >
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure
2024-10-08 20:09 ` Frank Li
@ 2024-10-09 2:54 ` Bjorn Andersson
2025-01-10 16:55 ` Frank Li
0 siblings, 1 reply; 37+ messages in thread
From: Bjorn Andersson @ 2024-10-09 2:54 UTC (permalink / raw)
To: Frank Li
Cc: Bjorn Andersson, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Felipe Balbi, Wesley Cheng,
Saravana Kannan, Thinh Nguyen, Philipp Zabel, Konrad Dybcio,
linux-usb, devicetree, linux-kernel, linux-arm-msm
On Tue, Oct 08, 2024 at 04:09:45PM -0400, Frank Li wrote:
> On Tue, Aug 13, 2024 at 02:07:01PM -0400, Frank Li wrote:
> > On Sun, Aug 11, 2024 at 08:11:57PM -0700, Bjorn Andersson wrote:
> > > The USB IP-block found in most Qualcomm platforms is modelled in the
> > > Linux kernel as 3 different independent device drivers, but as shown by
> > > the already existing layering violations in the Qualcomm glue driver
> > > they can not be operated independently.
> > >
> > > With the current implementation, the glue driver registers the core and
> > > has no way to know when this is done. As a result, e.g. the suspend
> > > callbacks needs to guard against NULL pointer dereferences when trying
> > > to peek into the struct dwc3 found in the drvdata of the child.
> > >
> > > Missing from the upstream Qualcomm USB support is handling of role
> > > switching, in which the glue needs to be notified upon DRD mode changes.
> > > Several attempts has been made through the years to register callbacks
> > > etc, but they always fall short when it comes to handling of the core's
> > > probe deferral on resources etc.
> > >
> > > Furhtermore, the DeviceTree binding is a direct representation of the
> > > Linux driver model, and doesn't necessarily describe "the USB IP-block".
> > >
> > > This series therefor attempts to flatten the driver split, and operate
> > > the glue and core out of the same platform_device instance. And in order
> > > to do this, the DeviceTree representation of the IP block is flattened.
> >
>
> Bjorn Andersson:
> Any follow up on this thread?
>
Thanks for reaching out, Frank. I did pick this up again a few days
back.
I'm struggling with Rob's request for not peeking into struct property
and/or utilizing overlays. Hoping to figure this out shortly, so I can
get v3 in shape.
Regards,
Bjorn
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure
2024-10-09 2:54 ` Bjorn Andersson
@ 2025-01-10 16:55 ` Frank Li
0 siblings, 0 replies; 37+ messages in thread
From: Frank Li @ 2025-01-10 16:55 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Bjorn Andersson, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Felipe Balbi, Wesley Cheng,
Saravana Kannan, Thinh Nguyen, Philipp Zabel, Konrad Dybcio,
linux-usb, devicetree, linux-kernel, linux-arm-msm
On Tue, Oct 08, 2024 at 07:54:48PM -0700, Bjorn Andersson wrote:
> On Tue, Oct 08, 2024 at 04:09:45PM -0400, Frank Li wrote:
> > On Tue, Aug 13, 2024 at 02:07:01PM -0400, Frank Li wrote:
> > > On Sun, Aug 11, 2024 at 08:11:57PM -0700, Bjorn Andersson wrote:
> > > > The USB IP-block found in most Qualcomm platforms is modelled in the
> > > > Linux kernel as 3 different independent device drivers, but as shown by
> > > > the already existing layering violations in the Qualcomm glue driver
> > > > they can not be operated independently.
> > > >
> > > > With the current implementation, the glue driver registers the core and
> > > > has no way to know when this is done. As a result, e.g. the suspend
> > > > callbacks needs to guard against NULL pointer dereferences when trying
> > > > to peek into the struct dwc3 found in the drvdata of the child.
> > > >
> > > > Missing from the upstream Qualcomm USB support is handling of role
> > > > switching, in which the glue needs to be notified upon DRD mode changes.
> > > > Several attempts has been made through the years to register callbacks
> > > > etc, but they always fall short when it comes to handling of the core's
> > > > probe deferral on resources etc.
> > > >
> > > > Furhtermore, the DeviceTree binding is a direct representation of the
> > > > Linux driver model, and doesn't necessarily describe "the USB IP-block".
> > > >
> > > > This series therefor attempts to flatten the driver split, and operate
> > > > the glue and core out of the same platform_device instance. And in order
> > > > to do this, the DeviceTree representation of the IP block is flattened.
> > >
> >
> > Bjorn Andersson:
> > Any follow up on this thread?
> >
>
> Thanks for reaching out, Frank. I did pick this up again a few days
> back.
>
> I'm struggling with Rob's request for not peeking into struct property
> and/or utilizing overlays. Hoping to figure this out shortly, so I can
> get v3 in shape.
Bjorn:
Do you still work on this? Or I missed somethings.
Frank
>
> Regards,
> Bjorn
^ permalink raw reply [flat|nested] 37+ messages in thread
end of thread, other threads:[~2025-01-10 16:55 UTC | newest]
Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-12 3:11 [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Bjorn Andersson
2024-08-12 3:11 ` [PATCH v2 1/7] dt-bindings: usb: snps,dwc3: Split core description Bjorn Andersson
2024-08-18 14:33 ` Rob Herring
2024-08-12 3:11 ` [PATCH v2 2/7] dt-bindings: usb: Introduce qcom,snps-dwc3 Bjorn Andersson
2024-08-12 4:32 ` Rob Herring (Arm)
2024-08-12 3:12 ` [PATCH v2 3/7] of: dynamic: Don't discard children upon node attach Bjorn Andersson
2024-08-12 20:24 ` Rob Herring
2024-08-12 21:21 ` Bjorn Andersson
2024-08-12 3:12 ` [PATCH v2 4/7] usb: dwc3: core: Expose core driver as library Bjorn Andersson
2024-08-12 12:21 ` kernel test robot
2024-08-12 19:00 ` Bjorn Andersson
2024-08-12 12:21 ` kernel test robot
2024-08-13 18:15 ` Frank Li
2024-08-14 1:01 ` Thinh Nguyen
2024-08-19 21:35 ` Bjorn Andersson
2024-08-14 0:56 ` Thinh Nguyen
2024-08-19 21:14 ` Bjorn Andersson
2024-08-19 17:48 ` Krishna Kurapati
2024-08-19 21:36 ` Bjorn Andersson
2024-09-12 22:21 ` Masahiro Yamada
2024-09-13 2:34 ` Bjorn Andersson
2024-08-12 3:12 ` [PATCH v2 5/7] usb: dwc3: qcom: Don't reply on drvdata during probe Bjorn Andersson
2024-08-13 18:18 ` Frank Li
2024-08-19 21:17 ` Bjorn Andersson
2024-09-12 22:21 ` Masahiro Yamada
2024-08-12 3:12 ` [PATCH v2 6/7] usb: dwc3: qcom: Transition to flattened model Bjorn Andersson
2024-08-12 13:33 ` kernel test robot
2024-08-12 21:21 ` Rob Herring
2024-08-12 22:16 ` Bjorn Andersson
2024-08-13 15:06 ` Rob Herring
2024-08-13 18:33 ` Frank Li
2024-08-19 21:28 ` Bjorn Andersson
2024-08-12 3:12 ` [PATCH v2 7/7] arm64: dts: qcom: sc8280x: Flatten the USB nodes Bjorn Andersson
2024-08-13 18:07 ` [PATCH v2 0/7] usb: dwc3: qcom: Flatten dwc3 structure Frank Li
2024-10-08 20:09 ` Frank Li
2024-10-09 2:54 ` Bjorn Andersson
2025-01-10 16:55 ` Frank Li
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).