USB/PHY driver updates for 5.8-rc1

Here are the large set of USB and PHY driver updates for 5.8-rc1.
 
 Nothing huge, just lots of little things:
 	- USB gadget fixes and additions all over the place
 	- new PHY drivers
 	- PHY driver fixes and updates
 	- XHCI driver updates
 	- musb driver updates
 	- more USB-serial driver ids added
 	- various USB quirks added
 	- thunderbolt minor updates and fixes
 	- typec updates and additions
 
 Full details are in the shortlog.
 
 All of these have been in linux-next for a while with no reported
 issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXtzqVA8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ynftwCfeanyI6TR5AdfJVZN50B6/ySvVwcAn07i9VRX
 tnt2kz0UqReYpLt0wyJ7
 =YP7o
 -----END PGP SIGNATURE-----

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

Pull USB/PHY driver updates from Greg KH:
 "Here are the large set of USB and PHY driver updates for 5.8-rc1.

  Nothing huge, just lots of little things:

   - USB gadget fixes and additions all over the place

   - new PHY drivers

   - PHY driver fixes and updates

   - XHCI driver updates

   - musb driver updates

   - more USB-serial driver ids added

   - various USB quirks added

   - thunderbolt minor updates and fixes

   - typec updates and additions

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'usb-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (245 commits)
  usb: dwc3: meson-g12a: fix USB2 PHY initialization on G12A and A1 SoCs
  usb: dwc3: meson-g12a: fix error path when fetching the reset line fails
  Revert "dt-bindings: usb: qcom,dwc3: Convert USB DWC3 bindings"
  Revert "dt-bindings: usb: qcom,dwc3: Add compatible for SC7180"
  Revert "dt-bindings: usb: qcom,dwc3: Introduce interconnect properties for Qualcomm DWC3 driver"
  USB: serial: ch341: fix lockup of devices with limited prescaler
  USB: serial: ch341: add basis for quirk detection
  CDC-ACM: heed quirk also in error handling
  USB: serial: option: add Telit LE910C1-EUX compositions
  usb: musb: Fix runtime PM imbalance on error
  usb: musb: jz4740: Prevent lockup when CONFIG_SMP is set
  usb: musb: mediatek: add reset FADDR to zero in reset interrupt handle
  usb: musb: use true for 'use_dma'
  usb: musb: start session in resume for host port
  usb: musb: return -ESHUTDOWN in urb when three-strikes error happened
  USB: serial: qcserial: add DW5816e QDL support
  thunderbolt: Add trivial .shutdown
  usb: dwc3: keystone: Turn on USB3 PHY before controller
  dt-bindings: usb: ti,keystone-dwc3.yaml: Add USB3.0 PHY property
  dt-bindings: usb: convert keystone-usb.txt to YAML
  ...
This commit is contained in:
Linus Torvalds 2020-06-07 09:42:16 -07:00
commit e611c0fe31
298 changed files with 7743 additions and 2673 deletions

View File

@ -0,0 +1,64 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/phy/amlogic,meson8b-usb2-phy.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Amlogic Meson8, Meson8b, Meson8m2 and GXBB USB2 PHY
maintainers:
- Martin Blumenstingl <martin.blumenstingl@googlemail.com>
properties:
compatible:
oneOf:
- items:
- enum:
- amlogic,meson8-usb2-phy
- amlogic,meson8b-usb2-phy
- amlogic,meson8m2-usb2-phy
- const: amlogic,meson-mx-usb2-phy
- const: amlogic,meson-gxbb-usb2-phy
reg:
maxItems: 1
clocks:
minItems: 2
clock-names:
items:
- const: usb_general
- const: usb
resets:
minItems: 1
"#phy-cells":
const: 0
phy-supply:
description:
Phandle to a regulator that provides power to the PHY. This
regulator will be managed during the PHY power on/off sequence.
required:
- compatible
- reg
- clocks
- clock-names
- "#phy-cells"
additionalProperties: false
examples:
- |
usb-phy@c0000000 {
compatible = "amlogic,meson-gxbb-usb2-phy";
reg = <0xc0000000 0x20>;
resets = <&reset_usb_phy>;
clocks = <&clk_usb_general>, <&reset_usb>;
clock-names = "usb_general", "usb";
phy-supply = <&usb_vbus>;
#phy-cells = <0>;
};

View File

@ -0,0 +1,52 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright (c) 2020 NXP
%YAML 1.2
---
$id: "http://devicetree.org/schemas/phy/cdns,salvo-phy.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Cadence SALVO PHY
maintainers:
- Peter Chen <peter.chen@nxp.com>
properties:
compatible:
enum:
- nxp,salvo-phy
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: salvo_phy_clk
power-domains:
maxItems: 1
"#phy-cells":
const: 0
required:
- compatible
- reg
- "#phy-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/firmware/imx/rsrc.h>
usb3phy: usb3-phy@5b160000 {
compatible = "nxp,salvo-phy";
reg = <0x5b160000 0x40000>;
clocks = <&usb3_lpcg 4>;
clock-names = "salvo_phy_clk";
power-domains = <&pd IMX_SC_R_USB_2_PHY>;
#phy-cells = <0>;
};

View File

@ -0,0 +1,101 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/intel,combo-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel ComboPhy Subsystem
maintainers:
- Dilip Kota <eswara.kota@linux.intel.com>
description: |
Intel Combophy subsystem supports PHYs for PCIe, EMAC and SATA
controllers. A single Combophy provides two PHY instances.
properties:
$nodename:
pattern: "combophy(@.*|-[0-9a-f])*$"
compatible:
items:
- const: intel,combophy-lgm
- const: intel,combo-phy
clocks:
maxItems: 1
reg:
items:
- description: ComboPhy core registers
- description: PCIe app core control registers
reg-names:
items:
- const: core
- const: app
resets:
maxItems: 4
reset-names:
items:
- const: phy
- const: core
- const: iphy0
- const: iphy1
intel,syscfg:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: Chip configuration registers handle and ComboPhy instance id
intel,hsio:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: HSIO registers handle and ComboPhy instance id on NOC
intel,aggregation:
type: boolean
description: |
Specify the flag to configure ComboPHY in dual lane mode.
intel,phy-mode:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Mode of the two phys in ComboPhy.
See dt-bindings/phy/phy.h for values.
"#phy-cells":
const: 1
required:
- compatible
- clocks
- reg
- reg-names
- intel,syscfg
- intel,hsio
- intel,phy-mode
- "#phy-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/phy/phy.h>
combophy@d0a00000 {
compatible = "intel,combophy-lgm", "intel,combo-phy";
clocks = <&cgu0 1>;
#phy-cells = <1>;
reg = <0xd0a00000 0x40000>,
<0xd0a40000 0x1000>;
reg-names = "core", "app";
resets = <&rcu0 0x50 6>,
<&rcu0 0x50 17>,
<&rcu0 0x50 23>,
<&rcu0 0x50 24>;
reset-names = "phy", "core", "iphy0", "iphy1";
intel,syscfg = <&sysconf 0>;
intel,hsio = <&hsiol 0>;
intel,phy-mode = <PHY_TYPE_PCIE>;
intel,aggregation;
};

View File

@ -1,31 +0,0 @@
* Amlogic Meson GXL and GXM USB3 PHY and OTG detection binding
Required properties:
- compatible: Should be "amlogic,meson-gxl-usb3-phy"
- #phys-cells: must be 0 (see phy-bindings.txt in this directory)
- reg: The base address and length of the registers
- interrupts: the interrupt specifier for the OTG detection
- clocks: phandles to the clocks for
- the USB3 PHY
- and peripheral mode/OTG detection
- clock-names: must contain "phy" and "peripheral"
- resets: phandle to the reset lines for:
- the USB3 PHY and
- peripheral mode/OTG detection
- reset-names: must contain "phy" and "peripheral"
Optional properties:
- phy-supply: see phy-bindings.txt in this directory
Example:
usb3_phy0: phy@78080 {
compatible = "amlogic,meson-gxl-usb3-phy";
#phy-cells = <0>;
reg = <0x0 0x78080 0x0 0x20>;
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clkc CLKID_USB_OTG>, <&clkc_AO CLKID_AO_CEC_32K>;
clock-names = "phy", "peripheral";
resets = <&reset RESET_USB_OTG>, <&reset RESET_USB_OTG>;
reset-names = "phy", "peripheral";
};

View File

@ -1,28 +0,0 @@
* Amlogic Meson8, Meson8b and GXBB USB2 PHY
Required properties:
- compatible: Depending on the platform this should be one of:
"amlogic,meson8-usb2-phy"
"amlogic,meson8b-usb2-phy"
"amlogic,meson-gxbb-usb2-phy"
- reg: The base address and length of the registers
- #phys-cells: should be 0 (see phy-bindings.txt in this directory)
- clocks: phandle and clock identifier for the phy clocks
- clock-names: "usb_general" and "usb"
Optional properties:
- resets: reference to the reset controller
- phy-supply: see phy-bindings.txt in this directory
Example:
usb0_phy: usb-phy@c0000000 {
compatible = "amlogic,meson-gxbb-usb2-phy";
#phy-cells = <0>;
reg = <0x0 0xc0000000 0x0 0x20>;
resets = <&reset RESET_USB_OTG>;
clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB0>;
clock-names = "usb_general", "usb";
phy-supply = <&usb_vbus>;
};

View File

@ -0,0 +1,313 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/phy/qcom,qmp-phy.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcomm QMP PHY controller
maintainers:
- Manu Gautam <mgautam@codeaurora.org>
description:
QMP phy controller supports physical layer functionality for a number of
controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.
properties:
compatible:
enum:
- qcom,ipq8074-qmp-pcie-phy
- qcom,msm8996-qmp-pcie-phy
- qcom,msm8996-qmp-ufs-phy
- qcom,msm8996-qmp-usb3-phy
- qcom,msm8998-qmp-pcie-phy
- qcom,msm8998-qmp-ufs-phy
- qcom,msm8998-qmp-usb3-phy
- qcom,sdm845-qhp-pcie-phy
- qcom,sdm845-qmp-pcie-phy
- qcom,sdm845-qmp-ufs-phy
- qcom,sdm845-qmp-usb3-uni-phy
- qcom,sm8150-qmp-ufs-phy
- qcom,sm8250-qmp-ufs-phy
reg:
items:
- description: Address and length of PHY's common serdes block.
"#clock-cells":
enum: [ 1, 2 ]
"#address-cells":
enum: [ 1, 2 ]
"#size-cells":
enum: [ 1, 2 ]
clocks:
minItems: 1
maxItems: 4
clock-names:
minItems: 1
maxItems: 4
resets:
minItems: 1
maxItems: 3
reset-names:
minItems: 1
maxItems: 3
vdda-phy-supply:
description:
Phandle to a regulator supply to PHY core block.
vdda-pll-supply:
description:
Phandle to 1.8V regulator supply to PHY refclk pll block.
vddp-ref-clk-supply:
description:
Phandle to a regulator supply to any specific refclk
pll block.
#Required nodes:
patternProperties:
"^phy@[0-9a-f]+$":
type: object
description:
Each device node of QMP phy is required to have as many child nodes as
the number of lanes the PHY has.
required:
- compatible
- reg
- "#clock-cells"
- "#address-cells"
- "#size-cells"
- clocks
- clock-names
- resets
- reset-names
- vdda-phy-supply
- vdda-pll-supply
additionalProperties: false
allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,sdm845-qmp-usb3-uni-phy
then:
properties:
clocks:
items:
- description: Phy aux clock.
- description: Phy config clock.
- description: 19.2 MHz ref clk.
- description: Phy common block aux clock.
clock-names:
items:
- const: aux
- const: cfg_ahb
- const: ref
- const: com_aux
resets:
items:
- description: reset of phy block.
- description: phy common block reset.
reset-names:
items:
- const: phy
- const: common
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8996-qmp-pcie-phy
then:
properties:
clocks:
items:
- description: Phy aux clock.
- description: Phy config clock.
- description: 19.2 MHz ref clk.
clock-names:
items:
- const: aux
- const: cfg_ahb
- const: ref
resets:
items:
- description: reset of phy block.
- description: phy common block reset.
- description: phy's ahb cfg block reset.
reset-names:
items:
- const: phy
- const: common
- const: cfg
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8996-qmp-usb3-phy
- qcom,msm8998-qmp-pcie-phy
- qcom,msm8998-qmp-usb3-phy
then:
properties:
clocks:
items:
- description: Phy aux clock.
- description: Phy config clock.
- description: 19.2 MHz ref clk.
clock-names:
items:
- const: aux
- const: cfg_ahb
- const: ref
resets:
items:
- description: reset of phy block.
- description: phy common block reset.
reset-names:
items:
- const: phy
- const: common
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8996-qmp-ufs-phy
then:
properties:
clocks:
items:
- description: 19.2 MHz ref clk.
clock-names:
items:
- const: ref
resets:
items:
- description: PHY reset in the UFS controller.
reset-names:
items:
- const: ufsphy
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8998-qmp-ufs-phy
- qcom,sdm845-qmp-ufs-phy
- qcom,sm8150-qmp-ufs-phy
- qcom,sm8250-qmp-ufs-phy
then:
properties:
clocks:
items:
- description: 19.2 MHz ref clk.
- description: Phy reference aux clock.
clock-names:
items:
- const: ref
- const: ref_aux
resets:
items:
- description: PHY reset in the UFS controller.
reset-names:
items:
- const: ufsphy
- if:
properties:
compatible:
contains:
enum:
- qcom,ipq8074-qmp-pcie-phy
then:
properties:
clocks:
items:
- description: pipe clk.
clock-names:
items:
- const: pipe_clk
resets:
items:
- description: reset of phy block.
- description: phy common block reset.
reset-names:
items:
- const: phy
- const: common
- if:
properties:
compatible:
contains:
enum:
- qcom,sdm845-qhp-pcie-phy
- qcom,sdm845-qmp-pcie-phy
then:
properties:
clocks:
items:
- description: Phy aux clock.
- description: Phy config clock.
- description: 19.2 MHz ref clk.
- description: Phy refgen clk.
clock-names:
items:
- const: aux
- const: cfg_ahb
- const: ref
- const: refgen
resets:
items:
- description: reset of phy block.
reset-names:
items:
- const: phy
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sdm845.h>
usb_2_qmpphy: phy-wrapper@88eb000 {
compatible = "qcom,sdm845-qmp-usb3-uni-phy";
reg = <0 0x088eb000 0 0x18c>;
#clock-cells = <1>;
#address-cells = <2>;
#size-cells = <2>;
clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK >,
<&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
<&gcc GCC_USB3_SEC_CLKREF_CLK>,
<&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>;
clock-names = "aux", "cfg_ahb", "ref", "com_aux";
resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>,
<&gcc GCC_USB3_PHY_SEC_BCR>;
reset-names = "phy", "common";
vdda-phy-supply = <&vdda_usb2_ss_1p2>;
vdda-pll-supply = <&vdda_usb2_ss_core>;
usb_2_ssphy: phy@88eb200 {
reg = <0 0x088eb200 0 0x128>,
<0 0x088eb400 0 0x1fc>,
<0 0x088eb800 0 0x218>,
<0 0x088eb600 0 0x70>;
#clock-cells = <0>;
#phy-cells = <0>;
clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
clock-names = "pipe0";
clock-output-names = "usb3_uni_phy_pipe_clk_src";
};
};

View File

@ -0,0 +1,136 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/phy/qcom,qmp-usb3-dp-phy.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcomm QMP USB3 DP PHY controller
maintainers:
- Manu Gautam <mgautam@codeaurora.org>
properties:
compatible:
enum:
- qcom,sc7180-qmp-usb3-phy
- qcom,sdm845-qmp-usb3-phy
reg:
items:
- description: Address and length of PHY's common serdes block.
- description: Address and length of the DP_COM control block.
reg-names:
items:
- const: reg-base
- const: dp_com
"#clock-cells":
enum: [ 1, 2 ]
"#address-cells":
enum: [ 1, 2 ]
"#size-cells":
enum: [ 1, 2 ]
clocks:
items:
- description: Phy aux clock.
- description: Phy config clock.
- description: 19.2 MHz ref clk.
- description: Phy common block aux clock.
clock-names:
items:
- const: aux
- const: cfg_ahb
- const: ref
- const: com_aux
resets:
items:
- description: reset of phy block.
- description: phy common block reset.
reset-names:
items:
- const: phy
- const: common
vdda-phy-supply:
description:
Phandle to a regulator supply to PHY core block.
vdda-pll-supply:
description:
Phandle to 1.8V regulator supply to PHY refclk pll block.
vddp-ref-clk-supply:
description:
Phandle to a regulator supply to any specific refclk
pll block.
#Required nodes:
patternProperties:
"^phy@[0-9a-f]+$":
type: object
description:
Each device node of QMP phy is required to have as many child nodes as
the number of lanes the PHY has.
required:
- compatible
- reg
- reg-names
- "#clock-cells"
- "#address-cells"
- "#size-cells"
- clocks
- clock-names
- resets
- reset-names
- vdda-phy-supply
- vdda-pll-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sdm845.h>
usb_1_qmpphy: phy-wrapper@88e9000 {
compatible = "qcom,sdm845-qmp-usb3-phy";
reg = <0 0x088e9000 0 0x18c>,
<0 0x088e8000 0 0x10>;
reg-names = "reg-base", "dp_com";
#clock-cells = <1>;
#address-cells = <2>;
#size-cells = <2>;
clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>,
<&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
<&gcc GCC_USB3_PRIM_CLKREF_CLK>,
<&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>;
clock-names = "aux", "cfg_ahb", "ref", "com_aux";
resets = <&gcc GCC_USB3_PHY_PRIM_BCR>,
<&gcc GCC_USB3_DP_PHY_PRIM_BCR>;
reset-names = "phy", "common";
vdda-phy-supply = <&vdda_usb2_ss_1p2>;
vdda-pll-supply = <&vdda_usb2_ss_core>;
usb_1_ssphy: phy@88e9200 {
reg = <0 0x088e9200 0 0x128>,
<0 0x088e9400 0 0x200>,
<0 0x088e9c00 0 0x218>,
<0 0x088e9600 0 0x128>,
<0 0x088e9800 0 0x200>,
<0 0x088e9a00 0 0x100>;
#clock-cells = <0>;
#phy-cells = <0>;
clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
clock-names = "pipe0";
clock-output-names = "usb3_phy_pipe_clk_src";
};
};

View File

@ -0,0 +1,80 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/phy/qcom,usb-snps-femto-v2.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcomm Synopsys Femto High-Speed USB PHY V2
maintainers:
- Wesley Cheng <wcheng@codeaurora.org>
description: |
Qualcomm High-Speed USB PHY
properties:
compatible:
enum:
- qcom,usb-snps-hs-7nm-phy
- qcom,sm8150-usb-hs-phy
- qcom,usb-snps-femto-v2-phy
reg:
maxItems: 1
"#phy-cells":
const: 0
clocks:
items:
- description: rpmhcc ref clock
clock-names:
items:
- const: ref
resets:
items:
- description: PHY core reset
vdda-pll-supply:
description: phandle to the regulator VDD supply node.
vdda18-supply:
description: phandle to the regulator 1.8V supply node.
vdda33-supply:
description: phandle to the regulator 3.3V supply node.
required:
- compatible
- reg
- "#phy-cells"
- clocks
- clock-names
- resets
- vdda-pll-supply
- vdda18-supply
- vdda33-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/clock/qcom,gcc-sm8150.h>
phy@88e2000 {
compatible = "qcom,sm8150-usb-hs-phy";
reg = <0 0x088e2000 0 0x400>;
#phy-cells = <0>;
clocks = <&rpmhcc RPMH_CXO_CLK>;
clock-names = "ref";
resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
vdda-pll-supply = <&vdd_usb_hs_core>;
vdda33-supply = <&vdda_usb_hs_3p1>;
vdda18-supply = <&vdda_usb_hs_1p8>;
};
...

View File

@ -1,242 +0,0 @@
Qualcomm QMP PHY controller
===========================
QMP phy controller supports physical layer functionality for a number of
controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.
Required properties:
- compatible: compatible list, contains:
"qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
"qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
"qcom,msm8996-qmp-ufs-phy" for 14nm UFS phy on msm8996,
"qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
"qcom,msm8998-qmp-usb3-phy" for USB3 QMP V3 phy on msm8998,
"qcom,msm8998-qmp-ufs-phy" for UFS QMP phy on msm8998,
"qcom,msm8998-qmp-pcie-phy" for PCIe QMP phy on msm8998,
"qcom,sdm845-qhp-pcie-phy" for QHP PCIe phy on sdm845,
"qcom,sdm845-qmp-pcie-phy" for QMP PCIe phy on sdm845,
"qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
"qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845,
"qcom,sdm845-qmp-ufs-phy" for UFS QMP phy on sdm845,
"qcom,sm8150-qmp-ufs-phy" for UFS QMP phy on sm8150.
- reg:
- index 0: address and length of register set for PHY's common
serdes block.
- index 1: address and length of the DP_COM control block (for
"qcom,sdm845-qmp-usb3-phy" only).
- reg-names:
- For "qcom,sdm845-qmp-usb3-phy":
- Should be: "reg-base", "dp_com"
- For all others:
- The reg-names property shouldn't be defined.
- #address-cells: must be 1
- #size-cells: must be 1
- ranges: must be present
- clocks: a list of phandles and clock-specifier pairs,
one for each entry in clock-names.
- clock-names: "cfg_ahb" for phy config clock,
"aux" for phy aux clock,
"ref" for 19.2 MHz ref clk,
"com_aux" for phy common block aux clock,
"ref_aux" for phy reference aux clock,
For "qcom,ipq8074-qmp-pcie-phy": no clocks are listed.
For "qcom,msm8996-qmp-pcie-phy" must contain:
"aux", "cfg_ahb", "ref".
For "qcom,msm8996-qmp-ufs-phy" must contain:
"ref".
For "qcom,msm8996-qmp-usb3-phy" must contain:
"aux", "cfg_ahb", "ref".
For "qcom,msm8998-qmp-usb3-phy" must contain:
"aux", "cfg_ahb", "ref".
For "qcom,msm8998-qmp-ufs-phy" must contain:
"ref", "ref_aux".
For "qcom,msm8998-qmp-pcie-phy" must contain:
"aux", "cfg_ahb", "ref".
For "qcom,sdm845-qhp-pcie-phy" must contain:
"aux", "cfg_ahb", "ref", "refgen".
For "qcom,sdm845-qmp-pcie-phy" must contain:
"aux", "cfg_ahb", "ref", "refgen".
For "qcom,sdm845-qmp-usb3-phy" must contain:
"aux", "cfg_ahb", "ref", "com_aux".
For "qcom,sdm845-qmp-usb3-uni-phy" must contain:
"aux", "cfg_ahb", "ref", "com_aux".
For "qcom,sdm845-qmp-ufs-phy" must contain:
"ref", "ref_aux".
For "qcom,sm8150-qmp-ufs-phy" must contain:
"ref", "ref_aux".
- resets: a list of phandles and reset controller specifier pairs,
one for each entry in reset-names.
- reset-names: "phy" for reset of phy block,
"common" for phy common block reset,
"cfg" for phy's ahb cfg block reset,
"ufsphy" for the PHY reset in the UFS controller.
For "qcom,ipq8074-qmp-pcie-phy" must contain:
"phy", "common".
For "qcom,msm8996-qmp-pcie-phy" must contain:
"phy", "common", "cfg".
For "qcom,msm8996-qmp-ufs-phy": must contain:
"ufsphy".
For "qcom,msm8996-qmp-usb3-phy" must contain
"phy", "common".
For "qcom,msm8998-qmp-usb3-phy" must contain
"phy", "common".
For "qcom,msm8998-qmp-ufs-phy": must contain:
"ufsphy".
For "qcom,msm8998-qmp-pcie-phy" must contain:
"phy", "common".
For "qcom,sdm845-qhp-pcie-phy" must contain:
"phy".
For "qcom,sdm845-qmp-pcie-phy" must contain:
"phy".
For "qcom,sdm845-qmp-usb3-phy" must contain:
"phy", "common".
For "qcom,sdm845-qmp-usb3-uni-phy" must contain:
"phy", "common".
For "qcom,sdm845-qmp-ufs-phy": must contain:
"ufsphy".
For "qcom,sm8150-qmp-ufs-phy": must contain:
"ufsphy".
- vdda-phy-supply: Phandle to a regulator supply to PHY core block.
- vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
Optional properties:
- vddp-ref-clk-supply: Phandle to a regulator supply to any specific refclk
pll block.
Required nodes:
- Each device node of QMP phy is required to have as many child nodes as
the number of lanes the PHY has.
Required properties for child nodes of PCIe PHYs (one child per lane):
- reg: list of offset and length pairs of register sets for PHY blocks -
tx, rx, pcs, and pcs_misc (optional).
- #phy-cells: must be 0
Required properties for a single "lanes" child node of non-PCIe PHYs:
- reg: list of offset and length pairs of register sets for PHY blocks
For 1-lane devices:
tx, rx, pcs, and (optionally) pcs_misc
For 2-lane devices:
tx0, rx0, pcs, tx1, rx1, and (optionally) pcs_misc
- #phy-cells: must be 0
Required properties for child node of PCIe and USB3 qmp phys:
- clocks: a list of phandles and clock-specifier pairs,
one for each entry in clock-names.
- clock-names: Must contain following:
"pipe<lane-number>" for pipe clock specific to each lane.
- clock-output-names: Name of the PHY clock that will be the parent for
the above pipe clock.
For "qcom,ipq8074-qmp-pcie-phy":
- "pcie20_phy0_pipe_clk" Pipe Clock parent
(or)
"pcie20_phy1_pipe_clk"
- #clock-cells: must be 0
- Phy pll outputs pipe clocks for pipe based PHYs. These clocks are then
gate-controlled by the gcc.
Required properties for child node of PHYs with lane reset, AKA:
"qcom,msm8996-qmp-pcie-phy"
- resets: a list of phandles and reset controller specifier pairs,
one for each entry in reset-names.
- reset-names: Must contain following:
"lane<lane-number>" for reset specific to each lane.
Example:
phy@34000 {
compatible = "qcom,msm8996-qmp-pcie-phy";
reg = <0x34000 0x488>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>,
<&gcc GCC_PCIE_PHY_CFG_AHB_CLK>,
<&gcc GCC_PCIE_CLKREF_CLK>;
clock-names = "aux", "cfg_ahb", "ref";
vdda-phy-supply = <&pm8994_l28>;
vdda-pll-supply = <&pm8994_l12>;
resets = <&gcc GCC_PCIE_PHY_BCR>,
<&gcc GCC_PCIE_PHY_COM_BCR>,
<&gcc GCC_PCIE_PHY_COM_NOCSR_BCR>;
reset-names = "phy", "common", "cfg";
pciephy_0: lane@35000 {
reg = <0x35000 0x130>,
<0x35200 0x200>,
<0x35400 0x1dc>;
#clock-cells = <0>;
#phy-cells = <0>;
clocks = <&gcc GCC_PCIE_0_PIPE_CLK>;
clock-names = "pipe0";
clock-output-names = "pcie_0_pipe_clk_src";
resets = <&gcc GCC_PCIE_0_PHY_BCR>;
reset-names = "lane0";
};
pciephy_1: lane@36000 {
...
...
};
phy@88eb000 {
compatible = "qcom,sdm845-qmp-usb3-uni-phy";
reg = <0x88eb000 0x18c>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>,
<&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
<&gcc GCC_USB3_SEC_CLKREF_CLK>,
<&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>;
clock-names = "aux", "cfg_ahb", "ref", "com_aux";
resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>,
<&gcc GCC_USB3_PHY_SEC_BCR>;
reset-names = "phy", "common";
lane@88eb200 {
reg = <0x88eb200 0x128>,
<0x88eb400 0x1fc>,
<0x88eb800 0x218>,
<0x88eb600 0x70>;
#clock-cells = <0>;
#phy-cells = <0>;
clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
clock-names = "pipe0";
clock-output-names = "usb3_uni_phy_pipe_clk_src";
};
};
phy@1d87000 {
compatible = "qcom,sdm845-qmp-ufs-phy";
reg = <0x1d87000 0x18c>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
clock-names = "ref",
"ref_aux";
clocks = <&gcc GCC_UFS_MEM_CLKREF_CLK>,
<&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
lanes@1d87400 {
reg = <0x1d87400 0x108>,
<0x1d87600 0x1e0>,
<0x1d87c00 0x1dc>,
<0x1d87800 0x108>,
<0x1d87a00 0x1e0>;
#phy-cells = <0>;
};
};

View File

@ -0,0 +1,50 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/phy/qcom-usb-ipq4019-phy.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcom IPQ40xx Dakota HS/SS USB PHY
maintainers:
- Robert Marko <robert.marko@sartura.hr>
properties:
compatible:
enum:
- qcom,usb-ss-ipq4019-phy
- qcom,usb-hs-ipq4019-phy
reg:
maxItems: 1
resets:
maxItems: 2
reset-names:
items:
- const: por_rst
- const: srif_rst
"#phy-cells":
const: 0
required:
- compatible
- reg
- resets
- reset-names
- "#phy-cells"
examples:
- |
#include <dt-bindings/clock/qcom,gcc-ipq4019.h>
hsphy@a8000 {
#phy-cells = <0>;
compatible = "qcom,usb-hs-ipq4019-phy";
reg = <0xa8000 0x40>;
resets = <&gcc USB2_HSPHY_POR_ARES>,
<&gcc USB2_HSPHY_S_ARES>;
reset-names = "por_rst", "srif_rst";
};

View File

@ -1,70 +0,0 @@
* Renesas R-Car generation 3 USB 2.0 PHY
This file provides information on what the device node for the R-Car generation
3, RZ/G1C, RZ/G2 and RZ/A2 USB 2.0 PHY contain.
Required properties:
- compatible: "renesas,usb2-phy-r7s9210" if the device is a part of an R7S9210
SoC.
"renesas,usb2-phy-r8a77470" if the device is a part of an R8A77470
SoC.
"renesas,usb2-phy-r8a774a1" if the device is a part of an R8A774A1
SoC.
"renesas,usb2-phy-r8a774b1" if the device is a part of an R8A774B1
SoC.
"renesas,usb2-phy-r8a774c0" if the device is a part of an R8A774C0
SoC.
"renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
SoC.
"renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796
SoC.
"renesas,usb2-phy-r8a77965" if the device is a part of an
R8A77965 SoC.
"renesas,usb2-phy-r8a77990" if the device is a part of an
R8A77990 SoC.
"renesas,usb2-phy-r8a77995" if the device is a part of an
R8A77995 SoC.
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3, RZ/G2 or
RZ/A2 compatible device.
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first
followed by the generic version.
- reg: offset and length of the partial USB 2.0 Host register block.
- clocks: clock phandle and specifier pair(s).
- #phy-cells: see phy-bindings.txt in the same directory, must be <1> (and
using <0> is deprecated).
The phandle's argument in the PHY specifier is the INT_STATUS bit of controller:
- 1 = USBH_INTA (OHCI)
- 2 = USBH_INTB (EHCI)
- 3 = UCOM_INT (OTG and BC)
Optional properties:
To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are
combined, the device tree node should set interrupt properties to use the
channel as USB OTG:
- interrupts: interrupt specifier for the PHY.
- vbus-supply: Phandle to a regulator that provides power to the VBUS. This
regulator will be managed during the PHY power on/off sequence.
- renesas,no-otg-pins: boolean, specify when a board does not provide proper
otg pins.
- dr_mode: string, indicates the working mode for the PHY. Can be "host",
"peripheral", or "otg". Should be set if otg controller is not used.
Example (R-Car H3):
usb-phy@ee080200 {
compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
reg = <0 0xee080200 0 0x700>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 703>;
};
usb-phy@ee0a0200 {
compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
reg = <0 0xee0a0200 0 0x700>;
clocks = <&cpg CPG_MOD 702>;
};

View File

@ -1,52 +0,0 @@
* Renesas R-Car generation 3 USB 3.0 PHY
This file provides information on what the device node for the R-Car generation
3 and RZ/G2 USB 3.0 PHY contain.
If you want to enable spread spectrum clock (ssc), you should use USB_EXTAL
instead of USB3_CLK. However, if you don't want to these features, you don't
need this driver.
Required properties:
- compatible: "renesas,r8a774a1-usb3-phy" if the device is a part of an R8A774A1
SoC.
"renesas,r8a774b1-usb3-phy" if the device is a part of an R8A774B1
SoC.
"renesas,r8a7795-usb3-phy" if the device is a part of an R8A7795
SoC.
"renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796
SoC.
"renesas,r8a77965-usb3-phy" if the device is a part of an
R8A77965 SoC.
"renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 or RZ/G2
compatible device.
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first
followed by the generic version.
- reg: offset and length of the USB 3.0 PHY register block.
- clocks: A list of phandles and clock-specifier pairs.
- clock-names: Name of the clocks.
- The funcional clock must be "usb3-if".
- The usb3's external clock must be "usb3s_clk".
- The usb2's external clock must be "usb_extal". If you want to use the ssc,
the clock-frequency must not be 0.
- #phy-cells: see phy-bindings.txt in the same directory, must be <0>.
Optional properties:
- renesas,ssc-range: Enable/disable spread spectrum clock (ssc) by using
the following values as u32:
- 0 (or the property doesn't exist): disable the ssc
- 4980: enable the ssc as -4980 ppm
- 4492: enable the ssc as -4492 ppm
- 4003: enable the ssc as -4003 ppm
Example (R-Car H3):
usb-phy@e65ee000 {
compatible = "renesas,r8a7795-usb3-phy",
"renesas,rcar-gen3-usb3-phy";
reg = <0 0xe65ee000 0 0x90>;
clocks = <&cpg CPG_MOD 328>, <&usb3s0_clk>, <&usb_extal>;
clock-names = "usb3-if", "usb3s_clk", "usb_extal";
};

View File

@ -0,0 +1,117 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/renesas,usb2-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Car generation 3 USB 2.0 PHY
maintainers:
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
properties:
compatible:
oneOf:
- items:
- const: renesas,usb2-phy-r8a77470 # RZ/G1C
- items:
- enum:
- renesas,usb2-phy-r7s9210 # RZ/A2
- renesas,usb2-phy-r8a774a1 # RZ/G2M
- renesas,usb2-phy-r8a774b1 # RZ/G2N
- renesas,usb2-phy-r8a774c0 # RZ/G2E
- renesas,usb2-phy-r8a7795 # R-Car H3
- renesas,usb2-phy-r8a7796 # R-Car M3-W
- renesas,usb2-phy-r8a77961 # R-Car M3-W+
- renesas,usb2-phy-r8a77965 # R-Car M3-N
- renesas,usb2-phy-r8a77990 # R-Car E3
- renesas,usb2-phy-r8a77995 # R-Car D3
- const: renesas,rcar-gen3-usb2-phy
reg:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
clock-names:
minItems: 1
maxItems: 2
items:
- const: fck
- const: usb_x1
'#phy-cells':
enum: [0, 1] # and 0 is deprecated.
description: |
The phandle's argument in the PHY specifier is the INT_STATUS bit of
controller.
- 1 = USBH_INTA (OHCI)
- 2 = USBH_INTB (EHCI)
- 3 = UCOM_INT (OTG and BC)
interrupts:
maxItems: 1
power-domains:
maxItems: 1
resets:
minItems: 1
maxItems: 2
items:
- description: reset of USB 2.0 host side
- description: reset of USB 2.0 peripheral side
vbus-supply:
description: |
Phandle to a regulator that provides power to the VBUS. This regulator
will be managed during the PHY power on/off sequence.
renesas,no-otg-pins:
$ref: /schemas/types.yaml#/definitions/flag
description: |
specify when a board does not provide proper otg pins.
dr_mode: true
if:
properties:
compatible:
items:
enum:
- renesas,usb2-phy-r7s9210
then:
required:
- clock-names
required:
- compatible
- reg
- clocks
- '#phy-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7795-sysc.h>
usb-phy@ee080200 {
compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
reg = <0xee080200 0x700>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 703>;
#phy-cells = <1>;
};
usb-phy@ee0a0200 {
compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
reg = <0xee0a0200 0x700>;
clocks = <&cpg CPG_MOD 702>;
#phy-cells = <1>;
};

View File

@ -0,0 +1,79 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/renesas,usb3-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Car generation 3 USB 3.0 PHY
maintainers:
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
properties:
compatible:
items:
- enum:
- renesas,r8a774a1-usb3-phy # RZ/G2M
- renesas,r8a774b1-usb3-phy # RZ/G2N
- renesas,r8a7795-usb3-phy # R-Car H3
- renesas,r8a7796-usb3-phy # R-Car M3-W
- renesas,r8a77961-usb3-phy # R-Car M3-W+
- renesas,r8a77965-usb3-phy # R-Car M3-N
- const: renesas,rcar-gen3-usb3-phy
reg:
maxItems: 1
clocks:
minItems: 2
maxItems: 3
clock-names:
# If you want to use the ssc, the clock-frequency of usb_extal
# must not be 0.
minItems: 2
maxItems: 3
items:
- const: usb3-if # The funcional clock
- const: usb3s_clk # The usb3's external clock
- const: usb_extal # The usb2's external clock
'#phy-cells':
# see phy-bindings.txt in the same directory
const: 0
power-domains:
maxItems: 1
resets:
maxItems: 1
renesas,ssc-range:
description: |
Enable/disable spread spectrum clock (ssc). 0 or the property doesn't
exist means disabling the ssc. The actual value will be -<value> ppm.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [ 0, 4003, 4492, 4980 ]
required:
- compatible
- reg
- clocks
- clock-names
- '#phy-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
#include <dt-bindings/power/r8a7795-sysc.h>
usb-phy@e65ee000 {
compatible = "renesas,r8a7795-usb3-phy", "renesas,rcar-gen3-usb3-phy";
reg = <0xe65ee000 0x90>;
clocks = <&cpg CPG_MOD 328>, <&usb3s0_clk>, <&usb_extal>;
clock-names = "usb3-if", "usb3s_clk", "usb_extal";
#phy-cells = <0>;
};

View File

@ -1,42 +0,0 @@
Amlogic Meson GX DWC3 USB SoC controller
Required properties:
- compatible: depending on the SoC this should contain one of:
* amlogic,meson-axg-dwc3
* amlogic,meson-gxl-dwc3
- clocks: a handle for the "USB general" clock
- clock-names: must be "usb_general"
- resets: a handle for the shared "USB OTG" reset line
- reset-names: must be "usb_otg"
Required child node:
A child node must exist to represent the core DWC3 IP block. The name of
the node is not important. The content of the node is defined in dwc3.txt.
PHY documentation is provided in the following places:
- Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
- Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
Example device nodes:
usb0: usb@ff500000 {
compatible = "amlogic,meson-axg-dwc3";
#address-cells = <2>;
#size-cells = <2>;
ranges;
clocks = <&clkc CLKID_USB>;
clock-names = "usb_general";
resets = <&reset RESET_USB_OTG>;
reset-names = "usb_otg";
dwc3: dwc3@ff500000 {
compatible = "snps,dwc3";
reg = <0x0 0xff500000 0x0 0x100000>;
interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
dr_mode = "host";
maximum-speed = "high-speed";
snps,dis_u2_susphy_quirk;
phys = <&usb3_phy>, <&usb2_phy0>;
phy-names = "usb2-phy", "usb3-phy";
};
};

View File

@ -25,9 +25,13 @@ description: |
The Amlogic A1 embeds a DWC3 USB IP Core configured for USB2 in
host-only mode.
The Amlogic GXL & GXM SoCs doesn't embed an USB3 PHY.
properties:
compatible:
enum:
- amlogic,meson-gxl-usb-ctrl
- amlogic,meson-gxm-usb-ctrl
- amlogic,meson-g12a-usb-ctrl
- amlogic,meson-a1-usb-ctrl
@ -41,6 +45,11 @@ properties:
clocks:
minItems: 1
maxItems: 3
clock-names:
minItems: 1
maxItems: 3
resets:
minItems: 1
@ -52,10 +61,8 @@ properties:
maxItems: 1
phy-names:
items:
- const: usb2-phy0 # USB2 PHY0 if USBHOST_A port is used
- const: usb2-phy1 # USB2 PHY1 if USBOTG_B port is used
- const: usb3-phy0 # USB3 PHY if USB3_0 is used
minItems: 1
maxItems: 3
phys:
minItems: 1
@ -89,6 +96,61 @@ required:
- dr_mode
allOf:
- if:
properties:
compatible:
enum:
- amlogic,meson-g12a-usb-ctrl
then:
properties:
phy-names:
items:
- const: usb2-phy0 # USB2 PHY0 if USBHOST_A port is used
- const: usb2-phy1 # USB2 PHY1 if USBOTG_B port is used
- const: usb3-phy0 # USB3 PHY if USB3_0 is used
- if:
properties:
compatible:
enum:
- amlogic,meson-gxl-usb-ctrl
then:
properties:
clocks:
minItems: 2
clock-names:
items:
- const: usb_ctrl
- const: ddr
phy-names:
items:
- const: usb2-phy0 # USB2 PHY0 if USBHOST_A port is used
- const: usb2-phy1 # USB2 PHY1 if USBOTG_B port is used
required:
- clock-names
- if:
properties:
compatible:
enum:
- amlogic,meson-gxm-usb-ctrl
then:
properties:
clocks:
minItems: 2
clock-names:
items:
- const: usb_ctrl
- const: ddr
phy-names:
items:
- const: usb2-phy0 # USB2 PHY0 if USBHOST_A port is used
- const: usb2-phy1 # USB2 PHY1 if USBOTG_B port is used
- const: usb2-phy2 # USB2 PHY2 if USBOTG_C port is used
required:
- clock-names
- if:
properties:
compatible:
@ -97,6 +159,9 @@ allOf:
then:
properties:
phy-names:
items:
- const: usb2-phy1 # USB2 PHY1 if USBOTG_B port is used
clocks:
minItems: 3
clock-names:

View File

@ -50,6 +50,59 @@ properties:
minimum: 1
maximum: 21
vhub-vendor-id:
description: vhub Vendor ID
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- maximum: 65535
vhub-product-id:
description: vhub Product ID
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- maximum: 65535
vhub-device-revision:
description: vhub Device Revision in binary-coded decimal
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- maximum: 65535
vhub-strings:
type: object
properties:
'#address-cells':
const: 1
'#size-cells':
const: 0
patternProperties:
'^string@[0-9a-f]+$':
type: object
description: string descriptors of the specific language
properties:
reg:
maxItems: 1
description: 16-bit Language Identifier defined by USB-IF
manufacturer:
description: vhub manufacturer
allOf:
- $ref: /schemas/types.yaml#/definitions/string
product:
description: vhub product name
allOf:
- $ref: /schemas/types.yaml#/definitions/string
serial-number:
description: vhub device serial number
allOf:
- $ref: /schemas/types.yaml#/definitions/string
required:
- compatible
- reg
@ -72,4 +125,19 @@ examples:
aspeed,vhub-generic-endpoints = <15>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb2ad_default>;
vhub-vendor-id = <0x1d6b>;
vhub-product-id = <0x0107>;
vhub-device-revision = <0x0100>;
vhub-strings {
#address-cells = <1>;
#size-cells = <0>;
string@0409 {
reg = <0x0409>;
manufacturer = "ASPEED";
product = "USB Virtual Hub";
serial-number = "0000";
};
};
};

View File

@ -88,13 +88,15 @@ Required properties:
- clock-names: Should contain two strings
"pclk" for the peripheral clock
"hclk" for the host clock
Deprecated property:
- ep childnode: To specify the number of endpoints and their properties.
Optional properties:
- atmel,vbus-gpio: If present, specifies a gpio that allows to detect whether
vbus is present (USB is connected).
Required child node properties:
Deprecated child node properties:
- name: Name of the endpoint.
- reg: Num of the endpoint.
- atmel,fifo-size: Size of the fifo.
@ -112,56 +114,4 @@ usb2: gadget@fff78000 {
clocks = <&utmi>, <&udphs_clk>;
clock-names = "hclk", "pclk";
atmel,vbus-gpio = <&pioB 19 0>;
ep@0 {
reg = <0>;
atmel,fifo-size = <64>;
atmel,nb-banks = <1>;
};
ep@1 {
reg = <1>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@2 {
reg = <2>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@3 {
reg = <3>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
};
ep@4 {
reg = <4>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
};
ep@5 {
reg = <5>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
ep@6 {
reg = <6>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
};

View File

@ -0,0 +1,59 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/brcm,bcm7445-ehci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom STB USB EHCI Controller Device Tree Bindings
allOf:
- $ref: "usb-hcd.yaml"
maintainers:
- Al Cooper <alcooperx@gmail.com>
properties:
compatible:
const: brcm,bcm7445-ehci
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
description: Clock specifier for the EHCI clock
clock-names:
const: sw_usb
phys:
maxItems: 1
phy-names:
const: usbphy
required:
- compatible
- reg
- interrupts
- phys
- clocks
additionalProperties: false
examples:
- |
usb@f0b00300 {
compatible = "brcm,bcm7445-ehci";
reg = <0xf0b00300 0xa8>;
interrupts = <0x0 0x5a 0x0>;
phys = <&usbphy_0 0x0>;
phy-names = "usbphy";
clocks = <&usb20>;
clock-names = "sw_usb";
};
...

View File

@ -15,8 +15,6 @@ Required properties:
Exception for clocks:
clocks are optional if the parent node (i.e. glue-layer) is compatible to
one of the following:
"amlogic,meson-axg-dwc3"
"amlogic,meson-gxl-dwc3"
"cavium,octeon-7130-usb-uctl"
"qcom,dwc3"
"samsung,exynos5250-dwusb3"

View File

@ -1,56 +0,0 @@
TI Keystone Soc USB Controller
DWC3 GLUE
Required properties:
- compatible: should be
"ti,keystone-dwc3" for Keystone 2 SoCs
"ti,am654-dwc3" for AM654 SoC
- #address-cells, #size-cells : should be '1' if the device has sub-nodes
with 'reg' property.
- reg : Address and length of the register set for the USB subsystem on
the SOC.
- interrupts : The irq number of this device that is used to interrupt the
MPU.
- ranges: allows valid 1:1 translation between child's address space and
parent's address space.
SoC-specific Required Properties:
The following are mandatory properties for Keystone 2 66AK2HK, 66AK2L and 66AK2E
SoCs only:
- clocks: Clock ID for USB functional clock.
- clock-names: Must be "usb".
The following are mandatory properties for 66AK2G and AM654:
- power-domains: Should contain a phandle to a PM domain provider node
and an args specifier containing the USB device id
value. This property is as per the binding,
Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
Sub-nodes:
The dwc3 core should be added as subnode to Keystone DWC3 glue.
- dwc3 :
The binding details of dwc3 can be found in:
Documentation/devicetree/bindings/usb/dwc3.txt
Example:
usb: usb@2680000 {
compatible = "ti,keystone-dwc3";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x2680000 0x10000>;
clocks = <&clkusb>;
clock-names = "usb";
interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
ranges;
dwc3@2690000 {
compatible = "synopsys,dwc3";
reg = <0x2690000 0x70000>;
interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
usb-phy = <&usb_phy>, <&usb_phy>;
};
};

View File

@ -21,6 +21,7 @@ properties:
- enum:
- nvidia,tegra210-xudc # For Tegra210
- nvidia,tegra186-xudc # For Tegra186
- nvidia,tegra194-xudc # For Tegra194
reg:
minItems: 2
@ -144,6 +145,7 @@ allOf:
contains:
enum:
- nvidia,tegra186-xudc
- nvidia,tegra194-xudc
then:
properties:
reg:

View File

@ -0,0 +1,77 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/ti,keystone-dwc3.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI Keystone Soc USB Controller
maintainers:
- Roger Quadros <rogerq@ti.com>
properties:
compatible:
oneOf:
- const: "ti,keystone-dwc3"
- const: "ti,am654-dwc3"
reg:
maxItems: 1
description: Address and length of the register set for the USB subsystem on
the SOC.
interrupts:
maxItems: 1
description: The irq number of this device that is used to interrupt the MPU.
clocks:
description: Clock ID for USB functional clock.
power-domains:
description: Should contain a phandle to a PM domain provider node
and an args specifier containing the USB device id
value. This property is as per the binding,
Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
phys:
description:
PHY specifier for the USB3.0 PHY. Some SoCs need the USB3.0 PHY
to be turned on before the controller.
Documentation/devicetree/bindings/phy/phy-bindings.txt
phy-names:
items:
- const: "usb3-phy"
dwc3:
description: This is the node representing the DWC3 controller instance
Documentation/devicetree/bindings/usb/dwc3.txt
required:
- compatible
- reg
- interrupts
- clocks
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
usb: usb@2680000 {
compatible = "ti,keystone-dwc3";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x2680000 0x10000>;
clocks = <&clkusb>;
clock-names = "usb";
interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
ranges;
dwc3@2690000 {
compatible = "synopsys,dwc3";
reg = <0x2690000 0x70000>;
interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
usb-phy = <&usb_phy>, <&usb_phy>;
};
};

View File

@ -0,0 +1,64 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/usb/ti,tps6598x.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Texas Instruments 6598x Type-C Port Switch and Power Delivery controller DT bindings
maintainers:
- Bryan O'Donoghue <bryan.odonoghue@linaro.org>
description: |
Texas Instruments 6598x Type-C Port Switch and Power Delivery controller
properties:
compatible:
enum:
- ti,tps6598x
reg:
maxItems: 1
interrupts:
maxItems: 1
interrupt-names:
items:
- const: irq
required:
- compatible
- reg
- interrupts
- interrupt-names
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
tps6598x: tps6598x@38 {
compatible = "ti,tps6598x";
reg = <0x38>;
interrupt-parent = <&msmgpio>;
interrupts = <107 IRQ_TYPE_LEVEL_LOW>;
interrupt-names = "irq";
pinctrl-names = "default";
pinctrl-0 = <&typec_pins>;
typec_con: connector {
compatible = "usb-c-connector";
label = "USB-C";
port {
typec_ep: endpoint {
remote-endpoint = <&otg_ep>;
};
};
};
};
};
...

View File

@ -25,6 +25,7 @@ Required properties:
device
- "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 or RZ/G2 compatible
device
- "brcm,bcm7445-xhci" for Broadcom STB SoCs with XHCI
- "xhci-platform" (deprecated)
When compatible with the generic version, nodes must list the

View File

@ -0,0 +1,153 @@
.. SPDX-License-Identifier: GPL-2.0
=====================
Intel North Mux-Agent
=====================
Introduction
============
North Mux-Agent is a function of the Intel PMC firmware that is supported on
most Intel based platforms that have the PMC microcontroller. It's used for
configuring the various USB Multiplexer/DeMultiplexers on the system. The
platforms that allow the mux-agent to be configured from the operating system
have an ACPI device object (node) with HID "INTC105C" that represents it.
The North Mux-Agent (aka. Intel PMC Mux Control, or just mux-agent) driver
communicates with the PMC microcontroller by using the PMC IPC method
(drivers/platform/x86/intel_scu_ipc.c). The driver registers with the USB Type-C
Mux Class which allows the USB Type-C Controller and Interface drivers to
configure the cable plug orientation and mode (with Alternate Modes). The driver
also registers with the USB Role Class in order to support both USB Host and
Device modes. The driver is located here: drivers/usb/typec/mux/intel_pmc_mux.c.
Port nodes
==========
General
-------
For every USB Type-C connector under the mux-agent control on the system, there
is a separate child node under the PMC mux-agent device node. Those nodes do not
represent the actual connectors, but instead the "channels" in the mux-agent
that are associated with the connectors::
Scope (_SB.PCI0.PMC.MUX)
{
Device (CH0)
{
Name (_ADR, 0)
}
Device (CH1)
{
Name (_ADR, 1)
}
}
_PLD (Physical Location of Device)
----------------------------------
The optional _PLD object can be used with the port (the channel) nodes. If _PLD
is supplied, it should match the connector node _PLD::
Scope (_SB.PCI0.PMC.MUX)
{
Device (CH0)
{
Name (_ADR, 0)
Method (_PLD, 0, NotSerialized)
{
/* Consider this as pseudocode. */
Return (\_SB.USBC.CON0._PLD())
}
}
}
Mux-agent specific _DSD Device Properties
-----------------------------------------
Port Numbers
~~~~~~~~~~~~
In order to configure the muxes behind a USB Type-C connector, the PMC firmware
needs to know the USB2 port and the USB3 port that is associated with the
connector. The driver extracts the correct port numbers by reading specific _DSD
device properties named "usb2-port-number" and "usb3-port-number". These
properties have integer value that means the port index. The port index number
is 1's based, and value 0 is illegal. The driver uses the numbers extracted from
these device properties as-is when sending the mux-agent specific messages to
the PMC::
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package() {
Package () {"usb2-port-number", 6},
Package () {"usb3-port-number", 3},
},
})
Orientation
~~~~~~~~~~~
Depending on the platform, the data and SBU lines coming from the connector may
be "fixed" from the mux-agent's point of view, which means the mux-agent driver
should not configure them according to the cable plug orientation. This can
happen for example if a retimer on the platform handles the cable plug
orientation. The driver uses a specific device properties "sbu-orientation"
(SBU) and "hsl-orientation" (data) to know if those lines are "fixed", and to
which orientation. The value that these properties have is a string value, and
it can be one that is defined for the USB Type-C connector orientation: "normal"
or "reversed"::
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package() {
Package () {"sbu-orientation", "normal"},
Package () {"hsl-orientation", "normal"},
},
})
Example ASL
===========
The following ASL is an example that shows the mux-agent node, and two
connectors under its control::
Scope (_SB.PCI0.PMC)
{
Device (MUX)
{
Name (_HID, "INTC105C")
Device (CH0)
{
Name (_ADR, 0)
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package() {
Package () {"usb2-port-number", 6},
Package () {"usb3-port-number", 3},
Package () {"sbu-orientation", "normal"},
Package () {"hsl-orientation", "normal"},
},
})
}
Device (CH1)
{
Name (_ADR, 1)
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package() {
Package () {"usb2-port-number", 5},
Package () {"usb3-port-number", 2},
Package () {"sbu-orientation", "normal"},
Package () {"hsl-orientation", "normal"},
},
})
}
}
}

View File

@ -3500,6 +3500,14 @@ S: Supported
F: Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml
F: drivers/i2c/busses/i2c-brcmstb.c
BROADCOM BRCMSTB USB EHCI DRIVER
M: Al Cooper <alcooperx@gmail.com>
L: linux-usb@vger.kernel.org
L: bcm-kernel-feedback-list@broadcom.com
S: Maintained
F: Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml
F: drivers/usb/host/ehci-brcm.*
BROADCOM BRCMSTB USB2 and USB3 PHY DRIVER
M: Al Cooper <alcooperx@gmail.com>
L: linux-kernel@vger.kernel.org
@ -17759,6 +17767,13 @@ F: Documentation/driver-api/usb/typec.rst
F: drivers/usb/typec/
F: include/linux/usb/typec.h
USB TYPEC INTEL PMC MUX DRIVER
M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/firmware-guide/acpi/intel-pmc-mux.rst
F: drivers/usb/typec/mux/intel_pmc_mux.c
USB TYPEC PI3USB30532 MUX DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: linux-usb@vger.kernel.org

View File

@ -933,8 +933,6 @@ spi1: spi@fffa8000 {
};
usb2: gadget@fff78000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "atmel,at91sam9g45-udc";
reg = <0x00600000 0x80000
0xfff78000 0x400>;
@ -942,58 +940,6 @@ usb2: gadget@fff78000 {
clocks = <&pmc PMC_TYPE_PERIPHERAL 27>, <&pmc PMC_TYPE_CORE PMC_UTMI>;
clock-names = "pclk", "hclk";
status = "disabled";
ep@0 {
reg = <0>;
atmel,fifo-size = <64>;
atmel,nb-banks = <1>;
};
ep@1 {
reg = <1>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@2 {
reg = <2>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@3 {
reg = <3>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
};
ep@4 {
reg = <4>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
};
ep@5 {
reg = <5>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
ep@6 {
reg = <6>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
};
clk32k: sckc@fffffd50 {

View File

@ -299,8 +299,6 @@ trigger3 {
};
usb0: gadget@fffd4000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "atmel,at91sam9rl-udc";
reg = <0x00600000 0x100000>,
<0xfffd4000 0x4000>;
@ -308,58 +306,6 @@ usb0: gadget@fffd4000 {
clocks = <&pmc PMC_TYPE_PERIPHERAL 22>, <&pmc PMC_TYPE_CORE PMC_UTMI>;
clock-names = "pclk", "hclk";
status = "disabled";
ep@0 {
reg = <0>;
atmel,fifo-size = <64>;
atmel,nb-banks = <1>;
};
ep@1 {
reg = <1>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@2 {
reg = <2>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@3 {
reg = <3>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
};
ep@4 {
reg = <4>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
};
ep@5 {
reg = <5>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
ep@6 {
reg = <6>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
};
dma0: dma-controller@ffffe600 {

View File

@ -867,8 +867,6 @@ spi1: spi@f0004000 {
};
usb2: gadget@f803c000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "atmel,at91sam9g45-udc";
reg = <0x00500000 0x80000
0xf803c000 0x400>;
@ -876,58 +874,6 @@ usb2: gadget@f803c000 {
clocks = <&pmc PMC_TYPE_CORE PMC_UTMI>, <&pmc PMC_TYPE_PERIPHERAL 23>;
clock-names = "hclk", "pclk";
status = "disabled";
ep@0 {
reg = <0>;
atmel,fifo-size = <64>;
atmel,nb-banks = <1>;
};
ep@1 {
reg = <1>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@2 {
reg = <2>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@3 {
reg = <3>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
};
ep@4 {
reg = <4>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
};
ep@5 {
reg = <5>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
ep@6 {
reg = <6>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
};
watchdog: watchdog@fffffe40 {

View File

@ -109,8 +109,6 @@ nfc_sram: sram@100000 {
};
usb0: gadget@300000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "atmel,sama5d3-udc";
reg = <0x00300000 0x100000
0xfc02c000 0x400>;
@ -118,124 +116,6 @@ usb0: gadget@300000 {
clocks = <&pmc PMC_TYPE_PERIPHERAL 42>, <&pmc PMC_TYPE_CORE PMC_UTMI>;
clock-names = "pclk", "hclk";
status = "disabled";
ep@0 {
reg = <0>;
atmel,fifo-size = <64>;
atmel,nb-banks = <1>;
};
ep@1 {
reg = <1>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
ep@2 {
reg = <2>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
ep@3 {
reg = <3>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@4 {
reg = <4>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@5 {
reg = <5>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@6 {
reg = <6>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@7 {
reg = <7>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@8 {
reg = <8>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@9 {
reg = <9>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@10 {
reg = <10>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@11 {
reg = <11>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@12 {
reg = <12>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@13 {
reg = <13>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@14 {
reg = <14>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@15 {
reg = <15>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
};
usb1: ohci@400000 {

View File

@ -1076,8 +1076,6 @@ nfc_sram: sram@200000 {
};
usb0: gadget@500000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "atmel,sama5d3-udc";
reg = <0x00500000 0x100000
0xf8030000 0x4000>;
@ -1085,111 +1083,6 @@ usb0: gadget@500000 {
clocks = <&pmc PMC_TYPE_PERIPHERAL 33>, <&pmc PMC_TYPE_CORE PMC_UTMI>;
clock-names = "pclk", "hclk";
status = "disabled";
ep@0 {
reg = <0>;
atmel,fifo-size = <64>;
atmel,nb-banks = <1>;
};
ep@1 {
reg = <1>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
ep@2 {
reg = <2>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
ep@3 {
reg = <3>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
};
ep@4 {
reg = <4>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
};
ep@5 {
reg = <5>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
};
ep@6 {
reg = <6>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
};
ep@7 {
reg = <7>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
};
ep@8 {
reg = <8>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
};
ep@9 {
reg = <9>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
};
ep@10 {
reg = <10>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
};
ep@11 {
reg = <11>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
};
ep@12 {
reg = <12>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
};
ep@13 {
reg = <13>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
};
ep@14 {
reg = <14>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
};
ep@15 {
reg = <15>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
};
};
usb1: ohci@600000 {

View File

@ -96,8 +96,6 @@ nfc_sram: sram@100000 {
};
usb0: gadget@400000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "atmel,sama5d3-udc";
reg = <0x00400000 0x100000
0xfc02c000 0x4000>;
@ -105,124 +103,6 @@ usb0: gadget@400000 {
clocks = <&pmc PMC_TYPE_PERIPHERAL 47>, <&pmc PMC_TYPE_CORE PMC_UTMI>;
clock-names = "pclk", "hclk";
status = "disabled";
ep@0 {
reg = <0>;
atmel,fifo-size = <64>;
atmel,nb-banks = <1>;
};
ep@1 {
reg = <1>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
ep@2 {
reg = <2>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <3>;
atmel,can-dma;
atmel,can-isoc;
};
ep@3 {
reg = <3>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@4 {
reg = <4>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@5 {
reg = <5>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@6 {
reg = <6>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@7 {
reg = <7>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-dma;
atmel,can-isoc;
};
ep@8 {
reg = <8>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@9 {
reg = <9>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@10 {
reg = <10>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@11 {
reg = <11>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@12 {
reg = <12>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@13 {
reg = <13>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@14 {
reg = <14>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
ep@15 {
reg = <15>;
atmel,fifo-size = <1024>;
atmel,nb-banks = <2>;
atmel,can-isoc;
};
};
usb1: ohci@500000 {

View File

@ -2244,6 +2244,10 @@ usb_1: usb@a6f8800 {
resets = <&gcc GCC_USB30_PRIM_BCR>;
interconnects = <&aggre2_noc MASTER_USB3 &mc_virt SLAVE_EBI1>,
<&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_USB3>;
interconnect-names = "usb-ddr", "apps-usb";
usb_1_dwc3: dwc3@a600000 {
compatible = "snps,dwc3";
reg = <0 0x0a600000 0 0xe000>;

View File

@ -3136,6 +3136,10 @@ usb_1: usb@a6f8800 {
resets = <&gcc GCC_USB30_PRIM_BCR>;
interconnects = <&aggre2_noc MASTER_USB3_0 &mem_noc SLAVE_EBI1>,
<&gladiator_noc MASTER_APPSS_PROC &config_noc SLAVE_USB3_0>;
interconnect-names = "usb-ddr", "apps-usb";
usb_1_dwc3: dwc3@a600000 {
compatible = "snps,dwc3";
reg = <0 0x0a600000 0 0xcd00>;
@ -3180,6 +3184,10 @@ usb_2: usb@a8f8800 {
resets = <&gcc GCC_USB30_SEC_BCR>;
interconnects = <&aggre2_noc MASTER_USB3_1 &mem_noc SLAVE_EBI1>,
<&gladiator_noc MASTER_APPSS_PROC &config_noc SLAVE_USB3_1>;
interconnect-names = "usb-ddr", "apps-usb";
usb_2_dwc3: dwc3@a800000 {
compatible = "snps,dwc3";
reg = <0 0x0a800000 0 0xcd00>;

View File

@ -466,6 +466,24 @@ static struct gpio_desc *of_find_arizona_gpio(struct device *dev,
return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags);
}
static struct gpio_desc *of_find_usb_gpio(struct device *dev,
const char *con_id,
enum of_gpio_flags *of_flags)
{
/*
* Currently this USB quirk is only for the Fairchild FUSB302 host which is using
* an undocumented DT GPIO line named "fcs,int_n" without the compulsory "-gpios"
* suffix.
*/
if (!IS_ENABLED(CONFIG_TYPEC_FUSB302))
return ERR_PTR(-ENOENT);
if (!con_id || strcmp(con_id, "fcs,int_n"))
return ERR_PTR(-ENOENT);
return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags);
}
struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
unsigned int idx, unsigned long *flags)
{
@ -510,6 +528,9 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
if (PTR_ERR(desc) == -ENOENT)
desc = of_find_arizona_gpio(dev, con_id, &of_flags);
if (PTR_ERR(desc) == -ENOENT)
desc = of_find_usb_gpio(dev, con_id, &of_flags);
if (IS_ERR(desc))
return desc;

View File

@ -3,12 +3,13 @@
# Phy drivers for Amlogic platforms
#
config PHY_MESON8B_USB2
tristate "Meson8, Meson8b and GXBB USB2 PHY driver"
tristate "Meson8, Meson8b, Meson8m2 and GXBB USB2 PHY driver"
default ARCH_MESON
depends on OF && (ARCH_MESON || COMPILE_TEST)
depends on USB_SUPPORT
select USB_COMMON
select GENERIC_PHY
select REGMAP_MMIO
help
Enable this to support the Meson USB2 PHYs found in Meson8,
Meson8b and GXBB SoCs.
@ -26,18 +27,6 @@ config PHY_MESON_GXL_USB2
GXL and GXM SoCs.
If unsure, say N.
config PHY_MESON_GXL_USB3
tristate "Meson GXL and GXM USB3 PHY drivers"
default ARCH_MESON
depends on OF && (ARCH_MESON || COMPILE_TEST)
depends on USB_SUPPORT
select GENERIC_PHY
select REGMAP_MMIO
help
Enable this to support the Meson USB3 PHY and OTG detection
IP block found in Meson GXL and GXM SoCs.
If unsure, say N.
config PHY_MESON_G12A_USB2
tristate "Meson G12A USB2 PHY driver"
default ARCH_MESON

View File

@ -2,7 +2,6 @@
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o
obj-$(CONFIG_PHY_MESON_G12A_USB2) += phy-meson-g12a-usb2.o
obj-$(CONFIG_PHY_MESON_GXL_USB3) += phy-meson-gxl-usb3.o
obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE) += phy-meson-g12a-usb3-pcie.o
obj-$(CONFIG_PHY_MESON_AXG_PCIE) += phy-meson-axg-pcie.o
obj-$(CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG) += phy-meson-axg-mipi-pcie-analog.o

View File

@ -1,283 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Meson GXL USB3 PHY and OTG mode detection driver
*
* Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/platform_device.h>
#define USB_R0 0x00
#define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
#define USB_R0_P30_PHY_RESET BIT(6)
#define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7)
#define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8)
#define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9)
#define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14)
#define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
#define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
#define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
#define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
#define USB_R0_U2D_ACT BIT(31)
#define USB_R1 0x04
#define USB_R1_U3H_BIGENDIAN_GS BIT(0)
#define USB_R1_U3H_PME_ENABLE BIT(1)
#define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2)
#define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7)
#define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12)
#define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
#define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
#define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
#define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
#define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
#define USB_R2 0x08
#define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0)
#define USB_R2_P30_CR_READ BIT(16)
#define USB_R2_P30_CR_WRITE BIT(17)
#define USB_R2_P30_CR_CAP_ADDR BIT(18)
#define USB_R2_P30_CR_CAP_DATA BIT(19)
#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
#define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
#define USB_R3 0x0c
#define USB_R3_P30_SSC_ENABLE BIT(0)
#define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
#define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
#define USB_R3_P30_REF_SSP_EN BIT(13)
#define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16)
#define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19)
#define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24)
#define USB_R4 0x10
#define USB_R4_P21_PORT_RESET_0 BIT(0)
#define USB_R4_P21_SLEEP_M0 BIT(1)
#define USB_R4_MEM_PD_MASK GENMASK(3, 2)
#define USB_R4_P21_ONLY BIT(4)
#define USB_R5 0x14
#define USB_R5_ID_DIG_SYNC BIT(0)
#define USB_R5_ID_DIG_REG BIT(1)
#define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
#define USB_R5_ID_DIG_EN_0 BIT(4)
#define USB_R5_ID_DIG_EN_1 BIT(5)
#define USB_R5_ID_DIG_CURR BIT(6)
#define USB_R5_ID_DIG_IRQ BIT(7)
#define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
#define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
/* read-only register */
#define USB_R6 0x18
#define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
#define USB_R6_P30_CR_ACK BIT(16)
struct phy_meson_gxl_usb3_priv {
struct regmap *regmap;
enum phy_mode mode;
struct clk *clk_phy;
struct clk *clk_peripheral;
struct reset_control *reset;
};
static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
.reg_bits = 8,
.val_bits = 32,
.reg_stride = 4,
.max_register = USB_R6,
};
static int phy_meson_gxl_usb3_power_on(struct phy *phy)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0,
USB_R5_ID_DIG_EN_0);
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1,
USB_R5_ID_DIG_EN_1);
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_TH_MASK,
FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
return 0;
}
static int phy_meson_gxl_usb3_power_off(struct phy *phy)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0, 0);
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1, 0);
return 0;
}
static int phy_meson_gxl_usb3_set_mode(struct phy *phy,
enum phy_mode mode, int submode)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
switch (mode) {
case PHY_MODE_USB_HOST:
regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT, 0);
regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
0);
break;
case PHY_MODE_USB_DEVICE:
regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT,
USB_R0_U2D_ACT);
regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
USB_R4_P21_SLEEP_M0);
break;
default:
dev_err(&phy->dev, "unsupported PHY mode %d\n", mode);
return -EINVAL;
}
priv->mode = mode;
return 0;
}
static int phy_meson_gxl_usb3_init(struct phy *phy)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
int ret;
ret = reset_control_reset(priv->reset);
if (ret)
goto err;
ret = clk_prepare_enable(priv->clk_phy);
if (ret)
goto err;
ret = clk_prepare_enable(priv->clk_peripheral);
if (ret)
goto err_disable_clk_phy;
ret = phy_meson_gxl_usb3_set_mode(phy, priv->mode, 0);
if (ret)
goto err_disable_clk_peripheral;
regmap_update_bits(priv->regmap, USB_R1,
USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
return 0;
err_disable_clk_peripheral:
clk_disable_unprepare(priv->clk_peripheral);
err_disable_clk_phy:
clk_disable_unprepare(priv->clk_phy);
err:
return ret;
}
static int phy_meson_gxl_usb3_exit(struct phy *phy)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
clk_disable_unprepare(priv->clk_peripheral);
clk_disable_unprepare(priv->clk_phy);
return 0;
}
static const struct phy_ops phy_meson_gxl_usb3_ops = {
.power_on = phy_meson_gxl_usb3_power_on,
.power_off = phy_meson_gxl_usb3_power_off,
.set_mode = phy_meson_gxl_usb3_set_mode,
.init = phy_meson_gxl_usb3_init,
.exit = phy_meson_gxl_usb3_exit,
.owner = THIS_MODULE,
};
static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct phy_meson_gxl_usb3_priv *priv;
struct resource *res;
struct phy *phy;
struct phy_provider *phy_provider;
void __iomem *base;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
priv->regmap = devm_regmap_init_mmio(dev, base,
&phy_meson_gxl_usb3_regmap_conf);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
priv->clk_phy = devm_clk_get(dev, "phy");
if (IS_ERR(priv->clk_phy))
return PTR_ERR(priv->clk_phy);
priv->clk_peripheral = devm_clk_get(dev, "peripheral");
if (IS_ERR(priv->clk_peripheral))
return PTR_ERR(priv->clk_peripheral);
priv->reset = devm_reset_control_array_get_shared(dev);
if (IS_ERR(priv->reset))
return PTR_ERR(priv->reset);
/*
* default to host mode as hardware defaults and/or boot-loader
* behavior can result in this PHY starting up in device mode. this
* default and the initialization in phy_meson_gxl_usb3_init ensure
* that we reproducibly start in a known mode on all devices.
*/
priv->mode = PHY_MODE_USB_HOST;
phy = devm_phy_create(dev, np, &phy_meson_gxl_usb3_ops);
if (IS_ERR(phy)) {
ret = PTR_ERR(phy);
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to create PHY\n");
return ret;
}
phy_set_drvdata(phy, priv);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id phy_meson_gxl_usb3_of_match[] = {
{ .compatible = "amlogic,meson-gxl-usb3-phy", },
{ },
};
MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb3_of_match);
static struct platform_driver phy_meson_gxl_usb3_driver = {
.probe = phy_meson_gxl_usb3_probe,
.driver = {
.name = "phy-meson-gxl-usb3",
.of_match_table = phy_meson_gxl_usb3_of_match,
},
};
module_platform_driver(phy_meson_gxl_usb3_driver);
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
MODULE_DESCRIPTION("Meson GXL USB3 PHY and OTG detection driver");
MODULE_LICENSE("GPL v2");

View File

@ -10,6 +10,8 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
@ -76,6 +78,17 @@
#define REG_ADP_BC_ACA_PIN_FLOAT BIT(26)
#define REG_DBG_UART 0x10
#define REG_DBG_UART_BYPASS_SEL BIT(0)
#define REG_DBG_UART_BYPASS_DM_EN BIT(1)
#define REG_DBG_UART_BYPASS_DP_EN BIT(2)
#define REG_DBG_UART_BYPASS_DM_DATA BIT(3)
#define REG_DBG_UART_BYPASS_DP_DATA BIT(4)
#define REG_DBG_UART_FSV_MINUS BIT(5)
#define REG_DBG_UART_FSV_PLUS BIT(6)
#define REG_DBG_UART_FSV_BURN_IN_TEST BIT(7)
#define REG_DBG_UART_LOOPBACK_EN_B BIT(8)
#define REG_DBG_UART_SET_IDDQ BIT(9)
#define REG_DBG_UART_ATE_RESET BIT(10)
#define REG_TEST 0x14
#define REG_TEST_DATA_IN_MASK GENMASK(3, 0)
@ -104,35 +117,30 @@
#define RESET_COMPLETE_TIME 500
#define ACA_ENABLE_COMPLETE_TIME 50
struct phy_meson8b_usb2_priv {
void __iomem *regs;
enum usb_dr_mode dr_mode;
struct clk *clk_usb_general;
struct clk *clk_usb;
struct reset_control *reset;
struct phy_meson8b_usb2_match_data {
bool host_enable_aca;
};
static u32 phy_meson8b_usb2_read(struct phy_meson8b_usb2_priv *phy_priv,
u32 reg)
{
return readl(phy_priv->regs + reg);
}
struct phy_meson8b_usb2_priv {
struct regmap *regmap;
enum usb_dr_mode dr_mode;
struct clk *clk_usb_general;
struct clk *clk_usb;
struct reset_control *reset;
const struct phy_meson8b_usb2_match_data *match;
};
static void phy_meson8b_usb2_mask_bits(struct phy_meson8b_usb2_priv *phy_priv,
u32 reg, u32 mask, u32 value)
{
u32 data;
data = phy_meson8b_usb2_read(phy_priv, reg);
data &= ~mask;
data |= (value & mask);
writel(data, phy_priv->regs + reg);
}
static const struct regmap_config phy_meson8b_usb2_regmap_conf = {
.reg_bits = 8,
.val_bits = 32,
.reg_stride = 4,
.max_register = REG_TUNE,
};
static int phy_meson8b_usb2_power_on(struct phy *phy)
{
struct phy_meson8b_usb2_priv *priv = phy_get_drvdata(phy);
u32 reg;
int ret;
if (!IS_ERR_OR_NULL(priv->reset)) {
@ -156,38 +164,43 @@ static int phy_meson8b_usb2_power_on(struct phy *phy)
return ret;
}
phy_meson8b_usb2_mask_bits(priv, REG_CONFIG, REG_CONFIG_CLK_32k_ALTSEL,
REG_CONFIG_CLK_32k_ALTSEL);
regmap_update_bits(priv->regmap, REG_CONFIG, REG_CONFIG_CLK_32k_ALTSEL,
REG_CONFIG_CLK_32k_ALTSEL);
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_REF_CLK_SEL_MASK,
0x2 << REG_CTRL_REF_CLK_SEL_SHIFT);
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_REF_CLK_SEL_MASK,
0x2 << REG_CTRL_REF_CLK_SEL_SHIFT);
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_FSEL_MASK,
0x5 << REG_CTRL_FSEL_SHIFT);
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_FSEL_MASK,
0x5 << REG_CTRL_FSEL_SHIFT);
/* reset the PHY */
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_POWER_ON_RESET,
REG_CTRL_POWER_ON_RESET);
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET,
REG_CTRL_POWER_ON_RESET);
udelay(RESET_COMPLETE_TIME);
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_POWER_ON_RESET, 0);
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET, 0);
udelay(RESET_COMPLETE_TIME);
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT,
REG_CTRL_SOF_TOGGLE_OUT);
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT,
REG_CTRL_SOF_TOGGLE_OUT);
if (priv->dr_mode == USB_DR_MODE_HOST) {
phy_meson8b_usb2_mask_bits(priv, REG_ADP_BC,
regmap_update_bits(priv->regmap, REG_DBG_UART,
REG_DBG_UART_SET_IDDQ, 0);
if (priv->match->host_enable_aca) {
regmap_update_bits(priv->regmap, REG_ADP_BC,
REG_ADP_BC_ACA_ENABLE,
REG_ADP_BC_ACA_ENABLE);
udelay(ACA_ENABLE_COMPLETE_TIME);
udelay(ACA_ENABLE_COMPLETE_TIME);
if (phy_meson8b_usb2_read(priv, REG_ADP_BC) &
REG_ADP_BC_ACA_PIN_FLOAT) {
dev_warn(&phy->dev, "USB ID detect failed!\n");
clk_disable_unprepare(priv->clk_usb);
clk_disable_unprepare(priv->clk_usb_general);
return -EINVAL;
regmap_read(priv->regmap, REG_ADP_BC, &reg);
if (reg & REG_ADP_BC_ACA_PIN_FLOAT) {
dev_warn(&phy->dev, "USB ID detect failed!\n");
clk_disable_unprepare(priv->clk_usb);
clk_disable_unprepare(priv->clk_usb_general);
return -EINVAL;
}
}
}
@ -198,6 +211,11 @@ static int phy_meson8b_usb2_power_off(struct phy *phy)
{
struct phy_meson8b_usb2_priv *priv = phy_get_drvdata(phy);
if (priv->dr_mode == USB_DR_MODE_HOST)
regmap_update_bits(priv->regmap, REG_DBG_UART,
REG_DBG_UART_SET_IDDQ,
REG_DBG_UART_SET_IDDQ);
clk_disable_unprepare(priv->clk_usb);
clk_disable_unprepare(priv->clk_usb_general);
@ -213,18 +231,26 @@ static const struct phy_ops phy_meson8b_usb2_ops = {
static int phy_meson8b_usb2_probe(struct platform_device *pdev)
{
struct phy_meson8b_usb2_priv *priv;
struct resource *res;
struct phy *phy;
struct phy_provider *phy_provider;
void __iomem *base;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->regs))
return PTR_ERR(priv->regs);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
priv->match = device_get_match_data(&pdev->dev);
if (!priv->match)
return -ENODEV;
priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&phy_meson8b_usb2_regmap_conf);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
priv->clk_usb_general = devm_clk_get(&pdev->dev, "usb_general");
if (IS_ERR(priv->clk_usb_general))
@ -259,11 +285,32 @@ static int phy_meson8b_usb2_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct phy_meson8b_usb2_match_data phy_meson8_usb2_match_data = {
.host_enable_aca = false,
};
static const struct phy_meson8b_usb2_match_data phy_meson8b_usb2_match_data = {
.host_enable_aca = true,
};
static const struct of_device_id phy_meson8b_usb2_of_match[] = {
{ .compatible = "amlogic,meson8-usb2-phy", },
{ .compatible = "amlogic,meson8b-usb2-phy", },
{ .compatible = "amlogic,meson-gxbb-usb2-phy", },
{ },
{
.compatible = "amlogic,meson8-usb2-phy",
.data = &phy_meson8_usb2_match_data
},
{
.compatible = "amlogic,meson8b-usb2-phy",
.data = &phy_meson8b_usb2_match_data
},
{
.compatible = "amlogic,meson8m2-usb2-phy",
.data = &phy_meson8b_usb2_match_data
},
{
.compatible = "amlogic,meson-gxbb-usb2-phy",
.data = &phy_meson8b_usb2_match_data
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, phy_meson8b_usb2_of_match);
@ -277,5 +324,5 @@ static struct platform_driver phy_meson8b_usb2_driver = {
module_platform_driver(phy_meson8b_usb2_driver);
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
MODULE_DESCRIPTION("Meson8, Meson8b and GXBB USB2 PHY driver");
MODULE_DESCRIPTION("Meson8, Meson8b, Meson8m2 and GXBB USB2 PHY driver");
MODULE_LICENSE("GPL");

View File

@ -279,7 +279,7 @@ static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
static struct phy_ops ops = {
static const struct phy_ops ops = {
.init = ns2_drd_phy_init,
.power_on = ns2_drd_phy_poweron,
.power_off = ns2_drd_phy_poweroff,

View File

@ -16,8 +16,6 @@ enum bcm_usb_phy_version {
};
enum bcm_usb_phy_reg {
PLL_NDIV_FRAC,
PLL_NDIV_INT,
PLL_CTRL,
PHY_CTRL,
PHY_PLL_CTRL,
@ -31,18 +29,11 @@ static const u8 bcm_usb_combo_phy_ss[] = {
};
static const u8 bcm_usb_combo_phy_hs[] = {
[PLL_NDIV_FRAC] = 0x04,
[PLL_NDIV_INT] = 0x08,
[PLL_CTRL] = 0x0c,
[PHY_CTRL] = 0x10,
};
#define HSPLL_NDIV_INT_VAL 0x13
#define HSPLL_NDIV_FRAC_VAL 0x1005
static const u8 bcm_usb_hs_phy[] = {
[PLL_NDIV_FRAC] = 0x0,
[PLL_NDIV_INT] = 0x4,
[PLL_CTRL] = 0x8,
[PHY_CTRL] = 0xc,
};
@ -52,7 +43,6 @@ enum pll_ctrl_bits {
SSPLL_SUSPEND_EN,
PLL_SEQ_START,
PLL_LOCK,
PLL_PDIV,
};
static const u8 u3pll_ctrl[] = {
@ -66,29 +56,17 @@ static const u8 u3pll_ctrl[] = {
#define HSPLL_PDIV_VAL 0x1
static const u8 u2pll_ctrl[] = {
[PLL_PDIV] = 1,
[PLL_RESETB] = 5,
[PLL_LOCK] = 6,
};
enum bcm_usb_phy_ctrl_bits {
CORERDY,
AFE_LDO_PWRDWNB,
AFE_PLL_PWRDWNB,
AFE_BG_PWRDWNB,
PHY_ISO,
PHY_RESETB,
PHY_PCTL,
};
#define PHY_PCTL_MASK 0xffff
/*
* 0x0806 of PCTL_VAL has below bits set
* BIT-8 : refclk divider 1
* BIT-3:2: device mode; mode is not effect
* BIT-1: soft reset active low
*/
#define HSPHY_PCTL_VAL 0x0806
#define SSPHY_PCTL_VAL 0x0006
static const u8 u3phy_ctrl[] = {
@ -98,10 +76,6 @@ static const u8 u3phy_ctrl[] = {
static const u8 u2phy_ctrl[] = {
[CORERDY] = 0,
[AFE_LDO_PWRDWNB] = 1,
[AFE_PLL_PWRDWNB] = 2,
[AFE_BG_PWRDWNB] = 3,
[PHY_ISO] = 4,
[PHY_RESETB] = 5,
[PHY_PCTL] = 6,
};
@ -186,38 +160,13 @@ static int bcm_usb_hs_phy_init(struct bcm_usb_phy_cfg *phy_cfg)
int ret = 0;
void __iomem *regs = phy_cfg->regs;
const u8 *offset;
u32 rd_data;
offset = phy_cfg->offset;
writel(HSPLL_NDIV_INT_VAL, regs + offset[PLL_NDIV_INT]);
writel(HSPLL_NDIV_FRAC_VAL, regs + offset[PLL_NDIV_FRAC]);
rd_data = readl(regs + offset[PLL_CTRL]);
rd_data &= ~(HSPLL_PDIV_MASK << u2pll_ctrl[PLL_PDIV]);
rd_data |= (HSPLL_PDIV_VAL << u2pll_ctrl[PLL_PDIV]);
writel(rd_data, regs + offset[PLL_CTRL]);
/* Set Core Ready high */
bcm_usb_reg32_setbits(regs + offset[PHY_CTRL],
BIT(u2phy_ctrl[CORERDY]));
/* Maximum timeout for Core Ready done */
msleep(30);
bcm_usb_reg32_clrbits(regs + offset[PLL_CTRL],
BIT(u2pll_ctrl[PLL_RESETB]));
bcm_usb_reg32_setbits(regs + offset[PLL_CTRL],
BIT(u2pll_ctrl[PLL_RESETB]));
bcm_usb_reg32_setbits(regs + offset[PHY_CTRL],
BIT(u2phy_ctrl[PHY_RESETB]));
rd_data = readl(regs + offset[PHY_CTRL]);
rd_data &= ~(PHY_PCTL_MASK << u2phy_ctrl[PHY_PCTL]);
rd_data |= (HSPHY_PCTL_VAL << u2phy_ctrl[PHY_PCTL]);
writel(rd_data, regs + offset[PHY_CTRL]);
/* Maximum timeout for PLL reset done */
msleep(30);
ret = bcm_usb_pll_lock_check(regs + offset[PLL_CTRL],
BIT(u2pll_ctrl[PLL_LOCK]));
@ -256,7 +205,7 @@ static int bcm_usb_phy_init(struct phy *phy)
return ret;
}
static struct phy_ops sr_phy_ops = {
static const struct phy_ops sr_phy_ops = {
.init = bcm_usb_phy_init,
.reset = bcm_usb_phy_reset,
.owner = THIS_MODULE,

View File

@ -39,14 +39,14 @@ struct match_chip_info {
u8 optional_reg;
};
static struct value_to_name_map brcm_dr_mode_to_name[] = {
static const struct value_to_name_map brcm_dr_mode_to_name[] = {
{ USB_CTLR_MODE_HOST, "host" },
{ USB_CTLR_MODE_DEVICE, "peripheral" },
{ USB_CTLR_MODE_DRD, "drd" },
{ USB_CTLR_MODE_TYPEC_PD, "typec-pd" }
};
static struct value_to_name_map brcm_dual_mode_to_name[] = {
static const struct value_to_name_map brcm_dual_mode_to_name[] = {
{ 0, "host" },
{ 1, "device" },
{ 2, "auto" },
@ -138,7 +138,7 @@ static int brcm_usb_phy_exit(struct phy *gphy)
return 0;
}
static struct phy_ops brcm_usb_phy_ops = {
static const struct phy_ops brcm_usb_phy_ops = {
.init = brcm_usb_phy_init,
.exit = brcm_usb_phy_exit,
.owner = THIS_MODULE,
@ -170,7 +170,7 @@ static struct phy *brcm_usb_phy_xlate(struct device *dev,
return ERR_PTR(-ENODEV);
}
static int name_to_value(struct value_to_name_map *table, int count,
static int name_to_value(const struct value_to_name_map *table, int count,
const char *name, int *value)
{
int x;
@ -185,7 +185,7 @@ static int name_to_value(struct value_to_name_map *table, int count,
return -EINVAL;
}
static const char *value_to_name(struct value_to_name_map *table, int count,
static const char *value_to_name(const struct value_to_name_map *table, int count,
int value)
{
if (value >= count)
@ -252,7 +252,7 @@ static const struct attribute_group brcm_usb_phy_group = {
.attrs = brcm_usb_phy_attrs,
};
static struct match_chip_info chip_info_7216 = {
static const struct match_chip_info chip_info_7216 = {
.init_func = &brcm_usb_dvr_init_7216,
.required_regs = {
BRCM_REGS_CTRL,
@ -262,7 +262,7 @@ static struct match_chip_info chip_info_7216 = {
},
};
static struct match_chip_info chip_info_7211b0 = {
static const struct match_chip_info chip_info_7211b0 = {
.init_func = &brcm_usb_dvr_init_7211b0,
.required_regs = {
BRCM_REGS_CTRL,
@ -275,7 +275,7 @@ static struct match_chip_info chip_info_7211b0 = {
.optional_reg = BRCM_REGS_BDC_EC,
};
static struct match_chip_info chip_info_7445 = {
static const struct match_chip_info chip_info_7445 = {
.init_func = &brcm_usb_dvr_init_7445,
.required_regs = {
BRCM_REGS_CTRL,

View File

@ -27,3 +27,12 @@ config PHY_CADENCE_SIERRA
select GENERIC_PHY
help
Enable this to support the Cadence Sierra PHY driver
config PHY_CADENCE_SALVO
tristate "Cadence Salvo PHY Driver"
depends on OF && HAS_IOMEM
select GENERIC_PHY
help
Enable this to support the Cadence SALVO PHY driver,
this PHY is a legacy PHY, and only are used for USB3
and USB2.

View File

@ -2,3 +2,4 @@
obj-$(CONFIG_PHY_CADENCE_TORRENT) += phy-cadence-torrent.o
obj-$(CONFIG_PHY_CADENCE_DPHY) += cdns-dphy.o
obj-$(CONFIG_PHY_CADENCE_SIERRA) += phy-cadence-sierra.o
obj-$(CONFIG_PHY_CADENCE_SALVO) += phy-cadence-salvo.o

View File

@ -0,0 +1,325 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Salvo PHY is a 28nm PHY, it is a legacy PHY, and only
* for USB3 and USB2.
*
* Copyright (c) 2019-2020 NXP
*/
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_platform.h>
/* PHY register definition */
#define PHY_PMA_CMN_CTRL1 0xC800
#define TB_ADDR_CMN_DIAG_HSCLK_SEL 0x01e0
#define TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR 0x0084
#define TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR 0x0085
#define TB_ADDR_CMN_PLL0_INTDIV 0x0094
#define TB_ADDR_CMN_PLL0_FRACDIV 0x0095
#define TB_ADDR_CMN_PLL0_HIGH_THR 0x0096
#define TB_ADDR_CMN_PLL0_SS_CTRL1 0x0098
#define TB_ADDR_CMN_PLL0_SS_CTRL2 0x0099
#define TB_ADDR_CMN_PLL0_DSM_DIAG 0x0097
#define TB_ADDR_CMN_DIAG_PLL0_OVRD 0x01c2
#define TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD 0x01c0
#define TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD 0x01c1
#define TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE 0x01C5
#define TB_ADDR_CMN_DIAG_PLL0_CP_TUNE 0x01C6
#define TB_ADDR_CMN_DIAG_PLL0_LF_PROG 0x01C7
#define TB_ADDR_CMN_DIAG_PLL0_TEST_MODE 0x01c4
#define TB_ADDR_CMN_PSM_CLK_CTRL 0x0061
#define TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR 0x40ea
#define TB_ADDR_XCVR_PSM_RCTRL 0x4001
#define TB_ADDR_TX_PSC_A0 0x4100
#define TB_ADDR_TX_PSC_A1 0x4101
#define TB_ADDR_TX_PSC_A2 0x4102
#define TB_ADDR_TX_PSC_A3 0x4103
#define TB_ADDR_TX_DIAG_ECTRL_OVRD 0x41f5
#define TB_ADDR_TX_PSC_CAL 0x4106
#define TB_ADDR_TX_PSC_RDY 0x4107
#define TB_ADDR_RX_PSC_A0 0x8000
#define TB_ADDR_RX_PSC_A1 0x8001
#define TB_ADDR_RX_PSC_A2 0x8002
#define TB_ADDR_RX_PSC_A3 0x8003
#define TB_ADDR_RX_PSC_CAL 0x8006
#define TB_ADDR_RX_PSC_RDY 0x8007
#define TB_ADDR_TX_TXCC_MGNLS_MULT_000 0x4058
#define TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY 0x41e7
#define TB_ADDR_RX_SLC_CU_ITER_TMR 0x80e3
#define TB_ADDR_RX_SIGDET_HL_FILT_TMR 0x8090
#define TB_ADDR_RX_SAMP_DAC_CTRL 0x8058
#define TB_ADDR_RX_DIAG_SIGDET_TUNE 0x81dc
#define TB_ADDR_RX_DIAG_LFPSDET_TUNE2 0x81df
#define TB_ADDR_RX_DIAG_BS_TM 0x81f5
#define TB_ADDR_RX_DIAG_DFE_CTRL1 0x81d3
#define TB_ADDR_RX_DIAG_ILL_IQE_TRIM4 0x81c7
#define TB_ADDR_RX_DIAG_ILL_E_TRIM0 0x81c2
#define TB_ADDR_RX_DIAG_ILL_IQ_TRIM0 0x81c1
#define TB_ADDR_RX_DIAG_ILL_IQE_TRIM6 0x81c9
#define TB_ADDR_RX_DIAG_RXFE_TM3 0x81f8
#define TB_ADDR_RX_DIAG_RXFE_TM4 0x81f9
#define TB_ADDR_RX_DIAG_LFPSDET_TUNE 0x81dd
#define TB_ADDR_RX_DIAG_DFE_CTRL3 0x81d5
#define TB_ADDR_RX_DIAG_SC2C_DELAY 0x81e1
#define TB_ADDR_RX_REE_VGA_GAIN_NODFE 0x81bf
#define TB_ADDR_XCVR_PSM_CAL_TMR 0x4002
#define TB_ADDR_XCVR_PSM_A0BYP_TMR 0x4004
#define TB_ADDR_XCVR_PSM_A0IN_TMR 0x4003
#define TB_ADDR_XCVR_PSM_A1IN_TMR 0x4005
#define TB_ADDR_XCVR_PSM_A2IN_TMR 0x4006
#define TB_ADDR_XCVR_PSM_A3IN_TMR 0x4007
#define TB_ADDR_XCVR_PSM_A4IN_TMR 0x4008
#define TB_ADDR_XCVR_PSM_A5IN_TMR 0x4009
#define TB_ADDR_XCVR_PSM_A0OUT_TMR 0x400a
#define TB_ADDR_XCVR_PSM_A1OUT_TMR 0x400b
#define TB_ADDR_XCVR_PSM_A2OUT_TMR 0x400c
#define TB_ADDR_XCVR_PSM_A3OUT_TMR 0x400d
#define TB_ADDR_XCVR_PSM_A4OUT_TMR 0x400e
#define TB_ADDR_XCVR_PSM_A5OUT_TMR 0x400f
#define TB_ADDR_TX_RCVDET_EN_TMR 0x4122
#define TB_ADDR_TX_RCVDET_ST_TMR 0x4123
#define TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40f2
#define TB_ADDR_TX_RCVDETSC_CTRL 0x4124
/* TB_ADDR_TX_RCVDETSC_CTRL */
#define RXDET_IN_P3_32KHZ BIT(1)
struct cdns_reg_pairs {
u16 val;
u32 off;
};
struct cdns_salvo_data {
u8 reg_offset_shift;
struct cdns_reg_pairs *init_sequence_val;
u8 init_sequence_length;
};
struct cdns_salvo_phy {
struct phy *phy;
struct clk *clk;
void __iomem *base;
struct cdns_salvo_data *data;
};
static const struct of_device_id cdns_salvo_phy_of_match[];
static u16 cdns_salvo_read(struct cdns_salvo_phy *salvo_phy, u32 reg)
{
return (u16)readl(salvo_phy->base +
reg * (1 << salvo_phy->data->reg_offset_shift));
}
static void cdns_salvo_write(struct cdns_salvo_phy *salvo_phy,
u32 reg, u16 val)
{
writel(val, salvo_phy->base +
reg * (1 << salvo_phy->data->reg_offset_shift));
}
/*
* Below bringup sequence pair are from Cadence PHY's User Guide
* and NXP platform tuning results.
*/
static struct cdns_reg_pairs cdns_nxp_sequence_pair[] = {
{0x0830, PHY_PMA_CMN_CTRL1},
{0x0010, TB_ADDR_CMN_DIAG_HSCLK_SEL},
{0x00f0, TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR},
{0x0018, TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR},
{0x00d0, TB_ADDR_CMN_PLL0_INTDIV},
{0x4aaa, TB_ADDR_CMN_PLL0_FRACDIV},
{0x0034, TB_ADDR_CMN_PLL0_HIGH_THR},
{0x01ee, TB_ADDR_CMN_PLL0_SS_CTRL1},
{0x7f03, TB_ADDR_CMN_PLL0_SS_CTRL2},
{0x0020, TB_ADDR_CMN_PLL0_DSM_DIAG},
{0x0000, TB_ADDR_CMN_DIAG_PLL0_OVRD},
{0x0000, TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD},
{0x0000, TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD},
{0x0007, TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE},
{0x0027, TB_ADDR_CMN_DIAG_PLL0_CP_TUNE},
{0x0008, TB_ADDR_CMN_DIAG_PLL0_LF_PROG},
{0x0022, TB_ADDR_CMN_DIAG_PLL0_TEST_MODE},
{0x000a, TB_ADDR_CMN_PSM_CLK_CTRL},
{0x0139, TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR},
{0xbefc, TB_ADDR_XCVR_PSM_RCTRL},
{0x7799, TB_ADDR_TX_PSC_A0},
{0x7798, TB_ADDR_TX_PSC_A1},
{0x509b, TB_ADDR_TX_PSC_A2},
{0x0003, TB_ADDR_TX_DIAG_ECTRL_OVRD},
{0x509b, TB_ADDR_TX_PSC_A3},
{0x2090, TB_ADDR_TX_PSC_CAL},
{0x2090, TB_ADDR_TX_PSC_RDY},
{0xA6FD, TB_ADDR_RX_PSC_A0},
{0xA6FD, TB_ADDR_RX_PSC_A1},
{0xA410, TB_ADDR_RX_PSC_A2},
{0x2410, TB_ADDR_RX_PSC_A3},
{0x23FF, TB_ADDR_RX_PSC_CAL},
{0x2010, TB_ADDR_RX_PSC_RDY},
{0x0020, TB_ADDR_TX_TXCC_MGNLS_MULT_000},
{0x00ff, TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY},
{0x0002, TB_ADDR_RX_SLC_CU_ITER_TMR},
{0x0013, TB_ADDR_RX_SIGDET_HL_FILT_TMR},
{0x0000, TB_ADDR_RX_SAMP_DAC_CTRL},
{0x1004, TB_ADDR_RX_DIAG_SIGDET_TUNE},
{0x4041, TB_ADDR_RX_DIAG_LFPSDET_TUNE2},
{0x0480, TB_ADDR_RX_DIAG_BS_TM},
{0x8006, TB_ADDR_RX_DIAG_DFE_CTRL1},
{0x003f, TB_ADDR_RX_DIAG_ILL_IQE_TRIM4},
{0x543f, TB_ADDR_RX_DIAG_ILL_E_TRIM0},
{0x543f, TB_ADDR_RX_DIAG_ILL_IQ_TRIM0},
{0x0000, TB_ADDR_RX_DIAG_ILL_IQE_TRIM6},
{0x8000, TB_ADDR_RX_DIAG_RXFE_TM3},
{0x0003, TB_ADDR_RX_DIAG_RXFE_TM4},
{0x2408, TB_ADDR_RX_DIAG_LFPSDET_TUNE},
{0x05ca, TB_ADDR_RX_DIAG_DFE_CTRL3},
{0x0258, TB_ADDR_RX_DIAG_SC2C_DELAY},
{0x1fff, TB_ADDR_RX_REE_VGA_GAIN_NODFE},
{0x02c6, TB_ADDR_XCVR_PSM_CAL_TMR},
{0x0002, TB_ADDR_XCVR_PSM_A0BYP_TMR},
{0x02c6, TB_ADDR_XCVR_PSM_A0IN_TMR},
{0x0010, TB_ADDR_XCVR_PSM_A1IN_TMR},
{0x0010, TB_ADDR_XCVR_PSM_A2IN_TMR},
{0x0010, TB_ADDR_XCVR_PSM_A3IN_TMR},
{0x0010, TB_ADDR_XCVR_PSM_A4IN_TMR},
{0x0010, TB_ADDR_XCVR_PSM_A5IN_TMR},
{0x0002, TB_ADDR_XCVR_PSM_A0OUT_TMR},
{0x0002, TB_ADDR_XCVR_PSM_A1OUT_TMR},
{0x0002, TB_ADDR_XCVR_PSM_A2OUT_TMR},
{0x0002, TB_ADDR_XCVR_PSM_A3OUT_TMR},
{0x0002, TB_ADDR_XCVR_PSM_A4OUT_TMR},
{0x0002, TB_ADDR_XCVR_PSM_A5OUT_TMR},
/* Change rx detect parameter */
{0x0960, TB_ADDR_TX_RCVDET_EN_TMR},
{0x01e0, TB_ADDR_TX_RCVDET_ST_TMR},
{0x0090, TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR},
};
static int cdns_salvo_phy_init(struct phy *phy)
{
struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy);
struct cdns_salvo_data *data = salvo_phy->data;
int ret, i;
u16 value;
ret = clk_prepare_enable(salvo_phy->clk);
if (ret)
return ret;
for (i = 0; i < data->init_sequence_length; i++) {
struct cdns_reg_pairs *reg_pair = data->init_sequence_val + i;
cdns_salvo_write(salvo_phy, reg_pair->off, reg_pair->val);
}
/* RXDET_IN_P3_32KHZ, Receiver detect slow clock enable */
value = cdns_salvo_read(salvo_phy, TB_ADDR_TX_RCVDETSC_CTRL);
value |= RXDET_IN_P3_32KHZ;
cdns_salvo_write(salvo_phy, TB_ADDR_TX_RCVDETSC_CTRL,
RXDET_IN_P3_32KHZ);
udelay(10);
clk_disable_unprepare(salvo_phy->clk);
return ret;
}
static int cdns_salvo_phy_power_on(struct phy *phy)
{
struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy);
return clk_prepare_enable(salvo_phy->clk);
}
static int cdns_salvo_phy_power_off(struct phy *phy)
{
struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy);
clk_disable_unprepare(salvo_phy->clk);
return 0;
}
static struct phy_ops cdns_salvo_phy_ops = {
.init = cdns_salvo_phy_init,
.power_on = cdns_salvo_phy_power_on,
.power_off = cdns_salvo_phy_power_off,
.owner = THIS_MODULE,
};
static int cdns_salvo_phy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
struct device *dev = &pdev->dev;
struct cdns_salvo_phy *salvo_phy;
struct resource *res;
const struct of_device_id *match;
struct cdns_salvo_data *data;
match = of_match_device(cdns_salvo_phy_of_match, dev);
if (!match)
return -EINVAL;
data = (struct cdns_salvo_data *)match->data;
salvo_phy = devm_kzalloc(dev, sizeof(*salvo_phy), GFP_KERNEL);
if (!salvo_phy)
return -ENOMEM;
salvo_phy->data = data;
salvo_phy->clk = devm_clk_get_optional(dev, "salvo_phy_clk");
if (IS_ERR(salvo_phy->clk))
return PTR_ERR(salvo_phy->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
salvo_phy->base = devm_ioremap_resource(dev, res);
if (IS_ERR(salvo_phy->base))
return PTR_ERR(salvo_phy->base);
salvo_phy->phy = devm_phy_create(dev, NULL, &cdns_salvo_phy_ops);
if (IS_ERR(salvo_phy->phy))
return PTR_ERR(salvo_phy->phy);
phy_set_drvdata(salvo_phy->phy, salvo_phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct cdns_salvo_data cdns_nxp_salvo_data = {
2,
cdns_nxp_sequence_pair,
ARRAY_SIZE(cdns_nxp_sequence_pair),
};
static const struct of_device_id cdns_salvo_phy_of_match[] = {
{
.compatible = "nxp,salvo-phy",
.data = &cdns_nxp_salvo_data,
},
{}
};
MODULE_DEVICE_TABLE(of, cdns_salvo_phy_of_match);
static struct platform_driver cdns_salvo_phy_driver = {
.probe = cdns_salvo_phy_probe,
.driver = {
.name = "cdns-salvo-phy",
.of_match_table = cdns_salvo_phy_of_match,
}
};
module_platform_driver(cdns_salvo_phy_driver);
MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Cadence SALVO PHY Driver");

View File

@ -685,10 +685,10 @@ static struct cdns_reg_pairs cdns_usb_cmn_regs_ext_ssc[] = {
static struct cdns_reg_pairs cdns_usb_ln_regs_ext_ssc[] = {
{0xFE0A, SIERRA_DET_STANDEC_A_PREG},
{0x000F, SIERRA_DET_STANDEC_B_PREG},
{0x00A5, SIERRA_DET_STANDEC_C_PREG},
{0x55A5, SIERRA_DET_STANDEC_C_PREG},
{0x69ad, SIERRA_DET_STANDEC_D_PREG},
{0x0241, SIERRA_DET_STANDEC_E_PREG},
{0x0010, SIERRA_PSM_LANECAL_DLY_A1_RESETS_PREG},
{0x0110, SIERRA_PSM_LANECAL_DLY_A1_RESETS_PREG},
{0x0014, SIERRA_PSM_A0IN_TMR_PREG},
{0xCF00, SIERRA_PSM_DIAG_PREG},
{0x001F, SIERRA_PSC_TX_A0_PREG},
@ -696,7 +696,7 @@ static struct cdns_reg_pairs cdns_usb_ln_regs_ext_ssc[] = {
{0x0003, SIERRA_PSC_TX_A2_PREG},
{0x0003, SIERRA_PSC_TX_A3_PREG},
{0x0FFF, SIERRA_PSC_RX_A0_PREG},
{0x0619, SIERRA_PSC_RX_A1_PREG},
{0x0003, SIERRA_PSC_RX_A1_PREG},
{0x0003, SIERRA_PSC_RX_A2_PREG},
{0x0001, SIERRA_PSC_RX_A3_PREG},
{0x0001, SIERRA_PLLCTRL_SUBRATE_PREG},
@ -705,19 +705,19 @@ static struct cdns_reg_pairs cdns_usb_ln_regs_ext_ssc[] = {
{0x00CA, SIERRA_CLKPATH_BIASTRIM_PREG},
{0x2512, SIERRA_DFE_BIASTRIM_PREG},
{0x0000, SIERRA_DRVCTRL_ATTEN_PREG},
{0x873E, SIERRA_CLKPATHCTRL_TMR_PREG},
{0x03CF, SIERRA_RX_CREQ_FLTR_A_MODE1_PREG},
{0x01CE, SIERRA_RX_CREQ_FLTR_A_MODE0_PREG},
{0x823E, SIERRA_CLKPATHCTRL_TMR_PREG},
{0x078F, SIERRA_RX_CREQ_FLTR_A_MODE1_PREG},
{0x078F, SIERRA_RX_CREQ_FLTR_A_MODE0_PREG},
{0x7B3C, SIERRA_CREQ_CCLKDET_MODE01_PREG},
{0x033F, SIERRA_RX_CTLE_MAINTENANCE_PREG},
{0x023C, SIERRA_RX_CTLE_MAINTENANCE_PREG},
{0x3232, SIERRA_CREQ_FSMCLK_SEL_PREG},
{0x0000, SIERRA_CREQ_EQ_CTRL_PREG},
{0x8000, SIERRA_CREQ_SPARE_PREG},
{0x0000, SIERRA_CREQ_SPARE_PREG},
{0xCC44, SIERRA_CREQ_EQ_OPEN_EYE_THRESH_PREG},
{0x8453, SIERRA_CTLELUT_CTRL_PREG},
{0x4110, SIERRA_DFE_ECMP_RATESEL_PREG},
{0x4110, SIERRA_DFE_SMP_RATESEL_PREG},
{0x0002, SIERRA_DEQ_PHALIGN_CTRL},
{0x8452, SIERRA_CTLELUT_CTRL_PREG},
{0x4121, SIERRA_DFE_ECMP_RATESEL_PREG},
{0x4121, SIERRA_DFE_SMP_RATESEL_PREG},
{0x0003, SIERRA_DEQ_PHALIGN_CTRL},
{0x3200, SIERRA_DEQ_CONCUR_CTRL1_PREG},
{0x5064, SIERRA_DEQ_CONCUR_CTRL2_PREG},
{0x0030, SIERRA_DEQ_EPIPWR_CTRL2_PREG},
@ -725,7 +725,7 @@ static struct cdns_reg_pairs cdns_usb_ln_regs_ext_ssc[] = {
{0x5A5A, SIERRA_DEQ_ERRCMP_CTRL_PREG},
{0x02F5, SIERRA_DEQ_OFFSET_CTRL_PREG},
{0x02F5, SIERRA_DEQ_GAIN_CTRL_PREG},
{0x9A8A, SIERRA_DEQ_VGATUNE_CTRL_PREG},
{0x9999, SIERRA_DEQ_VGATUNE_CTRL_PREG},
{0x0014, SIERRA_DEQ_GLUT0},
{0x0014, SIERRA_DEQ_GLUT1},
{0x0014, SIERRA_DEQ_GLUT2},
@ -772,6 +772,7 @@ static struct cdns_reg_pairs cdns_usb_ln_regs_ext_ssc[] = {
{0x000F, SIERRA_LFPSFILT_NS_PREG},
{0x0009, SIERRA_LFPSFILT_RD_PREG},
{0x0001, SIERRA_LFPSFILT_MP_PREG},
{0x6013, SIERRA_SIGDET_SUPPORT_PREG},
{0x8013, SIERRA_SDFILT_H2L_A_PREG},
{0x8009, SIERRA_SDFILT_L2H_PREG},
{0x0024, SIERRA_RXBUFFER_CTLECTRL_PREG},

View File

@ -2,8 +2,23 @@
#
# Phy drivers for Intel Lightning Mountain(LGM) platform
#
config PHY_INTEL_COMBO
bool "Intel ComboPHY driver"
depends on X86 || COMPILE_TEST
depends on OF && HAS_IOMEM
select MFD_SYSCON
select GENERIC_PHY
select REGMAP
help
Enable this to support Intel ComboPhy.
This driver configures ComboPhy subsystem on Intel gateway
chipsets which provides PHYs for various controllers, EMAC,
SATA and PCIe.
config PHY_INTEL_EMMC
tristate "Intel EMMC PHY driver"
depends on X86 || COMPILE_TEST
select GENERIC_PHY
help
Enable this to support the Intel EMMC PHY

View File

@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PHY_INTEL_COMBO) += phy-intel-combo.o
obj-$(CONFIG_PHY_INTEL_EMMC) += phy-intel-emmc.o

View File

@ -0,0 +1,632 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Intel Combo-PHY driver
*
* Copyright (C) 2019-2020 Intel Corporation.
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <dt-bindings/phy/phy.h>
#define PCIE_PHY_GEN_CTRL 0x00
#define PCIE_PHY_CLK_PAD BIT(17)
#define PAD_DIS_CFG 0x174
#define PCS_XF_ATE_OVRD_IN_2 0x3008
#define ADAPT_REQ_MSK GENMASK(5, 4)
#define PCS_XF_RX_ADAPT_ACK 0x3010
#define RX_ADAPT_ACK_BIT BIT(0)
#define CR_ADDR(addr, lane) (((addr) + (lane) * 0x100) << 2)
#define REG_COMBO_MODE(x) ((x) * 0x200)
#define REG_CLK_DISABLE(x) ((x) * 0x200 + 0x124)
#define COMBO_PHY_ID(x) ((x)->parent->id)
#define PHY_ID(x) ((x)->id)
#define CLK_100MHZ 100000000
#define CLK_156_25MHZ 156250000
static const unsigned long intel_iphy_clk_rates[] = {
CLK_100MHZ, CLK_156_25MHZ, CLK_100MHZ,
};
enum {
PHY_0,
PHY_1,
PHY_MAX_NUM
};
/*
* Clock Register bit fields to enable clocks
* for ComboPhy according to the mode.
*/
enum intel_phy_mode {
PHY_PCIE_MODE = 0,
PHY_XPCS_MODE,
PHY_SATA_MODE,
};
/* ComboPhy mode Register values */
enum intel_combo_mode {
PCIE0_PCIE1_MODE = 0,
PCIE_DL_MODE,
RXAUI_MODE,
XPCS0_XPCS1_MODE,
SATA0_SATA1_MODE,
};
enum aggregated_mode {
PHY_SL_MODE,
PHY_DL_MODE,
};
struct intel_combo_phy;
struct intel_cbphy_iphy {
struct phy *phy;
struct intel_combo_phy *parent;
struct reset_control *app_rst;
u32 id;
};
struct intel_combo_phy {
struct device *dev;
struct clk *core_clk;
unsigned long clk_rate;
void __iomem *app_base;
void __iomem *cr_base;
struct regmap *syscfg;
struct regmap *hsiocfg;
u32 id;
u32 bid;
struct reset_control *phy_rst;
struct reset_control *core_rst;
struct intel_cbphy_iphy iphy[PHY_MAX_NUM];
enum intel_phy_mode phy_mode;
enum aggregated_mode aggr_mode;
u32 init_cnt;
struct mutex lock;
};
static int intel_cbphy_iphy_enable(struct intel_cbphy_iphy *iphy, bool set)
{
struct intel_combo_phy *cbphy = iphy->parent;
u32 mask = BIT(cbphy->phy_mode * 2 + iphy->id);
u32 val;
/* Register: 0 is enable, 1 is disable */
val = set ? 0 : mask;
return regmap_update_bits(cbphy->hsiocfg, REG_CLK_DISABLE(cbphy->bid),
mask, val);
}
static int intel_cbphy_pcie_refclk_cfg(struct intel_cbphy_iphy *iphy, bool set)
{
struct intel_combo_phy *cbphy = iphy->parent;
u32 mask = BIT(cbphy->id * 2 + iphy->id);
u32 val;
/* Register: 0 is enable, 1 is disable */
val = set ? 0 : mask;
return regmap_update_bits(cbphy->syscfg, PAD_DIS_CFG, mask, val);
}
static inline void combo_phy_w32_off_mask(void __iomem *base, unsigned int reg,
u32 mask, u32 val)
{
u32 reg_val;
reg_val = readl(base + reg);
reg_val &= ~mask;
reg_val |= FIELD_PREP(mask, val);
writel(reg_val, base + reg);
}
static int intel_cbphy_iphy_cfg(struct intel_cbphy_iphy *iphy,
int (*phy_cfg)(struct intel_cbphy_iphy *))
{
struct intel_combo_phy *cbphy = iphy->parent;
int ret;
ret = phy_cfg(iphy);
if (ret)
return ret;
if (cbphy->aggr_mode != PHY_DL_MODE)
return 0;
return phy_cfg(&cbphy->iphy[PHY_1]);
}
static int intel_cbphy_pcie_en_pad_refclk(struct intel_cbphy_iphy *iphy)
{
struct intel_combo_phy *cbphy = iphy->parent;
int ret;
ret = intel_cbphy_pcie_refclk_cfg(iphy, true);
if (ret) {
dev_err(cbphy->dev, "Failed to enable PCIe pad refclk\n");
return ret;
}
if (cbphy->init_cnt)
return 0;
combo_phy_w32_off_mask(cbphy->app_base, PCIE_PHY_GEN_CTRL,
PCIE_PHY_CLK_PAD, 0);
/* Delay for stable clock PLL */
usleep_range(50, 100);
return 0;
}
static int intel_cbphy_pcie_dis_pad_refclk(struct intel_cbphy_iphy *iphy)
{
struct intel_combo_phy *cbphy = iphy->parent;
int ret;
ret = intel_cbphy_pcie_refclk_cfg(iphy, false);
if (ret) {
dev_err(cbphy->dev, "Failed to disable PCIe pad refclk\n");
return ret;
}
if (cbphy->init_cnt)
return 0;
combo_phy_w32_off_mask(cbphy->app_base, PCIE_PHY_GEN_CTRL,
PCIE_PHY_CLK_PAD, 1);
return 0;
}
static int intel_cbphy_set_mode(struct intel_combo_phy *cbphy)
{
enum intel_combo_mode cb_mode = PHY_PCIE_MODE;
enum aggregated_mode aggr = cbphy->aggr_mode;
struct device *dev = cbphy->dev;
enum intel_phy_mode mode;
int ret;
mode = cbphy->phy_mode;
switch (mode) {
case PHY_PCIE_MODE:
cb_mode = (aggr == PHY_DL_MODE) ? PCIE_DL_MODE : PCIE0_PCIE1_MODE;
break;
case PHY_XPCS_MODE:
cb_mode = (aggr == PHY_DL_MODE) ? RXAUI_MODE : XPCS0_XPCS1_MODE;
break;
case PHY_SATA_MODE:
if (aggr == PHY_DL_MODE) {
dev_err(dev, "Mode:%u not support dual lane!\n", mode);
return -EINVAL;
}
cb_mode = SATA0_SATA1_MODE;
break;
}
ret = regmap_write(cbphy->hsiocfg, REG_COMBO_MODE(cbphy->bid), cb_mode);
if (ret)
dev_err(dev, "Failed to set ComboPhy mode: %d\n", ret);
return ret;
}
static void intel_cbphy_rst_assert(struct intel_combo_phy *cbphy)
{
reset_control_assert(cbphy->core_rst);
reset_control_assert(cbphy->phy_rst);
}
static void intel_cbphy_rst_deassert(struct intel_combo_phy *cbphy)
{
reset_control_deassert(cbphy->core_rst);
reset_control_deassert(cbphy->phy_rst);
/* Delay to ensure reset process is done */
usleep_range(10, 20);
}
static int intel_cbphy_iphy_power_on(struct intel_cbphy_iphy *iphy)
{
struct intel_combo_phy *cbphy = iphy->parent;
int ret;
if (!cbphy->init_cnt) {
ret = clk_prepare_enable(cbphy->core_clk);
if (ret) {
dev_err(cbphy->dev, "Clock enable failed!\n");
return ret;
}
ret = clk_set_rate(cbphy->core_clk, cbphy->clk_rate);
if (ret) {
dev_err(cbphy->dev, "Clock freq set to %lu failed!\n",
cbphy->clk_rate);
goto clk_err;
}
intel_cbphy_rst_assert(cbphy);
intel_cbphy_rst_deassert(cbphy);
ret = intel_cbphy_set_mode(cbphy);
if (ret)
goto clk_err;
}
ret = intel_cbphy_iphy_enable(iphy, true);
if (ret) {
dev_err(cbphy->dev, "Failed enabling PHY core\n");
goto clk_err;
}
ret = reset_control_deassert(iphy->app_rst);
if (ret) {
dev_err(cbphy->dev, "PHY(%u:%u) reset deassert failed!\n",
COMBO_PHY_ID(iphy), PHY_ID(iphy));
goto clk_err;
}
/* Delay to ensure reset process is done */
udelay(1);
return 0;
clk_err:
clk_disable_unprepare(cbphy->core_clk);
return ret;
}
static int intel_cbphy_iphy_power_off(struct intel_cbphy_iphy *iphy)
{
struct intel_combo_phy *cbphy = iphy->parent;
int ret;
ret = reset_control_assert(iphy->app_rst);
if (ret) {
dev_err(cbphy->dev, "PHY(%u:%u) reset assert failed!\n",
COMBO_PHY_ID(iphy), PHY_ID(iphy));
return ret;
}
ret = intel_cbphy_iphy_enable(iphy, false);
if (ret) {
dev_err(cbphy->dev, "Failed disabling PHY core\n");
return ret;
}
if (cbphy->init_cnt)
return 0;
clk_disable_unprepare(cbphy->core_clk);
intel_cbphy_rst_assert(cbphy);
return 0;
}
static int intel_cbphy_init(struct phy *phy)
{
struct intel_cbphy_iphy *iphy = phy_get_drvdata(phy);
struct intel_combo_phy *cbphy = iphy->parent;
int ret;
mutex_lock(&cbphy->lock);
ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_iphy_power_on);
if (ret)
goto err;
if (cbphy->phy_mode == PHY_PCIE_MODE) {
ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_pcie_en_pad_refclk);
if (ret)
goto err;
}
cbphy->init_cnt++;
err:
mutex_unlock(&cbphy->lock);
return ret;
}
static int intel_cbphy_exit(struct phy *phy)
{
struct intel_cbphy_iphy *iphy = phy_get_drvdata(phy);
struct intel_combo_phy *cbphy = iphy->parent;
int ret;
mutex_lock(&cbphy->lock);
cbphy->init_cnt--;
if (cbphy->phy_mode == PHY_PCIE_MODE) {
ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_pcie_dis_pad_refclk);
if (ret)
goto err;
}
ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_iphy_power_off);
err:
mutex_unlock(&cbphy->lock);
return ret;
}
static int intel_cbphy_calibrate(struct phy *phy)
{
struct intel_cbphy_iphy *iphy = phy_get_drvdata(phy);
struct intel_combo_phy *cbphy = iphy->parent;
void __iomem *cr_base = cbphy->cr_base;
int val, ret, id;
if (cbphy->phy_mode != PHY_XPCS_MODE)
return 0;
id = PHY_ID(iphy);
/* trigger auto RX adaptation */
combo_phy_w32_off_mask(cr_base, CR_ADDR(PCS_XF_ATE_OVRD_IN_2, id),
ADAPT_REQ_MSK, 3);
/* Wait RX adaptation to finish */
ret = readl_poll_timeout(cr_base + CR_ADDR(PCS_XF_RX_ADAPT_ACK, id),
val, val & RX_ADAPT_ACK_BIT, 10, 5000);
if (ret)
dev_err(cbphy->dev, "RX Adaptation failed!\n");
else
dev_dbg(cbphy->dev, "RX Adaptation success!\n");
/* Stop RX adaptation */
combo_phy_w32_off_mask(cr_base, CR_ADDR(PCS_XF_ATE_OVRD_IN_2, id),
ADAPT_REQ_MSK, 0);
return ret;
}
static int intel_cbphy_fwnode_parse(struct intel_combo_phy *cbphy)
{
struct device *dev = cbphy->dev;
struct platform_device *pdev = to_platform_device(dev);
struct fwnode_handle *fwnode = dev_fwnode(dev);
struct fwnode_reference_args ref;
int ret;
u32 val;
cbphy->core_clk = devm_clk_get(dev, NULL);
if (IS_ERR(cbphy->core_clk)) {
ret = PTR_ERR(cbphy->core_clk);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Get clk failed:%d!\n", ret);
return ret;
}
cbphy->core_rst = devm_reset_control_get_optional(dev, "core");
if (IS_ERR(cbphy->core_rst)) {
ret = PTR_ERR(cbphy->core_rst);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Get core reset control err: %d!\n", ret);
return ret;
}
cbphy->phy_rst = devm_reset_control_get_optional(dev, "phy");
if (IS_ERR(cbphy->phy_rst)) {
ret = PTR_ERR(cbphy->phy_rst);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Get PHY reset control err: %d!\n", ret);
return ret;
}
cbphy->iphy[0].app_rst = devm_reset_control_get_optional(dev, "iphy0");
if (IS_ERR(cbphy->iphy[0].app_rst)) {
ret = PTR_ERR(cbphy->iphy[0].app_rst);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Get phy0 reset control err: %d!\n", ret);
return ret;
}
cbphy->iphy[1].app_rst = devm_reset_control_get_optional(dev, "iphy1");
if (IS_ERR(cbphy->iphy[1].app_rst)) {
ret = PTR_ERR(cbphy->iphy[1].app_rst);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Get phy1 reset control err: %d!\n", ret);
return ret;
}
cbphy->app_base = devm_platform_ioremap_resource_byname(pdev, "app");
if (IS_ERR(cbphy->app_base))
return PTR_ERR(cbphy->app_base);
cbphy->cr_base = devm_platform_ioremap_resource_byname(pdev, "core");
if (IS_ERR(cbphy->cr_base))
return PTR_ERR(cbphy->cr_base);
/*
* syscfg and hsiocfg variables stores the handle of the registers set
* in which ComboPhy subsytem specific registers are subset. Using
* Register map framework to access the registers set.
*/
ret = fwnode_property_get_reference_args(fwnode, "intel,syscfg", NULL,
1, 0, &ref);
if (ret < 0)
return ret;
cbphy->id = ref.args[0];
cbphy->syscfg = device_node_to_regmap(to_of_node(ref.fwnode));
fwnode_handle_put(ref.fwnode);
ret = fwnode_property_get_reference_args(fwnode, "intel,hsio", NULL, 1,
0, &ref);
if (ret < 0)
return ret;
cbphy->bid = ref.args[0];
cbphy->hsiocfg = device_node_to_regmap(to_of_node(ref.fwnode));
fwnode_handle_put(ref.fwnode);
ret = fwnode_property_read_u32_array(fwnode, "intel,phy-mode", &val, 1);
if (ret)
return ret;
switch (val) {
case PHY_TYPE_PCIE:
cbphy->phy_mode = PHY_PCIE_MODE;
break;
case PHY_TYPE_SATA:
cbphy->phy_mode = PHY_SATA_MODE;
break;
case PHY_TYPE_XPCS:
cbphy->phy_mode = PHY_XPCS_MODE;
break;
default:
dev_err(dev, "Invalid PHY mode: %u\n", val);
return -EINVAL;
}
cbphy->clk_rate = intel_iphy_clk_rates[cbphy->phy_mode];
if (fwnode_property_present(fwnode, "intel,aggregation"))
cbphy->aggr_mode = PHY_DL_MODE;
else
cbphy->aggr_mode = PHY_SL_MODE;
return 0;
}
static const struct phy_ops intel_cbphy_ops = {
.init = intel_cbphy_init,
.exit = intel_cbphy_exit,
.calibrate = intel_cbphy_calibrate,
.owner = THIS_MODULE,
};
static struct phy *intel_cbphy_xlate(struct device *dev,
struct of_phandle_args *args)
{
struct intel_combo_phy *cbphy = dev_get_drvdata(dev);
u32 iphy_id;
if (args->args_count < 1) {
dev_err(dev, "Invalid number of arguments\n");
return ERR_PTR(-EINVAL);
}
iphy_id = args->args[0];
if (iphy_id >= PHY_MAX_NUM) {
dev_err(dev, "Invalid phy instance %d\n", iphy_id);
return ERR_PTR(-EINVAL);
}
if (cbphy->aggr_mode == PHY_DL_MODE && iphy_id == PHY_1) {
dev_err(dev, "Invalid. ComboPhy is in Dual lane mode %d\n", iphy_id);
return ERR_PTR(-EINVAL);
}
return cbphy->iphy[iphy_id].phy;
}
static int intel_cbphy_create(struct intel_combo_phy *cbphy)
{
struct phy_provider *phy_provider;
struct device *dev = cbphy->dev;
struct intel_cbphy_iphy *iphy;
int i;
for (i = 0; i < PHY_MAX_NUM; i++) {
iphy = &cbphy->iphy[i];
iphy->parent = cbphy;
iphy->id = i;
/* In dual lane mode skip phy creation for the second phy */
if (cbphy->aggr_mode == PHY_DL_MODE && iphy->id == PHY_1)
continue;
iphy->phy = devm_phy_create(dev, NULL, &intel_cbphy_ops);
if (IS_ERR(iphy->phy)) {
dev_err(dev, "PHY[%u:%u]: create PHY instance failed!\n",
COMBO_PHY_ID(iphy), PHY_ID(iphy));
return PTR_ERR(iphy->phy);
}
phy_set_drvdata(iphy->phy, iphy);
}
dev_set_drvdata(dev, cbphy);
phy_provider = devm_of_phy_provider_register(dev, intel_cbphy_xlate);
if (IS_ERR(phy_provider))
dev_err(dev, "Register PHY provider failed!\n");
return PTR_ERR_OR_ZERO(phy_provider);
}
static int intel_cbphy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct intel_combo_phy *cbphy;
int ret;
cbphy = devm_kzalloc(dev, sizeof(*cbphy), GFP_KERNEL);
if (!cbphy)
return -ENOMEM;
cbphy->dev = dev;
cbphy->init_cnt = 0;
mutex_init(&cbphy->lock);
ret = intel_cbphy_fwnode_parse(cbphy);
if (ret)
return ret;
platform_set_drvdata(pdev, cbphy);
return intel_cbphy_create(cbphy);
}
static int intel_cbphy_remove(struct platform_device *pdev)
{
struct intel_combo_phy *cbphy = platform_get_drvdata(pdev);
intel_cbphy_rst_assert(cbphy);
clk_disable_unprepare(cbphy->core_clk);
return 0;
}
static const struct of_device_id of_intel_cbphy_match[] = {
{ .compatible = "intel,combo-phy" },
{ .compatible = "intel,combophy-lgm" },
{}
};
static struct platform_driver intel_cbphy_driver = {
.probe = intel_cbphy_probe,
.remove = intel_cbphy_remove,
.driver = {
.name = "intel-combo-phy",
.of_match_table = of_intel_cbphy_match,
}
};
module_platform_driver(intel_cbphy_driver);
MODULE_DESCRIPTION("Intel Combo-phy driver");
MODULE_LICENSE("GPL v2");

View File

@ -122,7 +122,6 @@ enum cpcap_gpio_mode {
struct cpcap_phy_ddata {
struct regmap *reg;
struct device *dev;
struct clk *refclk;
struct usb_phy phy;
struct delayed_work detect_work;
struct pinctrl *pins;
@ -707,7 +706,6 @@ static int cpcap_usb_phy_remove(struct platform_device *pdev)
usb_remove_phy(&ddata->phy);
cancel_delayed_work_sync(&ddata->detect_work);
clk_unprepare(ddata->refclk);
regulator_disable(ddata->vusb);
return 0;

View File

@ -18,6 +18,13 @@ config PHY_QCOM_APQ8064_SATA
depends on OF
select GENERIC_PHY
config PHY_QCOM_IPQ4019_USB
tristate "Qualcomm IPQ4019 USB PHY driver"
depends on OF && (ARCH_QCOM || COMPILE_TEST)
select GENERIC_PHY
help
Support for the USB PHY-s on Qualcomm IPQ40xx SoC-s.
config PHY_QCOM_IPQ806X_SATA
tristate "Qualcomm IPQ806x SATA SerDes/PHY driver"
depends on ARCH_QCOM
@ -85,6 +92,16 @@ config PHY_QCOM_USB_HS
Support for the USB high-speed ULPI compliant phy on Qualcomm
chipsets.
config PHY_QCOM_USB_SNPS_FEMTO_V2
tristate "Qualcomm SNPS FEMTO USB HS PHY V2 module"
depends on OF && (ARCH_QCOM || COMPILE_TEST)
select GENERIC_PHY
help
Enable support for the USB high-speed SNPS Femto phy on Qualcomm
chipsets. This PHY has differences in the register map compared
to the V1 variants. The PHY is paired with a Synopsys DWC3 USB
controller on Qualcomm SOCs.
config PHY_QCOM_USB_HSIC
tristate "Qualcomm USB HSIC ULPI PHY module"
depends on USB_ULPI_BUS

View File

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PHY_ATH79_USB) += phy-ath79-usb.o
obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o
obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o
@ -12,3 +13,4 @@ obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o
obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
obj-$(CONFIG_PHY_QCOM_USB_HS_28NM) += phy-qcom-usb-hs-28nm.o
obj-$(CONFIG_PHY_QCOM_USB_SS) += phy-qcom-usb-ss.o
obj-$(CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2)+= phy-qcom-snps-femto-v2.o

View File

@ -0,0 +1,148 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2018 John Crispin <john@phrozen.org>
*
* Based on code from
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
*
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
struct ipq4019_usb_phy {
struct device *dev;
struct phy *phy;
void __iomem *base;
struct reset_control *por_rst;
struct reset_control *srif_rst;
};
static int ipq4019_ss_phy_power_off(struct phy *_phy)
{
struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
reset_control_assert(phy->por_rst);
msleep(10);
return 0;
}
static int ipq4019_ss_phy_power_on(struct phy *_phy)
{
struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
ipq4019_ss_phy_power_off(_phy);
reset_control_deassert(phy->por_rst);
return 0;
}
static struct phy_ops ipq4019_usb_ss_phy_ops = {
.power_on = ipq4019_ss_phy_power_on,
.power_off = ipq4019_ss_phy_power_off,
};
static int ipq4019_hs_phy_power_off(struct phy *_phy)
{
struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
reset_control_assert(phy->por_rst);
msleep(10);
reset_control_assert(phy->srif_rst);
msleep(10);
return 0;
}
static int ipq4019_hs_phy_power_on(struct phy *_phy)
{
struct ipq4019_usb_phy *phy = phy_get_drvdata(_phy);
ipq4019_hs_phy_power_off(_phy);
reset_control_deassert(phy->srif_rst);
msleep(10);
reset_control_deassert(phy->por_rst);
return 0;
}
static struct phy_ops ipq4019_usb_hs_phy_ops = {
.power_on = ipq4019_hs_phy_power_on,
.power_off = ipq4019_hs_phy_power_off,
};
static const struct of_device_id ipq4019_usb_phy_of_match[] = {
{ .compatible = "qcom,usb-hs-ipq4019-phy", .data = &ipq4019_usb_hs_phy_ops},
{ .compatible = "qcom,usb-ss-ipq4019-phy", .data = &ipq4019_usb_ss_phy_ops},
{ },
};
MODULE_DEVICE_TABLE(of, ipq4019_usb_phy_of_match);
static int ipq4019_usb_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct phy_provider *phy_provider;
struct ipq4019_usb_phy *phy;
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
if (!phy)
return -ENOMEM;
phy->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
phy->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(phy->base)) {
dev_err(dev, "failed to remap register memory\n");
return PTR_ERR(phy->base);
}
phy->por_rst = devm_reset_control_get(phy->dev, "por_rst");
if (IS_ERR(phy->por_rst)) {
if (PTR_ERR(phy->por_rst) != -EPROBE_DEFER)
dev_err(dev, "POR reset is missing\n");
return PTR_ERR(phy->por_rst);
}
phy->srif_rst = devm_reset_control_get_optional(phy->dev, "srif_rst");
if (IS_ERR(phy->srif_rst))
return PTR_ERR(phy->srif_rst);
phy->phy = devm_phy_create(dev, NULL, of_device_get_match_data(dev));
if (IS_ERR(phy->phy)) {
dev_err(dev, "failed to create PHY\n");
return PTR_ERR(phy->phy);
}
phy_set_drvdata(phy->phy, phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static struct platform_driver ipq4019_usb_phy_driver = {
.probe = ipq4019_usb_phy_probe,
.driver = {
.of_match_table = ipq4019_usb_phy_of_match,
.name = "ipq4019-usb-phy",
}
};
module_platform_driver(ipq4019_usb_phy_driver);
MODULE_DESCRIPTION("QCOM/IPQ4019 USB phy driver");
MODULE_AUTHOR("John Crispin <john@phrozen.org>");
MODULE_LICENSE("GPL v2");

View File

@ -119,14 +119,17 @@ enum qphy_reg_layout {
QPHY_PCS_AUTONOMOUS_MODE_CTRL,
QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR,
QPHY_PCS_LFPS_RXTERM_IRQ_STATUS,
QPHY_PCS_POWER_DOWN_CONTROL,
/* Keep last to ensure regs_layout arrays are properly initialized */
QPHY_LAYOUT_SIZE
};
static const unsigned int msm8996_ufsphy_regs_layout[] = {
static const unsigned int msm8996_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_START_CTRL] = 0x00,
[QPHY_PCS_READY_STATUS] = 0x168,
};
static const unsigned int pciephy_regs_layout[] = {
static const unsigned int pciephy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_COM_SW_RESET] = 0x400,
[QPHY_COM_POWER_DOWN_CONTROL] = 0x404,
[QPHY_COM_START_CONTROL] = 0x408,
@ -142,7 +145,7 @@ static const unsigned int pciephy_regs_layout[] = {
[QPHY_PCS_STATUS] = 0x174,
};
static const unsigned int usb3phy_regs_layout[] = {
static const unsigned int usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_FLL_CNTRL1] = 0xc0,
[QPHY_FLL_CNTRL2] = 0xc4,
[QPHY_FLL_CNT_VAL_L] = 0xc8,
@ -156,7 +159,7 @@ static const unsigned int usb3phy_regs_layout[] = {
[QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x178,
};
static const unsigned int qmp_v3_usb3phy_regs_layout[] = {
static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL] = 0x08,
[QPHY_PCS_STATUS] = 0x174,
@ -165,27 +168,34 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[] = {
[QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
};
static const unsigned int sdm845_qmp_pciephy_regs_layout[] = {
static const unsigned int sdm845_qmp_pciephy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL] = 0x08,
[QPHY_PCS_STATUS] = 0x174,
};
static const unsigned int sdm845_qhp_pciephy_regs_layout[] = {
static const unsigned int sdm845_qhp_pciephy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL] = 0x08,
[QPHY_PCS_STATUS] = 0x2ac,
};
static const unsigned int sdm845_ufsphy_regs_layout[] = {
static const unsigned int qmp_v4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL] = 0x44,
[QPHY_PCS_STATUS] = 0x14,
[QPHY_PCS_POWER_DOWN_CONTROL] = 0x40,
};
static const unsigned int sdm845_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_START_CTRL] = 0x00,
[QPHY_PCS_READY_STATUS] = 0x160,
};
static const unsigned int sm8150_ufsphy_regs_layout[] = {
[QPHY_START_CTRL] = QPHY_V4_PHY_START,
[QPHY_PCS_READY_STATUS] = QPHY_V4_PCS_READY_STATUS,
[QPHY_SW_RESET] = QPHY_V4_SW_RESET,
static const unsigned int sm8150_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_START_CTRL] = QPHY_V4_PCS_UFS_PHY_START,
[QPHY_PCS_READY_STATUS] = QPHY_V4_PCS_UFS_READY_STATUS,
[QPHY_SW_RESET] = QPHY_V4_PCS_UFS_SW_RESET,
};
static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
@ -1272,13 +1282,121 @@ static const struct qmp_phy_init_tbl sm8150_ufsphy_rx_tbl[] = {
};
static const struct qmp_phy_init_tbl sm8150_ufsphy_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_RX_SIGDET_CTRL2, 0x6d),
QMP_PHY_INIT_CFG(QPHY_V4_TX_LARGE_AMP_DRV_LVL, 0x0a),
QMP_PHY_INIT_CFG(QPHY_V4_TX_SMALL_AMP_DRV_LVL, 0x02),
QMP_PHY_INIT_CFG(QPHY_V4_TX_MID_TERM_CTRL1, 0x43),
QMP_PHY_INIT_CFG(QPHY_V4_DEBUG_BUS_CLKSEL, 0x1f),
QMP_PHY_INIT_CFG(QPHY_V4_RX_MIN_HIBERN8_TIME, 0xff),
QMP_PHY_INIT_CFG(QPHY_V4_MULTI_LANE_CTRL1, 0x02),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_RX_SIGDET_CTRL2, 0x6d),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0a),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_DEBUG_BUS_CLKSEL, 0x1f),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_RX_MIN_HIBERN8_TIME, 0xff),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
};
static const struct qmp_phy_init_tbl sm8150_usb3_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER1, 0x31),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER2, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0, 0xde),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1, 0xde),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_BUF_ENABLE, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_IPTRIM, 0x20),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x16),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x36),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x1a),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x14),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x34),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0x34),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x82),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x82),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE1, 0x82),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE0, 0xab),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0xea),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE1, 0xab),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE1, 0xea),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE1, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE0, 0x24),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE1, 0x24),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE2_MODE1, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x08),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xca),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xca),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x1e),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x11),
};
static const struct qmp_phy_init_tbl sm8150_usb3_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_TX, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_RX, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0xd5),
QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12),
QMP_PHY_INIT_CFG(QSERDES_V4_TX_PI_QEC_CTRL, 0x20),
};
static const struct qmp_phy_init_tbl sm8150_usb3_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x05),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x99),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH1, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH2, 0x08),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN1, 0x05),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN2, 0x05),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL1, 0x54),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL2, 0x0e),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x0e),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0xbf),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xbf),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0x3f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0x7f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x94),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0xdc),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0xdc),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0x5c),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x0b),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0xb3),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE, 0xa0),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_DCC_CTRL1, 0x0c),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x1f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_VTH_CODE, 0x10),
};
static const struct qmp_phy_init_tbl sm8150_usb3_pcs_tbl[] = {
/* Lock Det settings */
QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG1, 0xd0),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG2, 0x07),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG6, 0x13),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_CDR_RESET_TIME, 0x0a),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG1, 0x88),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG2, 0x13),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCS_TX_RX_CONFIG, 0x0c),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG1, 0x4b),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x10),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07),
};
/* struct qmp_phy_cfg - per-PHY initialization config */
@ -1445,6 +1563,10 @@ static const char * const sdm845_pciephy_clk_l[] = {
"aux", "cfg_ahb", "ref", "refgen",
};
static const char * const qmp_v4_phy_clk_l[] = {
"aux", "ref_clk_src", "ref", "com_aux",
};
static const char * const sdm845_ufs_phy_clk_l[] = {
"ref", "ref_aux",
};
@ -1458,6 +1580,10 @@ static const char * const msm8996_usb3phy_reset_l[] = {
"phy", "common",
};
static const char * const sc7180_usb3phy_reset_l[] = {
"phy",
};
static const char * const sdm845_pciephy_reset_l[] = {
"phy",
};
@ -1671,6 +1797,37 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
.is_dual_lane_phy = true,
};
static const struct qmp_phy_cfg sc7180_usb3phy_cfg = {
.type = PHY_TYPE_USB3,
.nlanes = 1,
.serdes_tbl = qmp_v3_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl),
.tx_tbl = qmp_v3_usb3_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_tx_tbl),
.rx_tbl = qmp_v3_usb3_rx_tbl,
.rx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_rx_tbl),
.pcs_tbl = qmp_v3_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(qmp_v3_usb3_pcs_tbl),
.clk_list = qmp_v3_phy_clk_l,
.num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l),
.reset_list = sc7180_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(sc7180_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout,
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
.has_phy_dp_com_ctrl = true,
.is_dual_lane_phy = true,
};
static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
.type = PHY_TYPE_USB3,
.nlanes = 1,
@ -1798,6 +1955,37 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
.is_dual_lane_phy = true,
};
static const struct qmp_phy_cfg sm8150_usb3phy_cfg = {
.type = PHY_TYPE_USB3,
.nlanes = 1,
.serdes_tbl = sm8150_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl),
.tx_tbl = sm8150_usb3_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(sm8150_usb3_tx_tbl),
.rx_tbl = sm8150_usb3_rx_tbl,
.rx_tbl_num = ARRAY_SIZE(sm8150_usb3_rx_tbl),
.pcs_tbl = sm8150_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(sm8150_usb3_pcs_tbl),
.clk_list = qmp_v4_phy_clk_l,
.num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l),
.reset_list = msm8996_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = qmp_v4_usb3phy_regs_layout,
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
.has_phy_dp_com_ctrl = true,
.is_dual_lane_phy = true,
};
static void qcom_qmp_phy_configure(void __iomem *base,
const unsigned int *regs,
const struct qmp_phy_init_tbl tbl[],
@ -1880,11 +2068,18 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
}
if (cfg->has_phy_com_ctrl)
if (cfg->has_phy_com_ctrl) {
qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
SW_PWRDN);
else
qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
} else {
if (cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL])
qphy_setbits(pcs,
cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
cfg->pwrdn_ctrl);
else
qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL,
cfg->pwrdn_ctrl);
}
/* Serdes configuration */
qcom_qmp_phy_configure(serdes, cfg->regs, cfg->serdes_tbl,
@ -2110,7 +2305,13 @@ static int qcom_qmp_phy_disable(struct phy *phy)
qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
/* Put PHY into POWER DOWN state: active low */
qphy_clrbits(qphy->pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
if (cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL]) {
qphy_clrbits(qphy->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
cfg->pwrdn_ctrl);
} else {
qphy_clrbits(qphy->pcs, QPHY_POWER_DOWN_CONTROL,
cfg->pwrdn_ctrl);
}
if (cfg->has_lane_rst)
reset_control_assert(qphy->lane_rst);
@ -2515,6 +2716,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
}, {
.compatible = "qcom,ipq8074-qmp-pcie-phy",
.data = &ipq8074_pciephy_cfg,
}, {
.compatible = "qcom,sc7180-qmp-usb3-phy",
.data = &sc7180_usb3phy_cfg,
}, {
.compatible = "qcom,sdm845-qhp-pcie-phy",
.data = &sdm845_qhp_pciephy_cfg,
@ -2536,6 +2740,12 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
}, {
.compatible = "qcom,sm8150-qmp-ufs-phy",
.data = &sm8150_ufsphy_cfg,
}, {
.compatible = "qcom,sm8250-qmp-ufs-phy",
.data = &sm8150_ufsphy_cfg,
}, {
.compatible = "qcom,sm8150-qmp-usb3-phy",
.data = &sm8150_usb3phy_cfg,
},
{ },
};

View File

@ -125,7 +125,7 @@
#define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB 0x1DC
#define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1E0
/* Only for QMP V3 PHY - DP COM registers */
/* Only for QMP V3 & V4 PHY - DP COM registers */
#define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00
#define QPHY_V3_DP_COM_SW_RESET 0x04
#define QPHY_V3_DP_COM_POWER_DOWN_CTRL 0x08
@ -314,6 +314,14 @@
#define QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG5 0x60
/* Only for QMP V4 PHY - QSERDES COM registers */
#define QSERDES_V4_COM_SSC_EN_CENTER 0x010
#define QSERDES_V4_COM_SSC_PER1 0x01c
#define QSERDES_V4_COM_SSC_PER2 0x020
#define QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0 0x024
#define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0 0x028
#define QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1 0x030
#define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1 0x034
#define QSERDES_V4_COM_SYSCLK_BUF_ENABLE 0x050
#define QSERDES_V4_COM_PLL_IVCO 0x058
#define QSERDES_V4_COM_CMN_IPTRIM 0x060
#define QSERDES_V4_COM_CP_CTRL_MODE0 0x074
@ -330,10 +338,22 @@
#define QSERDES_V4_COM_DEC_START_MODE0 0x0bc
#define QSERDES_V4_COM_LOCK_CMP2_MODE1 0x0b8
#define QSERDES_V4_COM_DEC_START_MODE1 0x0c4
#define QSERDES_V4_COM_DIV_FRAC_START1_MODE0 0x0cc
#define QSERDES_V4_COM_DIV_FRAC_START2_MODE0 0x0d0
#define QSERDES_V4_COM_DIV_FRAC_START3_MODE0 0x0d4
#define QSERDES_V4_COM_DIV_FRAC_START1_MODE1 0x0d8
#define QSERDES_V4_COM_DIV_FRAC_START2_MODE1 0x0dc
#define QSERDES_V4_COM_DIV_FRAC_START3_MODE1 0x0e0
#define QSERDES_V4_COM_VCO_TUNE_MAP 0x10c
#define QSERDES_V4_COM_VCO_TUNE1_MODE0 0x110
#define QSERDES_V4_COM_VCO_TUNE2_MODE0 0x114
#define QSERDES_V4_COM_VCO_TUNE1_MODE1 0x118
#define QSERDES_V4_COM_VCO_TUNE2_MODE1 0x11c
#define QSERDES_V4_COM_VCO_TUNE_INITVAL2 0x124
#define QSERDES_V4_COM_HSCLK_SEL 0x158
#define QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL 0x15c
#define QSERDES_V4_COM_CORECLK_DIV_MODE1 0x16c
#define QSERDES_V4_COM_SVS_MODE_CLK_SEL 0x184
#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x1ac
#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x1b0
#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1 0x1b4
@ -341,12 +361,16 @@
#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1 0x1b8
/* Only for QMP V4 PHY - TX registers */
#define QSERDES_V4_TX_RES_CODE_LANE_TX 0x34
#define QSERDES_V4_TX_RES_CODE_LANE_RX 0x38
#define QSERDES_V4_TX_LANE_MODE_1 0x84
#define QSERDES_V4_TX_RCV_DETECT_LVL_2 0x9c
#define QSERDES_V4_TX_PWM_GEAR_1_DIVIDER_BAND0_1 0xd8
#define QSERDES_V4_TX_PWM_GEAR_2_DIVIDER_BAND0_1 0xdC
#define QSERDES_V4_TX_PWM_GEAR_3_DIVIDER_BAND0_1 0xe0
#define QSERDES_V4_TX_PWM_GEAR_4_DIVIDER_BAND0_1 0xe4
#define QSERDES_V4_TX_TRAN_DRVR_EMP_EN 0xb8
#define QSERDES_V4_TX_PI_QEC_CTRL 0x104
/* Only for QMP V4 PHY - RX registers */
#define QSERDES_V4_RX_UCDR_FO_GAIN 0x008
@ -354,17 +378,27 @@
#define QSERDES_V4_RX_UCDR_FASTLOCK_FO_GAIN 0x030
#define QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034
#define QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c
#define QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040
#define QSERDES_V4_RX_UCDR_PI_CONTROLS 0x044
#define QSERDES_V4_RX_UCDR_PI_CTRL2 0x048
#define QSERDES_V4_RX_UCDR_SB2_THRESH1 0x04c
#define QSERDES_V4_RX_UCDR_SB2_THRESH2 0x050
#define QSERDES_V4_RX_UCDR_SB2_GAIN1 0x054
#define QSERDES_V4_RX_UCDR_SB2_GAIN2 0x058
#define QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE 0x060
#define QSERDES_V4_RX_AC_JTAG_ENABLE 0x068
#define QSERDES_V4_RX_AC_JTAG_MODE 0x078
#define QSERDES_V4_RX_RX_TERM_BW 0x080
#define QSERDES_V4_RX_VGA_CAL_CNTRL1 0x0d4
#define QSERDES_V4_RX_VGA_CAL_CNTRL2 0x0d8
#define QSERDES_V4_RX_GM_CAL 0x0dc
#define QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2 0x0ec
#define QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3 0x0f0
#define QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4 0x0f4
#define QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW 0x0f8
#define QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH 0x0fc
#define QSERDES_V4_RX_RX_IDAC_MEASURE_TIME 0x100
#define QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x110
#define QSERDES_V4_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x114
#define QSERDES_V4_RX_SIGDET_CNTRL 0x11c
#define QSERDES_V4_RX_SIGDET_LVL 0x120
@ -385,29 +419,32 @@
#define QSERDES_V4_RX_RX_MODE_10_HIGH2 0x1a0
#define QSERDES_V4_RX_RX_MODE_10_HIGH3 0x1a4
#define QSERDES_V4_RX_RX_MODE_10_HIGH4 0x1a8
#define QSERDES_V4_RX_DFE_EN_TIMER 0x1b4
#define QSERDES_V4_RX_DFE_CTLE_POST_CAL_OFFSET 0x1b8
#define QSERDES_V4_RX_DCC_CTRL1 0x1bc
#define QSERDES_V4_RX_VTH_CODE 0x1c4
/* Only for QMP V4 PHY - PCS registers */
#define QPHY_V4_PHY_START 0x000
#define QPHY_V4_POWER_DOWN_CONTROL 0x004
#define QPHY_V4_SW_RESET 0x008
#define QPHY_V4_TIMER_20US_CORECLK_STEPS_MSB 0x00c
#define QPHY_V4_TIMER_20US_CORECLK_STEPS_LSB 0x010
#define QPHY_V4_PLL_CNTL 0x02c
#define QPHY_V4_TX_LARGE_AMP_DRV_LVL 0x030
#define QPHY_V4_TX_SMALL_AMP_DRV_LVL 0x038
#define QPHY_V4_BIST_FIXED_PAT_CTRL 0x060
#define QPHY_V4_TX_HSGEAR_CAPABILITY 0x074
#define QPHY_V4_RX_HSGEAR_CAPABILITY 0x0b4
#define QPHY_V4_DEBUG_BUS_CLKSEL 0x124
#define QPHY_V4_LINECFG_DISABLE 0x148
#define QPHY_V4_RX_MIN_HIBERN8_TIME 0x150
#define QPHY_V4_RX_SIGDET_CTRL2 0x158
#define QPHY_V4_TX_PWM_GEAR_BAND 0x160
#define QPHY_V4_TX_HS_GEAR_BAND 0x168
#define QPHY_V4_PCS_READY_STATUS 0x180
#define QPHY_V4_TX_MID_TERM_CTRL1 0x1d8
#define QPHY_V4_MULTI_LANE_CTRL1 0x1e0
/* Only for QMP V4 PHY - UFS PCS registers */
#define QPHY_V4_PCS_UFS_PHY_START 0x000
#define QPHY_V4_PCS_UFS_POWER_DOWN_CONTROL 0x004
#define QPHY_V4_PCS_UFS_SW_RESET 0x008
#define QPHY_V4_PCS_UFS_TIMER_20US_CORECLK_STEPS_MSB 0x00c
#define QPHY_V4_PCS_UFS_TIMER_20US_CORECLK_STEPS_LSB 0x010
#define QPHY_V4_PCS_UFS_PLL_CNTL 0x02c
#define QPHY_V4_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x030
#define QPHY_V4_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x038
#define QPHY_V4_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060
#define QPHY_V4_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074
#define QPHY_V4_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0b4
#define QPHY_V4_PCS_UFS_DEBUG_BUS_CLKSEL 0x124
#define QPHY_V4_PCS_UFS_LINECFG_DISABLE 0x148
#define QPHY_V4_PCS_UFS_RX_MIN_HIBERN8_TIME 0x150
#define QPHY_V4_PCS_UFS_RX_SIGDET_CTRL2 0x158
#define QPHY_V4_PCS_UFS_TX_PWM_GEAR_BAND 0x160
#define QPHY_V4_PCS_UFS_TX_HS_GEAR_BAND 0x168
#define QPHY_V4_PCS_UFS_READY_STATUS 0x180
#define QPHY_V4_PCS_UFS_TX_MID_TERM_CTRL1 0x1d8
#define QPHY_V4_PCS_UFS_MULTI_LANE_CTRL1 0x1e0
/* PCIE GEN3 COM registers */
#define PCIE_GEN3_QHP_COM_SSC_EN_CENTER 0x14
@ -523,4 +560,161 @@
#define PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG5 0x16c
#define PCIE_GEN3_QHP_PHY_PCS_TX_RX_CONFIG 0x174
/* Only for QMP V4 PHY - USB/PCIe PCS registers */
#define QPHY_V4_PCS_SW_RESET 0x000
#define QPHY_V4_PCS_REVISION_ID0 0x004
#define QPHY_V4_PCS_REVISION_ID1 0x008
#define QPHY_V4_PCS_REVISION_ID2 0x00c
#define QPHY_V4_PCS_REVISION_ID3 0x010
#define QPHY_V4_PCS_PCS_STATUS1 0x014
#define QPHY_V4_PCS_PCS_STATUS2 0x018
#define QPHY_V4_PCS_PCS_STATUS3 0x01c
#define QPHY_V4_PCS_PCS_STATUS4 0x020
#define QPHY_V4_PCS_PCS_STATUS5 0x024
#define QPHY_V4_PCS_PCS_STATUS6 0x028
#define QPHY_V4_PCS_PCS_STATUS7 0x02c
#define QPHY_V4_PCS_DEBUG_BUS_0_STATUS 0x030
#define QPHY_V4_PCS_DEBUG_BUS_1_STATUS 0x034
#define QPHY_V4_PCS_DEBUG_BUS_2_STATUS 0x038
#define QPHY_V4_PCS_DEBUG_BUS_3_STATUS 0x03c
#define QPHY_V4_PCS_POWER_DOWN_CONTROL 0x040
#define QPHY_V4_PCS_START_CONTROL 0x044
#define QPHY_V4_PCS_INSIG_SW_CTRL1 0x048
#define QPHY_V4_PCS_INSIG_SW_CTRL2 0x04c
#define QPHY_V4_PCS_INSIG_SW_CTRL3 0x050
#define QPHY_V4_PCS_INSIG_SW_CTRL4 0x054
#define QPHY_V4_PCS_INSIG_SW_CTRL5 0x058
#define QPHY_V4_PCS_INSIG_SW_CTRL6 0x05c
#define QPHY_V4_PCS_INSIG_SW_CTRL7 0x060
#define QPHY_V4_PCS_INSIG_SW_CTRL8 0x064
#define QPHY_V4_PCS_INSIG_MX_CTRL1 0x068
#define QPHY_V4_PCS_INSIG_MX_CTRL2 0x06c
#define QPHY_V4_PCS_INSIG_MX_CTRL3 0x070
#define QPHY_V4_PCS_INSIG_MX_CTRL4 0x074
#define QPHY_V4_PCS_INSIG_MX_CTRL5 0x078
#define QPHY_V4_PCS_INSIG_MX_CTRL7 0x07c
#define QPHY_V4_PCS_INSIG_MX_CTRL8 0x080
#define QPHY_V4_PCS_OUTSIG_SW_CTRL1 0x084
#define QPHY_V4_PCS_OUTSIG_MX_CTRL1 0x088
#define QPHY_V4_PCS_CLAMP_ENABLE 0x08c
#define QPHY_V4_PCS_POWER_STATE_CONFIG1 0x090
#define QPHY_V4_PCS_POWER_STATE_CONFIG2 0x094
#define QPHY_V4_PCS_FLL_CNTRL1 0x098
#define QPHY_V4_PCS_FLL_CNTRL2 0x09c
#define QPHY_V4_PCS_FLL_CNT_VAL_L 0x0a0
#define QPHY_V4_PCS_FLL_CNT_VAL_H_TOL 0x0a4
#define QPHY_V4_PCS_FLL_MAN_CODE 0x0a8
#define QPHY_V4_PCS_TEST_CONTROL1 0x0ac
#define QPHY_V4_PCS_TEST_CONTROL2 0x0b0
#define QPHY_V4_PCS_TEST_CONTROL3 0x0b4
#define QPHY_V4_PCS_TEST_CONTROL4 0x0b8
#define QPHY_V4_PCS_TEST_CONTROL5 0x0bc
#define QPHY_V4_PCS_TEST_CONTROL6 0x0c0
#define QPHY_V4_PCS_LOCK_DETECT_CONFIG1 0x0c4
#define QPHY_V4_PCS_LOCK_DETECT_CONFIG2 0x0c8
#define QPHY_V4_PCS_LOCK_DETECT_CONFIG3 0x0cc
#define QPHY_V4_PCS_LOCK_DETECT_CONFIG4 0x0d0
#define QPHY_V4_PCS_LOCK_DETECT_CONFIG5 0x0d4
#define QPHY_V4_PCS_LOCK_DETECT_CONFIG6 0x0d8
#define QPHY_V4_PCS_REFGEN_REQ_CONFIG1 0x0dc
#define QPHY_V4_PCS_REFGEN_REQ_CONFIG2 0x0e0
#define QPHY_V4_PCS_REFGEN_REQ_CONFIG3 0x0e4
#define QPHY_V4_PCS_BIST_CTRL 0x0e8
#define QPHY_V4_PCS_PRBS_POLY0 0x0ec
#define QPHY_V4_PCS_PRBS_POLY1 0x0f0
#define QPHY_V4_PCS_FIXED_PAT0 0x0f4
#define QPHY_V4_PCS_FIXED_PAT1 0x0f8
#define QPHY_V4_PCS_FIXED_PAT2 0x0fc
#define QPHY_V4_PCS_FIXED_PAT3 0x100
#define QPHY_V4_PCS_FIXED_PAT4 0x104
#define QPHY_V4_PCS_FIXED_PAT5 0x108
#define QPHY_V4_PCS_FIXED_PAT6 0x10c
#define QPHY_V4_PCS_FIXED_PAT7 0x110
#define QPHY_V4_PCS_FIXED_PAT8 0x114
#define QPHY_V4_PCS_FIXED_PAT9 0x118
#define QPHY_V4_PCS_FIXED_PAT10 0x11c
#define QPHY_V4_PCS_FIXED_PAT11 0x120
#define QPHY_V4_PCS_FIXED_PAT12 0x124
#define QPHY_V4_PCS_FIXED_PAT13 0x128
#define QPHY_V4_PCS_FIXED_PAT14 0x12c
#define QPHY_V4_PCS_FIXED_PAT15 0x130
#define QPHY_V4_PCS_TXMGN_CONFIG 0x134
#define QPHY_V4_PCS_G12S1_TXMGN_V0 0x138
#define QPHY_V4_PCS_G12S1_TXMGN_V1 0x13c
#define QPHY_V4_PCS_G12S1_TXMGN_V2 0x140
#define QPHY_V4_PCS_G12S1_TXMGN_V3 0x144
#define QPHY_V4_PCS_G12S1_TXMGN_V4 0x148
#define QPHY_V4_PCS_G12S1_TXMGN_V0_RS 0x14c
#define QPHY_V4_PCS_G12S1_TXMGN_V1_RS 0x150
#define QPHY_V4_PCS_G12S1_TXMGN_V2_RS 0x154
#define QPHY_V4_PCS_G12S1_TXMGN_V3_RS 0x158
#define QPHY_V4_PCS_G12S1_TXMGN_V4_RS 0x15c
#define QPHY_V4_PCS_G3S2_TXMGN_MAIN 0x160
#define QPHY_V4_PCS_G3S2_TXMGN_MAIN_RS 0x164
#define QPHY_V4_PCS_G12S1_TXDEEMPH_M6DB 0x168
#define QPHY_V4_PCS_G12S1_TXDEEMPH_M3P5DB 0x16c
#define QPHY_V4_PCS_G3S2_PRE_GAIN 0x170
#define QPHY_V4_PCS_G3S2_POST_GAIN 0x174
#define QPHY_V4_PCS_G3S2_PRE_POST_OFFSET 0x178
#define QPHY_V4_PCS_G3S2_PRE_GAIN_RS 0x17c
#define QPHY_V4_PCS_G3S2_POST_GAIN_RS 0x180
#define QPHY_V4_PCS_G3S2_PRE_POST_OFFSET_RS 0x184
#define QPHY_V4_PCS_RX_SIGDET_LVL 0x188
#define QPHY_V4_PCS_RX_SIGDET_DTCT_CNTRL 0x18c
#define QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_L 0x190
#define QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_H 0x194
#define QPHY_V4_PCS_RATE_SLEW_CNTRL1 0x198
#define QPHY_V4_PCS_RATE_SLEW_CNTRL2 0x19c
#define QPHY_V4_PCS_PWRUP_RESET_DLY_TIME_AUXCLK 0x1a0
#define QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_L 0x1a4
#define QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_H 0x1a8
#define QPHY_V4_PCS_TSYNC_RSYNC_TIME 0x1ac
#define QPHY_V4_PCS_CDR_RESET_TIME 0x1b0
#define QPHY_V4_PCS_TSYNC_DLY_TIME 0x1b4
#define QPHY_V4_PCS_ELECIDLE_DLY_SEL 0x1b8
#define QPHY_V4_PCS_CMN_ACK_OUT_SEL 0x1bc
#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG1 0x1c0
#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG2 0x1c4
#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG3 0x1c8
#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG4 0x1cc
#define QPHY_V4_PCS_PCS_TX_RX_CONFIG 0x1d0
#define QPHY_V4_PCS_RX_IDLE_DTCT_CNTRL 0x1d4
#define QPHY_V4_PCS_RX_DCC_CAL_CONFIG 0x1d8
#define QPHY_V4_PCS_EQ_CONFIG1 0x1dc
#define QPHY_V4_PCS_EQ_CONFIG2 0x1e0
#define QPHY_V4_PCS_EQ_CONFIG3 0x1e4
#define QPHY_V4_PCS_EQ_CONFIG4 0x1e8
#define QPHY_V4_PCS_EQ_CONFIG5 0x1ec
#define QPHY_V4_PCS_USB3_POWER_STATE_CONFIG1 0x300
#define QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_STATUS 0x304
#define QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL 0x308
#define QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL2 0x30c
#define QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_SOURCE_STATUS 0x310
#define QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR 0x314
#define QPHY_V4_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL 0x318
#define QPHY_V4_PCS_USB3_LFPS_TX_ECSTART 0x31c
#define QPHY_V4_PCS_USB3_LFPS_PER_TIMER_VAL 0x320
#define QPHY_V4_PCS_USB3_LFPS_TX_END_CNT_U3_START 0x324
#define QPHY_V4_PCS_USB3_RXEQTRAINING_LOCK_TIME 0x328
#define QPHY_V4_PCS_USB3_RXEQTRAINING_WAIT_TIME 0x32c
#define QPHY_V4_PCS_USB3_RXEQTRAINING_CTLE_TIME 0x330
#define QPHY_V4_PCS_USB3_RXEQTRAINING_WAIT_TIME_S2 0x334
#define QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2 0x338
#define QPHY_V4_PCS_USB3_RCVR_DTCT_DLY_U3_L 0x33c
#define QPHY_V4_PCS_USB3_RCVR_DTCT_DLY_U3_H 0x340
#define QPHY_V4_PCS_USB3_ARCVR_DTCT_EN_PERIOD 0x344
#define QPHY_V4_PCS_USB3_ARCVR_DTCT_CM_DLY 0x348
#define QPHY_V4_PCS_USB3_TXONESZEROS_RUN_LENGTH 0x34c
#define QPHY_V4_PCS_USB3_ALFPS_DEGLITCH_VAL 0x350
#define QPHY_V4_PCS_USB3_SIGDET_STARTUP_TIMER_VAL 0x354
#define QPHY_V4_PCS_USB3_TEST_CONTROL 0x358
/* Only for QMP V4 PHY - PCS_MISC registers */
#define QPHY_V4_PCS_MISC_TYPEC_CTRL 0x00
#define QPHY_V4_PCS_MISC_TYPEC_PWRDN_CTRL 0x04
#define QPHY_V4_PCS_MISC_PCS_MISC_CONFIG1 0x08
#define QPHY_V4_PCS_MISC_CLAMP_ENABLE 0x0c
#define QPHY_V4_PCS_MISC_TYPEC_STATUS 0x10
#define QPHY_V4_PCS_MISC_PLACEHOLDER_STATUS 0x14
#endif

View File

@ -0,0 +1,287 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
#define USB2_PHY_USB_PHY_UTMI_CTRL0 (0x3c)
#define SLEEPM BIT(0)
#define OPMODE_MASK GENMASK(4, 3)
#define OPMODE_NORMAL (0x00)
#define OPMODE_NONDRIVING BIT(3)
#define TERMSEL BIT(5)
#define USB2_PHY_USB_PHY_UTMI_CTRL1 (0x40)
#define XCVRSEL BIT(0)
#define USB2_PHY_USB_PHY_UTMI_CTRL5 (0x50)
#define POR BIT(1)
#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0 (0x54)
#define RETENABLEN BIT(3)
#define FSEL_MASK GENMASK(7, 5)
#define FSEL_DEFAULT (0x3 << 4)
#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1 (0x58)
#define VBUSVLDEXTSEL0 BIT(4)
#define PLLBTUNE BIT(5)
#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2 (0x5c)
#define VREGBYPASS BIT(0)
#define USB2_PHY_USB_PHY_HS_PHY_CTRL1 (0x60)
#define VBUSVLDEXT0 BIT(0)
#define USB2_PHY_USB_PHY_HS_PHY_CTRL2 (0x64)
#define USB2_AUTO_RESUME BIT(0)
#define USB2_SUSPEND_N BIT(2)
#define USB2_SUSPEND_N_SEL BIT(3)
#define USB2_PHY_USB_PHY_CFG0 (0x94)
#define UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN BIT(0)
#define UTMI_PHY_CMN_CTRL_OVERRIDE_EN BIT(1)
#define USB2_PHY_USB_PHY_REFCLK_CTRL (0xa0)
#define REFCLK_SEL_MASK GENMASK(1, 0)
#define REFCLK_SEL_DEFAULT (0x2 << 0)
static const char * const qcom_snps_hsphy_vreg_names[] = {
"vdda-pll", "vdda33", "vdda18",
};
#define SNPS_HS_NUM_VREGS ARRAY_SIZE(qcom_snps_hsphy_vreg_names)
/**
* struct qcom_snps_hsphy - snps hs phy attributes
*
* @phy: generic phy
* @base: iomapped memory space for snps hs phy
*
* @cfg_ahb_clk: AHB2PHY interface clock
* @ref_clk: phy reference clock
* @iface_clk: phy interface clock
* @phy_reset: phy reset control
* @vregs: regulator supplies bulk data
* @phy_initialized: if PHY has been initialized correctly
*/
struct qcom_snps_hsphy {
struct phy *phy;
void __iomem *base;
struct clk *cfg_ahb_clk;
struct clk *ref_clk;
struct reset_control *phy_reset;
struct regulator_bulk_data vregs[SNPS_HS_NUM_VREGS];
bool phy_initialized;
};
static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset,
u32 mask, u32 val)
{
u32 reg;
reg = readl_relaxed(base + offset);
reg &= ~mask;
reg |= val & mask;
writel_relaxed(reg, base + offset);
/* Ensure above write is completed */
readl_relaxed(base + offset);
}
static int qcom_snps_hsphy_init(struct phy *phy)
{
struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
int ret;
dev_vdbg(&phy->dev, "%s(): Initializing SNPS HS phy\n", __func__);
ret = regulator_bulk_enable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
if (ret)
return ret;
ret = clk_prepare_enable(hsphy->cfg_ahb_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
goto poweroff_phy;
}
ret = reset_control_assert(hsphy->phy_reset);
if (ret) {
dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret);
goto disable_ahb_clk;
}
usleep_range(100, 150);
ret = reset_control_deassert(hsphy->phy_reset);
if (ret) {
dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret);
goto disable_ahb_clk;
}
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
UTMI_PHY_CMN_CTRL_OVERRIDE_EN,
UTMI_PHY_CMN_CTRL_OVERRIDE_EN);
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
POR, POR);
qcom_snps_hsphy_write_mask(hsphy->base,
USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0,
FSEL_MASK, 0);
qcom_snps_hsphy_write_mask(hsphy->base,
USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
PLLBTUNE, PLLBTUNE);
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_REFCLK_CTRL,
REFCLK_SEL_DEFAULT, REFCLK_SEL_MASK);
qcom_snps_hsphy_write_mask(hsphy->base,
USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
VBUSVLDEXTSEL0, VBUSVLDEXTSEL0);
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1,
VBUSVLDEXT0, VBUSVLDEXT0);
qcom_snps_hsphy_write_mask(hsphy->base,
USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2,
VREGBYPASS, VREGBYPASS);
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
USB2_SUSPEND_N_SEL | USB2_SUSPEND_N,
USB2_SUSPEND_N_SEL | USB2_SUSPEND_N);
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL0,
SLEEPM, SLEEPM);
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
POR, 0);
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
USB2_SUSPEND_N_SEL, 0);
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0);
hsphy->phy_initialized = true;
return 0;
disable_ahb_clk:
clk_disable_unprepare(hsphy->cfg_ahb_clk);
poweroff_phy:
regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
return ret;
}
static int qcom_snps_hsphy_exit(struct phy *phy)
{
struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
reset_control_assert(hsphy->phy_reset);
clk_disable_unprepare(hsphy->cfg_ahb_clk);
regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
hsphy->phy_initialized = false;
return 0;
}
static const struct phy_ops qcom_snps_hsphy_gen_ops = {
.init = qcom_snps_hsphy_init,
.exit = qcom_snps_hsphy_exit,
.owner = THIS_MODULE,
};
static const struct of_device_id qcom_snps_hsphy_of_match_table[] = {
{ .compatible = "qcom,sm8150-usb-hs-phy", },
{ .compatible = "qcom,usb-snps-hs-7nm-phy", },
{ .compatible = "qcom,usb-snps-femto-v2-phy", },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_of_match_table);
static int qcom_snps_hsphy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct qcom_snps_hsphy *hsphy;
struct phy_provider *phy_provider;
struct phy *generic_phy;
int ret, i;
int num;
hsphy = devm_kzalloc(dev, sizeof(*hsphy), GFP_KERNEL);
if (!hsphy)
return -ENOMEM;
hsphy->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hsphy->base))
return PTR_ERR(hsphy->base);
hsphy->ref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(hsphy->ref_clk)) {
ret = PTR_ERR(hsphy->ref_clk);
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to get ref clk, %d\n", ret);
return ret;
}
hsphy->phy_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(hsphy->phy_reset)) {
dev_err(dev, "failed to get phy core reset\n");
return PTR_ERR(hsphy->phy_reset);
}
num = ARRAY_SIZE(hsphy->vregs);
for (i = 0; i < num; i++)
hsphy->vregs[i].supply = qcom_snps_hsphy_vreg_names[i];
ret = devm_regulator_bulk_get(dev, num, hsphy->vregs);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to get regulator supplies: %d\n",
ret);
return ret;
}
generic_phy = devm_phy_create(dev, NULL, &qcom_snps_hsphy_gen_ops);
if (IS_ERR(generic_phy)) {
ret = PTR_ERR(generic_phy);
dev_err(dev, "failed to create phy, %d\n", ret);
return ret;
}
hsphy->phy = generic_phy;
dev_set_drvdata(dev, hsphy);
phy_set_drvdata(generic_phy, hsphy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (!IS_ERR(phy_provider))
dev_dbg(dev, "Registered Qcom-SNPS HS phy\n");
return PTR_ERR_OR_ZERO(phy_provider);
}
static struct platform_driver qcom_snps_hsphy_driver = {
.probe = qcom_snps_hsphy_probe,
.driver = {
.name = "qcom-snps-hs-femto-v2-phy",
.of_match_table = qcom_snps_hsphy_of_match_table,
},
};
module_platform_driver(qcom_snps_hsphy_driver);
MODULE_DESCRIPTION("Qualcomm SNPS FEMTO USB HS PHY V2 driver");
MODULE_LICENSE("GPL v2");

View File

@ -139,6 +139,10 @@ static void s5pv210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
udelay(10);
rst &= ~rstbits;
writel(rst, drv->reg_phy + S5PV210_UPHYRST);
/* The following delay is necessary for the reset sequence to be
* completed
*/
udelay(80);
} else {
pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
pwr |= phypwr;

View File

@ -77,6 +77,7 @@ static struct regmap_config serdes_am654_regmap_config = {
.val_bits = 32,
.reg_stride = 4,
.fast_io = true,
.max_register = 0x1ffc,
};
static const struct reg_field cmu_master_cdn_o = REG_FIELD(CMU_R07C, 24, 24);
@ -200,9 +201,91 @@ static int serdes_am654_power_off(struct phy *x)
return 0;
}
static int serdes_am654_init(struct phy *x)
#define SERDES_AM654_CFG(offset, a, b, val) \
regmap_update_bits(phy->regmap, (offset),\
GENMASK((a), (b)), (val) << (b))
static int serdes_am654_usb3_init(struct serdes_am654 *phy)
{
SERDES_AM654_CFG(0x0000, 31, 24, 0x17);
SERDES_AM654_CFG(0x0004, 15, 8, 0x02);
SERDES_AM654_CFG(0x0004, 7, 0, 0x0e);
SERDES_AM654_CFG(0x0008, 23, 16, 0x2e);
SERDES_AM654_CFG(0x0008, 31, 24, 0x2e);
SERDES_AM654_CFG(0x0060, 7, 0, 0x4b);
SERDES_AM654_CFG(0x0060, 15, 8, 0x98);
SERDES_AM654_CFG(0x0060, 23, 16, 0x60);
SERDES_AM654_CFG(0x00d0, 31, 24, 0x45);
SERDES_AM654_CFG(0x00e8, 15, 8, 0x0e);
SERDES_AM654_CFG(0x0220, 7, 0, 0x34);
SERDES_AM654_CFG(0x0220, 15, 8, 0x34);
SERDES_AM654_CFG(0x0220, 31, 24, 0x37);
SERDES_AM654_CFG(0x0224, 7, 0, 0x37);
SERDES_AM654_CFG(0x0224, 15, 8, 0x37);
SERDES_AM654_CFG(0x0228, 23, 16, 0x37);
SERDES_AM654_CFG(0x0228, 31, 24, 0x37);
SERDES_AM654_CFG(0x022c, 7, 0, 0x37);
SERDES_AM654_CFG(0x022c, 15, 8, 0x37);
SERDES_AM654_CFG(0x0230, 15, 8, 0x2a);
SERDES_AM654_CFG(0x0230, 23, 16, 0x2a);
SERDES_AM654_CFG(0x0240, 23, 16, 0x10);
SERDES_AM654_CFG(0x0240, 31, 24, 0x34);
SERDES_AM654_CFG(0x0244, 7, 0, 0x40);
SERDES_AM654_CFG(0x0244, 23, 16, 0x34);
SERDES_AM654_CFG(0x0248, 15, 8, 0x0d);
SERDES_AM654_CFG(0x0258, 15, 8, 0x16);
SERDES_AM654_CFG(0x0258, 23, 16, 0x84);
SERDES_AM654_CFG(0x0258, 31, 24, 0xf2);
SERDES_AM654_CFG(0x025c, 7, 0, 0x21);
SERDES_AM654_CFG(0x0260, 7, 0, 0x27);
SERDES_AM654_CFG(0x0260, 15, 8, 0x04);
SERDES_AM654_CFG(0x0268, 15, 8, 0x04);
SERDES_AM654_CFG(0x0288, 15, 8, 0x2c);
SERDES_AM654_CFG(0x0330, 31, 24, 0xa0);
SERDES_AM654_CFG(0x0338, 23, 16, 0x03);
SERDES_AM654_CFG(0x0338, 31, 24, 0x00);
SERDES_AM654_CFG(0x033c, 7, 0, 0x00);
SERDES_AM654_CFG(0x0344, 31, 24, 0x18);
SERDES_AM654_CFG(0x034c, 7, 0, 0x18);
SERDES_AM654_CFG(0x039c, 23, 16, 0x3b);
SERDES_AM654_CFG(0x0a04, 7, 0, 0x03);
SERDES_AM654_CFG(0x0a14, 31, 24, 0x3c);
SERDES_AM654_CFG(0x0a18, 15, 8, 0x3c);
SERDES_AM654_CFG(0x0a38, 7, 0, 0x3e);
SERDES_AM654_CFG(0x0a38, 15, 8, 0x3e);
SERDES_AM654_CFG(0x0ae0, 7, 0, 0x07);
SERDES_AM654_CFG(0x0b6c, 23, 16, 0xcd);
SERDES_AM654_CFG(0x0b6c, 31, 24, 0x04);
SERDES_AM654_CFG(0x0b98, 23, 16, 0x03);
SERDES_AM654_CFG(0x1400, 7, 0, 0x3f);
SERDES_AM654_CFG(0x1404, 23, 16, 0x6f);
SERDES_AM654_CFG(0x1404, 31, 24, 0x6f);
SERDES_AM654_CFG(0x140c, 7, 0, 0x6f);
SERDES_AM654_CFG(0x140c, 15, 8, 0x6f);
SERDES_AM654_CFG(0x1410, 15, 8, 0x27);
SERDES_AM654_CFG(0x1414, 7, 0, 0x0c);
SERDES_AM654_CFG(0x1414, 23, 16, 0x07);
SERDES_AM654_CFG(0x1418, 23, 16, 0x40);
SERDES_AM654_CFG(0x141c, 7, 0, 0x00);
SERDES_AM654_CFG(0x141c, 15, 8, 0x1f);
SERDES_AM654_CFG(0x1428, 31, 24, 0x08);
SERDES_AM654_CFG(0x1434, 31, 24, 0x00);
SERDES_AM654_CFG(0x1444, 7, 0, 0x94);
SERDES_AM654_CFG(0x1460, 31, 24, 0x7f);
SERDES_AM654_CFG(0x1464, 7, 0, 0x43);
SERDES_AM654_CFG(0x1464, 23, 16, 0x6f);
SERDES_AM654_CFG(0x1464, 31, 24, 0x43);
SERDES_AM654_CFG(0x1484, 23, 16, 0x8f);
SERDES_AM654_CFG(0x1498, 7, 0, 0x4f);
SERDES_AM654_CFG(0x1498, 23, 16, 0x4f);
SERDES_AM654_CFG(0x007c, 31, 24, 0x0d);
SERDES_AM654_CFG(0x0b90, 15, 8, 0x0f);
return 0;
}
static int serdes_am654_pcie_init(struct serdes_am654 *phy)
{
struct serdes_am654 *phy = phy_get_drvdata(x);
int ret;
ret = regmap_field_write(phy->config_version, VERSION);
@ -220,11 +303,28 @@ static int serdes_am654_init(struct phy *x)
return 0;
}
static int serdes_am654_init(struct phy *x)
{
struct serdes_am654 *phy = phy_get_drvdata(x);
switch (phy->type) {
case PHY_TYPE_PCIE:
return serdes_am654_pcie_init(phy);
case PHY_TYPE_USB3:
return serdes_am654_usb3_init(phy);
default:
return -EINVAL;
}
}
static int serdes_am654_reset(struct phy *x)
{
struct serdes_am654 *phy = phy_get_drvdata(x);
int ret;
serdes_am654_disable_pll(phy);
serdes_am654_disable_txrx(phy);
ret = regmap_field_write(phy->por_en, 0x1);
if (ret)
return ret;

View File

@ -20,6 +20,7 @@
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
#include <dt-bindings/phy/phy.h>
#define WIZ_SERDES_CTRL 0x404
#define WIZ_SERDES_TOP_CTRL 0x408
@ -78,6 +79,8 @@ static const struct reg_field p_enable[WIZ_MAX_LANES] = {
REG_FIELD(WIZ_LANECTL(3), 30, 31),
};
enum p_enable { P_ENABLE = 2, P_ENABLE_FORCE = 1, P_ENABLE_DISABLE = 0 };
static const struct reg_field p_align[WIZ_MAX_LANES] = {
REG_FIELD(WIZ_LANECTL(0), 29, 29),
REG_FIELD(WIZ_LANECTL(1), 29, 29),
@ -220,6 +223,7 @@ struct wiz {
struct reset_controller_dev wiz_phy_reset_dev;
struct gpio_desc *gpio_typec_dir;
int typec_dir_delay;
u32 lane_phy_type[WIZ_MAX_LANES];
};
static int wiz_reset(struct wiz *wiz)
@ -242,12 +246,17 @@ static int wiz_reset(struct wiz *wiz)
static int wiz_mode_select(struct wiz *wiz)
{
u32 num_lanes = wiz->num_lanes;
enum wiz_lane_standard_mode mode;
int ret;
int i;
for (i = 0; i < num_lanes; i++) {
ret = regmap_field_write(wiz->p_standard_mode[i],
LANE_MODE_GEN4);
if (wiz->lane_phy_type[i] == PHY_TYPE_DP)
mode = LANE_MODE_GEN1;
else
mode = LANE_MODE_GEN4;
ret = regmap_field_write(wiz->p_standard_mode[i], mode);
if (ret)
return ret;
}
@ -707,7 +716,7 @@ static int wiz_phy_reset_assert(struct reset_controller_dev *rcdev,
return ret;
}
ret = regmap_field_write(wiz->p_enable[id - 1], false);
ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE_DISABLE);
return ret;
}
@ -734,7 +743,11 @@ static int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev,
return ret;
}
ret = regmap_field_write(wiz->p_enable[id - 1], true);
if (wiz->lane_phy_type[id - 1] == PHY_TYPE_DP)
ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE);
else
ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE_FORCE);
return ret;
}
@ -761,6 +774,40 @@ static const struct of_device_id wiz_id_table[] = {
};
MODULE_DEVICE_TABLE(of, wiz_id_table);
static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
{
struct device_node *serdes, *subnode;
serdes = of_get_child_by_name(dev->of_node, "serdes");
if (!serdes) {
dev_err(dev, "%s: Getting \"serdes\"-node failed\n", __func__);
return -EINVAL;
}
for_each_child_of_node(serdes, subnode) {
u32 reg, num_lanes = 1, phy_type = PHY_NONE;
int ret, i;
ret = of_property_read_u32(subnode, "reg", &reg);
if (ret) {
dev_err(dev,
"%s: Reading \"reg\" from \"%s\" failed: %d\n",
__func__, subnode->name, ret);
return ret;
}
of_property_read_u32(subnode, "cdns,num-lanes", &num_lanes);
of_property_read_u32(subnode, "cdns,phy-type", &phy_type);
dev_dbg(dev, "%s: Lanes %u-%u have phy-type %u\n", __func__,
reg, reg + num_lanes - 1, phy_type);
for (i = reg; i < reg + num_lanes; i++)
wiz->lane_phy_type[i] = phy_type;
}
return 0;
}
static int wiz_probe(struct platform_device *pdev)
{
struct reset_controller_dev *phy_reset_dev;
@ -794,8 +841,10 @@ static int wiz_probe(struct platform_device *pdev)
}
base = devm_ioremap(dev, res.start, resource_size(&res));
if (!base)
if (!base) {
ret = -ENOMEM;
goto err_addr_to_resource;
}
regmap = devm_regmap_init_mmio(dev, base, &wiz_regmap_config);
if (IS_ERR(regmap)) {
@ -812,6 +861,7 @@ static int wiz_probe(struct platform_device *pdev)
if (num_lanes > WIZ_MAX_LANES) {
dev_err(dev, "Cannot support %d lanes\n", num_lanes);
ret = -ENODEV;
goto err_addr_to_resource;
}
@ -844,6 +894,10 @@ static int wiz_probe(struct platform_device *pdev)
}
}
ret = wiz_get_lane_phy_types(dev, wiz);
if (ret)
return ret;
wiz->dev = dev;
wiz->regmap = regmap;
wiz->num_lanes = num_lanes;
@ -897,6 +951,7 @@ static int wiz_probe(struct platform_device *pdev)
serdes_pdev = of_platform_device_create(child_node, NULL, dev);
if (!serdes_pdev) {
dev_WARN(dev, "Unable to create SERDES platform device\n");
ret = -ENOMEM;
goto err_pdev_create;
}
wiz->serdes_pdev = serdes_pdev;

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* omap-usb2.c - USB PHY, talking to musb controller in OMAP.
* omap-usb2.c - USB PHY, talking to USB controller on TI SoCs.
*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
* Copyright (C) 2012-2020 Texas Instruments Incorporated - http://www.ti.com
* Author: Kishon Vijay Abraham I <kishon@ti.com>
*/
@ -23,13 +23,65 @@
#include <linux/regmap.h>
#include <linux/of_platform.h>
#define USB2PHY_DISCON_BYP_LATCH (1 << 31)
#define USB2PHY_ANA_CONFIG1 0x4c
#define USB2PHY_ANA_CONFIG1 0x4c
#define USB2PHY_DISCON_BYP_LATCH BIT(31)
/* SoC Specific USB2_OTG register definitions */
#define AM654_USB2_OTG_PD BIT(8)
#define AM654_USB2_VBUS_DET_EN BIT(5)
#define AM654_USB2_VBUSVALID_DET_EN BIT(4)
#define OMAP_DEV_PHY_PD BIT(0)
#define OMAP_USB2_PHY_PD BIT(28)
#define AM437X_USB2_PHY_PD BIT(0)
#define AM437X_USB2_OTG_PD BIT(1)
#define AM437X_USB2_OTGVDET_EN BIT(19)
#define AM437X_USB2_OTGSESSEND_EN BIT(20)
/* Driver Flags */
#define OMAP_USB2_HAS_START_SRP BIT(0)
#define OMAP_USB2_HAS_SET_VBUS BIT(1)
#define OMAP_USB2_CALIBRATE_FALSE_DISCONNECT BIT(2)
struct omap_usb {
struct usb_phy phy;
struct phy_companion *comparator;
void __iomem *pll_ctrl_base;
void __iomem *phy_base;
struct device *dev;
struct device *control_dev;
struct clk *wkupclk;
struct clk *optclk;
u8 flags;
struct regmap *syscon_phy_power; /* ctrl. reg. acces */
unsigned int power_reg; /* power reg. index within syscon */
u32 mask;
u32 power_on;
u32 power_off;
};
#define phy_to_omapusb(x) container_of((x), struct omap_usb, phy)
struct usb_phy_data {
const char *label;
u8 flags;
u32 mask;
u32 power_on;
u32 power_off;
};
static inline u32 omap_usb_readl(void __iomem *addr, unsigned int offset)
{
return __raw_readl(addr + offset);
}
static inline void omap_usb_writel(void __iomem *addr, unsigned int offset,
u32 data)
{
__raw_writel(data, addr + offset);
}
/**
* omap_usb2_set_comparator - links the comparator present in the sytem with
* this phy

View File

@ -2,7 +2,6 @@
menuconfig USB4
tristate "Unified support for USB4 and Thunderbolt"
depends on PCI
depends on X86 || COMPILE_TEST
select APPLE_PROPERTIES if EFI_STUB && X86
select CRC32
select CRYPTO

View File

@ -1633,6 +1633,15 @@ static void icm_icl_rtd3_veto(struct tb *tb, const struct icm_pkg_header *hdr)
icm_veto_end(tb);
}
static bool icm_tgl_is_supported(struct tb *tb)
{
/*
* If the firmware is not running use software CM. This platform
* should fully support both.
*/
return icm_firmware_running(tb->nhi);
}
static void icm_handle_notification(struct work_struct *work)
{
struct icm_notification *n = container_of(work, typeof(*n), work);
@ -2269,6 +2278,19 @@ struct tb *icm_probe(struct tb_nhi *nhi)
icm->rtd3_veto = icm_icl_rtd3_veto;
tb->cm_ops = &icm_icl_ops;
break;
case PCI_DEVICE_ID_INTEL_TGL_NHI0:
case PCI_DEVICE_ID_INTEL_TGL_NHI1:
icm->is_supported = icm_tgl_is_supported;
icm->driver_ready = icm_icl_driver_ready;
icm->set_uuid = icm_icl_set_uuid;
icm->device_connected = icm_icl_device_connected;
icm->device_disconnected = icm_tr_device_disconnected;
icm->xdomain_connected = icm_tr_xdomain_connected;
icm->xdomain_disconnected = icm_tr_xdomain_disconnected;
icm->rtd3_veto = icm_icl_rtd3_veto;
tb->cm_ops = &icm_icl_ops;
break;
}
if (!icm->is_supported || !icm->is_supported(tb)) {

View File

@ -1270,6 +1270,10 @@ static struct pci_device_id nhi_ids[] = {
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICL_NHI1),
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL_NHI0),
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL_NHI1),
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
/* Any USB4 compliant host */
{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_USB4, ~0) },
@ -1285,6 +1289,7 @@ static struct pci_driver nhi_driver = {
.id_table = nhi_ids,
.probe = nhi_probe,
.remove = nhi_remove,
.shutdown = nhi_remove,
.driver.pm = &nhi_pm_ops,
};

View File

@ -73,6 +73,8 @@ extern const struct tb_nhi_ops icl_nhi_ops;
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE 0x15ef
#define PCI_DEVICE_ID_INTEL_ICL_NHI1 0x8a0d
#define PCI_DEVICE_ID_INTEL_ICL_NHI0 0x8a17
#define PCI_DEVICE_ID_INTEL_TGL_NHI0 0x9a1b
#define PCI_DEVICE_ID_INTEL_TGL_NHI1 0x9a1d
#define PCI_CLASS_SERIAL_USB_USB4 0x0c0340

View File

@ -348,12 +348,6 @@ static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val,
return ret;
}
static int tb_switch_nvm_no_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
return -EPERM;
}
static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
@ -399,7 +393,6 @@ static struct nvmem_device *register_nvmem(struct tb_switch *sw, int id,
config.read_only = true;
} else {
config.name = "nvm_non_active";
config.reg_read = tb_switch_nvm_no_read;
config.reg_write = tb_switch_nvm_write;
config.root_only = true;
}

View File

@ -138,7 +138,7 @@ static int cdns_ti_probe(struct platform_device *pdev)
error = pm_runtime_get_sync(dev);
if (error < 0) {
dev_err(dev, "pm_runtime_get_sync failed: %d\n", error);
goto err_get;
goto err;
}
/* assert RESET */
@ -185,7 +185,6 @@ static int cdns_ti_probe(struct platform_device *pdev)
err:
pm_runtime_put_sync(data->dev);
err_get:
pm_runtime_disable(data->dev);
return error;

View File

@ -82,8 +82,6 @@ static void cdns3_exit_roles(struct cdns3 *cdns)
cdns3_drd_exit(cdns);
}
static enum usb_role cdsn3_hw_role_state_machine(struct cdns3 *cdns);
/**
* cdns3_core_init_role - initialize role of operation
* @cdns: Pointer to cdns3 structure
@ -193,12 +191,12 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
}
/**
* cdsn3_hw_role_state_machine - role switch state machine based on hw events.
* cdns3_hw_role_state_machine - role switch state machine based on hw events.
* @cdns: Pointer to controller structure.
*
* Returns next role to be entered based on hw events.
*/
static enum usb_role cdsn3_hw_role_state_machine(struct cdns3 *cdns)
static enum usb_role cdns3_hw_role_state_machine(struct cdns3 *cdns)
{
enum usb_role role;
int id, vbus;
@ -291,14 +289,10 @@ int cdns3_hw_role_switch(struct cdns3 *cdns)
enum usb_role real_role, current_role;
int ret = 0;
/* Do nothing if role based on syfs. */
if (cdns->role_override)
return 0;
pm_runtime_get_sync(cdns->dev);
current_role = cdns->role;
real_role = cdsn3_hw_role_state_machine(cdns);
real_role = cdns3_hw_role_state_machine(cdns);
/* Do nothing if nothing changed */
if (current_role == real_role)
@ -353,39 +347,6 @@ static int cdns3_role_set(struct usb_role_switch *sw, enum usb_role role)
pm_runtime_get_sync(cdns->dev);
/*
* FIXME: switch role framework should be extended to meet
* requirements. Driver assumes that role can be controlled
* by SW or HW. Temporary workaround is to use USB_ROLE_NONE to
* switch from SW to HW control.
*
* For dr_mode == USB_DR_MODE_OTG:
* if user sets USB_ROLE_HOST or USB_ROLE_DEVICE then driver
* sets role_override flag and forces that role.
* if user sets USB_ROLE_NONE, driver clears role_override and lets
* HW state machine take over.
*
* For dr_mode != USB_DR_MODE_OTG:
* Assumptions:
* 1. Restricted user control between NONE and dr_mode.
* 2. Driver doesn't need to rely on role_override flag.
* 3. Driver needs to ensure that HW state machine is never called
* if dr_mode != USB_DR_MODE_OTG.
*/
if (role == USB_ROLE_NONE)
cdns->role_override = 0;
else
cdns->role_override = 1;
/*
* HW state might have changed so driver need to trigger
* HW state machine if dr_mode == USB_DR_MODE_OTG.
*/
if (!cdns->role_override && cdns->dr_mode == USB_DR_MODE_OTG) {
cdns3_hw_role_switch(cdns);
goto pm_put;
}
if (cdns->role == role)
goto pm_put;
@ -528,6 +489,8 @@ static int cdns3_probe(struct platform_device *pdev)
sw_desc.get = cdns3_role_get;
sw_desc.allow_userspace_control = true;
sw_desc.driver_data = cdns;
if (device_property_read_bool(dev, "usb-role-switch"))
sw_desc.fwnode = dev->fwnode;
cdns->role_sw = usb_role_switch_register(dev, &sw_desc);
if (IS_ERR(cdns->role_sw)) {

View File

@ -62,7 +62,6 @@ struct cdns3_role_driver {
* This field based on firmware setting, kernel configuration
* and hardware configuration.
* @role_sw: pointer to role switch object.
* @role_override: set 1 if role rely on SW.
*/
struct cdns3 {
struct device *dev;
@ -90,7 +89,6 @@ struct cdns3 {
struct mutex mutex;
enum usb_dr_mode dr_mode;
struct usb_role_switch *role_sw;
int role_override;
};
int cdns3_hw_role_switch(struct cdns3 *cdns);

View File

@ -329,7 +329,7 @@ int cdns3_drd_init(struct cdns3 *cdns)
cdns->otg_v1_regs = NULL;
cdns->otg_regs = regs;
writel(1, &cdns->otg_v0_regs->simulate);
dev_info(cdns->dev, "DRD version v0 (%08x)\n",
dev_dbg(cdns->dev, "DRD version v0 (%08x)\n",
readl(&cdns->otg_v0_regs->version));
} else {
cdns->otg_v0_regs = NULL;
@ -337,7 +337,7 @@ int cdns3_drd_init(struct cdns3 *cdns)
cdns->otg_regs = (void *)&cdns->otg_v1_regs->cmd;
cdns->version = CDNS3_CONTROLLER_V1;
writel(1, &cdns->otg_v1_regs->simulate);
dev_info(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n",
dev_dbg(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n",
readl(&cdns->otg_v1_regs->did),
readl(&cdns->otg_v1_regs->rid));
}

View File

@ -332,13 +332,6 @@ static int cdns3_ep0_feature_handle_device(struct cdns3_device *priv_dev,
case TEST_K:
case TEST_SE0_NAK:
case TEST_PACKET:
cdns3_ep0_complete_setup(priv_dev, 0, 1);
/**
* Little delay to give the controller some time
* for sending status stage.
* This time should be less then 3ms.
*/
mdelay(1);
cdns3_set_register_bit(&priv_dev->regs->usb_cmd,
USB_CMD_STMODE |
USB_STS_TMODE_SEL(tmode - 1));

View File

@ -512,8 +512,8 @@ static void cdns3_wa2_descmiss_copy_data(struct cdns3_endpoint *priv_ep,
}
static struct usb_request *cdns3_wa2_gadget_giveback(struct cdns3_device *priv_dev,
struct cdns3_endpoint *priv_ep,
struct cdns3_request *priv_req)
struct cdns3_endpoint *priv_ep,
struct cdns3_request *priv_req)
{
if (priv_ep->flags & EP_QUIRK_EXTRA_BUF_EN &&
priv_req->flags & REQUEST_INTERNAL) {
@ -552,8 +552,8 @@ static struct usb_request *cdns3_wa2_gadget_giveback(struct cdns3_device *priv_d
}
static int cdns3_wa2_gadget_ep_queue(struct cdns3_device *priv_dev,
struct cdns3_endpoint *priv_ep,
struct cdns3_request *priv_req)
struct cdns3_endpoint *priv_ep,
struct cdns3_request *priv_req)
{
int deferred = 0;
@ -1905,7 +1905,7 @@ static int cdns3_ep_onchip_buffer_reserve(struct cdns3_device *priv_dev,
}
static void cdns3_stream_ep_reconfig(struct cdns3_device *priv_dev,
struct cdns3_endpoint *priv_ep)
struct cdns3_endpoint *priv_ep)
{
if (!priv_ep->use_streams || priv_dev->gadget.speed < USB_SPEED_SUPER)
return;
@ -1926,7 +1926,7 @@ static void cdns3_stream_ep_reconfig(struct cdns3_device *priv_dev,
}
static void cdns3_configure_dmult(struct cdns3_device *priv_dev,
struct cdns3_endpoint *priv_ep)
struct cdns3_endpoint *priv_ep)
{
struct cdns3_usb_regs __iomem *regs = priv_dev->regs;
@ -2965,7 +2965,7 @@ static int cdns3_init_eps(struct cdns3_device *priv_dev)
priv_ep->flags = 0;
dev_info(priv_dev->dev, "Initialized %s support: %s %s\n",
dev_dbg(priv_dev->dev, "Initialized %s support: %s %s\n",
priv_ep->name,
priv_ep->endpoint.caps.type_bulk ? "BULK, INT" : "",
priv_ep->endpoint.caps.type_iso ? "ISO" : "");
@ -3069,6 +3069,7 @@ static int cdns3_gadget_start(struct cdns3 *cdns)
priv_dev->gadget.name = "usb-ss-gadget";
priv_dev->gadget.sg_supported = 1;
priv_dev->gadget.quirk_avoids_skb_reserve = 1;
priv_dev->gadget.irq = cdns->dev_irq;
spin_lock_init(&priv_dev->lock);
INIT_WORK(&priv_dev->pending_status_wq,

View File

@ -18,17 +18,6 @@ config USB_CHIPIDEA
if USB_CHIPIDEA
config USB_CHIPIDEA_OF
tristate
depends on OF
default USB_CHIPIDEA
config USB_CHIPIDEA_PCI
tristate
depends on USB_PCI
depends on NOP_USB_XCEIV
default USB_CHIPIDEA
config USB_CHIPIDEA_UDC
bool "ChipIdea device controller"
depends on USB_GADGET
@ -43,4 +32,30 @@ config USB_CHIPIDEA_HOST
help
Say Y here to enable host controller functionality of the
ChipIdea driver.
config USB_CHIPIDEA_PCI
tristate "Enable PCI glue driver" if EMBEDDED
depends on USB_PCI
depends on NOP_USB_XCEIV
default USB_CHIPIDEA
config USB_CHIPIDEA_MSM
tristate "Enable MSM hsusb glue driver" if EMBEDDED
default USB_CHIPIDEA
config USB_CHIPIDEA_IMX
tristate "Enable i.MX USB glue driver" if EMBEDDED
depends on OF
default USB_CHIPIDEA
config USB_CHIPIDEA_GENERIC
tristate "Enable generic USB2 glue driver" if EMBEDDED
default USB_CHIPIDEA
config USB_CHIPIDEA_TEGRA
tristate "Enable Tegra UDC glue driver" if EMBEDDED
depends on OF
depends on USB_CHIPIDEA_UDC
default USB_CHIPIDEA
endif

View File

@ -8,11 +8,8 @@ ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o
# Glue/Bridge layers go here
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_usb2.o
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_msm.o
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_zevio.o
obj-$(CONFIG_USB_CHIPIDEA_PCI) += ci_hdrc_pci.o
obj-$(CONFIG_USB_CHIPIDEA_OF) += usbmisc_imx.o ci_hdrc_imx.o
obj-$(CONFIG_USB_CHIPIDEA_OF) += ci_hdrc_tegra.o
obj-$(CONFIG_USB_CHIPIDEA_GENERIC) += ci_hdrc_usb2.o
obj-$(CONFIG_USB_CHIPIDEA_MSM) += ci_hdrc_msm.o
obj-$(CONFIG_USB_CHIPIDEA_PCI) += ci_hdrc_pci.o
obj-$(CONFIG_USB_CHIPIDEA_IMX) += ci_hdrc_imx.o usbmisc_imx.o
obj-$(CONFIG_USB_CHIPIDEA_TEGRA) += ci_hdrc_tegra.o

View File

@ -25,6 +25,7 @@
#define TD_PAGE_COUNT 5
#define CI_HDRC_PAGE_SIZE 4096ul /* page size for TD's */
#define ENDPT_MAX 32
#define CI_MAX_BUF_SIZE (TD_PAGE_COUNT * CI_HDRC_PAGE_SIZE)
/******************************************************************************
* REGISTERS

View File

@ -271,6 +271,7 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event)
struct device *dev = ci->dev->parent;
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret = 0;
struct imx_usbmisc_data *mdata = data->usbmisc_data;
switch (event) {
case CI_HDRC_IMX_HSIC_ACTIVE_EVENT:
@ -284,11 +285,19 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event)
}
break;
case CI_HDRC_IMX_HSIC_SUSPEND_EVENT:
ret = imx_usbmisc_hsic_set_connect(data->usbmisc_data);
ret = imx_usbmisc_hsic_set_connect(mdata);
if (ret)
dev_err(dev,
"hsic_set_connect failed, err=%d\n", ret);
break;
case CI_HDRC_CONTROLLER_VBUS_EVENT:
if (ci->vbus_active)
ret = imx_usbmisc_charger_detection(mdata, true);
else
ret = imx_usbmisc_charger_detection(mdata, false);
if (ci->usb_phy)
schedule_work(&ci->usb_phy->chg_work);
break;
default:
break;
}
@ -414,6 +423,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
}
pdata.usb_phy = data->phy;
if (data->usbmisc_data)
data->usbmisc_data->usb_phy = data->phy;
if ((of_device_is_compatible(np, "fsl,imx53-usb") ||
of_device_is_compatible(np, "fsl,imx51-usb")) && pdata.usb_phy &&

View File

@ -24,6 +24,7 @@ struct imx_usbmisc_data {
unsigned int hsic:1; /* HSIC controlller */
unsigned int ext_id:1; /* ID from exteranl event */
unsigned int ext_vbus:1; /* Vbus from exteranl event */
struct usb_phy *usb_phy;
};
int imx_usbmisc_init(struct imx_usbmisc_data *data);
@ -31,5 +32,6 @@ int imx_usbmisc_init_post(struct imx_usbmisc_data *data);
int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled);
int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data);
int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on);
int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect);
#endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */

View File

@ -28,13 +28,19 @@ static const struct ci_hdrc_platform_data ci_default_pdata = {
.flags = CI_HDRC_DISABLE_STREAMING,
};
static struct ci_hdrc_platform_data ci_zynq_pdata = {
static const struct ci_hdrc_platform_data ci_zynq_pdata = {
.capoffset = DEF_CAPOFFSET,
};
static const struct ci_hdrc_platform_data ci_zevio_pdata = {
.capoffset = DEF_CAPOFFSET,
.flags = CI_HDRC_REGS_SHARED | CI_HDRC_FORCE_FULLSPEED,
};
static const struct of_device_id ci_hdrc_usb2_of_match[] = {
{ .compatible = "chipidea,usb2"},
{ .compatible = "xlnx,zynq-usb-2.20a", .data = &ci_zynq_pdata},
{ .compatible = "chipidea,usb2" },
{ .compatible = "xlnx,zynq-usb-2.20a", .data = &ci_zynq_pdata },
{ .compatible = "lsi,zevio-usb", .data = &ci_zevio_pdata },
{ }
};
MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match);
@ -64,13 +70,14 @@ static int ci_hdrc_usb2_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
priv->clk = devm_clk_get(dev, NULL);
if (!IS_ERR(priv->clk)) {
ret = clk_prepare_enable(priv->clk);
if (ret) {
dev_err(dev, "failed to enable the clock: %d\n", ret);
return ret;
}
priv->clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
ret = clk_prepare_enable(priv->clk);
if (ret) {
dev_err(dev, "failed to enable the clock: %d\n", ret);
return ret;
}
ci_pdata->name = dev_name(dev);
@ -94,8 +101,7 @@ static int ci_hdrc_usb2_probe(struct platform_device *pdev)
return 0;
clk_err:
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
clk_disable_unprepare(priv->clk);
return ret;
}

View File

@ -1,67 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
*
* Based off drivers/usb/chipidea/ci_hdrc_msm.c
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/usb/gadget.h>
#include <linux/usb/chipidea.h>
#include "ci.h"
static struct ci_hdrc_platform_data ci_hdrc_zevio_platdata = {
.name = "ci_hdrc_zevio",
.flags = CI_HDRC_REGS_SHARED | CI_HDRC_FORCE_FULLSPEED,
.capoffset = DEF_CAPOFFSET,
};
static int ci_hdrc_zevio_probe(struct platform_device *pdev)
{
struct platform_device *ci_pdev;
dev_dbg(&pdev->dev, "ci_hdrc_zevio_probe\n");
ci_pdev = ci_hdrc_add_device(&pdev->dev,
pdev->resource, pdev->num_resources,
&ci_hdrc_zevio_platdata);
if (IS_ERR(ci_pdev)) {
dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
return PTR_ERR(ci_pdev);
}
platform_set_drvdata(pdev, ci_pdev);
return 0;
}
static int ci_hdrc_zevio_remove(struct platform_device *pdev)
{
struct platform_device *ci_pdev = platform_get_drvdata(pdev);
ci_hdrc_remove_device(ci_pdev);
return 0;
}
static const struct of_device_id ci_hdrc_zevio_dt_ids[] = {
{ .compatible = "lsi,zevio-usb", },
{ /* sentinel */ }
};
static struct platform_driver ci_hdrc_zevio_driver = {
.probe = ci_hdrc_zevio_probe,
.remove = ci_hdrc_zevio_remove,
.driver = {
.name = "zevio_usb",
.of_match_table = ci_hdrc_zevio_dt_ids,
},
};
MODULE_DEVICE_TABLE(of, ci_hdrc_zevio_dt_ids);
module_platform_driver(ci_hdrc_zevio_driver);
MODULE_LICENSE("GPL v2");

View File

@ -3,42 +3,16 @@
* core.c - ChipIdea USB IP core family device controller
*
* Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
* Copyright (C) 2020 NXP
*
* Author: David Lopo
*/
/*
* Description: ChipIdea USB IP core family device controller
* Peter Chen <peter.chen@nxp.com>
*
* This driver is composed of several blocks:
* - HW: hardware interface
* - DBG: debug facilities (optional)
* - UTIL: utilities
* - ISR: interrupts handling
* - ENDPT: endpoint operations (Gadget API)
* - GADGET: gadget operations (Gadget API)
* - BUS: bus glue code, bus abstraction layer
*
* Compile Options
* - STALL_IN: non-empty bulk-in pipes cannot be halted
* if defined mass storage compliance succeeds but with warnings
* => case 4: Hi > Dn
* => case 5: Hi > Di
* => case 8: Hi <> Do
* if undefined usbtest 13 fails
* - TRACE: enable function tracing (depends on DEBUG)
*
* Main Features
* - Chapter 9 & Mass Storage Compliance with Gadget File Storage
* - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
* - Normal & LPM support
*
* USBTEST Report
* - OK: 0-12, 13 (STALL_IN defined) & 14
* - Not Supported: 15 & 16 (ISO)
*
* TODO List
* - Suspend & Remote Wakeup
* Main Features:
* - Four transfers are supported, usbtest is passed
* - USB Certification for gadget: CH9 and Mass Storage are passed
* - Low power mode
* - USB wakeup
*/
#include <linux/delay.h>
#include <linux/device.h>
@ -272,7 +246,7 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)
ci->rev = ci_get_revision(ci);
dev_dbg(ci->dev,
"ChipIdea HDRC found, revision: %d, lpm: %d; cap: %p op: %p\n",
"revision: %d, lpm: %d; cap: %px op: %px\n",
ci->rev, ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op);
/* setup lock mode ? */
@ -666,6 +640,7 @@ static int ci_usb_role_switch_set(struct usb_role_switch *sw,
static struct usb_role_switch_desc ci_role_switch = {
.set = ci_usb_role_switch_set,
.get = ci_usb_role_switch_get,
.allow_userspace_control = true,
};
static int ci_get_platdata(struct device *dev,
@ -1149,8 +1124,11 @@ static int ci_hdrc_probe(struct platform_device *pdev)
if (!ci_otg_is_fsm_mode(ci)) {
/* only update vbus status for peripheral */
if (ci->role == CI_ROLE_GADGET)
if (ci->role == CI_ROLE_GADGET) {
/* Pull down DP for possible charger detection */
hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
ci_handle_vbus_change(ci);
}
ret = ci_role_start(ci, ci->role);
if (ret) {

View File

@ -338,7 +338,7 @@ static int hw_usb_reset(struct ci_hdrc *ci)
*****************************************************************************/
static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
unsigned length)
unsigned int length, struct scatterlist *s)
{
int i;
u32 temp;
@ -366,7 +366,13 @@ static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
node->ptr->token |= cpu_to_le32(mul << __ffs(TD_MULTO));
}
temp = (u32) (hwreq->req.dma + hwreq->req.actual);
if (s) {
temp = (u32) (sg_dma_address(s) + hwreq->req.actual);
node->td_remaining_size = CI_MAX_BUF_SIZE - length;
} else {
temp = (u32) (hwreq->req.dma + hwreq->req.actual);
}
if (length) {
node->ptr->page[0] = cpu_to_le32(temp);
for (i = 1; i < TD_PAGE_COUNT; i++) {
@ -400,6 +406,122 @@ static inline u8 _usb_addr(struct ci_hw_ep *ep)
return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
}
static int prepare_td_for_non_sg(struct ci_hw_ep *hwep,
struct ci_hw_req *hwreq)
{
unsigned int rest = hwreq->req.length;
int pages = TD_PAGE_COUNT;
int ret = 0;
if (rest == 0) {
ret = add_td_to_list(hwep, hwreq, 0, NULL);
if (ret < 0)
return ret;
}
/*
* The first buffer could be not page aligned.
* In that case we have to span into one extra td.
*/
if (hwreq->req.dma % PAGE_SIZE)
pages--;
while (rest > 0) {
unsigned int count = min(hwreq->req.length - hwreq->req.actual,
(unsigned int)(pages * CI_HDRC_PAGE_SIZE));
ret = add_td_to_list(hwep, hwreq, count, NULL);
if (ret < 0)
return ret;
rest -= count;
}
if (hwreq->req.zero && hwreq->req.length && hwep->dir == TX
&& (hwreq->req.length % hwep->ep.maxpacket == 0)) {
ret = add_td_to_list(hwep, hwreq, 0, NULL);
if (ret < 0)
return ret;
}
return ret;
}
static int prepare_td_per_sg(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
struct scatterlist *s)
{
unsigned int rest = sg_dma_len(s);
int ret = 0;
hwreq->req.actual = 0;
while (rest > 0) {
unsigned int count = min_t(unsigned int, rest,
CI_MAX_BUF_SIZE);
ret = add_td_to_list(hwep, hwreq, count, s);
if (ret < 0)
return ret;
rest -= count;
}
return ret;
}
static void ci_add_buffer_entry(struct td_node *node, struct scatterlist *s)
{
int empty_td_slot_index = (CI_MAX_BUF_SIZE - node->td_remaining_size)
/ CI_HDRC_PAGE_SIZE;
int i;
node->ptr->token +=
cpu_to_le32(sg_dma_len(s) << __ffs(TD_TOTAL_BYTES));
for (i = empty_td_slot_index; i < TD_PAGE_COUNT; i++) {
u32 page = (u32) sg_dma_address(s) +
(i - empty_td_slot_index) * CI_HDRC_PAGE_SIZE;
page &= ~TD_RESERVED_MASK;
node->ptr->page[i] = cpu_to_le32(page);
}
}
static int prepare_td_for_sg(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
{
struct usb_request *req = &hwreq->req;
struct scatterlist *s = req->sg;
int ret = 0, i = 0;
struct td_node *node = NULL;
if (!s || req->zero || req->length == 0) {
dev_err(hwep->ci->dev, "not supported operation for sg\n");
return -EINVAL;
}
while (i++ < req->num_mapped_sgs) {
if (sg_dma_address(s) % PAGE_SIZE) {
dev_err(hwep->ci->dev, "not page aligned sg buffer\n");
return -EINVAL;
}
if (node && (node->td_remaining_size >= sg_dma_len(s))) {
ci_add_buffer_entry(node, s);
node->td_remaining_size -= sg_dma_len(s);
} else {
ret = prepare_td_per_sg(hwep, hwreq, s);
if (ret)
return ret;
node = list_entry(hwreq->tds.prev,
struct td_node, td);
}
s = sg_next(s);
}
return ret;
}
/**
* _hardware_enqueue: configures a request at hardware level
* @hwep: endpoint
@ -411,8 +533,6 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
{
struct ci_hdrc *ci = hwep->ci;
int ret = 0;
unsigned rest = hwreq->req.length;
int pages = TD_PAGE_COUNT;
struct td_node *firstnode, *lastnode;
/* don't queue twice */
@ -426,35 +546,13 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
if (ret)
return ret;
/*
* The first buffer could be not page aligned.
* In that case we have to span into one extra td.
*/
if (hwreq->req.dma % PAGE_SIZE)
pages--;
if (hwreq->req.num_mapped_sgs)
ret = prepare_td_for_sg(hwep, hwreq);
else
ret = prepare_td_for_non_sg(hwep, hwreq);
if (rest == 0) {
ret = add_td_to_list(hwep, hwreq, 0);
if (ret < 0)
goto done;
}
while (rest > 0) {
unsigned count = min(hwreq->req.length - hwreq->req.actual,
(unsigned)(pages * CI_HDRC_PAGE_SIZE));
ret = add_td_to_list(hwep, hwreq, count);
if (ret < 0)
goto done;
rest -= count;
}
if (hwreq->req.zero && hwreq->req.length && hwep->dir == TX
&& (hwreq->req.length % hwep->ep.maxpacket == 0)) {
ret = add_td_to_list(hwep, hwreq, 0);
if (ret < 0)
goto done;
}
if (ret)
return ret;
firstnode = list_first_entry(&hwreq->tds, struct td_node, td);
@ -1561,6 +1659,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
{
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&ci->lock, flags);
ci->vbus_active = is_active;
@ -1570,10 +1669,14 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
usb_phy_set_charger_state(ci->usb_phy, is_active ?
USB_CHARGER_PRESENT : USB_CHARGER_ABSENT);
if (ci->platdata->notify_event)
ret = ci->platdata->notify_event(ci,
CI_HDRC_CONTROLLER_VBUS_EVENT);
if (ci->driver)
ci_hdrc_gadget_connect(_gadget, is_active);
return 0;
return ret;
}
static int ci_udc_wakeup(struct usb_gadget *_gadget)
@ -1936,6 +2039,7 @@ static int udc_start(struct ci_hdrc *ci)
ci->gadget.max_speed = USB_SPEED_HIGH;
ci->gadget.name = ci->platdata->name;
ci->gadget.otg_caps = otg_caps;
ci->gadget.sg_supported = 1;
if (ci->platdata->flags & CI_HDRC_REQUIRES_ALIGNED_DMA)
ci->gadget.quirk_avoids_skb_reserve = 1;

View File

@ -61,16 +61,14 @@ struct td_node {
struct list_head td;
dma_addr_t dma;
struct ci_hw_td *ptr;
int td_remaining_size;
};
/**
* struct ci_hw_req - usb request representation
* @req: request structure for gadget drivers
* @queue: link to QH list
* @ptr: transfer descriptor for this request
* @dma: dma address for the transfer descriptor
* @zptr: transfer descriptor for the zero packet
* @zdma: dma address of the zero packet's transfer descriptor
* @tds: link to TD list
*/
struct ci_hw_req {
struct usb_request req;

View File

@ -8,6 +8,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/usb/otg.h>
#include "ci_hdrc_imx.h"
@ -99,6 +100,33 @@
#define MX7D_USB_VBUS_WAKEUP_SOURCE_AVALID MX7D_USB_VBUS_WAKEUP_SOURCE(1)
#define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID MX7D_USB_VBUS_WAKEUP_SOURCE(2)
#define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END MX7D_USB_VBUS_WAKEUP_SOURCE(3)
#define MX7D_USBNC_AUTO_RESUME BIT(2)
/* The default DM/DP value is pull-down */
#define MX7D_USBNC_USB_CTRL2_OPMODE(v) (v << 6)
#define MX7D_USBNC_USB_CTRL2_OPMODE_NON_DRIVING MX7D_USBNC_USB_CTRL2_OPMODE(1)
#define MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK (BIT(7) | BIT(6))
#define MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN BIT(8)
#define MX7D_USBNC_USB_CTRL2_DP_OVERRIDE_VAL BIT(12)
#define MX7D_USBNC_USB_CTRL2_DP_OVERRIDE_EN BIT(13)
#define MX7D_USBNC_USB_CTRL2_DM_OVERRIDE_VAL BIT(14)
#define MX7D_USBNC_USB_CTRL2_DM_OVERRIDE_EN BIT(15)
#define MX7D_USBNC_USB_CTRL2_DP_DM_MASK (BIT(12) | BIT(13) | \
BIT(14) | BIT(15))
#define MX7D_USB_OTG_PHY_CFG1 0x30
#define MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL BIT(0)
#define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 BIT(1)
#define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 BIT(2)
#define MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB BIT(3)
#define MX7D_USB_OTG_PHY_CFG2_DRVVBUS0 BIT(16)
#define MX7D_USB_OTG_PHY_CFG2 0x34
#define MX7D_USB_OTG_PHY_STATUS 0x3c
#define MX7D_USB_OTG_PHY_STATUS_LINE_STATE0 BIT(0)
#define MX7D_USB_OTG_PHY_STATUS_LINE_STATE1 BIT(1)
#define MX7D_USB_OTG_PHY_STATUS_VBUS_VLD BIT(3)
#define MX7D_USB_OTG_PHY_STATUS_CHRGDET BIT(29)
#define MX6_USB_OTG_WAKEUP_BITS (MX6_BM_WAKEUP_ENABLE | MX6_BM_VBUS_WAKEUP | \
MX6_BM_ID_WAKEUP)
@ -114,6 +142,8 @@ struct usbmisc_ops {
int (*hsic_set_connect)(struct imx_usbmisc_data *data);
/* It's called during suspend/resume */
int (*hsic_set_clk)(struct imx_usbmisc_data *data, bool enabled);
/* usb charger detection */
int (*charger_detection)(struct imx_usbmisc_data *data);
};
struct imx_usbmisc {
@ -609,10 +639,263 @@ static int usbmisc_imx7d_init(struct imx_usbmisc_data *data)
reg |= MX6_BM_PWR_POLARITY;
writel(reg, usbmisc->base);
reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID,
usbmisc->base + MX7D_USBNC_USB_CTRL2);
/* SoC non-burst setting */
reg = readl(usbmisc->base);
writel(reg | MX6_BM_NON_BURST_SETTING, usbmisc->base);
if (!data->hsic) {
reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID
| MX7D_USBNC_AUTO_RESUME,
usbmisc->base + MX7D_USBNC_USB_CTRL2);
}
spin_unlock_irqrestore(&usbmisc->lock, flags);
usbmisc_imx7d_set_wakeup(data, false);
return 0;
}
static int imx7d_charger_secondary_detection(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
struct usb_phy *usb_phy = data->usb_phy;
int val;
unsigned long flags;
/* VDM_SRC is connected to D- and IDP_SINK is connected to D+ */
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 |
MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 |
MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL,
usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
spin_unlock_irqrestore(&usbmisc->lock, flags);
usleep_range(1000, 2000);
/*
* Per BC 1.2, check voltage of D+:
* DCP: if greater than VDAT_REF;
* CDP: if less than VDAT_REF.
*/
val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
if (val & MX7D_USB_OTG_PHY_STATUS_CHRGDET) {
dev_dbg(data->dev, "It is a dedicate charging port\n");
usb_phy->chg_type = DCP_TYPE;
} else {
dev_dbg(data->dev, "It is a charging downstream port\n");
usb_phy->chg_type = CDP_TYPE;
}
return 0;
}
static void imx7_disable_charger_detector(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
u32 val;
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
val &= ~(MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB |
MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 |
MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 |
MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL);
writel(val, usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
/* Set OPMODE to be 2'b00 and disable its override */
val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2);
val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
writel(val & ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN,
usbmisc->base + MX7D_USBNC_USB_CTRL2);
spin_unlock_irqrestore(&usbmisc->lock, flags);
}
static int imx7d_charger_data_contact_detect(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
u32 val;
int i, data_pin_contact_count = 0;
/* Enable Data Contact Detect (DCD) per the USB BC 1.2 */
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB,
usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
spin_unlock_irqrestore(&usbmisc->lock, flags);
for (i = 0; i < 100; i = i + 1) {
val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
if (!(val & MX7D_USB_OTG_PHY_STATUS_LINE_STATE0)) {
if (data_pin_contact_count++ > 5)
/* Data pin makes contact */
break;
usleep_range(5000, 10000);
} else {
data_pin_contact_count = 0;
usleep_range(5000, 6000);
}
}
/* Disable DCD after finished data contact check */
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
writel(val & ~MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB,
usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
spin_unlock_irqrestore(&usbmisc->lock, flags);
if (i == 100) {
dev_err(data->dev,
"VBUS is coming from a dedicated power supply.\n");
return -ENXIO;
}
return 0;
}
static int imx7d_charger_primary_detection(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
struct usb_phy *usb_phy = data->usb_phy;
unsigned long flags;
u32 val;
/* VDP_SRC is connected to D+ and IDM_SINK is connected to D- */
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
val &= ~MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL;
writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 |
MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0,
usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
spin_unlock_irqrestore(&usbmisc->lock, flags);
usleep_range(1000, 2000);
/* Check if D- is less than VDAT_REF to determine an SDP per BC 1.2 */
val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
if (!(val & MX7D_USB_OTG_PHY_STATUS_CHRGDET)) {
dev_dbg(data->dev, "It is a standard downstream port\n");
usb_phy->chg_type = SDP_TYPE;
}
return 0;
}
/**
* Whole charger detection process:
* 1. OPMODE override to be non-driving
* 2. Data contact check
* 3. Primary detection
* 4. Secondary detection
* 5. Disable charger detection
*/
static int imx7d_charger_detection(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
struct usb_phy *usb_phy = data->usb_phy;
unsigned long flags;
u32 val;
int ret;
/* Check if vbus is valid */
val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
if (!(val & MX7D_USB_OTG_PHY_STATUS_VBUS_VLD)) {
dev_err(data->dev, "vbus is error\n");
return -EINVAL;
}
/*
* Keep OPMODE to be non-driving mode during the whole
* charger detection process.
*/
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
val |= MX7D_USBNC_USB_CTRL2_OPMODE_NON_DRIVING;
writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2);
val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
writel(val | MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN,
usbmisc->base + MX7D_USBNC_USB_CTRL2);
spin_unlock_irqrestore(&usbmisc->lock, flags);
ret = imx7d_charger_data_contact_detect(data);
if (ret)
return ret;
ret = imx7d_charger_primary_detection(data);
if (!ret && usb_phy->chg_type != SDP_TYPE)
ret = imx7d_charger_secondary_detection(data);
imx7_disable_charger_detector(data);
return ret;
}
static int usbmisc_imx7ulp_init(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
u32 reg;
if (data->index >= 1)
return -EINVAL;
spin_lock_irqsave(&usbmisc->lock, flags);
reg = readl(usbmisc->base);
if (data->disable_oc) {
reg |= MX6_BM_OVER_CUR_DIS;
} else {
reg &= ~MX6_BM_OVER_CUR_DIS;
/*
* If the polarity is not configured keep it as setup by the
* bootloader.
*/
if (data->oc_pol_configured && data->oc_pol_active_low)
reg |= MX6_BM_OVER_CUR_POLARITY;
else if (data->oc_pol_configured)
reg &= ~MX6_BM_OVER_CUR_POLARITY;
}
/* If the polarity is not set keep it as setup by the bootlader */
if (data->pwr_pol == 1)
reg |= MX6_BM_PWR_POLARITY;
writel(reg, usbmisc->base);
/* SoC non-burst setting */
reg = readl(usbmisc->base);
writel(reg | MX6_BM_NON_BURST_SETTING, usbmisc->base);
if (data->hsic) {
reg = readl(usbmisc->base);
writel(reg | MX6_BM_UTMI_ON_CLOCK, usbmisc->base);
reg = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET);
reg |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON;
writel(reg, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET);
/*
* For non-HSIC controller, the autoresume is enabled
* at MXS PHY driver (usbphy_ctrl bit18).
*/
reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
writel(reg | MX7D_USBNC_AUTO_RESUME,
usbmisc->base + MX7D_USBNC_USB_CTRL2);
} else {
reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID,
usbmisc->base + MX7D_USBNC_USB_CTRL2);
}
spin_unlock_irqrestore(&usbmisc->lock, flags);
@ -659,6 +942,14 @@ static const struct usbmisc_ops imx6sx_usbmisc_ops = {
static const struct usbmisc_ops imx7d_usbmisc_ops = {
.init = usbmisc_imx7d_init,
.set_wakeup = usbmisc_imx7d_set_wakeup,
.charger_detection = imx7d_charger_detection,
};
static const struct usbmisc_ops imx7ulp_usbmisc_ops = {
.init = usbmisc_imx7ulp_init,
.set_wakeup = usbmisc_imx7d_set_wakeup,
.hsic_set_connect = usbmisc_imx6_hsic_set_connect,
.hsic_set_clk = usbmisc_imx6_hsic_set_clk,
};
static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data)
@ -737,6 +1028,39 @@ int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on)
return usbmisc->ops->hsic_set_clk(data, on);
}
EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_clk);
int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect)
{
struct imx_usbmisc *usbmisc;
struct usb_phy *usb_phy;
int ret = 0;
if (!data)
return -EINVAL;
usbmisc = dev_get_drvdata(data->dev);
usb_phy = data->usb_phy;
if (!usbmisc->ops->charger_detection)
return -ENOTSUPP;
if (connect) {
ret = usbmisc->ops->charger_detection(data);
if (ret) {
dev_err(data->dev,
"Error occurs during detection: %d\n",
ret);
usb_phy->chg_state = USB_CHARGER_ABSENT;
} else {
usb_phy->chg_state = USB_CHARGER_PRESENT;
}
} else {
usb_phy->chg_state = USB_CHARGER_ABSENT;
usb_phy->chg_type = UNKNOWN_TYPE;
}
return ret;
}
EXPORT_SYMBOL_GPL(imx_usbmisc_charger_detection);
static const struct of_device_id usbmisc_imx_dt_ids[] = {
{
.compatible = "fsl,imx25-usbmisc",
@ -780,7 +1104,7 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
},
{
.compatible = "fsl,imx7ulp-usbmisc",
.data = &imx7d_usbmisc_ops,
.data = &imx7ulp_usbmisc_ops,
},
{ /* sentinel */ }
};

View File

@ -584,7 +584,7 @@ static void acm_softint(struct work_struct *work)
}
if (test_and_clear_bit(ACM_ERROR_DELAY, &acm->flags)) {
for (i = 0; i < ACM_NR; i++)
for (i = 0; i < acm->rx_buflimit; i++)
if (test_and_clear_bit(i, &acm->urbs_in_error_delay))
acm_submit_read_urb(acm, i, GFP_NOIO);
}

View File

@ -468,7 +468,8 @@ static int usblp_release(struct inode *inode, struct file *file)
usb_autopm_put_interface(usblp->intf);
if (!usblp->present) /* finish cleanup from disconnect */
usblp_cleanup(usblp);
usblp_cleanup(usblp); /* any URBs must be dead */
mutex_unlock(&usblp_mutex);
return 0;
}
@ -1375,9 +1376,11 @@ static void usblp_disconnect(struct usb_interface *intf)
usblp_unlink_urbs(usblp);
mutex_unlock(&usblp->mut);
usb_poison_anchored_urbs(&usblp->urbs);
if (!usblp->used)
usblp_cleanup(usblp);
mutex_unlock(&usblp_mutex);
}

View File

@ -159,6 +159,7 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
* usb_hcd_pci_probe - initialize PCI-based HCDs
* @dev: USB Host Controller being probed
* @id: pci hotplug id connecting controller to HCD framework
* @driver: USB HC driver handle
* Context: !in_interrupt()
*
* Allocates basic PCI resources for this USB host controller, and
@ -169,9 +170,9 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
*
* Return: 0 if successful.
*/
int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id,
const struct hc_driver *driver)
{
struct hc_driver *driver;
struct usb_hcd *hcd;
int retval;
int hcd_irq = 0;
@ -181,7 +182,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (!id)
return -EINVAL;
driver = (struct hc_driver *)id->driver_data;
if (!driver)
return -EINVAL;

View File

@ -93,7 +93,7 @@ module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(old_scheme_first,
"start with the old device initialization scheme");
static bool use_both_schemes = 1;
static bool use_both_schemes = true;
module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(use_both_schemes,
"try the other device initialization scheme if the "

View File

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* usb hub driver head file
*

View File

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* drivers/usb/core/otg_whitelist.h
*

View File

@ -1262,8 +1262,10 @@ void usb_create_sysfs_intf_files(struct usb_interface *intf)
if (!alt->string && !(udev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string && device_create_file(&intf->dev, &dev_attr_interface))
; /* We don't actually care if the function fails. */
if (alt->string && device_create_file(&intf->dev, &dev_attr_interface)) {
/* This is not a serious error */
dev_dbg(&intf->dev, "interface string descriptor file not created\n");
}
intf->sysfs_files_created = 1;
}

View File

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Released under the GPLv2 only.
*/

View File

@ -524,10 +524,25 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
greset |= GRSTCTL_CSFTRST;
dwc2_writel(hsotg, greset, GRSTCTL);
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 10000)) {
dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
__func__);
return -EBUSY;
if ((hsotg->hw_params.snpsid & DWC2_CORE_REV_MASK) <
(DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) {
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL,
GRSTCTL_CSFTRST, 10000)) {
dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST\n",
__func__);
return -EBUSY;
}
} else {
if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL,
GRSTCTL_CSFTRST_DONE, 10000)) {
dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST_DONE\n",
__func__);
return -EBUSY;
}
greset = dwc2_readl(hsotg, GRSTCTL);
greset &= ~GRSTCTL_CSFTRST;
greset |= GRSTCTL_CSFTRST_DONE;
dwc2_writel(hsotg, greset, GRSTCTL);
}
/* Wait for AHB master IDLE state */

View File

@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
/*
* core.h - DesignWare HS OTG Controller common declarations
*
@ -1103,8 +1103,10 @@ struct dwc2_hsotg {
#define DWC2_CORE_REV_3_00a 0x4f54300a
#define DWC2_CORE_REV_3_10a 0x4f54310a
#define DWC2_CORE_REV_4_00a 0x4f54400a
#define DWC2_CORE_REV_4_20a 0x4f54420a
#define DWC2_FS_IOT_REV_1_00a 0x5531100a
#define DWC2_HS_IOT_REV_1_00a 0x5532100a
#define DWC2_CORE_REV_MASK 0x0000ffff
/* DWC OTG HW Core ID */
#define DWC2_OTG_ID 0x4f540000
@ -1309,6 +1311,8 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg);
bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg);
int dwc2_check_core_version(struct dwc2_hsotg *hsotg);
/*
* Common core Functions.
* The following functions support managing the DWC_otg controller in either

View File

@ -416,10 +416,13 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
if (ret && (ret != -ENOTSUPP))
dev_err(hsotg->dev, "exit power_down failed\n");
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
call_gadget(hsotg, resume);
} else {
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
}
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
} else {
if (hsotg->params.power_down)
return;

View File

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* debug.h - Designware USB2 DRD controller debug header
*

View File

@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
/*
* hcd.h - DesignWare HS OTG Controller host-mode declarations
*

View File

@ -1,4 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
/*
* hw.h - DesignWare HS OTG Controller hardware definitions
*
@ -126,6 +126,7 @@
#define GRSTCTL HSOTG_REG(0x010)
#define GRSTCTL_AHBIDLE BIT(31)
#define GRSTCTL_DMAREQ BIT(30)
#define GRSTCTL_CSFTRST_DONE BIT(29)
#define GRSTCTL_TXFNUM_MASK (0x1f << 6)
#define GRSTCTL_TXFNUM_SHIFT 6
#define GRSTCTL_TXFNUM_LIMIT 0x1f

View File

@ -782,25 +782,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
u32 grxfsiz;
/*
* Attempt to ensure this device is really a DWC_otg Controller.
* Read and verify the GSNPSID register contents. The value should be
* 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx
*/
hw->snpsid = dwc2_readl(hsotg, GSNPSID);
if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
(hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
(hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
hw->snpsid);
return -ENODEV;
}
dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
hwcfg1 = dwc2_readl(hsotg, GHWCFG1);
hwcfg2 = dwc2_readl(hsotg, GHWCFG2);
hwcfg3 = dwc2_readl(hsotg, GHWCFG3);

View File

@ -362,6 +362,37 @@ static bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg)
return true;
}
/**
* Check core version
*
* @hsotg: Programming view of the DWC_otg controller
*
*/
int dwc2_check_core_version(struct dwc2_hsotg *hsotg)
{
struct dwc2_hw_params *hw = &hsotg->hw_params;
/*
* Attempt to ensure this device is really a DWC_otg Controller.
* Read and verify the GSNPSID register contents. The value should be
* 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx
*/
hw->snpsid = dwc2_readl(hsotg, GSNPSID);
if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
(hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
(hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
hw->snpsid);
return -ENODEV;
}
dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
return 0;
}
/**
* dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
* driver
@ -444,6 +475,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
of_property_read_bool(dev->dev.of_node,
"snps,need-phy-for-wake");
/*
* Before performing any core related operations
* check core version.
*/
retval = dwc2_check_core_version(hsotg);
if (retval)
goto error;
/*
* Reset before dwc2_get_hwparams() then it could get power-on real
* reset value form registers.

View File

@ -85,7 +85,9 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
* specified or set to OTG, then set the mode to peripheral.
*/
if (mode == USB_DR_MODE_OTG &&
dwc->revision >= DWC3_REVISION_330A)
(!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) ||
!device_property_read_bool(dwc->dev, "usb-role-switch")) &&
!DWC3_VER_IS_PRIOR(DWC3, 330A))
mode = USB_DR_MODE_PERIPHERAL;
}
@ -121,17 +123,19 @@ static void __dwc3_set_mode(struct work_struct *work)
if (dwc->dr_mode != USB_DR_MODE_OTG)
return;
pm_runtime_get_sync(dwc->dev);
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
dwc3_otg_update(dwc, 0);
if (!dwc->desired_dr_role)
return;
goto out;
if (dwc->desired_dr_role == dwc->current_dr_role)
return;
goto out;
if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
return;
goto out;
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_HOST:
@ -190,6 +194,9 @@ static void __dwc3_set_mode(struct work_struct *work)
break;
}
out:
pm_runtime_mark_last_busy(dwc->dev);
pm_runtime_put_autosuspend(dwc->dev);
}
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
@ -257,7 +264,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
* take a little more than 50ms. Set the polling rate at 20ms
* for 10 times instead.
*/
if (dwc3_is_usb31(dwc) && dwc->revision >= DWC3_USB31_REVISION_190A)
if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32))
retries = 10;
do {
@ -265,8 +272,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
if (!(reg & DWC3_DCTL_CSFTRST))
goto done;
if (dwc3_is_usb31(dwc) &&
dwc->revision >= DWC3_USB31_REVISION_190A)
if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32))
msleep(20);
else
udelay(1);
@ -283,7 +289,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
* is cleared, we must wait at least 50ms before accessing the PHY
* domain (synchronization delay).
*/
if (dwc3_is_usb31(dwc) && dwc->revision <= DWC3_USB31_REVISION_180A)
if (DWC3_VER_IS_WITHIN(DWC31, ANY, 180A))
msleep(50);
return 0;
@ -298,7 +304,7 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
u32 reg;
u32 dft;
if (dwc->revision < DWC3_REVISION_250A)
if (DWC3_VER_IS_PRIOR(DWC3, 250A))
return;
if (dwc->fladj == 0)
@ -579,7 +585,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
* will be '0' when the core is reset. Application needs to set it
* to '1' after the core initialization is completed.
*/
if (dwc->revision > DWC3_REVISION_194A)
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
/*
@ -670,7 +676,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
* be '0' when the core is reset. Application needs to set it to
* '1' after the core initialization is completed.
*/
if (dwc->revision > DWC3_REVISION_194A)
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
/*
@ -719,15 +725,13 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc)
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
dwc->ip = DWC3_GSNPS_ID(reg);
/* This should read as U3 followed by revision number */
if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
/* Detected DWC_usb3 IP */
if (DWC3_IP_IS(DWC3)) {
dwc->revision = reg;
} else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
/* Detected DWC_usb31 IP */
} else if (DWC3_IP_IS(DWC31) || DWC3_IP_IS(DWC32)) {
dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
dwc->revision |= DWC3_REVISION_IS_DWC31;
dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE);
} else {
return false;
@ -760,8 +764,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
*/
if ((dwc->dr_mode == USB_DR_MODE_HOST ||
dwc->dr_mode == USB_DR_MODE_OTG) &&
(dwc->revision >= DWC3_REVISION_210A &&
dwc->revision <= DWC3_REVISION_250A))
DWC3_VER_IS_WITHIN(DWC3, 210A, 250A))
reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
else
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
@ -804,7 +807,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
* and falls back to high-speed mode which causes
* the device to enter a Connect/Disconnect loop
*/
if (dwc->revision < DWC3_REVISION_190A)
if (DWC3_VER_IS_PRIOR(DWC3, 190A))
reg |= DWC3_GCTL_U2RSTECN;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
@ -957,7 +960,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
goto err0a;
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
dwc->revision > DWC3_REVISION_194A) {
!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) {
if (!dwc->dis_u3_susphy_quirk) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
@ -1004,20 +1007,20 @@ static int dwc3_core_init(struct dwc3 *dwc)
* the DWC_usb3 controller. It is NOT available in the
* DWC_usb31 controller.
*/
if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) {
if (DWC3_VER_IS_WITHIN(DWC3, 310A, ANY)) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
reg |= DWC3_GUCTL2_RST_ACTBITLATER;
dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
}
if (dwc->revision >= DWC3_REVISION_250A) {
if (!DWC3_VER_IS_PRIOR(DWC3, 250A)) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
/*
* Enable hardware control of sending remote wakeup
* in HS when the device is in the L1 state.
*/
if (dwc->revision >= DWC3_REVISION_290A)
if (!DWC3_VER_IS_PRIOR(DWC3, 290A))
reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW;
if (dwc->dis_tx_ipgap_linecheck_quirk)
@ -1049,7 +1052,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
* Must config both number of packets and max burst settings to enable
* RX and/or TX threshold.
*/
if (dwc3_is_usb31(dwc) && dwc->dr_mode == USB_DR_MODE_HOST) {
if (!DWC3_IP_IS(DWC3) && dwc->dr_mode == USB_DR_MODE_HOST) {
u8 rx_thr_num = dwc->rx_thr_num_pkt_prd;
u8 rx_maxburst = dwc->rx_max_burst_prd;
u8 tx_thr_num = dwc->tx_thr_num_pkt_prd;
@ -1371,10 +1374,9 @@ static void dwc3_get_properties(struct dwc3 *dwc)
/* check whether the core supports IMOD */
bool dwc3_has_imod(struct dwc3 *dwc)
{
return ((dwc3_is_usb3(dwc) &&
dwc->revision >= DWC3_REVISION_300A) ||
(dwc3_is_usb31(dwc) &&
dwc->revision >= DWC3_USB31_REVISION_120A));
return DWC3_VER_IS_WITHIN(DWC3, 300A, ANY) ||
DWC3_VER_IS_WITHIN(DWC31, 120A, ANY) ||
DWC3_IP_IS(DWC32);
}
static void dwc3_check_params(struct dwc3 *dwc)
@ -1395,7 +1397,7 @@ static void dwc3_check_params(struct dwc3 *dwc)
* affected version.
*/
if (!dwc->imod_interval &&
(dwc->revision == DWC3_REVISION_300A))
DWC3_VER_IS(DWC3, 300A))
dwc->imod_interval = 1;
/* Check the maximum_speed parameter */
@ -1417,7 +1419,7 @@ static void dwc3_check_params(struct dwc3 *dwc)
/*
* default to superspeed plus if we are capable.
*/
if (dwc3_is_usb31(dwc) &&
if ((DWC3_IP_IS(DWC31) || DWC3_IP_IS(DWC32)) &&
(DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
dwc->maximum_speed = USB_SPEED_SUPER_PLUS;

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