phy: for 5.8

*) Add new PHY driver to support Cadence SALVO PHY which supports USB3 & USB2
 *) Add new PHY driver to support Intel ComboPhy which supports PCIe, SATA and
    EMAC
 *) Add new PHY driver for Qualcomm IPQ40xx USB PHY
 *) Add new PHY driver for Synopsys FemtoPHY V2 driver used in Qualcomm SOCs
 *) Add support for Qualcomm SM8250 UFS PHY and SM8150 QMP USB3 PHY in
    qcom-qmp-phy driver
 *) Add support for Amlogic USB2 PHY on Meson8m2 in phy-meson8b-usb2 driver
 *) Add DisplayPort mode support in Wiz (TI Cadence PHY wrapper), to enable eDP
    in TI's J721E SoC
 *) Add support for super speed USB PHY in TI's AM654 SoC
 *) Add fix in Broadcom Stingray USB PHY to get USB PHY PLL lock reliably
 *) Add fix in Samsung phy-s5pv210-usb2 to get USB working on s5pv210
 *) Add fix in Amlogic phy-meson8b-usb2 to get host only mode working on Meson8
 *) Add fix in Cadence phy-cadence-sierra to get USB3 device disconnect issue
 *) Convert meson8b-usb2-phy, qcom-qmp-phy, rcar-gen3-phy-usb2 and
    rcar-gen3-phy-usb3 device tree binding to YAML schema
 *) Minor fixes and cleanups in phy-cpcap-usb, j721e-wiz, omap-usb2,
    phy-bcm-sr-usb, phy-brcm-usb PHY driver
 
 Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCgAsFiEEUXMr/TfP2p4suIY5Dlx4XIBNgtkFAl7GlXwOHGtpc2hvbkB0
 aS5jb20ACgkQDlx4XIBNgtkapw/+IpzMaMb//L1Z4HXLCUljz37OpWER6u6GivRK
 +OE89+NzsoYdNrCPVM7b9VvFdTmlDRm4N3c8PoZS5Xw5lBMuzYqobafS2duLt401
 ysuipcSihM5qKHboOXqDGHhzbTbYlLBPa7m7RHnlasC6hhK51a31Kmh6wb+buZKG
 iTogZAnObr7/EKm7HAud96vRv3Mh6V8UQgA4q1lnYnXiCWNY6w/U61JFVoWuaDxg
 5ED0nS5F6sgS+EIqYVo7du9sJO8dgbD4xmBV4ODXTTaszgXnRps+bBjMWIYBiXNt
 Iuwx67ZyEI1kYnFx/EjO3ktRQWtkyoo7ljm494Ds685rY/Ibpea02KPqOu1Adn69
 vph3R3YpH/B7C9CC9MTt00RRr3DCHS/GtBeNZAdkp8r+AQibwp4KRyLSFZgb3MjN
 0DkGGaZM+LDrlGdi4Bq0PJyy2p5I7zG2F2tw8hcJw25FO1KEJVyjtOPCYyDQSIzn
 vlI4q0bTl3kjQYhnxYulEiYB+6WfjOOG0oGCNAi1fhWbAakJbOVHX0icq0idFp/a
 PQRfsVjDCPGxF8gLAM//t4ITc6ZyAPmSq/yOu/bSCHkUIxfjd10aFs/6OIXaRaB+
 WbvsT6A6OwEdQOyod2iiP66RvQskujWK/BA1frXTF7hzPlL7qgVNhtHNlLAcwOXD
 A1Bl+pw=
 =H+Lw
 -----END PGP SIGNATURE-----

Merge tag 'phy-for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy into usb-next

Kishon writes:

phy: for 5.8

*) Add new PHY driver to support Cadence SALVO PHY which supports USB3 & USB2
*) Add new PHY driver to support Intel ComboPhy which supports PCIe, SATA and
   EMAC
*) Add new PHY driver for Qualcomm IPQ40xx USB PHY
*) Add new PHY driver for Synopsys FemtoPHY V2 driver used in Qualcomm SOCs
*) Add support for Qualcomm SM8250 UFS PHY and SM8150 QMP USB3 PHY in
   qcom-qmp-phy driver
*) Add support for Amlogic USB2 PHY on Meson8m2 in phy-meson8b-usb2 driver
*) Add DisplayPort mode support in Wiz (TI Cadence PHY wrapper), to enable eDP
   in TI's J721E SoC
*) Add support for super speed USB PHY in TI's AM654 SoC
*) Add fix in Broadcom Stingray USB PHY to get USB PHY PLL lock reliably
*) Add fix in Samsung phy-s5pv210-usb2 to get USB working on s5pv210
*) Add fix in Amlogic phy-meson8b-usb2 to get host only mode working on Meson8
*) Add fix in Cadence phy-cadence-sierra to get USB3 device disconnect issue
*) Convert meson8b-usb2-phy, qcom-qmp-phy, rcar-gen3-phy-usb2 and
   rcar-gen3-phy-usb3 device tree binding to YAML schema
*) Minor fixes and cleanups in phy-cpcap-usb, j721e-wiz, omap-usb2,
   phy-bcm-sr-usb, phy-brcm-usb PHY driver

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

* tag 'phy-for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (43 commits)
  phy: intel: Add driver support for ComboPhy
  dt-bindings: phy: Add YAML schemas for Intel ComboPhy
  dt-bindings: phy: Add PHY_TYPE_XPCS definition
  phy: qcom-qmp: Add QMP V3 USB3 PHY support for SC7180
  dt-bindings: phy: qcom,qmp-usb3-dp: Add support for SC7180
  dt-bindings: phy: qcom,qmp-usb3-dp: Add dt bindings for USB3 DP PHY
  dt-bindings: phy: qcom,qmp: Convert QMP PHY bindings to yaml
  phy: cadence: sierra: Fix for USB3 U1/U2 state
  phy: ti: am654: add support for USB super-speed
  phy: ti: am654: show up in regmap debugfs
  drivers: phy: sr-usb: do not use internal fsm for USB2 phy init
  dt-bindings: phy: renesas: usb3-phy: add r8a77961 support
  dt-bindings: phy: renesas: usb3-phy: convert bindings to json-schema
  dt-bindings: phy: renesas: usb2-phy: add r8a77961 support
  dt-bindings: phy: renesas: usb2-phy: convert bindings to json-schema
  phy: qcom-qmp: Ensure register indirection arrays initialized
  phy: omap-usb2: Clean up exported header
  phy: phy-bcm-ns2-usbdrd: Constify phy_ops
  phy: phy-brcm-usb: Constify static structs
  phy: sr-usb: Constify phy_ops
  ...
This commit is contained in:
Greg Kroah-Hartman 2020-05-22 09:28:16 +02:00
commit 14f3a5ccac
38 changed files with 3228 additions and 644 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -17,5 +17,6 @@
#define PHY_TYPE_USB3 4
#define PHY_TYPE_UFS 5
#define PHY_TYPE_DP 6
#define PHY_TYPE_XPCS 7
#endif /* _DT_BINDINGS_PHY */

View file

@ -2,68 +2,14 @@
/*
* omap_usb.h -- omap usb2 phy header file
*
* 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>
*/
#ifndef __DRIVERS_OMAP_USB2_H
#define __DRIVERS_OMAP_USB2_H
#include <linux/io.h>
#include <linux/usb/otg.h>
struct usb_dpll_params {
u16 m;
u8 n;
u8 freq:3;
u8 sd;
u32 mf;
};
enum omap_usb_phy_type {
TYPE_USB2, /* USB2_PHY, power down in CONTROL_DEV_CONF */
TYPE_DRA7USB2, /* USB2 PHY, power and power_aux e.g. DRA7 */
TYPE_AM437USB2, /* USB2 PHY, power e.g. AM437x */
};
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;
enum omap_usb_phy_type type;
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;
};
struct usb_phy_data {
const char *label;
u8 flags;
u32 mask;
u32 power_on;
u32 power_off;
};
/* Driver Flags */
#define OMAP_USB2_HAS_START_SRP (1 << 0)
#define OMAP_USB2_HAS_SET_VBUS (1 << 1)
#define OMAP_USB2_CALIBRATE_FALSE_DISCONNECT (1 << 2)
#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)
#include <linux/usb/phy_companion.h>
#define phy_to_omapusb(x) container_of((x), struct omap_usb, phy)
@ -76,15 +22,4 @@ static inline int omap_usb2_set_comparator(struct phy_companion *comparator)
}
#endif
static inline u32 omap_usb_readl(void __iomem *addr, unsigned offset)
{
return __raw_readl(addr + offset);
}
static inline void omap_usb_writel(void __iomem *addr, unsigned offset,
u32 data)
{
__raw_writel(data, addr + offset);
}
#endif /* __DRIVERS_OMAP_USB_H */