diff options
| author | Stephen Rothwell <sfr@canb.auug.org.au> | 2021-01-19 14:11:06 +1100 |
|---|---|---|
| committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2021-01-19 14:11:06 +1100 |
| commit | 7340e2100765f1fbfca3a83a6c45f4609bdf9e94 (patch) | |
| tree | 29a919d9953aaa3ea2e515539316395eb4323cb7 | |
| parent | 91c17f7c22cec3bd33a9fea58bd6e22616cd57c0 (diff) | |
| parent | c25c210f590e7a37eecd865d84f97d1f40e39786 (diff) | |
| download | linux-next-7340e2100765f1fbfca3a83a6c45f4609bdf9e94.tar.gz | |
Merge remote-tracking branch 'usb/usb-next'
Notice: this object is not reachable from any branch.
Notice: this object is not reachable from any branch.
82 files changed, 3122 insertions, 1616 deletions
diff --git a/Documentation/devicetree/bindings/net/btusb.txt b/Documentation/devicetree/bindings/net/btusb.txt index b1ad6ee68e909..a9c3f4277f695 100644 --- a/Documentation/devicetree/bindings/net/btusb.txt +++ b/Documentation/devicetree/bindings/net/btusb.txt @@ -4,7 +4,7 @@ Generic Bluetooth controller over USB (btusb driver) Required properties: - compatible : should comply with the format "usbVID,PID" specified in - Documentation/devicetree/bindings/usb/usb-device.txt + Documentation/devicetree/bindings/usb/usb-device.yaml At the time of writing, the only OF supported devices (more may be added later) are: diff --git a/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml b/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml index c0058332b9671..e349fa5de6061 100644 --- a/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml +++ b/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml @@ -79,7 +79,9 @@ properties: patternProperties: "^usb@[0-9a-f]+$": - type: object + oneOf: + - $ref: dwc2.yaml# + - $ref: snps,dwc3.yaml# additionalProperties: false @@ -229,6 +231,6 @@ examples: interrupts = <30>; dr_mode = "host"; snps,dis_u2_susphy_quirk; - snps,quirk-frame-length-adjustment; + snps,quirk-frame-length-adjustment = <0x20>; }; }; diff --git a/Documentation/devicetree/bindings/usb/dwc3-st.txt b/Documentation/devicetree/bindings/usb/dwc3-st.txt index df0e02e1ee43e..bf73de0d5b4af 100644 --- a/Documentation/devicetree/bindings/usb/dwc3-st.txt +++ b/Documentation/devicetree/bindings/usb/dwc3-st.txt @@ -31,13 +31,13 @@ See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt Sub-nodes: The dwc3 core should be added as subnode to ST DWC3 glue as shown in the example below. The DT binding details of dwc3 can be found in: -Documentation/devicetree/bindings/usb/dwc3.txt +Documentation/devicetree/bindings/usb/snps,dwc3.yaml NB: The dr_mode property described in [1] is NOT optional for this driver, as the default value is "otg", which isn't supported by this SoC. Valid dr_mode values for dwc3-st are either "host" or "device". -[1] Documentation/devicetree/bindings/usb/generic.txt +[1] Documentation/devicetree/bindings/usb/usb-drd.yaml Example: diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt deleted file mode 100644 index 1aae2b6160c13..0000000000000 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ /dev/null @@ -1,128 +0,0 @@ -synopsys DWC3 CORE - -DWC3- USB3 CONTROLLER. Complies to the generic USB binding properties - as described in 'usb/generic.txt' - -Required properties: - - compatible: must be "snps,dwc3" - - reg : Address and length of the register set for the device - - interrupts: Interrupts used by the dwc3 controller. - - clock-names: list of clock names. Ideally should be "ref", - "bus_early", "suspend" but may be less or more. - - clocks: list of phandle and clock specifier pairs corresponding to - entries in the clock-names property. - -Exception for clocks: - clocks are optional if the parent node (i.e. glue-layer) is compatible to - one of the following: - "cavium,octeon-7130-usb-uctl" - "qcom,dwc3" - "samsung,exynos5250-dwusb3" - "samsung,exynos5433-dwusb3" - "samsung,exynos7-dwusb3" - "sprd,sc9860-dwc3" - "st,stih407-dwc3" - "ti,am437x-dwc3" - "ti,dwc3" - "ti,keystone-dwc3" - "rockchip,rk3399-dwc3" - "xlnx,zynqmp-dwc3" - -Optional properties: - - usb-phy : array of phandle for the PHY device. The first element - in the array is expected to be a handle to the USB2/HS PHY and - the second element is expected to be a handle to the USB3/SS PHY - - phys: from the *Generic PHY* bindings - - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy" - or "usb3-phy". - - resets: set of phandle and reset specifier pairs - - snps,usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM - - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable - - snps,dis-start-transfer-quirk: when set, disable isoc START TRANSFER command - failure SW work-around for DWC_usb31 version 1.70a-ea06 - and prior. - - snps,disable_scramble_quirk: true when SW should disable data scrambling. - Only really useful for FPGA builds. - - snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled - - snps,lpm-nyet-threshold: LPM NYET threshold - - snps,u2exit_lfps_quirk: set if we want to enable u2exit lfps quirk - - snps,u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk - - snps,req_p1p2p3_quirk: when set, the core will always request for - P1/P2/P3 transition sequence. - - snps,del_p1p2p3_quirk: when set core will delay P1/P2/P3 until a certain - amount of 8B10B errors occur. - - snps,del_phy_power_chg_quirk: when set core will delay PHY power change - from P0 to P1/P2/P3. - - snps,lfps_filter_quirk: when set core will filter LFPS reception. - - snps,rx_detect_poll_quirk: when set core will disable a 400us delay to start - Polling LFPS after RX.Detect. - - snps,tx_de_emphasis_quirk: when set core will set Tx de-emphasis value. - - snps,tx_de_emphasis: the value driven to the PHY is controlled by the - LTSSM during USB3 Compliance mode. - - snps,dis_u3_susphy_quirk: when set core will disable USB3 suspend phy. - - snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy. - - snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG, - disabling the suspend signal to the PHY. - - snps,dis-u1-entry-quirk: set if link entering into U1 needs to be disabled. - - snps,dis-u2-entry-quirk: set if link entering into U2 needs to be disabled. - - snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection - in PHY P3 power state. - - snps,dis-u2-freeclk-exists-quirk: when set, clear the u2_freeclk_exists - in GUSB2PHYCFG, specify that USB2 PHY doesn't provide - a free-running PHY clock. - - snps,dis-del-phy-power-chg-quirk: when set core will change PHY power - from P0 to P1/P2/P3 without delay. - - snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check - during HS transmit. - - snps,parkmode-disable-ss-quirk: when set, all SuperSpeed bus instances in - park mode are disabled. - - snps,dis_metastability_quirk: when set, disable metastability workaround. - CAUTION: use only if you are absolutely sure of it. - - snps,dis-split-quirk: when set, change the way URBs are handled by the - driver. Needed to avoid -EPROTO errors with usbhid - on some devices (Hikey 970). - - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal - utmi_l1_suspend_n, false when asserts utmi_sleep_n - - snps,hird-threshold: HIRD threshold - - snps,hsphy_interface: High-Speed PHY interface selection between "utmi" for - UTMI+ and "ulpi" for ULPI when the DWC_USB3_HSPHY_INTERFACE has value 3. - - snps,quirk-frame-length-adjustment: Value for GFLADJ_30MHZ field of GFLADJ - register for post-silicon frame length adjustment when the - fladj_30mhz_sdbnd signal is invalid or incorrect. - - snps,rx-thr-num-pkt-prd: periodic ESS RX packet threshold count - host mode - only. Set this and rx-max-burst-prd to a valid, - non-zero value 1-16 (DWC_usb31 programming guide - section 1.2.4) to enable periodic ESS RX threshold. - - snps,rx-max-burst-prd: max periodic ESS RX burst size - host mode only. Set - this and rx-thr-num-pkt-prd to a valid, non-zero value - 1-16 (DWC_usb31 programming guide section 1.2.4) to - enable periodic ESS RX threshold. - - snps,tx-thr-num-pkt-prd: periodic ESS TX packet threshold count - host mode - only. Set this and tx-max-burst-prd to a valid, - non-zero value 1-16 (DWC_usb31 programming guide - section 1.2.3) to enable periodic ESS TX threshold. - - snps,tx-max-burst-prd: max periodic ESS TX burst size - host mode only. Set - this and tx-thr-num-pkt-prd to a valid, non-zero value - 1-16 (DWC_usb31 programming guide section 1.2.3) to - enable periodic ESS TX threshold. - - - <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated. - - snps,incr-burst-type-adjustment: Value for INCR burst type of GSBUSCFG0 - register, undefined length INCR burst type enable and INCRx type. - When just one value, which means INCRX burst mode enabled. When - more than one value, which means undefined length INCR burst type - enabled. The values can be 1, 4, 8, 16, 32, 64, 128 and 256. - - - in addition all properties from usb-xhci.txt from the current directory are - supported as well - - -This is usually a subnode to DWC3 glue to which it is connected. - -dwc3@4a030000 { - compatible = "snps,dwc3"; - reg = <0x4a030000 0xcfff>; - interrupts = <0 92 4> - usb-phy = <&usb2_phy>, <&usb3,phy>; - snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; -}; diff --git a/Documentation/devicetree/bindings/usb/exynos-usb.txt b/Documentation/devicetree/bindings/usb/exynos-usb.txt index 6aae1544f2405..f7ae79825d7d3 100644 --- a/Documentation/devicetree/bindings/usb/exynos-usb.txt +++ b/Documentation/devicetree/bindings/usb/exynos-usb.txt @@ -93,7 +93,7 @@ Sub-nodes: The dwc3 core should be added as subnode to Exynos dwc3 glue. - dwc3 : The binding details of dwc3 can be found in: - Documentation/devicetree/bindings/usb/dwc3.txt + Documentation/devicetree/bindings/usb/snps,dwc3.yaml Example: usb@12000000 { diff --git a/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml b/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml new file mode 100644 index 0000000000000..cb4c6f6d3a33a --- /dev/null +++ b/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2020 NXP +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/fsl,imx8mp-dwc3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP iMX8MP Soc USB Controller + +maintainers: + - Li Jun <jun.li@nxp.com> + +properties: + compatible: + const: fsl,imx8mp-dwc3 + + reg: + maxItems: 1 + description: Address and length of the register set for the wrapper of + dwc3 core on the SOC. + + "#address-cells": + enum: [ 1, 2 ] + + "#size-cells": + enum: [ 1, 2 ] + + dma-ranges: + description: + See section 2.3.9 of the DeviceTree Specification. + + ranges: true + + interrupts: + maxItems: 1 + description: The interrupt that is asserted when a wakeup event is + received. + + clocks: + description: + A list of phandle and clock-specifier pairs for the clocks + listed in clock-names. + items: + - description: system hsio root clock. + - description: suspend clock, used for usb wakeup logic. + + clock-names: + items: + - const: hsio + - const: suspend + +# Required child node: + +patternProperties: + "^dwc3@[0-9a-f]+$": + type: object + description: + A child node must exist to represent the core DWC3 IP block + The content of the node is defined in dwc3.txt. + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - dma-ranges + - ranges + - clocks + - clock-names + - interrupts + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/imx8mp-clock.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + usb3_0: usb@32f10100 { + compatible = "fsl,imx8mp-dwc3"; + reg = <0x32f10100 0x8>; + clocks = <&clk IMX8MP_CLK_HSIO_ROOT>, + <&clk IMX8MP_CLK_USB_ROOT>; + clock-names = "hsio", "suspend"; + interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <1>; + dma-ranges = <0x40000000 0x40000000 0xc0000000>; + ranges; + + dwc3@38100000 { + compatible = "snps,dwc3"; + reg = <0x38100000 0x10000>; + clocks = <&clk IMX8MP_CLK_HSIO_AXI>, + <&clk IMX8MP_CLK_USB_CORE_REF>, + <&clk IMX8MP_CLK_USB_ROOT>; + clock-names = "bus_early", "ref", "suspend"; + assigned-clocks = <&clk IMX8MP_CLK_HSIO_AXI>; + assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_500M>; + assigned-clock-rates = <500000000>; + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; + phys = <&usb3_phy0>, <&usb3_phy0>; + phy-names = "usb2-phy", "usb3-phy"; + snps,dis-u2-freeclk-exists-quirk; + }; + }; diff --git a/Documentation/devicetree/bindings/usb/generic-xhci.yaml b/Documentation/devicetree/bindings/usb/generic-xhci.yaml new file mode 100644 index 0000000000000..23d73df96ea3a --- /dev/null +++ b/Documentation/devicetree/bindings/usb/generic-xhci.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/generic-xhci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: USB xHCI Controller Device Tree Bindings + +maintainers: + - Mathias Nyman <mathias.nyman@intel.com> + +allOf: + - $ref: "usb-xhci.yaml#" + +properties: + compatible: + oneOf: + - description: Generic xHCI device + const: generic-xhci + - description: Armada 37xx/375/38x/8k SoCs + items: + - enum: + - marvell,armada3700-xhci + - marvell,armada-375-xhci + - marvell,armada-380-xhci + - marvell,armada-8k-xhci + - const: generic-xhci + - description: Broadcom STB SoCs with xHCI + enum: + - brcm,xhci-brcm-v2 + - brcm,bcm7445-xhci + - description: Generic xHCI device + const: xhci-platform + deprecated: true + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + items: + - const: core + - const: reg + +unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + +examples: + - | + usb@f0931000 { + compatible = "generic-xhci"; + reg = <0xf0931000 0x8c8>; + interrupts = <0x0 0x4e 0x0>; + }; diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt deleted file mode 100644 index ba472e7aefc9d..0000000000000 --- a/Documentation/devicetree/bindings/usb/generic.txt +++ /dev/null @@ -1,57 +0,0 @@ -Generic USB Properties - -Optional properties: - - maximum-speed: tells USB controllers we want to work up to a certain - speed. Valid arguments are "super-speed-plus", - "super-speed", "high-speed", "full-speed" and - "low-speed". In case this isn't passed via DT, USB - controllers should default to their maximum HW - capability. - - dr_mode: tells Dual-Role USB controllers that we want to work on a - particular mode. Valid arguments are "host", - "peripheral" and "otg". In case this attribute isn't - passed via DT, USB DRD controllers should default to - OTG. - - phy_type: tells USB controllers that we want to configure the core to support - a UTMI+ PHY with an 8- or 16-bit interface if UTMI+ is - selected. Valid arguments are "utmi" and "utmi_wide". - In case this isn't passed via DT, USB controllers should - default to HW capability. - - otg-rev: tells usb driver the release number of the OTG and EH supplement - with which the device and its descriptors are compliant, - in binary-coded decimal (i.e. 2.0 is 0200H). This - property is used if any real OTG features(HNP/SRP/ADP) - is enabled, if ADP is required, otg-rev should be - 0x0200 or above. - - companion: phandle of a companion - - hnp-disable: tells OTG controllers we want to disable OTG HNP, normally HNP - is the basic function of real OTG except you want it - to be a srp-capable only B device. - - srp-disable: tells OTG controllers we want to disable OTG SRP, SRP is - optional for OTG device. - - adp-disable: tells OTG controllers we want to disable OTG ADP, ADP is - optional for OTG device. - - usb-role-switch: boolean, indicates that the device is capable of assigning - the USB data role (USB host or USB device) for a given - USB connector, such as Type-C, Type-B(micro). - see connector/usb-connector.yaml. - - role-switch-default-mode: indicating if usb-role-switch is enabled, the - device default operation mode of controller while usb - role is USB_ROLE_NONE. Valid arguments are "host" and - "peripheral". Defaults to "peripheral" if not - specified. - - -This is an attribute to a USB controller such as: - -dwc3@4a030000 { - compatible = "synopsys,dwc3"; - reg = <0x4a030000 0xcfff>; - interrupts = <0 92 4> - usb-phy = <&usb2_phy>, <&usb3,phy>; - maximum-speed = "super-speed"; - dr_mode = "otg"; - phy_type = "utmi_wide"; - otg-rev = <0x0200>; - adp-disable; -}; diff --git a/Documentation/devicetree/bindings/usb/intel,keembay-dwc3.yaml b/Documentation/devicetree/bindings/usb/intel,keembay-dwc3.yaml index dd32c10ce6c72..43b91ab62004b 100644 --- a/Documentation/devicetree/bindings/usb/intel,keembay-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/intel,keembay-dwc3.yaml @@ -34,11 +34,8 @@ properties: # Required child node: patternProperties: - "^dwc3@[0-9a-f]+$": - type: object - description: - A child node must exist to represent the core DWC3 IP block. - The content of the node is defined in dwc3.txt. + "^usb@[0-9a-f]+$": + $ref: snps,dwc3.yaml# required: - compatible @@ -68,7 +65,7 @@ examples: #address-cells = <1>; #size-cells = <1>; - dwc3@34000000 { + usb@34000000 { compatible = "snps,dwc3"; reg = <0x34000000 0x10000>; interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt deleted file mode 100644 index 42d8814f903a9..0000000000000 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt +++ /dev/null @@ -1,121 +0,0 @@ -MT8173 xHCI - -The device node for Mediatek SOC USB3.0 host controller - -There are two scenarios: the first one only supports xHCI driver; -the second one supports dual-role mode, and the host is based on xHCI -driver. Take account of backward compatibility, we divide bindings -into two parts. - -1st: only supports xHCI driver ------------------------------------------------------------------------- - -Required properties: - - compatible : should be "mediatek,<soc-model>-xhci", "mediatek,mtk-xhci", - soc-model is the name of SoC, such as mt8173, mt2712 etc, when using - "mediatek,mtk-xhci" compatible string, you need SoC specific ones in - addition, one of: - - "mediatek,mt8173-xhci" - - reg : specifies physical base address and size of the registers - - reg-names: should be "mac" for xHCI MAC and "ippc" for IP port control - - interrupts : interrupt used by the controller - - power-domains : a phandle to USB power domain node to control USB's - mtcmos - - vusb33-supply : regulator of USB avdd3.3v - - - clocks : a list of phandle + clock-specifier pairs, one for each - entry in clock-names - - clock-names : must contain - "sys_ck": controller clock used by normal mode, - the following ones are optional: - "ref_ck": reference clock used by low power mode etc, - "mcu_ck": mcu_bus clock for register access, - "dma_ck": dma_bus clock for data transfer by DMA, - "xhci_ck": controller clock - - - phys : see usb-hcd.yaml in the current directory - -Optional properties: - - wakeup-source : enable USB remote wakeup; - - mediatek,syscon-wakeup : phandle to syscon used to access the register - of the USB wakeup glue layer between xHCI and SPM; it depends on - "wakeup-source", and has two arguments: - - the first one : register base address of the glue layer in syscon; - - the second one : hardware version of the glue layer - - 1 : used by mt8173 etc - - 2 : used by mt2712 etc - - mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0, - bit1 for u3port1, ... etc; - - vbus-supply : reference to the VBUS regulator; - - usb3-lpm-capable : supports USB3.0 LPM - - pinctrl-names : a pinctrl state named "default" must be defined - - pinctrl-0 : pin control group - See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt - - imod-interval-ns: default interrupt moderation interval is 5000ns - -additionally the properties from usb-hcd.yaml (in the current directory) are -supported. - -Example: -usb30: usb@11270000 { - compatible = "mediatek,mt8173-xhci"; - reg = <0 0x11270000 0 0x1000>, - <0 0x11280700 0 0x0100>; - reg-names = "mac", "ippc"; - interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; - power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; - clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>, - <&pericfg CLK_PERI_USB0>, - <&pericfg CLK_PERI_USB1>; - clock-names = "sys_ck", "ref_ck"; - phys = <&phy_port0 PHY_TYPE_USB3>, - <&phy_port1 PHY_TYPE_USB2>; - vusb33-supply = <&mt6397_vusb_reg>; - vbus-supply = <&usb_p1_vbus>; - usb3-lpm-capable; - mediatek,syscon-wakeup = <&pericfg 0x400 1>; - wakeup-source; - imod-interval-ns = <10000>; -}; - -2nd: dual-role mode with xHCI driver ------------------------------------------------------------------------- - -In the case, xhci is added as subnode to mtu3. An example and the DT binding -details of mtu3 can be found in: -Documentation/devicetree/bindings/usb/mediatek,mtu3.txt - -Required properties: - - compatible : should be "mediatek,<soc-model>-xhci", "mediatek,mtk-xhci", - soc-model is the name of SoC, such as mt8173, mt2712 etc, when using - "mediatek,mtk-xhci" compatible string, you need SoC specific ones in - addition, one of: - - "mediatek,mt8173-xhci" - - reg : specifies physical base address and size of the registers - - reg-names: should be "mac" for xHCI MAC - - interrupts : interrupt used by the host controller - - power-domains : a phandle to USB power domain node to control USB's - mtcmos - - vusb33-supply : regulator of USB avdd3.3v - - - clocks : a list of phandle + clock-specifier pairs, one for each - entry in clock-names - - clock-names : must contain "sys_ck", and the following ones are optional: - "ref_ck", "mcu_ck" and "dma_ck", "xhci_ck" - -Optional properties: - - vbus-supply : reference to the VBUS regulator; - - usb3-lpm-capable : supports USB3.0 LPM - -Example: -usb30: usb@11270000 { - compatible = "mediatek,mt8173-xhci"; - reg = <0 0x11270000 0 0x1000>; - reg-names = "mac"; - interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; - power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; - clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>; - clock-names = "sys_ck", "ref_ck"; - vusb33-supply = <&mt6397_vusb_reg>; - usb3-lpm-capable; -}; diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml new file mode 100644 index 0000000000000..38b1fe18aa790 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -0,0 +1,178 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2020 MediaTek +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/mediatek,mtk-xhci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek USB3 xHCI Device Tree Bindings + +maintainers: + - Chunfeng Yun <chunfeng.yun@mediatek.com> + +allOf: + - $ref: "usb-xhci.yaml" + +description: | + There are two scenarios: + case 1: only supports xHCI driver; + case 2: supports dual-role mode, and the host is based on xHCI driver. + +properties: + # common properties for both case 1 and case 2 + compatible: + items: + - enum: + - mediatek,mt2712-xhci + - mediatek,mt7622-xhci + - mediatek,mt7629-xhci + - mediatek,mt8173-xhci + - mediatek,mt8183-xhci + - const: mediatek,mtk-xhci + + reg: + minItems: 1 + items: + - description: the registers of xHCI MAC + - description: the registers of IP Port Control + + reg-names: + minItems: 1 + items: + - const: mac + - const: ippc # optional, only needed for case 1. + + interrupts: + maxItems: 1 + + power-domains: + description: A phandle to USB power domain node to control USB's MTCMOS + maxItems: 1 + + clocks: + minItems: 1 + items: + - description: Controller clock used by normal mode + - description: Reference clock used by low power mode etc + - description: Mcu bus clock for register access + - description: DMA bus clock for data transfer + - description: controller clock + + clock-names: + minItems: 1 + items: + - const: sys_ck # required, the following ones are optional + - const: ref_ck + - const: mcu_ck + - const: dma_ck + - const: xhci_ck + + phys: + description: + List of all PHYs used on this HCD, it's better to keep PHYs in order + as the hardware layout + minItems: 1 + items: + - description: USB2/HS PHY # required, others are optional + - description: USB3/SS(P) PHY + - description: USB2/HS PHY + - description: USB3/SS(P) PHY + - description: USB2/HS PHY + - description: USB3/SS(P) PHY + - description: USB2/HS PHY + - description: USB3/SS(P) PHY + - description: USB2/HS PHY + + vusb33-supply: + description: Regulator of USB AVDD3.3v + + vbus-supply: + description: Regulator of USB VBUS5v + + usb3-lpm-capable: + description: supports USB3.0 LPM + type: boolean + + imod-interval-ns: + description: + Interrupt moderation interval value, it is 8 times as much as that + defined in the xHCI spec on MTK's controller. + default: 5000 + + # the following properties are only used for case 1 + wakeup-source: + description: enable USB remote wakeup, see power/wakeup-source.txt + type: boolean + + mediatek,syscon-wakeup: + $ref: /schemas/types.yaml#/definitions/phandle-array + maxItems: 1 + description: + A phandle to syscon used to access the register of the USB wakeup glue + layer between xHCI and SPM, the field should always be 3 cells long. + items: + items: + - description: + The first cell represents a phandle to syscon + - description: + The second cell represents the register base address of the glue + layer in syscon + - description: + The third cell represents the hardware version of the glue layer, + 1 is used by mt8173 etc, 2 is used by mt2712 etc + enum: [1, 2] + + mediatek,u3p-dis-msk: + $ref: /schemas/types.yaml#/definitions/uint32 + description: The mask to disable u3ports, bit0 for u3port0, + bit1 for u3port1, ... etc + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "@[0-9a-f]{1}$": + type: object + description: The hard wired USB devices. + +dependencies: + wakeup-source: [ 'mediatek,syscon-wakeup' ] + +required: + - compatible + - reg + - reg-names + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/mt8173-clk.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/phy/phy.h> + #include <dt-bindings/power/mt8173-power.h> + + usb@11270000 { + compatible = "mediatek,mt8173-xhci", "mediatek,mtk-xhci"; + reg = <0x11270000 0x1000>, <0x11280700 0x0100>; + reg-names = "mac", "ippc"; + interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; + clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>; + clock-names = "sys_ck", "ref_ck"; + phys = <&u3port0 PHY_TYPE_USB3>, <&u2port1 PHY_TYPE_USB2>; + vusb33-supply = <&mt6397_vusb_reg>; + vbus-supply = <&usb_p1_vbus>; + imod-interval-ns = <10000>; + mediatek,syscon-wakeup = <&pericfg 0x400 1>; + wakeup-source; + usb3-lpm-capable; + }; +... diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt deleted file mode 100644 index a82ca438aec1f..0000000000000 --- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt +++ /dev/null @@ -1,108 +0,0 @@ -The device node for Mediatek USB3.0 DRD controller - -Required properties: - - compatible : should be "mediatek,<soc-model>-mtu3", "mediatek,mtu3", - soc-model is the name of SoC, such as mt8173, mt2712 etc, - when using "mediatek,mtu3" compatible string, you need SoC specific - ones in addition, one of: - - "mediatek,mt8173-mtu3" - - reg : specifies physical base address and size of the registers - - reg-names: should be "mac" for device IP and "ippc" for IP port control - - interrupts : interrupt used by the device IP - - power-domains : a phandle to USB power domain node to control USB's - mtcmos - - vusb33-supply : regulator of USB avdd3.3v - - clocks : a list of phandle + clock-specifier pairs, one for each - entry in clock-names - - clock-names : must contain "sys_ck" for clock of controller, - the following clocks are optional: - "ref_ck", "mcu_ck" and "dma_ck"; - - phys : see usb-hcd.yaml in the current directory - - dr_mode : should be one of "host", "peripheral" or "otg", - refer to usb/generic.txt - -Optional properties: - - #address-cells, #size-cells : should be '2' if the device has sub-nodes - with 'reg' property - - ranges : allows valid 1:1 translation between child's address space and - parent's address space - - extcon : external connector for vbus and idpin changes detection, needed - when supports dual-role mode. - it's considered valid for compatibility reasons, not allowed for - new bindings, and use "usb-role-switch" property instead. - - vbus-supply : reference to the VBUS regulator, needed when supports - dual-role mode. - it's considered valid for compatibility reasons, not allowed for - new bindings, and put into a usb-connector node. - see connector/usb-connector.yaml. - - pinctrl-names : a pinctrl state named "default" is optional, and need be - defined if auto drd switch is enabled, that means the property dr_mode - is set as "otg", and meanwhile the property "mediatek,enable-manual-drd" - is not set. - - pinctrl-0 : pin control group - See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt - - - maximum-speed : valid arguments are "super-speed", "high-speed" and - "full-speed"; refer to usb/generic.txt - - usb-role-switch : use USB Role Switch to support dual-role switch, but - not extcon; see usb/generic.txt. - - enable-manual-drd : supports manual dual-role switch via debugfs; usually - used when receptacle is TYPE-A and also wants to support dual-role - mode. - - wakeup-source: enable USB remote wakeup of host mode. - - mediatek,syscon-wakeup : phandle to syscon used to access the register - of the USB wakeup glue layer between SSUSB and SPM; it depends on - "wakeup-source", and has two arguments: - - the first one : register base address of the glue layer in syscon; - - the second one : hardware version of the glue layer - - 1 : used by mt8173 etc - - 2 : used by mt2712 etc - - mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0, - bit1 for u3port1, ... etc; - -additionally the properties from usb-hcd.yaml (in the current directory) are -supported. - -Sub-nodes: -The xhci should be added as subnode to mtu3 as shown in the following example -if host mode is enabled. The DT binding details of xhci can be found in: -Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt - -The port would be added as subnode if use "usb-role-switch" property. - see graph.txt - -Example: -ssusb: usb@11271000 { - compatible = "mediatek,mt8173-mtu3"; - reg = <0 0x11271000 0 0x3000>, - <0 0x11280700 0 0x0100>; - reg-names = "mac", "ippc"; - interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>; - phys = <&phy_port0 PHY_TYPE_USB3>, - <&phy_port1 PHY_TYPE_USB2>; - power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; - clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>, - <&pericfg CLK_PERI_USB0>, - <&pericfg CLK_PERI_USB1>; - clock-names = "sys_ck", "ref_ck"; - vusb33-supply = <&mt6397_vusb_reg>; - vbus-supply = <&usb_p0_vbus>; - extcon = <&extcon_usb>; - dr_mode = "otg"; - wakeup-source; - mediatek,syscon-wakeup = <&pericfg 0x400 1>; - #address-cells = <2>; - #size-cells = <2>; - ranges; - - usb_host: xhci@11270000 { - compatible = "mediatek,mt8173-xhci"; - reg = <0 0x11270000 0 0x1000>; - reg-names = "mac"; - interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; - power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; - clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>; - clock-names = "sys_ck", "ref_ck"; - vusb33-supply = <&mt6397_vusb_reg>; - }; -}; diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml new file mode 100644 index 0000000000000..f5c04b9d2de96 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml @@ -0,0 +1,287 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2020 MediaTek +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/mediatek,mtu3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek USB3 DRD Controller Device Tree Bindings + +maintainers: + - Chunfeng Yun <chunfeng.yun@mediatek.com> + +allOf: + - $ref: "usb-drd.yaml" + +description: | + The DRD controller has a glue layer IPPC (IP Port Control), and its host is + based on xHCI. + +properties: + compatible: + items: + - enum: + - mediatek,mt2712-mtu3 + - mediatek,mt8173-mtu3 + - mediatek,mt8183-mtu3 + - const: mediatek,mtu3 + + reg: + items: + - description: the registers of device MAC + - description: the registers of IP Port Control + + reg-names: + items: + - const: mac + - const: ippc + + interrupts: + maxItems: 1 + + power-domains: + description: A phandle to USB power domain node to control USB's MTCMOS + maxItems: 1 + + clocks: + minItems: 1 + items: + - description: Controller clock used by normal mode + - description: Reference clock used by low power mode etc + - description: Mcu bus clock for register access + - description: DMA bus clock for data transfer + + clock-names: + minItems: 1 + items: + - const: sys_ck # required, others are optional + - const: ref_ck + - const: mcu_ck + - const: dma_ck + + phys: + description: + List of all the USB PHYs used, it's better to keep the sequence + as the hardware layout. + minItems: 1 + items: + - description: USB2/HS PHY # required, others are optional + - description: USB3/SS(P) PHY + - description: USB2/HS PHY # the following for backward compatible + - description: USB3/SS(P) PHY + - description: USB2/HS PHY + - description: USB3/SS(P) PHY + - description: USB2/HS PHY + - description: USB3/SS(P) PHY + - description: USB2/HS PHY + + vusb33-supply: + description: Regulator of USB AVDD3.3v + + vbus-supply: + deprecated: true + description: | + Regulator of USB VBUS5v, needed when supports dual-role mode. + Particularly, if use an output GPIO to control a VBUS regulator, should + model it as a regulator. See bindings/regulator/fixed-regulator.yaml + It's considered valid for compatibility reasons, not allowed for + new bindings, and put into a usb-connector node. + + dr_mode: + enum: [host, peripheral, otg] + default: otg + + maximum-speed: + enum: [super-speed-plus, super-speed, high-speed, full-speed] + + "#address-cells": + enum: [1, 2] + + "#size-cells": + enum: [1, 2] + + ranges: true + + extcon: + deprecated: true + description: | + Phandle to the extcon device detecting the IDDIG/VBUS state, neede + when supports dual-role mode. + It's considered valid for compatibility reasons, not allowed for + new bindings, and use "usb-role-switch" property instead. + + usb-role-switch: + $ref: /schemas/types.yaml#/definitions/flag + description: Support role switch. + type: boolean + + connector: + $ref: /connector/usb-connector.yaml# + description: + Connector for dual role switch, especially for "gpio-usb-b-connector" + type: object + + port: + description: + Any connector to the data bus of this controller should be modelled + using the OF graph bindings specified, if the "usb-role-switch" + property is used. See graph.txt + type: object + + enable-manual-drd: + $ref: /schemas/types.yaml#/definitions/flag + description: + supports manual dual-role switch via debugfs; usually used when + receptacle is TYPE-A and also wants to support dual-role mode. + type: boolean + + wakeup-source: + description: enable USB remote wakeup, see power/wakeup-source.txt + type: boolean + + mediatek,syscon-wakeup: + $ref: /schemas/types.yaml#/definitions/phandle-array + maxItems: 1 + description: + A phandle to syscon used to access the register of the USB wakeup glue + layer between xHCI and SPM, the field should always be 3 cells long. + items: + items: + - description: + The first cell represents a phandle to syscon + - description: + The second cell represents the register base address of the glue + layer in syscon + - description: + The third cell represents the hardware version of the glue layer, + 1 is used by mt8173 etc, 2 is used by mt2712 etc + enum: [1, 2] + + mediatek,u3p-dis-msk: + $ref: /schemas/types.yaml#/definitions/uint32 + description: The mask to disable u3ports, bit0 for u3port0, + bit1 for u3port1, ... etc + +# Required child node when support dual-role +patternProperties: + "^usb@[0-9a-f]+$": + type: object + $ref: /usb/mediatek,mtk-xhci.yaml# + description: + The xhci should be added as subnode to mtu3 as shown in the following + example if the host mode is enabled. + +dependencies: + connector: [ 'usb-role-switch' ] + port: [ 'usb-role-switch' ] + wakeup-source: [ 'mediatek,syscon-wakeup' ] + +required: + - compatible + - reg + - reg-names + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + # Dual role switch by extcon + - | + #include <dt-bindings/clock/mt8173-clk.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/phy/phy.h> + #include <dt-bindings/power/mt8173-power.h> + + usb@11271000 { + compatible = "mediatek,mt8173-mtu3", "mediatek,mtu3"; + reg = <0x11271000 0x3000>, <0x11280700 0x0100>; + reg-names = "mac", "ippc"; + interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>; + phys = <&phy_port0 PHY_TYPE_USB3>, <&phy_port1 PHY_TYPE_USB2>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; + clocks = <&topckgen CLK_TOP_USB30_SEL>; + clock-names = "sys_ck"; + vusb33-supply = <&mt6397_vusb_reg>; + vbus-supply = <&usb_p0_vbus>; + extcon = <&extcon_usb>; + dr_mode = "otg"; + wakeup-source; + mediatek,syscon-wakeup = <&pericfg 0x400 1>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + xhci: usb@11270000 { + compatible = "mediatek,mt8173-xhci", "mediatek,mtk-xhci"; + reg = <0x11270000 0x1000>; + reg-names = "mac"; + interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; + clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>; + clock-names = "sys_ck", "ref_ck"; + vusb33-supply = <&mt6397_vusb_reg>; + }; + }; + + # Enable/disable device by an input gpio for VBUS pin + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/power/mt2712-power.h> + + usb@112c1000 { + compatible = "mediatek,mt2712-mtu3", "mediatek,mtu3"; + reg = <0x112c1000 0x3000>, <0x112d0700 0x0100>; + reg-names = "mac", "ippc"; + interrupts = <GIC_SPI 248 IRQ_TYPE_LEVEL_LOW>; + phys = <&u2port2 PHY_TYPE_USB2>; + power-domains = <&scpsys MT2712_POWER_DOMAIN_USB2>; + clocks = <&topckgen CLK_TOP_USB30_SEL>; + clock-names = "sys_ck"; + dr_mode = "peripheral"; + usb-role-switch; + + connector { + compatible = "gpio-usb-b-connector", "usb-b-connector"; + type = "micro"; + vbus-gpios = <&pio 13 GPIO_ACTIVE_HIGH>; + }; + }; + + # Dual role switch with type-c + - | + usb@11201000 { + compatible ="mediatek,mt8183-mtu3", "mediatek,mtu3"; + reg = <0x11201000 0x2e00>, <0x11203e00 0x0100>; + reg-names = "mac", "ippc"; + interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_LOW>; + phys = <&u2port0 PHY_TYPE_USB2>; + clocks = <&clk26m>; + clock-names = "sys_ck"; + mediatek,syscon-wakeup = <&pericfg 0x400 1>; + wakeup-source; + dr_mode = "otg"; + usb-role-switch; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + host: usb@11200000 { + compatible = "mediatek,mt8183-xhci", "mediatek,mtk-xhci"; + reg = <0x11200000 0x1000>; + reg-names = "mac"; + interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_LOW>; + clocks = <&clk26m>; + clock-names = "sys_ck"; + }; + + port { + usb_role_sw: endpoint { + remote-endpoint = <&hs_ep>; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/usb/mediatek,musb.txt b/Documentation/devicetree/bindings/usb/mediatek,musb.txt deleted file mode 100644 index 5eedb02965622..0000000000000 --- a/Documentation/devicetree/bindings/usb/mediatek,musb.txt +++ /dev/null @@ -1,57 +0,0 @@ -MediaTek musb DRD/OTG controller -------------------------------------------- - -Required properties: - - compatible : should be one of: - "mediatek,mt2701-musb" - ... - followed by "mediatek,mtk-musb" - - reg : specifies physical base address and size of - the registers - - interrupts : interrupt used by musb controller - - interrupt-names : must be "mc" - - phys : PHY specifier for the OTG phy - - dr_mode : should be one of "host", "peripheral" or "otg", - refer to usb/generic.txt - - clocks : a list of phandle + clock-specifier pairs, one for - each entry in clock-names - - clock-names : must contain "main", "mcu", "univpll" - for clocks of controller - -Optional properties: - - power-domains : a phandle to USB power domain node to control USB's - MTCMOS - -Required child nodes: - usb connector node as defined in bindings/connector/usb-connector.yaml -Optional properties: - - id-gpios : input GPIO for USB ID pin. - - vbus-gpios : input GPIO for USB VBUS pin. - - vbus-supply : reference to the VBUS regulator, needed when supports - dual-role mode - - usb-role-switch : use USB Role Switch to support dual-role switch, see - usb/generic.txt. - -Example: - -usb2: usb@11200000 { - compatible = "mediatek,mt2701-musb", - "mediatek,mtk-musb"; - reg = <0 0x11200000 0 0x1000>; - interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; - interrupt-names = "mc"; - phys = <&u2port2 PHY_TYPE_USB2>; - dr_mode = "otg"; - clocks = <&pericfg CLK_PERI_USB0>, - <&pericfg CLK_PERI_USB0_MCU>, - <&pericfg CLK_PERI_USB_SLV>; - clock-names = "main","mcu","univpll"; - power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; - usb-role-switch; - connector{ - compatible = "gpio-usb-b-connector", "usb-b-connector"; - type = "micro"; - id-gpios = <&pio 44 GPIO_ACTIVE_HIGH>; - vbus-supply = <&usb_vbus>; - }; -}; diff --git a/Documentation/devicetree/bindings/usb/mediatek,musb.yaml b/Documentation/devicetree/bindings/usb/mediatek,musb.yaml new file mode 100644 index 0000000000000..790efe8b62746 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/mediatek,musb.yaml @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2020 MediaTek +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/mediatek,musb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MUSB DRD/OTG Controller Device Tree Bindings + +maintainers: + - Min Guo <min.guo@mediatek.com> + +properties: + $nodename: + pattern: '^usb@[0-9a-f]+$' + + compatible: + items: + - enum: + - mediatek,mt2701-musb + - const: mediatek,mtk-musb + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + interrupt-names: + items: + - const: mc + + clocks: + items: + - description: The main/core clock + - description: The system bus clock + - description: The 48Mhz clock + + clock-names: + items: + - const: main + - const: mcu + - const: univpll + + phys: + maxItems: 1 + + usb-role-switch: + $ref: /schemas/types.yaml#/definitions/flag + description: Support role switch. See usb/generic.txt + type: boolean + + dr_mode: + enum: + - host + - otg + - peripheral + + power-domains: + description: A phandle to USB power domain node to control USB's MTCMOS + maxItems: 1 + + connector: + $ref: /connector/usb-connector.yaml# + description: Connector for dual role switch + type: object + +dependencies: + usb-role-switch: [ 'connector' ] + connector: [ 'usb-role-switch' ] + +required: + - compatible + - reg + - interrupts + - interrupt-names + - phys + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/mt2701-clk.h> + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/phy/phy.h> + #include <dt-bindings/power/mt2701-power.h> + + usb@11200000 { + compatible = "mediatek,mt2701-musb", "mediatek,mtk-musb"; + reg = <0x11200000 0x1000>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "mc"; + phys = <&u2port2 PHY_TYPE_USB2>; + dr_mode = "otg"; + clocks = <&pericfg CLK_PERI_USB0>, + <&pericfg CLK_PERI_USB0_MCU>, + <&pericfg CLK_PERI_USB_SLV>; + clock-names = "main","mcu","univpll"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; + usb-role-switch; + + connector { + compatible = "gpio-usb-b-connector", "usb-b-connector"; + type = "micro"; + id-gpios = <&pio 44 GPIO_ACTIVE_HIGH>; + vbus-supply = <&usb_vbus>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt index 38d9bb8507cf1..f0dbc5ae45ae8 100644 --- a/Documentation/devicetree/bindings/usb/omap-usb.txt +++ b/Documentation/devicetree/bindings/usb/omap-usb.txt @@ -65,7 +65,7 @@ Sub-nodes: The dwc3 core should be added as subnode to omap dwc3 glue. - dwc3 : The binding details of dwc3 can be found in: - Documentation/devicetree/bindings/usb/dwc3.txt + Documentation/devicetree/bindings/usb/snps,dwc3.yaml omap_dwc3 { compatible = "ti,dwc3"; diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index 2cf525d21e054..b336662e838ce 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -103,11 +103,8 @@ properties: # Required child node: patternProperties: - "^dwc3@[0-9a-f]+$": - type: object - description: - A child node must exist to represent the core DWC3 IP block - The content of the node is defined in dwc3.txt. + "^usb@[0-9a-f]+$": + $ref: snps,dwc3.yaml# required: - compatible @@ -162,7 +159,7 @@ examples: resets = <&gcc GCC_USB30_PRIM_BCR>; - dwc3@a600000 { + usb@a600000 { compatible = "snps,dwc3"; reg = <0 0x0a600000 0 0xcd00>; interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>; diff --git a/Documentation/devicetree/bindings/usb/renesas,usb-xhci.yaml b/Documentation/devicetree/bindings/usb/renesas,usb-xhci.yaml index 22603256ddf8f..4c5efaf023080 100644 --- a/Documentation/devicetree/bindings/usb/renesas,usb-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/renesas,usb-xhci.yaml @@ -11,7 +11,7 @@ maintainers: - Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> allOf: - - $ref: "usb-hcd.yaml" + - $ref: "usb-xhci.yaml" properties: compatible: @@ -68,7 +68,7 @@ required: - power-domains - resets -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml new file mode 100644 index 0000000000000..2247da77eac1b --- /dev/null +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -0,0 +1,332 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/snps,dwc3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Synopsys DesignWare USB3 Controller + +maintainers: + - Felipe Balbi <balbi@kernel.org> + +description: + This is usually a subnode to DWC3 glue to which it is connected, but can also + be presented as a standalone DT node with an optional vendor-specific + compatible string. + +allOf: + - $ref: usb-drd.yaml# + - if: + properties: + dr_mode: + const: peripheral + + required: + - dr_mode + then: + $ref: usb.yaml# + else: + $ref: usb-xhci.yaml# + +properties: + compatible: + contains: + oneOf: + - const: snps,dwc3 + - const: synopsys,dwc3 + deprecated: true + + interrupts: + description: + It's either a single common DWC3 interrupt (dwc_usb3) or individual + interrupts for the host, gadget and DRD modes. + minItems: 1 + maxItems: 3 + + interrupt-names: + minItems: 1 + maxItems: 3 + oneOf: + - const: dwc_usb3 + - items: + enum: [host, peripheral, otg] + + clocks: + description: + In general the core supports three types of clocks. bus_early is a + SoC Bus Clock (AHB/AXI/Native). ref generates ITP when the UTMI/ULPI + PHY is suspended. suspend clocks a small part of the USB3 core when + SS PHY in P3. But particular cases may differ from that having less + or more clock sources with another names. + + clock-names: + contains: + anyOf: + - enum: [bus_early, ref, suspend] + - true + + usb-phy: + minItems: 1 + items: + - description: USB2/HS PHY + - description: USB3/SS PHY + + phys: + minItems: 1 + items: + - description: USB2/HS PHY + - description: USB3/SS PHY + + phy-names: + minItems: 1 + items: + - const: usb2-phy + - const: usb3-phy + + resets: + minItems: 1 + + snps,usb2-lpm-disable: + description: Indicate if we don't want to enable USB2 HW LPM + type: boolean + + snps,usb3_lpm_capable: + description: Determines if platform is USB3 LPM capable + type: boolean + + snps,dis-start-transfer-quirk: + description: + When set, disable isoc START TRANSFER command failure SW work-around + for DWC_usb31 version 1.70a-ea06 and prior. + type: boolean + + snps,disable_scramble_quirk: + description: + True when SW should disable data scrambling. Only really useful for FPGA + builds. + type: boolean + + snps,has-lpm-erratum: + description: True when DWC3 was configured with LPM Erratum enabled + type: boolean + + snps,lpm-nyet-threshold: + description: LPM NYET threshold + $ref: /schemas/types.yaml#/definitions/uint8 + + snps,u2exit_lfps_quirk: + description: Set if we want to enable u2exit lfps quirk + type: boolean + + snps,u2ss_inp3_quirk: + description: Set if we enable P3 OK for U2/SS Inactive quirk + type: boolean + + snps,req_p1p2p3_quirk: + description: + When set, the core will always request for P1/P2/P3 transition sequence. + type: boolean + + snps,del_p1p2p3_quirk: + description: + When set core will delay P1/P2/P3 until a certain amount of 8B10B errors + occur. + type: boolean + + snps,del_phy_power_chg_quirk: + description: When set core will delay PHY power change from P0 to P1/P2/P3. + type: boolean + + snps,lfps_filter_quirk: + description: When set core will filter LFPS reception. + type: boolean + + snps,rx_detect_poll_quirk: + description: + when set core will disable a 400us delay to start Polling LFPS after + RX.Detect. + type: boolean + + snps,tx_de_emphasis_quirk: + description: When set core will set Tx de-emphasis value + type: boolean + + snps,tx_de_emphasis: + description: + The value driven to the PHY is controlled by the LTSSM during USB3 + Compliance mode. + $ref: /schemas/types.yaml#/definitions/uint8 + enum: + - 0 # -6dB de-emphasis + - 1 # -3.5dB de-emphasis + - 2 # No de-emphasis + + snps,dis_u3_susphy_quirk: + description: When set core will disable USB3 suspend phy + type: boolean + + snps,dis_u2_susphy_quirk: + description: When set core will disable USB2 suspend phy + type: boolean + + snps,dis_enblslpm_quirk: + description: + When set clears the enblslpm in GUSB2PHYCFG, disabling the suspend signal + to the PHY. + type: boolean + + snps,dis-u1-entry-quirk: + description: Set if link entering into U1 needs to be disabled + type: boolean + + snps,dis-u2-entry-quirk: + description: Set if link entering into U2 needs to be disabled + type: boolean + + snps,dis_rxdet_inp3_quirk: + description: + When set core will disable receiver detection in PHY P3 power state. + type: boolean + + snps,dis-u2-freeclk-exists-quirk: + description: + When set, clear the u2_freeclk_exists in GUSB2PHYCFG, specify that USB2 + PHY doesn't provide a free-running PHY clock. + type: boolean + + snps,dis-del-phy-power-chg-quirk: + description: + When set core will change PHY power from P0 to P1/P2/P3 without delay. + type: boolean + + snps,dis-tx-ipgap-linecheck-quirk: + description: When set, disable u2mac linestate check during HS transmit + type: boolean + + snps,parkmode-disable-ss-quirk: + description: + When set, all SuperSpeed bus instances in park mode are disabled. + type: boolean + + snps,dis_metastability_quirk: + description: + When set, disable metastability workaround. CAUTION! Use only if you are + absolutely sure of it. + type: boolean + + snps,dis-split-quirk: + description: + When set, change the way URBs are handled by the driver. Needed to + avoid -EPROTO errors with usbhid on some devices (Hikey 970). + type: boolean + + snps,is-utmi-l1-suspend: + description: + True when DWC3 asserts output signal utmi_l1_suspend_n, false when + asserts utmi_sleep_n. + type: boolean + + snps,hird-threshold: + description: HIRD threshold + $ref: /schemas/types.yaml#/definitions/uint8 + + snps,hsphy_interface: + description: + High-Speed PHY interface selection between UTMI+ and ULPI when the + DWC_USB3_HSPHY_INTERFACE has value 3. + $ref: /schemas/types.yaml#/definitions/uint8 + enum: [utmi, ulpi] + + snps,quirk-frame-length-adjustment: + description: + Value for GFLADJ_30MHZ field of GFLADJ register for post-silicon frame + length adjustment when the fladj_30mhz_sdbnd signal is invalid or + incorrect. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 0x3f + + snps,rx-thr-num-pkt-prd: + description: + Periodic ESS RX packet threshold count (host mode only). Set this and + snps,rx-max-burst-prd to a valid, non-zero value 1-16 (DWC_usb31 + programming guide section 1.2.4) to enable periodic ESS RX threshold. + $ref: /schemas/types.yaml#/definitions/uint8 + minimum: 1 + maximum: 16 + + snps,rx-max-burst-prd: + description: + Max periodic ESS RX burst size (host mode only). Set this and + snps,rx-thr-num-pkt-prd to a valid, non-zero value 1-16 (DWC_usb31 + programming guide section 1.2.4) to enable periodic ESS RX threshold. + $ref: /schemas/types.yaml#/definitions/uint8 + minimum: 1 + maximum: 16 + + snps,tx-thr-num-pkt-prd: + description: + Periodic ESS TX packet threshold count (host mode only). Set this and + snps,tx-max-burst-prd to a valid, non-zero value 1-16 (DWC_usb31 + programming guide section 1.2.3) to enable periodic ESS TX threshold. + $ref: /schemas/types.yaml#/definitions/uint8 + minimum: 1 + maximum: 16 + + snps,tx-max-burst-prd: + description: + Max periodic ESS TX burst size (host mode only). Set this and + snps,tx-thr-num-pkt-prd to a valid, non-zero value 1-16 (DWC_usb31 + programming guide section 1.2.3) to enable periodic ESS TX threshold. + $ref: /schemas/types.yaml#/definitions/uint8 + minimum: 1 + maximum: 16 + + tx-fifo-resize: + description: Determines if the FIFO *has* to be reallocated + deprecated: true + type: boolean + + snps,incr-burst-type-adjustment: + description: + Value for INCR burst type of GSBUSCFG0 register, undefined length INCR + burst type enable and INCRx type. A single value means INCRX burst mode + enabled. If more than one value specified, undefined length INCR burst + type will be enabled with burst lengths utilized up to the maximum + of the values passed in this property. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 8 + uniqueItems: true + items: + enum: [1, 4, 8, 16, 32, 64, 128, 256] + +unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + +examples: + - | + usb@4a030000 { + compatible = "snps,dwc3"; + reg = <0x4a030000 0xcfff>; + interrupts = <0 92 4>; + usb-phy = <&usb2_phy>, <&usb3_phy>; + snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; + }; + - | + usb@4a000000 { + compatible = "snps,dwc3"; + reg = <0x4a000000 0xcfff>; + interrupts = <0 92 4>; + clocks = <&clk 1>, <&clk 2>, <&clk 3>; + clock-names = "bus_early", "ref", "suspend"; + phys = <&usb2_phy>, <&usb3_phy>; + phy-names = "usb2-phy", "usb3-phy"; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + }; +... diff --git a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml index 91ef374faba81..9a068d3bc73b6 100644 --- a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml @@ -66,9 +66,7 @@ properties: patternProperties: "usb@[a-f0-9]+$": - type: object - description: This is the node representing the DWC3 controller instance - Documentation/devicetree/bindings/usb/dwc3.txt + $ref: snps,dwc3.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/usb/usb-device.txt b/Documentation/devicetree/bindings/usb/usb-device.txt deleted file mode 100644 index 036be172b1ae8..0000000000000 --- a/Documentation/devicetree/bindings/usb/usb-device.txt +++ /dev/null @@ -1,102 +0,0 @@ -Generic USB Device Properties - -Usually, we only use device tree for hard wired USB device. -The reference binding doc is from: -http://www.devicetree.org/open-firmware/bindings/usb/usb-1_0.ps - -Four types of device-tree nodes are defined: "host-controller nodes" -representing USB host controllers, "device nodes" representing USB devices, -"interface nodes" representing USB interfaces and "combined nodes" -representing simple USB devices. - -A combined node shall be used instead of a device node and an interface node -for devices of class 0 or 9 (hub) with a single configuration and a single -interface. - -A "hub node" is a combined node or an interface node that represents a USB -hub. - - -Required properties for device nodes: -- compatible: "usbVID,PID", where VID is the vendor id and PID the product id. - The textual representation of VID and PID shall be in lower case hexadecimal - with leading zeroes suppressed. The other compatible strings from the above - standard binding could also be used, but a device adhering to this binding - may leave out all except for "usbVID,PID". -- reg: the number of the USB hub port or the USB host-controller port to which - this device is attached. The range is 1-255. - - -Required properties for device nodes with interface nodes: -- #address-cells: shall be 2 -- #size-cells: shall be 0 - - -Required properties for interface nodes: -- compatible: "usbifVID,PID.configCN.IN", where VID is the vendor id, PID is - the product id, CN is the configuration value and IN is the interface - number. The textual representation of VID, PID, CN and IN shall be in lower - case hexadecimal with leading zeroes suppressed. The other compatible - strings from the above standard binding could also be used, but a device - adhering to this binding may leave out all except for - "usbifVID,PID.configCN.IN". -- reg: the interface number and configuration value - -The configuration component is not included in the textual representation of -an interface-node unit address for configuration 1. - - -Required properties for combined nodes: -- compatible: "usbVID,PID", where VID is the vendor id and PID the product id. - The textual representation of VID and PID shall be in lower case hexadecimal - with leading zeroes suppressed. The other compatible strings from the above - standard binding could also be used, but a device adhering to this binding - may leave out all except for "usbVID,PID". -- reg: the number of the USB hub port or the USB host-controller port to which - this device is attached. The range is 1-255. - - -Required properties for hub nodes with device nodes: -- #address-cells: shall be 1 -- #size-cells: shall be 0 - - -Required properties for host-controller nodes with device nodes: -- #address-cells: shall be 1 -- #size-cells: shall be 0 - - -Example: - -&usb1 { /* host controller */ - #address-cells = <1>; - #size-cells = <0>; - - hub@1 { /* hub connected to port 1 */ - compatible = "usb5e3,608"; - reg = <1>; - }; - - device@2 { /* device connected to port 2 */ - compatible = "usb123,4567"; - reg = <2>; - }; - - device@3 { /* device connected to port 3 */ - compatible = "usb123,abcd"; - reg = <3>; - - #address-cells = <2>; - #size-cells = <0>; - - interface@0 { /* interface 0 of configuration 1 */ - compatible = "usbif123,abcd.config1.0"; - reg = <0 1>; - }; - - interface@0,2 { /* interface 0 of configuration 2 */ - compatible = "usbif123,abcd.config2.0"; - reg = <0 2>; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/usb/usb-device.yaml b/Documentation/devicetree/bindings/usb/usb-device.yaml new file mode 100644 index 0000000000000..7bb25a45427d1 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb-device.yaml @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/usb-device.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: The device tree bindings for the Generic USB Device + +maintainers: + - Greg Kroah-Hartman <gregkh@linuxfoundation.org> + +description: | + Usually, we only use device tree for hard wired USB device. + The reference binding doc is from: + http://www.devicetree.org/open-firmware/bindings/usb/usb-1_0.ps + + Four types of device-tree nodes are defined: "host-controller nodes" + representing USB host controllers, "device nodes" representing USB devices, + "interface nodes" representing USB interfaces and "combined nodes" + representing simple USB devices. + + A combined node shall be used instead of a device node and an interface node + for devices of class 0 or 9 (hub) with a single configuration and a single + interface. + + A "hub node" is a combined node or an interface node that represents a USB + hub. + +properties: + compatible: + pattern: "^usb[0-9a-f]{1,4},[0-9a-f]{1,4}$" + description: Device nodes or combined nodes. + "usbVID,PID", where VID is the vendor id and PID the product id. + The textual representation of VID and PID shall be in lower case + hexadecimal with leading zeroes suppressed. The other compatible + strings from the above standard binding could also be used, + but a device adhering to this binding may leave out all except + for "usbVID,PID". + + reg: + description: the number of the USB hub port or the USB host-controller + port to which this device is attached. The range is 1-255. + maxItems: 1 + + "#address-cells": + description: should be 1 for hub nodes with device nodes, + should be 2 for device nodes with interface nodes. + enum: [1, 2] + + "#size-cells": + const: 0 + +patternProperties: + "^interface@[0-9a-f]{1,2}(,[0-9a-f]{1,2})$": + type: object + description: USB interface nodes. + The configuration component is not included in the textual + representation of an interface-node unit address for configuration 1. + + properties: + compatible: + pattern: "^usbif[0-9a-f]{1,4},[0-9a-f]{1,4}.config[0-9a-f]{1,2}.[0-9a-f]{1,2}$" + description: Interface nodes. + "usbifVID,PID.configCN.IN", where VID is the vendor id, PID is + the product id, CN is the configuration value and IN is the interface + number. The textual representation of VID, PID, CN and IN shall be + in lower case hexadecimal with leading zeroes suppressed. + The other compatible strings from the above standard binding could + also be used, but a device adhering to this binding may leave out + all except for "usbifVID,PID.configCN.IN". + + reg: + description: should be 2 cells long, the first cell represents + the interface number and the second cell represents the + configuration value. + maxItems: 1 + +required: + - compatile + - reg + +additionalProperties: true + +examples: + #hub connected to port 1 + #device connected to port 2 + #device connected to port 3 + # interface 0 of configuration 1 + # interface 0 of configuration 2 + - | + usb@11270000 { + reg = <0x11270000 0x1000>; + interrupts = <0x0 0x4e 0x0>; + #address-cells = <1>; + #size-cells = <0>; + + hub@1 { + compatible = "usb5e3,608"; + reg = <1>; + }; + + device@2 { + compatible = "usb123,4567"; + reg = <2>; + }; + + device@3 { + compatible = "usb123,abcd"; + reg = <3>; + + #address-cells = <2>; + #size-cells = <0>; + + interface@0 { + compatible = "usbif123,abcd.config1.0"; + reg = <0 1>; + }; + + interface@0,2 { + compatible = "usbif123,abcd.config2.0"; + reg = <0 2>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/usb/usb-drd.yaml b/Documentation/devicetree/bindings/usb/usb-drd.yaml new file mode 100644 index 0000000000000..f229fc8068d99 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb-drd.yaml @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/usb-drd.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic USB OTG Controller Device Tree Bindings + +maintainers: + - Greg Kroah-Hartman <gregkh@linuxfoundation.org> + +properties: + otg-rev: + description: + Tells usb driver the release number of the OTG and EH supplement with + which the device and its descriptors are compliant, in binary-coded + decimal (i.e. 2.0 is 0200H). This property is used if any real OTG + features (HNP/SRP/ADP) is enabled. If ADP is required, otg-rev should be + 0x0200 or above. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0x0100, 0x0120, 0x0130, 0x0200] + + dr_mode: + description: + Tells Dual-Role USB controllers that we want to work on a particular + mode. In case this attribute isn't passed via DT, USB DRD controllers + should default to OTG. + $ref: /schemas/types.yaml#/definitions/string + enum: [host, peripheral, otg] + + hnp-disable: + description: + Tells OTG controllers we want to disable OTG HNP. Normally HNP is the + basic function of real OTG except you want it to be a srp-capable only B + device. + type: boolean + + srp-disable: + description: + Tells OTG controllers we want to disable OTG SRP. SRP is optional for OTG + device. + type: boolean + + adp-disable: + description: + Tells OTG controllers we want to disable OTG ADP. ADP is optional for OTG + device. + type: boolean + + usb-role-switch: + description: + Indicates that the device is capable of assigning the USB data role + (USB host or USB device) for a given USB connector, such as Type-C, + Type-B(micro). See connector/usb-connector.yaml. + + role-switch-default-mode: + description: + Indicates if usb-role-switch is enabled, the device default operation + mode of controller while usb role is USB_ROLE_NONE. + $ref: /schemas/types.yaml#/definitions/string + enum: [host, peripheral] + default: peripheral + +additionalProperties: true + +examples: + - | + usb@4a030000 { + compatible = "snps,dwc3"; + reg = <0x4a030000 0xcfff>; + interrupts = <0 92 4>; + usb-phy = <&usb2_phy>, <&usb3_phy>; + maximum-speed = "super-speed"; + dr_mode = "otg"; + phy_type = "utmi_wide"; + otg-rev = <0x0200>; + adp-disable; + }; diff --git a/Documentation/devicetree/bindings/usb/usb-hcd.yaml b/Documentation/devicetree/bindings/usb/usb-hcd.yaml index b545b087b3422..56853c17af667 100644 --- a/Documentation/devicetree/bindings/usb/usb-hcd.yaml +++ b/Documentation/devicetree/bindings/usb/usb-hcd.yaml @@ -9,18 +9,31 @@ title: Generic USB Host Controller Device Tree Bindings maintainers: - Greg Kroah-Hartman <gregkh@linuxfoundation.org> +allOf: + - $ref: usb.yaml# + properties: - $nodename: - pattern: "^usb(@.*)?" + companion: + description: Phandle of a companion device + $ref: /schemas/types.yaml#/definitions/phandle - phys: - $ref: /schemas/types.yaml#/definitions/phandle-array + tpl-support: description: - List of all the USB PHYs on this HCD + Indicates if the Targeted Peripheral List is supported for given + targeted hosts (non-PC hosts). + type: boolean - phy-names: - description: - Name specifier for the USB PHY + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^.*@[0-9a-f]{1,2}$": + description: The hard wired USB devices + type: object + $ref: /usb/usb-device.yaml additionalProperties: true @@ -29,4 +42,11 @@ examples: usb { phys = <&usb2_phy1>, <&usb3_phy1>; phy-names = "usb"; + #address-cells = <1>; + #size-cells = <0>; + + hub@1 { + compatible = "usb5e3,610"; + reg = <1>; + }; }; diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt deleted file mode 100644 index 0c5cff84a969f..0000000000000 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ /dev/null @@ -1,41 +0,0 @@ -USB xHCI controllers - -Required properties: - - compatible: should be one or more of - - - "generic-xhci" for generic XHCI device - - "marvell,armada3700-xhci" for Armada 37xx SoCs - - "marvell,armada-375-xhci" for Armada 375 SoCs - - "marvell,armada-380-xhci" for Armada 38x SoCs - - "brcm,bcm7445-xhci" for Broadcom STB SoCs with XHCI - - "xhci-platform" (deprecated) - - When compatible with the generic version, nodes must list the - SoC-specific version corresponding to the platform first - followed by the generic version. - - - reg: should contain address and length of the standard XHCI - register set for the device. - - interrupts: one XHCI interrupt should be described here. - -Optional properties: - - clocks: reference to the clocks - - clock-names: mandatory if there is a second clock, in this case - the name must be "core" for the first clock and "reg" for the - second one - - usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM - - usb3-lpm-capable: determines if platform is USB3 LPM capable - - quirk-broken-port-ped: set if the controller has broken port disable mechanism - - imod-interval-ns: default interrupt moderation interval is 5000ns - - phys : see usb-hcd.yaml in the current directory - -additionally the properties from usb-hcd.yaml (in the current directory) are -supported. - - -Example: - usb@f0931000 { - compatible = "generic-xhci"; - reg = <0xf0931000 0x8c8>; - interrupts = <0x0 0x4e 0x0>; - }; diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.yaml b/Documentation/devicetree/bindings/usb/usb-xhci.yaml new file mode 100644 index 0000000000000..965f87fef7020 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb-xhci.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/usb-xhci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic USB xHCI Controller Device Tree Bindings + +maintainers: + - Mathias Nyman <mathias.nyman@intel.com> + +allOf: + - $ref: "usb-hcd.yaml#" + +properties: + usb2-lpm-disable: + description: Indicates if we don't want to enable USB2 HW LPM + type: boolean + + usb3-lpm-capable: + description: Determines if platform is USB3 LPM capable + type: boolean + + quirk-broken-port-ped: + description: Set if the controller has broken port disable mechanism + type: boolean + + imod-interval-ns: + description: Interrupt moderation interval + default: 5000 + +additionalProperties: true + +examples: + - | + usb@f0930000 { + compatible = "generic-xhci"; + reg = <0xf0930000 0x8c8>; + interrupts = <0x0 0x4e 0x0>; + usb2-lpm-disable; + usb3-lpm-capable; + }; diff --git a/Documentation/devicetree/bindings/usb/usb.yaml b/Documentation/devicetree/bindings/usb/usb.yaml new file mode 100644 index 0000000000000..ebe7f4275c590 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/usb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic USB Controller Device Tree Bindings + +maintainers: + - Greg Kroah-Hartman <gregkh@linuxfoundation.org> + +select: false + +properties: + $nodename: + pattern: "^usb(@.*)?" + + phys: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + List of all the USB PHYs on this HCD + + phy-names: + description: + Name specifier for the USB PHY + + usb-phy: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + List of all the USB PHYs on this HCD to be accepted by the legacy USB + Physical Layer subsystem. + deprecated: true + + phy_type: + description: + Tells USB controllers that we want to configure the core to support a + UTMI+ PHY with an 8- or 16-bit interface if UTMI+ is selected, UTMI+ low + pin interface if ULPI is specified, Serial core/PHY interconnect if + serial is specified and High-Speed Inter-Chip feature if HSIC is + selected. In case this isn't passed via DT, USB controllers should + default to HW capability. + $ref: /schemas/types.yaml#/definitions/string + enum: [utmi, utmi_wide, ulpi, serial, hsic] + + maximum-speed: + description: + Tells USB controllers we want to work up to a certain speed. In case this + isn't passed via DT, USB controllers should default to their maximum HW + capability. + $ref: /schemas/types.yaml#/definitions/string + enum: + - low-speed + - full-speed + - high-speed + - super-speed + - super-speed-plus + +additionalProperties: true + +... diff --git a/Documentation/usb/gadget-testing.rst b/Documentation/usb/gadget-testing.rst index 2eeb3e9299e44..2085e7b24eeb9 100644 --- a/Documentation/usb/gadget-testing.rst +++ b/Documentation/usb/gadget-testing.rst @@ -91,9 +91,9 @@ The ECM function provides these attributes in its function directory: and after creating the functions/ecm.<instance name> they contain default values: qmult is 5, dev_addr and host_addr are randomly selected. -Except for ifname they can be written to until the function is linked to a -configuration. The ifname is read-only and contains the name of the interface -which was assigned by the net core, e. g. usb0. +The ifname can be written to if the function is not bound. A write must be an +interface pattern such as "usb%d", which will cause the net core to choose the +next free usbX interface. By default, it is set to "usb%d". Testing the ECM function ------------------------ @@ -131,9 +131,9 @@ The ECM subset function provides these attributes in its function directory: and after creating the functions/ecm.<instance name> they contain default values: qmult is 5, dev_addr and host_addr are randomly selected. -Except for ifname they can be written to until the function is linked to a -configuration. The ifname is read-only and contains the name of the interface -which was assigned by the net core, e. g. usb0. +The ifname can be written to if the function is not bound. A write must be an +interface pattern such as "usb%d", which will cause the net core to choose the +next free usbX interface. By default, it is set to "usb%d". Testing the ECM subset function ------------------------------- @@ -171,9 +171,9 @@ The EEM function provides these attributes in its function directory: and after creating the functions/eem.<instance name> they contain default values: qmult is 5, dev_addr and host_addr are randomly selected. -Except for ifname they can be written to until the function is linked to a -configuration. The ifname is read-only and contains the name of the interface -which was assigned by the net core, e. g. usb0. +The ifname can be written to if the function is not bound. A write must be an +interface pattern such as "usb%d", which will cause the net core to choose the +next free usbX interface. By default, it is set to "usb%d". Testing the EEM function ------------------------ @@ -453,9 +453,9 @@ The NCM function provides these attributes in its function directory: and after creating the functions/ncm.<instance name> they contain default values: qmult is 5, dev_addr and host_addr are randomly selected. -Except for ifname they can be written to until the function is linked to a -configuration. The ifname is read-only and contains the name of the interface -which was assigned by the net core, e. g. usb0. +The ifname can be written to if the function is not bound. A write must be an +interface pattern such as "usb%d", which will cause the net core to choose the +next free usbX interface. By default, it is set to "usb%d". Testing the NCM function ------------------------ @@ -591,9 +591,9 @@ The RNDIS function provides these attributes in its function directory: and after creating the functions/rndis.<instance name> they contain default values: qmult is 5, dev_addr and host_addr are randomly selected. -Except for ifname they can be written to until the function is linked to a -configuration. The ifname is read-only and contains the name of the interface -which was assigned by the net core, e. g. usb0. +The ifname can be written to if the function is not bound. A write must be an +interface pattern such as "usb%d", which will cause the net core to choose the +next free usbX interface. By default, it is set to "usb%d". Testing the RNDIS function -------------------------- diff --git a/MAINTAINERS b/MAINTAINERS index 49ec9f7ebbaee..4f5aac4250109 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2085,7 +2085,7 @@ M: Chunfeng Yun <chunfeng.yun@mediatek.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Maintained -F: Documentation/devicetree/bindings/phy/phy-mtk-* +F: Documentation/devicetree/bindings/phy/mediatek,* F: drivers/phy/mediatek/ ARM/Microchip (AT91) SoC support @@ -11302,6 +11302,8 @@ L: linux-usb@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/usb/mediatek,* +F: drivers/usb/host/xhci-mtk* F: drivers/usb/mtu3/ MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig index 74739a52a8ade..ae0709265493e 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig @@ -237,12 +237,13 @@ CONFIG_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_TEGRA=y CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_ACM=y CONFIG_USB_WDM=y CONFIG_USB_STORAGE=y CONFIG_USB_CHIPIDEA=y CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_CHIPIDEA_TEGRA=y CONFIG_USB_GADGET=y CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=16 diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts index b10dce8767a45..7db4273cc88bc 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts @@ -127,6 +127,21 @@ status = "okay"; }; +&usb3_phy1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&usb_dwc3_1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb1_vbus>; + dr_mode = "host"; + status = "okay"; +}; + &usdhc2 { assigned-clocks = <&clk IMX8MP_CLK_USDHC2>; assigned-clock-rates = <400000000>; @@ -232,6 +247,12 @@ >; }; + pinctrl_usb1_vbus: usb1grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR 0x19 + >; + }; + pinctrl_usdhc2: usdhc2grp { fsl,pins = < MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x190 diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index f55e3f749d384..c7523fd4eae9b 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -803,5 +803,87 @@ reg = <0x3d800000 0x400000>; interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; }; + + usb3_phy0: usb-phy@381f0040 { + compatible = "fsl,imx8mp-usb-phy"; + reg = <0x381f0040 0x40>; + clocks = <&clk IMX8MP_CLK_USB_PHY_ROOT>; + clock-names = "phy"; + assigned-clocks = <&clk IMX8MP_CLK_USB_PHY_REF>; + assigned-clock-parents = <&clk IMX8MP_CLK_24M>; + #phy-cells = <0>; + status = "disabled"; + }; + + usb3_0: usb@32f10100 { + compatible = "fsl,imx8mp-dwc3"; + reg = <0x32f10100 0x8>; + clocks = <&clk IMX8MP_CLK_HSIO_ROOT>, + <&clk IMX8MP_CLK_USB_ROOT>; + clock-names = "hsio", "suspend"; + interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <1>; + dma-ranges = <0x40000000 0x40000000 0xc0000000>; + ranges; + status = "disabled"; + + usb_dwc3_0: dwc3@38100000 { + compatible = "snps,dwc3"; + reg = <0x38100000 0x10000>; + clocks = <&clk IMX8MP_CLK_HSIO_AXI>, + <&clk IMX8MP_CLK_USB_CORE_REF>, + <&clk IMX8MP_CLK_USB_ROOT>; + clock-names = "bus_early", "ref", "suspend"; + assigned-clocks = <&clk IMX8MP_CLK_HSIO_AXI>; + assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_500M>; + assigned-clock-rates = <500000000>; + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; + phys = <&usb3_phy0>, <&usb3_phy0>; + phy-names = "usb2-phy", "usb3-phy"; + snps,dis-u2-freeclk-exists-quirk; + }; + + }; + + usb3_phy1: usb-phy@382f0040 { + compatible = "fsl,imx8mp-usb-phy"; + reg = <0x382f0040 0x40>; + clocks = <&clk IMX8MP_CLK_USB_PHY_ROOT>; + clock-names = "phy"; + assigned-clocks = <&clk IMX8MP_CLK_USB_PHY_REF>; + assigned-clock-parents = <&clk IMX8MP_CLK_24M>; + #phy-cells = <0>; + }; + + usb3_1: usb@32f10108 { + compatible = "fsl,imx8mp-dwc3"; + reg = <0x32f10108 0x8>; + clocks = <&clk IMX8MP_CLK_HSIO_ROOT>, + <&clk IMX8MP_CLK_USB_ROOT>; + clock-names = "hsio", "suspend"; + interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <1>; + dma-ranges = <0x40000000 0x40000000 0xc0000000>; + ranges; + status = "disabled"; + + usb_dwc3_1: dwc3@38200000 { + compatible = "snps,dwc3"; + reg = <0x38200000 0x10000>; + clocks = <&clk IMX8MP_CLK_HSIO_AXI>, + <&clk IMX8MP_CLK_USB_CORE_REF>, + <&clk IMX8MP_CLK_USB_ROOT>; + clock-names = "bus_early", "ref", "suspend"; + assigned-clocks = <&clk IMX8MP_CLK_HSIO_AXI>; + assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_500M>; + assigned-clock-rates = <500000000>; + interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; + phys = <&usb3_phy1>, <&usb3_phy1>; + phy-names = "usb2-phy", "usb3-phy"; + snps,dis-u2-freeclk-exists-quirk; + }; + }; }; }; diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index 4a4b2008fbc26..4842dd6782000 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -48,6 +48,19 @@ EXPORT_SYMBOL_GPL(is_software_node); struct swnode, fwnode) : NULL; \ }) +static inline struct swnode *dev_to_swnode(struct device *dev) +{ + struct fwnode_handle *fwnode = dev_fwnode(dev); + + if (!fwnode) + return NULL; + + if (!is_software_node(fwnode)) + fwnode = fwnode->secondary; + + return to_swnode(fwnode); +} + static struct swnode * software_node_to_swnode(const struct software_node *node) { @@ -843,22 +856,62 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode) } EXPORT_SYMBOL_GPL(fwnode_remove_software_node); +/** + * device_add_software_node - Assign software node to a device + * @dev: The device the software node is meant for. + * @swnode: The software node. + * + * This function will register @swnode and make it the secondary firmware node + * pointer of @dev. If @dev has no primary node, then @swnode will become the primary + * node. + */ +int device_add_software_node(struct device *dev, const struct software_node *swnode) +{ + int ret; + + /* Only one software node per device. */ + if (dev_to_swnode(dev)) + return -EBUSY; + + ret = software_node_register(swnode); + if (ret) + return ret; + + set_secondary_fwnode(dev, software_node_fwnode(swnode)); + + return 0; +} +EXPORT_SYMBOL_GPL(device_add_software_node); + +/** + * device_remove_software_node - Remove device's software node + * @dev: The device with the software node. + * + * This function will unregister the software node of @dev. + */ +void device_remove_software_node(struct device *dev) +{ + struct swnode *swnode; + + swnode = dev_to_swnode(dev); + if (!swnode) + return; + + software_node_notify(dev, KOBJ_REMOVE); + set_secondary_fwnode(dev, NULL); + kobject_put(&swnode->kobj); +} +EXPORT_SYMBOL_GPL(device_remove_software_node); + int software_node_notify(struct device *dev, unsigned long action) { - struct fwnode_handle *fwnode = dev_fwnode(dev); struct swnode *swnode; int ret; - if (!fwnode) - return 0; - - if (!is_software_node(fwnode)) - fwnode = fwnode->secondary; - if (!is_software_node(fwnode)) + swnode = dev_to_swnode(dev); + if (!swnode) return 0; - swnode = to_swnode(fwnode); - switch (action) { case KOBJ_ADD: ret = sysfs_create_link(&dev->kobj, &swnode->kobj, diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index 8bafcfc6080d4..661818e8fed6b 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -53,9 +53,8 @@ config USB_CHIPIDEA_GENERIC default USB_CHIPIDEA config USB_CHIPIDEA_TEGRA - tristate "Enable Tegra UDC glue driver" if EMBEDDED + tristate "Enable Tegra USB glue driver" if EMBEDDED depends on OF - depends on USB_CHIPIDEA_UDC default USB_CHIPIDEA endif diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c index 7455df0ede49e..90f2a8b786be6 100644 --- a/drivers/usb/chipidea/ci_hdrc_tegra.c +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -4,57 +4,278 @@ */ #include <linux/clk.h> +#include <linux/io.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/reset.h> +#include <linux/usb.h> #include <linux/usb/chipidea.h> +#include <linux/usb/hcd.h> +#include <linux/usb/of.h> +#include <linux/usb/phy.h> + +#include "../host/ehci.h" #include "ci.h" -struct tegra_udc { +struct tegra_usb { struct ci_hdrc_platform_data data; struct platform_device *dev; + const struct tegra_usb_soc_info *soc; struct usb_phy *phy; struct clk *clk; + + bool needs_double_reset; }; -struct tegra_udc_soc_info { +struct tegra_usb_soc_info { unsigned long flags; + unsigned int txfifothresh; + enum usb_dr_mode dr_mode; }; -static const struct tegra_udc_soc_info tegra_udc_soc_info = { - .flags = CI_HDRC_REQUIRES_ALIGNED_DMA, +static const struct tegra_usb_soc_info tegra20_ehci_soc_info = { + .flags = CI_HDRC_REQUIRES_ALIGNED_DMA | + CI_HDRC_OVERRIDE_PHY_CONTROL | + CI_HDRC_SUPPORTS_RUNTIME_PM, + .dr_mode = USB_DR_MODE_HOST, + .txfifothresh = 10, }; -static const struct of_device_id tegra_udc_of_match[] = { +static const struct tegra_usb_soc_info tegra30_ehci_soc_info = { + .flags = CI_HDRC_REQUIRES_ALIGNED_DMA | + CI_HDRC_OVERRIDE_PHY_CONTROL | + CI_HDRC_SUPPORTS_RUNTIME_PM, + .dr_mode = USB_DR_MODE_HOST, + .txfifothresh = 16, +}; + +static const struct tegra_usb_soc_info tegra20_udc_soc_info = { + .flags = CI_HDRC_REQUIRES_ALIGNED_DMA | + CI_HDRC_OVERRIDE_PHY_CONTROL | + CI_HDRC_SUPPORTS_RUNTIME_PM, + .dr_mode = USB_DR_MODE_UNKNOWN, + .txfifothresh = 10, +}; + +static const struct tegra_usb_soc_info tegra30_udc_soc_info = { + .flags = CI_HDRC_REQUIRES_ALIGNED_DMA | + CI_HDRC_OVERRIDE_PHY_CONTROL | + CI_HDRC_SUPPORTS_RUNTIME_PM, + .dr_mode = USB_DR_MODE_UNKNOWN, + .txfifothresh = 16, +}; + +static const struct of_device_id tegra_usb_of_match[] = { { + .compatible = "nvidia,tegra20-ehci", + .data = &tegra20_ehci_soc_info, + }, { + .compatible = "nvidia,tegra30-ehci", + .data = &tegra30_ehci_soc_info, + }, { .compatible = "nvidia,tegra20-udc", - .data = &tegra_udc_soc_info, + .data = &tegra20_udc_soc_info, }, { .compatible = "nvidia,tegra30-udc", - .data = &tegra_udc_soc_info, + .data = &tegra30_udc_soc_info, }, { .compatible = "nvidia,tegra114-udc", - .data = &tegra_udc_soc_info, + .data = &tegra30_udc_soc_info, }, { .compatible = "nvidia,tegra124-udc", - .data = &tegra_udc_soc_info, + .data = &tegra30_udc_soc_info, }, { /* sentinel */ } }; -MODULE_DEVICE_TABLE(of, tegra_udc_of_match); +MODULE_DEVICE_TABLE(of, tegra_usb_of_match); + +static int tegra_usb_reset_controller(struct device *dev) +{ + struct reset_control *rst, *rst_utmi; + struct device_node *phy_np; + int err; + + rst = devm_reset_control_get_shared(dev, "usb"); + if (IS_ERR(rst)) { + dev_err(dev, "can't get ehci reset: %pe\n", rst); + return PTR_ERR(rst); + } + + phy_np = of_parse_phandle(dev->of_node, "nvidia,phy", 0); + if (!phy_np) + return -ENOENT; + + /* + * The 1st USB controller contains some UTMI pad registers that are + * global for all the controllers on the chip. Those registers are + * also cleared when reset is asserted to the 1st controller. + */ + rst_utmi = of_reset_control_get_shared(phy_np, "utmi-pads"); + if (IS_ERR(rst_utmi)) { + dev_warn(dev, "can't get utmi-pads reset from the PHY\n"); + dev_warn(dev, "continuing, but please update your DT\n"); + } else { + /* + * PHY driver performs UTMI-pads reset in a case of a + * non-legacy DT. + */ + reset_control_put(rst_utmi); + } + + of_node_put(phy_np); + + /* reset control is shared, hence initialize it first */ + err = reset_control_deassert(rst); + if (err) + return err; + + err = reset_control_assert(rst); + if (err) + return err; + + udelay(1); + + err = reset_control_deassert(rst); + if (err) + return err; + + return 0; +} + +static int tegra_usb_notify_event(struct ci_hdrc *ci, unsigned int event) +{ + struct tegra_usb *usb = dev_get_drvdata(ci->dev->parent); + struct ehci_hcd *ehci; + + switch (event) { + case CI_HDRC_CONTROLLER_RESET_EVENT: + if (ci->hcd) { + ehci = hcd_to_ehci(ci->hcd); + ehci->has_tdi_phy_lpm = false; + ehci_writel(ehci, usb->soc->txfifothresh << 16, + &ehci->regs->txfill_tuning); + } + break; + } + + return 0; +} + +static int tegra_usb_internal_port_reset(struct ehci_hcd *ehci, + u32 __iomem *portsc_reg, + unsigned long *flags) +{ + u32 saved_usbintr, temp; + unsigned int i, tries; + int retval = 0; + + saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable); + /* disable USB interrupt */ + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + spin_unlock_irqrestore(&ehci->lock, *flags); + + /* + * Here we have to do Port Reset at most twice for + * Port Enable bit to be set. + */ + for (i = 0; i < 2; i++) { + temp = ehci_readl(ehci, portsc_reg); + temp |= PORT_RESET; + ehci_writel(ehci, temp, portsc_reg); + fsleep(10000); + temp &= ~PORT_RESET; + ehci_writel(ehci, temp, portsc_reg); + fsleep(1000); + tries = 100; + do { + fsleep(1000); + /* + * Up to this point, Port Enable bit is + * expected to be set after 2 ms waiting. + * USB1 usually takes extra 45 ms, for safety, + * we take 100 ms as timeout. + */ + temp = ehci_readl(ehci, portsc_reg); + } while (!(temp & PORT_PE) && tries--); + if (temp & PORT_PE) + break; + } + if (i == 2) + retval = -ETIMEDOUT; + + /* + * Clear Connect Status Change bit if it's set. + * We can't clear PORT_PEC. It will also cause PORT_PE to be cleared. + */ + if (temp & PORT_CSC) + ehci_writel(ehci, PORT_CSC, portsc_reg); + + /* + * Write to clear any interrupt status bits that might be set + * during port reset. + */ + temp = ehci_readl(ehci, &ehci->regs->status); + ehci_writel(ehci, temp, &ehci->regs->status); + + /* restore original interrupt-enable bits */ + spin_lock_irqsave(&ehci->lock, *flags); + ehci_writel(ehci, saved_usbintr, &ehci->regs->intr_enable); + + return retval; +} + +static int tegra_ehci_hub_control(struct ci_hdrc *ci, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength, + bool *done, unsigned long *flags) +{ + struct tegra_usb *usb = dev_get_drvdata(ci->dev->parent); + struct ehci_hcd *ehci = hcd_to_ehci(ci->hcd); + u32 __iomem *status_reg; + int retval = 0; + + status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; + + switch (typeReq) { + case SetPortFeature: + if (wValue != USB_PORT_FEAT_RESET || !usb->needs_double_reset) + break; + + /* for USB1 port we need to issue Port Reset twice internally */ + retval = tegra_usb_internal_port_reset(ehci, status_reg, flags); + *done = true; + break; + } + + return retval; +} -static int tegra_udc_probe(struct platform_device *pdev) +static void tegra_usb_enter_lpm(struct ci_hdrc *ci, bool enable) { - const struct tegra_udc_soc_info *soc; - struct tegra_udc *udc; + /* + * Touching any register which belongs to AHB clock domain will + * hang CPU if USB controller is put into low power mode because + * AHB USB clock is gated on Tegra in the LPM. + * + * Tegra PHY has a separate register for checking the clock status + * and usb_phy_set_suspend() takes care of gating/ungating the clocks + * and restoring the PHY state on Tegra. Hence DEVLC/PORTSC registers + * shouldn't be touched directly by the CI driver. + */ + usb_phy_set_suspend(ci->usb_phy, enable); +} + +static int tegra_usb_probe(struct platform_device *pdev) +{ + const struct tegra_usb_soc_info *soc; + struct tegra_usb *usb; int err; - udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL); - if (!udc) + usb = devm_kzalloc(&pdev->dev, sizeof(*usb), GFP_KERNEL); + if (!usb) return -ENOMEM; soc = of_device_get_match_data(&pdev->dev); @@ -63,70 +284,99 @@ static int tegra_udc_probe(struct platform_device *pdev) return -EINVAL; } - udc->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); - if (IS_ERR(udc->phy)) { - err = PTR_ERR(udc->phy); + usb->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); + if (IS_ERR(usb->phy)) { + err = PTR_ERR(usb->phy); dev_err(&pdev->dev, "failed to get PHY: %d\n", err); return err; } - udc->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(udc->clk)) { - err = PTR_ERR(udc->clk); + usb->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(usb->clk)) { + err = PTR_ERR(usb->clk); dev_err(&pdev->dev, "failed to get clock: %d\n", err); return err; } - err = clk_prepare_enable(udc->clk); + err = clk_prepare_enable(usb->clk); if (err < 0) { dev_err(&pdev->dev, "failed to enable clock: %d\n", err); return err; } - /* setup and register ChipIdea HDRC device */ - udc->data.name = "tegra-udc"; - udc->data.flags = soc->flags; - udc->data.usb_phy = udc->phy; - udc->data.capoffset = DEF_CAPOFFSET; - - udc->dev = ci_hdrc_add_device(&pdev->dev, pdev->resource, - pdev->num_resources, &udc->data); - if (IS_ERR(udc->dev)) { - err = PTR_ERR(udc->dev); - dev_err(&pdev->dev, "failed to add HDRC device: %d\n", err); + if (device_property_present(&pdev->dev, "nvidia,needs-double-reset")) + usb->needs_double_reset = true; + + err = tegra_usb_reset_controller(&pdev->dev); + if (err) { + dev_err(&pdev->dev, "failed to reset controller: %d\n", err); goto fail_power_off; } - platform_set_drvdata(pdev, udc); + /* + * USB controller registers shouldn't be touched before PHY is + * initialized, otherwise CPU will hang because clocks are gated. + * PHY driver controls gating of internal USB clocks on Tegra. + */ + err = usb_phy_init(usb->phy); + if (err) + goto fail_power_off; + + platform_set_drvdata(pdev, usb); + + /* setup and register ChipIdea HDRC device */ + usb->soc = soc; + usb->data.name = "tegra-usb"; + usb->data.flags = soc->flags; + usb->data.usb_phy = usb->phy; + usb->data.dr_mode = soc->dr_mode; + usb->data.capoffset = DEF_CAPOFFSET; + usb->data.enter_lpm = tegra_usb_enter_lpm; + usb->data.hub_control = tegra_ehci_hub_control; + usb->data.notify_event = tegra_usb_notify_event; + + /* Tegra PHY driver currently doesn't support LPM for ULPI */ + if (of_usb_get_phy_mode(pdev->dev.of_node) == USBPHY_INTERFACE_MODE_ULPI) + usb->data.flags &= ~CI_HDRC_SUPPORTS_RUNTIME_PM; + + usb->dev = ci_hdrc_add_device(&pdev->dev, pdev->resource, + pdev->num_resources, &usb->data); + if (IS_ERR(usb->dev)) { + err = PTR_ERR(usb->dev); + dev_err(&pdev->dev, "failed to add HDRC device: %d\n", err); + goto phy_shutdown; + } return 0; +phy_shutdown: + usb_phy_shutdown(usb->phy); fail_power_off: - clk_disable_unprepare(udc->clk); + clk_disable_unprepare(usb->clk); return err; } -static int tegra_udc_remove(struct platform_device *pdev) +static int tegra_usb_remove(struct platform_device *pdev) { - struct tegra_udc *udc = platform_get_drvdata(pdev); + struct tegra_usb *usb = platform_get_drvdata(pdev); - ci_hdrc_remove_device(udc->dev); - clk_disable_unprepare(udc->clk); + ci_hdrc_remove_device(usb->dev); + usb_phy_shutdown(usb->phy); + clk_disable_unprepare(usb->clk); return 0; } -static struct platform_driver tegra_udc_driver = { +static struct platform_driver tegra_usb_driver = { .driver = { - .name = "tegra-udc", - .of_match_table = tegra_udc_of_match, + .name = "tegra-usb", + .of_match_table = tegra_usb_of_match, }, - .probe = tegra_udc_probe, - .remove = tegra_udc_remove, + .probe = tegra_usb_probe, + .remove = tegra_usb_remove, }; -module_platform_driver(tegra_udc_driver); +module_platform_driver(tegra_usb_driver); -MODULE_DESCRIPTION("NVIDIA Tegra USB device mode driver"); +MODULE_DESCRIPTION("NVIDIA Tegra USB driver"); MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); -MODULE_ALIAS("platform:tegra-udc"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index aa40e510b806e..3f6c21406dbd2 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -195,7 +195,7 @@ static void hw_wait_phy_stable(void) } /* The PHY enters/leaves low power mode */ -static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) +static void ci_hdrc_enter_lpm_common(struct ci_hdrc *ci, bool enable) { enum ci_hw_regs reg = ci->hw_bank.lpm ? OP_DEVLC : OP_PORTSC; bool lpm = !!(hw_read(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm))); @@ -208,6 +208,11 @@ static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) 0); } +static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) +{ + return ci->platdata->enter_lpm(ci, enable); +} + static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) { u32 reg; @@ -790,6 +795,9 @@ static int ci_get_platdata(struct device *dev, platdata->pins_device = p; } + if (!platdata->enter_lpm) + platdata->enter_lpm = ci_hdrc_enter_lpm_common; + return 0; } diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 48e4a5ca18359..67247d2ac07a8 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -29,6 +29,12 @@ struct ehci_ci_priv { bool enabled; }; +struct ci_hdrc_dma_aligned_buffer { + void *kmalloc_ptr; + void *old_xfer_buffer; + u8 data[0]; +}; + static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); @@ -160,14 +166,15 @@ static int host_start(struct ci_hdrc *ci) pinctrl_select_state(ci->platdata->pctl, ci->platdata->pins_host); + ci->hcd = hcd; + ret = usb_add_hcd(hcd, 0, 0); if (ret) { + ci->hcd = NULL; goto disable_reg; } else { struct usb_otg *otg = &ci->otg; - ci->hcd = hcd; - if (ci_otg_is_fsm_mode(ci)) { otg->host = &hcd->self; hcd->self.otg_port = 1; @@ -237,6 +244,7 @@ static int ci_ehci_hub_control( u32 temp; unsigned long flags; int retval = 0; + bool done = false; struct device *dev = hcd->self.controller; struct ci_hdrc *ci = dev_get_drvdata(dev); @@ -244,6 +252,13 @@ static int ci_ehci_hub_control( spin_lock_irqsave(&ehci->lock, flags); + if (ci->platdata->hub_control) { + retval = ci->platdata->hub_control(ci, typeReq, wValue, wIndex, + buf, wLength, &done, &flags); + if (done) + goto done; + } + if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { temp = ehci_readl(ehci, status_reg); if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) { @@ -349,6 +364,86 @@ static int ci_ehci_bus_suspend(struct usb_hcd *hcd) return 0; } +static void ci_hdrc_free_dma_aligned_buffer(struct urb *urb) +{ + struct ci_hdrc_dma_aligned_buffer *temp; + size_t length; + + if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) + return; + + temp = container_of(urb->transfer_buffer, + struct ci_hdrc_dma_aligned_buffer, data); + + if (usb_urb_dir_in(urb)) { + if (usb_pipeisoc(urb->pipe)) + length = urb->transfer_buffer_length; + else + length = urb->actual_length; + + memcpy(temp->old_xfer_buffer, temp->data, length); + } + urb->transfer_buffer = temp->old_xfer_buffer; + kfree(temp->kmalloc_ptr); + + urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; +} + +static int ci_hdrc_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) +{ + struct ci_hdrc_dma_aligned_buffer *temp, *kmalloc_ptr; + const unsigned int ci_hdrc_usb_dma_align = 32; + size_t kmalloc_size; + + if (urb->num_sgs || urb->sg || urb->transfer_buffer_length == 0 || + !((uintptr_t)urb->transfer_buffer & (ci_hdrc_usb_dma_align - 1))) + return 0; + + /* Allocate a buffer with enough padding for alignment */ + kmalloc_size = urb->transfer_buffer_length + + sizeof(struct ci_hdrc_dma_aligned_buffer) + + ci_hdrc_usb_dma_align - 1; + + kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); + if (!kmalloc_ptr) + return -ENOMEM; + + /* Position our struct dma_aligned_buffer such that data is aligned */ + temp = PTR_ALIGN(kmalloc_ptr + 1, ci_hdrc_usb_dma_align) - 1; + temp->kmalloc_ptr = kmalloc_ptr; + temp->old_xfer_buffer = urb->transfer_buffer; + if (usb_urb_dir_out(urb)) + memcpy(temp->data, urb->transfer_buffer, + urb->transfer_buffer_length); + urb->transfer_buffer = temp->data; + + urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; + + return 0; +} + +static int ci_hdrc_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) +{ + int ret; + + ret = ci_hdrc_alloc_dma_aligned_buffer(urb, mem_flags); + if (ret) + return ret; + + ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); + if (ret) + ci_hdrc_free_dma_aligned_buffer(urb); + + return ret; +} + +static void ci_hdrc_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + usb_hcd_unmap_urb_for_dma(hcd, urb); + ci_hdrc_free_dma_aligned_buffer(urb); +} + int ci_hdrc_host_init(struct ci_hdrc *ci) { struct ci_role_driver *rdrv; @@ -366,6 +461,11 @@ int ci_hdrc_host_init(struct ci_hdrc *ci) rdrv->name = "host"; ci->roles[CI_ROLE_HOST] = rdrv; + if (ci->platdata->flags & CI_HDRC_REQUIRES_ALIGNED_DMA) { + ci_ehci_hc_driver.map_urb_for_dma = ci_hdrc_map_urb_for_dma; + ci_ehci_hc_driver.unmap_urb_for_dma = ci_hdrc_unmap_urb_for_dma; + } + return 0; } diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index b222b777e6a43..74d5a9c5238af 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -25,7 +25,7 @@ /* Increment API VERSION when changing tmc.h with new flags or ioctls * or when changing a significant behavior of the driver. */ -#define USBTMC_API_VERSION (2) +#define USBTMC_API_VERSION (3) #define USBTMC_HEADER_SIZE 12 #define USBTMC_MINOR_BASE 176 @@ -475,33 +475,17 @@ static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write); } -static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, - void __user *arg) +static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb) { struct usbtmc_device_data *data = file_data->data; struct device *dev = &data->intf->dev; - int srq_asserted = 0; u8 *buffer; u8 tag; - __u8 stb; int rv; dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n", data->iin_ep_present); - spin_lock_irq(&data->dev_lock); - srq_asserted = atomic_xchg(&file_data->srq_asserted, srq_asserted); - if (srq_asserted) { - /* a STB with SRQ is already received */ - stb = file_data->srq_byte; - spin_unlock_irq(&data->dev_lock); - rv = put_user(stb, (__u8 __user *)arg); - dev_dbg(dev, "stb:0x%02x with srq received %d\n", - (unsigned int)stb, rv); - return rv; - } - spin_unlock_irq(&data->dev_lock); - buffer = kmalloc(8, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -548,13 +532,12 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, data->iin_bTag, tag); } - stb = data->bNotify2; + *stb = data->bNotify2; } else { - stb = buffer[2]; + *stb = buffer[2]; } - rv = put_user(stb, (__u8 __user *)arg); - dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)stb, rv); + dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)*stb, rv); exit: /* bump interrupt bTag */ @@ -567,6 +550,53 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, return rv; } +static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, + void __user *arg) +{ + int srq_asserted = 0; + __u8 stb; + int rv; + + rv = usbtmc_get_stb(file_data, &stb); + + if (rv > 0) { + srq_asserted = atomic_xchg(&file_data->srq_asserted, + srq_asserted); + if (srq_asserted) + stb |= 0x40; /* Set RQS bit */ + + rv = put_user(stb, (__u8 __user *)arg); + } + return rv; + +} + +static int usbtmc_ioctl_get_srq_stb(struct usbtmc_file_data *file_data, + void __user *arg) +{ + struct usbtmc_device_data *data = file_data->data; + struct device *dev = &data->intf->dev; + int srq_asserted = 0; + __u8 stb = 0; + int rv; + + spin_lock_irq(&data->dev_lock); + srq_asserted = atomic_xchg(&file_data->srq_asserted, srq_asserted); + + if (srq_asserted) { + stb = file_data->srq_byte; + spin_unlock_irq(&data->dev_lock); + rv = put_user(stb, (__u8 __user *)arg); + } else { + spin_unlock_irq(&data->dev_lock); + rv = -ENOMSG; + } + + dev_dbg(dev, "stb:0x%02x with srq received %d\n", (unsigned int)stb, rv); + + return rv; +} + static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, __u32 __user *arg) { @@ -2145,6 +2175,17 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) file_data->auto_abort = !!tmp_byte; break; + case USBTMC_IOCTL_GET_STB: + retval = usbtmc_get_stb(file_data, &tmp_byte); + if (retval > 0) + retval = put_user(tmp_byte, (__u8 __user *)arg); + break; + + case USBTMC_IOCTL_GET_SRQ_STB: + retval = usbtmc_ioctl_get_srq_stb(file_data, + (void __user *)arg); + break; + case USBTMC_IOCTL_CANCEL_IO: retval = usbtmc_ioctl_cancel_io(file_data); break; diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 267543c3dc381..92df3d620f7d2 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -177,7 +177,10 @@ static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg) p->i2c_enable = false; p->activate_stm_fs_transceiver = true; p->activate_stm_id_vb_detection = true; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; p->power_down = DWC2_POWER_DOWN_PARAM_NONE; + p->host_support_fs_ls_low_power = true; + p->host_ls_low_power_phy_clk = true; } static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg) @@ -189,7 +192,12 @@ static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg) p->host_rx_fifo_size = 440; p->host_nperio_tx_fifo_size = 256; p->host_perio_tx_fifo_size = 256; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; p->power_down = DWC2_POWER_DOWN_PARAM_NONE; + p->lpm = false; + p->lpm_clock_gating = false; + p->besl = false; + p->hird_threshold_en = false; } const struct of_device_id dwc2_of_match_table[] = { diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 7a2304565a732..2133acf8ee695 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -139,4 +139,14 @@ config USB_DWC3_QCOM for peripheral mode support. Say 'Y' or 'M' if you have one such device. +config USB_DWC3_IMX8MP + tristate "NXP iMX8MP Platform" + depends on OF && COMMON_CLK + depends on (ARCH_MXC && ARM64) || COMPILE_TEST + default USB_DWC3 + help + NXP iMX8M Plus SoC use DesignWare Core IP for USB2/3 + functionality. + Say 'Y' or 'M' if you have one such device. + endif diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index ae86da0dc5bd1..2259f8876fb2f 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -51,3 +51,4 @@ obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o +obj-$(CONFIG_USB_DWC3_IMX8MP) += dwc3-imx8mp.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 841daec70b6ef..6969196fccd6a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1126,11 +1126,8 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) ret = PTR_ERR(dwc->usb2_phy); if (ret == -ENXIO || ret == -ENODEV) { dwc->usb2_phy = NULL; - } else if (ret == -EPROBE_DEFER) { - return ret; } else { - dev_err(dev, "no usb2 phy configured\n"); - return ret; + return dev_err_probe(dev, ret, "no usb2 phy configured\n"); } } @@ -1138,11 +1135,8 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) ret = PTR_ERR(dwc->usb3_phy); if (ret == -ENXIO || ret == -ENODEV) { dwc->usb3_phy = NULL; - } else if (ret == -EPROBE_DEFER) { - return ret; } else { - dev_err(dev, "no usb3 phy configured\n"); - return ret; + return dev_err_probe(dev, ret, "no usb3 phy configured\n"); } } @@ -1151,11 +1145,8 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) ret = PTR_ERR(dwc->usb2_generic_phy); if (ret == -ENOSYS || ret == -ENODEV) { dwc->usb2_generic_phy = NULL; - } else if (ret == -EPROBE_DEFER) { - return ret; } else { - dev_err(dev, "no usb2 phy configured\n"); - return ret; + return dev_err_probe(dev, ret, "no usb2 phy configured\n"); } } @@ -1164,11 +1155,8 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) ret = PTR_ERR(dwc->usb3_generic_phy); if (ret == -ENOSYS || ret == -ENODEV) { dwc->usb3_generic_phy = NULL; - } else if (ret == -EPROBE_DEFER) { - return ret; } else { - dev_err(dev, "no usb3 phy configured\n"); - return ret; + return dev_err_probe(dev, ret, "no usb3 phy configured\n"); } } @@ -1190,11 +1178,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); ret = dwc3_gadget_init(dwc); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to initialize gadget\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to initialize gadget\n"); break; case USB_DR_MODE_HOST: dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); @@ -1205,20 +1190,14 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); ret = dwc3_host_init(dwc); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to initialize host\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to initialize host\n"); break; case USB_DR_MODE_OTG: INIT_WORK(&dwc->drd_work, __dwc3_set_mode); ret = dwc3_drd_init(dwc); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to initialize dual-role\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to initialize dual-role\n"); break; default: dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); @@ -1490,7 +1469,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc3_get_properties(dwc); - dwc->reset = devm_reset_control_array_get(dev, true, true); + dwc->reset = devm_reset_control_array_get_optional_shared(dev); if (IS_ERR(dwc->reset)) return PTR_ERR(dwc->reset); @@ -1555,8 +1534,7 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_core_init(dwc); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to initialize core: %d\n", ret); + dev_err_probe(dev, ret, "failed to initialize core\n"); goto err4; } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 1b241f937d8f4..eec1cf4ba2689 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -964,6 +964,7 @@ struct dwc3_scratchpad_array { * @nr_scratch: number of scratch buffers * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) + * @gadget_max_speed: maximum gadget speed requested * @ip: controller's ID * @revision: controller's version of an IP * @version_type: VERSIONTYPE register contents, a sub release of a revision @@ -1126,6 +1127,7 @@ struct dwc3 { u32 nr_scratch; u32 u1u2; u32 maximum_speed; + u32 gadget_max_speed; u32 ip; diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 3e1c1aacf002b..e2b68bb770d18 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -441,8 +441,8 @@ static int dwc3_drd_notifier(struct notifier_block *nb, static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) { struct device *dev = dwc->dev; - struct device_node *np_phy, *np_conn; - struct extcon_dev *edev; + struct device_node *np_phy; + struct extcon_dev *edev = NULL; const char *name; if (device_property_read_bool(dev, "extcon")) @@ -462,15 +462,22 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) 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); - np_conn = of_graph_get_remote_node(np_phy, -1, -1); + if (of_graph_is_present(np_phy)) { + struct device_node *np_conn; - if (np_conn) - edev = extcon_find_edev_by_node(np_conn); - else - edev = NULL; - - of_node_put(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; diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c new file mode 100644 index 0000000000000..75f0042b998b1 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-imx8mp.c @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * dwc3-imx8mp.c - NXP imx8mp Specific Glue layer + * + * Copyright (c) 2020 NXP. + */ + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#include "core.h" + +/* USB wakeup registers */ +#define USB_WAKEUP_CTRL 0x00 + +/* Global wakeup interrupt enable, also used to clear interrupt */ +#define USB_WAKEUP_EN BIT(31) +/* Wakeup from connect or disconnect, only for superspeed */ +#define USB_WAKEUP_SS_CONN BIT(5) +/* 0 select vbus_valid, 1 select sessvld */ +#define USB_WAKEUP_VBUS_SRC_SESS_VAL BIT(4) +/* Enable signal for wake up from u3 state */ +#define USB_WAKEUP_U3_EN BIT(3) +/* Enable signal for wake up from id change */ +#define USB_WAKEUP_ID_EN BIT(2) +/* Enable signal for wake up from vbus change */ +#define USB_WAKEUP_VBUS_EN BIT(1) +/* Enable signal for wake up from dp/dm change */ +#define USB_WAKEUP_DPDM_EN BIT(0) + +#define USB_WAKEUP_EN_MASK GENMASK(5, 0) + +struct dwc3_imx8mp { + struct device *dev; + struct platform_device *dwc3; + void __iomem *glue_base; + struct clk *hsio_clk; + struct clk *suspend_clk; + int irq; + bool pm_suspended; + bool wakeup_pending; +}; + +static void dwc3_imx8mp_wakeup_enable(struct dwc3_imx8mp *dwc3_imx) +{ + struct dwc3 *dwc3 = platform_get_drvdata(dwc3_imx->dwc3); + u32 val; + + if (!dwc3) + return; + + val = readl(dwc3_imx->glue_base + USB_WAKEUP_CTRL); + + if ((dwc3->current_dr_role == DWC3_GCTL_PRTCAP_HOST) && dwc3->xhci) + val |= USB_WAKEUP_EN | USB_WAKEUP_SS_CONN | + USB_WAKEUP_U3_EN | USB_WAKEUP_DPDM_EN; + else if (dwc3->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE) + val |= USB_WAKEUP_EN | USB_WAKEUP_VBUS_EN | + USB_WAKEUP_VBUS_SRC_SESS_VAL; + + writel(val, dwc3_imx->glue_base + USB_WAKEUP_CTRL); +} + +static void dwc3_imx8mp_wakeup_disable(struct dwc3_imx8mp *dwc3_imx) +{ + u32 val; + + val = readl(dwc3_imx->glue_base + USB_WAKEUP_CTRL); + val &= ~(USB_WAKEUP_EN | USB_WAKEUP_EN_MASK); + writel(val, dwc3_imx->glue_base + USB_WAKEUP_CTRL); +} + +static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx) +{ + struct dwc3_imx8mp *dwc3_imx = _dwc3_imx; + struct dwc3 *dwc = platform_get_drvdata(dwc3_imx->dwc3); + + if (!dwc3_imx->pm_suspended) + return IRQ_HANDLED; + + disable_irq_nosync(dwc3_imx->irq); + dwc3_imx->wakeup_pending = true; + + if ((dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) && dwc->xhci) + pm_runtime_resume(&dwc->xhci->dev); + else if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE) + pm_runtime_get(dwc->dev); + + return IRQ_HANDLED; +} + +static int dwc3_imx8mp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *dwc3_np, *node = dev->of_node; + struct dwc3_imx8mp *dwc3_imx; + int err, irq; + + if (!node) { + dev_err(dev, "device node not found\n"); + return -EINVAL; + } + + dwc3_imx = devm_kzalloc(dev, sizeof(*dwc3_imx), GFP_KERNEL); + if (!dwc3_imx) + return -ENOMEM; + + platform_set_drvdata(pdev, dwc3_imx); + + dwc3_imx->dev = dev; + + dwc3_imx->glue_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dwc3_imx->glue_base)) + return PTR_ERR(dwc3_imx->glue_base); + + dwc3_imx->hsio_clk = devm_clk_get(dev, "hsio"); + if (IS_ERR(dwc3_imx->hsio_clk)) { + err = PTR_ERR(dwc3_imx->hsio_clk); + dev_err(dev, "Failed to get hsio clk, err=%d\n", err); + return err; + } + + err = clk_prepare_enable(dwc3_imx->hsio_clk); + if (err) { + dev_err(dev, "Failed to enable hsio clk, err=%d\n", err); + return err; + } + + dwc3_imx->suspend_clk = devm_clk_get(dev, "suspend"); + if (IS_ERR(dwc3_imx->suspend_clk)) { + err = PTR_ERR(dwc3_imx->suspend_clk); + dev_err(dev, "Failed to get suspend clk, err=%d\n", err); + goto disable_hsio_clk; + } + + err = clk_prepare_enable(dwc3_imx->suspend_clk); + if (err) { + dev_err(dev, "Failed to enable suspend clk, err=%d\n", err); + goto disable_hsio_clk; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + err = irq; + goto disable_clks; + } + dwc3_imx->irq = irq; + + err = devm_request_threaded_irq(dev, irq, NULL, dwc3_imx8mp_interrupt, + IRQF_ONESHOT, dev_name(dev), dwc3_imx); + if (err) { + dev_err(dev, "failed to request IRQ #%d --> %d\n", irq, err); + goto disable_clks; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + err = pm_runtime_get_sync(dev); + if (err < 0) + goto disable_rpm; + + dwc3_np = of_get_child_by_name(node, "dwc3"); + if (!dwc3_np) { + dev_err(dev, "failed to find dwc3 core child\n"); + goto disable_rpm; + } + + err = of_platform_populate(node, NULL, NULL, dev); + if (err) { + dev_err(&pdev->dev, "failed to create dwc3 core\n"); + goto err_node_put; + } + + dwc3_imx->dwc3 = of_find_device_by_node(dwc3_np); + if (!dwc3_imx->dwc3) { + dev_err(dev, "failed to get dwc3 platform device\n"); + err = -ENODEV; + goto depopulate; + } + of_node_put(dwc3_np); + + device_set_wakeup_capable(dev, true); + pm_runtime_put(dev); + + return 0; + +depopulate: + of_platform_depopulate(dev); +err_node_put: + of_node_put(dwc3_np); +disable_rpm: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); +disable_clks: + clk_disable_unprepare(dwc3_imx->suspend_clk); +disable_hsio_clk: + clk_disable_unprepare(dwc3_imx->hsio_clk); + + return err; +} + +static int dwc3_imx8mp_remove(struct platform_device *pdev) +{ + struct dwc3_imx8mp *dwc3_imx = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + + pm_runtime_get_sync(dev); + of_platform_depopulate(dev); + + clk_disable_unprepare(dwc3_imx->suspend_clk); + clk_disable_unprepare(dwc3_imx->hsio_clk); + + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static int __maybe_unused dwc3_imx8mp_suspend(struct dwc3_imx8mp *dwc3_imx, + pm_message_t msg) +{ + if (dwc3_imx->pm_suspended) + return 0; + + /* Wakeup enable */ + if (PMSG_IS_AUTO(msg) || device_may_wakeup(dwc3_imx->dev)) + dwc3_imx8mp_wakeup_enable(dwc3_imx); + + dwc3_imx->pm_suspended = true; + + return 0; +} + +static int __maybe_unused dwc3_imx8mp_resume(struct dwc3_imx8mp *dwc3_imx, + pm_message_t msg) +{ + struct dwc3 *dwc = platform_get_drvdata(dwc3_imx->dwc3); + int ret = 0; + + if (!dwc3_imx->pm_suspended) + return 0; + + /* Wakeup disable */ + dwc3_imx8mp_wakeup_disable(dwc3_imx); + dwc3_imx->pm_suspended = false; + + if (dwc3_imx->wakeup_pending) { + dwc3_imx->wakeup_pending = false; + if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE) { + pm_runtime_mark_last_busy(dwc->dev); + pm_runtime_put_autosuspend(dwc->dev); + } else { + /* + * Add wait for xhci switch from suspend + * clock to normal clock to detect connection. + */ + usleep_range(9000, 10000); + } + enable_irq(dwc3_imx->irq); + } + + return ret; +} + +static int __maybe_unused dwc3_imx8mp_pm_suspend(struct device *dev) +{ + struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); + int ret; + + ret = dwc3_imx8mp_suspend(dwc3_imx, PMSG_SUSPEND); + + if (device_may_wakeup(dwc3_imx->dev)) + enable_irq_wake(dwc3_imx->irq); + else + clk_disable_unprepare(dwc3_imx->suspend_clk); + + clk_disable_unprepare(dwc3_imx->hsio_clk); + dev_dbg(dev, "dwc3 imx8mp pm suspend.\n"); + + return ret; +} + +static int __maybe_unused dwc3_imx8mp_pm_resume(struct device *dev) +{ + struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); + int ret; + + if (device_may_wakeup(dwc3_imx->dev)) { + disable_irq_wake(dwc3_imx->irq); + } else { + ret = clk_prepare_enable(dwc3_imx->suspend_clk); + if (ret) + return ret; + } + + ret = clk_prepare_enable(dwc3_imx->hsio_clk); + if (ret) + return ret; + + ret = dwc3_imx8mp_resume(dwc3_imx, PMSG_RESUME); + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + dev_dbg(dev, "dwc3 imx8mp pm resume.\n"); + + return ret; +} + +static int __maybe_unused dwc3_imx8mp_runtime_suspend(struct device *dev) +{ + struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); + + dev_dbg(dev, "dwc3 imx8mp runtime suspend.\n"); + + return dwc3_imx8mp_suspend(dwc3_imx, PMSG_AUTO_SUSPEND); +} + +static int __maybe_unused dwc3_imx8mp_runtime_resume(struct device *dev) +{ + struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); + + dev_dbg(dev, "dwc3 imx8mp runtime resume.\n"); + + return dwc3_imx8mp_resume(dwc3_imx, PMSG_AUTO_RESUME); +} + +static const struct dev_pm_ops dwc3_imx8mp_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(dwc3_imx8mp_pm_suspend, dwc3_imx8mp_pm_resume) + SET_RUNTIME_PM_OPS(dwc3_imx8mp_runtime_suspend, + dwc3_imx8mp_runtime_resume, NULL) +}; + +static const struct of_device_id dwc3_imx8mp_of_match[] = { + { .compatible = "fsl,imx8mp-dwc3", }, + {}, +}; +MODULE_DEVICE_TABLE(of, dwc3_imx8mp_of_match); + +static struct platform_driver dwc3_imx8mp_driver = { + .probe = dwc3_imx8mp_probe, + .remove = dwc3_imx8mp_remove, + .driver = { + .name = "imx8mp-dwc3", + .pm = &dwc3_imx8mp_dev_pm_ops, + .of_match_table = dwc3_imx8mp_of_match, + }, +}; + +module_platform_driver(dwc3_imx8mp_driver); + +MODULE_ALIAS("platform:imx8mp-dwc3"); +MODULE_AUTHOR("jun.li@nxp.com"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("DesignWare USB3 imx8mp Glue Layer"); diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 9a99253d5ba3b..057056c0975e4 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -99,13 +99,8 @@ static int kdwc3_probe(struct platform_device *pdev) /* PSC dependency on AM65 needs SERDES0 to be powered before USB0 */ kdwc->usb3_phy = devm_phy_optional_get(dev, "usb3-phy"); - if (IS_ERR(kdwc->usb3_phy)) { - error = PTR_ERR(kdwc->usb3_phy); - if (error != -EPROBE_DEFER) - dev_err(dev, "couldn't get usb3 phy: %d\n", error); - - return error; - } + if (IS_ERR(kdwc->usb3_phy)) + return dev_err_probe(dev, PTR_ERR(kdwc->usb3_phy), "couldn't get usb3 phy\n"); phy_pm_runtime_get_sync(kdwc->usb3_phy); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index bae6a70664c80..3d3918a8d5fbc 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -40,7 +40,9 @@ #define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee #define PCI_DEVICE_ID_INTEL_TGPH 0x43ee #define PCI_DEVICE_ID_INTEL_JSP 0x4dee +#define PCI_DEVICE_ID_INTEL_ADLP 0x51ee #define PCI_DEVICE_ID_INTEL_ADLS 0x7ae1 +#define PCI_DEVICE_ID_INTEL_TGL 0x9a15 #define PCI_INTEL_BXT_DSM_GUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511" #define PCI_INTEL_BXT_FUNC_PMU_PWR 4 @@ -142,6 +144,18 @@ static const struct property_entry dwc3_pci_amd_properties[] = { {} }; +static const struct software_node dwc3_pci_intel_swnode = { + .properties = dwc3_pci_intel_properties, +}; + +static const struct software_node dwc3_pci_intel_mrfld_swnode = { + .properties = dwc3_pci_mrfld_properties, +}; + +static const struct software_node dwc3_pci_amd_swnode = { + .properties = dwc3_pci_amd_properties, +}; + static int dwc3_pci_quirks(struct dwc3_pci *dwc) { struct pci_dev *pdev = dwc->pci; @@ -222,7 +236,6 @@ static void dwc3_pci_resume_work(struct work_struct *work) static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) { - struct property_entry *p = (struct property_entry *)id->driver_data; struct dwc3_pci *dwc; struct resource res[2]; int ret; @@ -265,7 +278,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) dwc->dwc3->dev.parent = dev; ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(dev)); - ret = platform_device_add_properties(dwc->dwc3, p); + ret = device_add_software_node(&dwc->dwc3->dev, (void *)id->driver_data); if (ret < 0) goto err; @@ -288,6 +301,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) return 0; err: + device_remove_software_node(&dwc->dwc3->dev); platform_device_put(dwc->dwc3); return ret; } @@ -304,75 +318,82 @@ static void dwc3_pci_remove(struct pci_dev *pci) #endif device_init_wakeup(&pci->dev, false); pm_runtime_get(&pci->dev); + device_remove_software_node(&dwc->dwc3->dev); platform_device_unregister(dwc->dwc3); } static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW), - (kernel_ulong_t) &dwc3_pci_intel_properties }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD), - (kernel_ulong_t) &dwc3_pci_mrfld_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_mrfld_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLLP), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLH), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPV), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPH), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_JSP), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLP), + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS), - (kernel_ulong_t) &dwc3_pci_intel_properties, }, + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL), + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB), - (kernel_ulong_t) &dwc3_pci_amd_properties, }, + (kernel_ulong_t) &dwc3_pci_amd_swnode, }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index c703d552bbcfc..d803ee98c628e 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -60,12 +60,14 @@ struct dwc3_acpi_pdata { int dp_hs_phy_irq_index; int dm_hs_phy_irq_index; int ss_phy_irq_index; + bool is_urs; }; struct dwc3_qcom { struct device *dev; void __iomem *qscratch_base; struct platform_device *dwc3; + struct platform_device *urs_usb; struct clk **clks; int num_clocks; struct reset_control *resets; @@ -429,13 +431,15 @@ static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom) static int dwc3_qcom_get_irq(struct platform_device *pdev, const char *name, int num) { + struct dwc3_qcom *qcom = platform_get_drvdata(pdev); + struct platform_device *pdev_irq = qcom->urs_usb ? qcom->urs_usb : pdev; struct device_node *np = pdev->dev.of_node; int ret; if (np) - ret = platform_get_irq_byname(pdev, name); + ret = platform_get_irq_byname(pdev_irq, name); else - ret = platform_get_irq(pdev, num); + ret = platform_get_irq(pdev_irq, num); return ret; } @@ -568,6 +572,8 @@ static int dwc3_qcom_acpi_register_core(struct platform_device *pdev) struct dwc3_qcom *qcom = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; struct resource *res, *child_res = NULL; + struct platform_device *pdev_irq = qcom->urs_usb ? qcom->urs_usb : + pdev; int irq; int ret; @@ -597,7 +603,7 @@ static int dwc3_qcom_acpi_register_core(struct platform_device *pdev) child_res[0].end = child_res[0].start + qcom->acpi_pdata->dwc3_core_base_size; - irq = platform_get_irq(pdev, 0); + irq = platform_get_irq(pdev_irq, 0); child_res[1].flags = IORESOURCE_IRQ; child_res[1].start = child_res[1].end = irq; @@ -651,6 +657,33 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev) return 0; } +static struct platform_device * +dwc3_qcom_create_urs_usb_platdev(struct device *dev) +{ + struct fwnode_handle *fwh; + struct acpi_device *adev; + char name[8]; + int ret; + int id; + + /* Figure out device id */ + ret = sscanf(fwnode_get_name(dev->fwnode), "URS%d", &id); + if (!ret) + return NULL; + + /* Find the child using name */ + snprintf(name, sizeof(name), "USB%d", id); + fwh = fwnode_get_named_child_node(dev->fwnode, name); + if (!fwh) + return NULL; + + adev = to_acpi_device_node(fwh); + if (!adev) + return NULL; + + return acpi_create_platform_device(adev, NULL); +} + static int dwc3_qcom_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -715,6 +748,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev) qcom->acpi_pdata->qscratch_base_offset; parent_res->end = parent_res->start + qcom->acpi_pdata->qscratch_base_size; + + if (qcom->acpi_pdata->is_urs) { + qcom->urs_usb = dwc3_qcom_create_urs_usb_platdev(dev); + if (!qcom->urs_usb) { + dev_err(dev, "failed to create URS USB platdev\n"); + return -ENODEV; + } + } } qcom->qscratch_base = devm_ioremap_resource(dev, parent_res); @@ -877,8 +918,20 @@ static const struct dwc3_acpi_pdata sdm845_acpi_pdata = { .ss_phy_irq_index = 2 }; +static const struct dwc3_acpi_pdata sdm845_acpi_urs_pdata = { + .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET, + .qscratch_base_size = SDM845_QSCRATCH_SIZE, + .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE, + .hs_phy_irq_index = 1, + .dp_hs_phy_irq_index = 4, + .dm_hs_phy_irq_index = 3, + .ss_phy_irq_index = 2, + .is_urs = true, +}; + static const struct acpi_device_id dwc3_qcom_acpi_match[] = { { "QCOM2430", (unsigned long)&sdm845_acpi_pdata }, + { "QCOM0304", (unsigned long)&sdm845_acpi_urs_pdata }, { }, }; MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index ee44321fee386..86f257f12d458 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2038,6 +2038,61 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc) } } +static void __dwc3_gadget_set_speed(struct dwc3 *dwc) +{ + u32 reg; + + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg &= ~(DWC3_DCFG_SPEED_MASK); + + /* + * WORKAROUND: DWC3 revision < 2.20a have an issue + * which would cause metastability state on Run/Stop + * bit if we try to force the IP to USB2-only mode. + * + * Because of that, we cannot configure the IP to any + * speed other than the SuperSpeed + * + * Refers to: + * + * STAR#9000525659: Clock Domain Crossing on DCTL in + * USB 2.0 Mode + */ + if (DWC3_VER_IS_PRIOR(DWC3, 220A) && + !dwc->dis_metastability_quirk) { + reg |= DWC3_DCFG_SUPERSPEED; + } else { + switch (dwc->gadget_max_speed) { + case USB_SPEED_LOW: + reg |= DWC3_DCFG_LOWSPEED; + break; + case USB_SPEED_FULL: + reg |= DWC3_DCFG_FULLSPEED; + break; + case USB_SPEED_HIGH: + reg |= DWC3_DCFG_HIGHSPEED; + break; + case USB_SPEED_SUPER: + reg |= DWC3_DCFG_SUPERSPEED; + break; + case USB_SPEED_SUPER_PLUS: + if (DWC3_IP_IS(DWC3)) + reg |= DWC3_DCFG_SUPERSPEED; + else + reg |= DWC3_DCFG_SUPERSPEED_PLUS; + break; + default: + dev_err(dwc->dev, "invalid speed (%d)\n", dwc->gadget_max_speed); + + if (DWC3_IP_IS(DWC3)) + reg |= DWC3_DCFG_SUPERSPEED; + else + reg |= DWC3_DCFG_SUPERSPEED_PLUS; + } + } + dwc3_writel(dwc->regs, DWC3_DCFG, reg); +} + static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) { u32 reg; @@ -2060,6 +2115,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) if (dwc->has_hibernation) reg |= DWC3_DCTL_KEEP_CONNECT; + __dwc3_gadget_set_speed(dwc); dwc->pullups_connected = true; } else { reg &= ~DWC3_DCTL_RUN_STOP; @@ -2111,6 +2167,17 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) } /* + * Check the return value for successful resume, or error. For a + * successful resume, the DWC3 runtime PM resume routine will handle + * the run stop sequence, so avoid duplicate operations here. + */ + ret = pm_runtime_get_sync(dwc->dev); + if (!ret || ret < 0) { + pm_runtime_put(dwc->dev); + return 0; + } + + /* * Synchronize any pending event handling before executing the controller * halt routine. */ @@ -2148,12 +2215,14 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) dwc->ev_buf->lpos = (dwc->ev_buf->lpos + count) % dwc->ev_buf->length; } + dwc->connected = false; } else { __dwc3_gadget_start(dwc); } ret = dwc3_gadget_run_stop(dwc, is_on, false); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put(dwc->dev); return ret; } @@ -2163,8 +2232,7 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc) u32 reg; /* Enable all but Start and End of Frame IRQs */ - reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | - DWC3_DEVTEN_EVNTOVERFLOWEN | + reg = (DWC3_DEVTEN_EVNTOVERFLOWEN | DWC3_DEVTEN_CMDCMPLTEN | DWC3_DEVTEN_ERRTICERREN | DWC3_DEVTEN_WKUPEVTEN | @@ -2401,60 +2469,20 @@ static void dwc3_gadget_set_speed(struct usb_gadget *g, { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; - u32 reg; spin_lock_irqsave(&dwc->lock, flags); - reg = dwc3_readl(dwc->regs, DWC3_DCFG); - reg &= ~(DWC3_DCFG_SPEED_MASK); + dwc->gadget_max_speed = speed; + spin_unlock_irqrestore(&dwc->lock, flags); +} - /* - * WORKAROUND: DWC3 revision < 2.20a have an issue - * which would cause metastability state on Run/Stop - * bit if we try to force the IP to USB2-only mode. - * - * Because of that, we cannot configure the IP to any - * speed other than the SuperSpeed - * - * Refers to: - * - * STAR#9000525659: Clock Domain Crossing on DCTL in - * USB 2.0 Mode - */ - if (DWC3_VER_IS_PRIOR(DWC3, 220A) && - !dwc->dis_metastability_quirk) { - reg |= DWC3_DCFG_SUPERSPEED; - } else { - switch (speed) { - case USB_SPEED_LOW: - reg |= DWC3_DCFG_LOWSPEED; - break; - case USB_SPEED_FULL: - reg |= DWC3_DCFG_FULLSPEED; - break; - case USB_SPEED_HIGH: - reg |= DWC3_DCFG_HIGHSPEED; - break; - case USB_SPEED_SUPER: - reg |= DWC3_DCFG_SUPERSPEED; - break; - case USB_SPEED_SUPER_PLUS: - if (DWC3_IP_IS(DWC3)) - reg |= DWC3_DCFG_SUPERSPEED; - else - reg |= DWC3_DCFG_SUPERSPEED_PLUS; - break; - default: - dev_err(dwc->dev, "invalid speed (%d)\n", speed); +static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA) +{ + struct dwc3 *dwc = gadget_to_dwc(g); - if (DWC3_IP_IS(DWC3)) - reg |= DWC3_DCFG_SUPERSPEED; - else - reg |= DWC3_DCFG_SUPERSPEED_PLUS; - } - } - dwc3_writel(dwc->regs, DWC3_DCFG, reg); + if (dwc->usb2_phy) + return usb_phy_set_power(dwc->usb2_phy, mA); - spin_unlock_irqrestore(&dwc->lock, flags); + return 0; } static const struct usb_gadget_ops dwc3_gadget_ops = { @@ -2466,6 +2494,7 @@ static const struct usb_gadget_ops dwc3_gadget_ops = { .udc_stop = dwc3_gadget_stop, .udc_set_speed = dwc3_gadget_set_speed, .get_config_params = dwc3_gadget_config_params, + .vbus_draw = dwc3_gadget_vbus_draw, }; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 1a556a628971f..9a7cc08d6593e 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2042,7 +2042,7 @@ done: return value; } -void composite_disconnect(struct usb_gadget *gadget) +static void __composite_disconnect(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); unsigned long flags; @@ -2059,6 +2059,23 @@ void composite_disconnect(struct usb_gadget *gadget) spin_unlock_irqrestore(&cdev->lock, flags); } +void composite_disconnect(struct usb_gadget *gadget) +{ + usb_gadget_vbus_draw(gadget, 0); + __composite_disconnect(gadget); +} + +void composite_reset(struct usb_gadget *gadget) +{ + /* + * Section 1.4.13 Standard Downstream Port of the USB battery charging + * specification v1.2 states that a device connected on a SDP shall only + * draw at max 100mA while in a connected, but unconfigured state. + */ + usb_gadget_vbus_draw(gadget, 100); + __composite_disconnect(gadget); +} + /*-------------------------------------------------------------------------*/ static ssize_t suspended_show(struct device *dev, struct device_attribute *attr, @@ -2379,7 +2396,7 @@ static const struct usb_gadget_driver composite_driver_template = { .unbind = composite_unbind, .setup = composite_setup, - .reset = composite_disconnect, + .reset = composite_reset, .disconnect = composite_disconnect, .suspend = composite_suspend, diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 36ffb43f9c1a0..0d56f33d63c29 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1488,6 +1488,28 @@ static void configfs_composite_disconnect(struct usb_gadget *gadget) spin_unlock_irqrestore(&gi->spinlock, flags); } +static void configfs_composite_reset(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev; + struct gadget_info *gi; + unsigned long flags; + + cdev = get_gadget_data(gadget); + if (!cdev) + return; + + gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + cdev = get_gadget_data(gadget); + if (!cdev || gi->unbind) { + spin_unlock_irqrestore(&gi->spinlock, flags); + return; + } + + composite_reset(gadget); + spin_unlock_irqrestore(&gi->spinlock, flags); +} + static void configfs_composite_suspend(struct usb_gadget *gadget) { struct usb_composite_dev *cdev; @@ -1537,7 +1559,7 @@ static const struct usb_gadget_driver configfs_driver_template = { .unbind = configfs_composite_unbind, .setup = configfs_composite_setup, - .reset = configfs_composite_disconnect, + .reset = configfs_composite_reset, .disconnect = configfs_composite_disconnect, .suspend = configfs_composite_suspend, diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 8fff995b8dd50..71a1a26e85c76 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -87,7 +87,7 @@ struct f_midi { struct snd_rawmidi_substream *out_substream[MAX_PORTS]; unsigned long out_triggered; - struct tasklet_struct tasklet; + struct work_struct work; unsigned int in_ports; unsigned int out_ports; int index; @@ -698,9 +698,11 @@ drop_out: f_midi_drop_out_substreams(midi); } -static void f_midi_in_tasklet(struct tasklet_struct *t) +static void f_midi_in_work(struct work_struct *work) { - struct f_midi *midi = from_tasklet(midi, t, tasklet); + struct f_midi *midi; + + midi = container_of(work, struct f_midi, work); f_midi_transmit(midi); } @@ -737,7 +739,7 @@ static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up) VDBG(midi, "%s() %d\n", __func__, up); midi->in_ports_array[substream->number].active = up; if (up) - tasklet_hi_schedule(&midi->tasklet); + queue_work(system_highpri_wq, &midi->work); } static int f_midi_out_open(struct snd_rawmidi_substream *substream) @@ -875,7 +877,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0; midi->gadget = cdev->gadget; - tasklet_setup(&midi->tasklet, f_midi_in_tasklet); + INIT_WORK(&midi->work, f_midi_in_work); status = f_midi_register_card(midi); if (status < 0) goto fail_register; diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 2f1eb2e81d306..61ce8e68f7a30 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -51,6 +51,8 @@ #define GET_PORT_STATUS 1 #define SOFT_RESET 2 +#define DEFAULT_Q_LEN 10 /* same as legacy g_printer gadget */ + static int major, minors; static struct class *usb_gadget_class; static DEFINE_IDA(printer_ida); @@ -1364,6 +1366,9 @@ static struct usb_function_instance *gprinter_alloc_inst(void) opts->func_inst.free_func_inst = gprinter_free_inst; ret = &opts->func_inst; + /* Make sure q_len is initialized, otherwise the bound device can't support read/write! */ + opts->q_len = DEFAULT_Q_LEN; + mutex_lock(&printer_ida_lock); if (ida_is_empty(&printer_ida)) { diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index c019f2b0c0af3..d1d044d9f8594 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -80,6 +80,7 @@ struct eth_dev { bool zlp; bool no_skb_reserve; + bool ifname_set; u8 host_mac[ETH_ALEN]; u8 dev_mac[ETH_ALEN]; }; @@ -1004,15 +1005,45 @@ EXPORT_SYMBOL_GPL(gether_get_qmult); int gether_get_ifname(struct net_device *net, char *name, int len) { + struct eth_dev *dev = netdev_priv(net); int ret; rtnl_lock(); - ret = scnprintf(name, len, "%s\n", netdev_name(net)); + ret = scnprintf(name, len, "%s\n", + dev->ifname_set ? net->name : netdev_name(net)); rtnl_unlock(); return ret; } EXPORT_SYMBOL_GPL(gether_get_ifname); +int gether_set_ifname(struct net_device *net, const char *name, int len) +{ + struct eth_dev *dev = netdev_priv(net); + char tmp[IFNAMSIZ]; + const char *p; + + if (name[len - 1] == '\n') + len--; + + if (len >= sizeof(tmp)) + return -E2BIG; + + strscpy(tmp, name, len + 1); + if (!dev_valid_name(tmp)) + return -EINVAL; + + /* Require exactly one %d, so binding will not fail with EEXIST. */ + p = strchr(name, '%'); + if (!p || p[1] != 'd' || strchr(p + 2, '%')) + return -EINVAL; + + strncpy(net->name, tmp, sizeof(net->name)); + dev->ifname_set = true; + + return 0; +} +EXPORT_SYMBOL_GPL(gether_set_ifname); + /* * gether_cleanup - remove Ethernet-over-USB device * Context: may sleep diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 10dd640684e2b..40144546d1b07 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -244,6 +244,18 @@ unsigned gether_get_qmult(struct net_device *net); */ int gether_get_ifname(struct net_device *net, char *name, int len); +/** + * gether_set_ifname - set an ethernet-over-usb link interface name + * @net: device representing this link + * @name: new interface name + * @len: length of @name + * + * This sets the interface name of this ethernet-over-usb link. + * A single terminating newline, if any, is ignored. + * Returns zero on success, else negative errno. + */ +int gether_set_ifname(struct net_device *net, const char *name, int len); + void gether_cleanup(struct eth_dev *dev); /* connect/disconnect is handled by individual functions */ diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index bd92b57030131..3dfb460908fae 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -148,7 +148,20 @@ out: \ return ret; \ } \ \ - CONFIGFS_ATTR_RO(_f_##_opts_, ifname) + static ssize_t _f_##_opts_ifname_store(struct config_item *item, \ + const char *page, size_t len)\ + { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ + int ret = -EBUSY; \ + \ + mutex_lock(&opts->lock); \ + if (!opts->refcnt) \ + ret = gether_set_ifname(opts->net, page, len); \ + mutex_unlock(&opts->lock); \ + return ret ?: len; \ + } \ + \ + CONFIGFS_ATTR(_f_##_opts_, ifname) #define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_) \ static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\ diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 2caccbb6e0140..768f883f486cd 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -258,9 +258,7 @@ __acquires(&port->port_lock) list_del(&req->list); req->zero = kfifo_is_empty(&port->port_write_buf); - pr_vdebug("ttyGS%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n", - port->port_num, len, *((u8 *)req->buf), - *((u8 *)req->buf+1), *((u8 *)req->buf+2)); + pr_vdebug("ttyGS%d: tx len=%d, %3ph ...\n", port->port_num, len, req->buf); /* Drop lock while we call out of driver; completions * could be issued while we do so. Disconnection may diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h index ac75e25c3b6ab..8d00b1239f219 100644 --- a/drivers/usb/gadget/udc/bdc/bdc.h +++ b/drivers/usb/gadget/udc/bdc/bdc.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * bdc.h - header for the BRCM BDC USB3.0 device controller * @@ -35,7 +35,7 @@ /* * Maximum size of ep0 response buffer for ch9 requests, * the set_sel request uses 6 so far, the max. -*/ + */ #define EP0_RESPONSE_BUFF 6 /* Start with SS as default */ #define EP0_MAX_PKT_SIZE 512 @@ -86,23 +86,23 @@ #define BDC_EPSTS5 0x74 #define BDC_EPSTS6 0x78 #define BDC_EPSTS7 0x7c -#define BDC_SRRBAL(n) (0x200 + (n * 0x10)) -#define BDC_SRRBAH(n) (0x204 + (n * 0x10)) -#define BDC_SRRINT(n) (0x208 + (n * 0x10)) -#define BDC_INTCTLS(n) (0x20c + (n * 0x10)) +#define BDC_SRRBAL(n) (0x200 + ((n) * 0x10)) +#define BDC_SRRBAH(n) (0x204 + ((n) * 0x10)) +#define BDC_SRRINT(n) (0x208 + ((n) * 0x10)) +#define BDC_INTCTLS(n) (0x20c + ((n) * 0x10)) /* Extended capability regs */ #define BDC_FSCNOC 0xcd4 #define BDC_FSCNIC 0xce4 -#define NUM_NCS(p) (p >> 28) +#define NUM_NCS(p) ((p) >> 28) /* Register bit fields and Masks */ /* BDC Configuration 0 */ #define BDC_PGS(p) (((p) & (0x7 << 8)) >> 8) -#define BDC_SPB(p) (p & 0x7) +#define BDC_SPB(p) ((p) & 0x7) /* BDC Capability1 */ -#define BDC_P64 (1 << 0) +#define BDC_P64 BIT(0) /* BDC Command register */ #define BDC_CMD_FH 0xe @@ -111,9 +111,9 @@ #define BDC_CMD_BLA 0x3 #define BDC_CMD_EPC 0x2 #define BDC_CMD_DVC 0x1 -#define BDC_CMD_CWS (0x1 << 5) +#define BDC_CMD_CWS BIT(5) #define BDC_CMD_CST(p) (((p) & (0xf << 6))>>6) -#define BDC_CMD_EPN(p) ((p & 0x1f) << 10) +#define BDC_CMD_EPN(p) (((p) & 0x1f) << 10) #define BDC_SUB_CMD_ADD (0x1 << 17) #define BDC_SUB_CMD_FWK (0x4 << 17) /* Reset sequence number */ @@ -124,7 +124,7 @@ #define BDC_SUB_CMD_EP_STP (0x2 << 17) #define BDC_SUB_CMD_EP_STL (0x4 << 17) #define BDC_SUB_CMD_EP_RST (0x1 << 17) -#define BDC_CMD_SRD (1 << 27) +#define BDC_CMD_SRD BIT(27) /* CMD completion status */ #define BDC_CMDS_SUCC 0x1 @@ -141,19 +141,19 @@ #define EPM_SHIFT 4 /* BDC USPSC */ -#define BDC_VBC (1 << 31) -#define BDC_PRC (1 << 30) -#define BDC_PCE (1 << 29) -#define BDC_CFC (1 << 28) -#define BDC_PCC (1 << 27) -#define BDC_PSC (1 << 26) -#define BDC_VBS (1 << 25) -#define BDC_PRS (1 << 24) -#define BDC_PCS (1 << 23) +#define BDC_VBC BIT(31) +#define BDC_PRC BIT(30) +#define BDC_PCE BIT(29) +#define BDC_CFC BIT(28) +#define BDC_PCC BIT(27) +#define BDC_PSC BIT(26) +#define BDC_VBS BIT(25) +#define BDC_PRS BIT(24) +#define BDC_PCS BIT(23) #define BDC_PSP(p) (((p) & (0x7 << 20))>>20) -#define BDC_SCN (1 << 8) -#define BDC_SDC (1 << 7) -#define BDC_SWS (1 << 4) +#define BDC_SCN BIT(8) +#define BDC_SDC BIT(7) +#define BDC_SWS BIT(4) #define BDC_USPSC_RW (BDC_SCN|BDC_SDC|BDC_SWS|0xf) #define BDC_PSP(p) (((p) & (0x7 << 20))>>20) @@ -163,21 +163,21 @@ #define BDC_SPEED_HS 0x3 #define BDC_SPEED_SS 0x4 -#define BDC_PST(p) (p & 0xf) +#define BDC_PST(p) ((p) & 0xf) #define BDC_PST_MASK 0xf /* USPPMS */ -#define BDC_U2E (0x1 << 31) -#define BDC_U1E (0x1 << 30) -#define BDC_U2A (0x1 << 29) -#define BDC_PORT_W1S (0x1 << 17) +#define BDC_U2E BIT(31) +#define BDC_U1E BIT(30) +#define BDC_U2A BIT(29) +#define BDC_PORT_W1S BIT(17) #define BDC_U1T(p) ((p) & 0xff) #define BDC_U2T(p) (((p) & 0xff) << 8) #define BDC_U1T_MASK 0xff /* USBPM2 */ /* Hardware LPM Enable */ -#define BDC_HLE (1 << 16) +#define BDC_HLE BIT(16) /* BDC Status and Control */ #define BDC_COP_RST (1 << 29) @@ -186,11 +186,11 @@ #define BDC_COP_MASK (BDC_COP_RST|BDC_COP_RUN|BDC_COP_STP) -#define BDC_COS (1 << 28) +#define BDC_COS BIT(28) #define BDC_CSTS(p) (((p) & (0x7 << 20)) >> 20) -#define BDC_MASK_MCW (1 << 7) -#define BDC_GIE (1 << 1) -#define BDC_GIP (1 << 0) +#define BDC_MASK_MCW BIT(7) +#define BDC_GIE BIT(1) +#define BDC_GIP BIT(0) #define BDC_HLT 1 #define BDC_NOR 2 @@ -201,19 +201,19 @@ #define BD_CHAIN 0xf #define BD_TFS_SHIFT 4 -#define BD_SOT (1 << 26) -#define BD_EOT (1 << 27) -#define BD_ISP (1 << 29) -#define BD_IOC (1 << 30) -#define BD_SBF (1 << 31) +#define BD_SOT BIT(26) +#define BD_EOT BIT(27) +#define BD_ISP BIT(29) +#define BD_IOC BIT(30) +#define BD_SBF BIT(31) #define BD_INTR_TARGET(p) (((p) & 0x1f) << 27) -#define BDC_SRR_RWS (1 << 4) -#define BDC_SRR_RST (1 << 3) -#define BDC_SRR_ISR (1 << 2) -#define BDC_SRR_IE (1 << 1) -#define BDC_SRR_IP (1 << 0) +#define BDC_SRR_RWS BIT(4) +#define BDC_SRR_RST BIT(3) +#define BDC_SRR_ISR BIT(2) +#define BDC_SRR_IE BIT(1) +#define BDC_SRR_IP BIT(0) #define BDC_SRR_EPI(p) (((p) & (0xff << 24)) >> 24) #define BDC_SRR_DPI(p) (((p) & (0xff << 16)) >> 16) #define BDC_SRR_DPI_MASK 0x00ff0000 @@ -221,14 +221,14 @@ #define MARK_CHAIN_BD (BD_CHAIN|BD_EOT|BD_SOT) /* Control transfer BD specific fields */ -#define BD_DIR_IN (1 << 25) +#define BD_DIR_IN BIT(25) #define BDC_PTC_MASK 0xf0000000 /* status report defines */ #define SR_XSF 0 #define SR_USPC 4 -#define SR_BD_LEN(p) (p & 0xffffff) +#define SR_BD_LEN(p) ((p) & 0xffffff) #define XSF_SUCC 0x1 #define XSF_SHORT 0x3 @@ -241,13 +241,13 @@ /* Transfer BD fields */ #define BD_LEN(p) ((p) & 0x1ffff) -#define BD_LTF (1 << 25) +#define BD_LTF BIT(25) #define BD_TYPE_DS 0x1 #define BD_TYPE_SS 0x2 -#define BDC_EP_ENABLED (1 << 0) -#define BDC_EP_STALL (1 << 1) -#define BDC_EP_STOP (1 << 2) +#define BDC_EP_ENABLED BIT(0) +#define BDC_EP_STALL BIT(1) +#define BDC_EP_STOP BIT(2) /* One BD can transfer max 65536 bytes */ #define BD_MAX_BUFF_SIZE (1 << 16) @@ -266,9 +266,9 @@ /* FUNCTION WAKE DEV NOTIFICATION interval, USB3 spec table 8.13 */ #define BDC_TNOTIFY 2500 /*in ms*/ /* Devstatus bitfields */ -#define REMOTE_WAKEUP_ISSUED (1 << 16) -#define DEVICE_SUSPENDED (1 << 17) -#define FUNC_WAKE_ISSUED (1 << 18) +#define REMOTE_WAKEUP_ISSUED BIT(16) +#define DEVICE_SUSPENDED BIT(17) +#define FUNC_WAKE_ISSUED BIT(18) #define REMOTE_WAKE_ENABLE (1 << USB_DEVICE_REMOTE_WAKEUP) /* On disconnect, preserve these bits and clear rest */ @@ -466,24 +466,24 @@ static inline void bdc_writel(void __iomem *base, u32 offset, u32 value) } /* Buffer descriptor list operations */ -void bdc_notify_xfr(struct bdc *, u32); -void bdc_softconn(struct bdc *); -void bdc_softdisconn(struct bdc *); -int bdc_run(struct bdc *); -int bdc_stop(struct bdc *); -int bdc_reset(struct bdc *); -int bdc_udc_init(struct bdc *); -void bdc_udc_exit(struct bdc *); -int bdc_reinit(struct bdc *); +void bdc_notify_xfr(struct bdc *bdc, u32 epnum); +void bdc_softconn(struct bdc *bdc); +void bdc_softdisconn(struct bdc *bdc); +int bdc_run(struct bdc *bdc); +int bdc_stop(struct bdc *bdc); +int bdc_reset(struct bdc *bdc); +int bdc_udc_init(struct bdc *bdc); +void bdc_udc_exit(struct bdc *bdc); +int bdc_reinit(struct bdc *bdc); /* Status report handlers */ /* Upstream port status change sr */ -void bdc_sr_uspc(struct bdc *, struct bdc_sr *); +void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport); /* transfer sr */ -void bdc_sr_xsf(struct bdc *, struct bdc_sr *); +void bdc_sr_xsf(struct bdc *bdc, struct bdc_sr *sreport); /* EP0 XSF handlers */ -void bdc_xsf_ep0_setup_recv(struct bdc *, struct bdc_sr *); -void bdc_xsf_ep0_data_start(struct bdc *, struct bdc_sr *); -void bdc_xsf_ep0_status_start(struct bdc *, struct bdc_sr *); +void bdc_xsf_ep0_setup_recv(struct bdc *bdc, struct bdc_sr *sreport); +void bdc_xsf_ep0_data_start(struct bdc *bdc, struct bdc_sr *sreport); +void bdc_xsf_ep0_status_start(struct bdc *bdc, struct bdc_sr *sreport); #endif /* __LINUX_BDC_H__ */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_cmd.c b/drivers/usb/gadget/udc/bdc/bdc_cmd.c index 44c2a5eef7858..995f79c79f968 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_cmd.c +++ b/drivers/usb/gadget/udc/bdc/bdc_cmd.c @@ -163,7 +163,7 @@ int bdc_config_ep(struct bdc *bdc, struct bdc_ep *ep) usb_endpoint_xfer_isoc(desc)) { param2 |= si; if (usb_endpoint_xfer_isoc(desc) && comp_desc) - mul = comp_desc->bmAttributes; + mul = comp_desc->bmAttributes; } param2 |= mul << EPM_SHIFT; diff --git a/drivers/usb/gadget/udc/bdc/bdc_cmd.h b/drivers/usb/gadget/udc/bdc/bdc_cmd.h index 29cc988a671ac..533ad52fa6d04 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_cmd.h +++ b/drivers/usb/gadget/udc/bdc/bdc_cmd.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * bdc_cmd.h - header for the BDC debug functions * @@ -10,15 +10,14 @@ #define __LINUX_BDC_CMD_H__ /* Command operations */ -int bdc_address_device(struct bdc *, u32); -int bdc_config_ep(struct bdc *, struct bdc_ep *); -int bdc_dconfig_ep(struct bdc *, struct bdc_ep *); -int bdc_stop_ep(struct bdc *, int); -int bdc_ep_set_stall(struct bdc *, int); -int bdc_ep_clear_stall(struct bdc *, int); -int bdc_ep_set_halt(struct bdc_ep *, u32 , int); -int bdc_ep_bla(struct bdc *, struct bdc_ep *, dma_addr_t); -int bdc_function_wake(struct bdc*, u8); -int bdc_function_wake_fh(struct bdc*, u8); +int bdc_address_device(struct bdc *bdc, u32 add); +int bdc_config_ep(struct bdc *bdc, struct bdc_ep *ep); +int bdc_dconfig_ep(struct bdc *bdc, struct bdc_ep *ep); +int bdc_stop_ep(struct bdc *bdc, int epnum); +int bdc_ep_set_stall(struct bdc *bdc, int epnum); +int bdc_ep_clear_stall(struct bdc *bdc, int epnum); +int bdc_ep_bla(struct bdc *bdc, struct bdc_ep *ep, dma_addr_t dma_addr); +int bdc_function_wake(struct bdc *bdc, u8 intf); +int bdc_function_wake_fh(struct bdc *bdc, u8 intf); #endif /* __LINUX_BDC_CMD_H__ */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_dbg.c b/drivers/usb/gadget/udc/bdc/bdc_dbg.c index 7ba7448ad7439..9c03e13308ca1 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_dbg.c +++ b/drivers/usb/gadget/udc/bdc/bdc_dbg.c @@ -68,7 +68,7 @@ void bdc_dbg_srr(struct bdc *bdc, u32 srr_num) sr = bdc->srr.sr_bds; addr = bdc->srr.dma_addr; - dev_vdbg(bdc->dev, "bdc_dbg_srr sr:%p dqp_index:%d\n", + dev_vdbg(bdc->dev, "%s sr:%p dqp_index:%d\n", __func__, sr, bdc->srr.dqp_index); for (i = 0; i < NUM_SR_ENTRIES; i++) { sr = &bdc->srr.sr_bds[i]; diff --git a/drivers/usb/gadget/udc/bdc/bdc_dbg.h b/drivers/usb/gadget/udc/bdc/bdc_dbg.h index 373d5abffbb8e..acd8332f85844 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_dbg.h +++ b/drivers/usb/gadget/udc/bdc/bdc_dbg.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * bdc_dbg.h - header for the BDC debug functions * @@ -12,10 +12,10 @@ #include "bdc.h" #ifdef CONFIG_USB_GADGET_VERBOSE -void bdc_dbg_bd_list(struct bdc *, struct bdc_ep*); -void bdc_dbg_srr(struct bdc *, u32); -void bdc_dbg_regs(struct bdc *); -void bdc_dump_epsts(struct bdc *); +void bdc_dbg_bd_list(struct bdc *bdc, struct bdc_ep *ep); +void bdc_dbg_srr(struct bdc *bdc, u32 srr_num); +void bdc_dbg_regs(struct bdc *bdc); +void bdc_dump_epsts(struct bdc *bdc); #else static inline void bdc_dbg_regs(struct bdc *bdc) { } diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index fafdc9fdb4a50..8e2f20b12519d 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -68,7 +68,7 @@ static void ep_bd_list_free(struct bdc_ep *ep, u32 num_tabs) * check if the bd_table struct is allocated ? * if yes, then check if bd memory has been allocated, then * free the dma_pool and also the bd_table struct memory - */ + */ bd_table = bd_list->bd_table_array[index]; dev_dbg(bdc->dev, "bd_table:%p index:%d\n", bd_table, index); if (!bd_table) { @@ -147,7 +147,7 @@ static int ep_bd_list_alloc(struct bdc_ep *ep) /* Allocate memory for each table */ for (index = 0; index < num_tabs; index++) { /* Allocate memory for bd_table structure */ - bd_table = kzalloc(sizeof(struct bd_table), GFP_ATOMIC); + bd_table = kzalloc(sizeof(*bd_table), GFP_ATOMIC); if (!bd_table) goto fail; @@ -275,7 +275,7 @@ static inline int find_end_bdi(struct bdc_ep *ep, int next_hwd_bdi) end_bdi = next_hwd_bdi - 1; if (end_bdi < 0) end_bdi = ep->bd_list.max_bdi - 1; - else if ((end_bdi % (ep->bd_list.num_bds_table-1)) == 0) + else if ((end_bdi % (ep->bd_list.num_bds_table-1)) == 0) end_bdi--; return end_bdi; @@ -756,7 +756,7 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req) dev_dbg(bdc->dev, "%s ep:%s start:%d end:%d\n", __func__, ep->name, start_bdi, end_bdi); - dev_dbg(bdc->dev, "ep_dequeue ep=%p ep->desc=%p\n", + dev_dbg(bdc->dev, "%s ep=%p ep->desc=%p\n", __func__, ep, (void *)ep->usb_ep.desc); /* if still connected, stop the ep to see where the HW is ? */ if (!(bdc_readl(bdc->regs, BDC_USPC) & BDC_PST_MASK)) { @@ -795,7 +795,7 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req) start_pending = true; end_pending = true; } else if (end_bdi >= curr_hw_dqpi || end_bdi <= eqp_bdi) { - end_pending = true; + end_pending = true; } } else { if (start_bdi >= curr_hw_dqpi) { @@ -1405,7 +1405,7 @@ static int ep0_set_sel(struct bdc *bdc, } /* - * Queue a 0 byte bd only if wLength is more than the length and and length is + * Queue a 0 byte bd only if wLength is more than the length and length is * a multiple of MaxPacket then queue 0 byte BD */ static int ep0_queue_zlp(struct bdc *bdc) @@ -1858,12 +1858,12 @@ static int bdc_gadget_ep_enable(struct usb_ep *_ep, int ret; if (!_ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) { - pr_debug("bdc_gadget_ep_enable invalid parameters\n"); + pr_debug("%s invalid parameters\n", __func__); return -EINVAL; } if (!desc->wMaxPacketSize) { - pr_debug("bdc_gadget_ep_enable missing wMaxPacketSize\n"); + pr_debug("%s missing wMaxPacketSize\n", __func__); return -EINVAL; } diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.h b/drivers/usb/gadget/udc/bdc/bdc_ep.h index a37ff8033b4fd..4d3affd07a65a 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.h +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * bdc_ep.h - header for the BDC debug functions * @@ -9,9 +9,9 @@ #ifndef __LINUX_BDC_EP_H__ #define __LINUX_BDC_EP_H__ -int bdc_init_ep(struct bdc *); -int bdc_ep_disable(struct bdc_ep *); -int bdc_ep_enable(struct bdc_ep *); -void bdc_free_ep(struct bdc *); +int bdc_init_ep(struct bdc *bdc); +int bdc_ep_disable(struct bdc_ep *ep); +int bdc_ep_enable(struct bdc_ep *ep); +void bdc_free_ep(struct bdc *bdc); #endif /* __LINUX_BDC_EP_H__ */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c index 248426a3e88a7..5ac0ef88334eb 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_udc.c +++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c @@ -164,7 +164,7 @@ static void bdc_func_wake_timer(struct work_struct *work) /* * Check if host has started transferring on endpoints * FUNC_WAKE_ISSUED is cleared when transfer has started after resume - */ + */ if (bdc->devstatus & FUNC_WAKE_ISSUED) { dev_dbg(bdc->dev, "FUNC_WAKE_ISSUED FLAG IS STILL SET\n"); /* flag is still set, so again send func wake */ @@ -205,7 +205,7 @@ static void handle_link_state_change(struct bdc *bdc, u32 uspc) * if not then send function wake again every * TNotification secs until host initiates * transfer to BDC, USB3 spec Table 8.13 - */ + */ schedule_delayed_work( &bdc->func_wake_notify, msecs_to_jiffies(BDC_TNOTIFY)); @@ -379,7 +379,7 @@ static int bdc_udc_start(struct usb_gadget *gadget, * Run the controller from here and when BDC is connected to * Host then driver will receive a USPC SR with VBUS present * and then driver will do a softconnect. - */ + */ ret = bdc_run(bdc); if (ret) { dev_err(bdc->dev, "%s bdc run fail\n", __func__); @@ -530,7 +530,7 @@ int bdc_udc_init(struct bdc *bdc) bdc->gadget.name = BRCM_BDC_NAME; ret = devm_request_irq(bdc->dev, bdc->irq, bdc_udc_interrupt, - IRQF_SHARED , BRCM_BDC_NAME, bdc); + IRQF_SHARED, BRCM_BDC_NAME, bdc); if (ret) { dev_err(bdc->dev, "failed to request irq #%d %d\n", diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index ea114f922ccf6..f1e732f3d8f41 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -29,6 +29,7 @@ * @list: for use by the udc class driver * @vbus: for udcs who care about vbus status, this value is real vbus status; * for udcs who do not care about vbus status, this value is always true + * @started: the UDC's started state. True if the UDC had started. * * This represents the internal data structure which is used by the UDC-class * to hold information about udc driver and gadget together. @@ -39,6 +40,7 @@ struct usb_udc { struct device dev; struct list_head list; bool vbus; + bool started; }; static struct class *udc_class; @@ -1082,7 +1084,18 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); */ static inline int usb_gadget_udc_start(struct usb_udc *udc) { - return udc->gadget->ops->udc_start(udc->gadget, udc->driver); + int ret; + + if (udc->started) { + dev_err(&udc->dev, "UDC had already started\n"); + return -EBUSY; + } + + ret = udc->gadget->ops->udc_start(udc->gadget, udc->driver); + if (!ret) + udc->started = true; + + return ret; } /** @@ -1098,7 +1111,13 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc) */ static inline void usb_gadget_udc_stop(struct usb_udc *udc) { + if (!udc->started) { + dev_err(&udc->dev, "UDC had already stopped\n"); + return; + } + udc->gadget->ops->udc_stop(udc->gadget); + udc->started = false; } /** @@ -1222,6 +1241,8 @@ int usb_add_gadget(struct usb_gadget *gadget) udc->gadget = gadget; gadget->udc = udc; + udc->started = false; + mutex_lock(&udc_lock); list_add_tail(&udc->list, &udc_list); diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index d5e9d20c097d2..77610b5f7db5b 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -1954,7 +1954,7 @@ static void xudc_nonctrl_ep_handler(struct xusb_udc *udc, u8 epnum, if (intrstatus & (XUSB_STATUS_EP0_BUFF1_COMP_MASK << epnum)) ep->buffer0ready = 0; if (intrstatus & (XUSB_STATUS_EP0_BUFF2_COMP_MASK << epnum)) - ep->buffer1ready = 0; + ep->buffer1ready = false; if (list_empty(&ep->queue)) return; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 31e59309da1f7..b94f2a070c056 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -269,10 +269,14 @@ config USB_EHCI_HCD_AT91 config USB_EHCI_TEGRA tristate "NVIDIA Tegra HCD support" depends on ARCH_TEGRA - select USB_EHCI_ROOT_HUB_TT - select USB_TEGRA_PHY + select USB_CHIPIDEA + select USB_CHIPIDEA_HOST + select USB_CHIPIDEA_TEGRA help - This driver enables support for the internal USB Host Controllers + This option is deprecated now and the driver was removed, use + USB_CHIPIDEA_TEGRA instead. + + Enable support for the internal USB Host Controllers found in NVIDIA Tegra SoCs. The controllers are EHCI compliant. config USB_EHCI_HCD_PPC_OF diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index c1b08703af103..3e4d298d851f0 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -47,7 +47,6 @@ obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o obj-$(CONFIG_USB_EHCI_HCD_STI) += ehci-st.o obj-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o -obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o obj-$(CONFIG_USB_EHCI_BRCMSTB) += ehci-brcm.o obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c deleted file mode 100644 index 869d9c4de5fcd..0000000000000 --- a/drivers/usb/host/ehci-tegra.c +++ /dev/null @@ -1,604 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * EHCI-compliant USB host controller driver for NVIDIA Tegra SoCs - * - * Copyright (C) 2010 Google, Inc. - * Copyright (C) 2009 - 2013 NVIDIA Corporation - */ - -#include <linux/clk.h> -#include <linux/dma-mapping.h> -#include <linux/err.h> -#include <linux/gpio.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_gpio.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/reset.h> -#include <linux/slab.h> -#include <linux/usb/ehci_def.h> -#include <linux/usb/tegra_usb_phy.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> -#include <linux/usb/otg.h> - -#include "ehci.h" - -#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) - -#define TEGRA_USB_DMA_ALIGN 32 - -#define DRIVER_DESC "Tegra EHCI driver" -#define DRV_NAME "tegra-ehci" - -static struct hc_driver __read_mostly tegra_ehci_hc_driver; - -struct tegra_ehci_soc_config { - bool has_hostpc; -}; - -struct tegra_ehci_hcd { - struct clk *clk; - struct reset_control *rst; - int port_resuming; - bool needs_double_reset; -}; - -static int tegra_reset_usb_controller(struct platform_device *pdev) -{ - struct device_node *phy_np; - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct tegra_ehci_hcd *tegra = - (struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv; - struct reset_control *rst; - int err; - - phy_np = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0); - if (!phy_np) - return -ENOENT; - - /* - * The 1st USB controller contains some UTMI pad registers that are - * global for all the controllers on the chip. Those registers are - * also cleared when reset is asserted to the 1st controller. - */ - rst = of_reset_control_get_shared(phy_np, "utmi-pads"); - if (IS_ERR(rst)) { - dev_warn(&pdev->dev, - "can't get utmi-pads reset from the PHY\n"); - dev_warn(&pdev->dev, - "continuing, but please update your DT\n"); - } else { - /* - * PHY driver performs UTMI-pads reset in a case of - * non-legacy DT. - */ - reset_control_put(rst); - } - - of_node_put(phy_np); - - /* reset control is shared, hence initialize it first */ - err = reset_control_deassert(tegra->rst); - if (err) - return err; - - err = reset_control_assert(tegra->rst); - if (err) - return err; - - udelay(1); - - err = reset_control_deassert(tegra->rst); - if (err) - return err; - - return 0; -} - -static int tegra_ehci_internal_port_reset( - struct ehci_hcd *ehci, - u32 __iomem *portsc_reg -) -{ - u32 temp; - unsigned long flags; - int retval = 0; - int i, tries; - u32 saved_usbintr; - - spin_lock_irqsave(&ehci->lock, flags); - saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable); - /* disable USB interrupt */ - ehci_writel(ehci, 0, &ehci->regs->intr_enable); - spin_unlock_irqrestore(&ehci->lock, flags); - - /* - * Here we have to do Port Reset at most twice for - * Port Enable bit to be set. - */ - for (i = 0; i < 2; i++) { - temp = ehci_readl(ehci, portsc_reg); - temp |= PORT_RESET; - ehci_writel(ehci, temp, portsc_reg); - mdelay(10); - temp &= ~PORT_RESET; - ehci_writel(ehci, temp, portsc_reg); - mdelay(1); - tries = 100; - do { - mdelay(1); - /* - * Up to this point, Port Enable bit is - * expected to be set after 2 ms waiting. - * USB1 usually takes extra 45 ms, for safety, - * we take 100 ms as timeout. - */ - temp = ehci_readl(ehci, portsc_reg); - } while (!(temp & PORT_PE) && tries--); - if (temp & PORT_PE) - break; - } - if (i == 2) - retval = -ETIMEDOUT; - - /* - * Clear Connect Status Change bit if it's set. - * We can't clear PORT_PEC. It will also cause PORT_PE to be cleared. - */ - if (temp & PORT_CSC) - ehci_writel(ehci, PORT_CSC, portsc_reg); - - /* - * Write to clear any interrupt status bits that might be set - * during port reset. - */ - temp = ehci_readl(ehci, &ehci->regs->status); - ehci_writel(ehci, temp, &ehci->regs->status); - - /* restore original interrupt enable bits */ - ehci_writel(ehci, saved_usbintr, &ehci->regs->intr_enable); - return retval; -} - -static int tegra_ehci_hub_control( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength -) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct tegra_ehci_hcd *tegra = (struct tegra_ehci_hcd *)ehci->priv; - u32 __iomem *status_reg; - u32 temp; - unsigned long flags; - int retval = 0; - - status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; - - spin_lock_irqsave(&ehci->lock, flags); - - if (typeReq == GetPortStatus) { - temp = ehci_readl(ehci, status_reg); - if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { - /* Resume completed, re-enable disconnect detection */ - tegra->port_resuming = 0; - tegra_usb_phy_postresume(hcd->usb_phy); - } - } - - else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { - temp = ehci_readl(ehci, status_reg); - if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) { - retval = -EPIPE; - goto done; - } - - temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E); - temp |= PORT_WKDISC_E | PORT_WKOC_E; - ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); - - /* - * If a transaction is in progress, there may be a delay in - * suspending the port. Poll until the port is suspended. - */ - if (ehci_handshake(ehci, status_reg, PORT_SUSPEND, - PORT_SUSPEND, 5000)) - pr_err("%s: timeout waiting for SUSPEND\n", __func__); - - set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports); - goto done; - } - - /* For USB1 port we need to issue Port Reset twice internally */ - if (tegra->needs_double_reset && - (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) { - spin_unlock_irqrestore(&ehci->lock, flags); - return tegra_ehci_internal_port_reset(ehci, status_reg); - } - - /* - * Tegra host controller will time the resume operation to clear the bit - * when the port control state switches to HS or FS Idle. This behavior - * is different from EHCI where the host controller driver is required - * to set this bit to a zero after the resume duration is timed in the - * driver. - */ - else if (typeReq == ClearPortFeature && - wValue == USB_PORT_FEAT_SUSPEND) { - temp = ehci_readl(ehci, status_reg); - if ((temp & PORT_RESET) || !(temp & PORT_PE)) { - retval = -EPIPE; - goto done; - } - - if (!(temp & PORT_SUSPEND)) - goto done; - - /* Disable disconnect detection during port resume */ - tegra_usb_phy_preresume(hcd->usb_phy); - - ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); - - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - /* start resume signalling */ - ehci_writel(ehci, temp | PORT_RESUME, status_reg); - set_bit(wIndex-1, &ehci->resuming_ports); - - spin_unlock_irqrestore(&ehci->lock, flags); - msleep(20); - spin_lock_irqsave(&ehci->lock, flags); - - /* Poll until the controller clears RESUME and SUSPEND */ - if (ehci_handshake(ehci, status_reg, PORT_RESUME, 0, 2000)) - pr_err("%s: timeout waiting for RESUME\n", __func__); - if (ehci_handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000)) - pr_err("%s: timeout waiting for SUSPEND\n", __func__); - - ehci->reset_done[wIndex-1] = 0; - clear_bit(wIndex-1, &ehci->resuming_ports); - - tegra->port_resuming = 1; - goto done; - } - - spin_unlock_irqrestore(&ehci->lock, flags); - - /* Handle the hub control events here */ - return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); - -done: - spin_unlock_irqrestore(&ehci->lock, flags); - return retval; -} - -struct dma_aligned_buffer { - void *kmalloc_ptr; - void *old_xfer_buffer; - u8 data[]; -}; - -static void free_dma_aligned_buffer(struct urb *urb) -{ - struct dma_aligned_buffer *temp; - size_t length; - - if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) - return; - - temp = container_of(urb->transfer_buffer, - struct dma_aligned_buffer, data); - - if (usb_urb_dir_in(urb)) { - if (usb_pipeisoc(urb->pipe)) - length = urb->transfer_buffer_length; - else - length = urb->actual_length; - - memcpy(temp->old_xfer_buffer, temp->data, length); - } - urb->transfer_buffer = temp->old_xfer_buffer; - kfree(temp->kmalloc_ptr); - - urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; -} - -static int alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) -{ - struct dma_aligned_buffer *temp, *kmalloc_ptr; - size_t kmalloc_size; - - if (urb->num_sgs || urb->sg || - urb->transfer_buffer_length == 0 || - !((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1))) - return 0; - - /* Allocate a buffer with enough padding for alignment */ - kmalloc_size = urb->transfer_buffer_length + - sizeof(struct dma_aligned_buffer) + TEGRA_USB_DMA_ALIGN - 1; - - kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); - if (!kmalloc_ptr) - return -ENOMEM; - - /* Position our struct dma_aligned_buffer such that data is aligned */ - temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1; - temp->kmalloc_ptr = kmalloc_ptr; - temp->old_xfer_buffer = urb->transfer_buffer; - if (usb_urb_dir_out(urb)) - memcpy(temp->data, urb->transfer_buffer, - urb->transfer_buffer_length); - urb->transfer_buffer = temp->data; - - urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; - - return 0; -} - -static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - int ret; - - ret = alloc_dma_aligned_buffer(urb, mem_flags); - if (ret) - return ret; - - ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); - if (ret) - free_dma_aligned_buffer(urb); - - return ret; -} - -static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) -{ - usb_hcd_unmap_urb_for_dma(hcd, urb); - free_dma_aligned_buffer(urb); -} - -static const struct tegra_ehci_soc_config tegra30_soc_config = { - .has_hostpc = true, -}; - -static const struct tegra_ehci_soc_config tegra20_soc_config = { - .has_hostpc = false, -}; - -static const struct of_device_id tegra_ehci_of_match[] = { - { .compatible = "nvidia,tegra30-ehci", .data = &tegra30_soc_config }, - { .compatible = "nvidia,tegra20-ehci", .data = &tegra20_soc_config }, - { }, -}; - -static int tegra_ehci_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - const struct tegra_ehci_soc_config *soc_config; - struct resource *res; - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct tegra_ehci_hcd *tegra; - int err = 0; - int irq; - struct usb_phy *u_phy; - - match = of_match_device(tegra_ehci_of_match, &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "Error: No device match found\n"); - return -ENODEV; - } - soc_config = match->data; - - /* Right now device-tree probed devices don't get dma_mask set. - * Since shared usb code relies on it, set it here for now. - * Once we have dma capability bindings this can go away. - */ - err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (err) - return err; - - hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); - if (!hcd) { - dev_err(&pdev->dev, "Unable to create HCD\n"); - return -ENOMEM; - } - platform_set_drvdata(pdev, hcd); - ehci = hcd_to_ehci(hcd); - tegra = (struct tegra_ehci_hcd *)ehci->priv; - - hcd->has_tt = 1; - - tegra->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(tegra->clk)) { - dev_err(&pdev->dev, "Can't get ehci clock\n"); - err = PTR_ERR(tegra->clk); - goto cleanup_hcd_create; - } - - tegra->rst = devm_reset_control_get_shared(&pdev->dev, "usb"); - if (IS_ERR(tegra->rst)) { - dev_err(&pdev->dev, "Can't get ehci reset\n"); - err = PTR_ERR(tegra->rst); - goto cleanup_hcd_create; - } - - err = clk_prepare_enable(tegra->clk); - if (err) - goto cleanup_hcd_create; - - err = tegra_reset_usb_controller(pdev); - if (err) { - dev_err(&pdev->dev, "Failed to reset controller\n"); - goto cleanup_clk_en; - } - - u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); - if (IS_ERR(u_phy)) { - err = -EPROBE_DEFER; - goto cleanup_clk_en; - } - hcd->usb_phy = u_phy; - hcd->skip_phy_initialization = 1; - - tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node, - "nvidia,needs-double-reset"); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(hcd->regs)) { - err = PTR_ERR(hcd->regs); - goto cleanup_clk_en; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - ehci->caps = hcd->regs + 0x100; - ehci->has_hostpc = soc_config->has_hostpc; - - err = usb_phy_init(hcd->usb_phy); - if (err) { - dev_err(&pdev->dev, "Failed to initialize phy\n"); - goto cleanup_clk_en; - } - - u_phy->otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), - GFP_KERNEL); - if (!u_phy->otg) { - err = -ENOMEM; - goto cleanup_phy; - } - u_phy->otg->host = hcd_to_bus(hcd); - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - err = irq; - goto cleanup_phy; - } - - otg_set_host(u_phy->otg, &hcd->self); - - err = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (err) { - dev_err(&pdev->dev, "Failed to add USB HCD\n"); - goto cleanup_otg_set_host; - } - device_wakeup_enable(hcd->self.controller); - - return err; - -cleanup_otg_set_host: - otg_set_host(u_phy->otg, NULL); -cleanup_phy: - usb_phy_shutdown(hcd->usb_phy); -cleanup_clk_en: - clk_disable_unprepare(tegra->clk); -cleanup_hcd_create: - usb_put_hcd(hcd); - return err; -} - -static int tegra_ehci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct tegra_ehci_hcd *tegra = - (struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv; - - usb_remove_hcd(hcd); - otg_set_host(hcd->usb_phy->otg, NULL); - usb_phy_shutdown(hcd->usb_phy); - clk_disable_unprepare(tegra->clk); - usb_put_hcd(hcd); - - return 0; -} - -static void tegra_ehci_hcd_shutdown(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - -static struct platform_driver tegra_ehci_driver = { - .probe = tegra_ehci_probe, - .remove = tegra_ehci_remove, - .shutdown = tegra_ehci_hcd_shutdown, - .driver = { - .name = DRV_NAME, - .of_match_table = tegra_ehci_of_match, - } -}; - -static int tegra_ehci_reset(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - int txfifothresh; - - retval = ehci_setup(hcd); - if (retval) - return retval; - - /* - * We should really pull this value out of tegra_ehci_soc_config, but - * to avoid needing access to it, make use of the fact that Tegra20 is - * the only one so far that needs a value of 10, and Tegra20 is the - * only one which doesn't set has_hostpc. - */ - txfifothresh = ehci->has_hostpc ? 0x10 : 10; - ehci_writel(ehci, txfifothresh << 16, &ehci->regs->txfill_tuning); - - return 0; -} - -static const struct ehci_driver_overrides tegra_overrides __initconst = { - .extra_priv_size = sizeof(struct tegra_ehci_hcd), - .reset = tegra_ehci_reset, -}; - -static int __init ehci_tegra_init(void) -{ - if (usb_disabled()) - return -ENODEV; - - pr_info(DRV_NAME ": " DRIVER_DESC "\n"); - - ehci_init_driver(&tegra_ehci_hc_driver, &tegra_overrides); - - /* - * The Tegra HW has some unusual quirks, which require Tegra-specific - * workarounds. We override certain hc_driver functions here to - * achieve that. We explicitly do not enhance ehci_driver_overrides to - * allow this more easily, since this is an unusual case, and we don't - * want to encourage others to override these functions by making it - * too easy. - */ - - tegra_ehci_hc_driver.map_urb_for_dma = tegra_ehci_map_urb_for_dma; - tegra_ehci_hc_driver.unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma; - tegra_ehci_hc_driver.hub_control = tegra_ehci_hub_control; - - return platform_driver_register(&tegra_ehci_driver); -} -module_init(ehci_tegra_init); - -static void __exit ehci_tegra_cleanup(void) -{ - platform_driver_unregister(&tegra_ehci_driver); -} -module_exit(ehci_tegra_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra_ehci_of_match); diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 03a333797382f..a48452a6172b6 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -45,6 +45,7 @@ #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) #define USB_SUSP_CTRL 0x400 +#define USB_WAKE_ON_RESUME_EN BIT(2) #define USB_WAKE_ON_CNNT_EN_DEV BIT(3) #define USB_WAKE_ON_DISCON_EN_DEV BIT(4) #define USB_SUSP_CLR BIT(5) @@ -56,6 +57,15 @@ #define USB_SUSP_SET BIT(14) #define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16) +#define USB_PHY_VBUS_SENSORS 0x404 +#define B_SESS_VLD_WAKEUP_EN BIT(6) +#define B_VBUS_VLD_WAKEUP_EN BIT(14) +#define A_SESS_VLD_WAKEUP_EN BIT(22) +#define A_VBUS_VLD_WAKEUP_EN BIT(30) + +#define USB_PHY_VBUS_WAKEUP_ID 0x408 +#define VBUS_WAKEUP_WAKEUP_EN BIT(30) + #define USB1_LEGACY_CTRL 0x410 #define USB1_NO_LEGACY_MODE BIT(0) #define USB1_VBUS_SENSE_CTL_MASK (3 << 1) @@ -334,6 +344,11 @@ static int utmip_pad_power_on(struct tegra_usb_phy *phy) writel_relaxed(val, base + UTMIP_BIAS_CFG0); } + if (phy->pad_wakeup) { + phy->pad_wakeup = false; + utmip_pad_count--; + } + spin_unlock(&utmip_pad_lock); clk_disable_unprepare(phy->pad_clk); @@ -359,6 +374,17 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy) goto ulock; } + /* + * In accordance to TRM, OTG and Bias pad circuits could be turned off + * to save power if wake is enabled, but the VBUS-change detection + * method is board-specific and these circuits may need to be enabled + * to generate wakeup event, hence we will just keep them both enabled. + */ + if (phy->wakeup_enabled) { + phy->pad_wakeup = true; + utmip_pad_count++; + } + if (--utmip_pad_count == 0) { val = readl_relaxed(base + UTMIP_BIAS_CFG0); val |= UTMIP_OTGPD | UTMIP_BIASPD; @@ -503,11 +529,24 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) writel_relaxed(val, base + UTMIP_PLL_CFG1); } + val = readl_relaxed(base + USB_SUSP_CTRL); + val &= ~USB_WAKE_ON_RESUME_EN; + writel_relaxed(val, base + USB_SUSP_CTRL); + if (phy->mode == USB_DR_MODE_PERIPHERAL) { val = readl_relaxed(base + USB_SUSP_CTRL); val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); writel_relaxed(val, base + USB_SUSP_CTRL); + val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID); + val &= ~VBUS_WAKEUP_WAKEUP_EN; + writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID); + + val = readl_relaxed(base + USB_PHY_VBUS_SENSORS); + val &= ~(A_VBUS_VLD_WAKEUP_EN | A_SESS_VLD_WAKEUP_EN); + val &= ~(B_VBUS_VLD_WAKEUP_EN | B_SESS_VLD_WAKEUP_EN); + writel_relaxed(val, base + USB_PHY_VBUS_SENSORS); + val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0); val &= ~UTMIP_PD_CHRG; writel_relaxed(val, base + UTMIP_BAT_CHRG_CFG0); @@ -605,31 +644,51 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) utmi_phy_clk_disable(phy); - if (phy->mode == USB_DR_MODE_PERIPHERAL) { + /* PHY won't resume if reset is asserted */ + if (!phy->wakeup_enabled) { val = readl_relaxed(base + USB_SUSP_CTRL); - val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); - val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5); + val |= UTMIP_RESET; writel_relaxed(val, base + USB_SUSP_CTRL); } - val = readl_relaxed(base + USB_SUSP_CTRL); - val |= UTMIP_RESET; - writel_relaxed(val, base + USB_SUSP_CTRL); - val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0); val |= UTMIP_PD_CHRG; writel_relaxed(val, base + UTMIP_BAT_CHRG_CFG0); - val = readl_relaxed(base + UTMIP_XCVR_CFG0); - val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | - UTMIP_FORCE_PDZI_POWERDOWN; - writel_relaxed(val, base + UTMIP_XCVR_CFG0); + if (!phy->wakeup_enabled) { + val = readl_relaxed(base + UTMIP_XCVR_CFG0); + val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | + UTMIP_FORCE_PDZI_POWERDOWN; + writel_relaxed(val, base + UTMIP_XCVR_CFG0); + } val = readl_relaxed(base + UTMIP_XCVR_CFG1); val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | UTMIP_FORCE_PDDR_POWERDOWN; writel_relaxed(val, base + UTMIP_XCVR_CFG1); + if (phy->wakeup_enabled) { + val = readl_relaxed(base + USB_SUSP_CTRL); + val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); + val |= USB_WAKEUP_DEBOUNCE_COUNT(5); + val |= USB_WAKE_ON_RESUME_EN; + writel_relaxed(val, base + USB_SUSP_CTRL); + + /* + * Ask VBUS sensor to generate wake event once cable is + * connected. + */ + if (phy->mode == USB_DR_MODE_PERIPHERAL) { + val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID); + val |= VBUS_WAKEUP_WAKEUP_EN; + writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID); + + val = readl_relaxed(base + USB_PHY_VBUS_SENSORS); + val |= A_VBUS_VLD_WAKEUP_EN; + writel_relaxed(val, base + USB_PHY_VBUS_SENSORS); + } + } + return utmip_pad_power_off(phy); } @@ -765,6 +824,15 @@ static int ulpi_phy_power_off(struct tegra_usb_phy *phy) usleep_range(5000, 6000); clk_disable_unprepare(phy->clk); + /* + * Wakeup currently unimplemented for ULPI, thus PHY needs to be + * force-resumed. + */ + if (WARN_ON_ONCE(phy->wakeup_enabled)) { + ulpi_phy_power_on(phy); + return -EOPNOTSUPP; + } + return 0; } @@ -784,6 +852,9 @@ static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) phy->powered_on = true; + /* Let PHY settle down */ + usleep_range(2000, 2500); + return 0; } @@ -824,6 +895,15 @@ static void tegra_usb_phy_shutdown(struct usb_phy *u_phy) phy->freq = NULL; } +static int tegra_usb_phy_set_wakeup(struct usb_phy *u_phy, bool enable) +{ + struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy); + + phy->wakeup_enabled = enable; + + return 0; +} + static int tegra_usb_phy_set_suspend(struct usb_phy *u_phy, int suspend) { struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy); @@ -1195,6 +1275,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->u_phy.dev = &pdev->dev; tegra_phy->u_phy.init = tegra_usb_phy_init; tegra_phy->u_phy.shutdown = tegra_usb_phy_shutdown; + tegra_phy->u_phy.set_wakeup = tegra_usb_phy_set_wakeup; tegra_phy->u_phy.set_suspend = tegra_usb_phy_set_suspend; platform_set_drvdata(pdev, tegra_phy); diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 2ca1409792c42..4e51f2969fc00 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -588,6 +588,7 @@ static void ucsi_unregister_partner(struct ucsi_connector *con) static void ucsi_partner_change(struct ucsi_connector *con) { + enum usb_role u_role = USB_ROLE_NONE; int ret; if (!con->partner) @@ -595,11 +596,14 @@ static void ucsi_partner_change(struct ucsi_connector *con) switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: - case UCSI_CONSTAT_PARTNER_TYPE_CABLE: case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: + u_role = USB_ROLE_HOST; + fallthrough; + case UCSI_CONSTAT_PARTNER_TYPE_CABLE: typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: + u_role = USB_ROLE_DEVICE; typec_set_data_role(con->port, TYPEC_DEVICE); break; default: @@ -610,6 +614,15 @@ static void ucsi_partner_change(struct ucsi_connector *con) if (!completion_done(&con->complete)) complete(&con->complete); + /* Only notify USB controller if partner supports USB data */ + if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & UCSI_CONSTAT_PARTNER_FLAG_USB)) + u_role = USB_ROLE_NONE; + + ret = usb_role_switch_set_role(con->usb_role_sw, u_role); + if (ret) + dev_err(con->ucsi->dev, "con:%d: failed to set usb role:%d\n", + con->num, u_role); + /* Can't rely on Partner Flags field. Always checking the alt modes. */ ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); if (ret) @@ -628,6 +641,7 @@ static void ucsi_handle_connector_change(struct work_struct *work) struct ucsi_connector_status pre_ack_status; struct ucsi_connector_status post_ack_status; enum typec_role role; + enum usb_role u_role = USB_ROLE_NONE; u16 inferred_changes; u16 changed_flags; u64 command; @@ -753,11 +767,14 @@ static void ucsi_handle_connector_change(struct work_struct *work) switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: - case UCSI_CONSTAT_PARTNER_TYPE_CABLE: case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: + u_role = USB_ROLE_HOST; + fallthrough; + case UCSI_CONSTAT_PARTNER_TYPE_CABLE: typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: + u_role = USB_ROLE_DEVICE; typec_set_data_role(con->port, TYPEC_DEVICE); break; default: @@ -770,6 +787,16 @@ static void ucsi_handle_connector_change(struct work_struct *work) ucsi_unregister_partner(con); ucsi_port_psy_changed(con); + + /* Only notify USB controller if partner supports USB data */ + if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & + UCSI_CONSTAT_PARTNER_FLAG_USB)) + u_role = USB_ROLE_NONE; + + ret = usb_role_switch_set_role(con->usb_role_sw, u_role); + if (ret) + dev_err(ucsi->dev, "con:%d: failed to set usb role:%d\n", + con->num, u_role); } if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE) @@ -988,6 +1015,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) struct ucsi_connector *con = &ucsi->connector[index]; struct typec_capability *cap = &con->typec_cap; enum typec_accessory *accessory = cap->accessory; + enum usb_role u_role = USB_ROLE_NONE; u64 command; int ret; @@ -1066,11 +1094,14 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: - case UCSI_CONSTAT_PARTNER_TYPE_CABLE: case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: + u_role = USB_ROLE_HOST; + fallthrough; + case UCSI_CONSTAT_PARTNER_TYPE_CABLE: typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: + u_role = USB_ROLE_DEVICE; typec_set_data_role(con->port, TYPEC_DEVICE); break; default: @@ -1086,6 +1117,24 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) ucsi_port_psy_changed(con); } + con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode); + if (IS_ERR(con->usb_role_sw)) { + dev_err(ucsi->dev, "con%d: failed to get usb role switch\n", + con->num); + con->usb_role_sw = NULL; + } + + /* Only notify USB controller if partner supports USB data */ + if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & UCSI_CONSTAT_PARTNER_FLAG_USB)) + u_role = USB_ROLE_NONE; + + ret = usb_role_switch_set_role(con->usb_role_sw, u_role); + if (ret) { + dev_err(ucsi->dev, "con:%d: failed to set usb role:%d\n", + con->num, u_role); + ret = 0; + } + if (con->partner) { ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); if (ret) { diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index dd9ba60ab4a30..3920e20a9e9ef 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -8,6 +8,7 @@ #include <linux/power_supply.h> #include <linux/types.h> #include <linux/usb/typec.h> +#include <linux/usb/role.h> /* -------------------------------------------------------------------------- */ @@ -331,6 +332,8 @@ struct ucsi_connector { u32 rdo; u32 src_pdos[UCSI_MAX_PDOS]; int num_pdos; + + struct usb_role_switch *usb_role_sw; }; int ucsi_send_command(struct ucsi *ucsi, u64 command, diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index c1c0bbc9f8b17..77a5b3f8736af 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -23,7 +23,7 @@ struct kmem_cache *stub_priv_cache; */ #define MAX_BUSID 16 static struct bus_id_priv busid_table[MAX_BUSID]; -static spinlock_t busid_table_lock; +static DEFINE_SPINLOCK(busid_table_lock); static void init_busid_table(void) { @@ -35,8 +35,6 @@ static void init_busid_table(void) */ memset(busid_table, 0, sizeof(busid_table)); - spin_lock_init(&busid_table_lock); - for (i = 0; i < MAX_BUSID; i++) spin_lock_init(&busid_table[i].busid_lock); } diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h index 8be857a4fa132..d60ce17d3dd2a 100644 --- a/drivers/usb/usbip/usbip_common.h +++ b/drivers/usb/usbip/usbip_common.h @@ -277,6 +277,10 @@ struct usbip_device { void (*reset)(struct usbip_device *); void (*unusable)(struct usbip_device *); } eh_ops; + +#ifdef CONFIG_KCOV + u64 kcov_handle; +#endif }; #define kthread_get_run(threadfn, data, namefmt, ...) \ @@ -337,4 +341,29 @@ static inline int interface_to_devnum(struct usb_interface *interface) return udev->devnum; } +#ifdef CONFIG_KCOV + +static inline void usbip_kcov_handle_init(struct usbip_device *ud) +{ + ud->kcov_handle = kcov_common_handle(); +} + +static inline void usbip_kcov_remote_start(struct usbip_device *ud) +{ + kcov_remote_start_common(ud->kcov_handle); +} + +static inline void usbip_kcov_remote_stop(void) +{ + kcov_remote_stop(); +} + +#else /* CONFIG_KCOV */ + +static inline void usbip_kcov_handle_init(struct usbip_device *ud) { } +static inline void usbip_kcov_remote_start(struct usbip_device *ud) { } +static inline void usbip_kcov_remote_stop(void) { } + +#endif /* CONFIG_KCOV */ + #endif /* __USBIP_COMMON_H */ diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c index 266024cbb64fe..7f2d1c241559f 100644 --- a/drivers/usb/usbip/vhci_rx.c +++ b/drivers/usb/usbip/vhci_rx.c @@ -261,7 +261,9 @@ int vhci_rx_loop(void *data) if (usbip_event_happened(ud)) break; + usbip_kcov_remote_start(ud); vhci_rx_pdu(ud); + usbip_kcov_remote_stop(); } return 0; diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index be37aec250c2b..96e5371dc335a 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -383,6 +383,7 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr, vdev->ud.sockfd = sockfd; vdev->ud.tcp_socket = socket; vdev->ud.status = VDEV_ST_NOTASSIGNED; + usbip_kcov_handle_init(&vdev->ud); spin_unlock(&vdev->ud.lock); spin_unlock_irqrestore(&vhci->lock, flags); diff --git a/include/linux/property.h b/include/linux/property.h index 0a9001fe7aeab..b0e413dc59271 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -488,4 +488,7 @@ fwnode_create_software_node(const struct property_entry *properties, const struct fwnode_handle *parent); void fwnode_remove_software_node(struct fwnode_handle *fwnode); +int device_add_software_node(struct device *dev, const struct software_node *swnode); +void device_remove_software_node(struct device *dev); + #endif /* _LINUX_PROPERTY_H_ */ diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 025b41687ce96..edf3342507f16 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -88,6 +88,12 @@ struct ci_hdrc_platform_data { struct pinctrl_state *pins_default; struct pinctrl_state *pins_host; struct pinctrl_state *pins_device; + + /* platform-specific hooks */ + int (*hub_control)(struct ci_hdrc *ci, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength, + bool *done, unsigned long *flags); + void (*enter_lpm)(struct ci_hdrc *ci, bool enable); }; /* Default offset of capability registers */ diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index a2d229ab63ba5..5646dad886e61 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -525,6 +525,8 @@ extern struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev, extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n); extern void composite_disconnect(struct usb_gadget *gadget); +extern void composite_reset(struct usb_gadget *gadget); + extern int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl); extern void composite_suspend(struct usb_gadget *gadget); diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index c29d1b4c93815..fd1c9f6a4e37f 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -79,6 +79,8 @@ struct tegra_usb_phy { bool is_ulpi_phy; struct gpio_desc *reset_gpio; struct reset_control *pad_rst; + bool wakeup_enabled; + bool pad_wakeup; bool powered_on; }; diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index fdd4d88a7b95d..d791cc58a7f03 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h @@ -102,6 +102,9 @@ struct usbtmc_message { #define USBTMC_IOCTL_MSG_IN_ATTR _IOR(USBTMC_IOC_NR, 24, __u8) #define USBTMC_IOCTL_AUTO_ABORT _IOW(USBTMC_IOC_NR, 25, __u8) +#define USBTMC_IOCTL_GET_STB _IOR(USBTMC_IOC_NR, 26, __u8) +#define USBTMC_IOCTL_GET_SRQ_STB _IOR(USBTMC_IOC_NR, 27, __u8) + /* Cancel and cleanup asynchronous calls */ #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35) #define USBTMC_IOCTL_CLEANUP_IO _IO(USBTMC_IOC_NR, 36) |
