Merge tag 'phy-for-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 19 Dec 2022 14:40:58 +0000 (08:40 -0600)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 19 Dec 2022 14:40:58 +0000 (08:40 -0600)
Pull phy updates from Vinod Koul:
 "This tme we have again a big pile of qcom-qmp-* changes, one new
  driver and bunch of new hardware support.

  New hardware support:

   - Allwinner H616 USB PHY and A100 DPHY support

   - TI J721s2, J784s4 and J721e support

   - Freescale i.MX8MP PCIe PHY support

   - New driver for Renesas Ethernet SERDES supporting R-Car S4-8

   - Qualcomm SM8450 PCIe1 PHY support in EP mode

   - Qualcomm SC8280XP PCIe PHY support (including x4 mode)

   - Fixed Qualcomm SC8280XP USB4-USB3-DP PHY DT bindings

  Updates:

   - A big pile of updates on qcom-qmp-* drivers following the driver
     split and reorganization merged earlier

   - Phy order of API calls documentation update"

* tag 'phy-for-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (174 commits)
  phy: ti: phy-j721e-wiz: add j721s2-wiz-10g module support
  dt-bindings: phy-j721e-wiz: add j721s2 compatible string
  phy: use devm_platform_get_and_ioremap_resource()
  phy: allwinner: phy-sun6i-mipi-dphy: Add the A100 DPHY variant
  phy: allwinner: phy-sun6i-mipi-dphy: Add a variant power-on hook
  phy: allwinner: phy-sun6i-mipi-dphy: Set the enable bit last
  phy: allwinner: phy-sun6i-mipi-dphy: Make RX support optional
  dt-bindings: sun6i-a31-mipi-dphy: Add the A100 DPHY variant
  dt-bindings: sun6i-a31-mipi-dphy: Add the interrupts property
  phy: qcom-qmp-pcie: drop redundant clock allocation
  phy: qcom-qmp-usb: drop redundant clock allocation
  phy: qcom-qmp: drop unused type header
  phy: qcom-qmp-usb: drop sc8280xp reference-clock source
  dt-bindings: phy: qcom,sc8280xp-qmp-usb3-uni: drop reference-clock source
  phy: qcom-qmp-combo: add support for updated sc8280xp binding
  phy: qcom-qmp-combo: rename DP_PHY register pointer
  phy: qcom-qmp-combo: rename common-register pointers
  phy: qcom-qmp-combo: clean up DP clock callbacks
  phy: qcom-qmp-combo: separate clock and provider registration
  phy: qcom-qmp-combo: add clock registration helper
  ...

52 files changed:
Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml
Documentation/devicetree/bindings/phy/allwinner,sun8i-h3-usb-phy.yaml
Documentation/devicetree/bindings/phy/fsl,imx8-pcie-phy.yaml
Documentation/devicetree/bindings/phy/qcom,ipq8074-qmp-pcie-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-ufs-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-usb3-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,qmp-pcie-phy.yaml [deleted file]
Documentation/devicetree/bindings/phy/qcom,qmp-ufs-phy.yaml [deleted file]
Documentation/devicetree/bindings/phy/qcom,qmp-usb-phy.yaml [deleted file]
Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml [deleted file]
Documentation/devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/renesas,r8a779f0-ether-serdes.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml
Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml
Documentation/driver-api/phy/phy.rst
drivers/pci/controller/dwc/pcie-qcom-ep.c
drivers/pci/controller/dwc/pcie-qcom.c
drivers/phy/allwinner/phy-sun4i-usb.c
drivers/phy/allwinner/phy-sun6i-mipi-dphy.c
drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
drivers/phy/broadcom/phy-brcm-usb-init.c
drivers/phy/broadcom/phy-brcm-usb-init.h
drivers/phy/broadcom/phy-brcm-usb.c
drivers/phy/freescale/phy-fsl-imx8m-pcie.c
drivers/phy/marvell/phy-mmp3-hsic.c
drivers/phy/marvell/phy-mvebu-a3700-comphy.c
drivers/phy/qualcomm/Kconfig
drivers/phy/qualcomm/phy-qcom-qmp-combo.c
drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c
drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5.h
drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h
drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h [new file with mode: 0644]
drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
drivers/phy/qualcomm/phy-qcom-qmp-usb.c
drivers/phy/qualcomm/phy-qcom-qmp.h
drivers/phy/renesas/Kconfig
drivers/phy/renesas/Makefile
drivers/phy/renesas/r8a779f0-ether-serdes.c [new file with mode: 0644]
drivers/phy/tegra/phy-tegra194-p2u.c
drivers/phy/tegra/xusb-tegra124.c
drivers/phy/tegra/xusb-tegra186.c
drivers/phy/tegra/xusb-tegra210.c
drivers/phy/tegra/xusb.c
drivers/phy/tegra/xusb.h
drivers/phy/ti/phy-gmii-sel.c
drivers/phy/ti/phy-j721e-wiz.c
include/dt-bindings/phy/phy-qcom-qmp.h [new file with mode: 0644]

index dfb6a89935351d14e8dd7e4409e63ef85468859e..fe9702e7bdd8a1f8cb4657773591401e5212c17f 100644 (file)
@@ -17,13 +17,20 @@ properties:
   compatible:
     oneOf:
       - const: allwinner,sun6i-a31-mipi-dphy
+      - const: allwinner,sun50i-a100-mipi-dphy
       - items:
           - const: allwinner,sun50i-a64-mipi-dphy
           - const: allwinner,sun6i-a31-mipi-dphy
+      - items:
+          - const: allwinner,sun20i-d1-mipi-dphy
+          - const: allwinner,sun50i-a100-mipi-dphy
 
   reg:
     maxItems: 1
 
+  interrupts:
+    maxItems: 1
+
   clocks:
     items:
       - description: Bus Clock
@@ -53,6 +60,7 @@ required:
   - "#phy-cells"
   - compatible
   - reg
+  - interrupts
   - clocks
   - clock-names
   - resets
@@ -61,9 +69,12 @@ additionalProperties: false
 
 examples:
   - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
     dphy0: d-phy@1ca1000 {
         compatible = "allwinner,sun6i-a31-mipi-dphy";
         reg = <0x01ca1000 0x1000>;
+        interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
         clocks = <&ccu 23>, <&ccu 97>;
         clock-names = "bus", "mod";
         resets = <&ccu 4>;
index 77539b4601c24d794930fa465d0c1bbf0c16b178..2df012d13655ee361e19b2b6e53e2ecc625206d7 100644 (file)
@@ -36,18 +36,22 @@ properties:
       - const: pmu3
 
   clocks:
+    minItems: 4
     items:
       - description: USB OTG PHY bus clock
       - description: USB Host 0 PHY bus clock
       - description: USB Host 1 PHY bus clock
       - description: USB Host 2 PHY bus clock
+      - description: PMU clock for host port 2
 
   clock-names:
+    minItems: 4
     items:
       - const: usb0_phy
       - const: usb1_phy
       - const: usb2_phy
       - const: usb3_phy
+      - const: pmu2_clk
 
   resets:
     items:
@@ -96,6 +100,28 @@ required:
   - resets
   - reset-names
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - allwinner,sun50i-h616-usb-phy
+    then:
+      properties:
+        clocks:
+          minItems: 5
+
+        clock-names:
+          minItems: 5
+    else:
+      properties:
+        clocks:
+          maxItems: 4
+
+        clock-names:
+          maxItems: 4
+
 additionalProperties: false
 
 examples:
index 0af765ba2793262a9284cdf52dda61dfc7f97177..182a219387b0e69164148b62a819d4dd5ba462b1 100644 (file)
@@ -16,6 +16,7 @@ properties:
   compatible:
     enum:
       - fsl,imx8mm-pcie-phy
+      - fsl,imx8mp-pcie-phy
 
   reg:
     maxItems: 1
@@ -28,11 +29,16 @@ properties:
       - const: ref
 
   resets:
-    maxItems: 1
+    minItems: 1
+    maxItems: 2
 
   reset-names:
-    items:
-      - const: pciephy
+    oneOf:
+      - items:          # for iMX8MM
+          - const: pciephy
+      - items:          # for IMX8MP
+          - const: pciephy
+          - const: perst
 
   fsl,refclk-pad-mode:
     description: |
@@ -60,6 +66,10 @@ properties:
     description: A boolean property indicating the CLKREQ# signal is
       not supported in the board design (optional)
 
+  power-domains:
+    description: PCIe PHY  power domain (optional).
+    maxItems: 1
+
 required:
   - "#phy-cells"
   - compatible
diff --git a/Documentation/devicetree/bindings/phy/qcom,ipq8074-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,ipq8074-qmp-pcie-phy.yaml
new file mode 100644 (file)
index 0000000..62045dc
--- /dev/null
@@ -0,0 +1,299 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,ipq8074-qmp-pcie-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QMP PHY controller (PCIe, IPQ8074)
+
+maintainers:
+  - Vinod Koul <vkoul@kernel.org>
+
+description:
+  QMP PHY controller supports physical layer functionality for a number of
+  controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.
+
+  Note that these bindings are for SoCs up to SC8180X. For newer SoCs, see
+  qcom,sc8280xp-qmp-pcie-phy.yaml.
+
+properties:
+  compatible:
+    enum:
+      - qcom,ipq6018-qmp-pcie-phy
+      - qcom,ipq8074-qmp-gen3-pcie-phy
+      - qcom,ipq8074-qmp-pcie-phy
+      - qcom,msm8998-qmp-pcie-phy
+      - qcom,sc8180x-qmp-pcie-phy
+      - qcom,sdm845-qhp-pcie-phy
+      - qcom,sdm845-qmp-pcie-phy
+      - qcom,sdx55-qmp-pcie-phy
+      - qcom,sm8250-qmp-gen3x1-pcie-phy
+      - qcom,sm8250-qmp-gen3x2-pcie-phy
+      - qcom,sm8250-qmp-modem-pcie-phy
+      - qcom,sm8450-qmp-gen3x1-pcie-phy
+      - qcom,sm8450-qmp-gen4x2-pcie-phy
+
+  reg:
+    items:
+      - description: serdes
+
+  "#address-cells":
+    enum: [ 1, 2 ]
+
+  "#size-cells":
+    enum: [ 1, 2 ]
+
+  ranges: true
+
+  clocks:
+    minItems: 2
+    maxItems: 4
+
+  clock-names:
+    minItems: 2
+    maxItems: 4
+
+  resets:
+    minItems: 1
+    maxItems: 2
+
+  reset-names:
+    minItems: 1
+    maxItems: 2
+
+  vdda-phy-supply: true
+
+  vdda-pll-supply: true
+
+  vddp-ref-clk-supply: true
+
+patternProperties:
+  "^phy@[0-9a-f]+$":
+    type: object
+    description: single PHY-provider child node
+    properties:
+      reg:
+        minItems: 3
+        maxItems: 6
+
+      clocks:
+        items:
+          - description: PIPE clock
+
+      clock-names:
+        deprecated: true
+        items:
+          - const: pipe0
+
+      "#clock-cells":
+        const: 0
+
+      clock-output-names:
+        maxItems: 1
+
+      "#phy-cells":
+        const: 0
+
+    required:
+      - reg
+      - clocks
+      - "#clock-cells"
+      - clock-output-names
+      - "#phy-cells"
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+
+additionalProperties: false
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,msm8998-qmp-pcie-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 3
+        clock-names:
+          items:
+            - const: aux
+            - const: cfg_ahb
+            - const: ref
+        resets:
+          maxItems: 2
+        reset-names:
+          items:
+            - const: phy
+            - const: common
+      required:
+        - vdda-phy-supply
+        - vdda-pll-supply
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,ipq6018-qmp-pcie-phy
+              - qcom,ipq8074-qmp-gen3-pcie-phy
+              - qcom,ipq8074-qmp-pcie-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 2
+        clock-names:
+          items:
+            - const: aux
+            - const: cfg_ahb
+        resets:
+          maxItems: 2
+        reset-names:
+          items:
+            - const: phy
+            - const: common
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,sc8180x-qmp-pcie-phy
+              - qcom,sdm845-qhp-pcie-phy
+              - qcom,sdm845-qmp-pcie-phy
+              - qcom,sdx55-qmp-pcie-phy
+              - qcom,sm8250-qmp-gen3x1-pcie-phy
+              - qcom,sm8250-qmp-gen3x2-pcie-phy
+              - qcom,sm8250-qmp-modem-pcie-phy
+              - qcom,sm8450-qmp-gen3x1-pcie-phy
+              - qcom,sm8450-qmp-gen4x2-pcie-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 4
+        clock-names:
+          items:
+            - const: aux
+            - const: cfg_ahb
+            - const: ref
+            - const: refgen
+        resets:
+          maxItems: 1
+        reset-names:
+          items:
+            - const: phy
+      required:
+        - vdda-phy-supply
+        - vdda-pll-supply
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,sm8250-qmp-gen3x2-pcie-phy
+              - qcom,sm8250-qmp-modem-pcie-phy
+              - qcom,sm8450-qmp-gen4x2-pcie-phy
+    then:
+      patternProperties:
+        "^phy@[0-9a-f]+$":
+          properties:
+            reg:
+              items:
+                - description: TX lane 1
+                - description: RX lane 1
+                - description: PCS
+                - description: TX lane 2
+                - description: RX lane 2
+                - description: PCS_MISC
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,sc8180x-qmp-pcie-phy
+              - qcom,sdm845-qmp-pcie-phy
+              - qcom,sdx55-qmp-pcie-phy
+              - qcom,sm8250-qmp-gen3x1-pcie-phy
+              - qcom,sm8450-qmp-gen3x1-pcie-phy
+    then:
+      patternProperties:
+        "^phy@[0-9a-f]+$":
+          properties:
+            reg:
+              items:
+                - description: TX
+                - description: RX
+                - description: PCS
+                - description: PCS_MISC
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,ipq6018-qmp-pcie-phy
+              - qcom,ipq8074-qmp-pcie-phy
+              - qcom,msm8998-qmp-pcie-phy
+              - qcom,sdm845-qhp-pcie-phy
+    then:
+      patternProperties:
+        "^phy@[0-9a-f]+$":
+          properties:
+            reg:
+              items:
+                - description: TX
+                - description: RX
+                - description: PCS
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sm8250.h>
+    phy-wrapper@1c0e000 {
+        compatible = "qcom,sm8250-qmp-gen3x2-pcie-phy";
+        reg = <0x01c0e000 0x1c0>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x0 0x01c0e000 0x1000>;
+
+        clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>,
+                 <&gcc GCC_PCIE_1_CFG_AHB_CLK>,
+                 <&gcc GCC_PCIE_WIGIG_CLKREF_EN>,
+                 <&gcc GCC_PCIE1_PHY_REFGEN_CLK>;
+        clock-names = "aux", "cfg_ahb", "ref", "refgen";
+
+        resets = <&gcc GCC_PCIE_1_PHY_BCR>;
+        reset-names = "phy";
+
+        vdda-phy-supply = <&vreg_l10c_0p88>;
+        vdda-pll-supply = <&vreg_l6b_1p2>;
+
+        phy@200 {
+            reg = <0x200 0x170>,
+                  <0x400 0x200>,
+                  <0xa00 0x1f0>,
+                  <0x600 0x170>,
+                  <0x800 0x200>,
+                  <0xe00 0xf4>;
+
+            clocks = <&gcc GCC_PCIE_1_PIPE_CLK>;
+
+            #clock-cells = <0>;
+            clock-output-names = "pcie_1_pipe_clk";
+
+            #phy-cells = <0>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-ufs-phy.yaml
new file mode 100644 (file)
index 0000000..be41acb
--- /dev/null
@@ -0,0 +1,241 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,msm8996-qmp-ufs-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QMP PHY controller (UFS, MSM8996)
+
+maintainers:
+  - Vinod Koul <vkoul@kernel.org>
+
+description:
+  QMP PHY controller supports physical layer functionality for a number of
+  controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.
+
+  Note that these bindings are for SoCs up to SC8180X. For newer SoCs, see
+  qcom,sc8280xp-qmp-ufs-phy.yaml.
+
+properties:
+  compatible:
+    enum:
+      - qcom,msm8996-qmp-ufs-phy
+      - qcom,msm8998-qmp-ufs-phy
+      - qcom,sc8180x-qmp-ufs-phy
+      - qcom,sdm845-qmp-ufs-phy
+      - qcom,sm6115-qmp-ufs-phy
+      - qcom,sm6350-qmp-ufs-phy
+      - qcom,sm8150-qmp-ufs-phy
+      - qcom,sm8250-qmp-ufs-phy
+      - qcom,sm8350-qmp-ufs-phy
+      - qcom,sm8450-qmp-ufs-phy
+
+  reg:
+    items:
+      - description: serdes
+
+  "#address-cells":
+    enum: [ 1, 2 ]
+
+  "#size-cells":
+    enum: [ 1, 2 ]
+
+  ranges: true
+
+  clocks:
+    minItems: 1
+    maxItems: 3
+
+  clock-names:
+    minItems: 1
+    maxItems: 3
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    items:
+      - const: ufsphy
+
+  vdda-phy-supply: true
+
+  vdda-pll-supply: true
+
+  vddp-ref-clk-supply: true
+
+patternProperties:
+  "^phy@[0-9a-f]+$":
+    type: object
+    description: single PHY-provider child node
+    properties:
+      reg:
+        minItems: 3
+        maxItems: 6
+
+      "#phy-cells":
+        const: 0
+
+    required:
+      - reg
+      - "#phy-cells"
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - vdda-phy-supply
+  - vdda-pll-supply
+
+additionalProperties: false
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,msm8996-qmp-ufs-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 1
+        clock-names:
+          items:
+            - const: ref
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,msm8998-qmp-ufs-phy
+              - qcom,sc8180x-qmp-ufs-phy
+              - qcom,sdm845-qmp-ufs-phy
+              - qcom,sm6115-qmp-ufs-phy
+              - qcom,sm6350-qmp-ufs-phy
+              - qcom,sm8150-qmp-ufs-phy
+              - qcom,sm8250-qmp-ufs-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 2
+        clock-names:
+          items:
+            - const: ref
+            - const: ref_aux
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,sm8450-qmp-ufs-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 3
+        clock-names:
+          items:
+            - const: ref
+            - const: ref_aux
+            - const: qref
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,msm8998-qmp-ufs-phy
+              - qcom,sdm845-qmp-ufs-phy
+              - qcom,sm6350-qmp-ufs-phy
+              - qcom,sm8150-qmp-ufs-phy
+              - qcom,sm8250-qmp-ufs-phy
+              - qcom,sm8350-qmp-ufs-phy
+              - qcom,sm8450-qmp-ufs-phy
+    then:
+      patternProperties:
+        "^phy@[0-9a-f]+$":
+          properties:
+            reg:
+              items:
+                - description: TX lane 1
+                - description: RX lane 1
+                - description: PCS
+                - description: TX lane 2
+                - description: RX lane 2
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,sc8180x-qmp-ufs-phy
+    then:
+      patternProperties:
+        "^phy@[0-9a-f]+$":
+          properties:
+            reg:
+              items:
+                - description: TX
+                - description: RX
+                - description: PCS
+                - description: PCS_MISC
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,msm8996-qmp-ufs-phy
+              - qcom,sm6115-qmp-ufs-phy
+    then:
+      patternProperties:
+        "^phy@[0-9a-f]+$":
+          properties:
+            reg:
+              items:
+                - description: TX
+                - description: RX
+                - description: PCS
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sm8250.h>
+    #include <dt-bindings/clock/qcom,rpmh.h>
+
+    phy-wrapper@1d87000 {
+        compatible = "qcom,sm8250-qmp-ufs-phy";
+        reg = <0x01d87000 0x1c0>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x0 0x01d87000 0x1000>;
+
+        clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+        clock-names = "ref", "ref_aux";
+
+        resets = <&ufs_mem_hc 0>;
+        reset-names = "ufsphy";
+
+        vdda-phy-supply = <&vreg_l6b>;
+        vdda-pll-supply = <&vreg_l3b>;
+
+        phy@400 {
+            reg = <0x400 0x108>,
+                  <0x600 0x1e0>,
+                  <0xc00 0x1dc>,
+                  <0x800 0x108>,
+                  <0xa00 0x1e0>;
+            #phy-cells = <0>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-usb3-phy.yaml
new file mode 100644 (file)
index 0000000..0c6b3ba
--- /dev/null
@@ -0,0 +1,391 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,msm8996-qmp-usb3-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QMP PHY controller (USB, MSM8996)
+
+maintainers:
+  - Vinod Koul <vkoul@kernel.org>
+
+description:
+  QMP PHY controller supports physical layer functionality for a number of
+  controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.
+
+  Note that these bindings are for SoCs up to SC8180X. For newer SoCs, see
+  qcom,sc8280xp-qmp-usb3-uni-phy.yaml.
+
+properties:
+  compatible:
+    enum:
+      - qcom,ipq6018-qmp-usb3-phy
+      - qcom,ipq8074-qmp-usb3-phy
+      - qcom,msm8996-qmp-usb3-phy
+      - qcom,msm8998-qmp-usb3-phy
+      - qcom,qcm2290-qmp-usb3-phy
+      - qcom,sc7180-qmp-usb3-phy
+      - qcom,sc8180x-qmp-usb3-phy
+      - qcom,sdm845-qmp-usb3-phy
+      - qcom,sdm845-qmp-usb3-uni-phy
+      - qcom,sdx55-qmp-usb3-uni-phy
+      - qcom,sdx65-qmp-usb3-uni-phy
+      - qcom,sm8150-qmp-usb3-phy
+      - qcom,sm8150-qmp-usb3-uni-phy
+      - qcom,sm8250-qmp-usb3-phy
+      - qcom,sm8250-qmp-usb3-uni-phy
+      - qcom,sm8350-qmp-usb3-phy
+      - qcom,sm8350-qmp-usb3-uni-phy
+      - qcom,sm8450-qmp-usb3-phy
+
+  reg:
+    minItems: 1
+    items:
+      - description: serdes
+      - description: DP_COM
+
+  "#address-cells":
+    enum: [ 1, 2 ]
+
+  "#size-cells":
+    enum: [ 1, 2 ]
+
+  ranges: true
+
+  clocks:
+    minItems: 3
+    maxItems: 4
+
+  clock-names:
+    minItems: 3
+    maxItems: 4
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 2
+
+  reset-names:
+    maxItems: 2
+
+  vdda-phy-supply: true
+
+  vdda-pll-supply: true
+
+  vddp-ref-clk-supply: true
+
+patternProperties:
+  "^phy@[0-9a-f]+$":
+    type: object
+    description: single PHY-provider child node
+    properties:
+      reg:
+        minItems: 3
+        maxItems: 6
+
+      clocks:
+        items:
+          - description: PIPE clock
+
+      clock-names:
+        deprecated: true
+        items:
+          - const: pipe0
+
+      "#clock-cells":
+        const: 0
+
+      clock-output-names:
+        maxItems: 1
+
+      "#phy-cells":
+        const: 0
+
+    required:
+      - reg
+      - clocks
+      - "#clock-cells"
+      - clock-output-names
+      - "#phy-cells"
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - vdda-phy-supply
+  - vdda-pll-supply
+
+additionalProperties: false
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,sc7180-qmp-usb3-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 4
+        clock-names:
+          items:
+            - const: aux
+            - const: cfg_ahb
+            - const: ref
+            - const: com_aux
+        resets:
+          maxItems: 1
+        reset-names:
+          items:
+            - const: phy
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,sdm845-qmp-usb3-uni-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 4
+        clock-names:
+          items:
+            - const: aux
+            - const: cfg_ahb
+            - const: ref
+            - const: com_aux
+        resets:
+          maxItems: 2
+        reset-names:
+          items:
+            - const: phy
+            - const: common
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,ipq8074-qmp-usb3-phy
+              - qcom,msm8996-qmp-usb3-phy
+              - qcom,msm8998-qmp-usb3-phy
+              - qcom,sdx55-qmp-usb3-uni-phy
+              - qcom,sdx65-qmp-usb3-uni-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 3
+        clock-names:
+          items:
+            - const: aux
+            - const: cfg_ahb
+            - const: ref
+        resets:
+          maxItems: 2
+        reset-names:
+          items:
+            - const: phy
+            - const: common
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,sm8150-qmp-usb3-phy
+              - qcom,sm8150-qmp-usb3-uni-phy
+              - qcom,sm8250-qmp-usb3-uni-phy
+              - qcom,sm8350-qmp-usb3-uni-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 4
+        clock-names:
+          items:
+            - const: aux
+            - const: ref_clk_src
+            - const: ref
+            - const: com_aux
+        resets:
+          maxItems: 2
+        reset-names:
+          items:
+            - const: phy
+            - const: common
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,sm8250-qmp-usb3-phy
+              - qcom,sm8350-qmp-usb3-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 3
+        clock-names:
+          items:
+            - const: aux
+            - const: ref_clk_src
+            - const: com_aux
+        resets:
+          maxItems: 2
+        reset-names:
+          items:
+            - const: phy
+            - const: common
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,qcm2290-qmp-usb3-phy
+    then:
+      properties:
+        clocks:
+          maxItems: 3
+        clock-names:
+          items:
+            - const: cfg_ahb
+            - const: ref
+            - const: com_aux
+        resets:
+          maxItems: 2
+        reset-names:
+          items:
+            - const: phy_phy
+            - const: phy
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,sdm845-qmp-usb3-phy
+              - qcom,sm8150-qmp-usb3-phy
+              - qcom,sm8350-qmp-usb3-phy
+              - qcom,sm8450-qmp-usb3-phy
+    then:
+      patternProperties:
+        "^phy@[0-9a-f]+$":
+          properties:
+            reg:
+              items:
+                - description: TX lane 1
+                - description: RX lane 1
+                - description: PCS
+                - description: TX lane 2
+                - description: RX lane 2
+                - description: PCS_MISC
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,msm8998-qmp-usb3-phy
+    then:
+      patternProperties:
+        "^phy@[0-9a-f]+$":
+          properties:
+            reg:
+              items:
+                - description: TX lane 1
+                - description: RX lane 1
+                - description: PCS
+                - description: TX lane 2
+                - description: RX lane 2
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,ipq6018-qmp-usb3-phy
+              - qcom,ipq8074-qmp-usb3-phy
+              - qcom,qcm2290-qmp-usb3-phy
+              - qcom,sc7180-qmp-usb3-phy
+              - qcom,sc8180x-qmp-usb3-phy
+              - qcom,sdx55-qmp-usb3-uni-phy
+              - qcom,sdx65-qmp-usb3-uni-phy
+              - qcom,sm8150-qmp-usb3-uni-phy
+              - qcom,sm8250-qmp-usb3-phy
+    then:
+      patternProperties:
+        "^phy@[0-9a-f]+$":
+          properties:
+            reg:
+              items:
+                - description: TX
+                - description: RX
+                - description: PCS
+                - description: PCS_MISC
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,msm8996-qmp-usb3-phy
+              - qcom,sm8250-qmp-usb3-uni-phy
+              - qcom,sm8350-qmp-usb3-uni-phy
+    then:
+      patternProperties:
+        "^phy@[0-9a-f]+$":
+          properties:
+            reg:
+              items:
+                - description: TX
+                - description: RX
+                - description: PCS
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sdm845.h>
+    usb_2_qmpphy: phy-wrapper@88eb000 {
+        compatible = "qcom,sdm845-qmp-usb3-uni-phy";
+        reg = <0x088eb000 0x18c>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x0 0x088eb000 0x2000>;
+
+        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@200 {
+                reg = <0x200 0x128>,
+                      <0x400 0x1fc>,
+                      <0x800 0x218>,
+                      <0x600 0x70>;
+
+                clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
+
+                #clock-cells = <0>;
+                clock-output-names = "usb3_uni_phy_pipe_clk_src";
+
+                #phy-cells = <0>;
+            };
+        };
diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-pcie-phy.yaml
deleted file mode 100644 (file)
index 324ad7d..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/phy/qcom,qmp-pcie-phy.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Qualcomm QMP PHY controller (PCIe)
-
-maintainers:
-  - Vinod Koul <vkoul@kernel.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,ipq6018-qmp-pcie-phy
-      - qcom,ipq8074-qmp-gen3-pcie-phy
-      - qcom,ipq8074-qmp-pcie-phy
-      - qcom,msm8998-qmp-pcie-phy
-      - qcom,sc8180x-qmp-pcie-phy
-      - qcom,sdm845-qhp-pcie-phy
-      - qcom,sdm845-qmp-pcie-phy
-      - qcom,sdx55-qmp-pcie-phy
-      - qcom,sm8250-qmp-gen3x1-pcie-phy
-      - qcom,sm8250-qmp-gen3x2-pcie-phy
-      - qcom,sm8250-qmp-modem-pcie-phy
-      - qcom,sm8450-qmp-gen3x1-pcie-phy
-      - qcom,sm8450-qmp-gen4x2-pcie-phy
-
-  reg:
-    items:
-      - description: serdes
-
-  "#address-cells":
-    enum: [ 1, 2 ]
-
-  "#size-cells":
-    enum: [ 1, 2 ]
-
-  ranges: true
-
-  clocks:
-    minItems: 2
-    maxItems: 4
-
-  clock-names:
-    minItems: 2
-    maxItems: 4
-
-  resets:
-    minItems: 1
-    maxItems: 2
-
-  reset-names:
-    minItems: 1
-    maxItems: 2
-
-  vdda-phy-supply: true
-
-  vdda-pll-supply: true
-
-  vddp-ref-clk-supply: true
-
-patternProperties:
-  "^phy@[0-9a-f]+$":
-    type: object
-    description: single PHY-provider child node
-    properties:
-      reg:
-        minItems: 3
-        maxItems: 6
-
-      clocks:
-        items:
-          - description: PIPE clock
-
-      clock-names:
-        deprecated: true
-        items:
-          - const: pipe0
-
-      "#clock-cells":
-        const: 0
-
-      clock-output-names:
-        maxItems: 1
-
-      "#phy-cells":
-        const: 0
-
-    required:
-      - reg
-      - clocks
-      - "#clock-cells"
-      - clock-output-names
-      - "#phy-cells"
-
-    additionalProperties: false
-
-required:
-  - compatible
-  - reg
-  - "#address-cells"
-  - "#size-cells"
-  - ranges
-  - clocks
-  - clock-names
-  - resets
-  - reset-names
-
-additionalProperties: false
-
-allOf:
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,msm8998-qmp-pcie-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 3
-        clock-names:
-          items:
-            - const: aux
-            - const: cfg_ahb
-            - const: ref
-        resets:
-          maxItems: 2
-        reset-names:
-          items:
-            - const: phy
-            - const: common
-      required:
-        - vdda-phy-supply
-        - vdda-pll-supply
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,ipq6018-qmp-pcie-phy
-              - qcom,ipq8074-qmp-gen3-pcie-phy
-              - qcom,ipq8074-qmp-pcie-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 2
-        clock-names:
-          items:
-            - const: aux
-            - const: cfg_ahb
-        resets:
-          maxItems: 2
-        reset-names:
-          items:
-            - const: phy
-            - const: common
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sc8180x-qmp-pcie-phy
-              - qcom,sdm845-qhp-pcie-phy
-              - qcom,sdm845-qmp-pcie-phy
-              - qcom,sdx55-qmp-pcie-phy
-              - qcom,sm8250-qmp-gen3x1-pcie-phy
-              - qcom,sm8250-qmp-gen3x2-pcie-phy
-              - qcom,sm8250-qmp-modem-pcie-phy
-              - qcom,sm8450-qmp-gen3x1-pcie-phy
-              - qcom,sm8450-qmp-gen4x2-pcie-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 4
-        clock-names:
-          items:
-            - const: aux
-            - const: cfg_ahb
-            - const: ref
-            - const: refgen
-        resets:
-          maxItems: 1
-        reset-names:
-          items:
-            - const: phy
-      required:
-        - vdda-phy-supply
-        - vdda-pll-supply
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sm8250-qmp-gen3x2-pcie-phy
-              - qcom,sm8250-qmp-modem-pcie-phy
-              - qcom,sm8450-qmp-gen4x2-pcie-phy
-    then:
-      patternProperties:
-        "^phy@[0-9a-f]+$":
-          properties:
-            reg:
-              items:
-                - description: TX lane 1
-                - description: RX lane 1
-                - description: PCS
-                - description: TX lane 2
-                - description: RX lane 2
-                - description: PCS_MISC
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sc8180x-qmp-pcie-phy
-              - qcom,sdm845-qmp-pcie-phy
-              - qcom,sdx55-qmp-pcie-phy
-              - qcom,sm8250-qmp-gen3x1-pcie-phy
-              - qcom,sm8450-qmp-gen3x1-pcie-phy
-    then:
-      patternProperties:
-        "^phy@[0-9a-f]+$":
-          properties:
-            reg:
-              items:
-                - description: TX
-                - description: RX
-                - description: PCS
-                - description: PCS_MISC
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,ipq6018-qmp-pcie-phy
-              - qcom,ipq8074-qmp-pcie-phy
-              - qcom,msm8998-qmp-pcie-phy
-              - qcom,sdm845-qhp-pcie-phy
-    then:
-      patternProperties:
-        "^phy@[0-9a-f]+$":
-          properties:
-            reg:
-              items:
-                - description: TX
-                - description: RX
-                - description: PCS
-
-examples:
-  - |
-    #include <dt-bindings/clock/qcom,gcc-sm8250.h>
-    phy-wrapper@1c0e000 {
-        compatible = "qcom,sm8250-qmp-gen3x2-pcie-phy";
-        reg = <0x01c0e000 0x1c0>;
-        #address-cells = <1>;
-        #size-cells = <1>;
-        ranges = <0x0 0x01c0e000 0x1000>;
-
-        clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>,
-                 <&gcc GCC_PCIE_1_CFG_AHB_CLK>,
-                 <&gcc GCC_PCIE_WIGIG_CLKREF_EN>,
-                 <&gcc GCC_PCIE1_PHY_REFGEN_CLK>;
-        clock-names = "aux", "cfg_ahb", "ref", "refgen";
-
-        resets = <&gcc GCC_PCIE_1_PHY_BCR>;
-        reset-names = "phy";
-
-        vdda-phy-supply = <&vreg_l10c_0p88>;
-        vdda-pll-supply = <&vreg_l6b_1p2>;
-
-        phy@200 {
-            reg = <0x200 0x170>,
-                  <0x400 0x200>,
-                  <0xa00 0x1f0>,
-                  <0x600 0x170>,
-                  <0x800 0x200>,
-                  <0xe00 0xf4>;
-
-            clocks = <&gcc GCC_PCIE_1_PIPE_CLK>;
-
-            #clock-cells = <0>;
-            clock-output-names = "pcie_1_pipe_clk";
-
-            #phy-cells = <0>;
-        };
-    };
diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-ufs-phy.yaml
deleted file mode 100644 (file)
index 815c375..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/phy/qcom,qmp-ufs-phy.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Qualcomm QMP PHY controller (UFS)
-
-maintainers:
-  - Vinod Koul <vkoul@kernel.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,msm8996-qmp-ufs-phy
-      - qcom,msm8998-qmp-ufs-phy
-      - qcom,sc8180x-qmp-ufs-phy
-      - qcom,sc8280xp-qmp-ufs-phy
-      - qcom,sdm845-qmp-ufs-phy
-      - qcom,sm6115-qmp-ufs-phy
-      - qcom,sm6350-qmp-ufs-phy
-      - qcom,sm8150-qmp-ufs-phy
-      - qcom,sm8250-qmp-ufs-phy
-      - qcom,sm8350-qmp-ufs-phy
-      - qcom,sm8450-qmp-ufs-phy
-
-  reg:
-    items:
-      - description: serdes
-
-  "#address-cells":
-    enum: [ 1, 2 ]
-
-  "#size-cells":
-    enum: [ 1, 2 ]
-
-  ranges: true
-
-  clocks:
-    minItems: 1
-    maxItems: 3
-
-  clock-names:
-    minItems: 1
-    maxItems: 3
-
-  power-domains:
-    maxItems: 1
-
-  resets:
-    maxItems: 1
-
-  reset-names:
-    items:
-      - const: ufsphy
-
-  vdda-phy-supply: true
-
-  vdda-pll-supply: true
-
-  vddp-ref-clk-supply: true
-
-patternProperties:
-  "^phy@[0-9a-f]+$":
-    type: object
-    description: single PHY-provider child node
-    properties:
-      reg:
-        minItems: 3
-        maxItems: 6
-
-      "#phy-cells":
-        const: 0
-
-    required:
-      - reg
-      - "#phy-cells"
-
-    additionalProperties: false
-
-required:
-  - compatible
-  - reg
-  - "#address-cells"
-  - "#size-cells"
-  - ranges
-  - clocks
-  - clock-names
-  - resets
-  - reset-names
-  - vdda-phy-supply
-  - vdda-pll-supply
-
-additionalProperties: false
-
-allOf:
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,msm8996-qmp-ufs-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 1
-        clock-names:
-          items:
-            - const: ref
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,msm8998-qmp-ufs-phy
-              - qcom,sc8180x-qmp-ufs-phy
-              - qcom,sc8280xp-qmp-ufs-phy
-              - qcom,sdm845-qmp-ufs-phy
-              - qcom,sm6115-qmp-ufs-phy
-              - qcom,sm6350-qmp-ufs-phy
-              - qcom,sm8150-qmp-ufs-phy
-              - qcom,sm8250-qmp-ufs-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 2
-        clock-names:
-          items:
-            - const: ref
-            - const: ref_aux
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sm8450-qmp-ufs-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 3
-        clock-names:
-          items:
-            - const: ref
-            - const: ref_aux
-            - const: qref
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,msm8998-qmp-ufs-phy
-              - qcom,sc8280xp-qmp-ufs-phy
-              - qcom,sdm845-qmp-ufs-phy
-              - qcom,sm6350-qmp-ufs-phy
-              - qcom,sm8150-qmp-ufs-phy
-              - qcom,sm8250-qmp-ufs-phy
-              - qcom,sm8350-qmp-ufs-phy
-              - qcom,sm8450-qmp-ufs-phy
-    then:
-      patternProperties:
-        "^phy@[0-9a-f]+$":
-          properties:
-            reg:
-              items:
-                - description: TX lane 1
-                - description: RX lane 1
-                - description: PCS
-                - description: TX lane 2
-                - description: RX lane 2
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sc8180x-qmp-ufs-phy
-    then:
-      patternProperties:
-        "^phy@[0-9a-f]+$":
-          properties:
-            reg:
-              items:
-                - description: TX
-                - description: RX
-                - description: PCS
-                - description: PCS_MISC
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,msm8996-qmp-ufs-phy
-              - qcom,sm6115-qmp-ufs-phy
-    then:
-      patternProperties:
-        "^phy@[0-9a-f]+$":
-          properties:
-            reg:
-              items:
-                - description: TX
-                - description: RX
-                - description: PCS
-
-examples:
-  - |
-    #include <dt-bindings/clock/qcom,gcc-sc8280xp.h>
-    #include <dt-bindings/clock/qcom,rpmh.h>
-    phy-wrapper@1d87000 {
-        compatible = "qcom,sc8280xp-qmp-ufs-phy";
-        reg = <0x01d87000 0xe10>;
-        #address-cells = <1>;
-        #size-cells = <1>;
-        ranges = <0x0 0x01d87000 0x1000>;
-
-        clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
-        clock-names = "ref", "ref_aux";
-
-        resets = <&ufs_mem_hc 0>;
-        reset-names = "ufsphy";
-
-        vdda-phy-supply = <&vreg_l6b>;
-        vdda-pll-supply = <&vreg_l3b>;
-
-        phy@400 {
-            reg = <0x400 0x108>,
-                  <0x600 0x1e0>,
-                  <0xc00 0x1dc>,
-                  <0x800 0x108>,
-                  <0xa00 0x1e0>;
-            #phy-cells = <0>;
-        };
-    };
diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-usb-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-usb-phy.yaml
deleted file mode 100644 (file)
index 7acb4b7..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/phy/qcom,qmp-usb-phy.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Qualcomm QMP PHY controller (USB)
-
-maintainers:
-  - Vinod Koul <vkoul@kernel.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,ipq6018-qmp-usb3-phy
-      - qcom,ipq8074-qmp-usb3-phy
-      - qcom,msm8996-qmp-usb3-phy
-      - qcom,msm8998-qmp-usb3-phy
-      - qcom,qcm2290-qmp-usb3-phy
-      - qcom,sc7180-qmp-usb3-phy
-      - qcom,sc8180x-qmp-usb3-phy
-      - qcom,sc8280xp-qmp-usb3-uni-phy
-      - qcom,sdm845-qmp-usb3-phy
-      - qcom,sdm845-qmp-usb3-uni-phy
-      - qcom,sdx55-qmp-usb3-uni-phy
-      - qcom,sdx65-qmp-usb3-uni-phy
-      - qcom,sm8150-qmp-usb3-phy
-      - qcom,sm8150-qmp-usb3-uni-phy
-      - qcom,sm8250-qmp-usb3-phy
-      - qcom,sm8250-qmp-usb3-uni-phy
-      - qcom,sm8350-qmp-usb3-phy
-      - qcom,sm8350-qmp-usb3-uni-phy
-      - qcom,sm8450-qmp-usb3-phy
-
-  reg:
-    minItems: 1
-    items:
-      - description: serdes
-      - description: DP_COM
-
-  "#address-cells":
-    enum: [ 1, 2 ]
-
-  "#size-cells":
-    enum: [ 1, 2 ]
-
-  ranges: true
-
-  clocks:
-    minItems: 3
-    maxItems: 4
-
-  clock-names:
-    minItems: 3
-    maxItems: 4
-
-  power-domains:
-    maxItems: 1
-
-  resets:
-    maxItems: 2
-
-  reset-names:
-    maxItems: 2
-
-  vdda-phy-supply: true
-
-  vdda-pll-supply: true
-
-  vddp-ref-clk-supply: true
-
-patternProperties:
-  "^phy@[0-9a-f]+$":
-    type: object
-    description: single PHY-provider child node
-    properties:
-      reg:
-        minItems: 3
-        maxItems: 6
-
-      clocks:
-        items:
-          - description: PIPE clock
-
-      clock-names:
-        deprecated: true
-        items:
-          - const: pipe0
-
-      "#clock-cells":
-        const: 0
-
-      clock-output-names:
-        maxItems: 1
-
-      "#phy-cells":
-        const: 0
-
-    required:
-      - reg
-      - clocks
-      - "#clock-cells"
-      - clock-output-names
-      - "#phy-cells"
-
-    additionalProperties: false
-
-required:
-  - compatible
-  - reg
-  - "#address-cells"
-  - "#size-cells"
-  - ranges
-  - clocks
-  - clock-names
-  - resets
-  - reset-names
-  - vdda-phy-supply
-  - vdda-pll-supply
-
-additionalProperties: false
-
-allOf:
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sc7180-qmp-usb3-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 4
-        clock-names:
-          items:
-            - const: aux
-            - const: cfg_ahb
-            - const: ref
-            - const: com_aux
-        resets:
-          maxItems: 1
-        reset-names:
-          items:
-            - const: phy
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sdm845-qmp-usb3-uni-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 4
-        clock-names:
-          items:
-            - const: aux
-            - const: cfg_ahb
-            - const: ref
-            - const: com_aux
-        resets:
-          maxItems: 2
-        reset-names:
-          items:
-            - const: phy
-            - const: common
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,ipq8074-qmp-usb3-phy
-              - qcom,msm8996-qmp-usb3-phy
-              - qcom,msm8998-qmp-usb3-phy
-              - qcom,sdx55-qmp-usb3-uni-phy
-              - qcom,sdx65-qmp-usb3-uni-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 3
-        clock-names:
-          items:
-            - const: aux
-            - const: cfg_ahb
-            - const: ref
-        resets:
-          maxItems: 2
-        reset-names:
-          items:
-            - const: phy
-            - const: common
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sc8280xp-qmp-usb3-uni-phy
-              - qcom,sm8150-qmp-usb3-phy
-              - qcom,sm8150-qmp-usb3-uni-phy
-              - qcom,sm8250-qmp-usb3-uni-phy
-              - qcom,sm8350-qmp-usb3-uni-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 4
-        clock-names:
-          items:
-            - const: aux
-            - const: ref_clk_src
-            - const: ref
-            - const: com_aux
-        resets:
-          maxItems: 2
-        reset-names:
-          items:
-            - const: phy
-            - const: common
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sm8250-qmp-usb3-phy
-              - qcom,sm8350-qmp-usb3-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 3
-        clock-names:
-          items:
-            - const: aux
-            - const: ref_clk_src
-            - const: com_aux
-        resets:
-          maxItems: 2
-        reset-names:
-          items:
-            - const: phy
-            - const: common
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,qcm2290-qmp-usb3-phy
-    then:
-      properties:
-        clocks:
-          maxItems: 3
-        clock-names:
-          items:
-            - const: cfg_ahb
-            - const: ref
-            - const: com_aux
-        resets:
-          maxItems: 2
-        reset-names:
-          items:
-            - const: phy_phy
-            - const: phy
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sc8280xp-qmp-usb3-uni-phy
-    then:
-      required:
-        - power-domains
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sdm845-qmp-usb3-phy
-              - qcom,sm8150-qmp-usb3-phy
-              - qcom,sm8350-qmp-usb3-phy
-              - qcom,sm8450-qmp-usb3-phy
-    then:
-      patternProperties:
-        "^phy@[0-9a-f]+$":
-          properties:
-            reg:
-              items:
-                - description: TX lane 1
-                - description: RX lane 1
-                - description: PCS
-                - description: TX lane 2
-                - description: RX lane 2
-                - description: PCS_MISC
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,msm8998-qmp-usb3-phy
-    then:
-      patternProperties:
-        "^phy@[0-9a-f]+$":
-          properties:
-            reg:
-              items:
-                - description: TX lane 1
-                - description: RX lane 1
-                - description: PCS
-                - description: TX lane 2
-                - description: RX lane 2
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,ipq6018-qmp-usb3-phy
-              - qcom,ipq8074-qmp-usb3-phy
-              - qcom,qcm2290-qmp-usb3-phy
-              - qcom,sc7180-qmp-usb3-phy
-              - qcom,sc8180x-qmp-usb3-phy
-              - qcom,sdx55-qmp-usb3-uni-phy
-              - qcom,sdx65-qmp-usb3-uni-phy
-              - qcom,sm8150-qmp-usb3-uni-phy
-              - qcom,sm8250-qmp-usb3-phy
-    then:
-      patternProperties:
-        "^phy@[0-9a-f]+$":
-          properties:
-            reg:
-              items:
-                - description: TX
-                - description: RX
-                - description: PCS
-                - description: PCS_MISC
-
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,msm8996-qmp-usb3-phy
-              - qcom,sc8280xp-qmp-usb3-uni-phy
-              - qcom,sm8250-qmp-usb3-uni-phy
-              - qcom,sm8350-qmp-usb3-uni-phy
-    then:
-      patternProperties:
-        "^phy@[0-9a-f]+$":
-          properties:
-            reg:
-              items:
-                - description: TX
-                - description: RX
-                - description: PCS
-
-examples:
-  - |
-    #include <dt-bindings/clock/qcom,gcc-sdm845.h>
-    usb_2_qmpphy: phy-wrapper@88eb000 {
-        compatible = "qcom,sdm845-qmp-usb3-uni-phy";
-        reg = <0x088eb000 0x18c>;
-        #address-cells = <1>;
-        #size-cells = <1>;
-        ranges = <0x0 0x088eb000 0x2000>;
-
-        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@200 {
-                reg = <0x200 0x128>,
-                      <0x400 0x1fc>,
-                      <0x800 0x218>,
-                      <0x600 0x70>;
-
-                clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
-
-                #clock-cells = <0>;
-                clock-output-names = "usb3_uni_phy_pipe_clk_src";
-
-                #phy-cells = <0>;
-            };
-        };
diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml
deleted file mode 100644 (file)
index 97a7eca..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-# 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:
-  - Wesley Cheng <quic_wcheng@quicinc.com>
-
-properties:
-  compatible:
-    enum:
-      - qcom,sc7180-qmp-usb3-dp-phy
-      - qcom,sc7280-qmp-usb3-dp-phy
-      - qcom,sc8180x-qmp-usb3-dp-phy
-      - qcom,sc8280xp-qmp-usb43dp-phy
-      - qcom,sdm845-qmp-usb3-dp-phy
-      - qcom,sm8250-qmp-usb3-dp-phy
-  reg:
-    items:
-      - description: Address and length of PHY's USB serdes block.
-      - description: Address and length of the DP_COM control block.
-      - description: Address and length of PHY's DP serdes block.
-
-  reg-names:
-    items:
-      - const: usb
-      - const: dp_com
-      - const: dp
-
-  "#address-cells":
-    enum: [ 1, 2 ]
-
-  "#size-cells":
-    enum: [ 1, 2 ]
-
-  ranges: true
-
-  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
-
-  power-domains:
-    maxItems: 1
-
-  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:
-  "^usb3-phy@[0-9a-f]+$":
-    type: object
-    additionalProperties: false
-    description:
-      The USB3 PHY.
-
-    properties:
-      reg:
-        items:
-          - description: Address and length of TX.
-          - description: Address and length of RX.
-          - description: Address and length of PCS.
-          - description: Address and length of TX2.
-          - description: Address and length of RX2.
-          - description: Address and length of pcs_misc.
-
-      clocks:
-        items:
-          - description: pipe clock
-
-      clock-names:
-        deprecated: true
-        items:
-          - const: pipe0
-
-      clock-output-names:
-        items:
-          - const: usb3_phy_pipe_clk_src
-
-      '#clock-cells':
-        const: 0
-
-      '#phy-cells':
-        const: 0
-
-    required:
-      - reg
-      - clocks
-      - '#clock-cells'
-      - '#phy-cells'
-
-  "^dp-phy@[0-9a-f]+$":
-    type: object
-    additionalProperties: false
-    description:
-      The DP PHY.
-
-    properties:
-      reg:
-        items:
-          - description: Address and length of TX.
-          - description: Address and length of RX.
-          - description: Address and length of PCS.
-          - description: Address and length of TX2.
-          - description: Address and length of RX2.
-
-      '#clock-cells':
-        const: 1
-
-      '#phy-cells':
-        const: 0
-
-    required:
-      - reg
-      - '#clock-cells'
-      - '#phy-cells'
-
-required:
-  - compatible
-  - reg
-  - "#address-cells"
-  - "#size-cells"
-  - ranges
-  - clocks
-  - clock-names
-  - resets
-  - reset-names
-  - vdda-phy-supply
-  - vdda-pll-supply
-
-additionalProperties: false
-
-allOf:
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - qcom,sc8280xp-qmp-usb43dp-phy
-    then:
-      required:
-        - power-domains
-
-examples:
-  - |
-    #include <dt-bindings/clock/qcom,gcc-sdm845.h>
-    usb_1_qmpphy: phy-wrapper@88e9000 {
-        compatible = "qcom,sdm845-qmp-usb3-dp-phy";
-        reg = <0x088e9000 0x18c>,
-              <0x088e8000 0x10>,
-              <0x088ea000 0x40>;
-        reg-names = "usb", "dp_com", "dp";
-        #address-cells = <1>;
-        #size-cells = <1>;
-        ranges = <0x0 0x088e9000 0x2000>;
-
-        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>;
-
-        usb3-phy@200 {
-            reg = <0x200 0x128>,
-                  <0x400 0x200>,
-                  <0xc00 0x218>,
-                  <0x600 0x128>,
-                  <0x800 0x200>,
-                  <0xa00 0x100>;
-            #clock-cells = <0>;
-            #phy-cells = <0>;
-            clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
-            clock-output-names = "usb3_phy_pipe_clk_src";
-        };
-
-        dp-phy@88ea200 {
-            reg = <0xa200 0x200>,
-                  <0xa400 0x200>,
-                  <0xaa00 0x200>,
-                  <0xa600 0x200>,
-                  <0xa800 0x200>;
-            #clock-cells = <1>;
-            #phy-cells = <0>;
-        };
-    };
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml
new file mode 100644 (file)
index 0000000..d9d0ab9
--- /dev/null
@@ -0,0 +1,219 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QMP USB3 DP PHY controller (SC7180)
+
+description:
+  The QMP PHY controller supports physical layer functionality for a number of
+  controllers on Qualcomm chipsets, such as, PCIe, UFS and USB.
+
+  Note that these bindings are for SoCs up to SC8180X. For newer SoCs, see
+  qcom,sc8280xp-qmp-usb43dp-phy.yaml.
+
+maintainers:
+  - Wesley Cheng <quic_wcheng@quicinc.com>
+
+properties:
+  compatible:
+    enum:
+      - qcom,sc7180-qmp-usb3-dp-phy
+      - qcom,sc7280-qmp-usb3-dp-phy
+      - qcom,sc8180x-qmp-usb3-dp-phy
+      - qcom,sdm845-qmp-usb3-dp-phy
+      - qcom,sm8250-qmp-usb3-dp-phy
+  reg:
+    items:
+      - description: Address and length of PHY's USB serdes block.
+      - description: Address and length of the DP_COM control block.
+      - description: Address and length of PHY's DP serdes block.
+
+  reg-names:
+    items:
+      - const: usb
+      - const: dp_com
+      - const: dp
+
+  "#address-cells":
+    enum: [ 1, 2 ]
+
+  "#size-cells":
+    enum: [ 1, 2 ]
+
+  ranges: true
+
+  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
+
+  power-domains:
+    maxItems: 1
+
+  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:
+  "^usb3-phy@[0-9a-f]+$":
+    type: object
+    additionalProperties: false
+    description:
+      The USB3 PHY.
+
+    properties:
+      reg:
+        items:
+          - description: Address and length of TX.
+          - description: Address and length of RX.
+          - description: Address and length of PCS.
+          - description: Address and length of TX2.
+          - description: Address and length of RX2.
+          - description: Address and length of pcs_misc.
+
+      clocks:
+        items:
+          - description: pipe clock
+
+      clock-names:
+        deprecated: true
+        items:
+          - const: pipe0
+
+      clock-output-names:
+        items:
+          - const: usb3_phy_pipe_clk_src
+
+      '#clock-cells':
+        const: 0
+
+      '#phy-cells':
+        const: 0
+
+    required:
+      - reg
+      - clocks
+      - '#clock-cells'
+      - '#phy-cells'
+
+  "^dp-phy@[0-9a-f]+$":
+    type: object
+    additionalProperties: false
+    description:
+      The DP PHY.
+
+    properties:
+      reg:
+        items:
+          - description: Address and length of TX.
+          - description: Address and length of RX.
+          - description: Address and length of PCS.
+          - description: Address and length of TX2.
+          - description: Address and length of RX2.
+
+      '#clock-cells':
+        const: 1
+
+      '#phy-cells':
+        const: 0
+
+    required:
+      - reg
+      - '#clock-cells'
+      - '#phy-cells'
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+  - 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-dp-phy";
+        reg = <0x088e9000 0x18c>,
+              <0x088e8000 0x10>,
+              <0x088ea000 0x40>;
+        reg-names = "usb", "dp_com", "dp";
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x0 0x088e9000 0x2000>;
+
+        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>;
+
+        usb3-phy@200 {
+            reg = <0x200 0x128>,
+                  <0x400 0x200>,
+                  <0xc00 0x218>,
+                  <0x600 0x128>,
+                  <0x800 0x200>,
+                  <0xa00 0x100>;
+            #clock-cells = <0>;
+            #phy-cells = <0>;
+            clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+            clock-output-names = "usb3_phy_pipe_clk_src";
+        };
+
+        dp-phy@88ea200 {
+            reg = <0xa200 0x200>,
+                  <0xa400 0x200>,
+                  <0xaa00 0x200>,
+                  <0xa600 0x200>,
+                  <0xa800 0x200>;
+            #clock-cells = <1>;
+            #phy-cells = <0>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
new file mode 100644 (file)
index 0000000..80aa8d2
--- /dev/null
@@ -0,0 +1,165 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,sc8280xp-qmp-pcie-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QMP PHY controller (PCIe, SC8280XP)
+
+maintainers:
+  - Vinod Koul <vkoul@kernel.org>
+
+description:
+  The 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,sc8280xp-qmp-gen3x1-pcie-phy
+      - qcom,sc8280xp-qmp-gen3x2-pcie-phy
+      - qcom,sc8280xp-qmp-gen3x4-pcie-phy
+
+  reg:
+    minItems: 1
+    maxItems: 2
+
+  clocks:
+    maxItems: 6
+
+  clock-names:
+    items:
+      - const: aux
+      - const: cfg_ahb
+      - const: ref
+      - const: rchng
+      - const: pipe
+      - const: pipediv2
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    items:
+      - const: phy
+
+  vdda-phy-supply: true
+
+  vdda-pll-supply: true
+
+  qcom,4ln-config-sel:
+    description: PCIe 4-lane configuration
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - items:
+          - description: phandle of TCSR syscon
+          - description: offset of PCIe 4-lane configuration register
+          - description: offset of configuration bit for this PHY
+
+  "#clock-cells":
+    const: 0
+
+  clock-output-names:
+    maxItems: 1
+
+  "#phy-cells":
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+  - resets
+  - reset-names
+  - vdda-phy-supply
+  - vdda-pll-supply
+  - "#clock-cells"
+  - clock-output-names
+  - "#phy-cells"
+
+additionalProperties: false
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,sc8280xp-qmp-gen3x4-pcie-phy
+    then:
+      properties:
+        reg:
+          items:
+            - description: port a
+            - description: port b
+      required:
+        - qcom,4ln-config-sel
+    else:
+      properties:
+        reg:
+          maxItems: 1
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sc8280xp.h>
+
+    pcie2b_phy: phy@1c18000 {
+      compatible = "qcom,sc8280xp-qmp-gen3x2-pcie-phy";
+      reg = <0x01c18000 0x2000>;
+
+      clocks = <&gcc GCC_PCIE_2B_AUX_CLK>,
+               <&gcc GCC_PCIE_2B_CFG_AHB_CLK>,
+               <&gcc GCC_PCIE_2A2B_CLKREF_CLK>,
+               <&gcc GCC_PCIE2B_PHY_RCHNG_CLK>,
+               <&gcc GCC_PCIE_2B_PIPE_CLK>,
+               <&gcc GCC_PCIE_2B_PIPEDIV2_CLK>;
+      clock-names = "aux", "cfg_ahb", "ref", "rchng",
+                    "pipe", "pipediv2";
+
+      power-domains = <&gcc PCIE_2B_GDSC>;
+
+      resets = <&gcc GCC_PCIE_2B_PHY_BCR>;
+      reset-names = "phy";
+
+      vdda-phy-supply = <&vreg_l6d>;
+      vdda-pll-supply = <&vreg_l4d>;
+
+      #clock-cells = <0>;
+      clock-output-names = "pcie_2b_pipe_clk";
+
+      #phy-cells = <0>;
+    };
+
+    pcie2a_phy: phy@1c24000 {
+      compatible = "qcom,sc8280xp-qmp-gen3x4-pcie-phy";
+      reg = <0x01c24000 0x2000>, <0x01c26000 0x2000>;
+
+      clocks = <&gcc GCC_PCIE_2A_AUX_CLK>,
+               <&gcc GCC_PCIE_2A_CFG_AHB_CLK>,
+               <&gcc GCC_PCIE_2A2B_CLKREF_CLK>,
+               <&gcc GCC_PCIE2A_PHY_RCHNG_CLK>,
+               <&gcc GCC_PCIE_2A_PIPE_CLK>,
+               <&gcc GCC_PCIE_2A_PIPEDIV2_CLK>;
+      clock-names = "aux", "cfg_ahb", "ref", "rchng",
+                    "pipe", "pipediv2";
+
+      power-domains = <&gcc PCIE_2A_GDSC>;
+
+      resets = <&gcc GCC_PCIE_2A_PHY_BCR>;
+      reset-names = "phy";
+
+      vdda-phy-supply = <&vreg_l6d>;
+      vdda-pll-supply = <&vreg_l4d>;
+
+      qcom,4ln-config-sel = <&tcsr 0xa044 0>;
+
+      #clock-cells = <0>;
+      clock-output-names = "pcie_2a_pipe_clk";
+
+      #phy-cells = <0>;
+    };
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
new file mode 100644 (file)
index 0000000..dde86a1
--- /dev/null
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,sc8280xp-qmp-ufs-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QMP PHY controller (UFS, SC8280XP)
+
+maintainers:
+  - Vinod Koul <vkoul@kernel.org>
+
+description:
+  The 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,sc8280xp-qmp-ufs-phy
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: ref
+      - const: ref_aux
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    items:
+      - const: ufsphy
+
+  vdda-phy-supply: true
+
+  vdda-pll-supply: true
+
+  "#phy-cells":
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+  - resets
+  - reset-names
+  - vdda-phy-supply
+  - vdda-pll-supply
+  - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sc8280xp.h>
+
+    ufs_mem_phy: phy@1d87000 {
+        compatible = "qcom,sc8280xp-qmp-ufs-phy";
+        reg = <0x01d87000 0x1000>;
+
+        clocks = <&gcc GCC_UFS_REF_CLKREF_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+        clock-names = "ref", "ref_aux";
+
+        power-domains = <&gcc UFS_PHY_GDSC>;
+
+        resets = <&ufs_mem_hc 0>;
+        reset-names = "ufsphy";
+
+        vdda-phy-supply = <&vreg_l6b>;
+        vdda-pll-supply = <&vreg_l3b>;
+
+        #phy-cells = <0>;
+    };
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml
new file mode 100644 (file)
index 0000000..16fce10
--- /dev/null
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QMP PHY controller (USB, SC8280XP)
+
+maintainers:
+  - Vinod Koul <vkoul@kernel.org>
+
+description:
+  The 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,sc8280xp-qmp-usb3-uni-phy
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 4
+
+  clock-names:
+    items:
+      - const: aux
+      - const: ref
+      - const: com_aux
+      - const: pipe
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 2
+
+  reset-names:
+    items:
+      - const: phy
+      - const: phy_phy
+
+  vdda-phy-supply: true
+
+  vdda-pll-supply: true
+
+  "#clock-cells":
+    const: 0
+
+  clock-output-names:
+    maxItems: 1
+
+  "#phy-cells":
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+  - resets
+  - reset-names
+  - vdda-phy-supply
+  - vdda-pll-supply
+  - "#clock-cells"
+  - clock-output-names
+  - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sc8280xp.h>
+    #include <dt-bindings/clock/qcom,rpmh.h>
+
+    phy@88ef000 {
+      compatible = "qcom,sc8280xp-qmp-usb3-uni-phy";
+      reg = <0x088ef000 0x2000>;
+
+      clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
+               <&gcc GCC_USB3_MP0_CLKREF_CLK>,
+               <&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
+               <&gcc GCC_USB3_MP_PHY_PIPE_0_CLK>;
+      clock-names = "aux", "ref", "com_aux", "pipe";
+
+      power-domains = <&gcc USB30_MP_GDSC>;
+
+      resets = <&gcc GCC_USB3_UNIPHY_MP0_BCR>,
+               <&gcc GCC_USB3UNIPHY_PHY_MP0_BCR>;
+      reset-names = "phy", "phy_phy";
+
+      vdda-phy-supply = <&vreg_l3a>;
+      vdda-pll-supply = <&vreg_l5a>;
+
+      #clock-cells = <0>;
+      clock-output-names = "usb2_phy0_pipe_clk";
+
+      #phy-cells = <0>;
+    };
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml
new file mode 100644 (file)
index 0000000..6f31693
--- /dev/null
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QMP USB4-USB3-DP PHY controller (SC8280XP)
+
+maintainers:
+  - Vinod Koul <vkoul@kernel.org>
+
+description:
+  The 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,sc8280xp-qmp-usb43dp-phy
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 4
+
+  clock-names:
+    items:
+      - const: aux
+      - const: ref
+      - const: com_aux
+      - const: usb3_pipe
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 2
+
+  reset-names:
+    items:
+      - const: phy
+      - const: common
+
+  vdda-phy-supply: true
+
+  vdda-pll-supply: true
+
+  "#clock-cells":
+    const: 1
+    description:
+      See include/dt-bindings/dt-bindings/phy/phy-qcom-qmp.h
+
+  "#phy-cells":
+    const: 1
+    description:
+      See include/dt-bindings/dt-bindings/phy/phy-qcom-qmp.h
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+  - resets
+  - reset-names
+  - vdda-phy-supply
+  - vdda-pll-supply
+  - "#clock-cells"
+  - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sc8280xp.h>
+
+    phy@88eb000 {
+      compatible = "qcom,sc8280xp-qmp-usb43dp-phy";
+      reg = <0x088eb000 0x4000>;
+
+      clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>,
+               <&gcc GCC_USB4_EUD_CLKREF_CLK>,
+               <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>,
+               <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+      clock-names = "aux", "ref", "com_aux", "usb3_pipe";
+
+      power-domains = <&gcc USB30_PRIM_GDSC>;
+
+      resets = <&gcc GCC_USB3_PHY_PRIM_BCR>,
+               <&gcc GCC_USB4_DP_PHY_PRIM_BCR>;
+      reset-names = "phy", "common";
+
+      vdda-phy-supply = <&vreg_l9d>;
+      vdda-pll-supply = <&vreg_l4d>;
+
+      #clock-cells = <1>;
+      #phy-cells = <1>;
+    };
diff --git a/Documentation/devicetree/bindings/phy/renesas,r8a779f0-ether-serdes.yaml b/Documentation/devicetree/bindings/phy/renesas,r8a779f0-ether-serdes.yaml
new file mode 100644 (file)
index 0000000..93ab728
--- /dev/null
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/renesas,r8a779f0-ether-serdes.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas Ethernet SERDES
+
+maintainers:
+  - Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+
+properties:
+  compatible:
+    const: renesas,r8a779f0-ether-serdes
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  '#phy-cells':
+    description: Port number of SERDES.
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - resets
+  - power-domains
+  - '#phy-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/r8a779f0-cpg-mssr.h>
+    #include <dt-bindings/power/r8a779f0-sysc.h>
+
+    phy@e6444000 {
+        compatible = "renesas,r8a779f0-ether-serdes";
+        reg = <0xe6444000 0xc00>;
+        clocks = <&cpg CPG_MOD 1506>;
+        power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+        resets = <&cpg 1506>;
+        #phy-cells = <1>;
+    };
index da7cac537e15c30a81ac6e30930b84d996803029..3a6d686383cf94a7076e767cad01f8256d819bde 100644 (file)
@@ -54,6 +54,7 @@ properties:
       - ti,dm814-phy-gmii-sel
       - ti,am654-phy-gmii-sel
       - ti,j7200-cpsw5g-phy-gmii-sel
+      - ti,j721e-cpsw9g-phy-gmii-sel
 
   reg:
     maxItems: 1
@@ -63,14 +64,17 @@ properties:
   ti,qsgmii-main-ports:
     $ref: /schemas/types.yaml#/definitions/uint32-array
     description: |
-      Required only for QSGMII mode. Array to select the port for
-      QSGMII main mode. Rest of the ports are selected as QSGMII_SUB
-      ports automatically. Any one of the 4 CPSW5G ports can act as the
-      main port with the rest of them being the QSGMII_SUB ports.
-    maxItems: 1
+      Required only for QSGMII mode. Array to select the port/s for QSGMII
+      main mode. The size of the array corresponds to the number of QSGMII
+      interfaces and thus, the number of distinct QSGMII main ports,
+      supported by the device. If the device supports two QSGMII interfaces
+      but only one QSGMII interface is desired, repeat the QSGMII main port
+      value corresponding to the QSGMII interface in the array.
+    minItems: 1
+    maxItems: 2
     items:
       minimum: 1
-      maximum: 4
+      maximum: 8
 
 allOf:
   - if:
@@ -81,12 +85,43 @@ allOf:
               - ti,dra7xx-phy-gmii-sel
               - ti,dm814-phy-gmii-sel
               - ti,am654-phy-gmii-sel
+              - ti,j7200-cpsw5g-phy-gmii-sel
+              - ti,j721e-cpsw9g-phy-gmii-sel
     then:
       properties:
         '#phy-cells':
           const: 1
           description: CPSW port number (starting from 1)
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - ti,j7200-cpsw5g-phy-gmii-sel
+    then:
+      properties:
+        ti,qsgmii-main-ports:
+          maxItems: 1
+          items:
+            minimum: 1
+            maximum: 4
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - ti,j721e-cpsw9g-phy-gmii-sel
+    then:
+      properties:
+        ti,qsgmii-main-ports:
+          minItems: 2
+          maxItems: 2
+          items:
+            minimum: 1
+            maximum: 8
+
   - if:
       not:
         properties:
@@ -94,6 +129,7 @@ allOf:
             contains:
               enum:
                 - ti,j7200-cpsw5g-phy-gmii-sel
+                - ti,j721e-cpsw9g-phy-gmii-sel
     then:
       properties:
         ti,qsgmii-main-ports: false
index 2225925b6dad898b8cb653245a36df910770e29e..c54b36c104abe9bfc413bd32b5a073bf1eb347e3 100644 (file)
@@ -15,8 +15,10 @@ properties:
     enum:
       - ti,j721e-wiz-16g
       - ti,j721e-wiz-10g
+      - ti,j721s2-wiz-10g
       - ti,am64-wiz-10g
       - ti,j7200-wiz-10g
+      - ti,j784s4-wiz-10g
 
   power-domains:
     maxItems: 1
index 8fc1ce0bb905de86dd4aa332e1dfc82cdd030339..8e8b3e8f95238d18dadc97b09bfdb08bc6230b74 100644 (file)
@@ -94,7 +94,8 @@ Inorder to dereference the private data (in phy_ops), the phy provider driver
 can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in
 phy_ops to get back the private data.
 
-4. Getting a reference to the PHY
+Getting a reference to the PHY
+==============================
 
 Before the controller can make use of the PHY, it has to get a reference to
 it. This framework provides the following APIs to get a reference to the PHY.
@@ -130,6 +131,28 @@ the phy_init() and phy_exit() calls, and phy_power_on() and
 phy_power_off() calls are all NOP when applied to a NULL phy. The NULL
 phy is useful in devices for handling optional phy devices.
 
+Order of API calls
+==================
+
+The general order of calls should be::
+
+    [devm_][of_]phy_get()
+    phy_init()
+    phy_power_on()
+    [phy_set_mode[_ext]()]
+    ...
+    phy_power_off()
+    phy_exit()
+    [[of_]phy_put()]
+
+Some PHY drivers may not implement :c:func:`phy_init` or :c:func:`phy_power_on`,
+but controllers should always call these functions to be compatible with other
+PHYs. Some PHYs may require :c:func:`phy_set_mode <phy_set_mode_ext>`, while
+others may use a default mode (typically configured via devicetree or other
+firmware). For compatibility, you should always call this function if you know
+what mode you will be using. Generally, this function should be called after
+:c:func:`phy_power_on`, although some PHY drivers may allow it at any time.
+
 Releasing a reference to the PHY
 ================================
 
index 6d0d1b759ca24a8a85f042090a25e6f1951aa36b..19b32839ea2610ae7cbee6d5870a5582632691e0 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
 #include <linux/mfd/syscon.h>
+#include <linux/phy/pcie.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
@@ -268,6 +269,10 @@ static int qcom_pcie_enable_resources(struct qcom_pcie_ep *pcie_ep)
        if (ret)
                goto err_disable_clk;
 
+       ret = phy_set_mode_ext(pcie_ep->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_EP);
+       if (ret)
+               goto err_phy_exit;
+
        ret = phy_power_on(pcie_ep->phy);
        if (ret)
                goto err_phy_exit;
index 38d5d46487bb91883b405223f18b017c9f472ca4..77e5dc7b88ad4b86c0af2a9df764c6e8e47b7851 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
+#include <linux/phy/pcie.h>
 #include <linux/phy/phy.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
@@ -1499,6 +1500,10 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp)
        if (ret)
                return ret;
 
+       ret = phy_set_mode_ext(pcie->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC);
+       if (ret)
+               goto err_deinit;
+
        ret = phy_power_on(pcie->phy);
        if (ret)
                goto err_deinit;
index 3a3831f6059a3f5e9733902a16ad947f34697ed6..5472db9e87ef88af6f743233d529fd29284cc111 100644 (file)
@@ -120,6 +120,7 @@ struct sun4i_usb_phy_cfg {
        u8 phyctl_offset;
        bool dedicated_clocks;
        bool phy0_dual_route;
+       bool needs_phy2_siddq;
        int missing_phys;
 };
 
@@ -289,6 +290,50 @@ static int sun4i_usb_phy_init(struct phy *_phy)
                return ret;
        }
 
+       /* Some PHYs on some SoCs need the help of PHY2 to work. */
+       if (data->cfg->needs_phy2_siddq && phy->index != 2) {
+               struct sun4i_usb_phy *phy2 = &data->phys[2];
+
+               ret = clk_prepare_enable(phy2->clk);
+               if (ret) {
+                       reset_control_assert(phy->reset);
+                       clk_disable_unprepare(phy->clk2);
+                       clk_disable_unprepare(phy->clk);
+                       return ret;
+               }
+
+               ret = reset_control_deassert(phy2->reset);
+               if (ret) {
+                       clk_disable_unprepare(phy2->clk);
+                       reset_control_assert(phy->reset);
+                       clk_disable_unprepare(phy->clk2);
+                       clk_disable_unprepare(phy->clk);
+                       return ret;
+               }
+
+               /*
+                * This extra clock is just needed to access the
+                * REG_HCI_PHY_CTL PMU register for PHY2.
+                */
+               ret = clk_prepare_enable(phy2->clk2);
+               if (ret) {
+                       reset_control_assert(phy2->reset);
+                       clk_disable_unprepare(phy2->clk);
+                       reset_control_assert(phy->reset);
+                       clk_disable_unprepare(phy->clk2);
+                       clk_disable_unprepare(phy->clk);
+                       return ret;
+               }
+
+               if (phy2->pmu && data->cfg->hci_phy_ctl_clear) {
+                       val = readl(phy2->pmu + REG_HCI_PHY_CTL);
+                       val &= ~data->cfg->hci_phy_ctl_clear;
+                       writel(val, phy2->pmu + REG_HCI_PHY_CTL);
+               }
+
+               clk_disable_unprepare(phy->clk2);
+       }
+
        if (phy->pmu && data->cfg->hci_phy_ctl_clear) {
                val = readl(phy->pmu + REG_HCI_PHY_CTL);
                val &= ~data->cfg->hci_phy_ctl_clear;
@@ -354,6 +399,13 @@ static int sun4i_usb_phy_exit(struct phy *_phy)
                data->phy0_init = false;
        }
 
+       if (data->cfg->needs_phy2_siddq && phy->index != 2) {
+               struct sun4i_usb_phy *phy2 = &data->phys[2];
+
+               clk_disable_unprepare(phy2->clk);
+               reset_control_assert(phy2->reset);
+       }
+
        sun4i_usb_phy_passby(phy, 0);
        reset_control_assert(phy->reset);
        clk_disable_unprepare(phy->clk2);
@@ -785,6 +837,13 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
                                dev_err(dev, "failed to get clock %s\n", name);
                                return PTR_ERR(phy->clk2);
                        }
+               } else {
+                       snprintf(name, sizeof(name), "pmu%d_clk", i);
+                       phy->clk2 = devm_clk_get_optional(dev, name);
+                       if (IS_ERR(phy->clk2)) {
+                               dev_err(dev, "failed to get clock %s\n", name);
+                               return PTR_ERR(phy->clk2);
+                       }
                }
 
                snprintf(name, sizeof(name), "usb%d_reset", i);
@@ -973,6 +1032,17 @@ static const struct sun4i_usb_phy_cfg sun50i_h6_cfg = {
        .missing_phys = BIT(1) | BIT(2),
 };
 
+static const struct sun4i_usb_phy_cfg sun50i_h616_cfg = {
+       .num_phys = 4,
+       .type = sun50i_h6_phy,
+       .disc_thresh = 3,
+       .phyctl_offset = REG_PHYCTL_A33,
+       .dedicated_clocks = true,
+       .phy0_dual_route = true,
+       .hci_phy_ctl_clear = PHY_CTL_SIDDQ,
+       .needs_phy2_siddq = true,
+};
+
 static const struct of_device_id sun4i_usb_phy_of_match[] = {
        { .compatible = "allwinner,sun4i-a10-usb-phy", .data = &sun4i_a10_cfg },
        { .compatible = "allwinner,sun5i-a13-usb-phy", .data = &sun5i_a13_cfg },
@@ -988,6 +1058,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {
        { .compatible = "allwinner,sun50i-a64-usb-phy",
          .data = &sun50i_a64_cfg},
        { .compatible = "allwinner,sun50i-h6-usb-phy", .data = &sun50i_h6_cfg },
+       { .compatible = "allwinner,sun50i-h616-usb-phy", .data = &sun50i_h616_cfg },
        { },
 };
 MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
index 3900f165085153d5c9d0b8954a6344a464d75445..36eab95271b2dcdea9e336c56c400c9f20223696 100644 (file)
 
 #define SUN6I_DPHY_ANA0_REG            0x4c
 #define SUN6I_DPHY_ANA0_REG_PWS                        BIT(31)
+#define SUN6I_DPHY_ANA0_REG_PWEND              BIT(30)
+#define SUN6I_DPHY_ANA0_REG_PWENC              BIT(29)
 #define SUN6I_DPHY_ANA0_REG_DMPC               BIT(28)
 #define SUN6I_DPHY_ANA0_REG_DMPD(n)            (((n) & 0xf) << 24)
+#define SUN6I_DPHY_ANA0_REG_SRXDT(n)           (((n) & 0xf) << 20)
+#define SUN6I_DPHY_ANA0_REG_SRXCK(n)           (((n) & 0xf) << 16)
+#define SUN6I_DPHY_ANA0_REG_SDIV2              BIT(15)
 #define SUN6I_DPHY_ANA0_REG_SLV(n)             (((n) & 7) << 12)
 #define SUN6I_DPHY_ANA0_REG_DEN(n)             (((n) & 0xf) << 8)
+#define SUN6I_DPHY_ANA0_REG_PLR(n)             (((n) & 0xf) << 4)
 #define SUN6I_DPHY_ANA0_REG_SFB(n)             (((n) & 3) << 2)
+#define SUN6I_DPHY_ANA0_REG_RSD                        BIT(1)
+#define SUN6I_DPHY_ANA0_REG_SELSCK             BIT(0)
 
 #define SUN6I_DPHY_ANA1_REG            0x50
 #define SUN6I_DPHY_ANA1_REG_VTTMODE            BIT(31)
 #define SUN6I_DPHY_ANA3_EN_LDOR                        BIT(18)
 
 #define SUN6I_DPHY_ANA4_REG            0x5c
+#define SUN6I_DPHY_ANA4_REG_EN_MIPI            BIT(31)
+#define SUN6I_DPHY_ANA4_REG_EN_COMTEST         BIT(30)
+#define SUN6I_DPHY_ANA4_REG_COMTEST(n)         (((n) & 3) << 28)
+#define SUN6I_DPHY_ANA4_REG_IB(n)              (((n) & 3) << 25)
 #define SUN6I_DPHY_ANA4_REG_DMPLVC             BIT(24)
 #define SUN6I_DPHY_ANA4_REG_DMPLVD(n)          (((n) & 0xf) << 20)
+#define SUN6I_DPHY_ANA4_REG_VTT_SET(n)         (((n) & 0x7) << 17)
 #define SUN6I_DPHY_ANA4_REG_CKDV(n)            (((n) & 0x1f) << 12)
 #define SUN6I_DPHY_ANA4_REG_TMSC(n)            (((n) & 3) << 10)
 #define SUN6I_DPHY_ANA4_REG_TMSD(n)            (((n) & 3) << 8)
 
 #define SUN6I_DPHY_DBG5_REG            0xf4
 
+#define SUN50I_DPHY_TX_SLEW_REG0       0xf8
+#define SUN50I_DPHY_TX_SLEW_REG1       0xfc
+#define SUN50I_DPHY_TX_SLEW_REG2       0x100
+
+#define SUN50I_DPHY_PLL_REG0           0x104
+#define SUN50I_DPHY_PLL_REG0_CP36_EN           BIT(23)
+#define SUN50I_DPHY_PLL_REG0_LDO_EN            BIT(22)
+#define SUN50I_DPHY_PLL_REG0_EN_LVS            BIT(21)
+#define SUN50I_DPHY_PLL_REG0_PLL_EN            BIT(20)
+#define SUN50I_DPHY_PLL_REG0_P(n)              (((n) & 0xf) << 16)
+#define SUN50I_DPHY_PLL_REG0_N(n)              (((n) & 0xff) << 8)
+#define SUN50I_DPHY_PLL_REG0_NDET              BIT(7)
+#define SUN50I_DPHY_PLL_REG0_TDIV              BIT(6)
+#define SUN50I_DPHY_PLL_REG0_M0(n)             (((n) & 3) << 4)
+#define SUN50I_DPHY_PLL_REG0_M1(n)             ((n) & 0xf)
+
+#define SUN50I_DPHY_PLL_REG1           0x108
+#define SUN50I_DPHY_PLL_REG1_UNLOCK_MDSEL(n)   (((n) & 3) << 14)
+#define SUN50I_DPHY_PLL_REG1_LOCKMDSEL         BIT(13)
+#define SUN50I_DPHY_PLL_REG1_LOCKDET_EN                BIT(12)
+#define SUN50I_DPHY_PLL_REG1_VSETA(n)          (((n) & 0x7) << 9)
+#define SUN50I_DPHY_PLL_REG1_VSETD(n)          (((n) & 0x7) << 6)
+#define SUN50I_DPHY_PLL_REG1_LPF_SW            BIT(5)
+#define SUN50I_DPHY_PLL_REG1_ICP_SEL(n)                (((n) & 3) << 3)
+#define SUN50I_DPHY_PLL_REG1_ATEST_SEL(n)      (((n) & 3) << 1)
+#define SUN50I_DPHY_PLL_REG1_TEST_EN           BIT(0)
+
+#define SUN50I_DPHY_PLL_REG2           0x10c
+#define SUN50I_DPHY_PLL_REG2_SDM_EN            BIT(31)
+#define SUN50I_DPHY_PLL_REG2_FF_EN             BIT(30)
+#define SUN50I_DPHY_PLL_REG2_SS_EN             BIT(29)
+#define SUN50I_DPHY_PLL_REG2_SS_FRAC(n)                (((n) & 0x1ff) << 20)
+#define SUN50I_DPHY_PLL_REG2_SS_INT(n)         (((n) & 0xff) << 12)
+#define SUN50I_DPHY_PLL_REG2_FRAC(n)           ((n) & 0xfff)
+
+#define SUN50I_COMBO_PHY_REG0          0x110
+#define SUN50I_COMBO_PHY_REG0_EN_TEST_COMBOLDO BIT(5)
+#define SUN50I_COMBO_PHY_REG0_EN_TEST_0P8      BIT(4)
+#define SUN50I_COMBO_PHY_REG0_EN_MIPI          BIT(3)
+#define SUN50I_COMBO_PHY_REG0_EN_LVDS          BIT(2)
+#define SUN50I_COMBO_PHY_REG0_EN_COMBOLDO      BIT(1)
+#define SUN50I_COMBO_PHY_REG0_EN_CP            BIT(0)
+
+#define SUN50I_COMBO_PHY_REG1          0x114
+#define SUN50I_COMBO_PHY_REG2_REG_VREF1P6(n)   (((n) & 0x7) << 4)
+#define SUN50I_COMBO_PHY_REG2_REG_VREF0P8(n)   ((n) & 0x7)
+
+#define SUN50I_COMBO_PHY_REG2          0x118
+#define SUN50I_COMBO_PHY_REG2_HS_STOP_DLY(n)   ((n) & 0xff)
+
 enum sun6i_dphy_direction {
        SUN6I_DPHY_DIRECTION_TX,
        SUN6I_DPHY_DIRECTION_RX,
 };
 
+struct sun6i_dphy;
+
+struct sun6i_dphy_variant {
+       void    (*tx_power_on)(struct sun6i_dphy *dphy);
+       bool    rx_supported;
+};
+
 struct sun6i_dphy {
        struct clk                              *bus_clk;
        struct clk                              *mod_clk;
@@ -123,6 +193,7 @@ struct sun6i_dphy {
        struct phy                              *phy;
        struct phy_configure_opts_mipi_dphy     config;
 
+       const struct sun6i_dphy_variant         *variant;
        enum sun6i_dphy_direction               direction;
 };
 
@@ -151,37 +222,10 @@ static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
        return 0;
 }
 
-static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy)
+static void sun6i_a31_mipi_dphy_tx_power_on(struct sun6i_dphy *dphy)
 {
        u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
 
-       regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
-                    SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
-
-       regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG,
-                    SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) |
-                    SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) |
-                    SUN6I_DPHY_TX_TIME0_HS_TRAIL(10));
-
-       regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG,
-                    SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) |
-                    SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) |
-                    SUN6I_DPHY_TX_TIME1_CLK_PRE(3) |
-                    SUN6I_DPHY_TX_TIME1_CLK_POST(10));
-
-       regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG,
-                    SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30));
-
-       regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0);
-
-       regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG,
-                    SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) |
-                    SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
-
-       regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
-                    SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) |
-                    SUN6I_DPHY_GCTL_EN);
-
        regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
                     SUN6I_DPHY_ANA0_REG_PWS |
                     SUN6I_DPHY_ANA0_REG_DMPC |
@@ -213,6 +257,106 @@ static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy)
                     SUN6I_DPHY_ANA3_EN_LDOC |
                     SUN6I_DPHY_ANA3_EN_LDOD);
        udelay(1);
+}
+
+static void sun50i_a100_mipi_dphy_tx_power_on(struct sun6i_dphy *dphy)
+{
+       unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate;
+       unsigned int div, n;
+
+       regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
+                    SUN6I_DPHY_ANA4_REG_IB(2) |
+                    SUN6I_DPHY_ANA4_REG_DMPLVD(4) |
+                    SUN6I_DPHY_ANA4_REG_VTT_SET(3) |
+                    SUN6I_DPHY_ANA4_REG_CKDV(3) |
+                    SUN6I_DPHY_ANA4_REG_TMSD(1) |
+                    SUN6I_DPHY_ANA4_REG_TMSC(1) |
+                    SUN6I_DPHY_ANA4_REG_TXPUSD(2) |
+                    SUN6I_DPHY_ANA4_REG_TXPUSC(3) |
+                    SUN6I_DPHY_ANA4_REG_TXDNSD(2) |
+                    SUN6I_DPHY_ANA4_REG_TXDNSC(3));
+
+       regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
+                          SUN6I_DPHY_ANA2_EN_CK_CPU,
+                          SUN6I_DPHY_ANA2_EN_CK_CPU);
+
+       regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
+                          SUN6I_DPHY_ANA2_REG_ENIB,
+                          SUN6I_DPHY_ANA2_REG_ENIB);
+
+       regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
+                    SUN6I_DPHY_ANA3_EN_LDOR |
+                    SUN6I_DPHY_ANA3_EN_LDOC |
+                    SUN6I_DPHY_ANA3_EN_LDOD);
+
+       regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
+                    SUN6I_DPHY_ANA0_REG_PLR(4) |
+                    SUN6I_DPHY_ANA0_REG_SFB(1));
+
+       regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG0,
+                    SUN50I_COMBO_PHY_REG0_EN_CP);
+
+       /* Choose a divider to limit the VCO frequency to around 2 GHz. */
+       div = 16 >> order_base_2(DIV_ROUND_UP(mipi_symbol_rate, 264000000));
+       n = mipi_symbol_rate * div / 24000000;
+
+       regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG0,
+                    SUN50I_DPHY_PLL_REG0_CP36_EN |
+                    SUN50I_DPHY_PLL_REG0_LDO_EN |
+                    SUN50I_DPHY_PLL_REG0_EN_LVS |
+                    SUN50I_DPHY_PLL_REG0_PLL_EN |
+                    SUN50I_DPHY_PLL_REG0_NDET |
+                    SUN50I_DPHY_PLL_REG0_P((div - 1) % 8) |
+                    SUN50I_DPHY_PLL_REG0_N(n) |
+                    SUN50I_DPHY_PLL_REG0_M0((div - 1) / 8) |
+                    SUN50I_DPHY_PLL_REG0_M1(2));
+
+       /* Disable sigma-delta modulation. */
+       regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG2, 0);
+
+       regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA4_REG,
+                          SUN6I_DPHY_ANA4_REG_EN_MIPI,
+                          SUN6I_DPHY_ANA4_REG_EN_MIPI);
+
+       regmap_update_bits(dphy->regs, SUN50I_COMBO_PHY_REG0,
+                          SUN50I_COMBO_PHY_REG0_EN_MIPI |
+                          SUN50I_COMBO_PHY_REG0_EN_COMBOLDO,
+                          SUN50I_COMBO_PHY_REG0_EN_MIPI |
+                          SUN50I_COMBO_PHY_REG0_EN_COMBOLDO);
+
+       regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG2,
+                    SUN50I_COMBO_PHY_REG2_HS_STOP_DLY(20));
+       udelay(1);
+}
+
+static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy)
+{
+       u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
+
+       regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
+                    SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
+
+       regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG,
+                    SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) |
+                    SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) |
+                    SUN6I_DPHY_TX_TIME0_HS_TRAIL(10));
+
+       regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG,
+                    SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) |
+                    SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) |
+                    SUN6I_DPHY_TX_TIME1_CLK_PRE(3) |
+                    SUN6I_DPHY_TX_TIME1_CLK_POST(10));
+
+       regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG,
+                    SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30));
+
+       regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0);
+
+       regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG,
+                    SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) |
+                    SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
+
+       dphy->variant->tx_power_on(dphy);
 
        regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
                           SUN6I_DPHY_ANA3_EN_VTTC |
@@ -239,6 +383,10 @@ static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy)
                           SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK,
                           SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask));
 
+       regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
+                    SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) |
+                    SUN6I_DPHY_GCTL_EN);
+
        return 0;
 }
 
@@ -393,7 +541,7 @@ static const struct regmap_config sun6i_dphy_regmap_config = {
        .reg_bits       = 32,
        .val_bits       = 32,
        .reg_stride     = 4,
-       .max_register   = SUN6I_DPHY_DBG5_REG,
+       .max_register   = SUN50I_COMBO_PHY_REG2,
        .name           = "mipi-dphy",
 };
 
@@ -409,6 +557,10 @@ static int sun6i_dphy_probe(struct platform_device *pdev)
        if (!dphy)
                return -ENOMEM;
 
+       dphy->variant = device_get_match_data(&pdev->dev);
+       if (!dphy->variant)
+               return -EINVAL;
+
        regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(regs)) {
                dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n");
@@ -445,8 +597,14 @@ static int sun6i_dphy_probe(struct platform_device *pdev)
        ret = of_property_read_string(pdev->dev.of_node, "allwinner,direction",
                                      &direction);
 
-       if (!ret && !strncmp(direction, "rx", 2))
+       if (!ret && !strncmp(direction, "rx", 2)) {
+               if (!dphy->variant->rx_supported) {
+                       dev_err(&pdev->dev, "RX not supported on this variant\n");
+                       return -EOPNOTSUPP;
+               }
+
                dphy->direction = SUN6I_DPHY_DIRECTION_RX;
+       }
 
        phy_set_drvdata(dphy->phy, dphy);
        phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
@@ -454,8 +612,24 @@ static int sun6i_dphy_probe(struct platform_device *pdev)
        return PTR_ERR_OR_ZERO(phy_provider);
 }
 
+static const struct sun6i_dphy_variant sun6i_a31_mipi_dphy_variant = {
+       .tx_power_on    = sun6i_a31_mipi_dphy_tx_power_on,
+       .rx_supported   = true,
+};
+
+static const struct sun6i_dphy_variant sun50i_a100_mipi_dphy_variant = {
+       .tx_power_on    = sun50i_a100_mipi_dphy_tx_power_on,
+};
+
 static const struct of_device_id sun6i_dphy_of_table[] = {
-       { .compatible = "allwinner,sun6i-a31-mipi-dphy" },
+       {
+               .compatible     = "allwinner,sun6i-a31-mipi-dphy",
+               .data           = &sun6i_a31_mipi_dphy_variant,
+       },
+       {
+               .compatible     = "allwinner,sun50i-a100-mipi-dphy",
+               .data           = &sun50i_a100_mipi_dphy_variant,
+       },
        { }
 };
 MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table);
index d2524b70ea16101cf9463153b48226896922230e..76cf4280d7ed943d8f85b9dbf7e001ff7159a67f 100644 (file)
 #define PIARBCTL_CAM                   0x00
 #define PIARBCTL_SPLITTER              0x04
 #define PIARBCTL_MISC                  0x08
-#define   PIARBCTL_MISC_SECURE_MASK                    0x80000000
-#define   PIARBCTL_MISC_USB_SELECT_MASK                        0x40000000
-#define   PIARBCTL_MISC_USB_4G_SDRAM_MASK              0x20000000
-#define   PIARBCTL_MISC_USB_PRIORITY_MASK              0x000f0000
-#define   PIARBCTL_MISC_USB_MEM_PAGE_MASK              0x0000f000
-#define   PIARBCTL_MISC_CAM1_MEM_PAGE_MASK             0x00000f00
-#define   PIARBCTL_MISC_CAM0_MEM_PAGE_MASK             0x000000f0
-#define   PIARBCTL_MISC_SATA_PRIORITY_MASK             0x0000000f
+#define   PIARBCTL_MISC_SATA_PRIORITY_MASK             GENMASK(3, 0)
+#define   PIARBCTL_MISC_CAM0_MEM_PAGE_MASK             GENMASK(7, 4)
+#define   PIARBCTL_MISC_CAM1_MEM_PAGE_MASK             GENMASK(11, 8)
+#define   PIARBCTL_MISC_USB_MEM_PAGE_MASK              GENMASK(15, 12)
+#define   PIARBCTL_MISC_USB_PRIORITY_MASK              GENMASK(19, 16)
+#define   PIARBCTL_MISC_USB_4G_SDRAM_MASK              BIT(29)
+#define   PIARBCTL_MISC_USB_SELECT_MASK                        BIT(30)
+#define   PIARBCTL_MISC_SECURE_MASK                    BIT(31)
 
 #define PIARBCTL_MISC_USB_ONLY_MASK            \
        (PIARBCTL_MISC_USB_SELECT_MASK |        \
 
 /* Register definitions for the USB CTRL block */
 #define USB_CTRL_SETUP                 0x00
-#define   USB_CTRL_SETUP_STRAP_IPP_SEL_MASK            0x02000000
-#define   USB_CTRL_SETUP_SCB2_EN_MASK                  0x00008000
-#define   USB_CTRL_SETUP_tca_drv_sel_MASK              0x01000000
-#define   USB_CTRL_SETUP_SCB1_EN_MASK                  0x00004000
-#define   USB_CTRL_SETUP_SOFT_SHUTDOWN_MASK            0x00000200
-#define   USB_CTRL_SETUP_IPP_MASK                      0x00000020
-#define   USB_CTRL_SETUP_IOC_MASK                      0x00000010
+#define   USB_CTRL_SETUP_IOC_MASK                      BIT(4)
+#define   USB_CTRL_SETUP_IPP_MASK                      BIT(5)
+#define   USB_CTRL_SETUP_SOFT_SHUTDOWN_MASK            BIT(9)
+#define   USB_CTRL_SETUP_SCB1_EN_MASK                  BIT(14)
+#define   USB_CTRL_SETUP_SCB2_EN_MASK                  BIT(15)
+#define   USB_CTRL_SETUP_tca_drv_sel_MASK              BIT(24)
+#define   USB_CTRL_SETUP_STRAP_IPP_SEL_MASK            BIT(25)
 #define USB_CTRL_USB_PM                        0x04
-#define   USB_CTRL_USB_PM_USB_PWRDN_MASK               0x80000000
-#define   USB_CTRL_USB_PM_SOFT_RESET_MASK              0x40000000
-#define   USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK         0x00800000
-#define   USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK         0x00400000
-#define   USB_CTRL_USB_PM_XHC_PME_EN_MASK              0x00000010
-#define   USB_CTRL_USB_PM_XHC_S2_CLK_SWITCH_EN_MASK    0x00000008
+#define   USB_CTRL_USB_PM_XHC_S2_CLK_SWITCH_EN_MASK    BIT(3)
+#define   USB_CTRL_USB_PM_XHC_PME_EN_MASK              BIT(4)
+#define   USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK         BIT(22)
+#define   USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK         BIT(23)
+#define   USB_CTRL_USB_PM_SOFT_RESET_MASK              BIT(30)
+#define   USB_CTRL_USB_PM_USB_PWRDN_MASK               BIT(31)
 #define USB_CTRL_USB_PM_STATUS         0x08
 #define USB_CTRL_USB_DEVICE_CTL1       0x10
-#define   USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK      0x00000003
+#define   USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK      GENMASK(1, 0)
 #define USB_CTRL_TEST_PORT_CTL         0x30
-#define   USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_MASK        0x000000ff
+#define   USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_MASK                GENMASK(7, 0)
 #define   USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_PME_GEN_MASK        0x0000002e
 #define USB_CTRL_TP_DIAG1              0x34
-#define   USB_CTLR_TP_DIAG1_wake_MASK  0x00000002
+#define   USB_CTLR_TP_DIAG1_wake_MASK                  BIT(1)
 #define USB_CTRL_CTLR_CSHCR            0x50
-#define   USB_CTRL_CTLR_CSHCR_ctl_pme_en_MASK  0x00040000
+#define   USB_CTRL_CTLR_CSHCR_ctl_pme_en_MASK          BIT(18)
 
 /* Register definitions for the USB_PHY block in 7211b0 */
 #define USB_PHY_PLL_CTL                        0x00
-#define   USB_PHY_PLL_CTL_PLL_RESETB_MASK              0x40000000
+#define   USB_PHY_PLL_CTL_PLL_SUSPEND_MASK             BIT(27)
+#define   USB_PHY_PLL_CTL_PLL_RESETB_MASK              BIT(30)
 #define USB_PHY_PLL_LDO_CTL            0x08
-#define   USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK         0x00000004
-#define   USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK     0x00000002
-#define   USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK      0x00000001
+#define   USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK      BIT(0)
+#define   USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK     BIT(1)
+#define   USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK         BIT(2)
 #define USB_PHY_UTMI_CTL_1             0x04
-#define   USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK      0x00000800
-#define   USB_PHY_UTMI_CTL_1_PHY_MODE_MASK             0x0000000c
+#define   USB_PHY_UTMI_CTL_1_PHY_MODE_MASK             GENMASK(3, 2)
 #define   USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT            2
+#define   USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK      BIT(11)
 #define USB_PHY_IDDQ                   0x1c
-#define   USB_PHY_IDDQ_phy_iddq_MASK                   0x00000001
+#define   USB_PHY_IDDQ_phy_iddq_MASK                   BIT(0)
 #define USB_PHY_STATUS                 0x20
-#define   USB_PHY_STATUS_pll_lock_MASK                 0x00000001
+#define   USB_PHY_STATUS_pll_lock_MASK                 BIT(0)
 
 /* Register definitions for the MDIO registers in the DWC2 block of
  * the 7211b0.
@@ -86,7 +87,7 @@
 
 /* Register definitions for the BDC EC block in 7211b0 */
 #define BDC_EC_AXIRDA                  0x0c
-#define   BDC_EC_AXIRDA_RTS_MASK                       0xf0000000
+#define   BDC_EC_AXIRDA_RTS_MASK                       GENMASK(31, 28)
 #define   BDC_EC_AXIRDA_RTS_SHIFT                      28
 
 
@@ -195,10 +196,10 @@ static void usb_init_common(struct brcm_usb_init_params *params)
        if (USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE)) {
                reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
                reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
-               reg |= params->mode;
+               reg |= params->port_mode;
                brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
        }
-       switch (params->mode) {
+       switch (params->supported_port_modes) {
        case USB_CTLR_MODE_HOST:
                USB_CTRL_UNSET(ctrl, USB_PM, BDC_SOFT_RESETB);
                break;
@@ -259,6 +260,11 @@ static void usb_init_common_7211b0(struct brcm_usb_init_params *params)
                brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
        }
 
+       /* Disable PLL auto suspend */
+       reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL);
+       reg |= USB_PHY_PLL_CTL_PLL_SUSPEND_MASK;
+       brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL);
+
        /* Init the PHY */
        reg = USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK |
                USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK |
@@ -276,7 +282,7 @@ static void usb_init_common_7211b0(struct brcm_usb_init_params *params)
        /* Set the PHY_MODE */
        reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1);
        reg &= ~USB_PHY_UTMI_CTL_1_PHY_MODE_MASK;
-       reg |= params->mode << USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT;
+       reg |= params->supported_port_modes << USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT;
        brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
 
        usb_init_common(params);
@@ -286,7 +292,7 @@ static void usb_init_common_7211b0(struct brcm_usb_init_params *params)
         * the default "Read Transaction Size" of 6 (1024 bytes).
         * Set it to 4 (256 bytes).
         */
-       if ((params->mode != USB_CTLR_MODE_HOST) && bdc_ec) {
+       if ((params->supported_port_modes != USB_CTLR_MODE_HOST) && bdc_ec) {
                reg = brcm_usb_readl(bdc_ec + BDC_EC_AXIRDA);
                reg &= ~BDC_EC_AXIRDA_RTS_MASK;
                reg |= (0x4 << BDC_EC_AXIRDA_RTS_SHIFT);
@@ -331,13 +337,12 @@ static void usb_uninit_common_7216(struct brcm_usb_init_params *params)
 
        pr_debug("%s\n", __func__);
 
-       if (!params->wake_enabled) {
-               USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
-
+       if (params->wake_enabled) {
                /* Switch to using slower clock during suspend to save power */
                USB_CTRL_SET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN);
-       } else {
                usb_wake_enable_7216(params, true);
+       } else {
+               USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
        }
 }
 
@@ -385,7 +390,7 @@ static int usb_get_dual_select(struct brcm_usb_init_params *params)
        return reg;
 }
 
-static void usb_set_dual_select(struct brcm_usb_init_params *params, int mode)
+static void usb_set_dual_select(struct brcm_usb_init_params *params)
 {
        void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
        u32 reg;
@@ -394,7 +399,7 @@ static void usb_set_dual_select(struct brcm_usb_init_params *params, int mode)
 
        reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
        reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
-       reg |= mode;
+       reg |= params->port_mode;
        brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
 }
 
@@ -425,7 +430,6 @@ void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params)
 
        params->family_name = "7216";
        params->ops = &bcm7216_ops;
-       params->suspend_with_clocks = true;
 }
 
 void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params)
@@ -435,5 +439,4 @@ void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params)
 
        params->family_name = "7211";
        params->ops = &bcm7211b0_ops;
-       params->suspend_with_clocks = true;
 }
index dddcbd3cd5f3da10ed2f6cdf89bf51d53d36da4f..a1ca83308f98d365c12eb29698b0cea4589d85d1 100644 (file)
 
 /* Register definitions for the USB CTRL block */
 #define USB_CTRL_SETUP                 0x00
-#define   USB_CTRL_SETUP_IOC_MASK                      0x00000010
-#define   USB_CTRL_SETUP_IPP_MASK                      0x00000020
-#define   USB_CTRL_SETUP_BABO_MASK                     0x00000001
-#define   USB_CTRL_SETUP_FNHW_MASK                     0x00000002
-#define   USB_CTRL_SETUP_FNBO_MASK                     0x00000004
-#define   USB_CTRL_SETUP_WABO_MASK                     0x00000008
-#define   USB_CTRL_SETUP_SCB_CLIENT_SWAP_MASK          0x00002000 /* option */
-#define   USB_CTRL_SETUP_SCB1_EN_MASK                  0x00004000 /* option */
-#define   USB_CTRL_SETUP_SCB2_EN_MASK                  0x00008000 /* option */
-#define   USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK          0X00020000 /* option */
-#define   USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK      0x00010000 /* option */
-#define   USB_CTRL_SETUP_STRAP_IPP_SEL_MASK            0x02000000 /* option */
-#define   USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK       0x04000000 /* option */
-#define   USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK 0x08000000 /* opt */
-#define   USB_CTRL_SETUP_OC3_DISABLE_MASK              0xc0000000 /* option */
+#define   USB_CTRL_SETUP_BABO_MASK                     BIT(0)
+#define   USB_CTRL_SETUP_FNHW_MASK                     BIT(1)
+#define   USB_CTRL_SETUP_FNBO_MASK                     BIT(2)
+#define   USB_CTRL_SETUP_WABO_MASK                     BIT(3)
+#define   USB_CTRL_SETUP_IOC_MASK                      BIT(4)
+#define   USB_CTRL_SETUP_IPP_MASK                      BIT(5)
+#define   USB_CTRL_SETUP_SCB_CLIENT_SWAP_MASK          BIT(13) /* option */
+#define   USB_CTRL_SETUP_SCB1_EN_MASK                  BIT(14) /* option */
+#define   USB_CTRL_SETUP_SCB2_EN_MASK                  BIT(15) /* option */
+#define   USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK          BIT(17) /* option */
+#define   USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK      BIT(16) /* option */
+#define   USB_CTRL_SETUP_STRAP_IPP_SEL_MASK            BIT(25) /* option */
+#define   USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK       BIT(26) /* option */
+#define   USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK BIT(27) /* opt */
+#define   USB_CTRL_SETUP_OC3_DISABLE_MASK              GENMASK(31, 30) /* option */
 #define USB_CTRL_PLL_CTL               0x04
-#define   USB_CTRL_PLL_CTL_PLL_SUSPEND_EN_MASK         0x08000000
-#define   USB_CTRL_PLL_CTL_PLL_RESETB_MASK             0x40000000
-#define   USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK         0x80000000 /* option */
+#define   USB_CTRL_PLL_CTL_PLL_SUSPEND_EN_MASK         BIT(27)
+#define   USB_CTRL_PLL_CTL_PLL_RESETB_MASK             BIT(30)
+#define   USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK         BIT(31) /* option */
 #define USB_CTRL_EBRIDGE               0x0c
-#define   USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK          0x00020000 /* option */
-#define   USB_CTRL_EBRIDGE_EBR_SCB_SIZE_MASK           0x00000f80 /* option */
+#define   USB_CTRL_EBRIDGE_EBR_SCB_SIZE_MASK           GENMASK(11, 7) /* option */
+#define   USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK          BIT(17) /* option */
 #define USB_CTRL_OBRIDGE               0x10
-#define   USB_CTRL_OBRIDGE_LS_KEEP_ALIVE_MASK          0x08000000
+#define   USB_CTRL_OBRIDGE_LS_KEEP_ALIVE_MASK          BIT(27)
 #define USB_CTRL_MDIO                  0x14
 #define USB_CTRL_MDIO2                 0x18
 #define USB_CTRL_UTMI_CTL_1            0x2c
-#define   USB_CTRL_UTMI_CTL_1_POWER_UP_FSM_EN_MASK     0x00000800
-#define   USB_CTRL_UTMI_CTL_1_POWER_UP_FSM_EN_P1_MASK  0x08000000
+#define   USB_CTRL_UTMI_CTL_1_POWER_UP_FSM_EN_MASK     BIT(11)
+#define   USB_CTRL_UTMI_CTL_1_POWER_UP_FSM_EN_P1_MASK  BIT(27)
 #define USB_CTRL_USB_PM                        0x34
-#define   USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK         0x00800000 /* option */
-#define   USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK         0x00400000 /* option */
-#define   USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK     0x40000000 /* option */
-#define   USB_CTRL_USB_PM_USB_PWRDN_MASK               0x80000000 /* option */
-#define   USB_CTRL_USB_PM_SOFT_RESET_MASK              0x40000000 /* option */
-#define   USB_CTRL_USB_PM_USB20_HC_RESETB_MASK         0x30000000 /* option */
-#define   USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK     0x00300000 /* option */
-#define   USB_CTRL_USB_PM_RMTWKUP_EN_MASK              0x00000001
+#define   USB_CTRL_USB_PM_RMTWKUP_EN_MASK              BIT(0)
+#define   USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK     GENMASK(21, 20) /* option */
+#define   USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK         BIT(22) /* option */
+#define   USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK         BIT(23) /* option */
+#define   USB_CTRL_USB_PM_USB20_HC_RESETB_MASK         GENMASK(29, 28) /* option */
+#define   USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK     BIT(30) /* option */
+#define   USB_CTRL_USB_PM_SOFT_RESET_MASK              BIT(30) /* option */
+#define   USB_CTRL_USB_PM_USB_PWRDN_MASK               BIT(31) /* option */
 #define USB_CTRL_USB_PM_STATUS         0x38
 #define USB_CTRL_USB30_CTL1            0x60
-#define   USB_CTRL_USB30_CTL1_PHY3_PLL_SEQ_START_MASK  0x00000010
-#define   USB_CTRL_USB30_CTL1_PHY3_RESETB_MASK         0x00010000
-#define   USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK     0x00020000 /* option */
-#define   USB_CTRL_USB30_CTL1_USB3_IOC_MASK            0x10000000 /* option */
-#define   USB_CTRL_USB30_CTL1_USB3_IPP_MASK            0x20000000 /* option */
+#define   USB_CTRL_USB30_CTL1_PHY3_PLL_SEQ_START_MASK  BIT(4)
+#define   USB_CTRL_USB30_CTL1_PHY3_RESETB_MASK         BIT(16)
+#define   USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK     BIT(17) /* option */
+#define   USB_CTRL_USB30_CTL1_USB3_IOC_MASK            BIT(28) /* option */
+#define   USB_CTRL_USB30_CTL1_USB3_IPP_MASK            BIT(29) /* option */
 #define USB_CTRL_USB30_PCTL            0x70
-#define   USB_CTRL_USB30_PCTL_PHY3_SOFT_RESETB_MASK    0x00000002
-#define   USB_CTRL_USB30_PCTL_PHY3_IDDQ_OVERRIDE_MASK  0x00008000
-#define   USB_CTRL_USB30_PCTL_PHY3_SOFT_RESETB_P1_MASK 0x00020000
+#define   USB_CTRL_USB30_PCTL_PHY3_SOFT_RESETB_MASK    BIT(1)
+#define   USB_CTRL_USB30_PCTL_PHY3_IDDQ_OVERRIDE_MASK  BIT(15)
+#define   USB_CTRL_USB30_PCTL_PHY3_SOFT_RESETB_P1_MASK BIT(17)
 #define USB_CTRL_USB_DEVICE_CTL1       0x90
-#define   USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK      0x00000003 /* option */
+#define   USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK      GENMASK(1, 0) /* option */
 
 /* Register definitions for the XHCI EC block */
 #define USB_XHCI_EC_IRAADR 0x658
@@ -876,11 +876,11 @@ static void usb_init_common(struct brcm_usb_init_params *params)
                reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
                reg &= ~USB_CTRL_MASK_FAMILY(params, USB_DEVICE_CTL1,
                                        PORT_MODE);
-               reg |= params->mode;
+               reg |= params->port_mode;
                brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
        }
        if (USB_CTRL_MASK_FAMILY(params, USB_PM, BDC_SOFT_RESETB)) {
-               switch (params->mode) {
+               switch (params->supported_port_modes) {
                case USB_CTLR_MODE_HOST:
                        USB_CTRL_UNSET_FAMILY(params, USB_PM, BDC_SOFT_RESETB);
                        break;
@@ -891,7 +891,7 @@ static void usb_init_common(struct brcm_usb_init_params *params)
                }
        }
        if (USB_CTRL_MASK_FAMILY(params, SETUP, CC_DRD_MODE_ENABLE)) {
-               if (params->mode == USB_CTLR_MODE_TYPEC_PD)
+               if (params->supported_port_modes == USB_CTLR_MODE_TYPEC_PD)
                        USB_CTRL_SET_FAMILY(params, SETUP, CC_DRD_MODE_ENABLE);
                else
                        USB_CTRL_UNSET_FAMILY(params, SETUP,
@@ -1000,7 +1000,7 @@ static int usb_get_dual_select(struct brcm_usb_init_params *params)
        return reg;
 }
 
-static void usb_set_dual_select(struct brcm_usb_init_params *params, int mode)
+static void usb_set_dual_select(struct brcm_usb_init_params *params)
 {
        void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
        u32 reg;
@@ -1011,7 +1011,7 @@ static void usb_set_dual_select(struct brcm_usb_init_params *params, int mode)
                reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
                reg &= ~USB_CTRL_MASK_FAMILY(params, USB_DEVICE_CTL1,
                                        PORT_MODE);
-               reg |= mode;
+               reg |= params->port_mode;
                brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
        }
 }
index 1ccb5ddab865c362571fc70c6048e8a9b6109eee..f9fbf8fb80e54b236253fcfcd6440c0d1eeb14d3 100644 (file)
@@ -45,14 +45,15 @@ struct brcm_usb_init_ops {
        void (*uninit_eohci)(struct brcm_usb_init_params *params);
        void (*uninit_xhci)(struct brcm_usb_init_params *params);
        int  (*get_dual_select)(struct brcm_usb_init_params *params);
-       void (*set_dual_select)(struct brcm_usb_init_params *params, int mode);
+       void (*set_dual_select)(struct brcm_usb_init_params *params);
 };
 
 struct  brcm_usb_init_params {
        void __iomem *regs[BRCM_REGS_MAX];
        int ioc;
        int ipp;
-       int mode;
+       int supported_port_modes;
+       int port_mode;
        u32 family_id;
        u32 product_id;
        int selected_family;
@@ -61,7 +62,6 @@ struct  brcm_usb_init_params {
        const struct brcm_usb_init_ops *ops;
        struct regmap *syscon_piarbctl;
        bool wake_enabled;
-       bool suspend_with_clocks;
 };
 
 void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params);
@@ -153,11 +153,10 @@ static inline int brcm_usb_get_dual_select(struct brcm_usb_init_params *ini)
        return 0;
 }
 
-static inline void brcm_usb_set_dual_select(struct brcm_usb_init_params *ini,
-       int mode)
+static inline void brcm_usb_set_dual_select(struct brcm_usb_init_params *ini)
 {
        if (ini->ops->set_dual_select)
-               ini->ops->set_dual_select(ini, mode);
+               ini->ops->set_dual_select(ini);
 }
 
 #endif /* _USB_BRCM_COMMON_INIT_H */
index 2cb3779fcdf8246cadfae38be26114c5b29798b2..4de39999f43d39e4d2323e67cbab885dc50e78e4 100644 (file)
@@ -102,9 +102,9 @@ static int brcm_pm_notifier(struct notifier_block *notifier,
 
 static irqreturn_t brcm_usb_phy_wake_isr(int irq, void *dev_id)
 {
-       struct phy *gphy = dev_id;
+       struct device *dev = dev_id;
 
-       pm_wakeup_event(&gphy->dev, 0);
+       pm_wakeup_event(dev, 0);
 
        return IRQ_HANDLED;
 }
@@ -233,7 +233,7 @@ static ssize_t dr_mode_show(struct device *dev,
        return sprintf(buf, "%s\n",
                value_to_name(&brcm_dr_mode_to_name[0],
                              ARRAY_SIZE(brcm_dr_mode_to_name),
-                             priv->ini.mode));
+                             priv->ini.supported_port_modes));
 }
 static DEVICE_ATTR_RO(dr_mode);
 
@@ -249,7 +249,8 @@ static ssize_t dual_select_store(struct device *dev,
        res = name_to_value(&brcm_dual_mode_to_name[0],
                            ARRAY_SIZE(brcm_dual_mode_to_name), buf, &value);
        if (!res) {
-               brcm_usb_set_dual_select(&priv->ini, value);
+               priv->ini.port_mode = value;
+               brcm_usb_set_dual_select(&priv->ini);
                res = len;
        }
        mutex_unlock(&sysfs_lock);
@@ -445,13 +446,13 @@ static int brcm_usb_phy_dvr_init(struct platform_device *pdev,
                priv->suspend_clk = NULL;
        }
 
-       priv->wake_irq = platform_get_irq_byname(pdev, "wake");
+       priv->wake_irq = platform_get_irq_byname_optional(pdev, "wake");
        if (priv->wake_irq < 0)
-               priv->wake_irq = platform_get_irq_byname(pdev, "wakeup");
+               priv->wake_irq = platform_get_irq_byname_optional(pdev, "wakeup");
        if (priv->wake_irq >= 0) {
                err = devm_request_irq(dev, priv->wake_irq,
                                       brcm_usb_phy_wake_isr, 0,
-                                      dev_name(dev), gphy);
+                                      dev_name(dev), dev);
                if (err < 0)
                        return err;
                device_set_wakeup_capable(dev, 1);
@@ -495,13 +496,16 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
        of_property_read_u32(dn, "brcm,ipp", &priv->ini.ipp);
        of_property_read_u32(dn, "brcm,ioc", &priv->ini.ioc);
 
-       priv->ini.mode = USB_CTLR_MODE_HOST;
+       priv->ini.supported_port_modes = USB_CTLR_MODE_HOST;
        err = of_property_read_string(dn, "dr_mode", &mode);
        if (err == 0) {
                name_to_value(&brcm_dr_mode_to_name[0],
                              ARRAY_SIZE(brcm_dr_mode_to_name),
-                       mode, &priv->ini.mode);
+                       mode, &priv->ini.supported_port_modes);
        }
+       /* Default port_mode to supported port_modes */
+       priv->ini.port_mode = priv->ini.supported_port_modes;
+
        if (of_property_read_bool(dn, "brcm,has-xhci"))
                priv->has_xhci = true;
        if (of_property_read_bool(dn, "brcm,has-eohci"))
@@ -539,7 +543,7 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
         * Create sysfs entries for mode.
         * Remove "dual_select" attribute if not in dual mode
         */
-       if (priv->ini.mode != USB_CTLR_MODE_DRD)
+       if (priv->ini.supported_port_modes != USB_CTLR_MODE_DRD)
                brcm_usb_phy_attrs[1] = NULL;
        err = sysfs_create_group(&dev->kobj, &brcm_usb_phy_group);
        if (err)
@@ -598,7 +602,7 @@ static int brcm_usb_phy_suspend(struct device *dev)
                 * and newer XHCI->2.0-clks/3.0-clks.
                 */
 
-               if (!priv->ini.suspend_with_clocks) {
+               if (!priv->ini.wake_enabled) {
                        if (priv->phys[BRCM_USB_PHY_3_0].inited)
                                clk_disable_unprepare(priv->usb_30_clk);
                        if (priv->phys[BRCM_USB_PHY_2_0].inited ||
@@ -615,8 +619,10 @@ static int brcm_usb_phy_resume(struct device *dev)
 {
        struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
 
-       clk_prepare_enable(priv->usb_20_clk);
-       clk_prepare_enable(priv->usb_30_clk);
+       if (!priv->ini.wake_enabled) {
+               clk_prepare_enable(priv->usb_20_clk);
+               clk_prepare_enable(priv->usb_30_clk);
+       }
        brcm_usb_init_ipp(&priv->ini);
 
        /*
index c93286483b4259178a5d46ef0d73f708af564825..7585e8080b77d58247aa94f5020f2aa98bcc9c30 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx7-iomuxc-gpr.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #define IMX8MM_PCIE_PHY_CMN_REG065     0x194
 #define  ANA_AUX_RX_TERM               (BIT(7) | BIT(4))
 #define  ANA_AUX_TX_LVL                        GENMASK(3, 0)
-#define IMX8MM_PCIE_PHY_CMN_REG75      0x1D4
-#define  PCIE_PHY_CMN_REG75_PLL_DONE   0x3
+#define IMX8MM_PCIE_PHY_CMN_REG075     0x1D4
+#define  ANA_PLL_DONE                  0x3
 #define PCIE_PHY_TRSV_REG5             0x414
-#define  PCIE_PHY_TRSV_REG5_GEN1_DEEMP 0x2D
 #define PCIE_PHY_TRSV_REG6             0x418
-#define  PCIE_PHY_TRSV_REG6_GEN2_DEEMP 0xF
 
 #define IMX8MM_GPR_PCIE_REF_CLK_SEL    GENMASK(25, 24)
 #define IMX8MM_GPR_PCIE_REF_CLK_PLL    FIELD_PREP(IMX8MM_GPR_PCIE_REF_CLK_SEL, 0x3)
 #define IMX8MM_GPR_PCIE_SSC_EN         BIT(16)
 #define IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE        BIT(9)
 
+enum imx8_pcie_phy_type {
+       IMX8MM,
+       IMX8MP,
+};
+
+struct imx8_pcie_phy_drvdata {
+       const   char                    *gpr;
+       enum    imx8_pcie_phy_type      variant;
+};
+
 struct imx8_pcie_phy {
        void __iomem            *base;
        struct clk              *clk;
        struct phy              *phy;
        struct regmap           *iomuxc_gpr;
+       struct reset_control    *perst;
        struct reset_control    *reset;
        u32                     refclk_pad_mode;
        u32                     tx_deemph_gen1;
        u32                     tx_deemph_gen2;
        bool                    clkreq_unused;
+       const struct imx8_pcie_phy_drvdata      *drvdata;
 };
 
 static int imx8_pcie_phy_power_on(struct phy *phy)
@@ -65,34 +76,22 @@ static int imx8_pcie_phy_power_on(struct phy *phy)
        u32 val, pad_mode;
        struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy);
 
-       reset_control_assert(imx8_phy->reset);
-
        pad_mode = imx8_phy->refclk_pad_mode;
-       /* Set AUX_EN_OVERRIDE 1'b0, when the CLKREQ# isn't hooked */
-       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
-                          IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE,
-                          imx8_phy->clkreq_unused ?
-                          0 : IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE);
-       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
-                          IMX8MM_GPR_PCIE_AUX_EN,
-                          IMX8MM_GPR_PCIE_AUX_EN);
-       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
-                          IMX8MM_GPR_PCIE_POWER_OFF, 0);
-       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
-                          IMX8MM_GPR_PCIE_SSC_EN, 0);
-
-       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
-                          IMX8MM_GPR_PCIE_REF_CLK_SEL,
-                          pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT ?
-                          IMX8MM_GPR_PCIE_REF_CLK_EXT :
-                          IMX8MM_GPR_PCIE_REF_CLK_PLL);
-       usleep_range(100, 200);
-
-       /* Do the PHY common block reset */
-       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
-                          IMX8MM_GPR_PCIE_CMN_RST,
-                          IMX8MM_GPR_PCIE_CMN_RST);
-       usleep_range(200, 500);
+       switch (imx8_phy->drvdata->variant) {
+       case IMX8MM:
+               reset_control_assert(imx8_phy->reset);
+
+               /* Tune PHY de-emphasis setting to pass PCIe compliance. */
+               if (imx8_phy->tx_deemph_gen1)
+                       writel(imx8_phy->tx_deemph_gen1,
+                              imx8_phy->base + PCIE_PHY_TRSV_REG5);
+               if (imx8_phy->tx_deemph_gen2)
+                       writel(imx8_phy->tx_deemph_gen2,
+                              imx8_phy->base + PCIE_PHY_TRSV_REG6);
+               break;
+       case IMX8MP: /* Do nothing. */
+               break;
+       }
 
        if (pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT ||
            pad_mode == IMX8_PCIE_REFCLK_PAD_UNUSED) {
@@ -120,20 +119,44 @@ static int imx8_pcie_phy_power_on(struct phy *phy)
                       imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG065);
        }
 
-       /* Tune PHY de-emphasis setting to pass PCIe compliance. */
-       if (imx8_phy->tx_deemph_gen1)
-               writel(imx8_phy->tx_deemph_gen1,
-                      imx8_phy->base + PCIE_PHY_TRSV_REG5);
-       if (imx8_phy->tx_deemph_gen2)
-               writel(imx8_phy->tx_deemph_gen2,
-                      imx8_phy->base + PCIE_PHY_TRSV_REG6);
+       /* Set AUX_EN_OVERRIDE 1'b0, when the CLKREQ# isn't hooked */
+       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
+                          IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE,
+                          imx8_phy->clkreq_unused ?
+                          0 : IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE);
+       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
+                          IMX8MM_GPR_PCIE_AUX_EN,
+                          IMX8MM_GPR_PCIE_AUX_EN);
+       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
+                          IMX8MM_GPR_PCIE_POWER_OFF, 0);
+       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
+                          IMX8MM_GPR_PCIE_SSC_EN, 0);
+
+       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
+                          IMX8MM_GPR_PCIE_REF_CLK_SEL,
+                          pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT ?
+                          IMX8MM_GPR_PCIE_REF_CLK_EXT :
+                          IMX8MM_GPR_PCIE_REF_CLK_PLL);
+       usleep_range(100, 200);
+
+       /* Do the PHY common block reset */
+       regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
+                          IMX8MM_GPR_PCIE_CMN_RST,
+                          IMX8MM_GPR_PCIE_CMN_RST);
 
-       reset_control_deassert(imx8_phy->reset);
+       switch (imx8_phy->drvdata->variant) {
+       case IMX8MP:
+               reset_control_deassert(imx8_phy->perst);
+               fallthrough;
+       case IMX8MM:
+               reset_control_deassert(imx8_phy->reset);
+               usleep_range(200, 500);
+               break;
+       }
 
        /* Polling to check the phy is ready or not. */
-       ret = readl_poll_timeout(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG75,
-                                val, val == PCIE_PHY_CMN_REG75_PLL_DONE,
-                                10, 20000);
+       ret = readl_poll_timeout(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG075,
+                                val, val == ANA_PLL_DONE, 10, 20000);
        return ret;
 }
 
@@ -160,6 +183,23 @@ static const struct phy_ops imx8_pcie_phy_ops = {
        .owner          = THIS_MODULE,
 };
 
+static const struct imx8_pcie_phy_drvdata imx8mm_drvdata = {
+       .gpr = "fsl,imx8mm-iomuxc-gpr",
+       .variant = IMX8MM,
+};
+
+static const struct imx8_pcie_phy_drvdata imx8mp_drvdata = {
+       .gpr = "fsl,imx8mp-iomuxc-gpr",
+       .variant = IMX8MP,
+};
+
+static const struct of_device_id imx8_pcie_phy_of_match[] = {
+       {.compatible = "fsl,imx8mm-pcie-phy", .data = &imx8mm_drvdata, },
+       {.compatible = "fsl,imx8mp-pcie-phy", .data = &imx8mp_drvdata, },
+       { },
+};
+MODULE_DEVICE_TABLE(of, imx8_pcie_phy_of_match);
+
 static int imx8_pcie_phy_probe(struct platform_device *pdev)
 {
        struct phy_provider *phy_provider;
@@ -172,6 +212,8 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
        if (!imx8_phy)
                return -ENOMEM;
 
+       imx8_phy->drvdata = of_device_get_match_data(dev);
+
        /* get PHY refclk pad mode */
        of_property_read_u32(np, "fsl,refclk-pad-mode",
                             &imx8_phy->refclk_pad_mode);
@@ -197,7 +239,7 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
 
        /* Grab GPR config register range */
        imx8_phy->iomuxc_gpr =
-                syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+                syscon_regmap_lookup_by_compatible(imx8_phy->drvdata->gpr);
        if (IS_ERR(imx8_phy->iomuxc_gpr)) {
                dev_err(dev, "unable to find iomuxc registers\n");
                return PTR_ERR(imx8_phy->iomuxc_gpr);
@@ -209,6 +251,14 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
                return PTR_ERR(imx8_phy->reset);
        }
 
+       if (imx8_phy->drvdata->variant == IMX8MP) {
+               imx8_phy->perst =
+                       devm_reset_control_get_exclusive(dev, "perst");
+               if (IS_ERR(imx8_phy->perst))
+                       dev_err_probe(dev, PTR_ERR(imx8_phy->perst),
+                                     "Failed to get PCIE PHY PERST control\n");
+       }
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        imx8_phy->base = devm_ioremap_resource(dev, res);
        if (IS_ERR(imx8_phy->base))
@@ -225,12 +275,6 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
        return PTR_ERR_OR_ZERO(phy_provider);
 }
 
-static const struct of_device_id imx8_pcie_phy_of_match[] = {
-       {.compatible = "fsl,imx8mm-pcie-phy",},
-       { },
-};
-MODULE_DEVICE_TABLE(of, imx8_pcie_phy_of_match);
-
 static struct platform_driver imx8_pcie_phy_driver = {
        .probe  = imx8_pcie_phy_probe,
        .driver = {
index 7cccf01848d8d5657c8ae809348b1a0859f99473..f2537fdcc3ab4dfebf62e830e58cc4f0094ea0b8 100644 (file)
@@ -41,12 +41,10 @@ static int mmp3_hsic_phy_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct phy_provider *provider;
-       struct resource *resource;
        void __iomem *base;
        struct phy *phy;
 
-       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(dev, resource);
+       base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
index 67712c77d806f2658e87ebd80fbe701c2463989a..d641b345afa35cf8392fb335c8214749a4efbf07 100644 (file)
@@ -826,6 +826,9 @@ mvebu_a3700_comphy_usb3_power_on(struct mvebu_a3700_comphy_lane *lane)
        if (ret)
                return ret;
 
+       /* COMPHY register reset (cleared automatically) */
+       comphy_lane_reg_set(lane, COMPHY_SFT_RESET, SFT_RST, SFT_RST);
+
        /*
         * 0. Set PHY OTG Control(0x5d034), bit 4, Power up OTG module The
         * register belong to UTMI module, so it is set in UTMI phy driver.
index 5c98850f5a360a38c48598f7d6b9093d2888da18..eb9ddc685b3852cd26d1df17889fed94e0d33fba 100644 (file)
@@ -54,6 +54,7 @@ config PHY_QCOM_QMP
        tristate "Qualcomm QMP PHY Driver"
        depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST)
        select GENERIC_PHY
+       select MFD_SYSCON
        help
          Enable this to support the QMP PHY transceiver that is used
          with controllers such as PCIe, UFS, and USB on Qualcomm chips.
index ba9d761ec49a75b39f12d183a9a94fc7b16e3834..77052c66cf70bc3f586bec526553b3c5a55c2fef 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/reset.h>
 #include <linux/slab.h>
 
-#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/phy/phy-qcom-qmp.h>
 
 #include "phy-qcom-qmp.h"
 
 #define CLAMP_EN                               BIT(0) /* enables i/o clamp_n */
 
 #define PHY_INIT_COMPLETE_TIMEOUT              10000
-#define POWER_DOWN_DELAY_US_MIN                        10
-#define POWER_DOWN_DELAY_US_MAX                        11
 
 struct qmp_phy_init_tbl {
        unsigned int offset;
        unsigned int val;
-       /*
-        * register part of layout ?
-        * if yes, then offset gives index in the reg-layout
-        */
-       bool in_layout;
        /*
         * mask of lanes for which this register is written
         * for cases when second lane needs different values
@@ -88,14 +81,6 @@ struct qmp_phy_init_tbl {
                .lane_mask = 0xff,      \
        }
 
-#define QMP_PHY_INIT_CFG_L(o, v)       \
-       {                               \
-               .offset = o,            \
-               .val = v,               \
-               .in_layout = true,      \
-               .lane_mask = 0xff,      \
-       }
-
 #define QMP_PHY_INIT_CFG_LANE(o, v, l) \
        {                               \
                .offset = o,            \
@@ -121,6 +106,7 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
        [QPHY_SW_RESET]                 = 0x00,
        [QPHY_START_CTRL]               = 0x08,
        [QPHY_PCS_STATUS]               = 0x174,
+       [QPHY_PCS_POWER_DOWN_CONTROL]   = 0x04,
        [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d8,
        [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR]  = 0x0dc,
        [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
@@ -810,13 +796,24 @@ static const u8 qmp_dp_v5_voltage_swing_hbr_rbr[4][4] = {
        { 0x3f, 0xff, 0xff, 0xff }
 };
 
-struct qmp_phy;
+struct qmp_combo;
+
+struct qmp_combo_offsets {
+       u16 com;
+       u16 txa;
+       u16 rxa;
+       u16 txb;
+       u16 rxb;
+       u16 usb3_serdes;
+       u16 usb3_pcs_misc;
+       u16 usb3_pcs;
+       u16 usb3_pcs_usb;
+       u16 dp_serdes;
+       u16 dp_dp_phy;
+};
 
-/* struct qmp_phy_cfg - per-PHY initialization config */
 struct qmp_phy_cfg {
-       /* phy-type - PCIE/UFS/USB */
-       unsigned int type;
-       int lanes;
+       const struct qmp_combo_offsets *offsets;
 
        /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
        const struct qmp_phy_init_tbl *serdes_tbl;
@@ -830,6 +827,11 @@ struct qmp_phy_cfg {
        const struct qmp_phy_init_tbl *pcs_usb_tbl;
        int pcs_usb_tbl_num;
 
+       const struct qmp_phy_init_tbl *dp_serdes_tbl;
+       int dp_serdes_tbl_num;
+       const struct qmp_phy_init_tbl *dp_tx_tbl;
+       int dp_tx_tbl_num;
+
        /* Init sequence for DP PHY block link rates */
        const struct qmp_phy_init_tbl *serdes_tbl_rbr;
        int serdes_tbl_rbr_num;
@@ -847,10 +849,10 @@ struct qmp_phy_cfg {
        const u8 (*pre_emphasis_hbr3_hbr2)[4][4];
 
        /* DP PHY callbacks */
-       int (*configure_dp_phy)(struct qmp_phy *qphy);
-       void (*configure_dp_tx)(struct qmp_phy *qphy);
-       int (*calibrate_dp_phy)(struct qmp_phy *qphy);
-       void (*dp_aux_init)(struct qmp_phy *qphy);
+       int (*configure_dp_phy)(struct qmp_combo *qmp);
+       void (*configure_dp_tx)(struct qmp_combo *qmp);
+       int (*calibrate_dp_phy)(struct qmp_combo *qmp);
+       void (*dp_aux_init)(struct qmp_combo *qmp);
 
        /* clock ids to be requested */
        const char * const *clk_list;
@@ -865,50 +867,21 @@ struct qmp_phy_cfg {
        /* array of registers with different offsets */
        const unsigned int *regs;
 
-       unsigned int start_ctrl;
-       unsigned int pwrdn_ctrl;
-       /* bit offset of PHYSTATUS in QPHY_PCS_STATUS register */
-       unsigned int phy_status;
-
        /* true, if PHY needs delay after POWER_DOWN */
        bool has_pwrdn_delay;
-       /* power_down delay in usec */
-       int pwrdn_delay_min;
-       int pwrdn_delay_max;
 
        /* Offset from PCS to PCS_USB region */
        unsigned int pcs_usb_offset;
 
 };
 
-struct qmp_phy_combo_cfg {
-       const struct qmp_phy_cfg *usb_cfg;
-       const struct qmp_phy_cfg *dp_cfg;
-};
+struct qmp_combo {
+       struct device *dev;
 
-/**
- * struct qmp_phy - per-lane phy descriptor
- *
- * @phy: generic phy
- * @cfg: phy specific configuration
- * @serdes: iomapped memory space for phy's serdes (i.e. PLL)
- * @tx: iomapped memory space for lane's tx
- * @rx: iomapped memory space for lane's rx
- * @pcs: iomapped memory space for lane's pcs
- * @tx2: iomapped memory space for second lane's tx (in dual lane PHYs)
- * @rx2: iomapped memory space for second lane's rx (in dual lane PHYs)
- * @pcs_misc: iomapped memory space for lane's pcs_misc
- * @pcs_usb: iomapped memory space for lane's pcs_usb
- * @pipe_clk: pipe clock
- * @qmp: QMP phy to which this lane belongs
- * @mode: current PHY mode
- * @dp_aux_cfg: Display port aux config
- * @dp_opts: Display port optional config
- * @dp_clks: Display port clocks
- */
-struct qmp_phy {
-       struct phy *phy;
        const struct qmp_phy_cfg *cfg;
+
+       void __iomem *com;
+
        void __iomem *serdes;
        void __iomem *tx;
        void __iomem *rx;
@@ -917,62 +890,43 @@ struct qmp_phy {
        void __iomem *rx2;
        void __iomem *pcs_misc;
        void __iomem *pcs_usb;
-       struct clk *pipe_clk;
-       struct qcom_qmp *qmp;
-       enum phy_mode mode;
-       unsigned int dp_aux_cfg;
-       struct phy_configure_opts_dp dp_opts;
-       struct qmp_phy_dp_clks *dp_clks;
-};
 
-struct qmp_phy_dp_clks {
-       struct qmp_phy *qphy;
-       struct clk_hw dp_link_hw;
-       struct clk_hw dp_pixel_hw;
-};
-
-/**
- * struct qcom_qmp - structure holding QMP phy block attributes
- *
- * @dev: device
- * @dp_com: iomapped memory space for phy's dp_com control block
- *
- * @clks: array of clocks required by phy
- * @resets: array of resets required by phy
- * @vregs: regulator supplies bulk data
- *
- * @phys: array of per-lane phy descriptors
- * @phy_mutex: mutex lock for PHY common block initialization
- * @init_count: phy common block initialization count
- * @ufs_reset: optional UFS PHY reset handle
- */
-struct qcom_qmp {
-       struct device *dev;
-       void __iomem *dp_com;
+       void __iomem *dp_serdes;
+       void __iomem *dp_tx;
+       void __iomem *dp_tx2;
+       void __iomem *dp_dp_phy;
 
+       struct clk *pipe_clk;
        struct clk_bulk_data *clks;
        struct reset_control_bulk_data *resets;
        struct regulator_bulk_data *vregs;
 
-       struct qmp_phy **phys;
-
        struct mutex phy_mutex;
        int init_count;
 
-       struct reset_control *ufs_reset;
+       struct phy *usb_phy;
+       enum phy_mode mode;
+
+       struct phy *dp_phy;
+       unsigned int dp_aux_cfg;
+       struct phy_configure_opts_dp dp_opts;
+
+       struct clk_fixed_rate pipe_clk_fixed;
+       struct clk_hw dp_link_hw;
+       struct clk_hw dp_pixel_hw;
 };
 
-static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy);
-static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy);
-static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy);
-static int qcom_qmp_v3_dp_phy_calibrate(struct qmp_phy *qphy);
+static void qmp_v3_dp_aux_init(struct qmp_combo *qmp);
+static void qmp_v3_configure_dp_tx(struct qmp_combo *qmp);
+static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp);
+static int qmp_v3_calibrate_dp_phy(struct qmp_combo *qmp);
 
-static void qcom_qmp_v4_phy_dp_aux_init(struct qmp_phy *qphy);
-static void qcom_qmp_v4_phy_configure_dp_tx(struct qmp_phy *qphy);
-static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy);
-static int qcom_qmp_v4_dp_phy_calibrate(struct qmp_phy *qphy);
+static void qmp_v4_dp_aux_init(struct qmp_combo *qmp);
+static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp);
+static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp);
+static int qmp_v4_calibrate_dp_phy(struct qmp_combo *qmp);
 
-static int qcom_qmp_v5_phy_configure_dp_phy(struct qmp_phy *qphy);
+static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp);
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
 {
@@ -1004,7 +958,7 @@ static const char * const qmp_v3_phy_clk_l[] = {
 };
 
 static const char * const qmp_v4_phy_clk_l[] = {
-       "aux", "ref_clk_src", "ref", "com_aux",
+       "aux", "ref", "com_aux",
 };
 
 /* the primary usb3 phy on sm8250 doesn't have a ref clock */
@@ -1021,10 +975,21 @@ static const char * const sc7180_usb3phy_reset_l[] = {
        "phy",
 };
 
-static const struct qmp_phy_cfg sc7180_usb3phy_cfg = {
-       .type                   = PHY_TYPE_USB3,
-       .lanes                  = 2,
+static const struct qmp_combo_offsets qmp_combo_offsets_v5 = {
+       .com            = 0x0000,
+       .txa            = 0x0400,
+       .rxa            = 0x0600,
+       .txb            = 0x0a00,
+       .rxb            = 0x0c00,
+       .usb3_serdes    = 0x1000,
+       .usb3_pcs_misc  = 0x1200,
+       .usb3_pcs       = 0x1400,
+       .usb3_pcs_usb   = 0x1700,
+       .dp_serdes      = 0x2000,
+       .dp_dp_phy      = 0x2200,
+};
 
+static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = {
        .serdes_tbl             = qmp_v3_usb3_serdes_tbl,
        .serdes_tbl_num         = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl),
        .tx_tbl                 = qmp_v3_usb3_tx_tbl,
@@ -1033,31 +998,11 @@ static const struct qmp_phy_cfg sc7180_usb3phy_cfg = {
        .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,
-       .phy_status             = PHYSTATUS,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
-};
 
-static const struct qmp_phy_cfg sc7180_dpphy_cfg = {
-       .type                   = PHY_TYPE_DP,
-       .lanes                  = 2,
-
-       .serdes_tbl             = qmp_v3_dp_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(qmp_v3_dp_serdes_tbl),
-       .tx_tbl                 = qmp_v3_dp_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(qmp_v3_dp_tx_tbl),
+       .dp_serdes_tbl          = qmp_v3_dp_serdes_tbl,
+       .dp_serdes_tbl_num      = ARRAY_SIZE(qmp_v3_dp_serdes_tbl),
+       .dp_tx_tbl              = qmp_v3_dp_tx_tbl,
+       .dp_tx_tbl_num          = ARRAY_SIZE(qmp_v3_dp_tx_tbl),
 
        .serdes_tbl_rbr         = qmp_v3_dp_serdes_tbl_rbr,
        .serdes_tbl_rbr_num     = ARRAY_SIZE(qmp_v3_dp_serdes_tbl_rbr),
@@ -1073,6 +1018,11 @@ static const struct qmp_phy_cfg sc7180_dpphy_cfg = {
        .swing_hbr3_hbr2        = &qmp_dp_v3_voltage_swing_hbr3_hbr2,
        .pre_emphasis_hbr3_hbr2 = &qmp_dp_v3_pre_emphasis_hbr3_hbr2,
 
+       .dp_aux_init            = qmp_v3_dp_aux_init,
+       .configure_dp_tx        = qmp_v3_configure_dp_tx,
+       .configure_dp_phy       = qmp_v3_configure_dp_phy,
+       .calibrate_dp_phy       = qmp_v3_calibrate_dp_phy,
+
        .clk_list               = qmp_v3_phy_clk_l,
        .num_clks               = ARRAY_SIZE(qmp_v3_phy_clk_l),
        .reset_list             = sc7180_usb3phy_reset_l,
@@ -1081,21 +1031,10 @@ static const struct qmp_phy_cfg sc7180_dpphy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = qmp_v3_usb3phy_regs_layout,
 
-       .dp_aux_init = qcom_qmp_v3_phy_dp_aux_init,
-       .configure_dp_tx = qcom_qmp_v3_phy_configure_dp_tx,
-       .configure_dp_phy = qcom_qmp_v3_phy_configure_dp_phy,
-       .calibrate_dp_phy = qcom_qmp_v3_dp_phy_calibrate,
-};
-
-static const struct qmp_phy_combo_cfg sc7180_usb3dpphy_cfg = {
-       .usb_cfg                = &sc7180_usb3phy_cfg,
-       .dp_cfg                 = &sc7180_dpphy_cfg,
+       .has_pwrdn_delay        = true,
 };
 
-static const struct qmp_phy_cfg sdm845_usb3phy_cfg = {
-       .type                   = PHY_TYPE_USB3,
-       .lanes                  = 2,
-
+static const struct qmp_phy_cfg sdm845_usb3dpphy_cfg = {
        .serdes_tbl             = qmp_v3_usb3_serdes_tbl,
        .serdes_tbl_num         = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl),
        .tx_tbl                 = qmp_v3_usb3_tx_tbl,
@@ -1104,6 +1043,31 @@ static const struct qmp_phy_cfg sdm845_usb3phy_cfg = {
        .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),
+
+       .dp_serdes_tbl          = qmp_v3_dp_serdes_tbl,
+       .dp_serdes_tbl_num      = ARRAY_SIZE(qmp_v3_dp_serdes_tbl),
+       .dp_tx_tbl              = qmp_v3_dp_tx_tbl,
+       .dp_tx_tbl_num          = ARRAY_SIZE(qmp_v3_dp_tx_tbl),
+
+       .serdes_tbl_rbr         = qmp_v3_dp_serdes_tbl_rbr,
+       .serdes_tbl_rbr_num     = ARRAY_SIZE(qmp_v3_dp_serdes_tbl_rbr),
+       .serdes_tbl_hbr         = qmp_v3_dp_serdes_tbl_hbr,
+       .serdes_tbl_hbr_num     = ARRAY_SIZE(qmp_v3_dp_serdes_tbl_hbr),
+       .serdes_tbl_hbr2        = qmp_v3_dp_serdes_tbl_hbr2,
+       .serdes_tbl_hbr2_num    = ARRAY_SIZE(qmp_v3_dp_serdes_tbl_hbr2),
+       .serdes_tbl_hbr3        = qmp_v3_dp_serdes_tbl_hbr3,
+       .serdes_tbl_hbr3_num    = ARRAY_SIZE(qmp_v3_dp_serdes_tbl_hbr3),
+
+       .swing_hbr_rbr          = &qmp_dp_v3_voltage_swing_hbr_rbr,
+       .pre_emphasis_hbr_rbr   = &qmp_dp_v3_pre_emphasis_hbr_rbr,
+       .swing_hbr3_hbr2        = &qmp_dp_v3_voltage_swing_hbr3_hbr2,
+       .pre_emphasis_hbr3_hbr2 = &qmp_dp_v3_pre_emphasis_hbr3_hbr2,
+
+       .dp_aux_init            = qmp_v3_dp_aux_init,
+       .configure_dp_tx        = qmp_v3_configure_dp_tx,
+       .configure_dp_phy       = qmp_v3_configure_dp_phy,
+       .calibrate_dp_phy       = qmp_v3_calibrate_dp_phy,
+
        .clk_list               = qmp_v3_phy_clk_l,
        .num_clks               = ARRAY_SIZE(qmp_v3_phy_clk_l),
        .reset_list             = msm8996_usb3phy_reset_l,
@@ -1112,24 +1076,10 @@ static const struct qmp_phy_cfg sdm845_usb3phy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = qmp_v3_usb3phy_regs_layout,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
 };
 
-static const struct qmp_phy_combo_cfg sdm845_usb3dpphy_cfg = {
-       .usb_cfg                = &sdm845_usb3phy_cfg,
-       .dp_cfg                 = &sc7180_dpphy_cfg,
-};
-
-static const struct qmp_phy_cfg sm8150_usb3phy_cfg = {
-       .type                   = PHY_TYPE_USB3,
-       .lanes                  = 2,
-
+static const struct qmp_phy_cfg sc8180x_usb3dpphy_cfg = {
        .serdes_tbl             = sm8150_usb3_serdes_tbl,
        .serdes_tbl_num         = ARRAY_SIZE(sm8150_usb3_serdes_tbl),
        .tx_tbl                 = sm8150_usb3_tx_tbl,
@@ -1140,33 +1090,11 @@ static const struct qmp_phy_cfg sm8150_usb3phy_cfg = {
        .pcs_tbl_num            = ARRAY_SIZE(sm8150_usb3_pcs_tbl),
        .pcs_usb_tbl            = sm8150_usb3_pcs_usb_tbl,
        .pcs_usb_tbl_num        = ARRAY_SIZE(sm8150_usb3_pcs_usb_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,
-       .pcs_usb_offset         = 0x300,
-
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
 
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
-};
-
-static const struct qmp_phy_cfg sc8180x_dpphy_cfg = {
-       .type                   = PHY_TYPE_DP,
-       .lanes                  = 2,
-
-       .serdes_tbl             = qmp_v4_dp_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(qmp_v4_dp_serdes_tbl),
-       .tx_tbl                 = qmp_v4_dp_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(qmp_v4_dp_tx_tbl),
+       .dp_serdes_tbl          = qmp_v4_dp_serdes_tbl,
+       .dp_serdes_tbl_num      = ARRAY_SIZE(qmp_v4_dp_serdes_tbl),
+       .dp_tx_tbl              = qmp_v4_dp_tx_tbl,
+       .dp_tx_tbl_num          = ARRAY_SIZE(qmp_v4_dp_tx_tbl),
 
        .serdes_tbl_rbr         = qmp_v4_dp_serdes_tbl_rbr,
        .serdes_tbl_rbr_num     = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_rbr),
@@ -1182,28 +1110,25 @@ static const struct qmp_phy_cfg sc8180x_dpphy_cfg = {
        .swing_hbr3_hbr2        = &qmp_dp_v3_voltage_swing_hbr3_hbr2,
        .pre_emphasis_hbr3_hbr2 = &qmp_dp_v3_pre_emphasis_hbr3_hbr2,
 
-       .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),
+       .dp_aux_init            = qmp_v4_dp_aux_init,
+       .configure_dp_tx        = qmp_v4_configure_dp_tx,
+       .configure_dp_phy       = qmp_v4_configure_dp_phy,
+       .calibrate_dp_phy       = qmp_v4_calibrate_dp_phy,
+
+       .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_v3_usb3phy_regs_layout,
-
-       .dp_aux_init = qcom_qmp_v4_phy_dp_aux_init,
-       .configure_dp_tx = qcom_qmp_v4_phy_configure_dp_tx,
-       .configure_dp_phy = qcom_qmp_v4_phy_configure_dp_phy,
-       .calibrate_dp_phy = qcom_qmp_v4_dp_phy_calibrate,
-};
+       .regs                   = qmp_v4_usb3phy_regs_layout,
+       .pcs_usb_offset         = 0x300,
 
-static const struct qmp_phy_combo_cfg sc8180x_usb3dpphy_cfg = {
-       .usb_cfg                = &sm8150_usb3phy_cfg,
-       .dp_cfg                 = &sc8180x_dpphy_cfg,
+       .has_pwrdn_delay        = true,
 };
 
-static const struct qmp_phy_cfg sc8280xp_usb43dp_usb_cfg = {
-       .type                   = PHY_TYPE_USB3,
-       .lanes                  = 2,
+static const struct qmp_phy_cfg sc8280xp_usb43dpphy_cfg = {
+       .offsets                = &qmp_combo_offsets_v5,
 
        .serdes_tbl             = sc8280xp_usb43dp_serdes_tbl,
        .serdes_tbl_num         = ARRAY_SIZE(sc8280xp_usb43dp_serdes_tbl),
@@ -1213,32 +1138,11 @@ static const struct qmp_phy_cfg sc8280xp_usb43dp_usb_cfg = {
        .rx_tbl_num             = ARRAY_SIZE(sc8280xp_usb43dp_rx_tbl),
        .pcs_tbl                = sc8280xp_usb43dp_pcs_tbl,
        .pcs_tbl_num            = ARRAY_SIZE(sc8280xp_usb43dp_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,
-       .pcs_usb_offset         = 0x300,
-
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
-};
-
-static const struct qmp_phy_cfg sc8280xp_usb43dp_dp_cfg = {
-       .type                   = PHY_TYPE_DP,
-       .lanes                  = 2,
 
-       .serdes_tbl             = qmp_v5_dp_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(qmp_v5_dp_serdes_tbl),
-       .tx_tbl                 = qmp_v5_5nm_dp_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(qmp_v5_5nm_dp_tx_tbl),
+       .dp_serdes_tbl          = qmp_v5_dp_serdes_tbl,
+       .dp_serdes_tbl_num      = ARRAY_SIZE(qmp_v5_dp_serdes_tbl),
+       .dp_tx_tbl              = qmp_v5_5nm_dp_tx_tbl,
+       .dp_tx_tbl_num          = ARRAY_SIZE(qmp_v5_5nm_dp_tx_tbl),
 
        .serdes_tbl_rbr         = qmp_v4_dp_serdes_tbl_rbr,
        .serdes_tbl_rbr_num     = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_rbr),
@@ -1254,6 +1158,11 @@ static const struct qmp_phy_cfg sc8280xp_usb43dp_dp_cfg = {
        .swing_hbr3_hbr2        = &qmp_dp_v5_voltage_swing_hbr3_hbr2,
        .pre_emphasis_hbr3_hbr2 = &qmp_dp_v5_pre_emphasis_hbr3_hbr2,
 
+       .dp_aux_init            = qmp_v4_dp_aux_init,
+       .configure_dp_tx        = qmp_v4_configure_dp_tx,
+       .configure_dp_phy       = qmp_v5_configure_dp_phy,
+       .calibrate_dp_phy       = qmp_v4_calibrate_dp_phy,
+
        .clk_list               = qmp_v4_phy_clk_l,
        .num_clks               = ARRAY_SIZE(qmp_v4_phy_clk_l),
        .reset_list             = msm8996_usb3phy_reset_l,
@@ -1261,22 +1170,9 @@ static const struct qmp_phy_cfg sc8280xp_usb43dp_dp_cfg = {
        .vreg_list              = qmp_phy_vreg_l,
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = qmp_v4_usb3phy_regs_layout,
-
-       .dp_aux_init = qcom_qmp_v4_phy_dp_aux_init,
-       .configure_dp_tx = qcom_qmp_v4_phy_configure_dp_tx,
-       .configure_dp_phy = qcom_qmp_v5_phy_configure_dp_phy,
-       .calibrate_dp_phy = qcom_qmp_v4_dp_phy_calibrate,
-};
-
-static const struct qmp_phy_combo_cfg sc8280xp_usb43dpphy_combo_cfg = {
-       .usb_cfg                = &sc8280xp_usb43dp_usb_cfg,
-       .dp_cfg                 = &sc8280xp_usb43dp_dp_cfg,
 };
 
-static const struct qmp_phy_cfg sm8250_usb3phy_cfg = {
-       .type                   = PHY_TYPE_USB3,
-       .lanes                  = 2,
-
+static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = {
        .serdes_tbl             = sm8150_usb3_serdes_tbl,
        .serdes_tbl_num         = ARRAY_SIZE(sm8150_usb3_serdes_tbl),
        .tx_tbl                 = sm8250_usb3_tx_tbl,
@@ -1287,32 +1183,11 @@ static const struct qmp_phy_cfg sm8250_usb3phy_cfg = {
        .pcs_tbl_num            = ARRAY_SIZE(sm8250_usb3_pcs_tbl),
        .pcs_usb_tbl            = sm8250_usb3_pcs_usb_tbl,
        .pcs_usb_tbl_num        = ARRAY_SIZE(sm8250_usb3_pcs_usb_tbl),
-       .clk_list               = qmp_v4_sm8250_usbphy_clk_l,
-       .num_clks               = ARRAY_SIZE(qmp_v4_sm8250_usbphy_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,
-       .pcs_usb_offset         = 0x300,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
-};
-
-static const struct qmp_phy_cfg sm8250_dpphy_cfg = {
-       .type                   = PHY_TYPE_DP,
-       .lanes                  = 2,
-
-       .serdes_tbl             = qmp_v4_dp_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(qmp_v4_dp_serdes_tbl),
-       .tx_tbl                 = qmp_v4_dp_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(qmp_v4_dp_tx_tbl),
+       .dp_serdes_tbl          = qmp_v4_dp_serdes_tbl,
+       .dp_serdes_tbl_num      = ARRAY_SIZE(qmp_v4_dp_serdes_tbl),
+       .dp_tx_tbl              = qmp_v4_dp_tx_tbl,
+       .dp_tx_tbl_num          = ARRAY_SIZE(qmp_v4_dp_tx_tbl),
 
        .serdes_tbl_rbr         = qmp_v4_dp_serdes_tbl_rbr,
        .serdes_tbl_rbr_num     = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_rbr),
@@ -1328,27 +1203,24 @@ static const struct qmp_phy_cfg sm8250_dpphy_cfg = {
        .swing_hbr3_hbr2        = &qmp_dp_v3_voltage_swing_hbr3_hbr2,
        .pre_emphasis_hbr3_hbr2 = &qmp_dp_v3_pre_emphasis_hbr3_hbr2,
 
-       .clk_list               = qmp_v4_phy_clk_l,
-       .num_clks               = ARRAY_SIZE(qmp_v4_phy_clk_l),
+       .dp_aux_init            = qmp_v4_dp_aux_init,
+       .configure_dp_tx        = qmp_v4_configure_dp_tx,
+       .configure_dp_phy       = qmp_v4_configure_dp_phy,
+       .calibrate_dp_phy       = qmp_v4_calibrate_dp_phy,
+
+       .clk_list               = qmp_v4_sm8250_usbphy_clk_l,
+       .num_clks               = ARRAY_SIZE(qmp_v4_sm8250_usbphy_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,
+       .pcs_usb_offset         = 0x300,
 
-       .dp_aux_init = qcom_qmp_v4_phy_dp_aux_init,
-       .configure_dp_tx = qcom_qmp_v4_phy_configure_dp_tx,
-       .configure_dp_phy = qcom_qmp_v4_phy_configure_dp_phy,
-       .calibrate_dp_phy = qcom_qmp_v4_dp_phy_calibrate,
-};
-
-static const struct qmp_phy_combo_cfg sm8250_usb3dpphy_cfg = {
-       .usb_cfg                = &sm8250_usb3phy_cfg,
-       .dp_cfg                 = &sm8250_dpphy_cfg,
+       .has_pwrdn_delay        = true,
 };
 
 static void qmp_combo_configure_lane(void __iomem *base,
-                                       const unsigned int *regs,
                                        const struct qmp_phy_init_tbl tbl[],
                                        int num,
                                        u8 lane_mask)
@@ -1363,110 +1235,98 @@ static void qmp_combo_configure_lane(void __iomem *base,
                if (!(t->lane_mask & lane_mask))
                        continue;
 
-               if (t->in_layout)
-                       writel(t->val, base + regs[t->offset]);
-               else
-                       writel(t->val, base + t->offset);
+               writel(t->val, base + t->offset);
        }
 }
 
 static void qmp_combo_configure(void __iomem *base,
-                                  const unsigned int *regs,
                                   const struct qmp_phy_init_tbl tbl[],
                                   int num)
 {
-       qmp_combo_configure_lane(base, regs, tbl, num, 0xff);
+       qmp_combo_configure_lane(base, tbl, num, 0xff);
 }
 
-static int qmp_combo_serdes_init(struct qmp_phy *qphy)
+static int qmp_combo_dp_serdes_init(struct qmp_combo *qmp)
 {
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *serdes = qphy->serdes;
-       const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
-       const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl;
-       int serdes_tbl_num = cfg->serdes_tbl_num;
-
-       qmp_combo_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num);
-
-       if (cfg->type == PHY_TYPE_DP) {
-               switch (dp_opts->link_rate) {
-               case 1620:
-                       qmp_combo_configure(serdes, cfg->regs,
-                                              cfg->serdes_tbl_rbr,
-                                              cfg->serdes_tbl_rbr_num);
-                       break;
-               case 2700:
-                       qmp_combo_configure(serdes, cfg->regs,
-                                              cfg->serdes_tbl_hbr,
-                                              cfg->serdes_tbl_hbr_num);
-                       break;
-               case 5400:
-                       qmp_combo_configure(serdes, cfg->regs,
-                                              cfg->serdes_tbl_hbr2,
-                                              cfg->serdes_tbl_hbr2_num);
-                       break;
-               case 8100:
-                       qmp_combo_configure(serdes, cfg->regs,
-                                              cfg->serdes_tbl_hbr3,
-                                              cfg->serdes_tbl_hbr3_num);
-                       break;
-               default:
-                       /* Other link rates aren't supported */
-                       return -EINVAL;
-               }
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *serdes = qmp->dp_serdes;
+       const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+
+       qmp_combo_configure(serdes, cfg->dp_serdes_tbl, cfg->dp_serdes_tbl_num);
+
+       switch (dp_opts->link_rate) {
+       case 1620:
+               qmp_combo_configure(serdes, cfg->serdes_tbl_rbr,
+                               cfg->serdes_tbl_rbr_num);
+               break;
+       case 2700:
+               qmp_combo_configure(serdes, cfg->serdes_tbl_hbr,
+                               cfg->serdes_tbl_hbr_num);
+               break;
+       case 5400:
+               qmp_combo_configure(serdes, cfg->serdes_tbl_hbr2,
+                               cfg->serdes_tbl_hbr2_num);
+               break;
+       case 8100:
+               qmp_combo_configure(serdes, cfg->serdes_tbl_hbr3,
+                               cfg->serdes_tbl_hbr3_num);
+               break;
+       default:
+               /* Other link rates aren't supported */
+               return -EINVAL;
        }
 
        return 0;
 }
 
-static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy)
+static void qmp_v3_dp_aux_init(struct qmp_combo *qmp)
 {
        writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
               DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
-              qphy->pcs + QSERDES_DP_PHY_PD_CTL);
+              qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
 
        /* Turn on BIAS current for PHY/PLL */
        writel(QSERDES_V3_COM_BIAS_EN | QSERDES_V3_COM_BIAS_EN_MUX |
               QSERDES_V3_COM_CLKBUF_L_EN | QSERDES_V3_COM_EN_SYSCLK_TX_SEL,
-              qphy->serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN);
+              qmp->dp_serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN);
 
-       writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_DP_PHY_PD_CTL);
+       writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
 
        writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
               DP_PHY_PD_CTL_LANE_0_1_PWRDN |
               DP_PHY_PD_CTL_LANE_2_3_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN |
               DP_PHY_PD_CTL_DP_CLAMP_EN,
-              qphy->pcs + QSERDES_DP_PHY_PD_CTL);
+              qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
 
        writel(QSERDES_V3_COM_BIAS_EN |
               QSERDES_V3_COM_BIAS_EN_MUX | QSERDES_V3_COM_CLKBUF_R_EN |
               QSERDES_V3_COM_CLKBUF_L_EN | QSERDES_V3_COM_EN_SYSCLK_TX_SEL |
               QSERDES_V3_COM_CLKBUF_RX_DRIVE_L,
-              qphy->serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN);
-
-       writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG0);
-       writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1);
-       writel(0x24, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2);
-       writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG3);
-       writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG4);
-       writel(0x26, qphy->pcs + QSERDES_DP_PHY_AUX_CFG5);
-       writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG6);
-       writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG7);
-       writel(0xbb, qphy->pcs + QSERDES_DP_PHY_AUX_CFG8);
-       writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG9);
-       qphy->dp_aux_cfg = 0;
+              qmp->dp_serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN);
+
+       writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0);
+       writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+       writel(0x24, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2);
+       writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG3);
+       writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG4);
+       writel(0x26, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG5);
+       writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG6);
+       writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7);
+       writel(0xbb, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8);
+       writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9);
+       qmp->dp_aux_cfg = 0;
 
        writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK |
               PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
               PHY_AUX_REQ_ERR_MASK,
-              qphy->pcs + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK);
+              qmp->dp_dp_phy + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK);
 }
 
-static int qmp_combo_configure_dp_swing(struct qmp_phy *qphy,
+static int qmp_combo_configure_dp_swing(struct qmp_combo *qmp,
                unsigned int drv_lvl_reg, unsigned int emp_post_reg)
 {
-       const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
        unsigned int v_level = 0, p_level = 0;
        u8 voltage_swing_cfg, pre_emphasis_cfg;
        int i;
@@ -1492,20 +1352,20 @@ static int qmp_combo_configure_dp_swing(struct qmp_phy *qphy,
        voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN;
        pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN;
 
-       writel(voltage_swing_cfg, qphy->tx + drv_lvl_reg);
-       writel(pre_emphasis_cfg, qphy->tx + emp_post_reg);
-       writel(voltage_swing_cfg, qphy->tx2 + drv_lvl_reg);
-       writel(pre_emphasis_cfg, qphy->tx2 + emp_post_reg);
+       writel(voltage_swing_cfg, qmp->dp_tx + drv_lvl_reg);
+       writel(pre_emphasis_cfg, qmp->dp_tx + emp_post_reg);
+       writel(voltage_swing_cfg, qmp->dp_tx2 + drv_lvl_reg);
+       writel(pre_emphasis_cfg, qmp->dp_tx2 + emp_post_reg);
 
        return 0;
 }
 
-static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy)
+static void qmp_v3_configure_dp_tx(struct qmp_combo *qmp)
 {
-       const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
+       const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
        u32 bias_en, drvr_en;
 
-       if (qmp_combo_configure_dp_swing(qphy, QSERDES_V3_TX_TX_DRV_LVL,
+       if (qmp_combo_configure_dp_swing(qmp, QSERDES_V3_TX_TX_DRV_LVL,
                                QSERDES_V3_TX_TX_EMP_POST1_LVL) < 0)
                return;
 
@@ -1517,13 +1377,13 @@ static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy)
                drvr_en = 0x10;
        }
 
-       writel(drvr_en, qphy->tx + QSERDES_V3_TX_HIGHZ_DRVR_EN);
-       writel(bias_en, qphy->tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
-       writel(drvr_en, qphy->tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN);
-       writel(bias_en, qphy->tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
+       writel(drvr_en, qmp->dp_tx + QSERDES_V3_TX_HIGHZ_DRVR_EN);
+       writel(bias_en, qmp->dp_tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
+       writel(drvr_en, qmp->dp_tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN);
+       writel(bias_en, qmp->dp_tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
 }
 
-static bool qmp_combo_configure_dp_mode(struct qmp_phy *qphy)
+static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp)
 {
        u32 val;
        bool reverse = false;
@@ -1543,27 +1403,26 @@ static bool qmp_combo_configure_dp_mode(struct qmp_phy *qphy)
         * if (lane_cnt == 4 || orientation == ORIENTATION_CC1)
         *      val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
         * if (orientation == ORIENTATION_CC2)
-        *      writel(0x4c, qphy->pcs + QSERDES_V3_DP_PHY_MODE);
+        *      writel(0x4c, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_MODE);
         */
        val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
-       writel(val, qphy->pcs + QSERDES_DP_PHY_PD_CTL);
+       writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
 
-       writel(0x5c, qphy->pcs + QSERDES_DP_PHY_MODE);
+       writel(0x5c, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE);
 
        return reverse;
 }
 
-static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy)
+static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp)
 {
-       const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks;
-       const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
+       const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
        u32 phy_vco_div, status;
        unsigned long pixel_freq;
 
-       qmp_combo_configure_dp_mode(qphy);
+       qmp_combo_configure_dp_mode(qmp);
 
-       writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL);
-       writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL);
+       writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL);
+       writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL);
 
        switch (dp_opts->link_rate) {
        case 1620:
@@ -1586,40 +1445,40 @@ static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy)
                /* Other link rates aren't supported */
                return -EINVAL;
        }
-       writel(phy_vco_div, qphy->pcs + QSERDES_V3_DP_PHY_VCO_DIV);
+       writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_VCO_DIV);
 
-       clk_set_rate(dp_clks->dp_link_hw.clk, dp_opts->link_rate * 100000);
-       clk_set_rate(dp_clks->dp_pixel_hw.clk, pixel_freq);
+       clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000);
+       clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq);
 
-       writel(0x04, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2);
-       writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG);
-       writel(0x05, qphy->pcs + QSERDES_DP_PHY_CFG);
-       writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG);
-       writel(0x09, qphy->pcs + QSERDES_DP_PHY_CFG);
+       writel(0x04, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2);
+       writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+       writel(0x05, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+       writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+       writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
 
-       writel(0x20, qphy->serdes + QSERDES_V3_COM_RESETSM_CNTRL);
+       writel(0x20, qmp->dp_serdes + QSERDES_V3_COM_RESETSM_CNTRL);
 
-       if (readl_poll_timeout(qphy->serdes + QSERDES_V3_COM_C_READY_STATUS,
+       if (readl_poll_timeout(qmp->dp_serdes + QSERDES_V3_COM_C_READY_STATUS,
                        status,
                        ((status & BIT(0)) > 0),
                        500,
                        10000))
                return -ETIMEDOUT;
 
-       writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG);
+       writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
 
-       if (readl_poll_timeout(qphy->pcs + QSERDES_V3_DP_PHY_STATUS,
+       if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V3_DP_PHY_STATUS,
                        status,
                        ((status & BIT(1)) > 0),
                        500,
                        10000))
                return -ETIMEDOUT;
 
-       writel(0x18, qphy->pcs + QSERDES_DP_PHY_CFG);
+       writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
        udelay(2000);
-       writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG);
+       writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
 
-       return readl_poll_timeout(qphy->pcs + QSERDES_V3_DP_PHY_STATUS,
+       return readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V3_DP_PHY_STATUS,
                        status,
                        ((status & BIT(1)) > 0),
                        500,
@@ -1630,76 +1489,75 @@ static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy)
  * We need to calibrate the aux setting here as many times
  * as the caller tries
  */
-static int qcom_qmp_v3_dp_phy_calibrate(struct qmp_phy *qphy)
+static int qmp_v3_calibrate_dp_phy(struct qmp_combo *qmp)
 {
        static const u8 cfg1_settings[] = { 0x13, 0x23, 0x1d };
        u8 val;
 
-       qphy->dp_aux_cfg++;
-       qphy->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
-       val = cfg1_settings[qphy->dp_aux_cfg];
+       qmp->dp_aux_cfg++;
+       qmp->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
+       val = cfg1_settings[qmp->dp_aux_cfg];
 
-       writel(val, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1);
+       writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
 
        return 0;
 }
 
-static void qcom_qmp_v4_phy_dp_aux_init(struct qmp_phy *qphy)
+static void qmp_v4_dp_aux_init(struct qmp_combo *qmp)
 {
        writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_PSR_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
               DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
-              qphy->pcs + QSERDES_DP_PHY_PD_CTL);
+              qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
 
        /* Turn on BIAS current for PHY/PLL */
-       writel(0x17, qphy->serdes + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN);
-
-       writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG0);
-       writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1);
-       writel(0xa4, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2);
-       writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG3);
-       writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG4);
-       writel(0x26, qphy->pcs + QSERDES_DP_PHY_AUX_CFG5);
-       writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG6);
-       writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG7);
-       writel(0xb7, qphy->pcs + QSERDES_DP_PHY_AUX_CFG8);
-       writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG9);
-       qphy->dp_aux_cfg = 0;
+       writel(0x17, qmp->dp_serdes + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN);
+
+       writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0);
+       writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+       writel(0xa4, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2);
+       writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG3);
+       writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG4);
+       writel(0x26, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG5);
+       writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG6);
+       writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7);
+       writel(0xb7, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8);
+       writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9);
+       qmp->dp_aux_cfg = 0;
 
        writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK |
               PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
               PHY_AUX_REQ_ERR_MASK,
-              qphy->pcs + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK);
+              qmp->dp_dp_phy + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK);
 }
 
-static void qcom_qmp_v4_phy_configure_dp_tx(struct qmp_phy *qphy)
+static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp)
 {
        /* Program default values before writing proper values */
-       writel(0x27, qphy->tx + QSERDES_V4_TX_TX_DRV_LVL);
-       writel(0x27, qphy->tx2 + QSERDES_V4_TX_TX_DRV_LVL);
+       writel(0x27, qmp->dp_tx + QSERDES_V4_TX_TX_DRV_LVL);
+       writel(0x27, qmp->dp_tx2 + QSERDES_V4_TX_TX_DRV_LVL);
 
-       writel(0x20, qphy->tx + QSERDES_V4_TX_TX_EMP_POST1_LVL);
-       writel(0x20, qphy->tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL);
+       writel(0x20, qmp->dp_tx + QSERDES_V4_TX_TX_EMP_POST1_LVL);
+       writel(0x20, qmp->dp_tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL);
 
-       qmp_combo_configure_dp_swing(qphy, QSERDES_V4_TX_TX_DRV_LVL,
+       qmp_combo_configure_dp_swing(qmp, QSERDES_V4_TX_TX_DRV_LVL,
                        QSERDES_V4_TX_TX_EMP_POST1_LVL);
 }
 
-static int qcom_qmp_v45_phy_configure_dp_phy(struct qmp_phy *qphy)
+static int qmp_v45_configure_dp_phy(struct qmp_combo *qmp)
 {
-       const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks;
-       const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
+       const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
        u32 phy_vco_div, status;
        unsigned long pixel_freq;
 
-       writel(0x0f, qphy->pcs + QSERDES_V4_DP_PHY_CFG_1);
+       writel(0x0f, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_CFG_1);
 
-       qmp_combo_configure_dp_mode(qphy);
+       qmp_combo_configure_dp_mode(qmp);
 
-       writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1);
-       writel(0xa4, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2);
+       writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+       writel(0xa4, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2);
 
-       writel(0x05, qphy->pcs + QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL);
-       writel(0x05, qphy->pcs + QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL);
+       writel(0x05, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL);
+       writel(0x05, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL);
 
        switch (dp_opts->link_rate) {
        case 1620:
@@ -1722,49 +1580,49 @@ static int qcom_qmp_v45_phy_configure_dp_phy(struct qmp_phy *qphy)
                /* Other link rates aren't supported */
                return -EINVAL;
        }
-       writel(phy_vco_div, qphy->pcs + QSERDES_V4_DP_PHY_VCO_DIV);
+       writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_VCO_DIV);
 
-       clk_set_rate(dp_clks->dp_link_hw.clk, dp_opts->link_rate * 100000);
-       clk_set_rate(dp_clks->dp_pixel_hw.clk, pixel_freq);
+       clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000);
+       clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq);
 
-       writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG);
-       writel(0x05, qphy->pcs + QSERDES_DP_PHY_CFG);
-       writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG);
-       writel(0x09, qphy->pcs + QSERDES_DP_PHY_CFG);
+       writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+       writel(0x05, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+       writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+       writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
 
-       writel(0x20, qphy->serdes + QSERDES_V4_COM_RESETSM_CNTRL);
+       writel(0x20, qmp->dp_serdes + QSERDES_V4_COM_RESETSM_CNTRL);
 
-       if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_C_READY_STATUS,
+       if (readl_poll_timeout(qmp->dp_serdes + QSERDES_V4_COM_C_READY_STATUS,
                        status,
                        ((status & BIT(0)) > 0),
                        500,
                        10000))
                return -ETIMEDOUT;
 
-       if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_CMN_STATUS,
+       if (readl_poll_timeout(qmp->dp_serdes + QSERDES_V4_COM_CMN_STATUS,
                        status,
                        ((status & BIT(0)) > 0),
                        500,
                        10000))
                return -ETIMEDOUT;
 
-       if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_CMN_STATUS,
+       if (readl_poll_timeout(qmp->dp_serdes + QSERDES_V4_COM_CMN_STATUS,
                        status,
                        ((status & BIT(1)) > 0),
                        500,
                        10000))
                return -ETIMEDOUT;
 
-       writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG);
+       writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
 
-       if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS,
+       if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V4_DP_PHY_STATUS,
                        status,
                        ((status & BIT(0)) > 0),
                        500,
                        10000))
                return -ETIMEDOUT;
 
-       if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS,
+       if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V4_DP_PHY_STATUS,
                        status,
                        ((status & BIT(1)) > 0),
                        500,
@@ -1774,15 +1632,15 @@ static int qcom_qmp_v45_phy_configure_dp_phy(struct qmp_phy *qphy)
        return 0;
 }
 
-static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy)
+static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp)
 {
-       const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
+       const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
        u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
        bool reverse = false;
        u32 status;
        int ret;
 
-       ret = qcom_qmp_v45_phy_configure_dp_phy(qphy);
+       ret = qmp_v45_configure_dp_phy(qmp);
        if (ret < 0)
                return ret;
 
@@ -1808,43 +1666,43 @@ static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy)
                drvr1_en = 0x10;
        }
 
-       writel(drvr0_en, qphy->tx + QSERDES_V4_TX_HIGHZ_DRVR_EN);
-       writel(bias0_en, qphy->tx + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN);
-       writel(drvr1_en, qphy->tx2 + QSERDES_V4_TX_HIGHZ_DRVR_EN);
-       writel(bias1_en, qphy->tx2 + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN);
+       writel(drvr0_en, qmp->dp_tx + QSERDES_V4_TX_HIGHZ_DRVR_EN);
+       writel(bias0_en, qmp->dp_tx + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN);
+       writel(drvr1_en, qmp->dp_tx2 + QSERDES_V4_TX_HIGHZ_DRVR_EN);
+       writel(bias1_en, qmp->dp_tx2 + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN);
 
-       writel(0x18, qphy->pcs + QSERDES_DP_PHY_CFG);
+       writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
        udelay(2000);
-       writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG);
+       writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
 
-       if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS,
+       if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V4_DP_PHY_STATUS,
                        status,
                        ((status & BIT(1)) > 0),
                        500,
                        10000))
                return -ETIMEDOUT;
 
-       writel(0x0a, qphy->tx + QSERDES_V4_TX_TX_POL_INV);
-       writel(0x0a, qphy->tx2 + QSERDES_V4_TX_TX_POL_INV);
+       writel(0x0a, qmp->dp_tx + QSERDES_V4_TX_TX_POL_INV);
+       writel(0x0a, qmp->dp_tx2 + QSERDES_V4_TX_TX_POL_INV);
 
-       writel(0x27, qphy->tx + QSERDES_V4_TX_TX_DRV_LVL);
-       writel(0x27, qphy->tx2 + QSERDES_V4_TX_TX_DRV_LVL);
+       writel(0x27, qmp->dp_tx + QSERDES_V4_TX_TX_DRV_LVL);
+       writel(0x27, qmp->dp_tx2 + QSERDES_V4_TX_TX_DRV_LVL);
 
-       writel(0x20, qphy->tx + QSERDES_V4_TX_TX_EMP_POST1_LVL);
-       writel(0x20, qphy->tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL);
+       writel(0x20, qmp->dp_tx + QSERDES_V4_TX_TX_EMP_POST1_LVL);
+       writel(0x20, qmp->dp_tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL);
 
        return 0;
 }
 
-static int qcom_qmp_v5_phy_configure_dp_phy(struct qmp_phy *qphy)
+static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp)
 {
-       const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
+       const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
        u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
        bool reverse = false;
        u32 status;
        int ret;
 
-       ret = qcom_qmp_v45_phy_configure_dp_phy(qphy);
+       ret = qmp_v45_configure_dp_phy(qmp);
        if (ret < 0)
                return ret;
 
@@ -1865,30 +1723,30 @@ static int qcom_qmp_v5_phy_configure_dp_phy(struct qmp_phy *qphy)
                drvr1_en = 0x10;
        }
 
-       writel(drvr0_en, qphy->tx + QSERDES_V5_5NM_TX_HIGHZ_DRVR_EN);
-       writel(bias0_en, qphy->tx + QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN);
-       writel(drvr1_en, qphy->tx2 + QSERDES_V5_5NM_TX_HIGHZ_DRVR_EN);
-       writel(bias1_en, qphy->tx2 + QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN);
+       writel(drvr0_en, qmp->dp_tx + QSERDES_V5_5NM_TX_HIGHZ_DRVR_EN);
+       writel(bias0_en, qmp->dp_tx + QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN);
+       writel(drvr1_en, qmp->dp_tx2 + QSERDES_V5_5NM_TX_HIGHZ_DRVR_EN);
+       writel(bias1_en, qmp->dp_tx2 + QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN);
 
-       writel(0x18, qphy->pcs + QSERDES_DP_PHY_CFG);
+       writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
        udelay(2000);
-       writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG);
+       writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
 
-       if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS,
+       if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V4_DP_PHY_STATUS,
                        status,
                        ((status & BIT(1)) > 0),
                        500,
                        10000))
                return -ETIMEDOUT;
 
-       writel(0x0a, qphy->tx + QSERDES_V5_5NM_TX_TX_POL_INV);
-       writel(0x0a, qphy->tx2 + QSERDES_V5_5NM_TX_TX_POL_INV);
+       writel(0x0a, qmp->dp_tx + QSERDES_V5_5NM_TX_TX_POL_INV);
+       writel(0x0a, qmp->dp_tx2 + QSERDES_V5_5NM_TX_TX_POL_INV);
 
-       writel(0x27, qphy->tx + QSERDES_V5_5NM_TX_TX_DRV_LVL);
-       writel(0x27, qphy->tx2 + QSERDES_V5_5NM_TX_TX_DRV_LVL);
+       writel(0x27, qmp->dp_tx + QSERDES_V5_5NM_TX_TX_DRV_LVL);
+       writel(0x27, qmp->dp_tx2 + QSERDES_V5_5NM_TX_TX_DRV_LVL);
 
-       writel(0x20, qphy->tx + QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL);
-       writel(0x20, qphy->tx2 + QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL);
+       writel(0x20, qmp->dp_tx + QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL);
+       writel(0x20, qmp->dp_tx2 + QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL);
 
        return 0;
 }
@@ -1897,52 +1755,50 @@ static int qcom_qmp_v5_phy_configure_dp_phy(struct qmp_phy *qphy)
  * We need to calibrate the aux setting here as many times
  * as the caller tries
  */
-static int qcom_qmp_v4_dp_phy_calibrate(struct qmp_phy *qphy)
+static int qmp_v4_calibrate_dp_phy(struct qmp_combo *qmp)
 {
        static const u8 cfg1_settings[] = { 0x20, 0x13, 0x23, 0x1d };
        u8 val;
 
-       qphy->dp_aux_cfg++;
-       qphy->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
-       val = cfg1_settings[qphy->dp_aux_cfg];
+       qmp->dp_aux_cfg++;
+       qmp->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
+       val = cfg1_settings[qmp->dp_aux_cfg];
 
-       writel(val, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1);
+       writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
 
        return 0;
 }
 
-static int qcom_qmp_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts)
+static int qmp_combo_dp_configure(struct phy *phy, union phy_configure_opts *opts)
 {
        const struct phy_configure_opts_dp *dp_opts = &opts->dp;
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_combo *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
-       memcpy(&qphy->dp_opts, dp_opts, sizeof(*dp_opts));
-       if (qphy->dp_opts.set_voltages) {
-               cfg->configure_dp_tx(qphy);
-               qphy->dp_opts.set_voltages = 0;
+       memcpy(&qmp->dp_opts, dp_opts, sizeof(*dp_opts));
+       if (qmp->dp_opts.set_voltages) {
+               cfg->configure_dp_tx(qmp);
+               qmp->dp_opts.set_voltages = 0;
        }
 
        return 0;
 }
 
-static int qcom_qmp_dp_phy_calibrate(struct phy *phy)
+static int qmp_combo_dp_calibrate(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_combo *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
        if (cfg->calibrate_dp_phy)
-               return cfg->calibrate_dp_phy(qphy);
+               return cfg->calibrate_dp_phy(qmp);
 
        return 0;
 }
 
-static int qmp_combo_com_init(struct qmp_phy *qphy)
+static int qmp_combo_com_init(struct qmp_combo *qmp)
 {
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *pcs = qphy->pcs;
-       void __iomem *dp_com = qmp->dp_com;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *com = qmp->com;
        int ret;
 
        mutex_lock(&qmp->phy_mutex);
@@ -1951,7 +1807,6 @@ static int qmp_combo_com_init(struct qmp_phy *qphy)
                return 0;
        }
 
-       /* turn on regulator supplies */
        ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
        if (ret) {
                dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
@@ -1974,33 +1829,28 @@ static int qmp_combo_com_init(struct qmp_phy *qphy)
        if (ret)
                goto err_assert_reset;
 
-       qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, SW_PWRDN);
+       qphy_setbits(com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, SW_PWRDN);
 
        /* override hardware control for reset of qmp phy */
-       qphy_setbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
+       qphy_setbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
                        SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
                        SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
 
        /* Default type-c orientation, i.e CC1 */
-       qphy_setbits(dp_com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02);
+       qphy_setbits(com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02);
 
-       qphy_setbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL, USB3_MODE | DP_MODE);
+       qphy_setbits(com, QPHY_V3_DP_COM_PHY_MODE_CTRL, USB3_MODE | DP_MODE);
 
        /* bring both QMP USB and QMP DP PHYs PCS block out of reset */
-       qphy_clrbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
+       qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
                        SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
                        SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
 
-       qphy_clrbits(dp_com, QPHY_V3_DP_COM_SWI_CTRL, 0x03);
-       qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET);
+       qphy_clrbits(com, QPHY_V3_DP_COM_SWI_CTRL, 0x03);
+       qphy_clrbits(com, QPHY_V3_DP_COM_SW_RESET, SW_RESET);
 
-       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_V2_PCS_POWER_DOWN_CONTROL,
-                               cfg->pwrdn_ctrl);
+       qphy_setbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
+                       SW_PWRDN);
 
        mutex_unlock(&qmp->phy_mutex);
 
@@ -2016,10 +1866,9 @@ err_unlock:
        return ret;
 }
 
-static int qmp_combo_com_exit(struct qmp_phy *qphy)
+static int qmp_combo_com_exit(struct qmp_combo *qmp)
 {
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
        mutex_lock(&qmp->phy_mutex);
        if (--qmp->init_count) {
@@ -2027,8 +1876,6 @@ static int qmp_combo_com_exit(struct qmp_phy *qphy)
                return 0;
        }
 
-       reset_control_assert(qmp->ufs_reset);
-
        reset_control_bulk_assert(cfg->num_resets, qmp->resets);
 
        clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
@@ -2040,183 +1887,201 @@ static int qmp_combo_com_exit(struct qmp_phy *qphy)
        return 0;
 }
 
-static int qmp_combo_init(struct phy *phy)
+static int qmp_combo_dp_init(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_combo *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
        int ret;
-       dev_vdbg(qmp->dev, "Initializing QMP phy\n");
 
-       ret = qmp_combo_com_init(qphy);
+       ret = qmp_combo_com_init(qmp);
        if (ret)
                return ret;
 
-       if (cfg->type == PHY_TYPE_DP)
-               cfg->dp_aux_init(qphy);
+       cfg->dp_aux_init(qmp);
+
+       return 0;
+}
+
+static int qmp_combo_dp_exit(struct phy *phy)
+{
+       struct qmp_combo *qmp = phy_get_drvdata(phy);
+
+       qmp_combo_com_exit(qmp);
 
        return 0;
 }
 
-static int qmp_combo_power_on(struct phy *phy)
+static int qmp_combo_dp_power_on(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *tx = qphy->tx;
-       void __iomem *rx = qphy->rx;
-       void __iomem *pcs = qphy->pcs;
+       struct qmp_combo *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *tx = qmp->dp_tx;
+       void __iomem *tx2 = qmp->dp_tx2;
+
+       qmp_combo_dp_serdes_init(qmp);
+
+       qmp_combo_configure_lane(tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1);
+       qmp_combo_configure_lane(tx2, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 2);
+
+       /* Configure special DP tx tunings */
+       cfg->configure_dp_tx(qmp);
+
+       /* Configure link rate, swing, etc. */
+       cfg->configure_dp_phy(qmp);
+
+       return 0;
+}
+
+static int qmp_combo_dp_power_off(struct phy *phy)
+{
+       struct qmp_combo *qmp = phy_get_drvdata(phy);
+
+       /* Assert DP PHY power down */
+       writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+       return 0;
+}
+
+static int qmp_combo_usb_power_on(struct phy *phy)
+{
+       struct qmp_combo *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *serdes = qmp->serdes;
+       void __iomem *tx = qmp->tx;
+       void __iomem *rx = qmp->rx;
+       void __iomem *tx2 = qmp->tx2;
+       void __iomem *rx2 = qmp->rx2;
+       void __iomem *pcs = qmp->pcs;
        void __iomem *status;
-       unsigned int mask, val, ready;
+       unsigned int val;
        int ret;
 
-       qmp_combo_serdes_init(qphy);
+       qmp_combo_configure(serdes, cfg->serdes_tbl, cfg->serdes_tbl_num);
 
-       ret = clk_prepare_enable(qphy->pipe_clk);
+       ret = clk_prepare_enable(qmp->pipe_clk);
        if (ret) {
                dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
                return ret;
        }
 
        /* Tx, Rx, and PCS configurations */
-       qmp_combo_configure_lane(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num, 1);
+       qmp_combo_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
+       qmp_combo_configure_lane(tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
 
-       if (cfg->lanes >= 2) {
-               qmp_combo_configure_lane(qphy->tx2, cfg->regs, cfg->tx_tbl,
-                                        cfg->tx_tbl_num, 2);
-       }
+       qmp_combo_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
+       qmp_combo_configure_lane(rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
 
-       /* Configure special DP tx tunings */
-       if (cfg->type == PHY_TYPE_DP)
-               cfg->configure_dp_tx(qphy);
-
-       qmp_combo_configure_lane(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num, 1);
-
-       if (cfg->lanes >= 2) {
-               qmp_combo_configure_lane(qphy->rx2, cfg->regs, cfg->rx_tbl,
-                                        cfg->rx_tbl_num, 2);
-       }
-
-       /* Configure link rate, swing, etc. */
-       if (cfg->type == PHY_TYPE_DP)
-               cfg->configure_dp_phy(qphy);
-       else
-               qmp_combo_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
-
-       ret = reset_control_deassert(qmp->ufs_reset);
-       if (ret)
-               goto err_disable_pipe_clk;
+       qmp_combo_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
 
        if (cfg->has_pwrdn_delay)
-               usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max);
+               usleep_range(10, 20);
 
-       if (cfg->type != PHY_TYPE_DP) {
-               /* Pull PHY out of reset state */
-               qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
-               /* start SerDes and Phy-Coding-Sublayer */
-               qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
+       /* Pull PHY out of reset state */
+       qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
-               status = pcs + cfg->regs[QPHY_PCS_STATUS];
-               mask = cfg->phy_status;
-               ready = 0;
+       /* start SerDes and Phy-Coding-Sublayer */
+       qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);
 
-               ret = readl_poll_timeout(status, val, (val & mask) == ready, 10,
-                                        PHY_INIT_COMPLETE_TIMEOUT);
-               if (ret) {
-                       dev_err(qmp->dev, "phy initialization timed-out\n");
-                       goto err_disable_pipe_clk;
-               }
+       status = pcs + cfg->regs[QPHY_PCS_STATUS];
+       ret = readl_poll_timeout(status, val, !(val & PHYSTATUS), 200,
+                       PHY_INIT_COMPLETE_TIMEOUT);
+       if (ret) {
+               dev_err(qmp->dev, "phy initialization timed-out\n");
+               goto err_disable_pipe_clk;
        }
+
        return 0;
 
 err_disable_pipe_clk:
-       clk_disable_unprepare(qphy->pipe_clk);
+       clk_disable_unprepare(qmp->pipe_clk);
 
        return ret;
 }
 
-static int qmp_combo_power_off(struct phy *phy)
+static int qmp_combo_usb_power_off(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_combo *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
-       clk_disable_unprepare(qphy->pipe_clk);
+       clk_disable_unprepare(qmp->pipe_clk);
 
-       if (cfg->type == PHY_TYPE_DP) {
-               /* Assert DP PHY power down */
-               writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_DP_PHY_PD_CTL);
-       } else {
-               /* PHY reset */
-               qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
-
-               /* stop SerDes and Phy-Coding-Sublayer */
-               qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
-
-               /* Put PHY into POWER DOWN state: active low */
-               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_V2_PCS_POWER_DOWN_CONTROL,
-                                       cfg->pwrdn_ctrl);
-               }
-       }
+       /* PHY reset */
+       qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
-       return 0;
-}
-
-static int qmp_combo_exit(struct phy *phy)
-{
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
+       /* stop SerDes and Phy-Coding-Sublayer */
+       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL],
+                       SERDES_START | PCS_START);
 
-       qmp_combo_com_exit(qphy);
+       /* Put PHY into POWER DOWN state: active low */
+       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
+                       SW_PWRDN);
 
        return 0;
 }
 
-static int qmp_combo_enable(struct phy *phy)
+static int qmp_combo_usb_init(struct phy *phy)
 {
+       struct qmp_combo *qmp = phy_get_drvdata(phy);
        int ret;
 
-       ret = qmp_combo_init(phy);
+       ret = qmp_combo_com_init(qmp);
        if (ret)
                return ret;
 
-       ret = qmp_combo_power_on(phy);
+       ret = qmp_combo_usb_power_on(phy);
        if (ret)
-               qmp_combo_exit(phy);
+               qmp_combo_com_exit(qmp);
 
        return ret;
 }
 
-static int qmp_combo_disable(struct phy *phy)
+static int qmp_combo_usb_exit(struct phy *phy)
 {
+       struct qmp_combo *qmp = phy_get_drvdata(phy);
        int ret;
 
-       ret = qmp_combo_power_off(phy);
+       ret = qmp_combo_usb_power_off(phy);
        if (ret)
                return ret;
-       return qmp_combo_exit(phy);
+
+       return qmp_combo_com_exit(qmp);
 }
 
-static int qmp_combo_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+static int qmp_combo_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
+       struct qmp_combo *qmp = phy_get_drvdata(phy);
 
-       qphy->mode = mode;
+       qmp->mode = mode;
 
        return 0;
 }
 
-static void qmp_combo_enable_autonomous_mode(struct qmp_phy *qphy)
+static const struct phy_ops qmp_combo_usb_phy_ops = {
+       .init           = qmp_combo_usb_init,
+       .exit           = qmp_combo_usb_exit,
+       .set_mode       = qmp_combo_usb_set_mode,
+       .owner          = THIS_MODULE,
+};
+
+static const struct phy_ops qmp_combo_dp_phy_ops = {
+       .init           = qmp_combo_dp_init,
+       .configure      = qmp_combo_dp_configure,
+       .power_on       = qmp_combo_dp_power_on,
+       .calibrate      = qmp_combo_dp_calibrate,
+       .power_off      = qmp_combo_dp_power_off,
+       .exit           = qmp_combo_dp_exit,
+       .owner          = THIS_MODULE,
+};
+
+static void qmp_combo_enable_autonomous_mode(struct qmp_combo *qmp)
 {
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *pcs_usb = qphy->pcs_usb ?: qphy->pcs;
-       void __iomem *pcs_misc = qphy->pcs_misc;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs;
+       void __iomem *pcs_misc = qmp->pcs_misc;
        u32 intr_mask;
 
-       if (qphy->mode == PHY_MODE_USB_HOST_SS ||
-           qphy->mode == PHY_MODE_USB_DEVICE_SS)
+       if (qmp->mode == PHY_MODE_USB_HOST_SS ||
+           qmp->mode == PHY_MODE_USB_DEVICE_SS)
                intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN;
        else
                intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL;
@@ -2237,11 +2102,11 @@ static void qmp_combo_enable_autonomous_mode(struct qmp_phy *qphy)
                qphy_clrbits(pcs_misc, QPHY_V3_PCS_MISC_CLAMP_ENABLE, CLAMP_EN);
 }
 
-static void qmp_combo_disable_autonomous_mode(struct qmp_phy *qphy)
+static void qmp_combo_disable_autonomous_mode(struct qmp_combo *qmp)
 {
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *pcs_usb = qphy->pcs_usb ?: qphy->pcs;
-       void __iomem *pcs_misc = qphy->pcs_misc;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs;
+       void __iomem *pcs_misc = qmp->pcs_misc;
 
        /* Disable i/o clamp_n on resume for normal mode */
        if (pcs_misc)
@@ -2257,24 +2122,19 @@ static void qmp_combo_disable_autonomous_mode(struct qmp_phy *qphy)
 
 static int __maybe_unused qmp_combo_runtime_suspend(struct device *dev)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
-       struct qmp_phy *qphy = qmp->phys[0];
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_combo *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
-       dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qphy->mode);
-
-       /* Supported only for USB3 PHY and luckily USB3 is the first phy */
-       if (cfg->type != PHY_TYPE_USB3)
-               return 0;
+       dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);
 
        if (!qmp->init_count) {
                dev_vdbg(dev, "PHY not initialized, bailing out\n");
                return 0;
        }
 
-       qmp_combo_enable_autonomous_mode(qphy);
+       qmp_combo_enable_autonomous_mode(qmp);
 
-       clk_disable_unprepare(qphy->pipe_clk);
+       clk_disable_unprepare(qmp->pipe_clk);
        clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 
        return 0;
@@ -2282,16 +2142,11 @@ static int __maybe_unused qmp_combo_runtime_suspend(struct device *dev)
 
 static int __maybe_unused qmp_combo_runtime_resume(struct device *dev)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
-       struct qmp_phy *qphy = qmp->phys[0];
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_combo *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
        int ret = 0;
 
-       dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qphy->mode);
-
-       /* Supported only for USB3 PHY and luckily USB3 is the first phy */
-       if (cfg->type != PHY_TYPE_USB3)
-               return 0;
+       dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
 
        if (!qmp->init_count) {
                dev_vdbg(dev, "PHY not initialized, bailing out\n");
@@ -2302,21 +2157,27 @@ static int __maybe_unused qmp_combo_runtime_resume(struct device *dev)
        if (ret)
                return ret;
 
-       ret = clk_prepare_enable(qphy->pipe_clk);
+       ret = clk_prepare_enable(qmp->pipe_clk);
        if (ret) {
                dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
                clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
                return ret;
        }
 
-       qmp_combo_disable_autonomous_mode(qphy);
+       qmp_combo_disable_autonomous_mode(qmp);
 
        return 0;
 }
 
-static int qmp_combo_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg)
+static const struct dev_pm_ops qmp_combo_pm_ops = {
+       SET_RUNTIME_PM_OPS(qmp_combo_runtime_suspend,
+                          qmp_combo_runtime_resume, NULL)
+};
+
+static int qmp_combo_vreg_init(struct qmp_combo *qmp)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        int num = cfg->num_vregs;
        int ret, i;
 
@@ -2346,9 +2207,10 @@ static int qmp_combo_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg
        return 0;
 }
 
-static int qmp_combo_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg)
+static int qmp_combo_reset_init(struct qmp_combo *qmp)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        int i;
        int ret;
 
@@ -2367,9 +2229,10 @@ static int qmp_combo_reset_init(struct device *dev, const struct qmp_phy_cfg *cf
        return 0;
 }
 
-static int qmp_combo_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg)
+static int qmp_combo_clk_init(struct qmp_combo *qmp)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        int num = cfg->num_clks;
        int i;
 
@@ -2406,41 +2269,21 @@ static void phy_clk_release_provider(void *res)
  *    clk  |   +-------+   |                   +-----+
  *         +---------------+
  */
-static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
+static int phy_pipe_clk_register(struct qmp_combo *qmp, struct device_node *np)
 {
-       struct clk_fixed_rate *fixed;
+       struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;
        struct clk_init_data init = { };
-       int ret;
-
-       ret = of_property_read_string(np, "clock-output-names", &init.name);
-       if (ret) {
-               dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np);
-               return ret;
-       }
-
-       fixed = devm_kzalloc(qmp->dev, sizeof(*fixed), GFP_KERNEL);
-       if (!fixed)
-               return -ENOMEM;
+       char name[64];
 
+       snprintf(name, sizeof(name), "%s::pipe_clk", dev_name(qmp->dev));
+       init.name = name;
        init.ops = &clk_fixed_rate_ops;
 
        /* controllers using QMP phys use 125MHz pipe clock interface */
        fixed->fixed_rate = 125000000;
        fixed->hw.init = &init;
 
-       ret = devm_clk_hw_register(qmp->dev, &fixed->hw);
-       if (ret)
-               return ret;
-
-       ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw);
-       if (ret)
-               return ret;
-
-       /*
-        * Roll a devm action because the clock provider is the child node, but
-        * the child node is not actually a device.
-        */
-       return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np);
+       return devm_clk_hw_register(qmp->dev, &fixed->hw);
 }
 
 /*
@@ -2492,8 +2335,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
  *              for DP pixel clock
  *
  */
-static int qcom_qmp_dp_pixel_clk_determine_rate(struct clk_hw *hw,
-                                               struct clk_rate_request *req)
+static int qmp_dp_pixel_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
 {
        switch (req->rate) {
        case 1620000000UL / 2:
@@ -2505,16 +2347,13 @@ static int qcom_qmp_dp_pixel_clk_determine_rate(struct clk_hw *hw,
        }
 }
 
-static unsigned long
-qcom_qmp_dp_pixel_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+static unsigned long qmp_dp_pixel_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 {
-       const struct qmp_phy_dp_clks *dp_clks;
-       const struct qmp_phy *qphy;
+       const struct qmp_combo *qmp;
        const struct phy_configure_opts_dp *dp_opts;
 
-       dp_clks = container_of(hw, struct qmp_phy_dp_clks, dp_pixel_hw);
-       qphy = dp_clks->qphy;
-       dp_opts = &qphy->dp_opts;
+       qmp = container_of(hw, struct qmp_combo, dp_pixel_hw);
+       dp_opts = &qmp->dp_opts;
 
        switch (dp_opts->link_rate) {
        case 1620:
@@ -2530,13 +2369,12 @@ qcom_qmp_dp_pixel_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
        }
 }
 
-static const struct clk_ops qcom_qmp_dp_pixel_clk_ops = {
-       .determine_rate = qcom_qmp_dp_pixel_clk_determine_rate,
-       .recalc_rate = qcom_qmp_dp_pixel_clk_recalc_rate,
+static const struct clk_ops qmp_dp_pixel_clk_ops = {
+       .determine_rate = qmp_dp_pixel_clk_determine_rate,
+       .recalc_rate    = qmp_dp_pixel_clk_recalc_rate,
 };
 
-static int qcom_qmp_dp_link_clk_determine_rate(struct clk_hw *hw,
-                                              struct clk_rate_request *req)
+static int qmp_dp_link_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
 {
        switch (req->rate) {
        case 162000000:
@@ -2549,16 +2387,13 @@ static int qcom_qmp_dp_link_clk_determine_rate(struct clk_hw *hw,
        }
 }
 
-static unsigned long
-qcom_qmp_dp_link_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+static unsigned long qmp_dp_link_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 {
-       const struct qmp_phy_dp_clks *dp_clks;
-       const struct qmp_phy *qphy;
+       const struct qmp_combo *qmp;
        const struct phy_configure_opts_dp *dp_opts;
 
-       dp_clks = container_of(hw, struct qmp_phy_dp_clks, dp_link_hw);
-       qphy = dp_clks->qphy;
-       dp_opts = &qphy->dp_opts;
+       qmp = container_of(hw, struct qmp_combo, dp_link_hw);
+       dp_opts = &qmp->dp_opts;
 
        switch (dp_opts->link_rate) {
        case 1620:
@@ -2571,15 +2406,14 @@ qcom_qmp_dp_link_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
        }
 }
 
-static const struct clk_ops qcom_qmp_dp_link_clk_ops = {
-       .determine_rate = qcom_qmp_dp_link_clk_determine_rate,
-       .recalc_rate = qcom_qmp_dp_link_clk_recalc_rate,
+static const struct clk_ops qmp_dp_link_clk_ops = {
+       .determine_rate = qmp_dp_link_clk_determine_rate,
+       .recalc_rate    = qmp_dp_link_clk_recalc_rate,
 };
 
-static struct clk_hw *
-qcom_qmp_dp_clks_hw_get(struct of_phandle_args *clkspec, void *data)
+static struct clk_hw *qmp_dp_clks_hw_get(struct of_phandle_args *clkspec, void *data)
 {
-       struct qmp_phy_dp_clks *dp_clks = data;
+       struct qmp_combo *qmp = data;
        unsigned int idx = clkspec->args[0];
 
        if (idx >= 2) {
@@ -2588,43 +2422,76 @@ qcom_qmp_dp_clks_hw_get(struct of_phandle_args *clkspec, void *data)
        }
 
        if (idx == 0)
-               return &dp_clks->dp_link_hw;
+               return &qmp->dp_link_hw;
 
-       return &dp_clks->dp_pixel_hw;
+       return &qmp->dp_pixel_hw;
 }
 
-static int phy_dp_clks_register(struct qcom_qmp *qmp, struct qmp_phy *qphy,
-                               struct device_node *np)
+static int phy_dp_clks_register(struct qmp_combo *qmp, struct device_node *np)
 {
        struct clk_init_data init = { };
-       struct qmp_phy_dp_clks *dp_clks;
        char name[64];
        int ret;
 
-       dp_clks = devm_kzalloc(qmp->dev, sizeof(*dp_clks), GFP_KERNEL);
-       if (!dp_clks)
-               return -ENOMEM;
-
-       dp_clks->qphy = qphy;
-       qphy->dp_clks = dp_clks;
-
        snprintf(name, sizeof(name), "%s::link_clk", dev_name(qmp->dev));
-       init.ops = &qcom_qmp_dp_link_clk_ops;
+       init.ops = &qmp_dp_link_clk_ops;
        init.name = name;
-       dp_clks->dp_link_hw.init = &init;
-       ret = devm_clk_hw_register(qmp->dev, &dp_clks->dp_link_hw);
+       qmp->dp_link_hw.init = &init;
+       ret = devm_clk_hw_register(qmp->dev, &qmp->dp_link_hw);
        if (ret)
                return ret;
 
        snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(qmp->dev));
-       init.ops = &qcom_qmp_dp_pixel_clk_ops;
+       init.ops = &qmp_dp_pixel_clk_ops;
        init.name = name;
-       dp_clks->dp_pixel_hw.init = &init;
-       ret = devm_clk_hw_register(qmp->dev, &dp_clks->dp_pixel_hw);
+       qmp->dp_pixel_hw.init = &init;
+       ret = devm_clk_hw_register(qmp->dev, &qmp->dp_pixel_hw);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static struct clk_hw *qmp_combo_clk_hw_get(struct of_phandle_args *clkspec, void *data)
+{
+       struct qmp_combo *qmp = data;
+
+       switch (clkspec->args[0]) {
+       case QMP_USB43DP_USB3_PIPE_CLK:
+               return &qmp->pipe_clk_fixed.hw;
+       case QMP_USB43DP_DP_LINK_CLK:
+               return &qmp->dp_link_hw;
+       case QMP_USB43DP_DP_VCO_DIV_CLK:
+               return &qmp->dp_pixel_hw;
+       }
+
+       return ERR_PTR(-EINVAL);
+}
+
+static int qmp_combo_register_clocks(struct qmp_combo *qmp, struct device_node *usb_np,
+                                       struct device_node *dp_np)
+{
+       int ret;
+
+       ret = phy_pipe_clk_register(qmp, usb_np);
+       if (ret)
+               return ret;
+
+       ret = phy_dp_clks_register(qmp, dp_np);
        if (ret)
                return ret;
 
-       ret = of_clk_add_hw_provider(np, qcom_qmp_dp_clks_hw_get, dp_clks);
+       /*
+        * Register a single provider for bindings without child nodes.
+        */
+       if (usb_np == qmp->dev->of_node)
+               return devm_of_clk_add_hw_provider(qmp->dev, qmp_combo_clk_hw_get, qmp);
+
+       /*
+        * Register multiple providers for legacy bindings with child nodes.
+        */
+       ret = of_clk_add_hw_provider(usb_np, of_clk_hw_simple_get,
+                                       &qmp->pipe_clk_fixed.hw);
        if (ret)
                return ret;
 
@@ -2632,162 +2499,184 @@ static int phy_dp_clks_register(struct qcom_qmp *qmp, struct qmp_phy *qphy,
         * Roll a devm action because the clock provider is the child node, but
         * the child node is not actually a device.
         */
-       return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np);
-}
+       ret = devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, usb_np);
+       if (ret)
+               return ret;
 
-static const struct phy_ops qmp_combo_usb_ops = {
-       .init           = qmp_combo_enable,
-       .exit           = qmp_combo_disable,
-       .set_mode       = qmp_combo_set_mode,
-       .owner          = THIS_MODULE,
-};
+       ret = of_clk_add_hw_provider(dp_np, qmp_dp_clks_hw_get, qmp);
+       if (ret)
+               return ret;
 
-static const struct phy_ops qmp_combo_dp_ops = {
-       .init           = qmp_combo_init,
-       .configure      = qcom_qmp_dp_phy_configure,
-       .power_on       = qmp_combo_power_on,
-       .calibrate      = qcom_qmp_dp_phy_calibrate,
-       .power_off      = qmp_combo_power_off,
-       .exit           = qmp_combo_exit,
-       .set_mode       = qmp_combo_set_mode,
-       .owner          = THIS_MODULE,
-};
+       return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, dp_np);
+}
 
-static int qmp_combo_create(struct device *dev, struct device_node *np, int id,
-                       void __iomem *serdes, const struct qmp_phy_cfg *cfg)
+static int qmp_combo_parse_dt_lecacy_dp(struct qmp_combo *qmp, struct device_node *np)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
-       struct phy *generic_phy;
-       struct qmp_phy *qphy;
-       const struct phy_ops *ops;
-       int ret;
+       struct device *dev = qmp->dev;
 
-       qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
-       if (!qphy)
-               return -ENOMEM;
+       /*
+        * Get memory resources from the DP child node:
+        * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2;
+        * tx2 -> 3; rx2 -> 4
+        *
+        * Note that only tx/tx2 and pcs (dp_phy) are used by the DP
+        * implementation.
+        */
+       qmp->dp_tx = devm_of_iomap(dev, np, 0, NULL);
+       if (IS_ERR(qmp->dp_tx))
+               return PTR_ERR(qmp->dp_tx);
+
+       qmp->dp_dp_phy = devm_of_iomap(dev, np, 2, NULL);
+       if (IS_ERR(qmp->dp_dp_phy))
+               return PTR_ERR(qmp->dp_dp_phy);
+
+       qmp->dp_tx2 = devm_of_iomap(dev, np, 3, NULL);
+       if (IS_ERR(qmp->dp_tx2))
+               return PTR_ERR(qmp->dp_tx2);
+
+       return 0;
+}
+
+static int qmp_combo_parse_dt_lecacy_usb(struct qmp_combo *qmp, struct device_node *np)
+{
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
 
-       qphy->cfg = cfg;
-       qphy->serdes = serdes;
        /*
-        * Get memory resources for each phy lane:
-        * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2.
-        * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5
-        * For single lane PHYs: pcs_misc (optional) -> 3.
+        * Get memory resources from the USB child node:
+        * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2;
+        * tx2 -> 3; rx2 -> 4; pcs_misc (optional) -> 5
         */
-       qphy->tx = devm_of_iomap(dev, np, 0, NULL);
-       if (IS_ERR(qphy->tx))
-               return PTR_ERR(qphy->tx);
+       qmp->tx = devm_of_iomap(dev, np, 0, NULL);
+       if (IS_ERR(qmp->tx))
+               return PTR_ERR(qmp->tx);
 
-       qphy->rx = devm_of_iomap(dev, np, 1, NULL);
-       if (IS_ERR(qphy->rx))
-               return PTR_ERR(qphy->rx);
+       qmp->rx = devm_of_iomap(dev, np, 1, NULL);
+       if (IS_ERR(qmp->rx))
+               return PTR_ERR(qmp->rx);
 
-       qphy->pcs = devm_of_iomap(dev, np, 2, NULL);
-       if (IS_ERR(qphy->pcs))
-               return PTR_ERR(qphy->pcs);
+       qmp->pcs = devm_of_iomap(dev, np, 2, NULL);
+       if (IS_ERR(qmp->pcs))
+               return PTR_ERR(qmp->pcs);
 
        if (cfg->pcs_usb_offset)
-               qphy->pcs_usb = qphy->pcs + cfg->pcs_usb_offset;
-
-       if (cfg->lanes >= 2) {
-               qphy->tx2 = devm_of_iomap(dev, np, 3, NULL);
-               if (IS_ERR(qphy->tx2))
-                       return PTR_ERR(qphy->tx2);
+               qmp->pcs_usb = qmp->pcs + cfg->pcs_usb_offset;
 
-               qphy->rx2 = devm_of_iomap(dev, np, 4, NULL);
-               if (IS_ERR(qphy->rx2))
-                       return PTR_ERR(qphy->rx2);
+       qmp->tx2 = devm_of_iomap(dev, np, 3, NULL);
+       if (IS_ERR(qmp->tx2))
+               return PTR_ERR(qmp->tx2);
 
-               qphy->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
-       } else {
-               qphy->pcs_misc = devm_of_iomap(dev, np, 3, NULL);
-       }
+       qmp->rx2 = devm_of_iomap(dev, np, 4, NULL);
+       if (IS_ERR(qmp->rx2))
+               return PTR_ERR(qmp->rx2);
 
-       if (IS_ERR(qphy->pcs_misc)) {
+       qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
+       if (IS_ERR(qmp->pcs_misc)) {
                dev_vdbg(dev, "PHY pcs_misc-reg not used\n");
-               qphy->pcs_misc = NULL;
+               qmp->pcs_misc = NULL;
        }
 
-       /*
-        * Get PHY's Pipe clock, if any. USB3 and PCIe are PIPE3
-        * based phys, so they essentially have pipe clock. So,
-        * we return error in case phy is USB3 or PIPE type.
-        * Otherwise, we initialize pipe clock to NULL for
-        * all phys that don't need this.
-        */
-       qphy->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
-       if (IS_ERR(qphy->pipe_clk)) {
-               if (cfg->type == PHY_TYPE_USB3)
-                       return dev_err_probe(dev, PTR_ERR(qphy->pipe_clk),
-                                            "failed to get lane%d pipe_clk\n",
-                                            id);
-               qphy->pipe_clk = NULL;
+       qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
+       if (IS_ERR(qmp->pipe_clk)) {
+               return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
+                                    "failed to get pipe clock\n");
        }
 
-       if (cfg->type == PHY_TYPE_DP)
-               ops = &qmp_combo_dp_ops;
-       else
-               ops = &qmp_combo_usb_ops;
+       return 0;
+}
 
-       generic_phy = devm_phy_create(dev, np, ops);
-       if (IS_ERR(generic_phy)) {
-               ret = PTR_ERR(generic_phy);
-               dev_err(dev, "failed to create qphy %d\n", ret);
+static int qmp_combo_parse_dt_legacy(struct qmp_combo *qmp, struct device_node *usb_np,
+                                       struct device_node *dp_np)
+{
+       struct platform_device *pdev = to_platform_device(qmp->dev);
+       int ret;
+
+       qmp->serdes = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(qmp->serdes))
+               return PTR_ERR(qmp->serdes);
+
+       qmp->com = devm_platform_ioremap_resource(pdev, 1);
+       if (IS_ERR(qmp->com))
+               return PTR_ERR(qmp->com);
+
+       qmp->dp_serdes = devm_platform_ioremap_resource(pdev, 2);
+       if (IS_ERR(qmp->dp_serdes))
+               return PTR_ERR(qmp->dp_serdes);
+
+       ret = qmp_combo_parse_dt_lecacy_usb(qmp, usb_np);
+       if (ret)
                return ret;
-       }
 
-       qphy->phy = generic_phy;
-       qphy->qmp = qmp;
-       qmp->phys[id] = qphy;
-       phy_set_drvdata(generic_phy, qphy);
+       ret = qmp_combo_parse_dt_lecacy_dp(qmp, dp_np);
+       if (ret)
+               return ret;
 
        return 0;
 }
 
-static const struct of_device_id qmp_combo_of_match_table[] = {
-       {
-               .compatible = "qcom,sc7180-qmp-usb3-dp-phy",
-               .data = &sc7180_usb3dpphy_cfg,
-       },
-       {
-               .compatible = "qcom,sdm845-qmp-usb3-dp-phy",
-               .data = &sdm845_usb3dpphy_cfg,
-       },
-       {
-               .compatible = "qcom,sm8250-qmp-usb3-dp-phy",
-               .data = &sm8250_usb3dpphy_cfg,
-       },
-       {
-               .compatible = "qcom,sc8180x-qmp-usb3-dp-phy",
-               .data = &sc8180x_usb3dpphy_cfg,
-       },
-       {
-               .compatible = "qcom,sc8280xp-qmp-usb43dp-phy",
-               .data = &sc8280xp_usb43dpphy_combo_cfg,
-       },
-       { }
-};
-MODULE_DEVICE_TABLE(of, qmp_combo_of_match_table);
+static int qmp_combo_parse_dt(struct qmp_combo *qmp)
+{
+       struct platform_device *pdev = to_platform_device(qmp->dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       const struct qmp_combo_offsets *offs = cfg->offsets;
+       struct device *dev = qmp->dev;
+       void __iomem *base;
 
-static const struct dev_pm_ops qmp_combo_pm_ops = {
-       SET_RUNTIME_PM_OPS(qmp_combo_runtime_suspend,
-                          qmp_combo_runtime_resume, NULL)
-};
+       if (!offs)
+               return -EINVAL;
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       qmp->com = base + offs->com;
+       qmp->tx = base + offs->txa;
+       qmp->rx = base + offs->rxa;
+       qmp->tx2 = base + offs->txb;
+       qmp->rx2 = base + offs->rxb;
+
+       qmp->serdes = base + offs->usb3_serdes;
+       qmp->pcs_misc = base + offs->usb3_pcs_misc;
+       qmp->pcs = base + offs->usb3_pcs;
+       qmp->pcs_usb = base + offs->usb3_pcs_usb;
+
+       qmp->dp_serdes = base + offs->dp_serdes;
+       qmp->dp_tx = base + offs->txa;
+       qmp->dp_tx2 = base + offs->txb;
+       qmp->dp_dp_phy = base + offs->dp_dp_phy;
+
+       qmp->pipe_clk = devm_clk_get(dev, "usb3_pipe");
+       if (IS_ERR(qmp->pipe_clk)) {
+               return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
+                               "failed to get usb3_pipe clock\n");
+       }
+
+       return 0;
+}
+
+static struct phy *qmp_combo_phy_xlate(struct device *dev, struct of_phandle_args *args)
+{
+       struct qmp_combo *qmp = dev_get_drvdata(dev);
+
+       if (args->args_count == 0)
+               return ERR_PTR(-EINVAL);
+
+       switch (args->args[0]) {
+       case QMP_USB43DP_USB3_PHY:
+               return qmp->usb_phy;
+       case QMP_USB43DP_DP_PHY:
+               return qmp->dp_phy;
+       }
+
+       return ERR_PTR(-EINVAL);
+}
 
 static int qmp_combo_probe(struct platform_device *pdev)
 {
-       struct qcom_qmp *qmp;
+       struct qmp_combo *qmp;
        struct device *dev = &pdev->dev;
-       struct device_node *child;
+       struct device_node *dp_np, *usb_np;
        struct phy_provider *phy_provider;
-       void __iomem *serdes;
-       void __iomem *usb_serdes;
-       void __iomem *dp_serdes = NULL;
-       const struct qmp_phy_combo_cfg *combo_cfg = NULL;
-       const struct qmp_phy_cfg *cfg = NULL;
-       const struct qmp_phy_cfg *usb_cfg = NULL;
-       const struct qmp_phy_cfg *dp_cfg = NULL;
-       int num, id, expected_phys;
        int ret;
 
        qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
@@ -2795,123 +2684,119 @@ static int qmp_combo_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        qmp->dev = dev;
-       dev_set_drvdata(dev, qmp);
 
-       /* Get the specific init parameters of QMP phy */
-       combo_cfg = of_device_get_match_data(dev);
-       if (!combo_cfg)
+       qmp->cfg = of_device_get_match_data(dev);
+       if (!qmp->cfg)
                return -EINVAL;
 
-       usb_cfg = combo_cfg->usb_cfg;
-       cfg = usb_cfg; /* Setup clks and regulators */
-
-       /* per PHY serdes; usually located at base address */
-       usb_serdes = serdes = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(serdes))
-               return PTR_ERR(serdes);
-
-       qmp->dp_com = devm_platform_ioremap_resource(pdev, 1);
-       if (IS_ERR(qmp->dp_com))
-               return PTR_ERR(qmp->dp_com);
-
-       /* Only two serdes for combo PHY */
-       dp_serdes = devm_platform_ioremap_resource(pdev, 2);
-       if (IS_ERR(dp_serdes))
-               return PTR_ERR(dp_serdes);
-
-       dp_cfg = combo_cfg->dp_cfg;
-       expected_phys = 2;
-
        mutex_init(&qmp->phy_mutex);
 
-       ret = qmp_combo_clk_init(dev, cfg);
+       ret = qmp_combo_clk_init(qmp);
        if (ret)
                return ret;
 
-       ret = qmp_combo_reset_init(dev, cfg);
+       ret = qmp_combo_reset_init(qmp);
        if (ret)
                return ret;
 
-       ret = qmp_combo_vreg_init(dev, cfg);
+       ret = qmp_combo_vreg_init(qmp);
        if (ret)
-               return dev_err_probe(dev, ret,
-                                    "failed to get regulator supplies\n");
+               return ret;
 
-       num = of_get_available_child_count(dev->of_node);
-       /* do we have a rogue child node ? */
-       if (num > expected_phys)
-               return -EINVAL;
+       /* Check for legacy binding with child nodes. */
+       usb_np = of_get_child_by_name(dev->of_node, "usb3-phy");
+       if (usb_np) {
+               dp_np = of_get_child_by_name(dev->of_node, "dp-phy");
+               if (!dp_np) {
+                       of_node_put(usb_np);
+                       return -EINVAL;
+               }
 
-       qmp->phys = devm_kcalloc(dev, num, sizeof(*qmp->phys), GFP_KERNEL);
-       if (!qmp->phys)
-               return -ENOMEM;
+               ret = qmp_combo_parse_dt_legacy(qmp, usb_np, dp_np);
+       } else {
+               usb_np = of_node_get(dev->of_node);
+               dp_np = of_node_get(dev->of_node);
+
+               ret = qmp_combo_parse_dt(qmp);
+       }
+       if (ret)
+               goto err_node_put;
 
        pm_runtime_set_active(dev);
        ret = devm_pm_runtime_enable(dev);
        if (ret)
-               return ret;
+               goto err_node_put;
        /*
         * Prevent runtime pm from being ON by default. Users can enable
         * it using power/control in sysfs.
         */
        pm_runtime_forbid(dev);
 
-       id = 0;
-       for_each_available_child_of_node(dev->of_node, child) {
-               if (of_node_name_eq(child, "dp-phy")) {
-                       cfg = dp_cfg;
-                       serdes = dp_serdes;
-
-                       /* Create per-lane phy */
-                       ret = qmp_combo_create(dev, child, id, serdes, cfg);
-                       if (ret) {
-                               dev_err(dev, "failed to create lane%d phy, %d\n",
-                                       id, ret);
-                               goto err_node_put;
-                       }
-
-                       ret = phy_dp_clks_register(qmp, qmp->phys[id], child);
-                       if (ret) {
-                               dev_err(qmp->dev,
-                                       "failed to register DP clock source\n");
-                               goto err_node_put;
-                       }
-               } else if (of_node_name_eq(child, "usb3-phy")) {
-                       cfg = usb_cfg;
-                       serdes = usb_serdes;
-
-                       /* Create per-lane phy */
-                       ret = qmp_combo_create(dev, child, id, serdes, cfg);
-                       if (ret) {
-                               dev_err(dev, "failed to create lane%d phy, %d\n",
-                                       id, ret);
-                               goto err_node_put;
-                       }
-
-                       /*
-                        * Register the pipe clock provided by phy.
-                        * See function description to see details of this pipe clock.
-                        */
-                       ret = phy_pipe_clk_register(qmp, child);
-                       if (ret) {
-                               dev_err(qmp->dev,
-                                       "failed to register pipe clock source\n");
-                               goto err_node_put;
-                       }
-               }
+       ret = qmp_combo_register_clocks(qmp, usb_np, dp_np);
+       if (ret)
+               goto err_node_put;
+
+       qmp->usb_phy = devm_phy_create(dev, usb_np, &qmp_combo_usb_phy_ops);
+       if (IS_ERR(qmp->usb_phy)) {
+               ret = PTR_ERR(qmp->usb_phy);
+               dev_err(dev, "failed to create USB PHY: %d\n", ret);
+               goto err_node_put;
+       }
+
+       phy_set_drvdata(qmp->usb_phy, qmp);
 
-               id++;
+       qmp->dp_phy = devm_phy_create(dev, dp_np, &qmp_combo_dp_phy_ops);
+       if (IS_ERR(qmp->dp_phy)) {
+               ret = PTR_ERR(qmp->dp_phy);
+               dev_err(dev, "failed to create DP PHY: %d\n", ret);
+               goto err_node_put;
        }
 
-       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+       phy_set_drvdata(qmp->dp_phy, qmp);
+
+       dev_set_drvdata(dev, qmp);
+
+       if (usb_np == dev->of_node)
+               phy_provider = devm_of_phy_provider_register(dev, qmp_combo_phy_xlate);
+       else
+               phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+       of_node_put(usb_np);
+       of_node_put(dp_np);
 
        return PTR_ERR_OR_ZERO(phy_provider);
 
 err_node_put:
-       of_node_put(child);
+       of_node_put(usb_np);
+       of_node_put(dp_np);
        return ret;
 }
 
+static const struct of_device_id qmp_combo_of_match_table[] = {
+       {
+               .compatible = "qcom,sc7180-qmp-usb3-dp-phy",
+               .data = &sc7180_usb3dpphy_cfg,
+       },
+       {
+               .compatible = "qcom,sc8180x-qmp-usb3-dp-phy",
+               .data = &sc8180x_usb3dpphy_cfg,
+       },
+       {
+               .compatible = "qcom,sc8280xp-qmp-usb43dp-phy",
+               .data = &sc8280xp_usb43dpphy_cfg,
+       },
+       {
+               .compatible = "qcom,sdm845-qmp-usb3-dp-phy",
+               .data = &sdm845_usb3dpphy_cfg,
+       },
+       {
+               .compatible = "qcom,sm8250-qmp-usb3-dp-phy",
+               .data = &sm8250_usb3dpphy_cfg,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, qmp_combo_of_match_table);
+
 static struct platform_driver qmp_combo_driver = {
        .probe          = qmp_combo_probe,
        .driver = {
index 461f0b5d464a8b788449111dda43bab95938a419..a088477e274f74db9b127e813b21bfc4135a12d0 100644 (file)
@@ -20,8 +20,6 @@
 #include <linux/reset.h>
 #include <linux/slab.h>
 
-#include <dt-bindings/phy/phy.h>
-
 #include "phy-qcom-qmp.h"
 
 /* QPHY_SW_RESET bit */
 #define PLL_READY_GATE_EN                      BIT(3)
 /* QPHY_PCS_STATUS bit */
 #define PHYSTATUS                              BIT(6)
-#define PHYSTATUS_4_20                         BIT(7)
 /* QPHY_COM_PCS_READY_STATUS bit */
 #define PCS_READY                              BIT(0)
 
 #define PHY_INIT_COMPLETE_TIMEOUT              10000
 #define POWER_DOWN_DELAY_US_MIN                        10
-#define POWER_DOWN_DELAY_US_MAX                        11
+#define POWER_DOWN_DELAY_US_MAX                        20
 
 struct qmp_phy_init_tbl {
        unsigned int offset;
        unsigned int val;
-       /*
-        * register part of layout ?
-        * if yes, then offset gives index in the reg-layout
-        */
-       bool in_layout;
        /*
         * mask of lanes for which this register is written
         * for cases when second lane needs different values
@@ -65,14 +57,6 @@ struct qmp_phy_init_tbl {
                .lane_mask = 0xff,      \
        }
 
-#define QMP_PHY_INIT_CFG_L(o, v)       \
-       {                               \
-               .offset = o,            \
-               .val = v,               \
-               .in_layout = true,      \
-               .lane_mask = 0xff,      \
-       }
-
 #define QMP_PHY_INIT_CFG_LANE(o, v, l) \
        {                               \
                .offset = o,            \
@@ -91,7 +75,6 @@ enum qphy_reg_layout {
        QPHY_SW_RESET,
        QPHY_START_CTRL,
        QPHY_PCS_STATUS,
-       QPHY_PCS_POWER_DOWN_CONTROL,
        /* Keep last to ensure regs_layout arrays are properly initialized */
        QPHY_LAYOUT_SIZE
 };
@@ -211,18 +194,6 @@ struct qmp_phy_cfg {
 
        /* array of registers with different offsets */
        const unsigned int *regs;
-
-       unsigned int start_ctrl;
-       unsigned int pwrdn_ctrl;
-       unsigned int mask_com_pcs_ready;
-       /* bit offset of PHYSTATUS in QPHY_PCS_STATUS register */
-       unsigned int phy_status;
-
-       /* true, if PHY needs delay after POWER_DOWN */
-       bool has_pwrdn_delay;
-       /* power_down delay in usec */
-       int pwrdn_delay_min;
-       int pwrdn_delay_max;
 };
 
 /**
@@ -335,19 +306,9 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = {
        .vreg_list              = qmp_phy_vreg_l,
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = pciephy_regs_layout,
-
-       .start_ctrl             = PCS_START | PLL_READY_GATE_EN,
-       .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
-       .mask_com_pcs_ready     = PCS_READY,
-       .phy_status             = PHYSTATUS,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
 };
 
 static void qmp_pcie_msm8996_configure_lane(void __iomem *base,
-                                       const unsigned int *regs,
                                        const struct qmp_phy_init_tbl tbl[],
                                        int num,
                                        u8 lane_mask)
@@ -362,19 +323,15 @@ static void qmp_pcie_msm8996_configure_lane(void __iomem *base,
                if (!(t->lane_mask & lane_mask))
                        continue;
 
-               if (t->in_layout)
-                       writel(t->val, base + regs[t->offset]);
-               else
-                       writel(t->val, base + t->offset);
+               writel(t->val, base + t->offset);
        }
 }
 
 static void qmp_pcie_msm8996_configure(void __iomem *base,
-                                  const unsigned int *regs,
                                   const struct qmp_phy_init_tbl tbl[],
                                   int num)
 {
-       qmp_pcie_msm8996_configure_lane(base, regs, tbl, num, 0xff);
+       qmp_pcie_msm8996_configure_lane(base, tbl, num, 0xff);
 }
 
 static int qmp_pcie_msm8996_serdes_init(struct qmp_phy *qphy)
@@ -385,19 +342,17 @@ static int qmp_pcie_msm8996_serdes_init(struct qmp_phy *qphy)
        const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl;
        int serdes_tbl_num = cfg->serdes_tbl_num;
        void __iomem *status;
-       unsigned int mask, val;
+       unsigned int val;
        int ret;
 
-       qmp_pcie_msm8996_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num);
+       qmp_pcie_msm8996_configure(serdes, serdes_tbl, serdes_tbl_num);
 
        qphy_clrbits(serdes, cfg->regs[QPHY_COM_SW_RESET], SW_RESET);
        qphy_setbits(serdes, cfg->regs[QPHY_COM_START_CONTROL],
                     SERDES_START | PCS_START);
 
        status = serdes + cfg->regs[QPHY_COM_PCS_READY_STATUS];
-       mask = cfg->mask_com_pcs_ready;
-
-       ret = readl_poll_timeout(status, val, (val & mask), 10,
+       ret = readl_poll_timeout(status, val, (val & PCS_READY), 200,
                                 PHY_INIT_COMPLETE_TIMEOUT);
        if (ret) {
                dev_err(qmp->dev,
@@ -421,7 +376,6 @@ static int qmp_pcie_msm8996_com_init(struct qmp_phy *qphy)
                return 0;
        }
 
-       /* turn on regulator supplies */
        ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
        if (ret) {
                dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
@@ -514,7 +468,7 @@ static int qmp_pcie_msm8996_power_on(struct phy *phy)
        void __iomem *rx = qphy->rx;
        void __iomem *pcs = qphy->pcs;
        void __iomem *status;
-       unsigned int mask, val, ready;
+       unsigned int val;
        int ret;
 
        qmp_pcie_msm8996_serdes_init(qphy);
@@ -533,34 +487,28 @@ static int qmp_pcie_msm8996_power_on(struct phy *phy)
        }
 
        /* Tx, Rx, and PCS configurations */
-       qmp_pcie_msm8996_configure_lane(tx, cfg->regs, cfg->tx_tbl,
-                                       cfg->tx_tbl_num, 1);
-
-       qmp_pcie_msm8996_configure_lane(rx, cfg->regs, cfg->rx_tbl,
-                                       cfg->rx_tbl_num, 1);
-
-       qmp_pcie_msm8996_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
+       qmp_pcie_msm8996_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
+       qmp_pcie_msm8996_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
+       qmp_pcie_msm8996_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
 
        /*
         * Pull out PHY from POWER DOWN state.
         * This is active low enable signal to power-down PHY.
         */
-       qphy_setbits(pcs, QPHY_V2_PCS_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
+       qphy_setbits(pcs, QPHY_V2_PCS_POWER_DOWN_CONTROL,
+                       SW_PWRDN | REFCLK_DRV_DSBL);
 
-       if (cfg->has_pwrdn_delay)
-               usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max);
+       usleep_range(POWER_DOWN_DELAY_US_MIN, POWER_DOWN_DELAY_US_MAX);
 
        /* Pull PHY out of reset state */
        qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
        /* start SerDes and Phy-Coding-Sublayer */
-       qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
+       qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL],
+                       PCS_START | PLL_READY_GATE_EN);
 
        status = pcs + cfg->regs[QPHY_PCS_STATUS];
-       mask = cfg->phy_status;
-       ready = 0;
-
-       ret = readl_poll_timeout(status, val, (val & mask) == ready, 10,
+       ret = readl_poll_timeout(status, val, !(val & PHYSTATUS), 200,
                                 PHY_INIT_COMPLETE_TIMEOUT);
        if (ret) {
                dev_err(qmp->dev, "phy initialization timed-out\n");
@@ -588,16 +536,12 @@ static int qmp_pcie_msm8996_power_off(struct phy *phy)
        qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
        /* stop SerDes and Phy-Coding-Sublayer */
-       qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
+       qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL],
+                       SERDES_START | PCS_START);
 
        /* Put PHY into POWER DOWN state: active low */
-       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_V2_PCS_POWER_DOWN_CONTROL,
-                               cfg->pwrdn_ctrl);
-       }
+       qphy_clrbits(qphy->pcs, QPHY_V2_PCS_POWER_DOWN_CONTROL,
+                       SW_PWRDN | REFCLK_DRV_DSBL);
 
        return 0;
 }
@@ -777,7 +721,7 @@ static int qmp_pcie_msm8996_create(struct device *dev, struct device_node *np, i
        qphy->cfg = cfg;
        qphy->serdes = serdes;
        /*
-        * Get memory resources for each phy lane:
+        * Get memory resources for each PHY:
         * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2.
         */
        qphy->tx = devm_of_iomap(dev, np, 0, NULL);
@@ -851,12 +795,10 @@ static int qmp_pcie_msm8996_probe(struct platform_device *pdev)
        qmp->dev = dev;
        dev_set_drvdata(dev, qmp);
 
-       /* Get the specific init parameters of QMP phy */
        cfg = of_device_get_match_data(dev);
        if (!cfg)
                return -EINVAL;
 
-       /* per PHY serdes; usually located at base address */
        serdes = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(serdes))
                return PTR_ERR(serdes);
@@ -875,8 +817,7 @@ static int qmp_pcie_msm8996_probe(struct platform_device *pdev)
 
        ret = qmp_pcie_msm8996_vreg_init(dev, cfg);
        if (ret)
-               return dev_err_probe(dev, ret,
-                                    "failed to get regulator supplies\n");
+               return ret;
 
        num = of_get_available_child_count(dev->of_node);
        /* do we have a rogue child node ? */
index 5be5348fbb26b023039e254451045c6ce0af6b8e..1b136a87053f881482cb4966da1edfbfd1472920 100644 (file)
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
+#include <linux/phy/pcie.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>
 
-#include <dt-bindings/phy/phy.h>
-
 #include "phy-qcom-qmp.h"
 
 /* QPHY_SW_RESET bit */
 struct qmp_phy_init_tbl {
        unsigned int offset;
        unsigned int val;
-       /*
-        * register part of layout ?
-        * if yes, then offset gives index in the reg-layout
-        */
-       bool in_layout;
        /*
         * mask of lanes for which this register is written
         * for cases when second lane needs different values
@@ -60,14 +56,6 @@ struct qmp_phy_init_tbl {
                .lane_mask = 0xff,      \
        }
 
-#define QMP_PHY_INIT_CFG_L(o, v)       \
-       {                               \
-               .offset = o,            \
-               .val = v,               \
-               .in_layout = true,      \
-               .lane_mask = 0xff,      \
-       }
-
 #define QMP_PHY_INIT_CFG_LANE(o, v, l) \
        {                               \
                .offset = o,            \
@@ -77,11 +65,6 @@ struct qmp_phy_init_tbl {
 
 /* set of registers with offsets different per-PHY */
 enum qphy_reg_layout {
-       /* Common block control registers */
-       QPHY_COM_SW_RESET,
-       QPHY_COM_POWER_DOWN_CONTROL,
-       QPHY_COM_START_CONTROL,
-       QPHY_COM_PCS_READY_STATUS,
        /* PCS registers */
        QPHY_SW_RESET,
        QPHY_START_CTRL,
@@ -99,25 +82,24 @@ static const unsigned int ipq_pciephy_gen3_regs_layout[QPHY_LAYOUT_SIZE] = {
 };
 
 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,
-       [QPHY_COM_PCS_READY_STATUS]     = 0x448,
        [QPHY_SW_RESET]                 = 0x00,
        [QPHY_START_CTRL]               = 0x08,
        [QPHY_PCS_STATUS]               = 0x174,
+       [QPHY_PCS_POWER_DOWN_CONTROL]   = 0x04,
 };
 
 static const unsigned int sdm845_qmp_pciephy_regs_layout[QPHY_LAYOUT_SIZE] = {
        [QPHY_SW_RESET]                 = 0x00,
        [QPHY_START_CTRL]               = 0x08,
        [QPHY_PCS_STATUS]               = 0x174,
+       [QPHY_PCS_POWER_DOWN_CONTROL]   = 0x04,
 };
 
 static const unsigned int sdm845_qhp_pciephy_regs_layout[QPHY_LAYOUT_SIZE] = {
        [QPHY_SW_RESET]                 = 0x00,
        [QPHY_START_CTRL]               = 0x08,
        [QPHY_PCS_STATUS]               = 0x2ac,
+       [QPHY_PCS_POWER_DOWN_CONTROL]   = 0x04,
 };
 
 static const unsigned int sm8250_pcie_regs_layout[QPHY_LAYOUT_SIZE] = {
@@ -393,8 +375,6 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V2_PCS_RX_SIGDET_LVL, 0x99),
        QMP_PHY_INIT_CFG(QPHY_V2_PCS_TXDEEMPH_M6DB_V0, 0x15),
        QMP_PHY_INIT_CFG(QPHY_V2_PCS_TXDEEMPH_M3P5DB_V0, 0xe),
-       QMP_PHY_INIT_CFG_L(QPHY_SW_RESET, 0x0),
-       QMP_PHY_INIT_CFG_L(QPHY_START_CTRL, 0x3),
 };
 
 static const struct qmp_phy_init_tbl ipq8074_pcie_gen3_serdes_tbl[] = {
@@ -505,6 +485,13 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_gen3_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V4_PCS_FLL_CNTRL1, 0x01),
        QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_H, 0x0),
        QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_L, 0x1),
+       QMP_PHY_INIT_CFG(QPHY_V4_PCS_G12S1_TXDEEMPH_M3P5DB, 0x10),
+       QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_DCC_CAL_CONFIG, 0x01),
+       QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa),
+       QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x0d),
+};
+
+static const struct qmp_phy_init_tbl ipq8074_pcie_gen3_pcs_misc_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_ACTIONS, 0x0),
        QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H, 0x00),
        QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
@@ -517,11 +504,7 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_gen3_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_MODE2_CONFIG2, 0x50),
        QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_MODE2_CONFIG4, 0x1a),
        QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5, 0x6),
-       QMP_PHY_INIT_CFG(QPHY_V4_PCS_G12S1_TXDEEMPH_M3P5DB, 0x10),
        QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
-       QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_DCC_CAL_CONFIG, 0x01),
-       QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa),
-       QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x0d),
 };
 
 static const struct qmp_phy_init_tbl sdm845_qmp_pcie_serdes_tbl[] = {
@@ -854,6 +837,147 @@ static const struct qmp_phy_init_tbl sc8180x_qmp_pcie_pcs_misc_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
 };
 
+static const struct qmp_phy_init_tbl sc8280xp_qmp_pcie_serdes_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_EN_CENTER, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER1, 0x31),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER2, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE0, 0xde),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE0, 0x07),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE1, 0x4c),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE1, 0x06),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_ENABLE1, 0x90),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0x0f),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE0, 0x06),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE1, 0x06),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE1, 0x16),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE1, 0x36),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x08),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_EN, 0x42),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x0a),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x1a),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE1, 0x14),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE1, 0x34),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE0, 0x82),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE1, 0x68),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START1_MODE0, 0x55),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START2_MODE0, 0x55),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START3_MODE0, 0x03),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START1_MODE1, 0xab),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START2_MODE1, 0xaa),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START3_MODE1, 0x02),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_MAP, 0x02),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE1_MODE0, 0x24),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE1_MODE1, 0xb4),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE2_MODE1, 0x03),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_SELECT, 0x34),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE1, 0x08),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xb9),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0x94),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x18),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, 0x11),
+};
+
+static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x1_pcie_rc_serdes_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_BUF_ENABLE, 0x07),
+};
+
+static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x2_pcie_rc_serdes_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
+};
+
+static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x4_pcie_serdes_4ln_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x1c),
+};
+
+static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x1_pcie_tx_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V5_TX_PI_QEC_CTRL, 0x20),
+       QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0x75),
+       QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_4, 0x3f),
+       QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x1d),
+       QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0c),
+};
+
+static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x1_pcie_rx_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_LOW, 0x7f),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH, 0xff),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xbf),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x3f),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xd8),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_LOW, 0xdc),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH, 0xdc),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH2, 0x5c),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x34),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xa6),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_TX_ADAPT_POST_THRESH, 0xf0),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_10_HIGH3, 0x34),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x07),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_GM_CAL, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH1, 0x08),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH2, 0x08),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0xf0),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
+};
+
+static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x1_pcie_pcs_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_REFGEN_REQ_CONFIG1, 0x05),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_RX_SIGDET_LVL, 0x77),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_RATE_SLEW_CNTRL1, 0x0b),
+};
+
+static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x1_pcie_pcs_misc_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_INT_AUX_CLK_CONFIG1, 0x00),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_EQ_CONFIG2, 0x0f),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
+};
+
+static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x2_pcie_tx_tbl[] = {
+       QMP_PHY_INIT_CFG_LANE(QSERDES_V5_TX_PI_QEC_CTRL, 0x02, 1),
+       QMP_PHY_INIT_CFG_LANE(QSERDES_V5_TX_PI_QEC_CTRL, 0x04, 2),
+       QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0xd5),
+       QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_4, 0x3f),
+       QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x11),
+       QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0c),
+};
+
+static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x2_pcie_rx_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_LOW, 0x7f),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH, 0xff),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0x7f),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x34),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xd8),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_LOW, 0xdc),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH, 0xdc),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH2, 0x5c),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x34),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xa6),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_10_HIGH3, 0x34),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x0f),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_GM_CAL, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH1, 0x08),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH2, 0x08),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0xf0),
+       QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
+};
+
+static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x2_pcie_pcs_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_REFGEN_REQ_CONFIG1, 0x05),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_RX_SIGDET_LVL, 0x88),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_RATE_SLEW_CNTRL1, 0x0b),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_EQ_CONFIG3, 0x0f),
+};
+
+static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x2_pcie_pcs_misc_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG2, 0x1d),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG4, 0x07),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
+       QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00),
+};
+
 static const struct qmp_phy_init_tbl sm8250_qmp_pcie_serdes_tbl[] = {
        QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08),
        QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34),
@@ -1184,15 +1308,29 @@ static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_pcs_misc_tbl[] = {
 };
 
 static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_serdes_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0x0f),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_EN, 0x46),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_CFG, 0x04),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_MAP, 0x02),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x12),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x0a),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE1, 0x04),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MISC1, 0x88),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_CONFIG, 0x06),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MODE, 0x14),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_DC_LEVEL_CTRL, 0x0f),
+};
+
+static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_rc_serdes_tbl[] = {
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER1, 0x31),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER2, 0x01),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE0, 0xde),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE0, 0x07),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE1, 0x97),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE1, 0x0c),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_ENABLE1, 0x90),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0x0f),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE0, 0x06),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE1, 0x06),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16),
@@ -1200,8 +1338,6 @@ static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_serdes_tbl[] = {
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE1, 0x36),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x08),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_EN, 0x46),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_CFG, 0x04),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x0a),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x1a),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE1, 0x14),
@@ -1214,17 +1350,8 @@ static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_serdes_tbl[] = {
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START1_MODE1, 0x55),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START2_MODE1, 0x55),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START3_MODE1, 0x05),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_MAP, 0x02),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_SELECT, 0x34),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x12),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x0a),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE1, 0x04),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MISC1, 0x88),
        QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORE_CLK_EN, 0x20),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_CONFIG, 0x06),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MODE, 0x14),
-       QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_DC_LEVEL_CTRL, 0x0f),
 };
 
 static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_tx_tbl[] = {
@@ -1285,46 +1412,95 @@ static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_rx_tbl[] = {
 };
 
 static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_pcs_tbl[] = {
-       QMP_PHY_INIT_CFG(QPHY_V5_PCS_EQ_CONFIG2, 0x16),
-       QMP_PHY_INIT_CFG(QPHY_V5_PCS_EQ_CONFIG3, 0x22),
-       QMP_PHY_INIT_CFG(QPHY_V5_PCS_G3S2_PRE_GAIN, 0x2e),
-       QMP_PHY_INIT_CFG(QPHY_V5_PCS_RX_SIGDET_LVL, 0x99),
+       QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG4, 0x16),
+       QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG5, 0x22),
+       QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_G3S2_PRE_GAIN, 0x2e),
+       QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_RX_SIGDET_LVL, 0x99),
 };
 
 static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_pcs_misc_tbl[] = {
-       QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
-       QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00),
        QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG5, 0x02),
        QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_EQ_CONFIG1, 0x16),
        QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_RX_MARGINING_CONFIG3, 0x28),
        QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_PRE_GAIN, 0x2e),
 };
 
+static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_rc_pcs_misc_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
+       QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00),
+       QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_PRESET_P10_POST, 0x00),
+};
+
+static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_ep_serdes_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_BG_TIMER, 0x02),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYS_CLK_CTRL, 0x07),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE0, 0x27),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE1, 0x0a),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x17),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE1, 0x19),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE1, 0x03),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE0, 0xff),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x04),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE1, 0xff),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE1, 0x09),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE0, 0x19),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE1, 0x28),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN0_MODE0, 0xfb),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN1_MODE0, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN0_MODE1, 0xfb),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN1_MODE1, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORE_CLK_EN, 0x60),
+};
+
+static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_ep_pcs_misc_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5, 0x08),
+};
+
+struct qmp_pcie_offsets {
+       u16 serdes;
+       u16 pcs;
+       u16 pcs_misc;
+       u16 tx;
+       u16 rx;
+       u16 tx2;
+       u16 rx2;
+};
+
+struct qmp_phy_cfg_tbls {
+       const struct qmp_phy_init_tbl *serdes;
+       int serdes_num;
+       const struct qmp_phy_init_tbl *tx;
+       int tx_num;
+       const struct qmp_phy_init_tbl *rx;
+       int rx_num;
+       const struct qmp_phy_init_tbl *pcs;
+       int pcs_num;
+       const struct qmp_phy_init_tbl *pcs_misc;
+       int pcs_misc_num;
+};
+
 /* struct qmp_phy_cfg - per-PHY initialization config */
 struct qmp_phy_cfg {
        int lanes;
 
-       /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
-       const struct qmp_phy_init_tbl *serdes_tbl;
-       int serdes_tbl_num;
-       const struct qmp_phy_init_tbl *serdes_tbl_sec;
-       int serdes_tbl_num_sec;
-       const struct qmp_phy_init_tbl *tx_tbl;
-       int tx_tbl_num;
-       const struct qmp_phy_init_tbl *tx_tbl_sec;
-       int tx_tbl_num_sec;
-       const struct qmp_phy_init_tbl *rx_tbl;
-       int rx_tbl_num;
-       const struct qmp_phy_init_tbl *rx_tbl_sec;
-       int rx_tbl_num_sec;
-       const struct qmp_phy_init_tbl *pcs_tbl;
-       int pcs_tbl_num;
-       const struct qmp_phy_init_tbl *pcs_tbl_sec;
-       int pcs_tbl_num_sec;
-       const struct qmp_phy_init_tbl *pcs_misc_tbl;
-       int pcs_misc_tbl_num;
-       const struct qmp_phy_init_tbl *pcs_misc_tbl_sec;
-       int pcs_misc_tbl_num_sec;
+       const struct qmp_pcie_offsets *offsets;
+
+       /* Main init sequence for PHY blocks - serdes, tx, rx, pcs */
+       const struct qmp_phy_cfg_tbls tbls;
+       /*
+        * Additional init sequences for PHY blocks, providing additional
+        * register programming. They are used for providing separate sequences
+        * for the Root Complex and End Point use cases.
+        *
+        * If EP mode is not supported, both tables can be left unset.
+        */
+       const struct qmp_phy_cfg_tbls *tbls_rc;
+       const struct qmp_phy_cfg_tbls *tbls_ep;
+
+       const struct qmp_phy_init_tbl *serdes_4ln_tbl;
+       int serdes_4ln_num;
 
        /* clock ids to be requested */
        const char * const *clk_list;
@@ -1339,69 +1515,43 @@ struct qmp_phy_cfg {
        /* array of registers with different offsets */
        const unsigned int *regs;
 
-       unsigned int start_ctrl;
        unsigned int pwrdn_ctrl;
        /* bit offset of PHYSTATUS in QPHY_PCS_STATUS register */
        unsigned int phy_status;
 
-       /* true, if PHY needs delay after POWER_DOWN */
-       bool has_pwrdn_delay;
-       /* power_down delay in usec */
-       int pwrdn_delay_min;
-       int pwrdn_delay_max;
+       bool skip_start_delay;
 
        /* QMP PHY pipe clock interface rate */
        unsigned long pipe_clock_rate;
 };
 
-/**
- * struct qmp_phy - per-lane phy descriptor
- *
- * @phy: generic phy
- * @cfg: phy specific configuration
- * @serdes: iomapped memory space for phy's serdes (i.e. PLL)
- * @tx: iomapped memory space for lane's tx
- * @rx: iomapped memory space for lane's rx
- * @pcs: iomapped memory space for lane's pcs
- * @tx2: iomapped memory space for second lane's tx (in dual lane PHYs)
- * @rx2: iomapped memory space for second lane's rx (in dual lane PHYs)
- * @pcs_misc: iomapped memory space for lane's pcs_misc
- * @pipe_clk: pipe clock
- * @qmp: QMP phy to which this lane belongs
- */
-struct qmp_phy {
-       struct phy *phy;
+struct qmp_pcie {
+       struct device *dev;
+
        const struct qmp_phy_cfg *cfg;
+       bool tcsr_4ln_config;
+
        void __iomem *serdes;
+       void __iomem *pcs;
+       void __iomem *pcs_misc;
        void __iomem *tx;
        void __iomem *rx;
-       void __iomem *pcs;
        void __iomem *tx2;
        void __iomem *rx2;
-       void __iomem *pcs_misc;
-       struct clk *pipe_clk;
-       struct qcom_qmp *qmp;
-};
 
-/**
- * struct qcom_qmp - structure holding QMP phy block attributes
- *
- * @dev: device
- *
- * @clks: array of clocks required by phy
- * @resets: array of resets required by phy
- * @vregs: regulator supplies bulk data
- *
- * @phys: array of per-lane phy descriptors
- */
-struct qcom_qmp {
-       struct device *dev;
+       void __iomem *port_b;
 
        struct clk_bulk_data *clks;
+       struct clk_bulk_data pipe_clks[2];
+       int num_pipe_clks;
+
        struct reset_control_bulk_data *resets;
        struct regulator_bulk_data *vregs;
 
-       struct qmp_phy **phys;
+       struct phy *phy;
+       int mode;
+
+       struct clk_fixed_rate pipe_clk_fixed;
 };
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -1429,10 +1579,17 @@ static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val)
 }
 
 /* list of clocks required by phy */
+static const char * const ipq8074_pciephy_clk_l[] = {
+       "aux", "cfg_ahb",
+};
+
 static const char * const msm8996_phy_clk_l[] = {
        "aux", "cfg_ahb", "ref",
 };
 
+static const char * const sc8280xp_pciephy_clk_l[] = {
+       "aux", "cfg_ahb", "ref", "rchng",
+};
 
 static const char * const sdm845_pciephy_clk_l[] = {
        "aux", "cfg_ahb", "ref", "refgen",
@@ -1443,10 +1600,6 @@ static const char * const qmp_phy_vreg_l[] = {
        "vdda-phy", "vdda-pll",
 };
 
-static const char * const ipq8074_pciephy_clk_l[] = {
-       "aux", "cfg_ahb",
-};
-
 /* list of resets */
 static const char * const ipq8074_pciephy_reset_l[] = {
        "phy", "common",
@@ -1456,17 +1609,29 @@ static const char * const sdm845_pciephy_reset_l[] = {
        "phy",
 };
 
+static const struct qmp_pcie_offsets qmp_pcie_offsets_v5 = {
+       .serdes         = 0,
+       .pcs            = 0x0200,
+       .pcs_misc       = 0x0600,
+       .tx             = 0x0e00,
+       .rx             = 0x1000,
+       .tx2            = 0x1600,
+       .rx2            = 0x1800,
+};
+
 static const struct qmp_phy_cfg ipq8074_pciephy_cfg = {
        .lanes                  = 1,
 
-       .serdes_tbl             = ipq8074_pcie_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(ipq8074_pcie_serdes_tbl),
-       .tx_tbl                 = ipq8074_pcie_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(ipq8074_pcie_tx_tbl),
-       .rx_tbl                 = ipq8074_pcie_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(ipq8074_pcie_rx_tbl),
-       .pcs_tbl                = ipq8074_pcie_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(ipq8074_pcie_pcs_tbl),
+       .tbls = {
+               .serdes         = ipq8074_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(ipq8074_pcie_serdes_tbl),
+               .tx             = ipq8074_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(ipq8074_pcie_tx_tbl),
+               .rx             = ipq8074_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(ipq8074_pcie_rx_tbl),
+               .pcs            = ipq8074_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(ipq8074_pcie_pcs_tbl),
+       },
        .clk_list               = ipq8074_pciephy_clk_l,
        .num_clks               = ARRAY_SIZE(ipq8074_pciephy_clk_l),
        .reset_list             = ipq8074_pciephy_reset_l,
@@ -1475,26 +1640,25 @@ static const struct qmp_phy_cfg ipq8074_pciephy_cfg = {
        .num_vregs              = 0,
        .regs                   = pciephy_regs_layout,
 
-       .start_ctrl             = SERDES_START | PCS_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
        .phy_status             = PHYSTATUS,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = 995,          /* us */
-       .pwrdn_delay_max        = 1005,         /* us */
 };
 
 static const struct qmp_phy_cfg ipq8074_pciephy_gen3_cfg = {
        .lanes                  = 1,
 
-       .serdes_tbl             = ipq8074_pcie_gen3_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(ipq8074_pcie_gen3_serdes_tbl),
-       .tx_tbl                 = ipq8074_pcie_gen3_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(ipq8074_pcie_gen3_tx_tbl),
-       .rx_tbl                 = ipq8074_pcie_gen3_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(ipq8074_pcie_gen3_rx_tbl),
-       .pcs_tbl                = ipq8074_pcie_gen3_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(ipq8074_pcie_gen3_pcs_tbl),
+       .tbls = {
+               .serdes         = ipq8074_pcie_gen3_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(ipq8074_pcie_gen3_serdes_tbl),
+               .tx             = ipq8074_pcie_gen3_tx_tbl,
+               .tx_num         = ARRAY_SIZE(ipq8074_pcie_gen3_tx_tbl),
+               .rx             = ipq8074_pcie_gen3_rx_tbl,
+               .rx_num         = ARRAY_SIZE(ipq8074_pcie_gen3_rx_tbl),
+               .pcs            = ipq8074_pcie_gen3_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(ipq8074_pcie_gen3_pcs_tbl),
+               .pcs_misc       = ipq8074_pcie_gen3_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(ipq8074_pcie_gen3_pcs_misc_tbl),
+       },
        .clk_list               = ipq8074_pciephy_clk_l,
        .num_clks               = ARRAY_SIZE(ipq8074_pciephy_clk_l),
        .reset_list             = ipq8074_pciephy_reset_l,
@@ -1503,12 +1667,8 @@ static const struct qmp_phy_cfg ipq8074_pciephy_gen3_cfg = {
        .num_vregs              = 0,
        .regs                   = ipq_pciephy_gen3_regs_layout,
 
-       .start_ctrl             = SERDES_START | PCS_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = 995,          /* us */
-       .pwrdn_delay_max        = 1005,         /* us */
+       .phy_status             = PHYSTATUS,
 
        .pipe_clock_rate        = 250000000,
 };
@@ -1516,16 +1676,18 @@ static const struct qmp_phy_cfg ipq8074_pciephy_gen3_cfg = {
 static const struct qmp_phy_cfg ipq6018_pciephy_cfg = {
        .lanes                  = 1,
 
-       .serdes_tbl             = ipq6018_pcie_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(ipq6018_pcie_serdes_tbl),
-       .tx_tbl                 = ipq6018_pcie_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(ipq6018_pcie_tx_tbl),
-       .rx_tbl                 = ipq6018_pcie_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(ipq6018_pcie_rx_tbl),
-       .pcs_tbl                = ipq6018_pcie_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(ipq6018_pcie_pcs_tbl),
-       .pcs_misc_tbl           = ipq6018_pcie_pcs_misc_tbl,
-       .pcs_misc_tbl_num       = ARRAY_SIZE(ipq6018_pcie_pcs_misc_tbl),
+       .tbls = {
+               .serdes         = ipq6018_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(ipq6018_pcie_serdes_tbl),
+               .tx             = ipq6018_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(ipq6018_pcie_tx_tbl),
+               .rx             = ipq6018_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(ipq6018_pcie_rx_tbl),
+               .pcs            = ipq6018_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(ipq6018_pcie_pcs_tbl),
+               .pcs_misc       = ipq6018_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(ipq6018_pcie_pcs_misc_tbl),
+       },
        .clk_list               = ipq8074_pciephy_clk_l,
        .num_clks               = ARRAY_SIZE(ipq8074_pciephy_clk_l),
        .reset_list             = ipq8074_pciephy_reset_l,
@@ -1534,27 +1696,25 @@ static const struct qmp_phy_cfg ipq6018_pciephy_cfg = {
        .num_vregs              = 0,
        .regs                   = ipq_pciephy_gen3_regs_layout,
 
-       .start_ctrl             = SERDES_START | PCS_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = 995,          /* us */
-       .pwrdn_delay_max        = 1005,         /* us */
+       .phy_status             = PHYSTATUS,
 };
 
 static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = {
        .lanes                  = 1,
 
-       .serdes_tbl             = sdm845_qmp_pcie_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(sdm845_qmp_pcie_serdes_tbl),
-       .tx_tbl                 = sdm845_qmp_pcie_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(sdm845_qmp_pcie_tx_tbl),
-       .rx_tbl                 = sdm845_qmp_pcie_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(sdm845_qmp_pcie_rx_tbl),
-       .pcs_tbl                = sdm845_qmp_pcie_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(sdm845_qmp_pcie_pcs_tbl),
-       .pcs_misc_tbl           = sdm845_qmp_pcie_pcs_misc_tbl,
-       .pcs_misc_tbl_num       = ARRAY_SIZE(sdm845_qmp_pcie_pcs_misc_tbl),
+       .tbls = {
+               .serdes         = sdm845_qmp_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sdm845_qmp_pcie_serdes_tbl),
+               .tx             = sdm845_qmp_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sdm845_qmp_pcie_tx_tbl),
+               .rx             = sdm845_qmp_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sdm845_qmp_pcie_rx_tbl),
+               .pcs            = sdm845_qmp_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sdm845_qmp_pcie_pcs_tbl),
+               .pcs_misc       = sdm845_qmp_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sdm845_qmp_pcie_pcs_misc_tbl),
+       },
        .clk_list               = sdm845_pciephy_clk_l,
        .num_clks               = ARRAY_SIZE(sdm845_pciephy_clk_l),
        .reset_list             = sdm845_pciephy_reset_l,
@@ -1563,26 +1723,23 @@ static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sdm845_qmp_pciephy_regs_layout,
 
-       .start_ctrl             = PCS_START | SERDES_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
        .phy_status             = PHYSTATUS,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = 995,          /* us */
-       .pwrdn_delay_max        = 1005,         /* us */
 };
 
 static const struct qmp_phy_cfg sdm845_qhp_pciephy_cfg = {
        .lanes                  = 1,
 
-       .serdes_tbl             = sdm845_qhp_pcie_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(sdm845_qhp_pcie_serdes_tbl),
-       .tx_tbl                 = sdm845_qhp_pcie_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(sdm845_qhp_pcie_tx_tbl),
-       .rx_tbl                 = sdm845_qhp_pcie_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(sdm845_qhp_pcie_rx_tbl),
-       .pcs_tbl                = sdm845_qhp_pcie_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(sdm845_qhp_pcie_pcs_tbl),
+       .tbls = {
+               .serdes         = sdm845_qhp_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sdm845_qhp_pcie_serdes_tbl),
+               .tx             = sdm845_qhp_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sdm845_qhp_pcie_tx_tbl),
+               .rx             = sdm845_qhp_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sdm845_qhp_pcie_rx_tbl),
+               .pcs            = sdm845_qhp_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sdm845_qhp_pcie_pcs_tbl),
+       },
        .clk_list               = sdm845_pciephy_clk_l,
        .num_clks               = ARRAY_SIZE(sdm845_pciephy_clk_l),
        .reset_list             = sdm845_pciephy_reset_l,
@@ -1591,36 +1748,35 @@ static const struct qmp_phy_cfg sdm845_qhp_pciephy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sdm845_qhp_pciephy_regs_layout,
 
-       .start_ctrl             = PCS_START | SERDES_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
        .phy_status             = PHYSTATUS,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = 995,          /* us */
-       .pwrdn_delay_max        = 1005,         /* us */
 };
 
 static const struct qmp_phy_cfg sm8250_qmp_gen3x1_pciephy_cfg = {
        .lanes                  = 1,
 
-       .serdes_tbl             = sm8250_qmp_pcie_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(sm8250_qmp_pcie_serdes_tbl),
-       .serdes_tbl_sec         = sm8250_qmp_gen3x1_pcie_serdes_tbl,
-       .serdes_tbl_num_sec     = ARRAY_SIZE(sm8250_qmp_gen3x1_pcie_serdes_tbl),
-       .tx_tbl                 = sm8250_qmp_pcie_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(sm8250_qmp_pcie_tx_tbl),
-       .rx_tbl                 = sm8250_qmp_pcie_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(sm8250_qmp_pcie_rx_tbl),
-       .rx_tbl_sec             = sm8250_qmp_gen3x1_pcie_rx_tbl,
-       .rx_tbl_num_sec         = ARRAY_SIZE(sm8250_qmp_gen3x1_pcie_rx_tbl),
-       .pcs_tbl                = sm8250_qmp_pcie_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(sm8250_qmp_pcie_pcs_tbl),
-       .pcs_tbl_sec            = sm8250_qmp_gen3x1_pcie_pcs_tbl,
-       .pcs_tbl_num_sec                = ARRAY_SIZE(sm8250_qmp_gen3x1_pcie_pcs_tbl),
-       .pcs_misc_tbl           = sm8250_qmp_pcie_pcs_misc_tbl,
-       .pcs_misc_tbl_num       = ARRAY_SIZE(sm8250_qmp_pcie_pcs_misc_tbl),
-       .pcs_misc_tbl_sec               = sm8250_qmp_gen3x1_pcie_pcs_misc_tbl,
-       .pcs_misc_tbl_num_sec   = ARRAY_SIZE(sm8250_qmp_gen3x1_pcie_pcs_misc_tbl),
+       .tbls = {
+               .serdes         = sm8250_qmp_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sm8250_qmp_pcie_serdes_tbl),
+               .tx             = sm8250_qmp_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sm8250_qmp_pcie_tx_tbl),
+               .rx             = sm8250_qmp_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sm8250_qmp_pcie_rx_tbl),
+               .pcs            = sm8250_qmp_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sm8250_qmp_pcie_pcs_tbl),
+               .pcs_misc       = sm8250_qmp_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sm8250_qmp_pcie_pcs_misc_tbl),
+       },
+       .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+               .serdes         = sm8250_qmp_gen3x1_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sm8250_qmp_gen3x1_pcie_serdes_tbl),
+               .rx             = sm8250_qmp_gen3x1_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sm8250_qmp_gen3x1_pcie_rx_tbl),
+               .pcs            = sm8250_qmp_gen3x1_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sm8250_qmp_gen3x1_pcie_pcs_tbl),
+               .pcs_misc       = sm8250_qmp_gen3x1_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sm8250_qmp_gen3x1_pcie_pcs_misc_tbl),
+       },
        .clk_list               = sdm845_pciephy_clk_l,
        .num_clks               = ARRAY_SIZE(sdm845_pciephy_clk_l),
        .reset_list             = sdm845_pciephy_reset_l,
@@ -1629,36 +1785,35 @@ static const struct qmp_phy_cfg sm8250_qmp_gen3x1_pciephy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sm8250_pcie_regs_layout,
 
-       .start_ctrl             = PCS_START | SERDES_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
        .phy_status             = PHYSTATUS,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = 995,          /* us */
-       .pwrdn_delay_max        = 1005,         /* us */
 };
 
 static const struct qmp_phy_cfg sm8250_qmp_gen3x2_pciephy_cfg = {
        .lanes                  = 2,
 
-       .serdes_tbl             = sm8250_qmp_pcie_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(sm8250_qmp_pcie_serdes_tbl),
-       .tx_tbl                 = sm8250_qmp_pcie_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(sm8250_qmp_pcie_tx_tbl),
-       .tx_tbl_sec             = sm8250_qmp_gen3x2_pcie_tx_tbl,
-       .tx_tbl_num_sec         = ARRAY_SIZE(sm8250_qmp_gen3x2_pcie_tx_tbl),
-       .rx_tbl                 = sm8250_qmp_pcie_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(sm8250_qmp_pcie_rx_tbl),
-       .rx_tbl_sec             = sm8250_qmp_gen3x2_pcie_rx_tbl,
-       .rx_tbl_num_sec         = ARRAY_SIZE(sm8250_qmp_gen3x2_pcie_rx_tbl),
-       .pcs_tbl                = sm8250_qmp_pcie_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(sm8250_qmp_pcie_pcs_tbl),
-       .pcs_tbl_sec            = sm8250_qmp_gen3x2_pcie_pcs_tbl,
-       .pcs_tbl_num_sec                = ARRAY_SIZE(sm8250_qmp_gen3x2_pcie_pcs_tbl),
-       .pcs_misc_tbl           = sm8250_qmp_pcie_pcs_misc_tbl,
-       .pcs_misc_tbl_num       = ARRAY_SIZE(sm8250_qmp_pcie_pcs_misc_tbl),
-       .pcs_misc_tbl_sec               = sm8250_qmp_gen3x2_pcie_pcs_misc_tbl,
-       .pcs_misc_tbl_num_sec   = ARRAY_SIZE(sm8250_qmp_gen3x2_pcie_pcs_misc_tbl),
+       .tbls = {
+               .serdes         = sm8250_qmp_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sm8250_qmp_pcie_serdes_tbl),
+               .tx             = sm8250_qmp_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sm8250_qmp_pcie_tx_tbl),
+               .rx             = sm8250_qmp_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sm8250_qmp_pcie_rx_tbl),
+               .pcs            = sm8250_qmp_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sm8250_qmp_pcie_pcs_tbl),
+               .pcs_misc       = sm8250_qmp_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sm8250_qmp_pcie_pcs_misc_tbl),
+       },
+       .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+               .tx             = sm8250_qmp_gen3x2_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sm8250_qmp_gen3x2_pcie_tx_tbl),
+               .rx             = sm8250_qmp_gen3x2_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sm8250_qmp_gen3x2_pcie_rx_tbl),
+               .pcs            = sm8250_qmp_gen3x2_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sm8250_qmp_gen3x2_pcie_pcs_tbl),
+               .pcs_misc       = sm8250_qmp_gen3x2_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sm8250_qmp_gen3x2_pcie_pcs_misc_tbl),
+       },
        .clk_list               = sdm845_pciephy_clk_l,
        .num_clks               = ARRAY_SIZE(sdm845_pciephy_clk_l),
        .reset_list             = sdm845_pciephy_reset_l,
@@ -1667,26 +1822,23 @@ static const struct qmp_phy_cfg sm8250_qmp_gen3x2_pciephy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sm8250_pcie_regs_layout,
 
-       .start_ctrl             = PCS_START | SERDES_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
        .phy_status             = PHYSTATUS,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = 995,          /* us */
-       .pwrdn_delay_max        = 1005,         /* us */
 };
 
 static const struct qmp_phy_cfg msm8998_pciephy_cfg = {
        .lanes                  = 1,
 
-       .serdes_tbl             = msm8998_pcie_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(msm8998_pcie_serdes_tbl),
-       .tx_tbl                 = msm8998_pcie_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(msm8998_pcie_tx_tbl),
-       .rx_tbl                 = msm8998_pcie_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(msm8998_pcie_rx_tbl),
-       .pcs_tbl                = msm8998_pcie_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(msm8998_pcie_pcs_tbl),
+       .tbls = {
+               .serdes         = msm8998_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(msm8998_pcie_serdes_tbl),
+               .tx             = msm8998_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(msm8998_pcie_tx_tbl),
+               .rx             = msm8998_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(msm8998_pcie_rx_tbl),
+               .pcs            = msm8998_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(msm8998_pcie_pcs_tbl),
+       },
        .clk_list               = msm8996_phy_clk_l,
        .num_clks               = ARRAY_SIZE(msm8996_phy_clk_l),
        .reset_list             = ipq8074_pciephy_reset_l,
@@ -1695,24 +1847,27 @@ static const struct qmp_phy_cfg msm8998_pciephy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = pciephy_regs_layout,
 
-       .start_ctrl             = SERDES_START | PCS_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
        .phy_status             = PHYSTATUS,
+
+       .skip_start_delay       = true,
 };
 
 static const struct qmp_phy_cfg sc8180x_pciephy_cfg = {
        .lanes                  = 1,
 
-       .serdes_tbl             = sc8180x_qmp_pcie_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(sc8180x_qmp_pcie_serdes_tbl),
-       .tx_tbl                 = sc8180x_qmp_pcie_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(sc8180x_qmp_pcie_tx_tbl),
-       .rx_tbl                 = sc8180x_qmp_pcie_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(sc8180x_qmp_pcie_rx_tbl),
-       .pcs_tbl                = sc8180x_qmp_pcie_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(sc8180x_qmp_pcie_pcs_tbl),
-       .pcs_misc_tbl           = sc8180x_qmp_pcie_pcs_misc_tbl,
-       .pcs_misc_tbl_num       = ARRAY_SIZE(sc8180x_qmp_pcie_pcs_misc_tbl),
+       .tbls = {
+               .serdes         = sc8180x_qmp_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sc8180x_qmp_pcie_serdes_tbl),
+               .tx             = sc8180x_qmp_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sc8180x_qmp_pcie_tx_tbl),
+               .rx             = sc8180x_qmp_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sc8180x_qmp_pcie_rx_tbl),
+               .pcs            = sc8180x_qmp_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sc8180x_qmp_pcie_pcs_tbl),
+               .pcs_misc       = sc8180x_qmp_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sc8180x_qmp_pcie_pcs_misc_tbl),
+       },
        .clk_list               = sdm845_pciephy_clk_l,
        .num_clks               = ARRAY_SIZE(sdm845_pciephy_clk_l),
        .reset_list             = sdm845_pciephy_reset_l,
@@ -1721,27 +1876,133 @@ static const struct qmp_phy_cfg sc8180x_pciephy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sm8250_pcie_regs_layout,
 
-       .start_ctrl             = PCS_START | SERDES_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
+       .phy_status             = PHYSTATUS,
+};
+
+static const struct qmp_phy_cfg sc8280xp_qmp_gen3x1_pciephy_cfg = {
+       .lanes                  = 1,
+
+       .offsets                = &qmp_pcie_offsets_v5,
+
+       .tbls = {
+               .serdes         = sc8280xp_qmp_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sc8280xp_qmp_pcie_serdes_tbl),
+               .tx             = sc8280xp_qmp_gen3x1_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sc8280xp_qmp_gen3x1_pcie_tx_tbl),
+               .rx             = sc8280xp_qmp_gen3x1_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sc8280xp_qmp_gen3x1_pcie_rx_tbl),
+               .pcs            = sc8280xp_qmp_gen3x1_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sc8280xp_qmp_gen3x1_pcie_pcs_tbl),
+               .pcs_misc       = sc8280xp_qmp_gen3x1_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sc8280xp_qmp_gen3x1_pcie_pcs_misc_tbl),
+       },
+
+       .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+               .serdes         = sc8280xp_qmp_gen3x1_pcie_rc_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sc8280xp_qmp_gen3x1_pcie_rc_serdes_tbl),
+       },
+
+       .clk_list               = sc8280xp_pciephy_clk_l,
+       .num_clks               = ARRAY_SIZE(sc8280xp_pciephy_clk_l),
+       .reset_list             = sdm845_pciephy_reset_l,
+       .num_resets             = ARRAY_SIZE(sdm845_pciephy_reset_l),
+       .vreg_list              = qmp_phy_vreg_l,
+       .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
+       .regs                   = sm8250_pcie_regs_layout,
+
+       .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
+       .phy_status             = PHYSTATUS,
+};
+
+static const struct qmp_phy_cfg sc8280xp_qmp_gen3x2_pciephy_cfg = {
+       .lanes                  = 2,
+
+       .offsets                = &qmp_pcie_offsets_v5,
+
+       .tbls = {
+               .serdes         = sc8280xp_qmp_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sc8280xp_qmp_pcie_serdes_tbl),
+               .tx             = sc8280xp_qmp_gen3x2_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_tx_tbl),
+               .rx             = sc8280xp_qmp_gen3x2_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_rx_tbl),
+               .pcs            = sc8280xp_qmp_gen3x2_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_pcs_tbl),
+               .pcs_misc       = sc8280xp_qmp_gen3x2_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_pcs_misc_tbl),
+       },
+
+       .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+               .serdes         = sc8280xp_qmp_gen3x2_pcie_rc_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_rc_serdes_tbl),
+       },
+
+       .clk_list               = sc8280xp_pciephy_clk_l,
+       .num_clks               = ARRAY_SIZE(sc8280xp_pciephy_clk_l),
+       .reset_list             = sdm845_pciephy_reset_l,
+       .num_resets             = ARRAY_SIZE(sdm845_pciephy_reset_l),
+       .vreg_list              = qmp_phy_vreg_l,
+       .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
+       .regs                   = sm8250_pcie_regs_layout,
+
+       .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
+       .phy_status             = PHYSTATUS,
+};
+
+static const struct qmp_phy_cfg sc8280xp_qmp_gen3x4_pciephy_cfg = {
+       .lanes                  = 4,
 
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = 995,          /* us */
-       .pwrdn_delay_max        = 1005,         /* us */
+       .offsets                = &qmp_pcie_offsets_v5,
+
+       .tbls = {
+               .serdes         = sc8280xp_qmp_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sc8280xp_qmp_pcie_serdes_tbl),
+               .tx             = sc8280xp_qmp_gen3x2_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_tx_tbl),
+               .rx             = sc8280xp_qmp_gen3x2_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_rx_tbl),
+               .pcs            = sc8280xp_qmp_gen3x2_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_pcs_tbl),
+               .pcs_misc       = sc8280xp_qmp_gen3x2_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_pcs_misc_tbl),
+       },
+
+       .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+               .serdes         = sc8280xp_qmp_gen3x2_pcie_rc_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_rc_serdes_tbl),
+       },
+
+       .serdes_4ln_tbl         = sc8280xp_qmp_gen3x4_pcie_serdes_4ln_tbl,
+       .serdes_4ln_num         = ARRAY_SIZE(sc8280xp_qmp_gen3x4_pcie_serdes_4ln_tbl),
+
+       .clk_list               = sc8280xp_pciephy_clk_l,
+       .num_clks               = ARRAY_SIZE(sc8280xp_pciephy_clk_l),
+       .reset_list             = sdm845_pciephy_reset_l,
+       .num_resets             = ARRAY_SIZE(sdm845_pciephy_reset_l),
+       .vreg_list              = qmp_phy_vreg_l,
+       .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
+       .regs                   = sm8250_pcie_regs_layout,
+
+       .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
+       .phy_status             = PHYSTATUS,
 };
 
 static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = {
        .lanes                  = 2,
 
-       .serdes_tbl             = sdx55_qmp_pcie_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(sdx55_qmp_pcie_serdes_tbl),
-       .tx_tbl                 = sdx55_qmp_pcie_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(sdx55_qmp_pcie_tx_tbl),
-       .rx_tbl                 = sdx55_qmp_pcie_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(sdx55_qmp_pcie_rx_tbl),
-       .pcs_tbl                = sdx55_qmp_pcie_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(sdx55_qmp_pcie_pcs_tbl),
-       .pcs_misc_tbl           = sdx55_qmp_pcie_pcs_misc_tbl,
-       .pcs_misc_tbl_num       = ARRAY_SIZE(sdx55_qmp_pcie_pcs_misc_tbl),
+       .tbls = {
+               .serdes         = sdx55_qmp_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sdx55_qmp_pcie_serdes_tbl),
+               .tx             = sdx55_qmp_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sdx55_qmp_pcie_tx_tbl),
+               .rx             = sdx55_qmp_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sdx55_qmp_pcie_rx_tbl),
+               .pcs            = sdx55_qmp_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sdx55_qmp_pcie_pcs_tbl),
+               .pcs_misc       = sdx55_qmp_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sdx55_qmp_pcie_pcs_misc_tbl),
+       },
        .clk_list               = sdm845_pciephy_clk_l,
        .num_clks               = ARRAY_SIZE(sdm845_pciephy_clk_l),
        .reset_list             = sdm845_pciephy_reset_l,
@@ -1750,28 +2011,25 @@ static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sm8250_pcie_regs_layout,
 
-       .start_ctrl             = PCS_START | SERDES_START,
        .pwrdn_ctrl             = SW_PWRDN,
        .phy_status             = PHYSTATUS_4_20,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = 995,          /* us */
-       .pwrdn_delay_max        = 1005,         /* us */
 };
 
 static const struct qmp_phy_cfg sm8450_qmp_gen3x1_pciephy_cfg = {
        .lanes                  = 1,
 
-       .serdes_tbl             = sm8450_qmp_gen3x1_pcie_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_serdes_tbl),
-       .tx_tbl                 = sm8450_qmp_gen3x1_pcie_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_tx_tbl),
-       .rx_tbl                 = sm8450_qmp_gen3x1_pcie_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_rx_tbl),
-       .pcs_tbl                = sm8450_qmp_gen3x1_pcie_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_pcs_tbl),
-       .pcs_misc_tbl           = sm8450_qmp_gen3x1_pcie_pcs_misc_tbl,
-       .pcs_misc_tbl_num       = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_pcs_misc_tbl),
+       .tbls = {
+               .serdes         = sm8450_qmp_gen3x1_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_serdes_tbl),
+               .tx             = sm8450_qmp_gen3x1_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_tx_tbl),
+               .rx             = sm8450_qmp_gen3x1_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_rx_tbl),
+               .pcs            = sm8450_qmp_gen3x1_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_pcs_tbl),
+               .pcs_misc       = sm8450_qmp_gen3x1_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_pcs_misc_tbl),
+       },
        .clk_list               = sdm845_pciephy_clk_l,
        .num_clks               = ARRAY_SIZE(sdm845_pciephy_clk_l),
        .reset_list             = sdm845_pciephy_reset_l,
@@ -1780,28 +2038,40 @@ static const struct qmp_phy_cfg sm8450_qmp_gen3x1_pciephy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sm8250_pcie_regs_layout,
 
-       .start_ctrl             = SERDES_START | PCS_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
        .phy_status             = PHYSTATUS,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = 995,          /* us */
-       .pwrdn_delay_max        = 1005,         /* us */
 };
 
 static const struct qmp_phy_cfg sm8450_qmp_gen4x2_pciephy_cfg = {
        .lanes                  = 2,
 
-       .serdes_tbl             = sm8450_qmp_gen4x2_pcie_serdes_tbl,
-       .serdes_tbl_num         = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_serdes_tbl),
-       .tx_tbl                 = sm8450_qmp_gen4x2_pcie_tx_tbl,
-       .tx_tbl_num             = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_tx_tbl),
-       .rx_tbl                 = sm8450_qmp_gen4x2_pcie_rx_tbl,
-       .rx_tbl_num             = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_rx_tbl),
-       .pcs_tbl                = sm8450_qmp_gen4x2_pcie_pcs_tbl,
-       .pcs_tbl_num            = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_pcs_tbl),
-       .pcs_misc_tbl           = sm8450_qmp_gen4x2_pcie_pcs_misc_tbl,
-       .pcs_misc_tbl_num       = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_pcs_misc_tbl),
+       .tbls = {
+               .serdes         = sm8450_qmp_gen4x2_pcie_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_serdes_tbl),
+               .tx             = sm8450_qmp_gen4x2_pcie_tx_tbl,
+               .tx_num         = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_tx_tbl),
+               .rx             = sm8450_qmp_gen4x2_pcie_rx_tbl,
+               .rx_num         = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_rx_tbl),
+               .pcs            = sm8450_qmp_gen4x2_pcie_pcs_tbl,
+               .pcs_num        = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_pcs_tbl),
+               .pcs_misc       = sm8450_qmp_gen4x2_pcie_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_pcs_misc_tbl),
+       },
+
+       .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+               .serdes         = sm8450_qmp_gen4x2_pcie_rc_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_rc_serdes_tbl),
+               .pcs_misc       = sm8450_qmp_gen4x2_pcie_rc_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_rc_pcs_misc_tbl),
+       },
+
+       .tbls_ep = &(const struct qmp_phy_cfg_tbls) {
+               .serdes         = sm8450_qmp_gen4x2_pcie_ep_serdes_tbl,
+               .serdes_num     = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_ep_serdes_tbl),
+               .pcs_misc       = sm8450_qmp_gen4x2_pcie_ep_pcs_misc_tbl,
+               .pcs_misc_num   = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_ep_pcs_misc_tbl),
+       },
+
        .clk_list               = sdm845_pciephy_clk_l,
        .num_clks               = ARRAY_SIZE(sdm845_pciephy_clk_l),
        .reset_list             = sdm845_pciephy_reset_l,
@@ -1810,17 +2080,11 @@ static const struct qmp_phy_cfg sm8450_qmp_gen4x2_pciephy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sm8250_pcie_regs_layout,
 
-       .start_ctrl             = SERDES_START | PCS_START,
        .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
        .phy_status             = PHYSTATUS_4_20,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = 995,          /* us */
-       .pwrdn_delay_max        = 1005,         /* us */
 };
 
 static void qmp_pcie_configure_lane(void __iomem *base,
-                                       const unsigned int *regs,
                                        const struct qmp_phy_init_tbl tbl[],
                                        int num,
                                        u8 lane_mask)
@@ -1835,43 +2099,74 @@ static void qmp_pcie_configure_lane(void __iomem *base,
                if (!(t->lane_mask & lane_mask))
                        continue;
 
-               if (t->in_layout)
-                       writel(t->val, base + regs[t->offset]);
-               else
-                       writel(t->val, base + t->offset);
+               writel(t->val, base + t->offset);
        }
 }
 
 static void qmp_pcie_configure(void __iomem *base,
-                                       const unsigned int *regs,
                                        const struct qmp_phy_init_tbl tbl[],
                                        int num)
 {
-       qmp_pcie_configure_lane(base, regs, tbl, num, 0xff);
+       qmp_pcie_configure_lane(base, tbl, num, 0xff);
 }
 
-static int qmp_pcie_serdes_init(struct qmp_phy *qphy)
+static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls)
 {
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *serdes = qphy->serdes;
-       const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl;
-       int serdes_tbl_num = cfg->serdes_tbl_num;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       const struct qmp_pcie_offsets *offs = cfg->offsets;
+       void __iomem *tx3, *rx3, *tx4, *rx4;
 
-       qmp_pcie_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num);
-       qmp_pcie_configure(serdes, cfg->regs, cfg->serdes_tbl_sec, cfg->serdes_tbl_num_sec);
+       tx3 = qmp->port_b + offs->tx;
+       rx3 = qmp->port_b + offs->rx;
+       tx4 = qmp->port_b + offs->tx2;
+       rx4 = qmp->port_b + offs->rx2;
 
-       return 0;
+       qmp_pcie_configure_lane(tx3, tbls->tx, tbls->tx_num, 1);
+       qmp_pcie_configure_lane(rx3, tbls->rx, tbls->rx_num, 1);
+
+       qmp_pcie_configure_lane(tx4, tbls->tx, tbls->tx_num, 2);
+       qmp_pcie_configure_lane(rx4, tbls->rx, tbls->rx_num, 2);
+}
+
+static void qmp_pcie_init_registers(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls)
+{
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *serdes = qmp->serdes;
+       void __iomem *tx = qmp->tx;
+       void __iomem *rx = qmp->rx;
+       void __iomem *tx2 = qmp->tx2;
+       void __iomem *rx2 = qmp->rx2;
+       void __iomem *pcs = qmp->pcs;
+       void __iomem *pcs_misc = qmp->pcs_misc;
+
+       if (!tbls)
+               return;
+
+       qmp_pcie_configure(serdes, tbls->serdes, tbls->serdes_num);
+
+       qmp_pcie_configure_lane(tx, tbls->tx, tbls->tx_num, 1);
+       qmp_pcie_configure_lane(rx, tbls->rx, tbls->rx_num, 1);
+
+       if (cfg->lanes >= 2) {
+               qmp_pcie_configure_lane(tx2, tbls->tx, tbls->tx_num, 2);
+               qmp_pcie_configure_lane(rx2, tbls->rx, tbls->rx_num, 2);
+       }
+
+       qmp_pcie_configure(pcs, tbls->pcs, tbls->pcs_num);
+       qmp_pcie_configure(pcs_misc, tbls->pcs_misc, tbls->pcs_misc_num);
+
+       if (cfg->lanes >= 4 && qmp->tcsr_4ln_config) {
+               qmp_pcie_configure(serdes, cfg->serdes_4ln_tbl, cfg->serdes_4ln_num);
+               qmp_pcie_init_port_b(qmp, tbls);
+       }
 }
 
 static int qmp_pcie_init(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *pcs = qphy->pcs;
+       struct qmp_pcie *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
        int ret;
 
-       /* turn on regulator supplies */
        ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
        if (ret) {
                dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
@@ -1884,6 +2179,8 @@ static int qmp_pcie_init(struct phy *phy)
                goto err_disable_regulators;
        }
 
+       usleep_range(200, 300);
+
        ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets);
        if (ret) {
                dev_err(qmp->dev, "reset deassert failed\n");
@@ -1894,14 +2191,6 @@ static int qmp_pcie_init(struct phy *phy)
        if (ret)
                goto err_assert_reset;
 
-       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_V2_PCS_POWER_DOWN_CONTROL,
-                               cfg->pwrdn_ctrl);
-
        return 0;
 
 err_assert_reset:
@@ -1914,9 +2203,8 @@ err_disable_regulators:
 
 static int qmp_pcie_exit(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_pcie *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
        reset_control_bulk_assert(cfg->num_resets, qmp->resets);
 
@@ -1929,72 +2217,41 @@ static int qmp_pcie_exit(struct phy *phy)
 
 static int qmp_pcie_power_on(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *tx = qphy->tx;
-       void __iomem *rx = qphy->rx;
-       void __iomem *pcs = qphy->pcs;
-       void __iomem *pcs_misc = qphy->pcs_misc;
+       struct qmp_pcie *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       const struct qmp_phy_cfg_tbls *mode_tbls;
+       void __iomem *pcs = qmp->pcs;
        void __iomem *status;
-       unsigned int mask, val, ready;
+       unsigned int mask, val;
        int ret;
 
-       qmp_pcie_serdes_init(qphy);
-
-       ret = clk_prepare_enable(qphy->pipe_clk);
-       if (ret) {
-               dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
-               return ret;
-       }
-
-       /* Tx, Rx, and PCS configurations */
-       qmp_pcie_configure_lane(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num, 1);
-       qmp_pcie_configure_lane(tx, cfg->regs, cfg->tx_tbl_sec, cfg->tx_tbl_num_sec, 1);
-
-       if (cfg->lanes >= 2) {
-               qmp_pcie_configure_lane(qphy->tx2, cfg->regs, cfg->tx_tbl,
-                                       cfg->tx_tbl_num, 2);
-               qmp_pcie_configure_lane(qphy->tx2, cfg->regs, cfg->tx_tbl_sec,
-                                       cfg->tx_tbl_num_sec, 2);
-       }
-
-       qmp_pcie_configure_lane(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num, 1);
-       qmp_pcie_configure_lane(rx, cfg->regs, cfg->rx_tbl_sec, cfg->rx_tbl_num_sec, 1);
+       qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
+                       cfg->pwrdn_ctrl);
 
-       if (cfg->lanes >= 2) {
-               qmp_pcie_configure_lane(qphy->rx2, cfg->regs, cfg->rx_tbl,
-                                       cfg->rx_tbl_num, 2);
-               qmp_pcie_configure_lane(qphy->rx2, cfg->regs, cfg->rx_tbl_sec,
-                                       cfg->rx_tbl_num_sec, 2);
-       }
-
-       qmp_pcie_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
-       qmp_pcie_configure(pcs, cfg->regs, cfg->pcs_tbl_sec, cfg->pcs_tbl_num_sec);
+       if (qmp->mode == PHY_MODE_PCIE_RC)
+               mode_tbls = cfg->tbls_rc;
+       else
+               mode_tbls = cfg->tbls_ep;
 
-       qmp_pcie_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl, cfg->pcs_misc_tbl_num);
-       qmp_pcie_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl_sec, cfg->pcs_misc_tbl_num_sec);
+       qmp_pcie_init_registers(qmp, &cfg->tbls);
+       qmp_pcie_init_registers(qmp, mode_tbls);
 
-       /*
-        * Pull out PHY from POWER DOWN state.
-        * This is active low enable signal to power-down PHY.
-        */
-       qphy_setbits(pcs, QPHY_V2_PCS_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
-
-       if (cfg->has_pwrdn_delay)
-               usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max);
+       ret = clk_bulk_prepare_enable(qmp->num_pipe_clks, qmp->pipe_clks);
+       if (ret)
+               return ret;
 
        /* Pull PHY out of reset state */
        qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
        /* start SerDes and Phy-Coding-Sublayer */
-       qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
+       qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);
+
+       if (!cfg->skip_start_delay)
+               usleep_range(1000, 1200);
 
        status = pcs + cfg->regs[QPHY_PCS_STATUS];
        mask = cfg->phy_status;
-       ready = 0;
-
-       ret = readl_poll_timeout(status, val, (val & mask) == ready, 10,
+       ret = readl_poll_timeout(status, val, !(val & mask), 200,
                                 PHY_INIT_COMPLETE_TIMEOUT);
        if (ret) {
                dev_err(qmp->dev, "phy initialization timed-out\n");
@@ -2004,32 +2261,28 @@ static int qmp_pcie_power_on(struct phy *phy)
        return 0;
 
 err_disable_pipe_clk:
-       clk_disable_unprepare(qphy->pipe_clk);
+       clk_bulk_disable_unprepare(qmp->num_pipe_clks, qmp->pipe_clks);
 
        return ret;
 }
 
 static int qmp_pcie_power_off(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_pcie *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
-       clk_disable_unprepare(qphy->pipe_clk);
+       clk_bulk_disable_unprepare(qmp->num_pipe_clks, qmp->pipe_clks);
 
        /* PHY reset */
-       qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
+       qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
        /* stop SerDes and Phy-Coding-Sublayer */
-       qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
+       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL],
+                       SERDES_START | PCS_START);
 
        /* Put PHY into POWER DOWN state: active low */
-       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_V2_PCS_POWER_DOWN_CONTROL,
-                               cfg->pwrdn_ctrl);
-       }
+       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
+                       cfg->pwrdn_ctrl);
 
        return 0;
 }
@@ -2060,9 +2313,34 @@ static int qmp_pcie_disable(struct phy *phy)
        return qmp_pcie_exit(phy);
 }
 
-static int qmp_pcie_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg)
+static int qmp_pcie_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+       struct qmp_pcie *qmp = phy_get_drvdata(phy);
+
+       switch (submode) {
+       case PHY_MODE_PCIE_RC:
+       case PHY_MODE_PCIE_EP:
+               qmp->mode = submode;
+               break;
+       default:
+               dev_err(&phy->dev, "Unsupported submode %d\n", submode);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct phy_ops qmp_pcie_phy_ops = {
+       .power_on       = qmp_pcie_enable,
+       .power_off      = qmp_pcie_disable,
+       .set_mode       = qmp_pcie_set_mode,
+       .owner          = THIS_MODULE,
+};
+
+static int qmp_pcie_vreg_init(struct qmp_pcie *qmp)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        int num = cfg->num_vregs;
        int i;
 
@@ -2076,9 +2354,10 @@ static int qmp_pcie_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg)
        return devm_regulator_bulk_get(dev, num, qmp->vregs);
 }
 
-static int qmp_pcie_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg)
+static int qmp_pcie_reset_init(struct qmp_pcie *qmp)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        int i;
        int ret;
 
@@ -2097,9 +2376,10 @@ static int qmp_pcie_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg
        return 0;
 }
 
-static int qmp_pcie_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg)
+static int qmp_pcie_clk_init(struct qmp_pcie *qmp)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        int num = cfg->num_clks;
        int i;
 
@@ -2136,9 +2416,9 @@ static void phy_clk_release_provider(void *res)
  *    clk  |   +-------+   |                   +-----+
  *         +---------------+
  */
-static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
+static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np)
 {
-       struct clk_fixed_rate *fixed;
+       struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;
        struct clk_init_data init = { };
        int ret;
 
@@ -2148,18 +2428,14 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
                return ret;
        }
 
-       fixed = devm_kzalloc(qmp->dev, sizeof(*fixed), GFP_KERNEL);
-       if (!fixed)
-               return -ENOMEM;
-
        init.ops = &clk_fixed_rate_ops;
 
        /*
         * Controllers using QMP PHY-s use 125MHz pipe clock interface
         * unless other frequency is specified in the PHY config.
         */
-       if (qmp->phys[0]->cfg->pipe_clock_rate)
-               fixed->fixed_rate = qmp->phys[0]->cfg->pipe_clock_rate;
+       if (qmp->cfg->pipe_clock_rate)
+               fixed->fixed_rate = qmp->cfg->pipe_clock_rate;
        else
                fixed->fixed_rate = 125000000;
 
@@ -2180,145 +2456,162 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
        return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np);
 }
 
-static const struct phy_ops qmp_pcie_ops = {
-       .power_on       = qmp_pcie_enable,
-       .power_off      = qmp_pcie_disable,
-       .owner          = THIS_MODULE,
-};
-
-static int qmp_pcie_create(struct device *dev, struct device_node *np, int id,
-                       void __iomem *serdes, const struct qmp_phy_cfg *cfg)
+static int qmp_pcie_parse_dt_legacy(struct qmp_pcie *qmp, struct device_node *np)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
-       struct phy *generic_phy;
-       struct qmp_phy *qphy;
-       int ret;
+       struct platform_device *pdev = to_platform_device(qmp->dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
+       struct clk *clk;
 
-       qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
-       if (!qphy)
-               return -ENOMEM;
+       qmp->serdes = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(qmp->serdes))
+               return PTR_ERR(qmp->serdes);
 
-       qphy->cfg = cfg;
-       qphy->serdes = serdes;
        /*
-        * Get memory resources for each phy lane:
+        * Get memory resources for the PHY:
         * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2.
         * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5
         * For single lane PHYs: pcs_misc (optional) -> 3.
         */
-       qphy->tx = devm_of_iomap(dev, np, 0, NULL);
-       if (IS_ERR(qphy->tx))
-               return PTR_ERR(qphy->tx);
+       qmp->tx = devm_of_iomap(dev, np, 0, NULL);
+       if (IS_ERR(qmp->tx))
+               return PTR_ERR(qmp->tx);
 
        if (of_device_is_compatible(dev->of_node, "qcom,sdm845-qhp-pcie-phy"))
-               qphy->rx = qphy->tx;
+               qmp->rx = qmp->tx;
        else
-               qphy->rx = devm_of_iomap(dev, np, 1, NULL);
-       if (IS_ERR(qphy->rx))
-               return PTR_ERR(qphy->rx);
+               qmp->rx = devm_of_iomap(dev, np, 1, NULL);
+       if (IS_ERR(qmp->rx))
+               return PTR_ERR(qmp->rx);
 
-       qphy->pcs = devm_of_iomap(dev, np, 2, NULL);
-       if (IS_ERR(qphy->pcs))
-               return PTR_ERR(qphy->pcs);
+       qmp->pcs = devm_of_iomap(dev, np, 2, NULL);
+       if (IS_ERR(qmp->pcs))
+               return PTR_ERR(qmp->pcs);
 
        if (cfg->lanes >= 2) {
-               qphy->tx2 = devm_of_iomap(dev, np, 3, NULL);
-               if (IS_ERR(qphy->tx2))
-                       return PTR_ERR(qphy->tx2);
+               qmp->tx2 = devm_of_iomap(dev, np, 3, NULL);
+               if (IS_ERR(qmp->tx2))
+                       return PTR_ERR(qmp->tx2);
 
-               qphy->rx2 = devm_of_iomap(dev, np, 4, NULL);
-               if (IS_ERR(qphy->rx2))
-                       return PTR_ERR(qphy->rx2);
+               qmp->rx2 = devm_of_iomap(dev, np, 4, NULL);
+               if (IS_ERR(qmp->rx2))
+                       return PTR_ERR(qmp->rx2);
 
-               qphy->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
+               qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
        } else {
-               qphy->pcs_misc = devm_of_iomap(dev, np, 3, NULL);
+               qmp->pcs_misc = devm_of_iomap(dev, np, 3, NULL);
        }
 
-       if (IS_ERR(qphy->pcs_misc) &&
+       if (IS_ERR(qmp->pcs_misc) &&
            of_device_is_compatible(dev->of_node, "qcom,ipq6018-qmp-pcie-phy"))
-               qphy->pcs_misc = qphy->pcs + 0x400;
+               qmp->pcs_misc = qmp->pcs + 0x400;
 
-       if (IS_ERR(qphy->pcs_misc)) {
-               if (cfg->pcs_misc_tbl || cfg->pcs_misc_tbl_sec)
-                       return PTR_ERR(qphy->pcs_misc);
+       if (IS_ERR(qmp->pcs_misc)) {
+               if (cfg->tbls.pcs_misc ||
+                   (cfg->tbls_rc && cfg->tbls_rc->pcs_misc) ||
+                   (cfg->tbls_ep && cfg->tbls_ep->pcs_misc)) {
+                       return PTR_ERR(qmp->pcs_misc);
+               }
        }
 
-       qphy->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
-       if (IS_ERR(qphy->pipe_clk)) {
-               return dev_err_probe(dev, PTR_ERR(qphy->pipe_clk),
-                                    "failed to get lane%d pipe clock\n", id);
+       clk = devm_get_clk_from_child(dev, np, NULL);
+       if (IS_ERR(clk)) {
+               return dev_err_probe(dev, PTR_ERR(clk),
+                                    "failed to get pipe clock\n");
+       }
+
+       qmp->num_pipe_clks = 1;
+       qmp->pipe_clks[0].id = "pipe";
+       qmp->pipe_clks[0].clk = clk;
+
+       return 0;
+}
+
+static int qmp_pcie_get_4ln_config(struct qmp_pcie *qmp)
+{
+       struct regmap *tcsr;
+       unsigned int args[2];
+       int ret;
+
+       tcsr = syscon_regmap_lookup_by_phandle_args(qmp->dev->of_node,
+                                                   "qcom,4ln-config-sel",
+                                                   ARRAY_SIZE(args), args);
+       if (IS_ERR(tcsr)) {
+               ret = PTR_ERR(tcsr);
+               if (ret == -ENOENT)
+                       return 0;
+
+               dev_err(qmp->dev, "failed to lookup syscon: %d\n", ret);
+               return ret;
        }
 
-       generic_phy = devm_phy_create(dev, np, &qmp_pcie_ops);
-       if (IS_ERR(generic_phy)) {
-               ret = PTR_ERR(generic_phy);
-               dev_err(dev, "failed to create qphy %d\n", ret);
+       ret = regmap_test_bits(tcsr, args[0], BIT(args[1]));
+       if (ret < 0) {
+               dev_err(qmp->dev, "failed to read tcsr: %d\n", ret);
                return ret;
        }
 
-       qphy->phy = generic_phy;
-       qphy->qmp = qmp;
-       qmp->phys[id] = qphy;
-       phy_set_drvdata(generic_phy, qphy);
+       qmp->tcsr_4ln_config = ret;
+
+       dev_dbg(qmp->dev, "4ln_config_sel = %d\n", qmp->tcsr_4ln_config);
 
        return 0;
 }
 
-static const struct of_device_id qmp_pcie_of_match_table[] = {
-       {
-               .compatible = "qcom,msm8998-qmp-pcie-phy",
-               .data = &msm8998_pciephy_cfg,
-       }, {
-               .compatible = "qcom,ipq8074-qmp-pcie-phy",
-               .data = &ipq8074_pciephy_cfg,
-       }, {
-               .compatible = "qcom,ipq8074-qmp-gen3-pcie-phy",
-               .data = &ipq8074_pciephy_gen3_cfg,
-       }, {
-               .compatible = "qcom,ipq6018-qmp-pcie-phy",
-               .data = &ipq6018_pciephy_cfg,
-       }, {
-               .compatible = "qcom,sc8180x-qmp-pcie-phy",
-               .data = &sc8180x_pciephy_cfg,
-       }, {
-               .compatible = "qcom,sdm845-qhp-pcie-phy",
-               .data = &sdm845_qhp_pciephy_cfg,
-       }, {
-               .compatible = "qcom,sdm845-qmp-pcie-phy",
-               .data = &sdm845_qmp_pciephy_cfg,
-       }, {
-               .compatible = "qcom,sm8250-qmp-gen3x1-pcie-phy",
-               .data = &sm8250_qmp_gen3x1_pciephy_cfg,
-       }, {
-               .compatible = "qcom,sm8250-qmp-gen3x2-pcie-phy",
-               .data = &sm8250_qmp_gen3x2_pciephy_cfg,
-       }, {
-               .compatible = "qcom,sm8250-qmp-modem-pcie-phy",
-               .data = &sm8250_qmp_gen3x2_pciephy_cfg,
-       }, {
-               .compatible = "qcom,sdx55-qmp-pcie-phy",
-               .data = &sdx55_qmp_pciephy_cfg,
-       }, {
-               .compatible = "qcom,sm8450-qmp-gen3x1-pcie-phy",
-               .data = &sm8450_qmp_gen3x1_pciephy_cfg,
-       }, {
-               .compatible = "qcom,sm8450-qmp-gen4x2-pcie-phy",
-               .data = &sm8450_qmp_gen4x2_pciephy_cfg,
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(of, qmp_pcie_of_match_table);
+static int qmp_pcie_parse_dt(struct qmp_pcie *qmp)
+{
+       struct platform_device *pdev = to_platform_device(qmp->dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       const struct qmp_pcie_offsets *offs = cfg->offsets;
+       struct device *dev = qmp->dev;
+       void __iomem *base;
+       int ret;
+
+       if (!offs)
+               return -EINVAL;
+
+       ret = qmp_pcie_get_4ln_config(qmp);
+       if (ret)
+               return ret;
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       qmp->serdes = base + offs->serdes;
+       qmp->pcs = base + offs->pcs;
+       qmp->pcs_misc = base + offs->pcs_misc;
+       qmp->tx = base + offs->tx;
+       qmp->rx = base + offs->rx;
+
+       if (cfg->lanes >= 2) {
+               qmp->tx2 = base + offs->tx2;
+               qmp->rx2 = base + offs->rx2;
+       }
+
+       if (qmp->cfg->lanes >= 4 && qmp->tcsr_4ln_config) {
+               qmp->port_b = devm_platform_ioremap_resource(pdev, 1);
+               if (IS_ERR(qmp->port_b))
+                       return PTR_ERR(qmp->port_b);
+       }
+
+       qmp->num_pipe_clks = 2;
+       qmp->pipe_clks[0].id = "pipe";
+       qmp->pipe_clks[1].id = "pipediv2";
+
+       ret = devm_clk_bulk_get(dev, qmp->num_pipe_clks, qmp->pipe_clks);
+       if (ret)
+               return ret;
+
+       return 0;
+}
 
 static int qmp_pcie_probe(struct platform_device *pdev)
 {
-       struct qcom_qmp *qmp;
        struct device *dev = &pdev->dev;
-       struct device_node *child;
        struct phy_provider *phy_provider;
-       void __iomem *serdes;
-       const struct qmp_phy_cfg *cfg = NULL;
-       int num, id;
+       struct device_node *np;
+       struct qmp_pcie *qmp;
        int ret;
 
        qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
@@ -2326,73 +2619,117 @@ static int qmp_pcie_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        qmp->dev = dev;
-       dev_set_drvdata(dev, qmp);
 
-       /* Get the specific init parameters of QMP phy */
-       cfg = of_device_get_match_data(dev);
-       if (!cfg)
+       qmp->cfg = of_device_get_match_data(dev);
+       if (!qmp->cfg)
                return -EINVAL;
 
-       /* per PHY serdes; usually located at base address */
-       serdes = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(serdes))
-               return PTR_ERR(serdes);
+       WARN_ON_ONCE(!qmp->cfg->pwrdn_ctrl);
+       WARN_ON_ONCE(!qmp->cfg->phy_status);
 
-       ret = qmp_pcie_clk_init(dev, cfg);
+       ret = qmp_pcie_clk_init(qmp);
        if (ret)
                return ret;
 
-       ret = qmp_pcie_reset_init(dev, cfg);
+       ret = qmp_pcie_reset_init(qmp);
        if (ret)
                return ret;
 
-       ret = qmp_pcie_vreg_init(dev, cfg);
+       ret = qmp_pcie_vreg_init(qmp);
        if (ret)
-               return dev_err_probe(dev, ret,
-                                    "failed to get regulator supplies\n");
-
-       num = of_get_available_child_count(dev->of_node);
-       /* do we have a rogue child node ? */
-       if (num > 1)
-               return -EINVAL;
+               return ret;
 
-       qmp->phys = devm_kcalloc(dev, num, sizeof(*qmp->phys), GFP_KERNEL);
-       if (!qmp->phys)
-               return -ENOMEM;
+       /* Check for legacy binding with child node. */
+       np = of_get_next_available_child(dev->of_node, NULL);
+       if (np) {
+               ret = qmp_pcie_parse_dt_legacy(qmp, np);
+       } else {
+               np = of_node_get(dev->of_node);
+               ret = qmp_pcie_parse_dt(qmp);
+       }
+       if (ret)
+               goto err_node_put;
 
-       id = 0;
-       for_each_available_child_of_node(dev->of_node, child) {
-               /* Create per-lane phy */
-               ret = qmp_pcie_create(dev, child, id, serdes, cfg);
-               if (ret) {
-                       dev_err(dev, "failed to create lane%d phy, %d\n",
-                               id, ret);
-                       goto err_node_put;
-               }
+       ret = phy_pipe_clk_register(qmp, np);
+       if (ret)
+               goto err_node_put;
 
-               /*
-                * Register the pipe clock provided by phy.
-                * See function description to see details of this pipe clock.
-                */
-               ret = phy_pipe_clk_register(qmp, child);
-               if (ret) {
-                       dev_err(qmp->dev,
-                               "failed to register pipe clock source\n");
-                       goto err_node_put;
-               }
+       qmp->mode = PHY_MODE_PCIE_RC;
 
-               id++;
+       qmp->phy = devm_phy_create(dev, np, &qmp_pcie_phy_ops);
+       if (IS_ERR(qmp->phy)) {
+               ret = PTR_ERR(qmp->phy);
+               dev_err(dev, "failed to create PHY: %d\n", ret);
+               goto err_node_put;
        }
 
+       phy_set_drvdata(qmp->phy, qmp);
+
+       of_node_put(np);
+
        phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 
        return PTR_ERR_OR_ZERO(phy_provider);
 
 err_node_put:
-       of_node_put(child);
+       of_node_put(np);
        return ret;
 }
 
+static const struct of_device_id qmp_pcie_of_match_table[] = {
+       {
+               .compatible = "qcom,ipq6018-qmp-pcie-phy",
+               .data = &ipq6018_pciephy_cfg,
+       }, {
+               .compatible = "qcom,ipq8074-qmp-gen3-pcie-phy",
+               .data = &ipq8074_pciephy_gen3_cfg,
+       }, {
+               .compatible = "qcom,ipq8074-qmp-pcie-phy",
+               .data = &ipq8074_pciephy_cfg,
+       }, {
+               .compatible = "qcom,msm8998-qmp-pcie-phy",
+               .data = &msm8998_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sc8180x-qmp-pcie-phy",
+               .data = &sc8180x_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sc8280xp-qmp-gen3x1-pcie-phy",
+               .data = &sc8280xp_qmp_gen3x1_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sc8280xp-qmp-gen3x2-pcie-phy",
+               .data = &sc8280xp_qmp_gen3x2_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sc8280xp-qmp-gen3x4-pcie-phy",
+               .data = &sc8280xp_qmp_gen3x4_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sdm845-qhp-pcie-phy",
+               .data = &sdm845_qhp_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sdm845-qmp-pcie-phy",
+               .data = &sdm845_qmp_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sdx55-qmp-pcie-phy",
+               .data = &sdx55_qmp_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sm8250-qmp-gen3x1-pcie-phy",
+               .data = &sm8250_qmp_gen3x1_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sm8250-qmp-gen3x2-pcie-phy",
+               .data = &sm8250_qmp_gen3x2_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sm8250-qmp-modem-pcie-phy",
+               .data = &sm8250_qmp_gen3x2_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sm8450-qmp-gen3x1-pcie-phy",
+               .data = &sm8450_qmp_gen3x1_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sm8450-qmp-gen4x2-pcie-phy",
+               .data = &sm8450_qmp_gen4x2_pciephy_cfg,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, qmp_pcie_of_match_table);
+
 static struct platform_driver qmp_pcie_driver = {
        .probe          = qmp_pcie_probe,
        .driver = {
index 2e19fb3f051e028355d819acd64b4980b1e5d7c9..a469ae2a10a135f98162311138423155959ec02f 100644 (file)
@@ -8,6 +8,8 @@
 #define QCOM_PHY_QMP_PCS_PCIE_V5_H_
 
 /* Only for QMP V5 PHY - PCS_PCIE registers */
+#define QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG2           0x0c
+#define QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG4           0x14
 #define QPHY_V5_PCS_PCIE_ENDPOINT_REFCLK_DRIVE         0x20
 #define QPHY_V5_PCS_PCIE_INT_AUX_CLK_CONFIG1           0x54
 #define QPHY_V5_PCS_PCIE_OSC_DTCT_ACTIONS              0x94
index 1eedf50cf9cbccc38b47d4c8b278f59fb9356f85..3d9713d348fe6b827a991b7f8e8c8f0703b54167 100644 (file)
@@ -8,8 +8,10 @@
 
 /* Only for QMP V5_20 PHY - PCIe PCS registers */
 #define QPHY_V5_20_PCS_PCIE_ENDPOINT_REFCLK_DRIVE      0x01c
+#define QPHY_V5_20_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5     0x084
 #define QPHY_V5_20_PCS_PCIE_OSC_DTCT_ACTIONS           0x090
 #define QPHY_V5_20_PCS_PCIE_EQ_CONFIG1                 0x0a0
+#define QPHY_V5_20_PCS_PCIE_PRESET_P10_POST            0x0e0
 #define QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG5              0x108
 #define QPHY_V5_20_PCS_PCIE_G4_PRE_GAIN                        0x15c
 #define QPHY_V5_20_PCS_PCIE_RX_MARGINING_CONFIG3       0x184
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h
new file mode 100644 (file)
index 0000000..9a5a20d
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022, Linaro Ltd.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_V5_20_H_
+#define QCOM_PHY_QMP_PCS_V5_20_H_
+
+#define QPHY_V5_20_PCS_G3S2_PRE_GAIN                   0x170
+#define QPHY_V5_20_PCS_RX_SIGDET_LVL                   0x188
+#define QPHY_V5_20_PCS_EQ_CONFIG4                      0x1e0
+#define QPHY_V5_20_PCS_EQ_CONFIG5                      0x1e4
+
+#endif
index c08d34ad1313e77db98773debe32d97f1875404d..318eea35b9721969dbaa996b1b7c58c9234c1c15 100644 (file)
@@ -20,8 +20,6 @@
 #include <linux/reset.h>
 #include <linux/slab.h>
 
-#include <dt-bindings/phy/phy.h>
-
 #include "phy-qcom-qmp.h"
 
 /* QPHY_SW_RESET bit */
@@ -31,8 +29,6 @@
 /* QPHY_START_CONTROL bits */
 #define SERDES_START                           BIT(0)
 #define PCS_START                              BIT(1)
-/* QPHY_PCS_STATUS bit */
-#define PHYSTATUS                              BIT(6)
 /* QPHY_PCS_READY_STATUS bit */
 #define PCS_READY                              BIT(0)
 
 struct qmp_phy_init_tbl {
        unsigned int offset;
        unsigned int val;
-       /*
-        * register part of layout ?
-        * if yes, then offset gives index in the reg-layout
-        */
-       bool in_layout;
        /*
         * mask of lanes for which this register is written
         * for cases when second lane needs different values
@@ -60,14 +51,6 @@ struct qmp_phy_init_tbl {
                .lane_mask = 0xff,      \
        }
 
-#define QMP_PHY_INIT_CFG_L(o, v)       \
-       {                               \
-               .offset = o,            \
-               .val = v,               \
-               .in_layout = true,      \
-               .lane_mask = 0xff,      \
-       }
-
 #define QMP_PHY_INIT_CFG_LANE(o, v, l) \
        {                               \
                .offset = o,            \
@@ -89,22 +72,26 @@ enum qphy_reg_layout {
 static const unsigned int msm8996_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
        [QPHY_START_CTRL]               = 0x00,
        [QPHY_PCS_READY_STATUS]         = 0x168,
+       [QPHY_PCS_POWER_DOWN_CONTROL]   = 0x04,
 };
 
 static const unsigned int sdm845_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
        [QPHY_START_CTRL]               = 0x00,
        [QPHY_PCS_READY_STATUS]         = 0x160,
+       [QPHY_PCS_POWER_DOWN_CONTROL]   = 0x04,
 };
 
 static const unsigned int sm6115_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
        [QPHY_START_CTRL]               = 0x00,
        [QPHY_PCS_READY_STATUS]         = 0x168,
+       [QPHY_PCS_POWER_DOWN_CONTROL]   = 0x04,
 };
 
 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,
+       [QPHY_PCS_POWER_DOWN_CONTROL]   = QPHY_V4_PCS_UFS_POWER_DOWN_CONTROL,
 };
 
 static const struct qmp_phy_init_tbl msm8996_ufs_serdes_tbl[] = {
@@ -531,10 +518,21 @@ static const struct qmp_phy_init_tbl sm8350_ufsphy_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
 };
 
+struct qmp_ufs_offsets {
+       u16 serdes;
+       u16 pcs;
+       u16 tx;
+       u16 rx;
+       u16 tx2;
+       u16 rx2;
+};
+
 /* struct qmp_phy_cfg - per-PHY initialization config */
 struct qmp_phy_cfg {
        int lanes;
 
+       const struct qmp_ufs_offsets *offsets;
+
        /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
        const struct qmp_phy_init_tbl *serdes_tbl;
        int serdes_tbl_num;
@@ -555,63 +553,28 @@ struct qmp_phy_cfg {
        /* array of registers with different offsets */
        const unsigned int *regs;
 
-       unsigned int start_ctrl;
-       unsigned int pwrdn_ctrl;
-       /* bit offset of PHYSTATUS in QPHY_PCS_STATUS register */
-       unsigned int phy_status;
-
        /* true, if PCS block has no separate SW_RESET register */
        bool no_pcs_sw_reset;
 };
 
-/**
- * struct qmp_phy - per-lane phy descriptor
- *
- * @phy: generic phy
- * @cfg: phy specific configuration
- * @serdes: iomapped memory space for phy's serdes (i.e. PLL)
- * @tx: iomapped memory space for lane's tx
- * @rx: iomapped memory space for lane's rx
- * @pcs: iomapped memory space for lane's pcs
- * @tx2: iomapped memory space for second lane's tx (in dual lane PHYs)
- * @rx2: iomapped memory space for second lane's rx (in dual lane PHYs)
- * @pcs_misc: iomapped memory space for lane's pcs_misc
- * @qmp: QMP phy to which this lane belongs
- */
-struct qmp_phy {
-       struct phy *phy;
+struct qmp_ufs {
+       struct device *dev;
+
        const struct qmp_phy_cfg *cfg;
+
        void __iomem *serdes;
+       void __iomem *pcs;
+       void __iomem *pcs_misc;
        void __iomem *tx;
        void __iomem *rx;
-       void __iomem *pcs;
        void __iomem *tx2;
        void __iomem *rx2;
-       void __iomem *pcs_misc;
-       struct qcom_qmp *qmp;
-};
-
-/**
- * struct qcom_qmp - structure holding QMP phy block attributes
- *
- * @dev: device
- *
- * @clks: array of clocks required by phy
- * @resets: array of resets required by phy
- * @vregs: regulator supplies bulk data
- *
- * @phys: array of per-lane phy descriptors
- * @ufs_reset: optional UFS PHY reset handle
- */
-struct qcom_qmp {
-       struct device *dev;
 
        struct clk_bulk_data *clks;
        struct regulator_bulk_data *vregs;
-
-       struct qmp_phy **phys;
-
        struct reset_control *ufs_reset;
+
+       struct phy *phy;
 };
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -657,6 +620,15 @@ static const char * const qmp_phy_vreg_l[] = {
        "vdda-phy", "vdda-pll",
 };
 
+static const struct qmp_ufs_offsets qmp_ufs_offsets_v5 = {
+       .serdes         = 0,
+       .pcs            = 0xc00,
+       .tx             = 0x400,
+       .rx             = 0x600,
+       .tx2            = 0x800,
+       .rx2            = 0xa00,
+};
+
 static const struct qmp_phy_cfg msm8996_ufs_cfg = {
        .lanes                  = 1,
 
@@ -675,13 +647,29 @@ static const struct qmp_phy_cfg msm8996_ufs_cfg = {
 
        .regs                   = msm8996_ufsphy_regs_layout,
 
-       .start_ctrl             = SERDES_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .no_pcs_sw_reset        = true,
 };
 
+static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
+       .lanes                  = 2,
+
+       .offsets                = &qmp_ufs_offsets_v5,
+
+       .serdes_tbl             = sm8350_ufsphy_serdes_tbl,
+       .serdes_tbl_num         = ARRAY_SIZE(sm8350_ufsphy_serdes_tbl),
+       .tx_tbl                 = sm8350_ufsphy_tx_tbl,
+       .tx_tbl_num             = ARRAY_SIZE(sm8350_ufsphy_tx_tbl),
+       .rx_tbl                 = sm8350_ufsphy_rx_tbl,
+       .rx_tbl_num             = ARRAY_SIZE(sm8350_ufsphy_rx_tbl),
+       .pcs_tbl                = sm8350_ufsphy_pcs_tbl,
+       .pcs_tbl_num            = ARRAY_SIZE(sm8350_ufsphy_pcs_tbl),
+       .clk_list               = sdm845_ufs_phy_clk_l,
+       .num_clks               = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
+       .vreg_list              = qmp_phy_vreg_l,
+       .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
+       .regs                   = sm8150_ufsphy_regs_layout,
+};
+
 static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
        .lanes                  = 2,
 
@@ -699,10 +687,6 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sdm845_ufsphy_regs_layout,
 
-       .start_ctrl             = SERDES_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .no_pcs_sw_reset        = true,
 };
 
@@ -723,9 +707,6 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sm6115_ufsphy_regs_layout,
 
-       .start_ctrl             = SERDES_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-
        .no_pcs_sw_reset        = true,
 };
 
@@ -745,10 +726,6 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
        .vreg_list              = qmp_phy_vreg_l,
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sm8150_ufsphy_regs_layout,
-
-       .start_ctrl             = SERDES_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
 };
 
 static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
@@ -767,10 +744,6 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
        .vreg_list              = qmp_phy_vreg_l,
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sm8150_ufsphy_regs_layout,
-
-       .start_ctrl             = SERDES_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
 };
 
 static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
@@ -789,14 +762,9 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
        .vreg_list              = qmp_phy_vreg_l,
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = sm8150_ufsphy_regs_layout,
-
-       .start_ctrl             = SERDES_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
 };
 
 static void qmp_ufs_configure_lane(void __iomem *base,
-                                       const unsigned int *regs,
                                        const struct qmp_phy_init_tbl tbl[],
                                        int num,
                                        u8 lane_mask)
@@ -811,41 +779,35 @@ static void qmp_ufs_configure_lane(void __iomem *base,
                if (!(t->lane_mask & lane_mask))
                        continue;
 
-               if (t->in_layout)
-                       writel(t->val, base + regs[t->offset]);
-               else
-                       writel(t->val, base + t->offset);
+               writel(t->val, base + t->offset);
        }
 }
 
 static void qmp_ufs_configure(void __iomem *base,
-                                  const unsigned int *regs,
                                   const struct qmp_phy_init_tbl tbl[],
                                   int num)
 {
-       qmp_ufs_configure_lane(base, regs, tbl, num, 0xff);
+       qmp_ufs_configure_lane(base, tbl, num, 0xff);
 }
 
-static int qmp_ufs_serdes_init(struct qmp_phy *qphy)
+static int qmp_ufs_serdes_init(struct qmp_ufs *qmp)
 {
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *serdes = qphy->serdes;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *serdes = qmp->serdes;
        const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl;
        int serdes_tbl_num = cfg->serdes_tbl_num;
 
-       qmp_ufs_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num);
+       qmp_ufs_configure(serdes, serdes_tbl, serdes_tbl_num);
 
        return 0;
 }
 
-static int qmp_ufs_com_init(struct qmp_phy *qphy)
+static int qmp_ufs_com_init(struct qmp_ufs *qmp)
 {
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *pcs = qphy->pcs;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *pcs = qmp->pcs;
        int ret;
 
-       /* turn on regulator supplies */
        ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
        if (ret) {
                dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
@@ -856,13 +818,7 @@ static int qmp_ufs_com_init(struct qmp_phy *qphy)
        if (ret)
                goto err_disable_regulators;
 
-       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_V2_PCS_POWER_DOWN_CONTROL,
-                            cfg->pwrdn_ctrl);
+       qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN);
 
        return 0;
 
@@ -872,10 +828,9 @@ err_disable_regulators:
        return ret;
 }
 
-static int qmp_ufs_com_exit(struct qmp_phy *qphy)
+static int qmp_ufs_com_exit(struct qmp_ufs *qmp)
 {
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
        reset_control_assert(qmp->ufs_reset);
 
@@ -888,9 +843,8 @@ static int qmp_ufs_com_exit(struct qmp_phy *qphy)
 
 static int qmp_ufs_init(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_ufs *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
        int ret;
        dev_vdbg(qmp->dev, "Initializing QMP phy\n");
 
@@ -921,7 +875,7 @@ static int qmp_ufs_init(struct phy *phy)
                        return ret;
        }
 
-       ret = qmp_ufs_com_init(qphy);
+       ret = qmp_ufs_com_init(qmp);
        if (ret)
                return ret;
 
@@ -930,34 +884,27 @@ static int qmp_ufs_init(struct phy *phy)
 
 static int qmp_ufs_power_on(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *tx = qphy->tx;
-       void __iomem *rx = qphy->rx;
-       void __iomem *pcs = qphy->pcs;
+       struct qmp_ufs *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *tx = qmp->tx;
+       void __iomem *rx = qmp->rx;
+       void __iomem *pcs = qmp->pcs;
        void __iomem *status;
-       unsigned int mask, val, ready;
+       unsigned int val;
        int ret;
 
-       qmp_ufs_serdes_init(qphy);
+       qmp_ufs_serdes_init(qmp);
 
        /* Tx, Rx, and PCS configurations */
-       qmp_ufs_configure_lane(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num, 1);
-
-       if (cfg->lanes >= 2) {
-               qmp_ufs_configure_lane(qphy->tx2, cfg->regs,
-                                       cfg->tx_tbl, cfg->tx_tbl_num, 2);
-       }
-
-       qmp_ufs_configure_lane(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num, 1);
+       qmp_ufs_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
+       qmp_ufs_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
 
        if (cfg->lanes >= 2) {
-               qmp_ufs_configure_lane(qphy->rx2, cfg->regs,
-                                       cfg->rx_tbl, cfg->rx_tbl_num, 2);
+               qmp_ufs_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
+               qmp_ufs_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
        }
 
-       qmp_ufs_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
+       qmp_ufs_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
 
        ret = reset_control_deassert(qmp->ufs_reset);
        if (ret)
@@ -966,14 +913,12 @@ static int qmp_ufs_power_on(struct phy *phy)
        /* Pull PHY out of reset state */
        if (!cfg->no_pcs_sw_reset)
                qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
-       /* start SerDes and Phy-Coding-Sublayer */
-       qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
 
-       status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
-       mask = PCS_READY;
-       ready = PCS_READY;
+       /* start SerDes */
+       qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], SERDES_START);
 
-       ret = readl_poll_timeout(status, val, (val & mask) == ready, 10,
+       status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
+       ret = readl_poll_timeout(status, val, (val & PCS_READY), 200,
                                 PHY_INIT_COMPLETE_TIMEOUT);
        if (ret) {
                dev_err(qmp->dev, "phy initialization timed-out\n");
@@ -985,33 +930,28 @@ static int qmp_ufs_power_on(struct phy *phy)
 
 static int qmp_ufs_power_off(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_ufs *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
        /* PHY reset */
        if (!cfg->no_pcs_sw_reset)
-               qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
+               qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
-       /* stop SerDes and Phy-Coding-Sublayer */
-       qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
+       /* stop SerDes */
+       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START);
 
        /* Put PHY into POWER DOWN state: active low */
-       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_V2_PCS_POWER_DOWN_CONTROL,
-                               cfg->pwrdn_ctrl);
-       }
+       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
+                       SW_PWRDN);
 
        return 0;
 }
 
 static int qmp_ufs_exit(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
+       struct qmp_ufs *qmp = phy_get_drvdata(phy);
 
-       qmp_ufs_com_exit(qphy);
+       qmp_ufs_com_exit(qmp);
 
        return 0;
 }
@@ -1041,9 +981,16 @@ static int qmp_ufs_disable(struct phy *phy)
        return qmp_ufs_exit(phy);
 }
 
-static int qmp_ufs_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg)
+static const struct phy_ops qcom_qmp_ufs_phy_ops = {
+       .power_on       = qmp_ufs_enable,
+       .power_off      = qmp_ufs_disable,
+       .owner          = THIS_MODULE,
+};
+
+static int qmp_ufs_vreg_init(struct qmp_ufs *qmp)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        int num = cfg->num_vregs;
        int i;
 
@@ -1057,9 +1004,10 @@ static int qmp_ufs_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg)
        return devm_regulator_bulk_get(dev, num, qmp->vregs);
 }
 
-static int qmp_ufs_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg)
+static int qmp_ufs_clk_init(struct qmp_ufs *qmp)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        int num = cfg->num_clks;
        int i;
 
@@ -1073,74 +1021,136 @@ static int qmp_ufs_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg)
        return devm_clk_bulk_get(dev, num, qmp->clks);
 }
 
-static const struct phy_ops qcom_qmp_ufs_ops = {
-       .power_on       = qmp_ufs_enable,
-       .power_off      = qmp_ufs_disable,
-       .owner          = THIS_MODULE,
-};
-
-static int qmp_ufs_create(struct device *dev, struct device_node *np, int id,
-                       void __iomem *serdes, const struct qmp_phy_cfg *cfg)
+static int qmp_ufs_parse_dt_legacy(struct qmp_ufs *qmp, struct device_node *np)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
-       struct phy *generic_phy;
-       struct qmp_phy *qphy;
-       int ret;
+       struct platform_device *pdev = to_platform_device(qmp->dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
 
-       qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
-       if (!qphy)
-               return -ENOMEM;
+       qmp->serdes = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(qmp->serdes))
+               return PTR_ERR(qmp->serdes);
 
-       qphy->cfg = cfg;
-       qphy->serdes = serdes;
        /*
-        * Get memory resources for each phy lane:
+        * Get memory resources for the PHY:
         * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2.
         * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5
         * For single lane PHYs: pcs_misc (optional) -> 3.
         */
-       qphy->tx = devm_of_iomap(dev, np, 0, NULL);
-       if (IS_ERR(qphy->tx))
-               return PTR_ERR(qphy->tx);
+       qmp->tx = devm_of_iomap(dev, np, 0, NULL);
+       if (IS_ERR(qmp->tx))
+               return PTR_ERR(qmp->tx);
 
-       qphy->rx = devm_of_iomap(dev, np, 1, NULL);
-       if (IS_ERR(qphy->rx))
-               return PTR_ERR(qphy->rx);
+       qmp->rx = devm_of_iomap(dev, np, 1, NULL);
+       if (IS_ERR(qmp->rx))
+               return PTR_ERR(qmp->rx);
 
-       qphy->pcs = devm_of_iomap(dev, np, 2, NULL);
-       if (IS_ERR(qphy->pcs))
-               return PTR_ERR(qphy->pcs);
+       qmp->pcs = devm_of_iomap(dev, np, 2, NULL);
+       if (IS_ERR(qmp->pcs))
+               return PTR_ERR(qmp->pcs);
 
        if (cfg->lanes >= 2) {
-               qphy->tx2 = devm_of_iomap(dev, np, 3, NULL);
-               if (IS_ERR(qphy->tx2))
-                       return PTR_ERR(qphy->tx2);
+               qmp->tx2 = devm_of_iomap(dev, np, 3, NULL);
+               if (IS_ERR(qmp->tx2))
+                       return PTR_ERR(qmp->tx2);
 
-               qphy->rx2 = devm_of_iomap(dev, np, 4, NULL);
-               if (IS_ERR(qphy->rx2))
-                       return PTR_ERR(qphy->rx2);
+               qmp->rx2 = devm_of_iomap(dev, np, 4, NULL);
+               if (IS_ERR(qmp->rx2))
+                       return PTR_ERR(qmp->rx2);
 
-               qphy->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
+               qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
        } else {
-               qphy->pcs_misc = devm_of_iomap(dev, np, 3, NULL);
+               qmp->pcs_misc = devm_of_iomap(dev, np, 3, NULL);
        }
 
-       if (IS_ERR(qphy->pcs_misc))
+       if (IS_ERR(qmp->pcs_misc))
                dev_vdbg(dev, "PHY pcs_misc-reg not used\n");
 
-       generic_phy = devm_phy_create(dev, np, &qcom_qmp_ufs_ops);
-       if (IS_ERR(generic_phy)) {
-               ret = PTR_ERR(generic_phy);
-               dev_err(dev, "failed to create qphy %d\n", ret);
+       return 0;
+}
+
+static int qmp_ufs_parse_dt(struct qmp_ufs *qmp)
+{
+       struct platform_device *pdev = to_platform_device(qmp->dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       const struct qmp_ufs_offsets *offs = cfg->offsets;
+       void __iomem *base;
+
+       if (!offs)
+               return -EINVAL;
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       qmp->serdes = base + offs->serdes;
+       qmp->pcs = base + offs->pcs;
+       qmp->tx = base + offs->tx;
+       qmp->rx = base + offs->rx;
+
+       if (cfg->lanes >= 2) {
+               qmp->tx2 = base + offs->tx2;
+               qmp->rx2 = base + offs->rx2;
+       }
+
+       return 0;
+}
+
+static int qmp_ufs_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct phy_provider *phy_provider;
+       struct device_node *np;
+       struct qmp_ufs *qmp;
+       int ret;
+
+       qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
+       if (!qmp)
+               return -ENOMEM;
+
+       qmp->dev = dev;
+
+       qmp->cfg = of_device_get_match_data(dev);
+       if (!qmp->cfg)
+               return -EINVAL;
+
+       ret = qmp_ufs_clk_init(qmp);
+       if (ret)
                return ret;
+
+       ret = qmp_ufs_vreg_init(qmp);
+       if (ret)
+               return ret;
+
+       /* Check for legacy binding with child node. */
+       np = of_get_next_available_child(dev->of_node, NULL);
+       if (np) {
+               ret = qmp_ufs_parse_dt_legacy(qmp, np);
+       } else {
+               np = of_node_get(dev->of_node);
+               ret = qmp_ufs_parse_dt(qmp);
        }
+       if (ret)
+               goto err_node_put;
 
-       qphy->phy = generic_phy;
-       qphy->qmp = qmp;
-       qmp->phys[id] = qphy;
-       phy_set_drvdata(generic_phy, qphy);
+       qmp->phy = devm_phy_create(dev, np, &qcom_qmp_ufs_phy_ops);
+       if (IS_ERR(qmp->phy)) {
+               ret = PTR_ERR(qmp->phy);
+               dev_err(dev, "failed to create PHY: %d\n", ret);
+               goto err_node_put;
+       }
 
-       return 0;
+       phy_set_drvdata(qmp->phy, qmp);
+
+       of_node_put(np);
+
+       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+       return PTR_ERR_OR_ZERO(phy_provider);
+
+err_node_put:
+       of_node_put(np);
+       return ret;
 }
 
 static const struct of_device_id qmp_ufs_of_match_table[] = {
@@ -1155,7 +1165,7 @@ static const struct of_device_id qmp_ufs_of_match_table[] = {
                .data = &sm8150_ufsphy_cfg,
        }, {
                .compatible = "qcom,sc8280xp-qmp-ufs-phy",
-               .data = &sm8350_ufsphy_cfg,
+               .data = &sc8280xp_ufsphy_cfg,
        }, {
                .compatible = "qcom,sdm845-qmp-ufs-phy",
                .data = &sdm845_ufsphy_cfg,
@@ -1182,74 +1192,6 @@ static const struct of_device_id qmp_ufs_of_match_table[] = {
 };
 MODULE_DEVICE_TABLE(of, qmp_ufs_of_match_table);
 
-static int qmp_ufs_probe(struct platform_device *pdev)
-{
-       struct qcom_qmp *qmp;
-       struct device *dev = &pdev->dev;
-       struct device_node *child;
-       struct phy_provider *phy_provider;
-       void __iomem *serdes;
-       const struct qmp_phy_cfg *cfg = NULL;
-       int num, id;
-       int ret;
-
-       qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
-       if (!qmp)
-               return -ENOMEM;
-
-       qmp->dev = dev;
-       dev_set_drvdata(dev, qmp);
-
-       /* Get the specific init parameters of QMP phy */
-       cfg = of_device_get_match_data(dev);
-       if (!cfg)
-               return -EINVAL;
-
-       /* per PHY serdes; usually located at base address */
-       serdes = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(serdes))
-               return PTR_ERR(serdes);
-
-       ret = qmp_ufs_clk_init(dev, cfg);
-       if (ret)
-               return ret;
-
-       ret = qmp_ufs_vreg_init(dev, cfg);
-       if (ret)
-               return dev_err_probe(dev, ret,
-                                    "failed to get regulator supplies\n");
-
-       num = of_get_available_child_count(dev->of_node);
-       /* do we have a rogue child node ? */
-       if (num > 1)
-               return -EINVAL;
-
-       qmp->phys = devm_kcalloc(dev, num, sizeof(*qmp->phys), GFP_KERNEL);
-       if (!qmp->phys)
-               return -ENOMEM;
-
-       id = 0;
-       for_each_available_child_of_node(dev->of_node, child) {
-               /* Create per-lane phy */
-               ret = qmp_ufs_create(dev, child, id, serdes, cfg);
-               if (ret) {
-                       dev_err(dev, "failed to create lane%d phy, %d\n",
-                               id, ret);
-                       goto err_node_put;
-               }
-
-               id++;
-       }
-
-       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-
-       return PTR_ERR_OR_ZERO(phy_provider);
-
-err_node_put:
-       of_node_put(child);
-       return ret;
-}
-
 static struct platform_driver qmp_ufs_driver = {
        .probe          = qmp_ufs_probe,
        .driver = {
index b84c0d4b57541644e96dc0b567f724a1775ff725..4aa338fc4643c3e39561d95ad349f8eb109e5cc0 100644 (file)
@@ -20,8 +20,6 @@
 #include <linux/reset.h>
 #include <linux/slab.h>
 
-#include <dt-bindings/phy/phy.h>
-
 #include "phy-qcom-qmp.h"
 
 /* QPHY_SW_RESET bit */
 #define CLAMP_EN                               BIT(0) /* enables i/o clamp_n */
 
 #define PHY_INIT_COMPLETE_TIMEOUT              10000
-#define POWER_DOWN_DELAY_US_MIN                        10
-#define POWER_DOWN_DELAY_US_MAX                        11
 
 struct qmp_phy_init_tbl {
        unsigned int offset;
        unsigned int val;
-       /*
-        * register part of layout ?
-        * if yes, then offset gives index in the reg-layout
-        */
-       bool in_layout;
        /*
         * mask of lanes for which this register is written
         * for cases when second lane needs different values
@@ -88,14 +79,6 @@ struct qmp_phy_init_tbl {
                .lane_mask = 0xff,      \
        }
 
-#define QMP_PHY_INIT_CFG_L(o, v)       \
-       {                               \
-               .offset = o,            \
-               .val = v,               \
-               .in_layout = true,      \
-               .lane_mask = 0xff,      \
-       }
-
 #define QMP_PHY_INIT_CFG_LANE(o, v, l) \
        {                               \
                .offset = o,            \
@@ -126,6 +109,7 @@ static const unsigned int usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
        [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d4,
        [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR]  = 0x0d8,
        [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x178,
+       [QPHY_PCS_POWER_DOWN_CONTROL]   = 0x04,
 };
 
 static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
@@ -135,6 +119,7 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
        [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d8,
        [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR]  = 0x0dc,
        [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
+       [QPHY_PCS_POWER_DOWN_CONTROL]   = 0x04,
 };
 
 static const unsigned int qmp_v4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
@@ -1427,10 +1412,20 @@ static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V5_PCS_REFGEN_REQ_CONFIG1, 0x21),
 };
 
+struct qmp_usb_offsets {
+       u16 serdes;
+       u16 pcs;
+       u16 pcs_usb;
+       u16 tx;
+       u16 rx;
+};
+
 /* struct qmp_phy_cfg - per-PHY initialization config */
 struct qmp_phy_cfg {
        int lanes;
 
+       const struct qmp_usb_offsets *offsets;
+
        /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
        const struct qmp_phy_init_tbl *serdes_tbl;
        int serdes_tbl_num;
@@ -1456,16 +1451,8 @@ struct qmp_phy_cfg {
        /* array of registers with different offsets */
        const unsigned int *regs;
 
-       unsigned int start_ctrl;
-       unsigned int pwrdn_ctrl;
-       /* bit offset of PHYSTATUS in QPHY_PCS_STATUS register */
-       unsigned int phy_status;
-
        /* true, if PHY needs delay after POWER_DOWN */
        bool has_pwrdn_delay;
-       /* power_down delay in usec */
-       int pwrdn_delay_min;
-       int pwrdn_delay_max;
 
        /* true, if PHY has a separate DP_COM control block */
        bool has_phy_dp_com_ctrl;
@@ -1474,60 +1461,32 @@ struct qmp_phy_cfg {
        unsigned int pcs_usb_offset;
 };
 
-/**
- * struct qmp_phy - per-lane phy descriptor
- *
- * @phy: generic phy
- * @cfg: phy specific configuration
- * @serdes: iomapped memory space for phy's serdes (i.e. PLL)
- * @tx: iomapped memory space for lane's tx
- * @rx: iomapped memory space for lane's rx
- * @pcs: iomapped memory space for lane's pcs
- * @tx2: iomapped memory space for second lane's tx (in dual lane PHYs)
- * @rx2: iomapped memory space for second lane's rx (in dual lane PHYs)
- * @pcs_misc: iomapped memory space for lane's pcs_misc
- * @pcs_usb: iomapped memory space for lane's pcs_usb
- * @pipe_clk: pipe clock
- * @qmp: QMP phy to which this lane belongs
- * @mode: current PHY mode
- */
-struct qmp_phy {
-       struct phy *phy;
+struct qmp_usb {
+       struct device *dev;
+
        const struct qmp_phy_cfg *cfg;
+
        void __iomem *serdes;
+       void __iomem *pcs;
+       void __iomem *pcs_misc;
+       void __iomem *pcs_usb;
        void __iomem *tx;
        void __iomem *rx;
-       void __iomem *pcs;
        void __iomem *tx2;
        void __iomem *rx2;
-       void __iomem *pcs_misc;
-       void __iomem *pcs_usb;
-       struct clk *pipe_clk;
-       struct qcom_qmp *qmp;
-       enum phy_mode mode;
-};
 
-/**
- * struct qcom_qmp - structure holding QMP phy block attributes
- *
- * @dev: device
- * @dp_com: iomapped memory space for phy's dp_com control block
- *
- * @clks: array of clocks required by phy
- * @resets: array of resets required by phy
- * @vregs: regulator supplies bulk data
- *
- * @phys: array of per-lane phy descriptors
- */
-struct qcom_qmp {
-       struct device *dev;
        void __iomem *dp_com;
 
+       struct clk *pipe_clk;
        struct clk_bulk_data *clks;
        struct reset_control_bulk_data *resets;
        struct regulator_bulk_data *vregs;
 
-       struct qmp_phy **phys;
+       enum phy_mode mode;
+
+       struct phy *phy;
+
+       struct clk_fixed_rate pipe_clk_fixed;
 };
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -1564,6 +1523,10 @@ static const char * const qmp_v3_phy_clk_l[] = {
 };
 
 static const char * const qmp_v4_phy_clk_l[] = {
+       "aux", "ref", "com_aux",
+};
+
+static const char * const qmp_v4_ref_phy_clk_l[] = {
        "aux", "ref_clk_src", "ref", "com_aux",
 };
 
@@ -1599,6 +1562,14 @@ static const char * const qmp_phy_vreg_l[] = {
        "vdda-phy", "vdda-pll",
 };
 
+static const struct qmp_usb_offsets qmp_usb_offsets_v5 = {
+       .serdes         = 0,
+       .pcs            = 0x0200,
+       .pcs_usb        = 0x1200,
+       .tx             = 0x0e00,
+       .rx             = 0x1000,
+};
+
 static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = {
        .lanes                  = 1,
 
@@ -1616,11 +1587,7 @@ static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = {
        .num_resets             = ARRAY_SIZE(msm8996_usb3phy_reset_l),
        .vreg_list              = qmp_phy_vreg_l,
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
-       .regs                   = usb3phy_regs_layout,
-
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
+       .regs                   = qmp_v3_usb3phy_regs_layout,
 };
 
 static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
@@ -1641,10 +1608,6 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
        .vreg_list              = qmp_phy_vreg_l,
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = usb3phy_regs_layout,
-
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
 };
 
 static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
@@ -1666,14 +1629,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = qmp_v3_usb3phy_regs_layout,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .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,
 };
 
@@ -1696,20 +1652,15 @@ static const struct qmp_phy_cfg sc7180_usb3phy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = qmp_v3_usb3phy_regs_layout,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .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,
 };
 
 static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = {
        .lanes                  = 1,
 
+       .offsets                = &qmp_usb_offsets_v5,
+
        .serdes_tbl             = sc8280xp_usb3_uniphy_serdes_tbl,
        .serdes_tbl_num         = ARRAY_SIZE(sc8280xp_usb3_uniphy_serdes_tbl),
        .tx_tbl                 = sc8280xp_usb3_uniphy_tx_tbl,
@@ -1720,19 +1671,11 @@ static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = {
        .pcs_tbl_num            = ARRAY_SIZE(sc8280xp_usb3_uniphy_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),
+       .reset_list             = qcm2290_usb3phy_reset_l,
+       .num_resets             = ARRAY_SIZE(qcm2290_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,
-       .phy_status             = PHYSTATUS,
-
-       .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
 };
 
 static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
@@ -1754,13 +1697,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = qmp_v3_usb3phy_regs_layout,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
 };
 
 static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
@@ -1781,10 +1718,6 @@ static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
        .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,
-       .phy_status             = PHYSTATUS,
 };
 
 static const struct qmp_phy_cfg sm8150_usb3phy_cfg = {
@@ -1800,8 +1733,8 @@ static const struct qmp_phy_cfg sm8150_usb3phy_cfg = {
        .pcs_tbl_num            = ARRAY_SIZE(sm8150_usb3_pcs_tbl),
        .pcs_usb_tbl            = sm8150_usb3_pcs_usb_tbl,
        .pcs_usb_tbl_num        = ARRAY_SIZE(sm8150_usb3_pcs_usb_tbl),
-       .clk_list               = qmp_v4_phy_clk_l,
-       .num_clks               = ARRAY_SIZE(qmp_v4_phy_clk_l),
+       .clk_list               = qmp_v4_ref_phy_clk_l,
+       .num_clks               = ARRAY_SIZE(qmp_v4_ref_phy_clk_l),
        .reset_list             = msm8996_usb3phy_reset_l,
        .num_resets             = ARRAY_SIZE(msm8996_usb3phy_reset_l),
        .vreg_list              = qmp_phy_vreg_l,
@@ -1809,15 +1742,7 @@ static const struct qmp_phy_cfg sm8150_usb3phy_cfg = {
        .regs                   = qmp_v4_usb3phy_regs_layout,
        .pcs_usb_offset         = 0x300,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
-
        .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,
 };
 
@@ -1834,8 +1759,8 @@ static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = {
        .pcs_tbl_num            = ARRAY_SIZE(sm8150_usb3_uniphy_pcs_tbl),
        .pcs_usb_tbl            = sm8150_usb3_uniphy_pcs_usb_tbl,
        .pcs_usb_tbl_num        = ARRAY_SIZE(sm8150_usb3_uniphy_pcs_usb_tbl),
-       .clk_list               = qmp_v4_phy_clk_l,
-       .num_clks               = ARRAY_SIZE(qmp_v4_phy_clk_l),
+       .clk_list               = qmp_v4_ref_phy_clk_l,
+       .num_clks               = ARRAY_SIZE(qmp_v4_ref_phy_clk_l),
        .reset_list             = msm8996_usb3phy_reset_l,
        .num_resets             = ARRAY_SIZE(msm8996_usb3phy_reset_l),
        .vreg_list              = qmp_phy_vreg_l,
@@ -1843,13 +1768,7 @@ static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = {
        .regs                   = qmp_v4_usb3phy_regs_layout,
        .pcs_usb_offset         = 0x600,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
 };
 
 static const struct qmp_phy_cfg sm8250_usb3phy_cfg = {
@@ -1874,14 +1793,7 @@ static const struct qmp_phy_cfg sm8250_usb3phy_cfg = {
        .regs                   = qmp_v4_usb3phy_regs_layout,
        .pcs_usb_offset         = 0x300,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .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,
 };
 
@@ -1898,8 +1810,8 @@ static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = {
        .pcs_tbl_num            = ARRAY_SIZE(sm8250_usb3_uniphy_pcs_tbl),
        .pcs_usb_tbl            = sm8250_usb3_uniphy_pcs_usb_tbl,
        .pcs_usb_tbl_num        = ARRAY_SIZE(sm8250_usb3_uniphy_pcs_usb_tbl),
-       .clk_list               = qmp_v4_phy_clk_l,
-       .num_clks               = ARRAY_SIZE(qmp_v4_phy_clk_l),
+       .clk_list               = qmp_v4_ref_phy_clk_l,
+       .num_clks               = ARRAY_SIZE(qmp_v4_ref_phy_clk_l),
        .reset_list             = msm8996_usb3phy_reset_l,
        .num_resets             = ARRAY_SIZE(msm8996_usb3phy_reset_l),
        .vreg_list              = qmp_phy_vreg_l,
@@ -1907,13 +1819,7 @@ static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = {
        .regs                   = qmp_v4_usb3phy_regs_layout,
        .pcs_usb_offset         = 0x600,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
 };
 
 static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = {
@@ -1938,13 +1844,7 @@ static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = {
        .regs                   = qmp_v4_usb3phy_regs_layout,
        .pcs_usb_offset         = 0x600,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
 };
 
 static const struct qmp_phy_cfg sdx65_usb3_uniphy_cfg = {
@@ -1969,13 +1869,7 @@ static const struct qmp_phy_cfg sdx65_usb3_uniphy_cfg = {
        .regs                   = qmp_v4_usb3phy_regs_layout,
        .pcs_usb_offset         = 0x1000,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
 };
 
 static const struct qmp_phy_cfg sm8350_usb3phy_cfg = {
@@ -2000,14 +1894,7 @@ static const struct qmp_phy_cfg sm8350_usb3phy_cfg = {
        .regs                   = qmp_v4_usb3phy_regs_layout,
        .pcs_usb_offset         = 0x300,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .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,
 };
 
@@ -2024,8 +1911,8 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = {
        .pcs_tbl_num            = ARRAY_SIZE(sm8350_usb3_uniphy_pcs_tbl),
        .pcs_usb_tbl            = sm8350_usb3_uniphy_pcs_usb_tbl,
        .pcs_usb_tbl_num        = ARRAY_SIZE(sm8350_usb3_uniphy_pcs_usb_tbl),
-       .clk_list               = qmp_v4_phy_clk_l,
-       .num_clks               = ARRAY_SIZE(qmp_v4_phy_clk_l),
+       .clk_list               = qmp_v4_ref_phy_clk_l,
+       .num_clks               = ARRAY_SIZE(qmp_v4_ref_phy_clk_l),
        .reset_list             = msm8996_usb3phy_reset_l,
        .num_resets             = ARRAY_SIZE(msm8996_usb3phy_reset_l),
        .vreg_list              = qmp_phy_vreg_l,
@@ -2033,13 +1920,7 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = {
        .regs                   = qmp_v4_usb3phy_regs_layout,
        .pcs_usb_offset         = 0x1000,
 
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
-
        .has_pwrdn_delay        = true,
-       .pwrdn_delay_min        = POWER_DOWN_DELAY_US_MIN,
-       .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
 };
 
 static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
@@ -2060,14 +1941,9 @@ static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
        .vreg_list              = qmp_phy_vreg_l,
        .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
        .regs                   = qcm2290_usb3phy_regs_layout,
-
-       .start_ctrl             = SERDES_START | PCS_START,
-       .pwrdn_ctrl             = SW_PWRDN,
-       .phy_status             = PHYSTATUS,
 };
 
 static void qmp_usb_configure_lane(void __iomem *base,
-                                       const unsigned int *regs,
                                        const struct qmp_phy_init_tbl tbl[],
                                        int num,
                                        u8 lane_mask)
@@ -2082,43 +1958,37 @@ static void qmp_usb_configure_lane(void __iomem *base,
                if (!(t->lane_mask & lane_mask))
                        continue;
 
-               if (t->in_layout)
-                       writel(t->val, base + regs[t->offset]);
-               else
-                       writel(t->val, base + t->offset);
+               writel(t->val, base + t->offset);
        }
 }
 
 static void qmp_usb_configure(void __iomem *base,
-                                  const unsigned int *regs,
                                   const struct qmp_phy_init_tbl tbl[],
                                   int num)
 {
-       qmp_usb_configure_lane(base, regs, tbl, num, 0xff);
+       qmp_usb_configure_lane(base, tbl, num, 0xff);
 }
 
-static int qmp_usb_serdes_init(struct qmp_phy *qphy)
+static int qmp_usb_serdes_init(struct qmp_usb *qmp)
 {
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *serdes = qphy->serdes;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *serdes = qmp->serdes;
        const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl;
        int serdes_tbl_num = cfg->serdes_tbl_num;
 
-       qmp_usb_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num);
+       qmp_usb_configure(serdes, serdes_tbl, serdes_tbl_num);
 
        return 0;
 }
 
 static int qmp_usb_init(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *pcs = qphy->pcs;
+       struct qmp_usb *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *pcs = qmp->pcs;
        void __iomem *dp_com = qmp->dp_com;
        int ret;
 
-       /* turn on regulator supplies */
        ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
        if (ret) {
                dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
@@ -2164,13 +2034,7 @@ static int qmp_usb_init(struct phy *phy)
                qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET);
        }
 
-       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_V2_PCS_POWER_DOWN_CONTROL,
-                            cfg->pwrdn_ctrl);
+       qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN);
 
        return 0;
 
@@ -2184,9 +2048,8 @@ err_disable_regulators:
 
 static int qmp_usb_exit(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_usb *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
        reset_control_bulk_assert(cfg->num_resets, qmp->resets);
 
@@ -2199,56 +2062,45 @@ static int qmp_usb_exit(struct phy *phy)
 
 static int qmp_usb_power_on(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *tx = qphy->tx;
-       void __iomem *rx = qphy->rx;
-       void __iomem *pcs = qphy->pcs;
+       struct qmp_usb *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *tx = qmp->tx;
+       void __iomem *rx = qmp->rx;
+       void __iomem *pcs = qmp->pcs;
        void __iomem *status;
-       unsigned int mask, val, ready;
+       unsigned int val;
        int ret;
 
-       qmp_usb_serdes_init(qphy);
+       qmp_usb_serdes_init(qmp);
 
-       ret = clk_prepare_enable(qphy->pipe_clk);
+       ret = clk_prepare_enable(qmp->pipe_clk);
        if (ret) {
                dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
                return ret;
        }
 
        /* Tx, Rx, and PCS configurations */
-       qmp_usb_configure_lane(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num, 1);
-
-       if (cfg->lanes >= 2) {
-               qmp_usb_configure_lane(qphy->tx2, cfg->regs,
-                                       cfg->tx_tbl, cfg->tx_tbl_num, 2);
-       }
-
-       qmp_usb_configure_lane(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num, 1);
+       qmp_usb_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
+       qmp_usb_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
 
        if (cfg->lanes >= 2) {
-               qmp_usb_configure_lane(qphy->rx2, cfg->regs,
-                                       cfg->rx_tbl, cfg->rx_tbl_num, 2);
+               qmp_usb_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
+               qmp_usb_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
        }
 
-       /* Configure link rate, swing, etc. */
-       qmp_usb_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
+       qmp_usb_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
 
        if (cfg->has_pwrdn_delay)
-               usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max);
+               usleep_range(10, 20);
 
        /* Pull PHY out of reset state */
        qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
        /* start SerDes and Phy-Coding-Sublayer */
-       qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
+       qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);
 
        status = pcs + cfg->regs[QPHY_PCS_STATUS];
-       mask = cfg->phy_status;
-       ready = 0;
-
-       ret = readl_poll_timeout(status, val, (val & mask) == ready, 10,
+       ret = readl_poll_timeout(status, val, !(val & PHYSTATUS), 200,
                                 PHY_INIT_COMPLETE_TIMEOUT);
        if (ret) {
                dev_err(qmp->dev, "phy initialization timed-out\n");
@@ -2258,32 +2110,28 @@ static int qmp_usb_power_on(struct phy *phy)
        return 0;
 
 err_disable_pipe_clk:
-       clk_disable_unprepare(qphy->pipe_clk);
+       clk_disable_unprepare(qmp->pipe_clk);
 
        return ret;
 }
 
 static int qmp_usb_power_off(struct phy *phy)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_usb *qmp = phy_get_drvdata(phy);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
-       clk_disable_unprepare(qphy->pipe_clk);
+       clk_disable_unprepare(qmp->pipe_clk);
 
        /* PHY reset */
-       qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
+       qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
        /* stop SerDes and Phy-Coding-Sublayer */
-       qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
+       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL],
+                       SERDES_START | PCS_START);
 
        /* Put PHY into POWER DOWN state: active low */
-       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_V2_PCS_POWER_DOWN_CONTROL,
-                               cfg->pwrdn_ctrl);
-       }
+       qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
+                       SW_PWRDN);
 
        return 0;
 }
@@ -2315,22 +2163,29 @@ static int qmp_usb_disable(struct phy *phy)
 
 static int qmp_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode)
 {
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
+       struct qmp_usb *qmp = phy_get_drvdata(phy);
 
-       qphy->mode = mode;
+       qmp->mode = mode;
 
        return 0;
 }
 
-static void qmp_usb_enable_autonomous_mode(struct qmp_phy *qphy)
+static const struct phy_ops qmp_usb_phy_ops = {
+       .init           = qmp_usb_enable,
+       .exit           = qmp_usb_disable,
+       .set_mode       = qmp_usb_set_mode,
+       .owner          = THIS_MODULE,
+};
+
+static void qmp_usb_enable_autonomous_mode(struct qmp_usb *qmp)
 {
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *pcs_usb = qphy->pcs_usb ?: qphy->pcs;
-       void __iomem *pcs_misc = qphy->pcs_misc;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs;
+       void __iomem *pcs_misc = qmp->pcs_misc;
        u32 intr_mask;
 
-       if (qphy->mode == PHY_MODE_USB_HOST_SS ||
-           qphy->mode == PHY_MODE_USB_DEVICE_SS)
+       if (qmp->mode == PHY_MODE_USB_HOST_SS ||
+           qmp->mode == PHY_MODE_USB_DEVICE_SS)
                intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN;
        else
                intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL;
@@ -2351,11 +2206,11 @@ static void qmp_usb_enable_autonomous_mode(struct qmp_phy *qphy)
                qphy_clrbits(pcs_misc, QPHY_V3_PCS_MISC_CLAMP_ENABLE, CLAMP_EN);
 }
 
-static void qmp_usb_disable_autonomous_mode(struct qmp_phy *qphy)
+static void qmp_usb_disable_autonomous_mode(struct qmp_usb *qmp)
 {
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
-       void __iomem *pcs_usb = qphy->pcs_usb ?: qphy->pcs;
-       void __iomem *pcs_misc = qphy->pcs_misc;
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs;
+       void __iomem *pcs_misc = qmp->pcs_misc;
 
        /* Disable i/o clamp_n on resume for normal mode */
        if (pcs_misc)
@@ -2371,20 +2226,19 @@ static void qmp_usb_disable_autonomous_mode(struct qmp_phy *qphy)
 
 static int __maybe_unused qmp_usb_runtime_suspend(struct device *dev)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
-       struct qmp_phy *qphy = qmp->phys[0];
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_usb *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
 
-       dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qphy->mode);
+       dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);
 
-       if (!qphy->phy->init_count) {
+       if (!qmp->phy->init_count) {
                dev_vdbg(dev, "PHY not initialized, bailing out\n");
                return 0;
        }
 
-       qmp_usb_enable_autonomous_mode(qphy);
+       qmp_usb_enable_autonomous_mode(qmp);
 
-       clk_disable_unprepare(qphy->pipe_clk);
+       clk_disable_unprepare(qmp->pipe_clk);
        clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
 
        return 0;
@@ -2392,14 +2246,13 @@ static int __maybe_unused qmp_usb_runtime_suspend(struct device *dev)
 
 static int __maybe_unused qmp_usb_runtime_resume(struct device *dev)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
-       struct qmp_phy *qphy = qmp->phys[0];
-       const struct qmp_phy_cfg *cfg = qphy->cfg;
+       struct qmp_usb *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
        int ret = 0;
 
-       dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qphy->mode);
+       dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
 
-       if (!qphy->phy->init_count) {
+       if (!qmp->phy->init_count) {
                dev_vdbg(dev, "PHY not initialized, bailing out\n");
                return 0;
        }
@@ -2408,21 +2261,27 @@ static int __maybe_unused qmp_usb_runtime_resume(struct device *dev)
        if (ret)
                return ret;
 
-       ret = clk_prepare_enable(qphy->pipe_clk);
+       ret = clk_prepare_enable(qmp->pipe_clk);
        if (ret) {
                dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
                clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
                return ret;
        }
 
-       qmp_usb_disable_autonomous_mode(qphy);
+       qmp_usb_disable_autonomous_mode(qmp);
 
        return 0;
 }
 
-static int qmp_usb_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg)
+static const struct dev_pm_ops qmp_usb_pm_ops = {
+       SET_RUNTIME_PM_OPS(qmp_usb_runtime_suspend,
+                          qmp_usb_runtime_resume, NULL)
+};
+
+static int qmp_usb_vreg_init(struct qmp_usb *qmp)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        int num = cfg->num_vregs;
        int i;
 
@@ -2436,9 +2295,10 @@ static int qmp_usb_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg)
        return devm_regulator_bulk_get(dev, num, qmp->vregs);
 }
 
-static int qmp_usb_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg)
+static int qmp_usb_reset_init(struct qmp_usb *qmp)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        int i;
        int ret;
 
@@ -2457,9 +2317,10 @@ static int qmp_usb_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg)
        return 0;
 }
 
-static int qmp_usb_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg)
+static int qmp_usb_clk_init(struct qmp_usb *qmp)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        int num = cfg->num_clks;
        int i;
 
@@ -2496,9 +2357,9 @@ static void phy_clk_release_provider(void *res)
  *    clk  |   +-------+   |                   +-----+
  *         +---------------+
  */
-static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
+static int phy_pipe_clk_register(struct qmp_usb *qmp, struct device_node *np)
 {
-       struct clk_fixed_rate *fixed;
+       struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;
        struct clk_init_data init = { };
        int ret;
 
@@ -2508,10 +2369,6 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
                return ret;
        }
 
-       fixed = devm_kzalloc(qmp->dev, sizeof(*fixed), GFP_KERNEL);
-       if (!fixed)
-               return -ENOMEM;
-
        init.ops = &clk_fixed_rate_ops;
 
        /* controllers using QMP phys use 125MHz pipe clock interface */
@@ -2533,13 +2390,6 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
        return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np);
 }
 
-static const struct phy_ops qmp_usb_ops = {
-       .init           = qmp_usb_enable,
-       .exit           = qmp_usb_disable,
-       .set_mode       = qmp_usb_set_mode,
-       .owner          = THIS_MODULE,
-};
-
 static void __iomem *qmp_usb_iomap(struct device *dev, struct device_node *np,
                                        int index, bool exclusive)
 {
@@ -2555,15 +2405,22 @@ static void __iomem *qmp_usb_iomap(struct device *dev, struct device_node *np,
        return devm_of_iomap(dev, np, index, NULL);
 }
 
-static
-int qmp_usb_create(struct device *dev, struct device_node *np, int id,
-                       void __iomem *serdes, const struct qmp_phy_cfg *cfg)
+static int qmp_usb_parse_dt_legacy(struct qmp_usb *qmp, struct device_node *np)
 {
-       struct qcom_qmp *qmp = dev_get_drvdata(dev);
-       struct phy *generic_phy;
-       struct qmp_phy *qphy;
+       struct platform_device *pdev = to_platform_device(qmp->dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       struct device *dev = qmp->dev;
        bool exclusive = true;
-       int ret;
+
+       qmp->serdes = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(qmp->serdes))
+               return PTR_ERR(qmp->serdes);
+
+       if (cfg->has_phy_dp_com_ctrl) {
+               qmp->dp_com = devm_platform_ioremap_resource(pdev, 1);
+               if (IS_ERR(qmp->dp_com))
+                       return PTR_ERR(qmp->dp_com);
+       }
 
        /*
         * FIXME: These bindings should be fixed to not rely on overlapping
@@ -2574,83 +2431,176 @@ int qmp_usb_create(struct device *dev, struct device_node *np, int id,
        if (of_device_is_compatible(dev->of_node, "qcom,sm8350-qmp-usb3-uni-phy"))
                exclusive = false;
 
-       qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
-       if (!qphy)
-               return -ENOMEM;
-
-       qphy->cfg = cfg;
-       qphy->serdes = serdes;
        /*
-        * Get memory resources for each phy lane:
+        * Get memory resources for the PHY:
         * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2.
         * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5
         * For single lane PHYs: pcs_misc (optional) -> 3.
         */
-       qphy->tx = devm_of_iomap(dev, np, 0, NULL);
-       if (IS_ERR(qphy->tx))
-               return PTR_ERR(qphy->tx);
+       qmp->tx = devm_of_iomap(dev, np, 0, NULL);
+       if (IS_ERR(qmp->tx))
+               return PTR_ERR(qmp->tx);
 
-       qphy->rx = devm_of_iomap(dev, np, 1, NULL);
-       if (IS_ERR(qphy->rx))
-               return PTR_ERR(qphy->rx);
+       qmp->rx = devm_of_iomap(dev, np, 1, NULL);
+       if (IS_ERR(qmp->rx))
+               return PTR_ERR(qmp->rx);
 
-       qphy->pcs = qmp_usb_iomap(dev, np, 2, exclusive);
-       if (IS_ERR(qphy->pcs))
-               return PTR_ERR(qphy->pcs);
+       qmp->pcs = qmp_usb_iomap(dev, np, 2, exclusive);
+       if (IS_ERR(qmp->pcs))
+               return PTR_ERR(qmp->pcs);
 
        if (cfg->pcs_usb_offset)
-               qphy->pcs_usb = qphy->pcs + cfg->pcs_usb_offset;
+               qmp->pcs_usb = qmp->pcs + cfg->pcs_usb_offset;
 
        if (cfg->lanes >= 2) {
-               qphy->tx2 = devm_of_iomap(dev, np, 3, NULL);
-               if (IS_ERR(qphy->tx2))
-                       return PTR_ERR(qphy->tx2);
+               qmp->tx2 = devm_of_iomap(dev, np, 3, NULL);
+               if (IS_ERR(qmp->tx2))
+                       return PTR_ERR(qmp->tx2);
 
-               qphy->rx2 = devm_of_iomap(dev, np, 4, NULL);
-               if (IS_ERR(qphy->rx2))
-                       return PTR_ERR(qphy->rx2);
+               qmp->rx2 = devm_of_iomap(dev, np, 4, NULL);
+               if (IS_ERR(qmp->rx2))
+                       return PTR_ERR(qmp->rx2);
 
-               qphy->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
+               qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL);
        } else {
-               qphy->pcs_misc = devm_of_iomap(dev, np, 3, NULL);
+               qmp->pcs_misc = devm_of_iomap(dev, np, 3, NULL);
        }
 
-       if (IS_ERR(qphy->pcs_misc)) {
+       if (IS_ERR(qmp->pcs_misc)) {
                dev_vdbg(dev, "PHY pcs_misc-reg not used\n");
-               qphy->pcs_misc = NULL;
+               qmp->pcs_misc = NULL;
        }
 
-       qphy->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
-       if (IS_ERR(qphy->pipe_clk)) {
-               return dev_err_probe(dev, PTR_ERR(qphy->pipe_clk),
-                                    "failed to get lane%d pipe clock\n", id);
+       qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
+       if (IS_ERR(qmp->pipe_clk)) {
+               return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
+                                    "failed to get pipe clock\n");
+       }
+
+       return 0;
+}
+
+static int qmp_usb_parse_dt(struct qmp_usb *qmp)
+{
+       struct platform_device *pdev = to_platform_device(qmp->dev);
+       const struct qmp_phy_cfg *cfg = qmp->cfg;
+       const struct qmp_usb_offsets *offs = cfg->offsets;
+       struct device *dev = qmp->dev;
+       void __iomem *base;
+
+       if (!offs)
+               return -EINVAL;
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       qmp->serdes = base + offs->serdes;
+       qmp->pcs = base + offs->pcs;
+       qmp->pcs_usb = base + offs->pcs_usb;
+       qmp->tx = base + offs->tx;
+       qmp->rx = base + offs->rx;
+
+       qmp->pipe_clk = devm_clk_get(dev, "pipe");
+       if (IS_ERR(qmp->pipe_clk)) {
+               return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
+                                    "failed to get pipe clock\n");
        }
 
-       generic_phy = devm_phy_create(dev, np, &qmp_usb_ops);
-       if (IS_ERR(generic_phy)) {
-               ret = PTR_ERR(generic_phy);
-               dev_err(dev, "failed to create qphy %d\n", ret);
+       return 0;
+}
+
+static int qmp_usb_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct phy_provider *phy_provider;
+       struct device_node *np;
+       struct qmp_usb *qmp;
+       int ret;
+
+       qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
+       if (!qmp)
+               return -ENOMEM;
+
+       qmp->dev = dev;
+
+       qmp->cfg = of_device_get_match_data(dev);
+       if (!qmp->cfg)
+               return -EINVAL;
+
+       ret = qmp_usb_clk_init(qmp);
+       if (ret)
                return ret;
+
+       ret = qmp_usb_reset_init(qmp);
+       if (ret)
+               return ret;
+
+       ret = qmp_usb_vreg_init(qmp);
+       if (ret)
+               return ret;
+
+       /* Check for legacy binding with child node. */
+       np = of_get_next_available_child(dev->of_node, NULL);
+       if (np) {
+               ret = qmp_usb_parse_dt_legacy(qmp, np);
+       } else {
+               np = of_node_get(dev->of_node);
+               ret = qmp_usb_parse_dt(qmp);
+       }
+       if (ret)
+               goto err_node_put;
+
+       pm_runtime_set_active(dev);
+       ret = devm_pm_runtime_enable(dev);
+       if (ret)
+               goto err_node_put;
+       /*
+        * Prevent runtime pm from being ON by default. Users can enable
+        * it using power/control in sysfs.
+        */
+       pm_runtime_forbid(dev);
+
+       ret = phy_pipe_clk_register(qmp, np);
+       if (ret)
+               goto err_node_put;
+
+       qmp->phy = devm_phy_create(dev, np, &qmp_usb_phy_ops);
+       if (IS_ERR(qmp->phy)) {
+               ret = PTR_ERR(qmp->phy);
+               dev_err(dev, "failed to create PHY: %d\n", ret);
+               goto err_node_put;
        }
 
-       qphy->phy = generic_phy;
-       qphy->qmp = qmp;
-       qmp->phys[id] = qphy;
-       phy_set_drvdata(generic_phy, qphy);
+       phy_set_drvdata(qmp->phy, qmp);
 
-       return 0;
+       of_node_put(np);
+
+       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+       return PTR_ERR_OR_ZERO(phy_provider);
+
+err_node_put:
+       of_node_put(np);
+       return ret;
 }
 
 static const struct of_device_id qmp_usb_of_match_table[] = {
        {
+               .compatible = "qcom,ipq6018-qmp-usb3-phy",
+               .data = &ipq8074_usb3phy_cfg,
+       }, {
                .compatible = "qcom,ipq8074-qmp-usb3-phy",
                .data = &ipq8074_usb3phy_cfg,
        }, {
                .compatible = "qcom,msm8996-qmp-usb3-phy",
                .data = &msm8996_usb3phy_cfg,
        }, {
-               .compatible = "qcom,ipq6018-qmp-usb3-phy",
-               .data = &ipq8074_usb3phy_cfg,
+               .compatible = "qcom,msm8998-qmp-usb3-phy",
+               .data = &msm8998_usb3phy_cfg,
+       }, {
+               .compatible = "qcom,qcm2290-qmp-usb3-phy",
+               .data = &qcm2290_usb3phy_cfg,
        }, {
                .compatible = "qcom,sc7180-qmp-usb3-phy",
                .data = &sc7180_usb3phy_cfg,
@@ -2667,8 +2617,11 @@ static const struct of_device_id qmp_usb_of_match_table[] = {
                .compatible = "qcom,sdm845-qmp-usb3-uni-phy",
                .data = &qmp_v3_usb3_uniphy_cfg,
        }, {
-               .compatible = "qcom,msm8998-qmp-usb3-phy",
-               .data = &msm8998_usb3phy_cfg,
+               .compatible = "qcom,sdx55-qmp-usb3-uni-phy",
+               .data = &sdx55_usb3_uniphy_cfg,
+       }, {
+               .compatible = "qcom,sdx65-qmp-usb3-uni-phy",
+               .data = &sdx65_usb3_uniphy_cfg,
        }, {
                .compatible = "qcom,sm8150-qmp-usb3-phy",
                .data = &sm8150_usb3phy_cfg,
@@ -2681,12 +2634,6 @@ static const struct of_device_id qmp_usb_of_match_table[] = {
        }, {
                .compatible = "qcom,sm8250-qmp-usb3-uni-phy",
                .data = &sm8250_usb3_uniphy_cfg,
-       }, {
-               .compatible = "qcom,sdx55-qmp-usb3-uni-phy",
-               .data = &sdx55_usb3_uniphy_cfg,
-       }, {
-               .compatible = "qcom,sdx65-qmp-usb3-uni-phy",
-               .data = &sdx65_usb3_uniphy_cfg,
        }, {
                .compatible = "qcom,sm8350-qmp-usb3-phy",
                .data = &sm8350_usb3phy_cfg,
@@ -2696,119 +2643,11 @@ static const struct of_device_id qmp_usb_of_match_table[] = {
        }, {
                .compatible = "qcom,sm8450-qmp-usb3-phy",
                .data = &sm8350_usb3phy_cfg,
-       }, {
-               .compatible = "qcom,qcm2290-qmp-usb3-phy",
-               .data = &qcm2290_usb3phy_cfg,
        },
        { },
 };
 MODULE_DEVICE_TABLE(of, qmp_usb_of_match_table);
 
-static const struct dev_pm_ops qmp_usb_pm_ops = {
-       SET_RUNTIME_PM_OPS(qmp_usb_runtime_suspend,
-                          qmp_usb_runtime_resume, NULL)
-};
-
-static int qmp_usb_probe(struct platform_device *pdev)
-{
-       struct qcom_qmp *qmp;
-       struct device *dev = &pdev->dev;
-       struct device_node *child;
-       struct phy_provider *phy_provider;
-       void __iomem *serdes;
-       const struct qmp_phy_cfg *cfg = NULL;
-       int num, id;
-       int ret;
-
-       qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
-       if (!qmp)
-               return -ENOMEM;
-
-       qmp->dev = dev;
-       dev_set_drvdata(dev, qmp);
-
-       /* Get the specific init parameters of QMP phy */
-       cfg = of_device_get_match_data(dev);
-       if (!cfg)
-               return -EINVAL;
-
-       /* per PHY serdes; usually located at base address */
-       serdes = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(serdes))
-               return PTR_ERR(serdes);
-
-       /* per PHY dp_com; if PHY has dp_com control block */
-       if (cfg->has_phy_dp_com_ctrl) {
-               qmp->dp_com = devm_platform_ioremap_resource(pdev, 1);
-               if (IS_ERR(qmp->dp_com))
-                       return PTR_ERR(qmp->dp_com);
-       }
-
-       ret = qmp_usb_clk_init(dev, cfg);
-       if (ret)
-               return ret;
-
-       ret = qmp_usb_reset_init(dev, cfg);
-       if (ret)
-               return ret;
-
-       ret = qmp_usb_vreg_init(dev, cfg);
-       if (ret)
-               return dev_err_probe(dev, ret,
-                                    "failed to get regulator supplies\n");
-
-       num = of_get_available_child_count(dev->of_node);
-       /* do we have a rogue child node ? */
-       if (num > 1)
-               return -EINVAL;
-
-       qmp->phys = devm_kcalloc(dev, num, sizeof(*qmp->phys), GFP_KERNEL);
-       if (!qmp->phys)
-               return -ENOMEM;
-
-       pm_runtime_set_active(dev);
-       ret = devm_pm_runtime_enable(dev);
-       if (ret)
-               return ret;
-       /*
-        * Prevent runtime pm from being ON by default. Users can enable
-        * it using power/control in sysfs.
-        */
-       pm_runtime_forbid(dev);
-
-       id = 0;
-       for_each_available_child_of_node(dev->of_node, child) {
-               /* Create per-lane phy */
-               ret = qmp_usb_create(dev, child, id, serdes, cfg);
-               if (ret) {
-                       dev_err(dev, "failed to create lane%d phy, %d\n",
-                               id, ret);
-                       goto err_node_put;
-               }
-
-               /*
-                * Register the pipe clock provided by phy.
-                * See function description to see details of this pipe clock.
-                */
-               ret = phy_pipe_clk_register(qmp, child);
-               if (ret) {
-                       dev_err(qmp->dev,
-                               "failed to register pipe clock source\n");
-                       goto err_node_put;
-               }
-
-               id++;
-       }
-
-       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-
-       return PTR_ERR_OR_ZERO(phy_provider);
-
-err_node_put:
-       of_node_put(child);
-       return ret;
-}
-
 static struct platform_driver qmp_usb_driver = {
        .probe          = qmp_usb_probe,
        .driver = {
index 26274e3c0cf9512615f71b217ecce49147602342..29a48f0436d2aa9fa4f2eade4fb729d2775f8b4d 100644 (file)
@@ -38,6 +38,7 @@
 #include "phy-qcom-qmp-pcs-pcie-v4_20.h"
 
 #include "phy-qcom-qmp-pcs-v5.h"
+#include "phy-qcom-qmp-pcs-v5_20.h"
 #include "phy-qcom-qmp-pcs-pcie-v5.h"
 #include "phy-qcom-qmp-pcs-usb-v5.h"
 #include "phy-qcom-qmp-pcs-ufs-v5.h"
index 111bdcae775c8ddf4e6185479fa694d56fdfbf55..36505fc5f386e2ca17b3efa8b30c1eb554b3e9a7 100644 (file)
@@ -2,6 +2,14 @@
 #
 # Phy drivers for Renesas platforms
 #
+# NOTE: Please sorted config names alphabetically.
+config PHY_R8A779F0_ETHERNET_SERDES
+       tristate "Renesas R-Car S4-8 Ethernet SERDES driver"
+       depends on ARCH_RENESAS || COMPILE_TEST
+       select GENERIC_PHY
+       help
+         Support for Ethernet SERDES found on Renesas R-Car S4-8 SoCs.
+
 config PHY_RCAR_GEN2
        tristate "Renesas R-Car generation 2 USB PHY driver"
        depends on ARCH_RENESAS
index b599ff8a4349cff092fa37ae15968ec72ab33be7..8896d1919faa6ec11ae6c1e6bf65960cb948914f 100644 (file)
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_PHY_R8A779F0_ETHERNET_SERDES)     += r8a779f0-ether-serdes.o
 obj-$(CONFIG_PHY_RCAR_GEN2)            += phy-rcar-gen2.o
 obj-$(CONFIG_PHY_RCAR_GEN3_PCIE)       += phy-rcar-gen3-pcie.o
 obj-$(CONFIG_PHY_RCAR_GEN3_USB2)       += phy-rcar-gen3-usb2.o
diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c
new file mode 100644 (file)
index 0000000..ec6594e
--- /dev/null
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Renesas Ethernet SERDES device driver
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#define R8A779F0_ETH_SERDES_NUM                        3
+#define R8A779F0_ETH_SERDES_OFFSET             0x0400
+#define R8A779F0_ETH_SERDES_BANK_SELECT                0x03fc
+#define R8A779F0_ETH_SERDES_TIMEOUT_US         100000
+#define R8A779F0_ETH_SERDES_NUM_RETRY_LINKUP   3
+#define R8A779F0_ETH_SERDES_NUM_RETRY_INIT     3
+
+struct r8a779f0_eth_serdes_drv_data;
+struct r8a779f0_eth_serdes_channel {
+       struct r8a779f0_eth_serdes_drv_data *dd;
+       struct phy *phy;
+       void __iomem *addr;
+       phy_interface_t phy_interface;
+       int speed;
+       int index;
+};
+
+struct r8a779f0_eth_serdes_drv_data {
+       void __iomem *addr;
+       struct platform_device *pdev;
+       struct reset_control *reset;
+       struct r8a779f0_eth_serdes_channel channel[R8A779F0_ETH_SERDES_NUM];
+       bool initialized;
+};
+
+/*
+ * The datasheet describes initialization procedure without any information
+ * about registers' name/bits. So, this is all black magic to initialize
+ * the hardware.
+ */
+static void r8a779f0_eth_serdes_write32(void __iomem *addr, u32 offs, u32 bank, u32 data)
+{
+       iowrite32(bank, addr + R8A779F0_ETH_SERDES_BANK_SELECT);
+       iowrite32(data, addr + offs);
+}
+
+static int
+r8a779f0_eth_serdes_reg_wait(struct r8a779f0_eth_serdes_channel *channel,
+                            u32 offs, u32 bank, u32 mask, u32 expected)
+{
+       int ret;
+       u32 val;
+
+       iowrite32(bank, channel->addr + R8A779F0_ETH_SERDES_BANK_SELECT);
+
+       ret = readl_poll_timeout_atomic(channel->addr + offs, val,
+                                       (val & mask) == expected,
+                                       1, R8A779F0_ETH_SERDES_TIMEOUT_US);
+       if (ret)
+               dev_dbg(&channel->phy->dev,
+                       "%s: index %d, offs %x, bank %x, mask %x, expected %x\n",
+                        __func__, channel->index, offs, bank, mask, expected);
+
+       return ret;
+}
+
+static int
+r8a779f0_eth_serdes_common_init_ram(struct r8a779f0_eth_serdes_drv_data *dd)
+{
+       struct r8a779f0_eth_serdes_channel *channel;
+       int i, ret;
+
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
+               channel = &dd->channel[i];
+               ret = r8a779f0_eth_serdes_reg_wait(channel, 0x026c, 0x180, BIT(0), 0x01);
+               if (ret)
+                       return ret;
+       }
+
+       r8a779f0_eth_serdes_write32(dd->addr, 0x026c, 0x180, 0x03);
+
+       return ret;
+}
+
+static int
+r8a779f0_eth_serdes_common_setting(struct r8a779f0_eth_serdes_channel *channel)
+{
+       struct r8a779f0_eth_serdes_drv_data *dd = channel->dd;
+
+       switch (channel->phy_interface) {
+       case PHY_INTERFACE_MODE_SGMII:
+               r8a779f0_eth_serdes_write32(dd->addr, 0x0244, 0x180, 0x0097);
+               r8a779f0_eth_serdes_write32(dd->addr, 0x01d0, 0x180, 0x0060);
+               r8a779f0_eth_serdes_write32(dd->addr, 0x01d8, 0x180, 0x2200);
+               r8a779f0_eth_serdes_write32(dd->addr, 0x01d4, 0x180, 0x0000);
+               r8a779f0_eth_serdes_write32(dd->addr, 0x01e0, 0x180, 0x003d);
+               return 0;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int
+r8a779f0_eth_serdes_chan_setting(struct r8a779f0_eth_serdes_channel *channel)
+{
+       int ret;
+
+       switch (channel->phy_interface) {
+       case PHY_INTERFACE_MODE_SGMII:
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2000);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x01c0, 0x180, 0x0011);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0248, 0x180, 0x0540);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0258, 0x180, 0x0015);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0100);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x01a0, 0x180, 0x0000);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x00d0, 0x180, 0x0002);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0150, 0x180, 0x0003);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0100);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0100);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0174, 0x180, 0x0000);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0160, 0x180, 0x0007);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x01ac, 0x180, 0x0000);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x0310);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x380, 0x0101);
+               ret = r8a779f0_eth_serdes_reg_wait(channel, 0x00c8, 0x0180, BIT(0), 0);
+               if (ret)
+                       return ret;
+
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0101);
+               ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0148, 0x0180, BIT(0), 0);
+               if (ret)
+                       return ret;
+
+               r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x1310);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x00d8, 0x180, 0x1800);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x00dc, 0x180, 0x0000);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x001c, 0x300, 0x0001);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2100);
+               ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0000, 0x0380, BIT(8), 0);
+               if (ret)
+                       return ret;
+
+               if (channel->speed == 1000)
+                       r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x0140);
+               else if (channel->speed == 100)
+                       r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x2100);
+
+               /* For AN_ON */
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0004, 0x1f80, 0x0005);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0028, 0x1f80, 0x07a1);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f80, 0x0208);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static int
+r8a779f0_eth_serdes_chan_speed(struct r8a779f0_eth_serdes_channel *channel)
+{
+       int ret;
+
+       switch (channel->phy_interface) {
+       case PHY_INTERFACE_MODE_SGMII:
+               /* For AN_ON */
+               if (channel->speed == 1000)
+                       r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x1140);
+               else if (channel->speed == 100)
+                       r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x3100);
+               ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0008, 0x1f80, BIT(0), 1);
+               if (ret)
+                       return ret;
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0008, 0x1f80, 0x0000);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+
+static int r8a779f0_eth_serdes_monitor_linkup(struct r8a779f0_eth_serdes_channel *channel)
+{
+       int i, ret;
+
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM_RETRY_LINKUP; i++) {
+               ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0004, 0x300,
+                                                  BIT(2), BIT(2));
+               if (!ret)
+                       break;
+
+               /* restart */
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0100);
+               udelay(1);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0000);
+       }
+
+       return ret;
+}
+
+static int r8a779f0_eth_serdes_hw_init(struct r8a779f0_eth_serdes_channel *channel)
+{
+       struct r8a779f0_eth_serdes_drv_data *dd = channel->dd;
+       int i, ret;
+
+       if (dd->initialized)
+               return 0;
+
+       ret = r8a779f0_eth_serdes_common_init_ram(dd);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
+               ret = r8a779f0_eth_serdes_reg_wait(&dd->channel[i], 0x0000,
+                                                  0x300, BIT(15), 0);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++)
+               r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03d4, 0x380, 0x0443);
+
+       ret = r8a779f0_eth_serdes_common_setting(channel);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++)
+               r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03d0, 0x380, 0x0001);
+
+
+       r8a779f0_eth_serdes_write32(dd->addr, 0x0000, 0x380, 0x8000);
+
+       ret = r8a779f0_eth_serdes_common_init_ram(dd);
+       if (ret)
+               return ret;
+
+       ret = r8a779f0_eth_serdes_reg_wait(&dd->channel[0], 0x0000, 0x380, BIT(15), 0);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
+               ret = r8a779f0_eth_serdes_chan_setting(&dd->channel[i]);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
+               ret = r8a779f0_eth_serdes_chan_speed(&dd->channel[i]);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++)
+               r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03c0, 0x380, 0x0000);
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++)
+               r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03d0, 0x380, 0x0000);
+
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
+               ret = r8a779f0_eth_serdes_monitor_linkup(&dd->channel[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int r8a779f0_eth_serdes_init(struct phy *p)
+{
+       struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
+       int i, ret;
+
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM_RETRY_INIT; i++) {
+               ret = r8a779f0_eth_serdes_hw_init(channel);
+               if (!ret) {
+                       channel->dd->initialized = true;
+                       break;
+               }
+               usleep_range(1000, 2000);
+       }
+
+       return ret;
+}
+
+static int r8a779f0_eth_serdes_set_mode(struct phy *p, enum phy_mode mode,
+                                       int submode)
+{
+       struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
+
+       if (mode != PHY_MODE_ETHERNET)
+               return -EOPNOTSUPP;
+
+       switch (submode) {
+       case PHY_INTERFACE_MODE_GMII:
+       case PHY_INTERFACE_MODE_SGMII:
+       case PHY_INTERFACE_MODE_USXGMII:
+               channel->phy_interface = submode;
+               return 0;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int r8a779f0_eth_serdes_set_speed(struct phy *p, int speed)
+{
+       struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
+
+       channel->speed = speed;
+
+       return 0;
+}
+
+static const struct phy_ops r8a779f0_eth_serdes_ops = {
+       .init           = r8a779f0_eth_serdes_init,
+       .set_mode       = r8a779f0_eth_serdes_set_mode,
+       .set_speed      = r8a779f0_eth_serdes_set_speed,
+};
+
+static struct phy *r8a779f0_eth_serdes_xlate(struct device *dev,
+                                            struct of_phandle_args *args)
+{
+       struct r8a779f0_eth_serdes_drv_data *dd = dev_get_drvdata(dev);
+
+       if (args->args[0] >= R8A779F0_ETH_SERDES_NUM)
+               return ERR_PTR(-ENODEV);
+
+       return dd->channel[args->args[0]].phy;
+}
+
+static const struct of_device_id r8a779f0_eth_serdes_of_table[] = {
+       { .compatible = "renesas,r8a779f0-ether-serdes", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, r8a779f0_eth_serdes_of_table);
+
+static int r8a779f0_eth_serdes_probe(struct platform_device *pdev)
+{
+       struct r8a779f0_eth_serdes_drv_data *dd;
+       struct phy_provider *provider;
+       struct resource *res;
+       int i;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "invalid resource\n");
+               return -EINVAL;
+       }
+
+       dd = devm_kzalloc(&pdev->dev, sizeof(*dd), GFP_KERNEL);
+       if (!dd)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, dd);
+       dd->pdev = pdev;
+       dd->addr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dd->addr))
+               return PTR_ERR(dd->addr);
+
+       dd->reset = devm_reset_control_get(&pdev->dev, NULL);
+       if (IS_ERR(dd->reset))
+               return PTR_ERR(dd->reset);
+
+       reset_control_reset(dd->reset);
+
+       for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
+               struct r8a779f0_eth_serdes_channel *channel = &dd->channel[i];
+
+               channel->phy = devm_phy_create(&pdev->dev, NULL,
+                                              &r8a779f0_eth_serdes_ops);
+               if (IS_ERR(channel->phy))
+                       return PTR_ERR(channel->phy);
+               channel->addr = dd->addr + R8A779F0_ETH_SERDES_OFFSET * i;
+               channel->dd = dd;
+               channel->index = i;
+               phy_set_drvdata(channel->phy, channel);
+       }
+
+       provider = devm_of_phy_provider_register(&pdev->dev,
+                                                r8a779f0_eth_serdes_xlate);
+       if (IS_ERR(provider))
+               return PTR_ERR(provider);
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+
+       return 0;
+}
+
+static int r8a779f0_eth_serdes_remove(struct platform_device *pdev)
+{
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver r8a779f0_eth_serdes_driver_platform = {
+       .probe = r8a779f0_eth_serdes_probe,
+       .remove = r8a779f0_eth_serdes_remove,
+       .driver = {
+               .name = "r8a779f0_eth_serdes",
+               .of_match_table = r8a779f0_eth_serdes_of_table,
+       }
+};
+module_platform_driver(r8a779f0_eth_serdes_driver_platform);
+MODULE_AUTHOR("Yoshihiro Shimoda");
+MODULE_DESCRIPTION("Renesas Ethernet SERDES device driver");
+MODULE_LICENSE("GPL");
index 1415ca71de382fb0dc92b5de276b64ad1ef420fd..633e6b7472759a6b819320dfa9d29adce2171ecc 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/phy/phy.h>
 
 #define P2U_CONTROL_CMN                        0x74
+#define P2U_CONTROL_CMN_ENABLE_L2_EXIT_RATE_CHANGE             BIT(13)
 #define P2U_CONTROL_CMN_SKP_SIZE_PROTECTION_EN                 BIT(20)
 
 #define P2U_PERIODIC_EQ_CTRL_GEN3      0xc0
@@ -85,8 +86,21 @@ static int tegra_p2u_power_on(struct phy *x)
        return 0;
 }
 
+static int tegra_p2u_calibrate(struct phy *x)
+{
+       struct tegra_p2u *phy = phy_get_drvdata(x);
+       u32 val;
+
+       val = p2u_readl(phy, P2U_CONTROL_CMN);
+       val |= P2U_CONTROL_CMN_ENABLE_L2_EXIT_RATE_CHANGE;
+       p2u_writel(phy, val, P2U_CONTROL_CMN);
+
+       return 0;
+}
+
 static const struct phy_ops ops = {
        .power_on = tegra_p2u_power_on,
+       .calibrate = tegra_p2u_calibrate,
        .owner = THIS_MODULE,
 };
 
index db56c7fbe60be01d23f1a4f89f30acef6c0db8a7..f4f75ea033b81a445da1675cc4dc03fc48cd4ae3 100644 (file)
@@ -1652,7 +1652,6 @@ tegra124_usb3_port_map(struct tegra_xusb_port *port)
 
 static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = {
        .release = tegra_xusb_usb3_port_release,
-       .remove = tegra_xusb_usb3_port_remove,
        .enable = tegra124_usb3_port_enable,
        .disable = tegra124_usb3_port_disable,
        .map = tegra124_usb3_port_map,
index 0996ede63387a25a4760b82f70c3ec7c7e3873c1..6a8bd87cfdbda7af843b93849876bece2c528385 100644 (file)
@@ -1185,7 +1185,6 @@ tegra186_usb3_port_map(struct tegra_xusb_port *port)
 
 static const struct tegra_xusb_port_ops tegra186_usb3_port_ops = {
        .release = tegra_xusb_usb3_port_release,
-       .remove = tegra_xusb_usb3_port_remove,
        .enable = tegra186_usb3_port_enable,
        .disable = tegra186_usb3_port_disable,
        .map = tegra186_usb3_port_map,
index eedfc7c2cc05270f0be4598fe758af168bc0fc62..ebc8a7e21a318160b162113eea8a6c97b7ed7966 100644 (file)
@@ -3078,7 +3078,6 @@ tegra210_usb3_port_map(struct tegra_xusb_port *port)
 
 static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = {
        .release = tegra_xusb_usb3_port_release,
-       .remove = tegra_xusb_usb3_port_remove,
        .enable = tegra210_usb3_port_enable,
        .disable = tegra210_usb3_port_disable,
        .map = tegra210_usb3_port_map,
index dce45fbbd699c12c668e17d4cd62d301c96096b2..ff4b930879f3c32b921c95ca0a01ead96804c5a1 100644 (file)
@@ -954,8 +954,7 @@ static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
                        return -EINVAL;
        }
 
-       usb3->supply = regulator_get(&port->dev, "vbus");
-       return PTR_ERR_OR_ZERO(usb3->supply);
+       return 0;
 }
 
 static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl,
@@ -1012,13 +1011,6 @@ void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port)
        kfree(usb3);
 }
 
-void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port)
-{
-       struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
-
-       regulator_put(usb3->supply);
-}
-
 static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl)
 {
        struct tegra_xusb_port *port, *tmp;
index 8cfbbdbd6e0c0103b9086128e7889ab9afc0027f..c384734a61c2ab7f324f5f9bd4baa6313d248348 100644 (file)
@@ -359,7 +359,6 @@ void tegra_xusb_hsic_port_release(struct tegra_xusb_port *port);
 
 struct tegra_xusb_usb3_port {
        struct tegra_xusb_port base;
-       struct regulator *supply;
        bool context_saved;
        unsigned int port;
        bool internal;
@@ -381,7 +380,6 @@ struct tegra_xusb_usb3_port *
 tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl,
                          unsigned int index);
 void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port);
-void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port);
 
 struct tegra_xusb_port_ops {
        void (*release)(struct tegra_xusb_port *port);
index 0bcfd6d96b4d0a67d0d0cc5a7dc579610844c8e4..8c667819c39a10b0fe3186f7f65197ffb4b21f2f 100644 (file)
@@ -50,6 +50,7 @@ struct phy_gmii_sel_soc_data {
        const struct reg_field (*regfields)[PHY_GMII_SEL_LAST];
        bool use_of_data;
        u64 extra_modes;
+       u32 num_qsgmii_main_ports;
 };
 
 struct phy_gmii_sel_priv {
@@ -213,6 +214,17 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = {
        .use_of_data = true,
        .regfields = phy_gmii_sel_fields_am654,
        .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII),
+       .num_ports = 4,
+       .num_qsgmii_main_ports = 1,
+};
+
+static const
+struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j721e = {
+       .use_of_data = true,
+       .regfields = phy_gmii_sel_fields_am654,
+       .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII),
+       .num_ports = 8,
+       .num_qsgmii_main_ports = 2,
 };
 
 static const struct of_device_id phy_gmii_sel_id_table[] = {
@@ -240,6 +252,10 @@ static const struct of_device_id phy_gmii_sel_id_table[] = {
                .compatible     = "ti,j7200-cpsw5g-phy-gmii-sel",
                .data           = &phy_gmii_sel_cpsw5g_soc_j7200,
        },
+       {
+               .compatible     = "ti,j721e-cpsw9g-phy-gmii-sel",
+               .data           = &phy_gmii_sel_cpsw9g_soc_j721e,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table);
@@ -378,11 +394,13 @@ static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
 static int phy_gmii_sel_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       const struct phy_gmii_sel_soc_data *soc_data;
        struct device_node *node = dev->of_node;
        const struct of_device_id *of_id;
        struct phy_gmii_sel_priv *priv;
        u32 main_ports = 1;
        int ret;
+       u32 i;
 
        of_id = of_match_node(phy_gmii_sel_id_table, pdev->dev.of_node);
        if (!of_id)
@@ -394,16 +412,26 @@ static int phy_gmii_sel_probe(struct platform_device *pdev)
 
        priv->dev = &pdev->dev;
        priv->soc_data = of_id->data;
+       soc_data = priv->soc_data;
        priv->num_ports = priv->soc_data->num_ports;
-       of_property_read_u32(node, "ti,qsgmii-main-ports", &main_ports);
+       priv->qsgmii_main_ports = 0;
+
        /*
-        * Ensure that main_ports is within bounds. If the property
-        * ti,qsgmii-main-ports is not mentioned, or the value mentioned
-        * is out of bounds, default to 1.
+        * Based on the compatible, try to read the appropriate number of
+        * QSGMII main ports from the "ti,qsgmii-main-ports" property from
+        * the device-tree node.
         */
-       if (main_ports < 1 || main_ports > 4)
-               main_ports = 1;
-       priv->qsgmii_main_ports = PHY_GMII_PORT(main_ports);
+       for (i = 0; i < soc_data->num_qsgmii_main_ports; i++) {
+               of_property_read_u32_index(node, "ti,qsgmii-main-ports", i, &main_ports);
+               /*
+                * Ensure that main_ports is within bounds.
+                */
+               if (main_ports < 1 || main_ports > soc_data->num_ports) {
+                       dev_err(dev, "Invalid qsgmii main port provided\n");
+                       return -EINVAL;
+               }
+               priv->qsgmii_main_ports |= PHY_GMII_PORT(main_ports);
+       }
 
        priv->regmap = syscon_node_to_regmap(node->parent);
        if (IS_ERR(priv->regmap)) {
index 41725c6bcdf6f30656127165c96838b0eed502c9..ddce5ef7711c605541951e38698a18c79ec2f7e6 100644 (file)
@@ -81,14 +81,20 @@ static const struct reg_field phy_reset_n = REG_FIELD(WIZ_SERDES_RST, 31, 31);
 static const struct reg_field phy_en_refclk = REG_FIELD(WIZ_SERDES_RST, 30, 30);
 static const struct reg_field pll1_refclk_mux_sel =
                                        REG_FIELD(WIZ_SERDES_RST, 29, 29);
+static const struct reg_field pll1_refclk_mux_sel_2 =
+                                       REG_FIELD(WIZ_SERDES_RST, 22, 23);
 static const struct reg_field pll0_refclk_mux_sel =
                                        REG_FIELD(WIZ_SERDES_RST, 28, 28);
+static const struct reg_field pll0_refclk_mux_sel_2 =
+                                       REG_FIELD(WIZ_SERDES_RST, 28, 29);
 static const struct reg_field refclk_dig_sel_16g =
                                        REG_FIELD(WIZ_SERDES_RST, 24, 25);
 static const struct reg_field refclk_dig_sel_10g =
                                        REG_FIELD(WIZ_SERDES_RST, 24, 24);
 static const struct reg_field pma_cmn_refclk_int_mode =
                                        REG_FIELD(WIZ_SERDES_TOP_CTRL, 28, 29);
+static const struct reg_field pma_cmn_refclk1_int_mode =
+                                       REG_FIELD(WIZ_SERDES_TOP_CTRL, 20, 21);
 static const struct reg_field pma_cmn_refclk_mode =
                                        REG_FIELD(WIZ_SERDES_TOP_CTRL, 30, 31);
 static const struct reg_field pma_cmn_refclk_dig_div =
@@ -315,6 +321,8 @@ enum wiz_type {
        J721E_WIZ_10G,  /* Also for J7200 SR1.0 */
        AM64_WIZ_10G,
        J7200_WIZ_10G,  /* J7200 SR2.0 */
+       J784S4_WIZ_10G,
+       J721S2_WIZ_10G,
 };
 
 struct wiz_data {
@@ -992,6 +1000,8 @@ static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node)
        switch (wiz->type) {
        case AM64_WIZ_10G:
        case J7200_WIZ_10G:
+       case J784S4_WIZ_10G:
+       case J721S2_WIZ_10G:
                of_clk_del_provider(dev->of_node);
                return;
        default:
@@ -1123,6 +1133,8 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
        switch (wiz->type) {
        case AM64_WIZ_10G:
        case J7200_WIZ_10G:
+       case J784S4_WIZ_10G:
+       case J721S2_WIZ_10G:
                ret = wiz_clock_register(wiz);
                if (ret)
                        dev_err(dev, "Failed to register wiz clocks\n");
@@ -1205,6 +1217,7 @@ static int wiz_phy_fullrt_div(struct wiz *wiz, int lane)
                break;
        case J721E_WIZ_10G:
        case J7200_WIZ_10G:
+       case J721S2_WIZ_10G:
                if (wiz->lane_phy_type[lane] == PHY_TYPE_SGMII)
                        return regmap_field_write(wiz->p0_fullrt_div[lane], 0x2);
                break;
@@ -1299,6 +1312,25 @@ static struct wiz_data j7200_pg2_10g_data = {
        .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G,
 };
 
+static struct wiz_data j784s4_10g_data = {
+       .type = J784S4_WIZ_10G,
+       .pll0_refclk_mux_sel = &pll0_refclk_mux_sel_2,
+       .pll1_refclk_mux_sel = &pll1_refclk_mux_sel_2,
+       .refclk_dig_sel = &refclk_dig_sel_16g,
+       .pma_cmn_refclk1_int_mode = &pma_cmn_refclk1_int_mode,
+       .clk_mux_sel = clk_mux_sel_10g_2_refclk,
+       .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G,
+};
+
+static struct wiz_data j721s2_10g_data = {
+       .type = J721S2_WIZ_10G,
+       .pll0_refclk_mux_sel = &pll0_refclk_mux_sel,
+       .pll1_refclk_mux_sel = &pll1_refclk_mux_sel,
+       .refclk_dig_sel = &refclk_dig_sel_10g,
+       .clk_mux_sel = clk_mux_sel_10g,
+       .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G,
+};
+
 static const struct of_device_id wiz_id_table[] = {
        {
                .compatible = "ti,j721e-wiz-16g", .data = &j721e_16g_data,
@@ -1312,6 +1344,12 @@ static const struct of_device_id wiz_id_table[] = {
        {
                .compatible = "ti,j7200-wiz-10g", .data = &j7200_pg2_10g_data,
        },
+       {
+               .compatible = "ti,j784s4-wiz-10g", .data = &j784s4_10g_data,
+       },
+       {
+               .compatible = "ti,j721s2-wiz-10g", .data = &j721s2_10g_data,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, wiz_id_table);
diff --git a/include/dt-bindings/phy/phy-qcom-qmp.h b/include/dt-bindings/phy/phy-qcom-qmp.h
new file mode 100644 (file)
index 0000000..4edec4c
--- /dev/null
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Qualcomm QMP PHY constants
+ *
+ * Copyright (C) 2022 Linaro Limited
+ */
+
+#ifndef _DT_BINDINGS_PHY_QMP
+#define _DT_BINDINGS_PHY_QMP
+
+/* QMP USB4-USB3-DP clocks */
+#define QMP_USB43DP_USB3_PIPE_CLK      0
+#define QMP_USB43DP_DP_LINK_CLK                1
+#define QMP_USB43DP_DP_VCO_DIV_CLK     2
+
+/* QMP USB4-USB3-DP PHYs */
+#define QMP_USB43DP_USB3_PHY           0
+#define QMP_USB43DP_DP_PHY             1
+
+#endif /* _DT_BINDINGS_PHY_QMP */