USB / Thunderbolt changes for 5.19-rc1

Here is the "big" set of USB and Thunderbolt driver changes for
 5.18-rc1.  For the most part it's been a quiet development cycle for the
 USB core, but there are the usual "hot spots" of development activity.
 
 Included in here are:
 	- Thunderbolt driver updates:
 		- fixes for devices without displayport adapters
 		- lane bonding support and improvements
 		- other minor changes based on device testing
 	- dwc3 gadget driver changes.  It seems this driver will never
 	  be finished given that the IP core is showing up in zillions
 	  of new devices and each implementation decides to do something
 	  different with it...
 	- uvc gadget driver updates as more devices start to use and
 	  rely on this hardware as well
 	- usb_maxpacket() api changes to remove an unneeded and unused
 	  parameter.
 	- usb-serial driver device id updates and small cleanups
 	- typec cleanups and fixes based on device testing
 	- device tree updates for usb properties
 	- lots of other small fixes and driver updates.
 
 All of these have been in linux-next for weeks with no reported
 problems.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYpnZGw8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ymQhwCeLVANsQjBcL4ys4skl+1In17y28gAn3rEZ7rQ
 Yv4uP9zadUqg3Cx0vjgf
 =3s5s
 -----END PGP SIGNATURE-----

Merge tag 'usb-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB / Thunderbolt updates from Greg KH:
 "Here is the "big" set of USB and Thunderbolt driver changes for
  5.18-rc1. For the most part it's been a quiet development cycle for
  the USB core, but there are the usual "hot spots" of development
  activity.

  Included in here are:

   - Thunderbolt driver updates:
       - fixes for devices without displayport adapters
       - lane bonding support and improvements
       - other minor changes based on device testing

   - dwc3 gadget driver changes.

     It seems this driver will never be finished given that the IP core
     is showing up in zillions of new devices and each implementation
     decides to do something different with it...

   - uvc gadget driver updates as more devices start to use and rely on
     this hardware as well

   - usb_maxpacket() api changes to remove an unneeded and unused
     parameter.

   - usb-serial driver device id updates and small cleanups

   - typec cleanups and fixes based on device testing

   - device tree updates for usb properties

   - lots of other small fixes and driver updates.

  All of these have been in linux-next for weeks with no reported
  problems"

* tag 'usb-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (154 commits)
  USB: new quirk for Dell Gen 2 devices
  usb: dwc3: core: Add error log when core soft reset failed
  usb: dwc3: gadget: Move null pinter check to proper place
  usb: hub: Simplify error and success path in port_over_current_notify
  usb: cdns3: allocate TX FIFO size according to composite EP number
  usb: dwc3: Fix ep0 handling when getting reset while doing control transfer
  usb: Probe EHCI, OHCI controllers asynchronously
  usb: isp1760: Fix out-of-bounds array access
  xhci: Don't defer primary roothub registration if there is only one roothub
  USB: serial: option: add Quectel BG95 modem
  USB: serial: pl2303: fix type detection for odd device
  xhci: Allow host runtime PM as default for Intel Alder Lake N xHCI
  xhci: Remove quirk for over 10 year old evaluation hardware
  xhci: prevent U2 link power state if Intel tier policy prevented U1
  xhci: use generic command timer for stop endpoint commands.
  usb: host: xhci-plat: omit shared hcd if either root hub has no ports
  usb: host: xhci-plat: prepare operation w/o shared hcd
  usb: host: xhci-plat: create shared hcd after having added main hcd
  xhci: prepare for operation w/o shared hcd
  xhci: factor out parts of xhci_gen_setup()
  ...
This commit is contained in:
Linus Torvalds 2022-06-03 11:17:49 -07:00
commit 54c2cc7919
192 changed files with 3681 additions and 1487 deletions

View File

@ -7,6 +7,7 @@ Description: UVC function directory
streaming_maxburst 0..15 (ss only)
streaming_maxpacket 1..1023 (fs), 1..3072 (hs/ss)
streaming_interval 1..16
function_name string [32]
=================== =============================
What: /config/usb-gadget/gadget/functions/uvc.name/control

View File

@ -293,6 +293,16 @@ Contact: thunderbolt-software@lists.01.org
Description: This contains XDomain service specific settings as
bitmask. Format: %x
What: /sys/bus/thunderbolt/devices/usb4_portX/connector
Date: April 2022
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Description:
Symlink to the USB Type-C connector. This link is only
created when USB Type-C Connector Class is enabled,
and only if the system firmware is capable of
describing the connection between a port and its
connector.
What: /sys/bus/thunderbolt/devices/usb4_portX/link
Date: Sep 2021
KernelVersion: v5.14

View File

@ -61,8 +61,9 @@ DMA
endpoint number (0 … 14 for endpoints 1 … 15 on instance 0 and 15 … 29
for endpoints 1 … 15 on instance 1). The second number is 0 for RX and
1 for TX transfers.
- #dma-channels: should be set to 30 representing the 15 endpoints for
- dma-channels: should be set to 30 representing the 15 endpoints for
each USB instance.
- #dma-channels: deprecated
Example:
~~~~~~~~
@ -193,7 +194,7 @@ usb: usb@47400000 {
interrupts = <17>;
interrupt-names = "glue";
#dma-cells = <2>;
#dma-channels = <30>;
#dma-requests = <256>;
dma-channels = <30>;
dma-requests = <256>;
};
};

View File

@ -36,7 +36,8 @@ DMA
- #dma-cells: should be set to 2. The first number represents the
channel number (0 … 3 for endpoints 1 … 4).
The second number is 0 for RX and 1 for TX transfers.
- #dma-channels: should be set to 4 representing the 4 endpoints.
- dma-channels: should be set to 4 representing the 4 endpoints.
- #dma-channels: deprecated
Example:
usb_phy: usb-phy {
@ -74,7 +75,7 @@ Example:
reg-names = "controller", "scheduler", "queuemgr";
interrupts = <58>;
#dma-cells = <2>;
#dma-channels = <4>;
dma-channels = <4>;
};
};

View File

@ -17,6 +17,13 @@ properties:
oneOf:
- const: brcm,bcm2835-usb
- const: hisilicon,hi6220-usb
- const: ingenic,jz4775-otg
- const: ingenic,jz4780-otg
- const: ingenic,x1000-otg
- const: ingenic,x1600-otg
- const: ingenic,x1700-otg
- const: ingenic,x1830-otg
- const: ingenic,x2000-otg
- items:
- const: rockchip,rk3066-usb
- const: snps,dwc2

View File

@ -71,6 +71,10 @@ properties:
- usb2-phy
- usb3-phy
reset-gpios:
description: GPIO used for the reset ulpi-phy
maxItems: 1
# Required child node:
patternProperties:

View File

@ -0,0 +1,72 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: "http://devicetree.org/schemas/usb/fcs,fsa4480.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: ON Semiconductor Analog Audio Switch
maintainers:
- Bjorn Andersson <bjorn.andersson@linaro.org>
properties:
compatible:
enum:
- fcs,fsa4480
reg:
maxItems: 1
interrupts:
maxItems: 1
vcc-supply:
description: power supply (2.7V-5.5V)
mode-switch:
description: Flag the port as possible handle of altmode switching
type: boolean
orientation-switch:
description: Flag the port as possible handler of orientation switching
type: boolean
port:
$ref: /schemas/graph.yaml#/properties/port
description:
A port node to link the FSA4480 to a TypeC controller for the purpose of
handling altmode muxing and orientation switching.
required:
- compatible
- reg
- port
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c13 {
#address-cells = <1>;
#size-cells = <0>;
fsa4480@42 {
compatible = "fcs,fsa4480";
reg = <0x42>;
interrupts-extended = <&tlmm 2 IRQ_TYPE_LEVEL_LOW>;
vcc-supply = <&vreg_bob>;
mode-switch;
orientation-switch;
port {
fsa4480_ept: endpoint {
remote-endpoint = <&typec_controller>;
};
};
};
};
...

View File

@ -55,6 +55,7 @@ properties:
- brcm,bcm7420-ehci
- brcm,bcm7425-ehci
- brcm,bcm7435-ehci
- hpe,gxp-ehci
- ibm,476gtr-ehci
- nxp,lpc1850-ehci
- qca,ar7100-ehci

View File

@ -42,6 +42,7 @@ properties:
- brcm,bcm7420-ohci
- brcm,bcm7425-ohci
- brcm,bcm7435-ohci
- hpe,gxp-ohci
- ibm,476gtr-ohci
- ingenic,jz4740-ohci
- snps,hsdk-v1.0-ohci

View File

@ -25,6 +25,7 @@ properties:
- mediatek,mt8173-mtu3
- mediatek,mt8183-mtu3
- mediatek,mt8192-mtu3
- mediatek,mt8195-mtu3
- const: mediatek,mtu3
reg:

View File

@ -16,16 +16,21 @@ properties:
- qcom,ipq4019-dwc3
- qcom,ipq6018-dwc3
- qcom,ipq8064-dwc3
- qcom,ipq8074-dwc3
- qcom,msm8953-dwc3
- qcom,msm8994-dwc3
- qcom,msm8996-dwc3
- qcom,msm8998-dwc3
- qcom,qcs404-dwc3
- qcom,sc7180-dwc3
- qcom,sc7280-dwc3
- qcom,sdm660-dwc3
- qcom,sdm845-dwc3
- qcom,sdx55-dwc3
- qcom,sdx65-dwc3
- qcom,sm4250-dwc3
- qcom,sm6115-dwc3
- qcom,sm6125-dwc3
- qcom,sm6350-dwc3
- qcom,sm8150-dwc3
- qcom,sm8250-dwc3
@ -50,26 +55,22 @@ properties:
maxItems: 1
clocks:
description:
A list of phandle and clock-specifier pairs for the clocks
listed in clock-names.
items:
- description: System Config NOC clock.
- description: Master/Core clock, has to be >= 125 MHz
for SS operation and >= 60MHz for HS operation.
- description: System bus AXI clock.
- description: Mock utmi clock needed for ITP/SOF generation
in host mode. Its frequency should be 19.2MHz.
- description: Sleep clock, used for wakeup when
USB3 core goes into low power mode (U3).
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: 6
clock-names:
items:
- const: cfg_noc
- const: core
- const: iface
- const: mock_utmi
- const: sleep
minItems: 1
maxItems: 6
assigned-clocks:
items:
@ -132,6 +133,185 @@ required:
- interrupts
- interrupt-names
allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,ipq4019-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,msm8953-dwc3
- qcom,msm8996-dwc3
- qcom,msm8998-dwc3
- qcom,sc7180-dwc3
- qcom,sc7280-dwc3
- qcom,sdm845-dwc3
- qcom,sdx55-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
then:
properties:
clocks:
maxItems: 4
clock-names:
items:
- const: cfg_noc
- const: core
- const: sleep
- const: mock_utmi
- if:
properties:
compatible:
contains:
enum:
- 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,sdm660-dwc3
then:
properties:
clocks:
minItems: 6
clock-names:
items:
- const: cfg_noc
- const: core
- const: iface
- const: sleep
- const: mock_utmi
- const: bus
- if:
properties:
compatible:
contains:
enum:
- qcom,sm6125-dwc3
- qcom,sm8150-dwc3
- qcom,sm8250-dwc3
- qcom,sm8450-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
additionalProperties: false
examples:
@ -153,10 +333,13 @@ examples:
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_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep";
<&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>;

View File

@ -19,6 +19,7 @@ properties:
- items:
- enum:
- renesas,usbhs-r7s9210 # RZ/A2
- renesas,usbhs-r9a07g043 # RZ/G2UL
- renesas,usbhs-r9a07g044 # RZ/G2{L,LC}
- renesas,usbhs-r9a07g054 # RZ/V2L
- const: renesas,rza2-usbhs
@ -118,6 +119,7 @@ allOf:
compatible:
contains:
enum:
- renesas,usbhs-r9a07g043
- renesas,usbhs-r9a07g044
- renesas,usbhs-r9a07g054
then:
@ -128,6 +130,8 @@ allOf:
- description: U2P_INT_DMA[0]
- description: U2P_INT_DMA[1]
- description: U2P_INT_DMAERR
required:
- resets
else:
properties:
interrupts:

View File

@ -15,9 +15,6 @@ properties:
- samsung,exynos4210-ehci
- samsung,exynos4210-ohci
'#address-cells':
const: 1
clocks:
maxItems: 1
@ -46,15 +43,6 @@ properties:
Only for controller in EHCI mode, if present, specifies the GPIO that
needs to be pulled up for the bus to be powered.
'#size-cells':
const: 0
patternProperties:
"^.*@[0-9a-f]{1,2}$":
description: The hard wired USB devices
type: object
$ref: /usb/usb-device.yaml
required:
- compatible
- clocks
@ -65,6 +53,7 @@ required:
- reg
allOf:
- $ref: usb-hcd.yaml#
- if:
properties:
compatible:
@ -74,7 +63,7 @@ allOf:
properties:
samsung,vbus-gpio: false
additionalProperties: false
unevaluatedProperties: false
examples:
- |

View File

@ -0,0 +1,103 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/ti,am62-usb.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI's AM62 wrapper module for the Synopsys USBSS-DRD controller
maintainers:
- Aswath Govindraju <a-govindraju@ti.com>
properties:
compatible:
const: ti,am62-usb
reg:
maxItems: 1
ranges: true
power-domains:
description:
PM domain provider node and an args specifier containing
the USB ISO device id value. See,
Documentation/devicetree/bindings/soc/ti/sci-pm-domain.yaml
maxItems: 1
clocks:
description: Clock phandle to usb2_refclk
maxItems: 1
clock-names:
items:
- const: ref
ti,vbus-divider:
description:
Should be present if USB VBUS line is connected to the
VBUS pin of the SoC via a 1/3 voltage divider.
type: boolean
ti,syscon-phy-pll-refclk:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- description: Phandle to the SYSCON entry
- description: USB phy control register offset within SYSCON
description:
Specifier for conveying frequency of ref clock input, for the
operation of USB2PHY.
'#address-cells':
const: 2
'#size-cells':
const: 2
patternProperties:
"^usb@[0-9a-f]+$":
$ref: snps,dwc3.yaml#
description: Required child node
required:
- compatible
- reg
- power-domains
- clocks
- clock-names
- ti,syscon-phy-pll-refclk
additionalProperties: false
examples:
- |
#include <dt-bindings/soc/ti,sci_pm_domain.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/gpio/gpio.h>
bus {
#address-cells = <2>;
#size-cells = <2>;
usbss1: usb@f910000 {
compatible = "ti,am62-usb";
reg = <0x00 0x0f910000 0x00 0x800>;
clocks = <&k3_clks 162 3>;
clock-names = "ref";
ti,syscon-phy-pll-refclk = <&wkup_conf 0x4018>;
power-domains = <&k3_pds 179 TI_SCI_PD_EXCLUSIVE>;
#address-cells = <2>;
#size-cells = <2>;
usb@31100000 {
compatible = "snps,dwc3";
reg =<0x00 0x31100000 0x00 0x50000>;
interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>, /* irq.0 */
<GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>; /* irq.0 */
interrupt-names = "host", "peripheral";
maximum-speed = "high-speed";
dr_mode = "otg";
};
};
};

View File

@ -787,6 +787,7 @@ The uvc function provides these attributes in its function directory:
streaming_maxpacket maximum packet size this endpoint is capable of
sending or receiving when this configuration is
selected
function_name name of the interface
=================== ================================================
There are also "control" and "streaming" subdirectories, each of which contain

View File

@ -646,7 +646,7 @@
clocks = <&gcc GCC_USB3_MASTER_CLK>,
<&gcc GCC_USB3_SLEEP_CLK>,
<&gcc GCC_USB3_MOCK_UTMI_CLK>;
clock-names = "master", "sleep", "mock_utmi";
clock-names = "core", "sleep", "mock_utmi";
ranges;
status = "disabled";

View File

@ -483,10 +483,13 @@
clocks = <&gcc GCC_USB30_SLV_AHB_CLK>,
<&gcc GCC_USB30_MASTER_CLK>,
<&gcc GCC_USB30_MSTR_AXI_CLK>,
<&gcc GCC_USB30_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep";
<&gcc GCC_USB30_SLEEP_CLK>,
<&gcc GCC_USB30_MOCK_UTMI_CLK>;
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi";
assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_MASTER_CLK>;

View File

@ -1052,22 +1052,22 @@
&usb2 {
status = "okay";
extcon = <&usb2_id>;
};
dwc3@7600000 {
extcon = <&usb2_id>;
dr_mode = "otg";
maximum-speed = "high-speed";
};
&usb2_dwc3 {
extcon = <&usb2_id>;
dr_mode = "otg";
maximum-speed = "high-speed";
};
&usb3 {
status = "okay";
extcon = <&usb3_id>;
};
dwc3@6a00000 {
extcon = <&usb3_id>;
dr_mode = "otg";
};
&usb3_dwc3 {
extcon = <&usb3_id>;
dr_mode = "otg";
};
&usb3phy {

View File

@ -653,7 +653,7 @@
status = "disabled";
};
usb2: usb2@7000000 {
usb2: usb@70f8800 {
compatible = "qcom,ipq6018-dwc3", "qcom,dwc3";
reg = <0x0 0x070F8800 0x0 0x400>;
#address-cells = <2>;
@ -662,7 +662,7 @@
clocks = <&gcc GCC_USB1_MASTER_CLK>,
<&gcc GCC_USB1_SLEEP_CLK>,
<&gcc GCC_USB1_MOCK_UTMI_CLK>;
clock-names = "master",
clock-names = "core",
"sleep",
"mock_utmi";
@ -730,7 +730,7 @@
status = "disabled";
};
usb3: usb3@8A00000 {
usb3: usb@8af8800 {
compatible = "qcom,ipq6018-dwc3", "qcom,dwc3";
reg = <0x0 0x8AF8800 0x0 0x400>;
#address-cells = <2>;
@ -741,8 +741,8 @@
<&gcc GCC_USB0_MASTER_CLK>,
<&gcc GCC_USB0_SLEEP_CLK>,
<&gcc GCC_USB0_MOCK_UTMI_CLK>;
clock-names = "sys_noc_axi",
"master",
clock-names = "cfg_noc",
"core",
"sleep",
"mock_utmi";
@ -756,7 +756,7 @@
resets = <&gcc GCC_USB0_BCR>;
status = "disabled";
dwc_0: usb@8A00000 {
dwc_0: usb@8a00000 {
compatible = "snps,dwc3";
reg = <0x0 0x8A00000 0x0 0xcd00>;
interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;

View File

@ -553,7 +553,7 @@
};
usb_0: usb@8af8800 {
compatible = "qcom,dwc3";
compatible = "qcom,ipq8074-dwc3", "qcom,dwc3";
reg = <0x08af8800 0x400>;
#address-cells = <1>;
#size-cells = <1>;
@ -563,8 +563,8 @@
<&gcc GCC_USB0_MASTER_CLK>,
<&gcc GCC_USB0_SLEEP_CLK>,
<&gcc GCC_USB0_MOCK_UTMI_CLK>;
clock-names = "sys_noc_axi",
"master",
clock-names = "cfg_noc",
"core",
"sleep",
"mock_utmi";
@ -578,7 +578,7 @@
resets = <&gcc GCC_USB0_BCR>;
status = "disabled";
dwc_0: dwc3@8a00000 {
dwc_0: usb@8a00000 {
compatible = "snps,dwc3";
reg = <0x8a00000 0xcd00>;
interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
@ -593,7 +593,7 @@
};
usb_1: usb@8cf8800 {
compatible = "qcom,dwc3";
compatible = "qcom,ipq8074-dwc3", "qcom,dwc3";
reg = <0x08cf8800 0x400>;
#address-cells = <1>;
#size-cells = <1>;
@ -603,8 +603,8 @@
<&gcc GCC_USB1_MASTER_CLK>,
<&gcc GCC_USB1_SLEEP_CLK>,
<&gcc GCC_USB1_MOCK_UTMI_CLK>;
clock-names = "sys_noc_axi",
"master",
clock-names = "cfg_noc",
"core",
"sleep",
"mock_utmi";
@ -618,7 +618,7 @@
resets = <&gcc GCC_USB1_BCR>;
status = "disabled";
dwc_1: dwc3@8c00000 {
dwc_1: usb@8c00000 {
compatible = "snps,dwc3";
reg = <0x8c00000 0xcd00>;
interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;

View File

@ -759,10 +759,13 @@
clocks = <&gcc GCC_USB_PHY_CFG_AHB_CLK>,
<&gcc GCC_USB30_MASTER_CLK>,
<&gcc GCC_PCNOC_USB3_AXI_CLK>,
<&gcc GCC_USB30_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface",
"mock_utmi", "sleep";
<&gcc GCC_USB30_SLEEP_CLK>,
<&gcc GCC_USB30_MOCK_UTMI_CLK>;
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi";
assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_MASTER_CLK>;

View File

@ -428,7 +428,7 @@
};
usb3: usb@f92f8800 {
compatible = "qcom,msm8996-dwc3", "qcom,dwc3";
compatible = "qcom,msm8994-dwc3", "qcom,dwc3";
reg = <0xf92f8800 0x400>;
#address-cells = <1>;
#size-cells = <1>;
@ -438,7 +438,10 @@
<&gcc GCC_SYS_NOC_USB3_AXI_CLK>,
<&gcc GCC_USB30_SLEEP_CLK>,
<&gcc GCC_USB30_MOCK_UTMI_CLK>;
clock-names = "core", "iface", "sleep", "mock_utmi", "ref", "xo";
clock-names = "core",
"iface",
"sleep",
"mock_utmi";
assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_MASTER_CLK>;

View File

@ -308,19 +308,19 @@
extcon = <&typec>;
qcom,select-utmi-as-pipe-clk;
};
dwc3@6a00000 {
extcon = <&typec>;
&usb3_dwc3 {
extcon = <&typec>;
/* usb3-phy is not used on this device */
phys = <&hsusb_phy1>;
phy-names = "usb2-phy";
/* usb3-phy is not used on this device */
phys = <&hsusb_phy1>;
phy-names = "usb2-phy";
maximum-speed = "high-speed";
snps,is-utmi-l1-suspend;
snps,usb2-gadget-lpm-disable;
snps,hird-threshold = /bits/ 8 <0>;
};
maximum-speed = "high-speed";
snps,is-utmi-l1-suspend;
snps,usb2-gadget-lpm-disable;
snps,hird-threshold = /bits/ 8 <0>;
};
&hsusb_phy1 {

View File

@ -2718,11 +2718,15 @@
interrupt-names = "hs_phy_irq", "ss_phy_irq";
clocks = <&gcc GCC_SYS_NOC_USB3_AXI_CLK>,
<&gcc GCC_USB30_MASTER_CLK>,
<&gcc GCC_AGGRE2_USB3_AXI_CLK>,
<&gcc GCC_USB30_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SLEEP_CLK>,
<&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
<&gcc GCC_USB30_MASTER_CLK>,
<&gcc GCC_AGGRE2_USB3_AXI_CLK>,
<&gcc GCC_USB30_SLEEP_CLK>,
<&gcc GCC_USB30_MOCK_UTMI_CLK>;
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi";
assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_MASTER_CLK>;
@ -2731,7 +2735,7 @@
power-domains = <&gcc USB30_GDSC>;
status = "disabled";
usb3_dwc3: dwc3@6a00000 {
usb3_dwc3: usb@6a00000 {
compatible = "snps,dwc3";
reg = <0x06a00000 0xcc00>;
interrupts = <0 131 IRQ_TYPE_LEVEL_HIGH>;
@ -3050,6 +3054,11 @@
<&gcc GCC_USB20_MOCK_UTMI_CLK>,
<&gcc GCC_USB20_SLEEP_CLK>,
<&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi";
assigned-clocks = <&gcc GCC_USB20_MOCK_UTMI_CLK>,
<&gcc GCC_USB20_MASTER_CLK>;
@ -3059,7 +3068,7 @@
qcom,select-utmi-as-pipe-clk;
status = "disabled";
dwc3@7600000 {
usb2_dwc3: usb@7600000 {
compatible = "snps,dwc3";
reg = <0x07600000 0xcc00>;
interrupts = <0 138 IRQ_TYPE_LEVEL_HIGH>;

View File

@ -2023,10 +2023,13 @@
clocks = <&gcc GCC_CFG_NOC_USB3_AXI_CLK>,
<&gcc GCC_USB30_MASTER_CLK>,
<&gcc GCC_AGGRE1_USB3_AXI_CLK>,
<&gcc GCC_USB30_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep";
<&gcc GCC_USB30_SLEEP_CLK>,
<&gcc GCC_USB30_MOCK_UTMI_CLK>;
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi";
assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_MASTER_CLK>;
@ -2040,7 +2043,7 @@
resets = <&gcc GCC_USB_30_BCR>;
usb3_dwc3: dwc3@a800000 {
usb3_dwc3: usb@a800000 {
compatible = "snps,dwc3";
reg = <0x0a800000 0xcd00>;
interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;

View File

@ -337,9 +337,10 @@
&usb3 {
status = "okay";
dwc3@7580000 {
dr_mode = "host";
};
};
&usb3_dwc3 {
dr_mode = "host";
};
&usb2_phy_prim {

View File

@ -529,7 +529,7 @@
};
usb3: usb@7678800 {
compatible = "qcom,dwc3";
compatible = "qcom,qcs404-dwc3", "qcom,dwc3";
reg = <0x07678800 0x400>;
#address-cells = <1>;
#size-cells = <1>;
@ -544,7 +544,7 @@
assigned-clock-rates = <19200000>, <200000000>;
status = "disabled";
dwc3@7580000 {
usb3_dwc3: usb@7580000 {
compatible = "snps,dwc3";
reg = <0x07580000 0xcd00>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
@ -558,7 +558,7 @@
};
usb2: usb@79b8800 {
compatible = "qcom,dwc3";
compatible = "qcom,qcs404-dwc3", "qcom,dwc3";
reg = <0x079b8800 0x400>;
#address-cells = <1>;
#size-cells = <1>;
@ -573,7 +573,7 @@
assigned-clock-rates = <19200000>, <133333333>;
status = "disabled";
dwc3@78c0000 {
usb@78c0000 {
compatible = "snps,dwc3";
reg = <0x078c0000 0xcc00>;
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;

View File

@ -2755,10 +2755,13 @@
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_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep";
<&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>;
@ -2779,7 +2782,7 @@
<&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3 0>;
interconnect-names = "usb-ddr", "apps-usb";
usb_1_dwc3: dwc3@a600000 {
usb_1_dwc3: usb@a600000 {
compatible = "snps,dwc3";
reg = <0 0x0a600000 0 0xe000>;
interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;

View File

@ -3069,10 +3069,13 @@
clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>,
<&gcc GCC_USB30_SEC_MASTER_CLK>,
<&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>,
<&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SEC_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface","mock_utmi",
"sleep";
<&gcc GCC_USB30_SEC_SLEEP_CLK>,
<&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>;
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi";
assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SEC_MASTER_CLK>;
@ -3102,6 +3105,12 @@
phys = <&usb_2_hsphy>;
phy-names = "usb2-phy";
maximum-speed = "high-speed";
usb-role-switch;
port {
usb2_role_switch: endpoint {
remote-endpoint = <&eud_ep>;
};
};
};
};
@ -3194,6 +3203,36 @@
interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
};
eud: eud@88e0000 {
compatible = "qcom,sc7280-eud","qcom,eud";
reg = <0 0x88e0000 0 0x2000>,
<0 0x88e2000 0 0x1000>;
interrupts-extended = <&pdc 11 IRQ_TYPE_LEVEL_HIGH>;
ports {
port@0 {
eud_ep: endpoint {
remote-endpoint = <&usb2_role_switch>;
};
};
port@1 {
eud_con: endpoint {
remote-endpoint = <&con_eud>;
};
};
};
};
eud_typec: connector {
compatible = "usb-c-connector";
ports {
port@0 {
con_eud: endpoint {
remote-endpoint = <&eud_con>;
};
};
};
};
nsp_noc: interconnect@a0c0000 {
reg = <0 0x0a0c0000 0 0x10000>;
compatible = "qcom,sc7280-nsp-noc";
@ -3213,21 +3252,26 @@
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_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep";
<&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>, <200000000>;
interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
<&pdc 14 IRQ_TYPE_EDGE_BOTH>,
<&pdc 17 IRQ_TYPE_EDGE_BOTH>,
<&pdc 15 IRQ_TYPE_EDGE_BOTH>,
<&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "hs_phy_irq", "dp_hs_phy_irq",
"dm_hs_phy_irq", "ss_phy_irq";
<&pdc 14 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "hs_phy_irq",
"ss_phy_irq",
"dm_hs_phy_irq",
"dp_hs_phy_irq";
power-domains = <&gcc GCC_USB30_PRIM_GDSC>;

View File

@ -1215,11 +1215,15 @@
clocks = <&gcc GCC_CFG_NOC_USB3_AXI_CLK>,
<&gcc GCC_USB30_MASTER_CLK>,
<&gcc GCC_AGGRE2_USB3_AXI_CLK>,
<&rpmcc RPM_SMD_AGGR2_NOC_CLK>,
<&gcc GCC_USB30_SLEEP_CLK>,
<&gcc GCC_USB30_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface", "bus",
"mock_utmi", "sleep";
<&rpmcc RPM_SMD_AGGR2_NOC_CLK>;
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi",
"bus";
assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_MASTER_CLK>,

View File

@ -3844,10 +3844,13 @@
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_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep";
<&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>;
@ -3868,7 +3871,7 @@
<&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_0 0>;
interconnect-names = "usb-ddr", "apps-usb";
usb_1_dwc3: dwc3@a600000 {
usb_1_dwc3: usb@a600000 {
compatible = "snps,dwc3";
reg = <0 0x0a600000 0 0xcd00>;
interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
@ -3892,10 +3895,13 @@
clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>,
<&gcc GCC_USB30_SEC_MASTER_CLK>,
<&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>,
<&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SEC_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep";
<&gcc GCC_USB30_SEC_SLEEP_CLK>,
<&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>;
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi";
assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SEC_MASTER_CLK>;
@ -3916,7 +3922,7 @@
<&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_1 0>;
interconnect-names = "usb-ddr", "apps-usb";
usb_2_dwc3: dwc3@a800000 {
usb_2_dwc3: usb@a800000 {
compatible = "snps,dwc3";
reg = <0 0x0a800000 0 0xcd00>;
interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;

View File

@ -481,18 +481,24 @@
};
usb3: usb@4ef8800 {
compatible = "qcom,msm8996-dwc3", "qcom,dwc3";
compatible = "qcom,sm6125-dwc3", "qcom,dwc3";
reg = <0x04ef8800 0x400>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
clocks = <&gcc GCC_USB30_PRIM_MASTER_CLK>,
clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>,
<&gcc GCC_USB30_PRIM_MASTER_CLK>,
<&gcc GCC_SYS_NOC_USB3_PRIM_AXI_CLK>,
<&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>,
<&gcc GCC_USB3_PRIM_CLKREF_CLK>,
<&gcc GCC_USB30_PRIM_SLEEP_CLK>,
<&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>;
<&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
<&gcc GCC_USB3_PRIM_CLKREF_CLK>;
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi",
"xo";
assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_MASTER_CLK>;

View File

@ -1034,10 +1034,13 @@
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_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep";
<&gcc GCC_USB30_PRIM_SLEEP_CLK>,
<&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>;
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi";
interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
<&pdc 17 IRQ_TYPE_LEVEL_HIGH>,

View File

@ -3614,11 +3614,15 @@
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_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_SLEEP_CLK>,
<&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
<&gcc GCC_USB3_SEC_CLKREF_CLK>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep", "xo";
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi",
"xo";
assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_MASTER_CLK>;
@ -3635,7 +3639,7 @@
resets = <&gcc GCC_USB30_PRIM_BCR>;
usb_1_dwc3: dwc3@a600000 {
usb_1_dwc3: usb@a600000 {
compatible = "snps,dwc3";
reg = <0 0x0a600000 0 0xcd00>;
interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
@ -3659,11 +3663,15 @@
clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>,
<&gcc GCC_USB30_SEC_MASTER_CLK>,
<&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>,
<&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SEC_SLEEP_CLK>,
<&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB3_SEC_CLKREF_CLK>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep", "xo";
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi",
"xo";
assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SEC_MASTER_CLK>;

View File

@ -2995,11 +2995,15 @@
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_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_SLEEP_CLK>,
<&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
<&gcc GCC_USB3_SEC_CLKREF_EN>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep", "xo";
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi",
"xo";
assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_MASTER_CLK>;
@ -3046,11 +3050,15 @@
clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>,
<&gcc GCC_USB30_SEC_MASTER_CLK>,
<&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>,
<&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SEC_SLEEP_CLK>,
<&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB3_SEC_CLKREF_EN>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep", "xo";
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi",
"xo";
assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SEC_MASTER_CLK>;

View File

@ -2449,10 +2449,13 @@
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_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_SLEEP_CLK>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep";
<&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>;
@ -2492,11 +2495,15 @@
clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>,
<&gcc GCC_USB30_SEC_MASTER_CLK>,
<&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>,
<&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SEC_SLEEP_CLK>,
<&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB3_SEC_CLKREF_EN>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep", "xo";
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi",
"xo";
assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_SEC_MASTER_CLK>;

View File

@ -3107,22 +3107,28 @@
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_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_SLEEP_CLK>,
<&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
<&gcc GCC_USB3_0_CLKREF_EN>;
clock-names = "cfg_noc", "core", "iface", "mock_utmi",
"sleep", "xo";
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
"mock_utmi",
"xo";
assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_PRIM_MASTER_CLK>;
assigned-clock-rates = <19200000>, <200000000>;
interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
<&pdc 14 IRQ_TYPE_EDGE_BOTH>,
<&pdc 17 IRQ_TYPE_LEVEL_HIGH>,
<&pdc 15 IRQ_TYPE_EDGE_BOTH>,
<&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "hs_phy_irq", "dp_hs_phy_irq",
"dm_hs_phy_irq", "ss_phy_irq";
<&pdc 14 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "hs_phy_irq",
"ss_phy_irq",
"dm_hs_phy_irq",
"dp_hs_phy_irq";
power-domains = <&gcc USB30_PRIM_GDSC>;

View File

@ -577,7 +577,7 @@
};
otg: usb@13500000 {
compatible = "ingenic,jz4780-otg", "snps,dwc2";
compatible = "ingenic,jz4780-otg";
reg = <0x13500000 0x40000>;
interrupt-parent = <&intc>;

View File

@ -398,7 +398,7 @@
};
otg: usb@13500000 {
compatible = "ingenic,x1000-otg", "snps,dwc2";
compatible = "ingenic,x1000-otg";
reg = <0x13500000 0x40000>;
interrupt-parent = <&intc>;

View File

@ -408,7 +408,7 @@
};
otg: usb@13500000 {
compatible = "ingenic,x1830-otg", "snps,dwc2";
compatible = "ingenic,x1830-otg";
reg = <0x13500000 0x40000>;
interrupt-parent = <&intc>;

View File

@ -1206,15 +1206,23 @@ const void *device_get_match_data(struct device *dev)
}
EXPORT_SYMBOL_GPL(device_get_match_data);
static void *
fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
void *data, devcon_match_fn_t match)
static unsigned int fwnode_graph_devcon_matches(struct fwnode_handle *fwnode,
const char *con_id, void *data,
devcon_match_fn_t match,
void **matches,
unsigned int matches_len)
{
struct fwnode_handle *node;
struct fwnode_handle *ep;
unsigned int count = 0;
void *ret;
fwnode_graph_for_each_endpoint(fwnode, ep) {
if (matches && count >= matches_len) {
fwnode_handle_put(ep);
break;
}
node = fwnode_graph_get_remote_port_parent(ep);
if (!fwnode_device_is_available(node)) {
fwnode_handle_put(node);
@ -1224,33 +1232,43 @@ fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
ret = match(node, con_id, data);
fwnode_handle_put(node);
if (ret) {
fwnode_handle_put(ep);
return ret;
if (matches)
matches[count] = ret;
count++;
}
}
return NULL;
return count;
}
static void *
fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
void *data, devcon_match_fn_t match)
static unsigned int fwnode_devcon_matches(struct fwnode_handle *fwnode,
const char *con_id, void *data,
devcon_match_fn_t match,
void **matches,
unsigned int matches_len)
{
struct fwnode_handle *node;
unsigned int count = 0;
unsigned int i;
void *ret;
int i;
for (i = 0; ; i++) {
if (matches && count >= matches_len)
break;
node = fwnode_find_reference(fwnode, con_id, i);
if (IS_ERR(node))
break;
ret = match(node, NULL, data);
fwnode_handle_put(node);
if (ret)
return ret;
if (ret) {
if (matches)
matches[count] = ret;
count++;
}
}
return NULL;
return count;
}
/**
@ -1268,15 +1286,61 @@ void *fwnode_connection_find_match(struct fwnode_handle *fwnode,
const char *con_id, void *data,
devcon_match_fn_t match)
{
unsigned int count;
void *ret;
if (!fwnode || !match)
return NULL;
ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
if (ret)
count = fwnode_graph_devcon_matches(fwnode, con_id, data, match, &ret, 1);
if (count)
return ret;
return fwnode_devcon_match(fwnode, con_id, data, match);
count = fwnode_devcon_matches(fwnode, con_id, data, match, &ret, 1);
return count ? ret : NULL;
}
EXPORT_SYMBOL_GPL(fwnode_connection_find_match);
/**
* fwnode_connection_find_matches - Find connections from a device node
* @fwnode: Device node with the connection
* @con_id: Identifier for the connection
* @data: Data for the match function
* @match: Function to check and convert the connection description
* @matches: (Optional) array of pointers to fill with matches
* @matches_len: Length of @matches
*
* Find up to @matches_len connections with unique identifier @con_id between
* @fwnode and other device nodes. @match will be used to convert the
* connection description to data the caller is expecting to be returned
* through the @matches array.
* If @matches is NULL @matches_len is ignored and the total number of resolved
* matches is returned.
*
* Return: Number of matches resolved, or negative errno.
*/
int fwnode_connection_find_matches(struct fwnode_handle *fwnode,
const char *con_id, void *data,
devcon_match_fn_t match,
void **matches, unsigned int matches_len)
{
unsigned int count_graph;
unsigned int count_ref;
if (!fwnode || !match)
return -EINVAL;
count_graph = fwnode_graph_devcon_matches(fwnode, con_id, data, match,
matches, matches_len);
if (matches) {
matches += count_graph;
matches_len -= count_graph;
}
count_ref = fwnode_devcon_matches(fwnode, con_id, data, match,
matches, matches_len);
return count_graph + count_ref;
}
EXPORT_SYMBOL_GPL(fwnode_connection_find_matches);

View File

@ -387,7 +387,7 @@ static int hid_submit_ctrl(struct hid_device *hid)
usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
maxpacket = usb_maxpacket(hid_to_usb_dev(hid),
usbhid->urbctrl->pipe, 0);
usbhid->urbctrl->pipe);
len += (len == 0); /* Don't allow 0-length reports */
len = round_up(len, maxpacket);
if (len > usbhid->bufsize)

View File

@ -279,7 +279,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
return -ENODEV;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
maxp = usb_maxpacket(dev, pipe);
kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
input_dev = input_allocate_device();

View File

@ -123,7 +123,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
return -ENODEV;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
maxp = usb_maxpacket(dev, pipe);
mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
input_dev = input_allocate_device();

View File

@ -639,7 +639,7 @@ static int ati_remote2_urb_init(struct ati_remote2 *ar2)
return -ENOMEM;
pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
maxp = usb_maxpacket(udev, pipe);
maxp = maxp > 4 ? 4 : maxp;
usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp,

View File

@ -745,7 +745,7 @@ static int cm109_usb_probe(struct usb_interface *intf,
/* get a handle to the interrupt data pipe */
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
ret = usb_maxpacket(udev, pipe);
if (ret != USB_PKT_LEN)
dev_err(&intf->dev, "invalid payload size %d, expected %d\n",
ret, USB_PKT_LEN);

View File

@ -374,7 +374,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
/* get a handle to the interrupt data pipe */
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
maxp = usb_maxpacket(udev, pipe);
if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) {
printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n",

View File

@ -905,7 +905,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* get a handle to the interrupt data pipe */
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
ret = usb_maxpacket(udev, pipe);
if (ret != USB_PKT_LEN)
dev_err(&intf->dev, "invalid payload size %d, expected %zd\n",
ret, USB_PKT_LEN);

View File

@ -130,7 +130,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
return -ENODEV;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
maxp = usb_maxpacket(dev, pipe);
acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
input_dev = input_allocate_device();

View File

@ -296,7 +296,7 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus->intf = intf;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
pegasus->data_len = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
pegasus->data_len = usb_maxpacket(dev, pipe);
pegasus->data = usb_alloc_coherent(dev, pegasus->data_len, GFP_KERNEL,
&pegasus->data_dma);

View File

@ -773,7 +773,7 @@ static int ati_remote_initialize(struct ati_remote *ati_remote)
/* Set up irq_urb */
pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
maxp = usb_maxpacket(udev, pipe);
maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
@ -784,7 +784,7 @@ static int ati_remote_initialize(struct ati_remote *ati_remote)
/* Set up out_urb */
pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
maxp = usb_maxpacket(udev, pipe);
maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,

View File

@ -1728,7 +1728,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress);
else
pipe = usb_rcvbulkpipe(dev, ep_in->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
maxp = usb_maxpacket(dev, pipe);
ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL);
if (!ir)

View File

@ -307,7 +307,7 @@ static int streamzap_probe(struct usb_interface *intf,
}
pipe = usb_rcvintpipe(usbdev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(usbdev, pipe, usb_pipeout(pipe));
maxp = usb_maxpacket(usbdev, pipe);
if (maxp == 0) {
dev_err(&intf->dev, "%s: endpoint Max Packet Size is 0!?!\n",

View File

@ -171,7 +171,7 @@ static int xbox_remote_initialize(struct xbox_remote *xbox_remote,
/* Set up irq_urb */
pipe = usb_rcvintpipe(udev, endpoint_in->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
maxp = usb_maxpacket(udev, pipe);
maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
usb_fill_int_urb(xbox_remote->irq_urb, udev, pipe, xbox_remote->inbuf,

View File

@ -120,7 +120,7 @@ static int tm6000_start_stream(struct tm6000_core *dev)
pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK);
size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
size = usb_maxpacket(dev->udev, pipe);
size = size * 15; /* 512 x 8 or 12 or 15 */
dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);

View File

@ -340,7 +340,7 @@ static int __tm6000_ir_int_start(struct rc_dev *rc)
dev->int_in.endp->desc.bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK);
size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
size = usb_maxpacket(dev->udev, pipe);
dprintk(1, "IR max size: %d\n", size);
ir->int_urb->transfer_buffer = kzalloc(size, GFP_ATOMIC);

View File

@ -570,7 +570,7 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev)
dev->isoc_in.endp->desc.bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK);
size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
size = usb_maxpacket(dev->udev, pipe);
if (size > dev->isoc_in.maxsize)
size = dev->isoc_in.maxsize;

View File

@ -784,7 +784,7 @@ static int mei_hdcp_component_match(struct device *dev, int subcomponent,
{
struct device *base = data;
if (strcmp(dev->driver->name, "i915") ||
if (!dev->driver || strcmp(dev->driver->name, "i915") ||
subcomponent != I915_COMPONENT_HDCP)
return 0;

View File

@ -131,7 +131,7 @@ static int mei_pxp_component_match(struct device *dev, int subcomponent,
{
struct device *base = data;
if (strcmp(dev->driver->name, "i915") ||
if (!dev->driver || strcmp(dev->driver->name, "i915") ||
subcomponent != I915_COMPONENT_PXP)
return 0;

View File

@ -441,7 +441,7 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
* .bind which is called before usbnet sets up dev->maxpacket
*/
if (val != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
val % usb_maxpacket(dev->udev, dev->out, 1) == 0)
val % usb_maxpacket(dev->udev, dev->out) == 0)
val++;
/* we might need to flush any pending tx buffers if running */
@ -465,7 +465,7 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
usbnet_update_max_qlen(dev);
/* never pad more than 3 full USB packets per transfer */
ctx->min_tx_pkt = clamp_t(u16, ctx->tx_max - 3 * usb_maxpacket(dev->udev, dev->out, 1),
ctx->min_tx_pkt = clamp_t(u16, ctx->tx_max - 3 * usb_maxpacket(dev->udev, dev->out),
CDC_NCM_MIN_TX_PKT, ctx->tx_max);
}

View File

@ -4421,7 +4421,7 @@ static int lan78xx_probe(struct usb_interface *intf,
goto out4;
period = ep_intr->desc.bInterval;
maxp = usb_maxpacket(dev->udev, dev->pipe_intr, 0);
maxp = usb_maxpacket(dev->udev, dev->pipe_intr);
buf = kmalloc(maxp, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
@ -4439,7 +4439,7 @@ static int lan78xx_probe(struct usb_interface *intf,
dev->urb_intr->transfer_flags |= URB_FREE_BUFFER;
}
dev->maxpacket = usb_maxpacket(dev->udev, dev->pipe_out, 1);
dev->maxpacket = usb_maxpacket(dev->udev, dev->pipe_out);
/* Reject broken descriptors. */
if (dev->maxpacket == 0) {

View File

@ -333,7 +333,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
net->hard_header_len += sizeof (struct rndis_data_hdr);
dev->hard_mtu = net->mtu + net->hard_header_len;
dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1);
dev->maxpacket = usb_maxpacket(dev->udev, dev->out);
if (dev->maxpacket == 0) {
netif_dbg(dev, probe, dev->net,
"dev->maxpacket can't be 0\n");

View File

@ -229,7 +229,7 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf)
pipe = usb_rcvintpipe (dev->udev,
dev->status->desc.bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK);
maxp = usb_maxpacket (dev->udev, pipe, 0);
maxp = usb_maxpacket(dev->udev, pipe);
/* avoid 1 msec chatter: min 8 msec poll rate */
period = max ((int) dev->status->desc.bInterval,
@ -1789,7 +1789,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
if (!dev->rx_urb_size)
dev->rx_urb_size = dev->hard_mtu;
dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1);
dev->maxpacket = usb_maxpacket(dev->udev, dev->out);
if (dev->maxpacket == 0) {
/* that is a broken device */
status = -ENODEV;

View File

@ -1068,7 +1068,7 @@ int __mt76u_init(struct mt76_dev *dev, struct usb_interface *intf,
INIT_WORK(&usb->stat_work, mt76u_tx_status_data);
usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0), 1);
usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0));
if (usb->data_len < 32)
usb->data_len = 32;

View File

@ -586,10 +586,10 @@ static void rt2x00usb_assign_endpoint(struct data_queue *queue,
if (queue->qid == QID_RX) {
pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint);
queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0);
queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe);
} else {
pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint);
queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1);
queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe);
}
if (!queue->usb_maxpacket)

View File

@ -158,21 +158,20 @@ static bool tb_cfg_request_is_active(struct tb_cfg_request *req)
static struct tb_cfg_request *
tb_cfg_request_find(struct tb_ctl *ctl, struct ctl_pkg *pkg)
{
struct tb_cfg_request *req;
bool found = false;
struct tb_cfg_request *req = NULL, *iter;
mutex_lock(&pkg->ctl->request_queue_lock);
list_for_each_entry(req, &pkg->ctl->request_queue, list) {
tb_cfg_request_get(req);
if (req->match(req, pkg)) {
found = true;
list_for_each_entry(iter, &pkg->ctl->request_queue, list) {
tb_cfg_request_get(iter);
if (iter->match(iter, pkg)) {
req = iter;
break;
}
tb_cfg_request_put(req);
tb_cfg_request_put(iter);
}
mutex_unlock(&pkg->ctl->request_queue_lock);
return found ? req : NULL;
return req;
}
/* utility functions */

View File

@ -1250,7 +1250,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
nhi->pdev = pdev;
nhi->ops = (const struct tb_nhi_ops *)id->driver_data;
/* cannot fail - table is allocated bin pcim_iomap_regions */
/* cannot fail - table is allocated in pcim_iomap_regions */
nhi->iobase = pcim_iomap_table(pdev)[0];
nhi->hop_count = ioread32(nhi->iobase + REG_HOP_COUNT) & 0x3ff;
dev_dbg(&pdev->dev, "total paths: %d\n", nhi->hop_count);

View File

@ -166,6 +166,9 @@ struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid,
return NULL;
}
tb_dbg(path->tb, "discovering %s path starting from %llx:%u\n",
path->name, tb_route(src->sw), src->port);
p = src;
h = src_hopid;
@ -198,10 +201,13 @@ struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid,
path->hops[i].out_port = out_port;
path->hops[i].next_hop_index = next_hop;
tb_dump_hop(&path->hops[i], &hop);
h = next_hop;
p = out_port->remote;
}
tb_dbg(path->tb, "path discovery complete\n");
return path;
err:

View File

@ -693,8 +693,14 @@ static int __tb_port_enable(struct tb_port *port, bool enable)
else
phy |= LANE_ADP_CS_1_LD;
return tb_port_write(port, &phy, TB_CFG_PORT,
port->cap_phy + LANE_ADP_CS_1, 1);
ret = tb_port_write(port, &phy, TB_CFG_PORT,
port->cap_phy + LANE_ADP_CS_1, 1);
if (ret)
return ret;
tb_port_dbg(port, "lane %sabled\n", enable ? "en" : "dis");
return 0;
}
/**
@ -993,7 +999,17 @@ static bool tb_port_is_width_supported(struct tb_port *port, int width)
return !!(widths & width);
}
static int tb_port_set_link_width(struct tb_port *port, unsigned int width)
/**
* tb_port_set_link_width() - Set target link width of the lane adapter
* @port: Lane adapter
* @width: Target link width (%1 or %2)
*
* Sets the target link width of the lane adapter to @width. Does not
* enable/disable lane bonding. For that call tb_port_set_lane_bonding().
*
* Return: %0 in case of success and negative errno in case of error
*/
int tb_port_set_link_width(struct tb_port *port, unsigned int width)
{
u32 val;
int ret;
@ -1020,12 +1036,58 @@ static int tb_port_set_link_width(struct tb_port *port, unsigned int width)
return -EINVAL;
}
val |= LANE_ADP_CS_1_LB;
return tb_port_write(port, &val, TB_CFG_PORT,
port->cap_phy + LANE_ADP_CS_1, 1);
}
/**
* tb_port_set_lane_bonding() - Enable/disable lane bonding
* @port: Lane adapter
* @bonding: enable/disable bonding
*
* Enables or disables lane bonding. This should be called after target
* link width has been set (tb_port_set_link_width()). Note in most
* cases one should use tb_port_lane_bonding_enable() instead to enable
* lane bonding.
*
* As a side effect sets @port->bonding accordingly (and does the same
* for lane 1 too).
*
* Return: %0 in case of success and negative errno in case of error
*/
int tb_port_set_lane_bonding(struct tb_port *port, bool bonding)
{
u32 val;
int ret;
if (!port->cap_phy)
return -EINVAL;
ret = tb_port_read(port, &val, TB_CFG_PORT,
port->cap_phy + LANE_ADP_CS_1, 1);
if (ret)
return ret;
if (bonding)
val |= LANE_ADP_CS_1_LB;
else
val &= ~LANE_ADP_CS_1_LB;
ret = tb_port_write(port, &val, TB_CFG_PORT,
port->cap_phy + LANE_ADP_CS_1, 1);
if (ret)
return ret;
/*
* When lane 0 bonding is set it will affect lane 1 too so
* update both.
*/
port->bonded = bonding;
port->dual_link_port->bonded = bonding;
return 0;
}
/**
* tb_port_lane_bonding_enable() - Enable bonding on port
* @port: port to enable
@ -1050,22 +1112,27 @@ int tb_port_lane_bonding_enable(struct tb_port *port)
if (ret == 1) {
ret = tb_port_set_link_width(port, 2);
if (ret)
return ret;
goto err_lane0;
}
ret = tb_port_get_link_width(port->dual_link_port);
if (ret == 1) {
ret = tb_port_set_link_width(port->dual_link_port, 2);
if (ret) {
tb_port_set_link_width(port, 1);
return ret;
}
if (ret)
goto err_lane0;
}
port->bonded = true;
port->dual_link_port->bonded = true;
ret = tb_port_set_lane_bonding(port, true);
if (ret)
goto err_lane1;
return 0;
err_lane1:
tb_port_set_link_width(port->dual_link_port, 1);
err_lane0:
tb_port_set_link_width(port, 1);
return ret;
}
/**
@ -1074,13 +1141,10 @@ int tb_port_lane_bonding_enable(struct tb_port *port)
*
* Disable bonding by setting the link width of the port and the
* other port in case of dual link port.
*
*/
void tb_port_lane_bonding_disable(struct tb_port *port)
{
port->dual_link_port->bonded = false;
port->bonded = false;
tb_port_set_lane_bonding(port, false);
tb_port_set_link_width(port->dual_link_port, 1);
tb_port_set_link_width(port, 1);
}
@ -1104,10 +1168,17 @@ int tb_port_wait_for_link_width(struct tb_port *port, int width,
do {
ret = tb_port_get_link_width(port);
if (ret < 0)
return ret;
else if (ret == width)
if (ret < 0) {
/*
* Sometimes we get port locked error when
* polling the lanes so we can ignore it and
* retry.
*/
if (ret != -EACCES)
return ret;
} else if (ret == width) {
return 0;
}
usleep_range(1000, 2000);
} while (ktime_before(ktime_get(), timeout));

View File

@ -169,12 +169,6 @@ static void tb_discover_tunnels(struct tb *tb)
static int tb_port_configure_xdomain(struct tb_port *port)
{
/*
* XDomain paths currently only support single lane so we must
* disable the other lane according to USB4 spec.
*/
tb_port_disable(port->dual_link_port);
if (tb_switch_is_usb4(port->sw))
return usb4_port_configure_xdomain(port);
return tb_lc_configure_xdomain(port);
@ -867,7 +861,7 @@ static struct tb_port *tb_find_dp_out(struct tb *tb, struct tb_port *in)
static void tb_tunnel_dp(struct tb *tb)
{
int available_up, available_down, ret;
int available_up, available_down, ret, link_nr;
struct tb_cm *tcm = tb_priv(tb);
struct tb_port *port, *in, *out;
struct tb_tunnel *tunnel;
@ -912,6 +906,20 @@ static void tb_tunnel_dp(struct tb *tb)
return;
}
/*
* This is only applicable to links that are not bonded (so
* when Thunderbolt 1 hardware is involved somewhere in the
* topology). For these try to share the DP bandwidth between
* the two lanes.
*/
link_nr = 1;
list_for_each_entry(tunnel, &tcm->tunnel_list, list) {
if (tb_tunnel_is_dp(tunnel)) {
link_nr = 0;
break;
}
}
/*
* DP stream needs the domain to be active so runtime resume
* both ends of the tunnel.
@ -943,7 +951,8 @@ static void tb_tunnel_dp(struct tb *tb)
tb_dbg(tb, "available bandwidth for new DP tunnel %u/%u Mb/s\n",
available_up, available_down);
tunnel = tb_tunnel_alloc_dp(tb, in, out, available_up, available_down);
tunnel = tb_tunnel_alloc_dp(tb, in, out, link_nr, available_up,
available_down);
if (!tunnel) {
tb_port_dbg(out, "could not allocate DP tunnel\n");
goto err_reclaim;

View File

@ -674,7 +674,7 @@ static inline int tb_port_write(struct tb_port *port, const void *buffer,
#define __TB_PORT_PRINT(level, _port, fmt, arg...) \
do { \
const struct tb_port *__port = (_port); \
level(__port->sw->tb, "%llx:%x: " fmt, \
level(__port->sw->tb, "%llx:%u: " fmt, \
tb_route(__port->sw), __port->port, ## arg); \
} while (0)
#define tb_port_WARN(port, fmt, arg...) \
@ -991,6 +991,7 @@ int tb_switch_pcie_l1_enable(struct tb_switch *sw);
int tb_switch_xhci_connect(struct tb_switch *sw);
void tb_switch_xhci_disconnect(struct tb_switch *sw);
int tb_port_state(struct tb_port *port);
int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged);
int tb_port_add_nfc_credits(struct tb_port *port, int credits);
int tb_port_clear_counter(struct tb_port *port, int counter);
@ -1023,7 +1024,8 @@ static inline bool tb_port_use_credit_allocation(const struct tb_port *port)
int tb_port_get_link_speed(struct tb_port *port);
int tb_port_get_link_width(struct tb_port *port);
int tb_port_state(struct tb_port *port);
int tb_port_set_link_width(struct tb_port *port, unsigned int width);
int tb_port_set_lane_bonding(struct tb_port *port, bool bonding);
int tb_port_lane_bonding_enable(struct tb_port *port);
void tb_port_lane_bonding_disable(struct tb_port *port);
int tb_port_wait_for_link_width(struct tb_port *port, int width,

View File

@ -527,6 +527,10 @@ enum tb_xdp_type {
PROPERTIES_CHANGED_RESPONSE,
ERROR_RESPONSE,
UUID_REQUEST = 12,
LINK_STATE_STATUS_REQUEST = 15,
LINK_STATE_STATUS_RESPONSE,
LINK_STATE_CHANGE_REQUEST,
LINK_STATE_CHANGE_RESPONSE,
};
struct tb_xdp_header {
@ -540,6 +544,41 @@ struct tb_xdp_error_response {
u32 error;
};
struct tb_xdp_link_state_status {
struct tb_xdp_header hdr;
};
struct tb_xdp_link_state_status_response {
union {
struct tb_xdp_error_response err;
struct {
struct tb_xdp_header hdr;
u32 status;
u8 slw;
u8 tlw;
u8 sls;
u8 tls;
};
};
};
struct tb_xdp_link_state_change {
struct tb_xdp_header hdr;
u8 tlw;
u8 tls;
u16 reserved;
};
struct tb_xdp_link_state_change_response {
union {
struct tb_xdp_error_response err;
struct {
struct tb_xdp_header hdr;
u32 status;
};
};
};
struct tb_xdp_uuid {
struct tb_xdp_header hdr;
};

View File

@ -311,11 +311,16 @@ struct tb_regs_port_header {
/* Lane adapter registers */
#define LANE_ADP_CS_0 0x00
#define LANE_ADP_CS_0_SUPPORTED_SPEED_MASK GENMASK(19, 16)
#define LANE_ADP_CS_0_SUPPORTED_SPEED_SHIFT 16
#define LANE_ADP_CS_0_SUPPORTED_WIDTH_MASK GENMASK(25, 20)
#define LANE_ADP_CS_0_SUPPORTED_WIDTH_SHIFT 20
#define LANE_ADP_CS_0_SUPPORTED_WIDTH_DUAL 0x2
#define LANE_ADP_CS_0_CL0S_SUPPORT BIT(26)
#define LANE_ADP_CS_0_CL1_SUPPORT BIT(27)
#define LANE_ADP_CS_1 0x01
#define LANE_ADP_CS_1_TARGET_SPEED_MASK GENMASK(3, 0)
#define LANE_ADP_CS_1_TARGET_SPEED_GEN3 0xc
#define LANE_ADP_CS_1_TARGET_WIDTH_MASK GENMASK(9, 4)
#define LANE_ADP_CS_1_TARGET_WIDTH_SHIFT 4
#define LANE_ADP_CS_1_TARGET_WIDTH_SINGLE 0x1

View File

@ -341,6 +341,47 @@ static struct tb_switch *alloc_dev_with_dpin(struct kunit *test,
return sw;
}
static struct tb_switch *alloc_dev_without_dp(struct kunit *test,
struct tb_switch *parent,
u64 route, bool bonded)
{
struct tb_switch *sw;
int i;
sw = alloc_dev_default(test, parent, route, bonded);
if (!sw)
return NULL;
/*
* Device with:
* 2x USB4 Adapters (adapters 1,2 and 3,4),
* 1x PCIe Upstream (adapter 9),
* 1x PCIe Downstream (adapter 10),
* 1x USB3 Upstream (adapter 16),
* 1x USB3 Downstream (adapter 17)
*/
for (i = 5; i <= 8; i++)
sw->ports[i].disabled = true;
for (i = 11; i <= 14; i++)
sw->ports[i].disabled = true;
sw->ports[13].cap_adap = 0;
sw->ports[14].cap_adap = 0;
for (i = 18; i <= 19; i++)
sw->ports[i].disabled = true;
sw->generation = 4;
sw->credit_allocation = true;
sw->max_usb3_credits = 109;
sw->min_dp_aux_credits = 0;
sw->min_dp_main_credits = 0;
sw->max_pcie_credits = 30;
sw->max_dma_credits = 1;
return sw;
}
static struct tb_switch *alloc_dev_usb4(struct kunit *test,
struct tb_switch *parent,
u64 route, bool bonded)
@ -1348,7 +1389,7 @@ static void tb_test_tunnel_dp(struct kunit *test)
in = &host->ports[5];
out = &dev->ports[13];
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
KUNIT_ASSERT_NOT_NULL(test, tunnel);
KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
@ -1394,7 +1435,7 @@ static void tb_test_tunnel_dp_chain(struct kunit *test)
in = &host->ports[5];
out = &dev4->ports[14];
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
KUNIT_ASSERT_NOT_NULL(test, tunnel);
KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
@ -1444,7 +1485,7 @@ static void tb_test_tunnel_dp_tree(struct kunit *test)
in = &dev2->ports[13];
out = &dev5->ports[13];
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
KUNIT_ASSERT_NOT_NULL(test, tunnel);
KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
@ -1509,7 +1550,7 @@ static void tb_test_tunnel_dp_max_length(struct kunit *test)
in = &dev6->ports[13];
out = &dev12->ports[13];
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
KUNIT_ASSERT_NOT_NULL(test, tunnel);
KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
@ -1627,7 +1668,7 @@ static void tb_test_tunnel_port_on_path(struct kunit *test)
in = &dev2->ports[13];
out = &dev5->ports[13];
dp_tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
dp_tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
KUNIT_ASSERT_NOT_NULL(test, dp_tunnel);
KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, in));
@ -1996,6 +2037,56 @@ static void tb_test_credit_alloc_pcie(struct kunit *test)
tb_tunnel_free(tunnel);
}
static void tb_test_credit_alloc_without_dp(struct kunit *test)
{
struct tb_switch *host, *dev;
struct tb_port *up, *down;
struct tb_tunnel *tunnel;
struct tb_path *path;
host = alloc_host_usb4(test);
dev = alloc_dev_without_dp(test, host, 0x1, true);
/*
* The device has no DP therefore baMinDPmain = baMinDPaux = 0
*
* Create PCIe path with buffers less than baMaxPCIe.
*
* For a device with buffers configurations:
* baMaxUSB3 = 109
* baMinDPaux = 0
* baMinDPmain = 0
* baMaxPCIe = 30
* baMaxHI = 1
* Remaining Buffers = Total - (CP + DP) = 120 - (2 + 0) = 118
* PCIe Credits = Max(6, Min(baMaxPCIe, Remaining Buffers - baMaxUSB3)
* = Max(6, Min(30, 9) = 9
*/
down = &host->ports[8];
up = &dev->ports[9];
tunnel = tb_tunnel_alloc_pci(NULL, up, down);
KUNIT_ASSERT_TRUE(test, tunnel != NULL);
KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
/* PCIe downstream path */
path = tunnel->paths[0];
KUNIT_ASSERT_EQ(test, path->path_length, 2);
KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 9U);
/* PCIe upstream path */
path = tunnel->paths[1];
KUNIT_ASSERT_EQ(test, path->path_length, 2);
KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 64U);
tb_tunnel_free(tunnel);
}
static void tb_test_credit_alloc_dp(struct kunit *test)
{
struct tb_switch *host, *dev;
@ -2009,7 +2100,7 @@ static void tb_test_credit_alloc_dp(struct kunit *test)
in = &host->ports[5];
out = &dev->ports[14];
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
KUNIT_ASSERT_NOT_NULL(test, tunnel);
KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3);
@ -2245,7 +2336,7 @@ static struct tb_tunnel *TB_TEST_DP_TUNNEL1(struct kunit *test,
in = &host->ports[5];
out = &dev->ports[13];
dp_tunnel1 = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
dp_tunnel1 = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
KUNIT_ASSERT_NOT_NULL(test, dp_tunnel1);
KUNIT_ASSERT_EQ(test, dp_tunnel1->npaths, (size_t)3);
@ -2282,7 +2373,7 @@ static struct tb_tunnel *TB_TEST_DP_TUNNEL2(struct kunit *test,
in = &host->ports[6];
out = &dev->ports[14];
dp_tunnel2 = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
dp_tunnel2 = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
KUNIT_ASSERT_NOT_NULL(test, dp_tunnel2);
KUNIT_ASSERT_EQ(test, dp_tunnel2->npaths, (size_t)3);
@ -2709,6 +2800,7 @@ static struct kunit_case tb_test_cases[] = {
KUNIT_CASE(tb_test_credit_alloc_legacy_not_bonded),
KUNIT_CASE(tb_test_credit_alloc_legacy_bonded),
KUNIT_CASE(tb_test_credit_alloc_pcie),
KUNIT_CASE(tb_test_credit_alloc_without_dp),
KUNIT_CASE(tb_test_credit_alloc_dp),
KUNIT_CASE(tb_test_credit_alloc_usb3),
KUNIT_CASE(tb_test_credit_alloc_dma),

View File

@ -102,8 +102,11 @@ static unsigned int tb_available_credits(const struct tb_port *port,
* Maximum number of DP streams possible through the
* lane adapter.
*/
ndp = (credits - (usb3 + pcie + spare)) /
(sw->min_dp_aux_credits + sw->min_dp_main_credits);
if (sw->min_dp_aux_credits + sw->min_dp_main_credits)
ndp = (credits - (usb3 + pcie + spare)) /
(sw->min_dp_aux_credits + sw->min_dp_main_credits);
else
ndp = 0;
} else {
ndp = 0;
}
@ -858,6 +861,7 @@ err_free:
* @tb: Pointer to the domain structure
* @in: DP in adapter port
* @out: DP out adapter port
* @link_nr: Preferred lane adapter when the link is not bonded
* @max_up: Maximum available upstream bandwidth for the DP tunnel (%0
* if not limited)
* @max_down: Maximum available downstream bandwidth for the DP tunnel
@ -869,8 +873,8 @@ err_free:
* Return: Returns a tb_tunnel on success or NULL on failure.
*/
struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
struct tb_port *out, int max_up,
int max_down)
struct tb_port *out, int link_nr,
int max_up, int max_down)
{
struct tb_tunnel *tunnel;
struct tb_path **paths;
@ -894,21 +898,21 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
paths = tunnel->paths;
path = tb_path_alloc(tb, in, TB_DP_VIDEO_HOPID, out, TB_DP_VIDEO_HOPID,
1, "Video");
link_nr, "Video");
if (!path)
goto err_free;
tb_dp_init_video_path(path);
paths[TB_DP_VIDEO_PATH_OUT] = path;
path = tb_path_alloc(tb, in, TB_DP_AUX_TX_HOPID, out,
TB_DP_AUX_TX_HOPID, 1, "AUX TX");
TB_DP_AUX_TX_HOPID, link_nr, "AUX TX");
if (!path)
goto err_free;
tb_dp_init_aux_path(path);
paths[TB_DP_AUX_PATH_OUT] = path;
path = tb_path_alloc(tb, out, TB_DP_AUX_RX_HOPID, in,
TB_DP_AUX_RX_HOPID, 1, "AUX RX");
TB_DP_AUX_RX_HOPID, link_nr, "AUX RX");
if (!path)
goto err_free;
tb_dp_init_aux_path(path);

View File

@ -71,8 +71,8 @@ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up,
struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in,
bool alloc_hopid);
struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
struct tb_port *out, int max_up,
int max_down);
struct tb_port *out, int link_nr,
int max_up, int max_down);
struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi,
struct tb_port *dst, int transmit_path,
int transmit_ring, int receive_path,

View File

@ -7,9 +7,37 @@
*/
#include <linux/pm_runtime.h>
#include <linux/component.h>
#include <linux/property.h>
#include "tb.h"
static int connector_bind(struct device *dev, struct device *connector, void *data)
{
int ret;
ret = sysfs_create_link(&dev->kobj, &connector->kobj, "connector");
if (ret)
return ret;
ret = sysfs_create_link(&connector->kobj, &dev->kobj, dev_name(dev));
if (ret)
sysfs_remove_link(&dev->kobj, "connector");
return ret;
}
static void connector_unbind(struct device *dev, struct device *connector, void *data)
{
sysfs_remove_link(&connector->kobj, dev_name(dev));
sysfs_remove_link(&dev->kobj, "connector");
}
static const struct component_ops connector_ops = {
.bind = connector_bind,
.unbind = connector_unbind,
};
static ssize_t link_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@ -246,6 +274,14 @@ struct usb4_port *usb4_port_device_add(struct tb_port *port)
return ERR_PTR(ret);
}
if (dev_fwnode(&usb4->dev)) {
ret = component_add(&usb4->dev, &connector_ops);
if (ret) {
dev_err(&usb4->dev, "failed to add component\n");
device_unregister(&usb4->dev);
}
}
pm_runtime_no_callbacks(&usb4->dev);
pm_runtime_set_active(&usb4->dev);
pm_runtime_enable(&usb4->dev);
@ -265,6 +301,8 @@ struct usb4_port *usb4_port_device_add(struct tb_port *port)
*/
void usb4_port_device_remove(struct usb4_port *usb4)
{
if (dev_fwnode(&usb4->dev))
component_del(&usb4->dev, &connector_ops);
device_unregister(&usb4->dev);
}

View File

@ -19,13 +19,38 @@
#include "tb.h"
#define XDOMAIN_DEFAULT_TIMEOUT 1000 /* ms */
#define XDOMAIN_UUID_RETRIES 10
#define XDOMAIN_PROPERTIES_RETRIES 10
#define XDOMAIN_PROPERTIES_CHANGED_RETRIES 10
#define XDOMAIN_BONDING_WAIT 100 /* ms */
#define XDOMAIN_SHORT_TIMEOUT 100 /* ms */
#define XDOMAIN_DEFAULT_TIMEOUT 1000 /* ms */
#define XDOMAIN_BONDING_TIMEOUT 10000 /* ms */
#define XDOMAIN_RETRIES 10
#define XDOMAIN_DEFAULT_MAX_HOPID 15
enum {
XDOMAIN_STATE_INIT,
XDOMAIN_STATE_UUID,
XDOMAIN_STATE_LINK_STATUS,
XDOMAIN_STATE_LINK_STATE_CHANGE,
XDOMAIN_STATE_LINK_STATUS2,
XDOMAIN_STATE_BONDING_UUID_LOW,
XDOMAIN_STATE_BONDING_UUID_HIGH,
XDOMAIN_STATE_PROPERTIES,
XDOMAIN_STATE_ENUMERATED,
XDOMAIN_STATE_ERROR,
};
static const char * const state_names[] = {
[XDOMAIN_STATE_INIT] = "INIT",
[XDOMAIN_STATE_UUID] = "UUID",
[XDOMAIN_STATE_LINK_STATUS] = "LINK_STATUS",
[XDOMAIN_STATE_LINK_STATE_CHANGE] = "LINK_STATE_CHANGE",
[XDOMAIN_STATE_LINK_STATUS2] = "LINK_STATUS2",
[XDOMAIN_STATE_BONDING_UUID_LOW] = "BONDING_UUID_LOW",
[XDOMAIN_STATE_BONDING_UUID_HIGH] = "BONDING_UUID_HIGH",
[XDOMAIN_STATE_PROPERTIES] = "PROPERTIES",
[XDOMAIN_STATE_ENUMERATED] = "ENUMERATED",
[XDOMAIN_STATE_ERROR] = "ERROR",
};
struct xdomain_request_work {
struct work_struct work;
struct tb_xdp_header *pkg;
@ -235,7 +260,7 @@ static int tb_xdp_handle_error(const struct tb_xdp_error_response *res)
}
static int tb_xdp_uuid_request(struct tb_ctl *ctl, u64 route, int retry,
uuid_t *uuid)
uuid_t *uuid, u64 *remote_route)
{
struct tb_xdp_uuid_response res;
struct tb_xdp_uuid req;
@ -258,6 +283,8 @@ static int tb_xdp_uuid_request(struct tb_ctl *ctl, u64 route, int retry,
return ret;
uuid_copy(uuid, &res.src_uuid);
*remote_route = (u64)res.src_route_hi << 32 | res.src_route_lo;
return 0;
}
@ -473,6 +500,112 @@ tb_xdp_properties_changed_response(struct tb_ctl *ctl, u64 route, u8 sequence)
TB_CFG_PKG_XDOMAIN_RESP);
}
static int tb_xdp_link_state_status_request(struct tb_ctl *ctl, u64 route,
u8 sequence, u8 *slw, u8 *tlw,
u8 *sls, u8 *tls)
{
struct tb_xdp_link_state_status_response res;
struct tb_xdp_link_state_status req;
int ret;
memset(&req, 0, sizeof(req));
tb_xdp_fill_header(&req.hdr, route, sequence, LINK_STATE_STATUS_REQUEST,
sizeof(req));
memset(&res, 0, sizeof(res));
ret = __tb_xdomain_request(ctl, &req, sizeof(req), TB_CFG_PKG_XDOMAIN_REQ,
&res, sizeof(res), TB_CFG_PKG_XDOMAIN_RESP,
XDOMAIN_DEFAULT_TIMEOUT);
if (ret)
return ret;
ret = tb_xdp_handle_error(&res.err);
if (ret)
return ret;
if (res.status != 0)
return -EREMOTEIO;
*slw = res.slw;
*tlw = res.tlw;
*sls = res.sls;
*tls = res.tls;
return 0;
}
static int tb_xdp_link_state_status_response(struct tb *tb, struct tb_ctl *ctl,
struct tb_xdomain *xd, u8 sequence)
{
struct tb_switch *sw = tb_to_switch(xd->dev.parent);
struct tb_xdp_link_state_status_response res;
struct tb_port *port = tb_port_at(xd->route, sw);
u32 val[2];
int ret;
memset(&res, 0, sizeof(res));
tb_xdp_fill_header(&res.hdr, xd->route, sequence,
LINK_STATE_STATUS_RESPONSE, sizeof(res));
ret = tb_port_read(port, val, TB_CFG_PORT,
port->cap_phy + LANE_ADP_CS_0, ARRAY_SIZE(val));
if (ret)
return ret;
res.slw = (val[0] & LANE_ADP_CS_0_SUPPORTED_WIDTH_MASK) >>
LANE_ADP_CS_0_SUPPORTED_WIDTH_SHIFT;
res.sls = (val[0] & LANE_ADP_CS_0_SUPPORTED_SPEED_MASK) >>
LANE_ADP_CS_0_SUPPORTED_SPEED_SHIFT;
res.tls = val[1] & LANE_ADP_CS_1_TARGET_SPEED_MASK;
res.tlw = (val[1] & LANE_ADP_CS_1_TARGET_WIDTH_MASK) >>
LANE_ADP_CS_1_TARGET_WIDTH_SHIFT;
return __tb_xdomain_response(ctl, &res, sizeof(res),
TB_CFG_PKG_XDOMAIN_RESP);
}
static int tb_xdp_link_state_change_request(struct tb_ctl *ctl, u64 route,
u8 sequence, u8 tlw, u8 tls)
{
struct tb_xdp_link_state_change_response res;
struct tb_xdp_link_state_change req;
int ret;
memset(&req, 0, sizeof(req));
tb_xdp_fill_header(&req.hdr, route, sequence, LINK_STATE_CHANGE_REQUEST,
sizeof(req));
req.tlw = tlw;
req.tls = tls;
memset(&res, 0, sizeof(res));
ret = __tb_xdomain_request(ctl, &req, sizeof(req), TB_CFG_PKG_XDOMAIN_REQ,
&res, sizeof(res), TB_CFG_PKG_XDOMAIN_RESP,
XDOMAIN_DEFAULT_TIMEOUT);
if (ret)
return ret;
ret = tb_xdp_handle_error(&res.err);
if (ret)
return ret;
return res.status != 0 ? -EREMOTEIO : 0;
}
static int tb_xdp_link_state_change_response(struct tb_ctl *ctl, u64 route,
u8 sequence, u32 status)
{
struct tb_xdp_link_state_change_response res;
memset(&res, 0, sizeof(res));
tb_xdp_fill_header(&res.hdr, route, sequence, LINK_STATE_CHANGE_RESPONSE,
sizeof(res));
res.status = status;
return __tb_xdomain_response(ctl, &res, sizeof(res),
TB_CFG_PKG_XDOMAIN_RESP);
}
/**
* tb_register_protocol_handler() - Register protocol handler
* @handler: Handler to register
@ -600,14 +733,13 @@ static void tb_xdp_handle_request(struct work_struct *work)
goto out;
}
tb_dbg(tb, "%llx: received XDomain request %#x\n", route, pkg->type);
xd = tb_xdomain_find_by_route_locked(tb, route);
if (xd)
update_property_block(xd);
switch (pkg->type) {
case PROPERTIES_REQUEST:
tb_dbg(tb, "%llx: received XDomain properties request\n", route);
if (xd) {
ret = tb_xdp_properties_response(tb, ctl, xd, sequence,
(const struct tb_xdp_properties *)pkg);
@ -615,6 +747,9 @@ static void tb_xdp_handle_request(struct work_struct *work)
break;
case PROPERTIES_CHANGED_REQUEST:
tb_dbg(tb, "%llx: received XDomain properties changed request\n",
route);
ret = tb_xdp_properties_changed_response(ctl, route, sequence);
/*
@ -622,18 +757,51 @@ static void tb_xdp_handle_request(struct work_struct *work)
* the xdomain related to this connection as well in
* case there is a change in services it offers.
*/
if (xd && device_is_registered(&xd->dev)) {
queue_delayed_work(tb->wq, &xd->get_properties_work,
msecs_to_jiffies(50));
}
if (xd && device_is_registered(&xd->dev))
queue_delayed_work(tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
break;
case UUID_REQUEST_OLD:
case UUID_REQUEST:
tb_dbg(tb, "%llx: received XDomain UUID request\n", route);
ret = tb_xdp_uuid_response(ctl, route, sequence, uuid);
break;
case LINK_STATE_STATUS_REQUEST:
tb_dbg(tb, "%llx: received XDomain link state status request\n",
route);
if (xd) {
ret = tb_xdp_link_state_status_response(tb, ctl, xd,
sequence);
} else {
tb_xdp_error_response(ctl, route, sequence,
ERROR_NOT_READY);
}
break;
case LINK_STATE_CHANGE_REQUEST:
tb_dbg(tb, "%llx: received XDomain link state change request\n",
route);
if (xd && xd->state == XDOMAIN_STATE_BONDING_UUID_HIGH) {
const struct tb_xdp_link_state_change *lsc =
(const struct tb_xdp_link_state_change *)pkg;
ret = tb_xdp_link_state_change_response(ctl, route,
sequence, 0);
xd->target_link_width = lsc->tlw;
queue_delayed_work(tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
} else {
tb_xdp_error_response(ctl, route, sequence,
ERROR_NOT_READY);
}
break;
default:
tb_dbg(tb, "%llx: unknown XDomain request %#x\n", route, pkg->type);
tb_xdp_error_response(ctl, route, sequence,
ERROR_NOT_SUPPORTED);
break;
@ -1000,32 +1168,38 @@ static int tb_xdomain_update_link_attributes(struct tb_xdomain *xd)
return 0;
}
static void tb_xdomain_get_uuid(struct work_struct *work)
static int tb_xdomain_get_uuid(struct tb_xdomain *xd)
{
struct tb_xdomain *xd = container_of(work, typeof(*xd),
get_uuid_work.work);
struct tb *tb = xd->tb;
uuid_t uuid;
u64 route;
int ret;
dev_dbg(&xd->dev, "requesting remote UUID\n");
ret = tb_xdp_uuid_request(tb->ctl, xd->route, xd->uuid_retries, &uuid);
ret = tb_xdp_uuid_request(tb->ctl, xd->route, xd->state_retries, &uuid,
&route);
if (ret < 0) {
if (xd->uuid_retries-- > 0) {
if (xd->state_retries-- > 0) {
dev_dbg(&xd->dev, "failed to request UUID, retrying\n");
queue_delayed_work(xd->tb->wq, &xd->get_uuid_work,
msecs_to_jiffies(100));
return -EAGAIN;
} else {
dev_dbg(&xd->dev, "failed to read remote UUID\n");
}
return;
return ret;
}
dev_dbg(&xd->dev, "got remote UUID %pUb\n", &uuid);
if (uuid_equal(&uuid, xd->local_uuid))
dev_dbg(&xd->dev, "intra-domain loop detected\n");
if (uuid_equal(&uuid, xd->local_uuid)) {
if (route == xd->route)
dev_dbg(&xd->dev, "loop back detected\n");
else
dev_dbg(&xd->dev, "intra-domain loop detected\n");
/* Don't bond lanes automatically for loops */
xd->bonding_possible = false;
}
/*
* If the UUID is different, there is another domain connected
@ -1035,27 +1209,152 @@ static void tb_xdomain_get_uuid(struct work_struct *work)
if (xd->remote_uuid && !uuid_equal(&uuid, xd->remote_uuid)) {
dev_dbg(&xd->dev, "remote UUID is different, unplugging\n");
xd->is_unplugged = true;
return;
return -ENODEV;
}
/* First time fill in the missing UUID */
if (!xd->remote_uuid) {
xd->remote_uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL);
if (!xd->remote_uuid)
return;
return -ENOMEM;
}
/* Now we can start the normal properties exchange */
queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
msecs_to_jiffies(100));
queue_delayed_work(xd->tb->wq, &xd->get_properties_work,
msecs_to_jiffies(1000));
return 0;
}
static void tb_xdomain_get_properties(struct work_struct *work)
static int tb_xdomain_get_link_status(struct tb_xdomain *xd)
{
struct tb *tb = xd->tb;
u8 slw, tlw, sls, tls;
int ret;
dev_dbg(&xd->dev, "sending link state status request to %pUb\n",
xd->remote_uuid);
ret = tb_xdp_link_state_status_request(tb->ctl, xd->route,
xd->state_retries, &slw, &tlw, &sls,
&tls);
if (ret) {
if (ret != -EOPNOTSUPP && xd->state_retries-- > 0) {
dev_dbg(&xd->dev,
"failed to request remote link status, retrying\n");
return -EAGAIN;
}
dev_dbg(&xd->dev, "failed to receive remote link status\n");
return ret;
}
dev_dbg(&xd->dev, "remote link supports width %#x speed %#x\n", slw, sls);
if (slw < LANE_ADP_CS_0_SUPPORTED_WIDTH_DUAL) {
dev_dbg(&xd->dev, "remote adapter is single lane only\n");
return -EOPNOTSUPP;
}
return 0;
}
static int tb_xdomain_link_state_change(struct tb_xdomain *xd,
unsigned int width)
{
struct tb_switch *sw = tb_to_switch(xd->dev.parent);
struct tb_port *port = tb_port_at(xd->route, sw);
struct tb *tb = xd->tb;
u8 tlw, tls;
u32 val;
int ret;
if (width == 2)
tlw = LANE_ADP_CS_1_TARGET_WIDTH_DUAL;
else if (width == 1)
tlw = LANE_ADP_CS_1_TARGET_WIDTH_SINGLE;
else
return -EINVAL;
/* Use the current target speed */
ret = tb_port_read(port, &val, TB_CFG_PORT, port->cap_phy + LANE_ADP_CS_1, 1);
if (ret)
return ret;
tls = val & LANE_ADP_CS_1_TARGET_SPEED_MASK;
dev_dbg(&xd->dev, "sending link state change request with width %#x speed %#x\n",
tlw, tls);
ret = tb_xdp_link_state_change_request(tb->ctl, xd->route,
xd->state_retries, tlw, tls);
if (ret) {
if (ret != -EOPNOTSUPP && xd->state_retries-- > 0) {
dev_dbg(&xd->dev,
"failed to change remote link state, retrying\n");
return -EAGAIN;
}
dev_err(&xd->dev, "failed request link state change, aborting\n");
return ret;
}
dev_dbg(&xd->dev, "received link state change response\n");
return 0;
}
static int tb_xdomain_bond_lanes_uuid_high(struct tb_xdomain *xd)
{
struct tb_port *port;
int ret, width;
if (xd->target_link_width == LANE_ADP_CS_1_TARGET_WIDTH_SINGLE) {
width = 1;
} else if (xd->target_link_width == LANE_ADP_CS_1_TARGET_WIDTH_DUAL) {
width = 2;
} else {
if (xd->state_retries-- > 0) {
dev_dbg(&xd->dev,
"link state change request not received yet, retrying\n");
return -EAGAIN;
}
dev_dbg(&xd->dev, "timeout waiting for link change request\n");
return -ETIMEDOUT;
}
port = tb_port_at(xd->route, tb_xdomain_parent(xd));
/*
* We can't use tb_xdomain_lane_bonding_enable() here because it
* is the other side that initiates lane bonding. So here we
* just set the width to both lane adapters and wait for the
* link to transition bonded.
*/
ret = tb_port_set_link_width(port->dual_link_port, width);
if (ret) {
tb_port_warn(port->dual_link_port,
"failed to set link width to %d\n", width);
return ret;
}
ret = tb_port_set_link_width(port, width);
if (ret) {
tb_port_warn(port, "failed to set link width to %d\n", width);
return ret;
}
ret = tb_port_wait_for_link_width(port, width, XDOMAIN_BONDING_TIMEOUT);
if (ret) {
dev_warn(&xd->dev, "error waiting for link width to become %d\n",
width);
return ret;
}
port->bonded = width == 2;
port->dual_link_port->bonded = width == 2;
tb_port_update_credits(port);
tb_xdomain_update_link_attributes(xd);
dev_dbg(&xd->dev, "lane bonding %sabled\n", width == 2 ? "en" : "dis");
return 0;
}
static int tb_xdomain_get_properties(struct tb_xdomain *xd)
{
struct tb_xdomain *xd = container_of(work, typeof(*xd),
get_properties_work.work);
struct tb_property_dir *dir;
struct tb *tb = xd->tb;
bool update = false;
@ -1066,34 +1365,35 @@ static void tb_xdomain_get_properties(struct work_struct *work)
dev_dbg(&xd->dev, "requesting remote properties\n");
ret = tb_xdp_properties_request(tb->ctl, xd->route, xd->local_uuid,
xd->remote_uuid, xd->properties_retries,
xd->remote_uuid, xd->state_retries,
&block, &gen);
if (ret < 0) {
if (xd->properties_retries-- > 0) {
if (xd->state_retries-- > 0) {
dev_dbg(&xd->dev,
"failed to request remote properties, retrying\n");
queue_delayed_work(xd->tb->wq, &xd->get_properties_work,
msecs_to_jiffies(1000));
return -EAGAIN;
} else {
/* Give up now */
dev_err(&xd->dev,
"failed read XDomain properties from %pUb\n",
xd->remote_uuid);
}
return;
}
xd->properties_retries = XDOMAIN_PROPERTIES_RETRIES;
return ret;
}
mutex_lock(&xd->lock);
/* Only accept newer generation properties */
if (xd->remote_properties && gen <= xd->remote_property_block_gen)
if (xd->remote_properties && gen <= xd->remote_property_block_gen) {
ret = 0;
goto err_free_block;
}
dir = tb_property_parse_dir(block, ret);
if (!dir) {
dev_err(&xd->dev, "failed to parse XDomain properties\n");
ret = -ENOMEM;
goto err_free_block;
}
@ -1124,9 +1424,16 @@ static void tb_xdomain_get_properties(struct work_struct *work)
* registered, we notify the userspace that it has changed.
*/
if (!update) {
struct tb_port *port;
/* Now disable lane 1 if bonding was not enabled */
port = tb_port_at(xd->route, tb_xdomain_parent(xd));
if (!port->bonded)
tb_port_disable(port->dual_link_port);
if (device_add(&xd->dev)) {
dev_err(&xd->dev, "failed to add XDomain device\n");
return;
return -ENODEV;
}
dev_info(&xd->dev, "new host found, vendor=%#x device=%#x\n",
xd->vendor, xd->device);
@ -1138,13 +1445,193 @@ static void tb_xdomain_get_properties(struct work_struct *work)
}
enumerate_services(xd);
return;
return 0;
err_free_dir:
tb_property_free_dir(dir);
err_free_block:
kfree(block);
mutex_unlock(&xd->lock);
return ret;
}
static void tb_xdomain_queue_uuid(struct tb_xdomain *xd)
{
xd->state = XDOMAIN_STATE_UUID;
xd->state_retries = XDOMAIN_RETRIES;
queue_delayed_work(xd->tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
}
static void tb_xdomain_queue_link_status(struct tb_xdomain *xd)
{
xd->state = XDOMAIN_STATE_LINK_STATUS;
xd->state_retries = XDOMAIN_RETRIES;
queue_delayed_work(xd->tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
}
static void tb_xdomain_queue_link_status2(struct tb_xdomain *xd)
{
xd->state = XDOMAIN_STATE_LINK_STATUS2;
xd->state_retries = XDOMAIN_RETRIES;
queue_delayed_work(xd->tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
}
static void tb_xdomain_queue_bonding(struct tb_xdomain *xd)
{
if (memcmp(xd->local_uuid, xd->remote_uuid, UUID_SIZE) > 0) {
dev_dbg(&xd->dev, "we have higher UUID, other side bonds the lanes\n");
xd->state = XDOMAIN_STATE_BONDING_UUID_HIGH;
} else {
dev_dbg(&xd->dev, "we have lower UUID, bonding lanes\n");
xd->state = XDOMAIN_STATE_LINK_STATE_CHANGE;
}
xd->state_retries = XDOMAIN_RETRIES;
queue_delayed_work(xd->tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
}
static void tb_xdomain_queue_bonding_uuid_low(struct tb_xdomain *xd)
{
xd->state = XDOMAIN_STATE_BONDING_UUID_LOW;
xd->state_retries = XDOMAIN_RETRIES;
queue_delayed_work(xd->tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
}
static void tb_xdomain_queue_properties(struct tb_xdomain *xd)
{
xd->state = XDOMAIN_STATE_PROPERTIES;
xd->state_retries = XDOMAIN_RETRIES;
queue_delayed_work(xd->tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
}
static void tb_xdomain_queue_properties_changed(struct tb_xdomain *xd)
{
xd->properties_changed_retries = XDOMAIN_RETRIES;
queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
}
static void tb_xdomain_state_work(struct work_struct *work)
{
struct tb_xdomain *xd = container_of(work, typeof(*xd), state_work.work);
int ret, state = xd->state;
if (WARN_ON_ONCE(state < XDOMAIN_STATE_INIT ||
state > XDOMAIN_STATE_ERROR))
return;
dev_dbg(&xd->dev, "running state %s\n", state_names[state]);
switch (state) {
case XDOMAIN_STATE_INIT:
if (xd->needs_uuid) {
tb_xdomain_queue_uuid(xd);
} else {
tb_xdomain_queue_properties_changed(xd);
tb_xdomain_queue_properties(xd);
}
break;
case XDOMAIN_STATE_UUID:
ret = tb_xdomain_get_uuid(xd);
if (ret) {
if (ret == -EAGAIN)
goto retry_state;
xd->state = XDOMAIN_STATE_ERROR;
} else {
tb_xdomain_queue_properties_changed(xd);
if (xd->bonding_possible)
tb_xdomain_queue_link_status(xd);
else
tb_xdomain_queue_properties(xd);
}
break;
case XDOMAIN_STATE_LINK_STATUS:
ret = tb_xdomain_get_link_status(xd);
if (ret) {
if (ret == -EAGAIN)
goto retry_state;
/*
* If any of the lane bonding states fail we skip
* bonding completely and try to continue from
* reading properties.
*/
tb_xdomain_queue_properties(xd);
} else {
tb_xdomain_queue_bonding(xd);
}
break;
case XDOMAIN_STATE_LINK_STATE_CHANGE:
ret = tb_xdomain_link_state_change(xd, 2);
if (ret) {
if (ret == -EAGAIN)
goto retry_state;
tb_xdomain_queue_properties(xd);
} else {
tb_xdomain_queue_link_status2(xd);
}
break;
case XDOMAIN_STATE_LINK_STATUS2:
ret = tb_xdomain_get_link_status(xd);
if (ret) {
if (ret == -EAGAIN)
goto retry_state;
tb_xdomain_queue_properties(xd);
} else {
tb_xdomain_queue_bonding_uuid_low(xd);
}
break;
case XDOMAIN_STATE_BONDING_UUID_LOW:
tb_xdomain_lane_bonding_enable(xd);
tb_xdomain_queue_properties(xd);
break;
case XDOMAIN_STATE_BONDING_UUID_HIGH:
if (tb_xdomain_bond_lanes_uuid_high(xd) == -EAGAIN)
goto retry_state;
tb_xdomain_queue_properties(xd);
break;
case XDOMAIN_STATE_PROPERTIES:
ret = tb_xdomain_get_properties(xd);
if (ret) {
if (ret == -EAGAIN)
goto retry_state;
xd->state = XDOMAIN_STATE_ERROR;
} else {
xd->state = XDOMAIN_STATE_ENUMERATED;
}
break;
case XDOMAIN_STATE_ENUMERATED:
tb_xdomain_queue_properties(xd);
break;
case XDOMAIN_STATE_ERROR:
break;
default:
dev_warn(&xd->dev, "unexpected state %d\n", state);
break;
}
return;
retry_state:
queue_delayed_work(xd->tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
}
static void tb_xdomain_properties_changed(struct work_struct *work)
@ -1163,13 +1650,13 @@ static void tb_xdomain_properties_changed(struct work_struct *work)
"failed to send properties changed notification, retrying\n");
queue_delayed_work(xd->tb->wq,
&xd->properties_changed_work,
msecs_to_jiffies(1000));
msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
}
dev_err(&xd->dev, "failed to send properties changed notification\n");
return;
}
xd->properties_changed_retries = XDOMAIN_PROPERTIES_CHANGED_RETRIES;
xd->properties_changed_retries = XDOMAIN_RETRIES;
}
static ssize_t device_show(struct device *dev, struct device_attribute *attr,
@ -1304,31 +1791,17 @@ static void tb_xdomain_release(struct device *dev)
static void start_handshake(struct tb_xdomain *xd)
{
xd->uuid_retries = XDOMAIN_UUID_RETRIES;
xd->properties_retries = XDOMAIN_PROPERTIES_RETRIES;
xd->properties_changed_retries = XDOMAIN_PROPERTIES_CHANGED_RETRIES;
if (xd->needs_uuid) {
queue_delayed_work(xd->tb->wq, &xd->get_uuid_work,
msecs_to_jiffies(100));
} else {
/* Start exchanging properties with the other host */
queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
msecs_to_jiffies(100));
queue_delayed_work(xd->tb->wq, &xd->get_properties_work,
msecs_to_jiffies(1000));
}
xd->state = XDOMAIN_STATE_INIT;
queue_delayed_work(xd->tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
}
static void stop_handshake(struct tb_xdomain *xd)
{
xd->uuid_retries = 0;
xd->properties_retries = 0;
xd->properties_changed_retries = 0;
cancel_delayed_work_sync(&xd->get_uuid_work);
cancel_delayed_work_sync(&xd->get_properties_work);
cancel_delayed_work_sync(&xd->properties_changed_work);
cancel_delayed_work_sync(&xd->state_work);
xd->properties_changed_retries = 0;
xd->state_retries = 0;
}
static int __maybe_unused tb_xdomain_suspend(struct device *dev)
@ -1389,8 +1862,7 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent,
ida_init(&xd->in_hopids);
ida_init(&xd->out_hopids);
mutex_init(&xd->lock);
INIT_DELAYED_WORK(&xd->get_uuid_work, tb_xdomain_get_uuid);
INIT_DELAYED_WORK(&xd->get_properties_work, tb_xdomain_get_properties);
INIT_DELAYED_WORK(&xd->state_work, tb_xdomain_state_work);
INIT_DELAYED_WORK(&xd->properties_changed_work,
tb_xdomain_properties_changed);
@ -1405,6 +1877,7 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent,
goto err_free_local_uuid;
} else {
xd->needs_uuid = true;
xd->bonding_possible = !!down->dual_link_port;
}
device_initialize(&xd->dev);
@ -1523,9 +1996,9 @@ int tb_xdomain_lane_bonding_enable(struct tb_xdomain *xd)
return ret;
}
ret = tb_port_wait_for_link_width(port, 2, 100);
ret = tb_port_wait_for_link_width(port, 2, XDOMAIN_BONDING_TIMEOUT);
if (ret) {
tb_port_warn(port, "timeout enabling lane bonding\n");
tb_port_warn(port, "failed to enable lane bonding\n");
return ret;
}

View File

@ -1091,7 +1091,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
snd_buf_bytes - (snd_buf_bytes % instance->tx_channel.stride));
/* rx buffer size must be a positive multiple of the endpoint maxpacket */
maxpacket = usb_maxpacket(usb_dev, instance->rx_channel.endpoint, 0);
maxpacket = usb_maxpacket(usb_dev, instance->rx_channel.endpoint);
if ((maxpacket < 1) || (maxpacket > UDSL_MAX_BUF_SIZE)) {
dev_err(dev, "%s: invalid endpoint %02x!\n", __func__,

View File

@ -189,14 +189,12 @@ static int c67x00_drv_remove(struct platform_device *pdev)
c67x00_ll_release(c67x00);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res)
free_irq(res->start, c67x00);
free_irq(res->start, c67x00);
iounmap(c67x00->hpi.base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
release_mem_region(res->start, resource_size(res));
release_mem_region(res->start, resource_size(res));
kfree(c67x00);

View File

@ -655,7 +655,7 @@ static int c67x00_add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb)
usb_pipeout(urb->pipe));
remaining = urb->transfer_buffer_length - urb->actual_length;
maxps = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
maxps = usb_maxpacket(urb->dev, urb->pipe);
need_empty = (urb->transfer_flags & URB_ZERO_PACKET) &&
usb_pipeout(urb->pipe) && !(remaining % maxps);
@ -866,7 +866,7 @@ static inline int c67x00_end_of_data(struct c67x00_td *td)
if (unlikely(!act_bytes))
return 1; /* This was an empty packet */
maxps = usb_maxpacket(td_udev(td), td->pipe, usb_pipeout(td->pipe));
maxps = usb_maxpacket(td_udev(td), td->pipe);
if (unlikely(act_bytes < maxps))
return 1; /* Smaller then full packet */

View File

@ -2038,7 +2038,7 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable)
u8 mult = 0;
int ret;
buffering = CDNS3_EP_BUF_SIZE - 1;
buffering = priv_dev->ep_buf_size - 1;
cdns3_configure_dmult(priv_dev, priv_ep);
@ -2057,7 +2057,7 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable)
break;
default:
ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_ISOC);
mult = CDNS3_EP_ISO_HS_MULT - 1;
mult = priv_dev->ep_iso_burst - 1;
buffering = mult + 1;
}
@ -2073,14 +2073,14 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable)
mult = 0;
max_packet_size = 1024;
if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) {
maxburst = CDNS3_EP_ISO_SS_BURST - 1;
maxburst = priv_dev->ep_iso_burst - 1;
buffering = (mult + 1) *
(maxburst + 1);
if (priv_ep->interval > 1)
buffering++;
} else {
maxburst = CDNS3_EP_BUF_SIZE - 1;
maxburst = priv_dev->ep_buf_size - 1;
}
break;
default:
@ -2095,6 +2095,10 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable)
else
priv_ep->trb_burst_size = 16;
mult = min_t(u8, mult, EP_CFG_MULT_MAX);
buffering = min_t(u8, buffering, EP_CFG_BUFFERING_MAX);
maxburst = min_t(u8, maxburst, EP_CFG_MAXBURST_MAX);
/* onchip buffer is only allocated before configuration */
if (!priv_dev->hw_configured_flag) {
ret = cdns3_ep_onchip_buffer_reserve(priv_dev, buffering + 1,
@ -2961,6 +2965,40 @@ static int cdns3_gadget_udc_stop(struct usb_gadget *gadget)
return 0;
}
/**
* cdns3_gadget_check_config - ensure cdns3 can support the USB configuration
* @gadget: pointer to the USB gadget
*
* Used to record the maximum number of endpoints being used in a USB composite
* device. (across all configurations) This is to be used in the calculation
* of the TXFIFO sizes when resizing internal memory for individual endpoints.
* It will help ensured that the resizing logic reserves enough space for at
* least one max packet.
*/
static int cdns3_gadget_check_config(struct usb_gadget *gadget)
{
struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget);
struct usb_ep *ep;
int n_in = 0;
int total;
list_for_each_entry(ep, &gadget->ep_list, ep_list) {
if (ep->claimed && (ep->address & USB_DIR_IN))
n_in++;
}
/* 2KB are reserved for EP0, 1KB for out*/
total = 2 + n_in + 1;
if (total > priv_dev->onchip_buffers)
return -ENOMEM;
priv_dev->ep_buf_size = priv_dev->ep_iso_burst =
(priv_dev->onchip_buffers - 2) / (n_in + 1);
return 0;
}
static const struct usb_gadget_ops cdns3_gadget_ops = {
.get_frame = cdns3_gadget_get_frame,
.wakeup = cdns3_gadget_wakeup,
@ -2969,6 +3007,7 @@ static const struct usb_gadget_ops cdns3_gadget_ops = {
.udc_start = cdns3_gadget_udc_start,
.udc_stop = cdns3_gadget_udc_stop,
.match_ep = cdns3_gadget_match_ep,
.check_config = cdns3_gadget_check_config,
};
static void cdns3_free_all_eps(struct cdns3_device *priv_dev)

View File

@ -562,15 +562,18 @@ struct cdns3_usb_regs {
/* Max burst size (used only in SS mode). */
#define EP_CFG_MAXBURST_MASK GENMASK(11, 8)
#define EP_CFG_MAXBURST(p) (((p) << 8) & EP_CFG_MAXBURST_MASK)
#define EP_CFG_MAXBURST_MAX 15
/* ISO max burst. */
#define EP_CFG_MULT_MASK GENMASK(15, 14)
#define EP_CFG_MULT(p) (((p) << 14) & EP_CFG_MULT_MASK)
#define EP_CFG_MULT_MAX 2
/* ISO max burst. */
#define EP_CFG_MAXPKTSIZE_MASK GENMASK(26, 16)
#define EP_CFG_MAXPKTSIZE(p) (((p) << 16) & EP_CFG_MAXPKTSIZE_MASK)
/* Max number of buffered packets. */
#define EP_CFG_BUFFERING_MASK GENMASK(31, 27)
#define EP_CFG_BUFFERING(p) (((p) << 27) & EP_CFG_BUFFERING_MASK)
#define EP_CFG_BUFFERING_MAX 15
/* EP_CMD - bitmasks */
/* Endpoint reset. */
@ -1094,9 +1097,6 @@ struct cdns3_trb {
#define CDNS3_ENDPOINTS_MAX_COUNT 32
#define CDNS3_EP_ZLP_BUF_SIZE 1024
#define CDNS3_EP_BUF_SIZE 4 /* KB */
#define CDNS3_EP_ISO_HS_MULT 3
#define CDNS3_EP_ISO_SS_BURST 3
#define CDNS3_MAX_NUM_DESCMISS_BUF 32
#define CDNS3_DESCMIS_BUF_SIZE 2048 /* Bytes */
#define CDNS3_WA2_NUM_BUFFERS 128
@ -1333,6 +1333,9 @@ struct cdns3_device {
/*in KB */
u16 onchip_buffers;
u16 onchip_used_size;
u16 ep_buf_size;
u16 ep_iso_burst;
};
void cdns3_set_register_bit(void __iomem *ptr, u32 mask);

View File

@ -228,8 +228,6 @@ static char *usb_dump_interface(int speed, char *start, char *end,
start = usb_dump_interface_descriptor(start, end, intfc, iface, setno);
for (i = 0; i < desc->desc.bNumEndpoints; i++) {
if (start > end)
return start;
start = usb_dump_endpoint_descriptor(speed,
start, end, &desc->endpoint[i].desc);
}
@ -302,8 +300,6 @@ static char *usb_dump_config(int speed, char *start, char *end,
intfc = config->intf_cache[i];
interface = config->interface[i];
for (j = 0; j < intfc->num_altsetting; j++) {
if (start > end)
return start;
start = usb_dump_interface(speed,
start, end, intfc, interface, j);
}
@ -369,19 +365,11 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
{
int i;
if (start > end)
return start;
start = usb_dump_device_descriptor(start, end, &dev->descriptor);
if (start > end)
return start;
start = usb_dump_device_strings(start, end, dev);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (start > end)
return start;
start = usb_dump_config(dev->speed,
start, end, dev->config + i,
/* active ? */
@ -390,41 +378,6 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
return start;
}
#ifdef PROC_EXTRA /* TBD: may want to add this code later */
static char *usb_dump_hub_descriptor(char *start, char *end,
const struct usb_hub_descriptor *desc)
{
int leng = USB_DT_HUB_NONVAR_SIZE;
unsigned char *ptr = (unsigned char *)desc;
if (start > end)
return start;
start += sprintf(start, "Interface:");
while (leng && start <= end) {
start += sprintf(start, " %02x", *ptr);
ptr++; leng--;
}
*start++ = '\n';
return start;
}
static char *usb_dump_string(char *start, char *end,
const struct usb_device *dev, char *id, int index)
{
if (start > end)
return start;
start += sprintf(start, "Interface:");
if (index <= dev->maxstring && dev->stringindex &&
dev->stringindex[index])
start += sprintf(start, "%s: %.100s ", id,
dev->stringindex[index]);
return start;
}
#endif /* PROC_EXTRA */
/*****************************************************************/
/* This is a recursive function. Parameters:

View File

@ -1533,22 +1533,23 @@ static void choose_wakeup(struct usb_device *udev, pm_message_t msg)
{
int w;
/* Remote wakeup is needed only when we actually go to sleep.
* For things like FREEZE and QUIESCE, if the device is already
* autosuspended then its current wakeup setting is okay.
/*
* For FREEZE/QUIESCE, disable remote wakeups so no interrupts get
* generated.
*/
if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_QUIESCE) {
if (udev->state != USB_STATE_SUSPENDED)
udev->do_remote_wakeup = 0;
return;
w = 0;
} else {
/*
* Enable remote wakeup if it is allowed, even if no interface
* drivers actually want it.
*/
w = device_may_wakeup(&udev->dev);
}
/* Enable remote wakeup if it is allowed, even if no interface drivers
* actually want it.
*/
w = device_may_wakeup(&udev->dev);
/* If the device is autosuspended with the wrong wakeup setting,
/*
* If the device is autosuspended with the wrong wakeup setting,
* autoresume now so the setting can be changed.
*/
if (udev->state == USB_STATE_SUSPENDED && w != udev->do_remote_wakeup)

View File

@ -15,7 +15,6 @@
#ifdef CONFIG_PPC_PMAC
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/prom.h>
#endif
#include "usb.h"
@ -616,10 +615,10 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = {
.suspend_noirq = hcd_pci_suspend_noirq,
.resume_noirq = hcd_pci_resume_noirq,
.resume = hcd_pci_resume,
.freeze = check_root_hub_suspended,
.freeze = hcd_pci_suspend,
.freeze_noirq = check_root_hub_suspended,
.thaw_noirq = NULL,
.thaw = NULL,
.thaw = hcd_pci_resume,
.poweroff = hcd_pci_suspend,
.poweroff_noirq = hcd_pci_suspend_noirq,
.restore_noirq = hcd_pci_resume_noirq,

View File

@ -2816,6 +2816,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
{
int retval;
struct usb_device *rhdev;
struct usb_hcd *shared_hcd;
if (!hcd->skip_phy_initialization && usb_hcd_is_primary_hcd(hcd)) {
hcd->phy_roothub = usb_phy_roothub_alloc(hcd->self.sysdev);
@ -2976,13 +2977,26 @@ int usb_add_hcd(struct usb_hcd *hcd,
goto err_hcd_driver_start;
}
/* starting here, usbcore will pay attention to this root hub */
retval = register_root_hub(hcd);
if (retval != 0)
goto err_register_root_hub;
/* starting here, usbcore will pay attention to the shared HCD roothub */
shared_hcd = hcd->shared_hcd;
if (!usb_hcd_is_primary_hcd(hcd) && shared_hcd && HCD_DEFER_RH_REGISTER(shared_hcd)) {
retval = register_root_hub(shared_hcd);
if (retval != 0)
goto err_register_root_hub;
if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
usb_hcd_poll_rh_status(hcd);
if (shared_hcd->uses_new_polling && HCD_POLL_RH(shared_hcd))
usb_hcd_poll_rh_status(shared_hcd);
}
/* starting here, usbcore will pay attention to this root hub */
if (!HCD_DEFER_RH_REGISTER(hcd)) {
retval = register_root_hub(hcd);
if (retval != 0)
goto err_register_root_hub;
if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
usb_hcd_poll_rh_status(hcd);
}
return retval;
@ -3020,6 +3034,7 @@ EXPORT_SYMBOL_GPL(usb_add_hcd);
void usb_remove_hcd(struct usb_hcd *hcd)
{
struct usb_device *rhdev = hcd->self.root_hub;
bool rh_registered;
dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);
@ -3030,6 +3045,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
dev_dbg(hcd->self.controller, "roothub graceful disconnect\n");
spin_lock_irq (&hcd_root_hub_lock);
rh_registered = hcd->rh_registered;
hcd->rh_registered = 0;
spin_unlock_irq (&hcd_root_hub_lock);
@ -3039,7 +3055,8 @@ void usb_remove_hcd(struct usb_hcd *hcd)
cancel_work_sync(&hcd->died_work);
mutex_lock(&usb_bus_idr_lock);
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
if (rh_registered)
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
mutex_unlock(&usb_bus_idr_lock);
/*

View File

@ -1635,7 +1635,7 @@ static int hub_configure(struct usb_hub *hub,
* maxpktsize is defined in hcd.c's fake endpoint descriptors
* to be big enough for at least USB_MAXCHILDREN ports. */
pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
maxp = usb_maxpacket(hdev, pipe);
if (maxp > sizeof(*hub->buffer))
maxp = sizeof(*hub->buffer);
@ -5511,7 +5511,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
/* Handle notifying userspace about hub over-current events */
static void port_over_current_notify(struct usb_port *port_dev)
{
char *envp[3];
char *envp[3] = { NULL, NULL, NULL };
struct device *hub_dev;
char *port_dev_path;
@ -5528,20 +5528,18 @@ static void port_over_current_notify(struct usb_port *port_dev)
envp[0] = kasprintf(GFP_KERNEL, "OVER_CURRENT_PORT=%s", port_dev_path);
if (!envp[0])
goto exit_path;
goto exit;
envp[1] = kasprintf(GFP_KERNEL, "OVER_CURRENT_COUNT=%u",
port_dev->over_current_count);
if (!envp[1])
goto exit;
envp[2] = NULL;
kobject_uevent_env(&hub_dev->kobj, KOBJ_CHANGE, envp);
kfree(envp[1]);
exit:
kfree(envp[1]);
kfree(envp[0]);
exit_path:
kfree(port_dev_path);
}

View File

@ -510,6 +510,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* DJI CineSSD */
{ USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
/* DELL USB GEN2 */
{ USB_DEVICE(0x413c, 0xb062), .driver_info = USB_QUIRK_NO_LPM | USB_QUIRK_RESET_RESUME },
/* VCOM device */
{ USB_DEVICE(0x4296, 0x7570), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS },

View File

@ -205,8 +205,11 @@ usb_acpi_find_companion_for_device(struct usb_device *udev)
struct usb_hub *hub;
if (!udev->parent) {
/* root hub is only child (_ADR=0) under its parent, the HC */
adev = ACPI_COMPANION(udev->dev.parent);
/*
* root hub is only child (_ADR=0) under its parent, the HC.
* sysdev pointer is the HC as seen from firmware.
*/
adev = ACPI_COMPANION(udev->bus->sysdev);
return acpi_find_child_device(adev, 0, false);
}

View File

@ -1153,6 +1153,7 @@ static void dwc2_set_turnaround_time(struct dwc2_hsotg *hsotg)
int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
{
u32 usbcfg;
u32 otgctl;
int retval = 0;
if ((hsotg->params.speed == DWC2_SPEED_PARAM_FULL ||
@ -1187,6 +1188,14 @@ int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
dwc2_writel(hsotg, usbcfg, GUSBCFG);
}
if (!hsotg->params.activate_ingenic_overcurrent_detection) {
if (dwc2_is_host_mode(hsotg)) {
otgctl = readl(hsotg->regs + GOTGCTL);
otgctl |= GOTGCTL_VBVALOEN | GOTGCTL_VBVALOVAL;
writel(otgctl, hsotg->regs + GOTGCTL);
}
}
return retval;
}

View File

@ -426,6 +426,10 @@ enum dwc2_ep0_state {
* detection using GGPIO register.
* 0 - Deactivate the external level detection (default)
* 1 - Activate the external level detection
* @activate_ingenic_overcurrent_detection: Activate Ingenic overcurrent
* detection.
* 0 - Deactivate the overcurrent detection
* 1 - Activate the overcurrent detection (default)
* @g_dma: Enables gadget dma usage (default: autodetect).
* @g_dma_desc: Enables gadget descriptor DMA (default: autodetect).
* @g_rx_fifo_size: The periodic rx fifo size for the device, in
@ -494,6 +498,7 @@ struct dwc2_core_params {
u8 hird_threshold;
bool activate_stm_fs_transceiver;
bool activate_stm_id_vb_detection;
bool activate_ingenic_overcurrent_detection;
bool ipg_isoc_en;
u16 max_packet_count;
u32 max_transfer_size;

View File

@ -4544,7 +4544,6 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget,
WARN_ON(hsotg->driver);
driver->driver.bus = NULL;
hsotg->driver = driver;
hsotg->gadget.dev.of_node = hsotg->dev->of_node;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;

View File

@ -73,6 +73,47 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
}
static void dwc2_set_jz4775_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->otg_caps.hnp_support = false;
p->speed = DWC2_SPEED_PARAM_HIGH;
p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
p->phy_utmi_width = 16;
p->activate_ingenic_overcurrent_detection =
!device_property_read_bool(hsotg->dev, "disable-over-current");
}
static void dwc2_set_x1600_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->otg_caps.hnp_support = false;
p->speed = DWC2_SPEED_PARAM_HIGH;
p->host_channels = 16;
p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
p->phy_utmi_width = 16;
p->activate_ingenic_overcurrent_detection =
!device_property_read_bool(hsotg->dev, "disable-over-current");
}
static void dwc2_set_x2000_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->otg_caps.hnp_support = false;
p->speed = DWC2_SPEED_PARAM_HIGH;
p->host_rx_fifo_size = 1024;
p->host_nperio_tx_fifo_size = 1024;
p->host_perio_tx_fifo_size = 1024;
p->host_channels = 16;
p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
p->phy_utmi_width = 16;
p->activate_ingenic_overcurrent_detection =
!device_property_read_bool(hsotg->dev, "disable-over-current");
}
static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
@ -221,7 +262,14 @@ static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg)
const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params },
{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params },
{ .compatible = "ingenic,jz4775-otg", .data = dwc2_set_jz4775_params },
{ .compatible = "ingenic,jz4780-otg", .data = dwc2_set_jz4775_params },
{ .compatible = "ingenic,x1000-otg", .data = dwc2_set_jz4775_params },
{ .compatible = "ingenic,x1600-otg", .data = dwc2_set_x1600_params },
{ .compatible = "ingenic,x1700-otg", .data = dwc2_set_x1600_params },
{ .compatible = "ingenic,x1830-otg", .data = dwc2_set_x1600_params },
{ .compatible = "ingenic,x2000-otg", .data = dwc2_set_x2000_params },
{ .compatible = "rockchip,rk3066-usb", .data = dwc2_set_rk_params },
{ .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params },
{ .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params },

View File

@ -159,4 +159,13 @@ config USB_DWC3_XILINX
This driver handles both ZynqMP and Versal SoC operations.
Say 'Y' or 'M' if you have one such device.
config USB_DWC3_AM62
tristate "Texas Instruments AM62 Platforms"
depends on ARCH_K3 || COMPILE_TEST
default USB_DWC3
help
Support TI's AM62 platforms with DesignWare Core USB3 IP.
The Designware Core USB3 IP is progammed to operate in
in USB 2.0 mode only.
Say 'Y' or 'M' here if you have one such device
endif

View File

@ -42,6 +42,7 @@ endif
# and allyesconfig builds.
##
obj-$(CONFIG_USB_DWC3_AM62) += dwc3-am62.o
obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o
obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o
obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.o

View File

@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/acpi.h>
#include <linux/pinctrl/consumer.h>
#include <linux/reset.h>
@ -85,7 +86,7 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
* mode. If the controller supports DRD but the dr_mode is not
* specified or set to OTG, then set the mode to peripheral.
*/
if (mode == USB_DR_MODE_OTG &&
if (mode == USB_DR_MODE_OTG && !dwc->edev &&
(!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) ||
!device_property_read_bool(dwc->dev, "usb-role-switch")) &&
!DWC3_VER_IS_PRIOR(DWC3, 330A))
@ -297,6 +298,7 @@ int dwc3_core_soft_reset(struct dwc3 *dwc)
udelay(1);
} while (--retries);
dev_warn(dwc->dev, "DWC3 controller soft reset failed.\n");
return -ETIMEDOUT;
done:
@ -342,7 +344,6 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
* from the default, this will set clock period in DWC3_GUCTL
* register.
* @dwc: Pointer to our controller context structure
* @ref_clk_per: reference clock period in ns
*/
static void dwc3_ref_clk_period(struct dwc3 *dwc)
{
@ -964,10 +965,8 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
return;
vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL);
if (!vals) {
dev_err(dev, "Error to get memory\n");
if (!vals)
return;
}
/* Get INCR burst type, and parse it */
ret = device_property_read_u32_array(dev,
@ -1268,40 +1267,36 @@ static int dwc3_core_get_phy(struct dwc3 *dwc)
if (IS_ERR(dwc->usb2_phy)) {
ret = PTR_ERR(dwc->usb2_phy);
if (ret == -ENXIO || ret == -ENODEV) {
if (ret == -ENXIO || ret == -ENODEV)
dwc->usb2_phy = NULL;
} else {
else
return dev_err_probe(dev, ret, "no usb2 phy configured\n");
}
}
if (IS_ERR(dwc->usb3_phy)) {
ret = PTR_ERR(dwc->usb3_phy);
if (ret == -ENXIO || ret == -ENODEV) {
if (ret == -ENXIO || ret == -ENODEV)
dwc->usb3_phy = NULL;
} else {
else
return dev_err_probe(dev, ret, "no usb3 phy configured\n");
}
}
dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
if (IS_ERR(dwc->usb2_generic_phy)) {
ret = PTR_ERR(dwc->usb2_generic_phy);
if (ret == -ENOSYS || ret == -ENODEV) {
if (ret == -ENOSYS || ret == -ENODEV)
dwc->usb2_generic_phy = NULL;
} else {
else
return dev_err_probe(dev, ret, "no usb2 phy configured\n");
}
}
dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
if (IS_ERR(dwc->usb3_generic_phy)) {
ret = PTR_ERR(dwc->usb3_generic_phy);
if (ret == -ENOSYS || ret == -ENODEV) {
if (ret == -ENOSYS || ret == -ENODEV)
dwc->usb3_generic_phy = NULL;
} else {
else
return dev_err_probe(dev, ret, "no usb3 phy configured\n");
}
}
return 0;
@ -1633,6 +1628,51 @@ static void dwc3_check_params(struct dwc3 *dwc)
}
}
static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
{
struct device *dev = dwc->dev;
struct device_node *np_phy;
struct extcon_dev *edev = NULL;
const char *name;
if (device_property_read_bool(dev, "extcon"))
return extcon_get_edev_by_phandle(dev, 0);
/*
* Device tree platforms should get extcon via phandle.
* On ACPI platforms, we get the name from a device property.
* This device property is for kernel internal use only and
* is expected to be set by the glue code.
*/
if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
edev = extcon_get_extcon_dev(name);
if (!edev)
return ERR_PTR(-EPROBE_DEFER);
return edev;
}
/*
* Try to get an extcon device from the USB PHY controller's "port"
* node. Check if it has the "port" node first, to avoid printing the
* error message from underlying code, as it's a valid case: extcon
* device (and "port" node) may be missing in case of "usb-role-switch"
* or OTG mode.
*/
np_phy = of_parse_phandle(dev->of_node, "phys", 0);
if (of_graph_is_present(np_phy)) {
struct device_node *np_conn;
np_conn = of_graph_get_remote_node(np_phy, -1, -1);
if (np_conn)
edev = extcon_find_edev_by_node(np_conn);
of_node_put(np_conn);
}
of_node_put(np_phy);
return edev;
}
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -1768,6 +1808,13 @@ static int dwc3_probe(struct platform_device *pdev)
goto err2;
}
dwc->edev = dwc3_get_extcon(dwc);
if (IS_ERR(dwc->edev)) {
ret = PTR_ERR(dwc->edev);
dev_err_probe(dwc->dev, ret, "failed to get extcon\n");
goto err3;
}
ret = dwc3_get_dr_mode(dwc);
if (ret)
goto err3;

View File

@ -1046,6 +1046,7 @@ struct dwc3_scratchpad_array {
* @tx_thr_num_pkt_prd: periodic ESS transmit packet count
* @tx_max_burst_prd: max periodic ESS transmit burst size
* @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize
* @clear_stall_protocol: endpoint number that requires a delayed status phase
* @hsphy_interface: "utmi" or "ulpi"
* @connected: true when we're connected to a host, false otherwise
* @softconnect: true when gadget connect is called, false when disconnect runs
@ -1266,6 +1267,7 @@ struct dwc3 {
u8 tx_thr_num_pkt_prd;
u8 tx_max_burst_prd;
u8 tx_fifo_resize_max_num;
u8 clear_stall_protocol;
const char *hsphy_interface;

View File

@ -8,7 +8,6 @@
*/
#include <linux/extcon.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@ -439,51 +438,6 @@ static int dwc3_drd_notifier(struct notifier_block *nb,
return NOTIFY_DONE;
}
static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
{
struct device *dev = dwc->dev;
struct device_node *np_phy;
struct extcon_dev *edev = NULL;
const char *name;
if (device_property_read_bool(dev, "extcon"))
return extcon_get_edev_by_phandle(dev, 0);
/*
* Device tree platforms should get extcon via phandle.
* On ACPI platforms, we get the name from a device property.
* This device property is for kernel internal use only and
* is expected to be set by the glue code.
*/
if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
edev = extcon_get_extcon_dev(name);
if (!edev)
return ERR_PTR(-EPROBE_DEFER);
return edev;
}
/*
* Try to get an extcon device from the USB PHY controller's "port"
* node. Check if it has the "port" node first, to avoid printing the
* error message from underlying code, as it's a valid case: extcon
* device (and "port" node) may be missing in case of "usb-role-switch"
* or OTG mode.
*/
np_phy = of_parse_phandle(dev->of_node, "phys", 0);
if (of_graph_is_present(np_phy)) {
struct device_node *np_conn;
np_conn = of_graph_get_remote_node(np_phy, -1, -1);
if (np_conn)
edev = extcon_find_edev_by_node(np_conn);
of_node_put(np_conn);
}
of_node_put(np_phy);
return edev;
}
#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
#define ROLE_SWITCH 1
static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
@ -588,10 +542,6 @@ int dwc3_drd_init(struct dwc3 *dwc)
device_property_read_bool(dwc->dev, "usb-role-switch"))
return dwc3_setup_role_switch(dwc);
dwc->edev = dwc3_get_extcon(dwc);
if (IS_ERR(dwc->edev))
return PTR_ERR(dwc->edev);
if (dwc->edev) {
dwc->edev_nb.notifier_call = dwc3_drd_notifier;
ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,

View File

@ -0,0 +1,332 @@
// SPDX-License-Identifier: GPL-2.0
/*
* dwc3-am62.c - TI specific Glue layer for AM62 DWC3 USB Controller
*
* Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/regmap.h>
#include <linux/pinctrl/consumer.h>
/* USB WRAPPER register offsets */
#define USBSS_PID 0x0
#define USBSS_OVERCURRENT_CTRL 0x4
#define USBSS_PHY_CONFIG 0x8
#define USBSS_PHY_TEST 0xc
#define USBSS_CORE_STAT 0x14
#define USBSS_HOST_VBUS_CTRL 0x18
#define USBSS_MODE_CONTROL 0x1c
#define USBSS_WAKEUP_CONFIG 0x30
#define USBSS_WAKEUP_STAT 0x34
#define USBSS_OVERRIDE_CONFIG 0x38
#define USBSS_IRQ_MISC_STATUS_RAW 0x430
#define USBSS_IRQ_MISC_STATUS 0x434
#define USBSS_IRQ_MISC_ENABLE_SET 0x438
#define USBSS_IRQ_MISC_ENABLE_CLR 0x43c
#define USBSS_IRQ_MISC_EOI 0x440
#define USBSS_INTR_TEST 0x490
#define USBSS_VBUS_FILTER 0x614
#define USBSS_VBUS_STAT 0x618
#define USBSS_DEBUG_CFG 0x708
#define USBSS_DEBUG_DATA 0x70c
#define USBSS_HOST_HUB_CTRL 0x714
/* PHY CONFIG register bits */
#define USBSS_PHY_VBUS_SEL_MASK GENMASK(2, 1)
#define USBSS_PHY_VBUS_SEL_SHIFT 1
#define USBSS_PHY_LANE_REVERSE BIT(0)
/* MODE CONTROL register bits */
#define USBSS_MODE_VALID BIT(0)
/* WAKEUP CONFIG register bits */
#define USBSS_WAKEUP_CFG_OVERCURRENT_EN BIT(3)
#define USBSS_WAKEUP_CFG_LINESTATE_EN BIT(2)
#define USBSS_WAKEUP_CFG_SESSVALID_EN BIT(1)
#define USBSS_WAKEUP_CFG_VBUSVALID_EN BIT(0)
/* WAKEUP STAT register bits */
#define USBSS_WAKEUP_STAT_OVERCURRENT BIT(4)
#define USBSS_WAKEUP_STAT_LINESTATE BIT(3)
#define USBSS_WAKEUP_STAT_SESSVALID BIT(2)
#define USBSS_WAKEUP_STAT_VBUSVALID BIT(1)
#define USBSS_WAKEUP_STAT_CLR BIT(0)
/* IRQ_MISC_STATUS_RAW register bits */
#define USBSS_IRQ_MISC_RAW_VBUSVALID BIT(22)
#define USBSS_IRQ_MISC_RAW_SESSVALID BIT(20)
/* IRQ_MISC_STATUS register bits */
#define USBSS_IRQ_MISC_VBUSVALID BIT(22)
#define USBSS_IRQ_MISC_SESSVALID BIT(20)
/* IRQ_MISC_ENABLE_SET register bits */
#define USBSS_IRQ_MISC_ENABLE_SET_VBUSVALID BIT(22)
#define USBSS_IRQ_MISC_ENABLE_SET_SESSVALID BIT(20)
/* IRQ_MISC_ENABLE_CLR register bits */
#define USBSS_IRQ_MISC_ENABLE_CLR_VBUSVALID BIT(22)
#define USBSS_IRQ_MISC_ENABLE_CLR_SESSVALID BIT(20)
/* IRQ_MISC_EOI register bits */
#define USBSS_IRQ_MISC_EOI_VECTOR BIT(0)
/* VBUS_STAT register bits */
#define USBSS_VBUS_STAT_SESSVALID BIT(2)
#define USBSS_VBUS_STAT_VBUSVALID BIT(0)
/* Mask for PHY PLL REFCLK */
#define PHY_PLL_REFCLK_MASK GENMASK(3, 0)
#define DWC3_AM62_AUTOSUSPEND_DELAY 100
struct dwc3_data {
struct device *dev;
void __iomem *usbss;
struct clk *usb2_refclk;
int rate_code;
struct regmap *syscon;
unsigned int offset;
unsigned int vbus_divider;
};
static const int dwc3_ti_rate_table[] = { /* in KHZ */
9600,
10000,
12000,
19200,
20000,
24000,
25000,
26000,
38400,
40000,
58000,
50000,
52000,
};
static inline u32 dwc3_ti_readl(struct dwc3_data *data, u32 offset)
{
return readl((data->usbss) + offset);
}
static inline void dwc3_ti_writel(struct dwc3_data *data, u32 offset, u32 value)
{
writel(value, (data->usbss) + offset);
}
static int phy_syscon_pll_refclk(struct dwc3_data *data)
{
struct device *dev = data->dev;
struct device_node *node = dev->of_node;
struct of_phandle_args args;
struct regmap *syscon;
int ret;
syscon = syscon_regmap_lookup_by_phandle(node, "ti,syscon-phy-pll-refclk");
if (IS_ERR(syscon)) {
dev_err(dev, "unable to get ti,syscon-phy-pll-refclk regmap\n");
return PTR_ERR(syscon);
}
data->syscon = syscon;
ret = of_parse_phandle_with_fixed_args(node, "ti,syscon-phy-pll-refclk", 1,
0, &args);
if (ret)
return ret;
data->offset = args.args[0];
ret = regmap_update_bits(data->syscon, data->offset, PHY_PLL_REFCLK_MASK, data->rate_code);
if (ret) {
dev_err(dev, "failed to set phy pll reference clock rate\n");
return ret;
}
return 0;
}
static int dwc3_ti_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = pdev->dev.of_node;
struct dwc3_data *data;
int i, ret;
unsigned long rate;
u32 reg;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->dev = dev;
platform_set_drvdata(pdev, data);
data->usbss = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->usbss)) {
dev_err(dev, "can't map IOMEM resource\n");
return PTR_ERR(data->usbss);
}
data->usb2_refclk = devm_clk_get(dev, "ref");
if (IS_ERR(data->usb2_refclk)) {
dev_err(dev, "can't get usb2_refclk\n");
return PTR_ERR(data->usb2_refclk);
}
/* Calculate the rate code */
rate = clk_get_rate(data->usb2_refclk);
rate /= 1000; // To KHz
for (i = 0; i < ARRAY_SIZE(dwc3_ti_rate_table); i++) {
if (dwc3_ti_rate_table[i] == rate)
break;
}
if (i == ARRAY_SIZE(dwc3_ti_rate_table)) {
dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
ret = -EINVAL;
goto err_clk_disable;
}
data->rate_code = i;
/* Read the syscon property and set the rate code */
ret = phy_syscon_pll_refclk(data);
if (ret)
goto err_clk_disable;
/* VBUS divider select */
data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
reg = dwc3_ti_readl(data, USBSS_PHY_CONFIG);
if (data->vbus_divider)
reg |= 1 << USBSS_PHY_VBUS_SEL_SHIFT;
dwc3_ti_writel(data, USBSS_PHY_CONFIG, reg);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
/*
* Don't ignore its dependencies with its children
*/
pm_suspend_ignore_children(dev, false);
clk_prepare_enable(data->usb2_refclk);
pm_runtime_get_noresume(dev);
ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) {
dev_err(dev, "failed to create dwc3 core: %d\n", ret);
goto err_pm_disable;
}
/* Set mode valid bit to indicate role is valid */
reg = dwc3_ti_readl(data, USBSS_MODE_CONTROL);
reg |= USBSS_MODE_VALID;
dwc3_ti_writel(data, USBSS_MODE_CONTROL, reg);
/* Setting up autosuspend */
pm_runtime_set_autosuspend_delay(dev, DWC3_AM62_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(dev);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
err_pm_disable:
clk_disable_unprepare(data->usb2_refclk);
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
err_clk_disable:
clk_put(data->usb2_refclk);
return ret;
}
static int dwc3_ti_remove_core(struct device *dev, void *c)
{
struct platform_device *pdev = to_platform_device(dev);
platform_device_unregister(pdev);
return 0;
}
static int dwc3_ti_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dwc3_data *data = platform_get_drvdata(pdev);
u32 reg;
device_for_each_child(dev, NULL, dwc3_ti_remove_core);
/* Clear mode valid bit */
reg = dwc3_ti_readl(data, USBSS_MODE_CONTROL);
reg &= ~USBSS_MODE_VALID;
dwc3_ti_writel(data, USBSS_MODE_CONTROL, reg);
pm_runtime_put_sync(dev);
clk_disable_unprepare(data->usb2_refclk);
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
clk_put(data->usb2_refclk);
platform_set_drvdata(pdev, NULL);
return 0;
}
#ifdef CONFIG_PM
static int dwc3_ti_suspend_common(struct device *dev)
{
struct dwc3_data *data = dev_get_drvdata(dev);
clk_disable_unprepare(data->usb2_refclk);
return 0;
}
static int dwc3_ti_resume_common(struct device *dev)
{
struct dwc3_data *data = dev_get_drvdata(dev);
clk_prepare_enable(data->usb2_refclk);
return 0;
}
static UNIVERSAL_DEV_PM_OPS(dwc3_ti_pm_ops, dwc3_ti_suspend_common,
dwc3_ti_resume_common, NULL);
#define DEV_PM_OPS (&dwc3_ti_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif /* CONFIG_PM */
static const struct of_device_id dwc3_ti_of_match[] = {
{ .compatible = "ti,am62-usb"},
{},
};
MODULE_DEVICE_TABLE(of, dwc3_ti_of_match);
static struct platform_driver dwc3_ti_driver = {
.probe = dwc3_ti_probe,
.remove = dwc3_ti_remove,
.driver = {
.name = "dwc3-am62",
.pm = DEV_PM_OPS,
.of_match_table = dwc3_ti_of_match,
},
};
module_platform_driver(dwc3_ti_driver);
MODULE_ALIAS("platform:dwc3-am62");
MODULE_AUTHOR("Aswath Govindraju <a-govindraju@ti.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("DesignWare USB3 TI Glue Layer");

Some files were not shown because too many files have changed in this diff Show More