mirror of https://gitee.com/openkylin/linux.git
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:
commit
e611c0fe31
|
@ -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>;
|
||||
};
|
|
@ -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>;
|
||||
};
|
|
@ -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;
|
||||
};
|
|
@ -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";
|
||||
};
|
|
@ -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>;
|
||||
};
|
|
@ -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";
|
||||
};
|
||||
};
|
|
@ -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";
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
};
|
||||
...
|
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -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";
|
||||
};
|
|
@ -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>;
|
||||
};
|
|
@ -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";
|
||||
};
|
|
@ -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>;
|
||||
};
|
|
@ -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>;
|
||||
};
|
|
@ -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";
|
||||
};
|
||||
};
|
|
@ -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:
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
||||
...
|
|
@ -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"
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -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:
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
15
MAINTAINERS
15
MAINTAINERS
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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, ®);
|
||||
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");
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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", ®);
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */ }
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* usb hub driver head file
|
||||
*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* drivers/usb/core/otg_whitelist.h
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Released under the GPLv2 only.
|
||||
*/
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* debug.h - Designware USB2 DRD controller debug header
|
||||
*
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue