summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-17 11:40:04 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-17 11:40:04 -0800
commit9b725d5959a1d9bb670ccdb23add45f0eaafefb5 (patch)
treee55a94fe0836bcebb1528d2c5bb8a9360a2b5edc
parent4e15e819710e3518ec28735a12e0f45b7550290d (diff)
parentdbeea86fecef7cf2b93aded4525d74f6277376ef (diff)
Merge tag 'phy-for-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy
Pull phy updates from Vinod Koul: "Core: - Add suuport for "rx-polarity" and "tx-polarity" device tree properties and phy common properties to manage this New Support: - Qualcomm Glymur PCIe Gen4 2-lanes PCIe phy, DP and edp phy, USB UNI PHY and SMB2370 eUSB2 repeater. SC8280xp QMP UFS PHY, Kaanapali PCIe phy and QMP PHY, QCS615 QMP USB3+DP PHY and driver support for that. - SpacemiT PCIe/combo PHY and K1 USB2 PHY driver. - HDMI 2.1 FRL configuration support and driver enabling for rockchip samsung-hdptx driver - TI TCAN1046 phy - Renesas RZ/V2H(P) and RZ/V2N usb3 - Mediatek MT8188 hdmi-phy - Google Tensor SoC USB PHY driver - Apple Type-C PHY Updates: - Subsystem conversion for clock round_rate() to determine_rate() - TI USB3 DT schema conversion - Samsung ExynosAutov920 usb3, combo hsphy and ssphy support" * tag 'phy-for-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (143 commits) phy: ti: phy-j721e-wiz: convert from divider_round_rate() to divider_determine_rate() dt-bindings: phy: ti,control-phy-otghs: convert to DT schema dt-bindings: phy: ti,phy-usb3: convert to DT schema phy: tegra: xusb: Remove unused powered_on variable phy: renesas: rcar-gen3-usb2: add regulator dependency phy: GOOGLE_USB: add TYPEC dependency phy: enter drivers/phy/Makefile even without CONFIG_GENERIC_PHY phy: renesas: rcar-gen3-usb2: Use mux-state for phyrst management phy: renesas: rcar-gen3-usb2: Add regulator for OTG VBUS control phy: renesas: rcar-gen3-usb2: Use devm_pm_runtime_enable() phy: renesas: rcar-gen3-usb2: Factor out VBUS control logic dt-bindings: phy: renesas,usb2-phy: Document RZ/G3E SoC dt-bindings: phy: renesas,usb2-phy: Document mux-states property dt-bindings: phy: renesas,usb2-phy: Document USB VBUS regulator phy: rockchip: samsung-hdptx: Add HDMI 2.1 FRL support phy: rockchip: samsung-hdptx: Extend rk_hdptx_phy_verify_hdmi_config() helper phy: rockchip: samsung-hdptx: Switch to driver specific HDMI config phy: rockchip: samsung-hdptx: Drop hw_rate driver data phy: rockchip: samsung-hdptx: Compute clk rate from PLL config phy: rockchip: samsung-hdptx: Cleanup *_cmn_init_seq lists ...
-rw-r--r--Documentation/devicetree/bindings/phy/apple,atcphy.yaml222
-rw-r--r--Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml71
-rw-r--r--Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml133
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml30
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,m31-eusb2-phy.yaml10
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml111
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml6
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml6
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml18
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml70
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml9
-rw-r--r--Documentation/devicetree/bindings/phy/renesas,rzg3e-usb3-phy.yaml9
-rw-r--r--Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml15
-rw-r--r--Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml3
-rw-r--r--Documentation/devicetree/bindings/phy/samsung,usb3-drd-phy.yaml51
-rw-r--r--Documentation/devicetree/bindings/phy/spacemit,k1-combo-phy.yaml114
-rw-r--r--Documentation/devicetree/bindings/phy/spacemit,k1-pcie-phy.yaml71
-rw-r--r--Documentation/devicetree/bindings/phy/spacemit,usb2-phy.yaml40
-rw-r--r--Documentation/devicetree/bindings/phy/ti,control-phy-otghs.yaml99
-rw-r--r--Documentation/devicetree/bindings/phy/ti,phy-usb3.yaml138
-rw-r--r--Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml3
-rw-r--r--Documentation/devicetree/bindings/phy/ti-phy.txt98
-rw-r--r--MAINTAINERS4
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/phy/Kconfig25
-rw-r--r--drivers/phy/Makefile6
-rw-r--r--drivers/phy/allwinner/phy-sun4i-usb.c14
-rw-r--r--drivers/phy/apple/Kconfig13
-rw-r--r--drivers/phy/apple/Makefile4
-rw-r--r--drivers/phy/apple/atc.c2295
-rw-r--r--drivers/phy/cadence/phy-cadence-torrent.c166
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8mq-usb.c25
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8qm-hsio.c2
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c6
-rw-r--r--drivers/phy/freescale/phy-fsl-lynx-28g.c1156
-rw-r--r--drivers/phy/freescale/phy-fsl-samsung-hdmi.c13
-rw-r--r--drivers/phy/marvell/phy-mvebu-cp110-utmi.c2
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c8
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c16
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c10
-rw-r--r--drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c10
-rw-r--r--drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c10
-rw-r--r--drivers/phy/mediatek/phy-mtk-xfi-tphy.c2
-rw-r--r--drivers/phy/phy-core.c15
-rw-r--r--drivers/phy/phy-google-usb.c296
-rw-r--r--drivers/phy/phy-spacemit-k1-pcie.c670
-rw-r--r--drivers/phy/qualcomm/phy-qcom-edp.c246
-rw-r--r--drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c40
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-combo.c683
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h21
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v8.h25
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-dp-qserdes-com-v8.h52
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcie.c213
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v6.h12
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v8.h17
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v5.h12
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v8.h12
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v8.h34
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h106
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v8.h11
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-dp-com-v8.h52
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-lalb-v8.h639
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-pcie-v8.h71
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h68
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-ufs.c96
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-usb.c190
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-usb43-pcs-v8.h33
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-usb43-qserdes-com-v8.h224
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-usbc.c1071
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp.h5
-rw-r--r--drivers/phy/renesas/Kconfig2
-rw-r--r--drivers/phy/renesas/phy-rcar-gen2.c6
-rw-r--r--drivers/phy/renesas/phy-rcar-gen3-usb2.c261
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-hdmi.c30
-rw-r--r--drivers/phy/rockchip/phy-rockchip-naneng-combphy.c12
-rw-r--r--drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c4
-rw-r--r--drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c756
-rw-r--r--drivers/phy/rockchip/phy-rockchip-usb.c7
-rw-r--r--drivers/phy/samsung/phy-exynos5-usbdrd.c651
-rw-r--r--drivers/phy/socionext/phy-uniphier-usb2.c28
-rw-r--r--drivers/phy/spacemit/Kconfig13
-rw-r--r--drivers/phy/spacemit/Makefile2
-rw-r--r--drivers/phy/spacemit/phy-k1-usb2.c200
-rw-r--r--drivers/phy/tegra/xusb.h1
-rw-r--r--drivers/phy/ti/phy-j721e-wiz.c27
-rw-r--r--drivers/soc/apple/Kconfig4
-rw-r--r--drivers/soc/apple/Makefile3
-rw-r--r--drivers/soc/apple/tunable.c80
-rw-r--r--include/dt-bindings/phy/phy.h1
-rw-r--r--include/linux/phy/phy-hdmi.h19
-rw-r--r--include/linux/phy/phy.h7
-rw-r--r--include/linux/soc/apple/tunable.h62
-rw-r--r--include/linux/soc/samsung/exynos-regs-pmu.h3
93 files changed, 11329 insertions, 880 deletions
diff --git a/Documentation/devicetree/bindings/phy/apple,atcphy.yaml b/Documentation/devicetree/bindings/phy/apple,atcphy.yaml
new file mode 100644
index 000000000000..0acac7e3ee67
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/apple,atcphy.yaml
@@ -0,0 +1,222 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/apple,atcphy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple Type-C PHY (ATCPHY)
+
+maintainers:
+ - Sven Peter <sven@kernel.org>
+
+description: >
+ The Apple Type-C PHY (ATCPHY) is a combined PHY for USB 2.0, USB 3.x,
+ USB4/Thunderbolt, and DisplayPort connectivity via Type-C ports found in
+ Apple Silicon SoCs.
+
+ The PHY handles muxing between these different protocols and also provides the
+ reset controller for the attached DWC3 USB controller.
+
+ It is designed for USB4 operation and does not handle individual differential
+ pairs as distinct DisplayPort lanes. Any reference to lane in this binding
+ hence refers to two differential pairs (RX and TX) as used in USB terminology.
+
+ In order to correctly setup these lanes for the various modes calibration
+ values copied from Apple's firmware and converted to the format described
+ below by our bootloader m1n1 are required. Without these only USB2 operation
+ is possible.
+
+allOf:
+ - $ref: /schemas/usb/usb-switch.yaml#
+
+$defs:
+ apple,tunable:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ items:
+ items:
+ - description: Register offset
+ - description: Mask to be applied to the register value
+ - description: Bits to be set after applying the mask
+ description: >
+ List of (register offset, mask, value) tuples copied from Apple's Device
+ Tree by our bootloader m1n1 and used to configure the PHY. These values
+ even vary for a single product/device and likely contain calibration
+ values determined by Apple at manufacturing time.
+ Unless otherwise noted these tunables are always applied to the core
+ register region.
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - apple,t6000-atcphy
+ - apple,t6020-atcphy
+ - apple,t8112-atcphy
+ - const: apple,t8103-atcphy
+ - const: apple,t8103-atcphy
+
+ reg:
+ items:
+ - description: Common controls for all PHYs (USB2/3/4, DisplayPort, TBT)
+ - description: DisplayPort Alternate Mode PHY specific controls
+ - description: Type-C PHY AXI to Apple Fabric interconnect controls
+ - description: USB2 PHY specific controls
+ - description: USB3 PIPE interface controls
+
+ reg-names:
+ items:
+ - const: core
+ - const: lpdptx
+ - const: axi2af
+ - const: usb2phy
+ - const: pipehandler
+
+ "#phy-cells":
+ const: 1
+
+ "#reset-cells":
+ const: 0
+
+ mode-switch: true
+ orientation-switch: true
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Outgoing connection to the SS port of the Type-C connector.
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Incoming endpoint from the USB3 controller.
+
+ port@2:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Incoming endpoint from the DisplayPort controller.
+
+ port@3:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Incoming endpoint from the USB4/Thunderbolt controller.
+
+ apple,tunable-common-a:
+ $ref: "#/$defs/apple,tunable"
+ description: >
+ Common tunables required for all modes, applied before tunable-axi2af.
+
+ apple,tunable-axi2af:
+ $ref: "#/$defs/apple,tunable"
+ description: >
+ AXI to Apple Fabric tunables, required for all modes. Unlike all other
+ tunables these are applied to the axi2af region.
+
+ apple,tunable-common-b:
+ $ref: "#/$defs/apple,tunable"
+ description: >
+ Common tunables required for all modes, applied after tunable-axi2af.
+
+ apple,tunable-lane0-usb:
+ $ref: "#/$defs/apple,tunable"
+ description: USB3 tunables for lane 0.
+
+ apple,tunable-lane1-usb:
+ $ref: "#/$defs/apple,tunable"
+ description: USB3 tunables for lane 1.
+
+ apple,tunable-lane0-cio:
+ $ref: "#/$defs/apple,tunable"
+ description: USB4/Thunderbolt ("Converged IO") tunables for lane 0.
+
+ apple,tunable-lane1-cio:
+ $ref: "#/$defs/apple,tunable"
+ description: USB4/Thunderbolt ("Converged IO") tunables for lane 1.
+
+ apple,tunable-lane0-dp:
+ $ref: "#/$defs/apple,tunable"
+ description: >
+ DisplayPort tunables for lane 0.
+
+ Note that lane here refers to a USB RX and TX pair re-used for DisplayPort
+ and not to an individual DisplayPort differential lane.
+
+ apple,tunable-lane1-dp:
+ $ref: "#/$defs/apple,tunable"
+ description: >
+ DisplayPort tunables for lane 1.
+
+ Note that lane here refers to a USB RX and TX pair re-used for DisplayPort
+ and not to an individual DisplayPort differential lane.
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - "#phy-cells"
+ - "#reset-cells"
+ - orientation-switch
+ - mode-switch
+ - power-domains
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ phy@83000000 {
+ compatible = "apple,t8103-atcphy";
+ reg = <0x83000000 0x4c000>,
+ <0x83050000 0x8000>,
+ <0x80000000 0x4000>,
+ <0x82a90000 0x4000>,
+ <0x82a84000 0x4000>;
+ reg-names = "core", "lpdptx", "axi2af", "usb2phy",
+ "pipehandler";
+
+ #phy-cells = <1>;
+ #reset-cells = <0>;
+
+ orientation-switch;
+ mode-switch;
+ power-domains = <&ps_atc0_usb>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ endpoint {
+ remote-endpoint = <&typec_connector_ss>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ endpoint {
+ remote-endpoint = <&dwc3_ss_out>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+
+ endpoint {
+ remote-endpoint = <&dcp_dp_out>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+
+ endpoint {
+ remote-endpoint = <&acio_tbt_out>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
index ff9f9ca0f19c..e96229c2f8fb 100644
--- a/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
+++ b/Documentation/devicetree/bindings/phy/fsl,lynx-28g.yaml
@@ -20,6 +20,32 @@ properties:
"#phy-cells":
const: 1
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+patternProperties:
+ "^phy@[0-7]$":
+ type: object
+ description: SerDes lane (single RX/TX differential pair)
+
+ properties:
+ reg:
+ minimum: 0
+ maximum: 7
+ description: Lane index as seen in register map
+
+ "#phy-cells":
+ const: 0
+
+ required:
+ - reg
+ - "#phy-cells"
+
+ additionalProperties: false
+
required:
- compatible
- reg
@@ -32,9 +58,52 @@ examples:
soc {
#address-cells = <2>;
#size-cells = <2>;
- serdes_1: phy@1ea0000 {
+
+ serdes@1ea0000 {
compatible = "fsl,lynx-28g";
reg = <0x0 0x1ea0000 0x0 0x1e30>;
+ #address-cells = <1>;
+ #size-cells = <0>;
#phy-cells = <1>;
+
+ phy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ };
+
+ phy@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ };
+
+ phy@2 {
+ reg = <2>;
+ #phy-cells = <0>;
+ };
+
+ phy@3 {
+ reg = <3>;
+ #phy-cells = <0>;
+ };
+
+ phy@4 {
+ reg = <4>;
+ #phy-cells = <0>;
+ };
+
+ phy@5 {
+ reg = <5>;
+ #phy-cells = <0>;
+ };
+
+ phy@6 {
+ reg = <6>;
+ #phy-cells = <0>;
+ };
+
+ phy@7 {
+ reg = <7>;
+ #phy-cells = <0>;
+ };
};
};
diff --git a/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml b/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
new file mode 100644
index 000000000000..427e2e3425f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
@@ -0,0 +1,133 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2025, Google LLC
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/google,lga-usb-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Google Tensor Series G5 (Laguna) USB PHY
+
+maintainers:
+ - Roy Luo <royluo@google.com>
+
+description:
+ Describes the USB PHY interfaces integrated with the DWC3 USB controller on
+ Google Tensor SoCs, starting with the G5 generation (laguna).
+ Two specific PHY IPs from Synopsys are integrated, including eUSB 2.0 PHY IP
+ and USB3.2/DisplayPort combo PHY IP.
+
+properties:
+ compatible:
+ const: google,lga-usb-phy
+
+ reg:
+ items:
+ - description: USB3.2/DisplayPort combo PHY core registers.
+ - description: USB3.2/DisplayPort combo PHY Type-C Assist registers.
+ - description: eUSB 2.0 PHY core registers.
+ - description: Top-level wrapper registers for the integrated PHYs.
+
+ reg-names:
+ items:
+ - const: usb3_core
+ - const: usb3_tca
+ - const: usb2_core
+ - const: usbdp_top
+
+ "#phy-cells":
+ description: |
+ The phandle's argument in the PHY specifier selects one of the three
+ following PHY interfaces.
+ - 0 for USB high-speed.
+ - 1 for USB super-speed.
+ - 2 for DisplayPort.
+ const: 1
+
+ clocks:
+ items:
+ - description: USB2 PHY clock.
+ - description: USB2 PHY APB clock.
+ - description: USB3.2/DisplayPort combo PHY clock.
+ - description: USB3.2/DisplayPort combo PHY firmware clock.
+
+ clock-names:
+ items:
+ - const: usb2
+ - const: usb2_apb
+ - const: usb3
+ - const: usb3_fw
+
+ resets:
+ items:
+ - description: USB2 PHY reset.
+ - description: USB2 PHY APB reset.
+ - description: USB3.2/DisplayPort combo PHY reset.
+
+ reset-names:
+ items:
+ - const: usb2
+ - const: usb2_apb
+ - const: usb3
+
+ power-domains:
+ maxItems: 1
+
+ orientation-switch:
+ type: boolean
+ description:
+ Indicates the PHY as a handler of USB Type-C orientation changes
+
+ google,usb-cfg-csr:
+ description:
+ A phandle to a syscon node used to access the USB configuration
+ registers. These registers are the top-level wrapper of the USB
+ subsystem and provide control and status for the integrated USB
+ controller and USB PHY.
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ - items:
+ - description: phandle to the syscon node.
+ - description: USB2 PHY configuration register offset.
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - "#phy-cells"
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - power-domains
+ - orientation-switch
+ - google,usb-cfg-csr
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ usb-phy@c410000 {
+ compatible = "google,lga-usb-phy";
+ reg = <0 0x0c410000 0 0x20000>,
+ <0 0x0c430000 0 0x1000>,
+ <0 0x0c440000 0 0x10000>,
+ <0 0x0c637000 0 0xa0>;
+ reg-names = "usb3_core", "usb3_tca", "usb2_core", "usbdp_top";
+ #phy-cells = <1>;
+ clocks = <&hsion_usb2_phy_clk>, <&hsion_u2phy_apb_clk>,
+ <&hsion_usb3_phy_clk>, <&hsion_usb3_phy_fw_clk>;
+ clock-names = "usb2", "usb2_apb", "usb3", "usb3_fw";
+ resets = <&hsion_resets_usb2_phy>,
+ <&hsion_resets_u2phy_apb>,
+ <&hsion_resets_usb3_phy>;
+ reset-names = "usb2", "usb2_apb", "usb3";
+ power-domains = <&hsio_n_usb_pd>;
+ orientation-switch;
+ google,usb-cfg-csr = <&usb_cfg_csr 0x14>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml
index eb97181cbb95..4a1daae3d8d4 100644
--- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml
@@ -18,6 +18,7 @@ properties:
compatible:
oneOf:
- enum:
+ - qcom,glymur-dp-phy
- qcom,sa8775p-edp-phy
- qcom,sc7280-edp-phy
- qcom,sc8180x-edp-phy
@@ -37,12 +38,15 @@ properties:
- description: PLL register block
clocks:
- maxItems: 2
+ minItems: 2
+ maxItems: 3
clock-names:
+ minItems: 2
items:
- const: aux
- const: cfg_ahb
+ - const: ref
"#clock-cells":
const: 1
@@ -64,6 +68,30 @@ required:
- "#clock-cells"
- "#phy-cells"
+allOf:
+ - if:
+ properties:
+ compatible:
+ enum:
+ - qcom,glymur-dp-phy
+ - qcom,x1e80100-dp-phy
+ then:
+ properties:
+ clocks:
+ minItems: 3
+ maxItems: 3
+ clock-names:
+ minItems: 3
+ maxItems: 3
+ else:
+ properties:
+ clocks:
+ minItems: 2
+ maxItems: 2
+ clock-names:
+ minItems: 2
+ maxItems: 2
+
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/phy/qcom,m31-eusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,m31-eusb2-phy.yaml
index c84c62d0e8cb..cd6b84213a7c 100644
--- a/Documentation/devicetree/bindings/phy/qcom,m31-eusb2-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,m31-eusb2-phy.yaml
@@ -15,9 +15,13 @@ description:
properties:
compatible:
- items:
- - enum:
- - qcom,sm8750-m31-eusb2-phy
+ oneOf:
+ - items:
+ - enum:
+ - qcom,glymur-m31-eusb2-phy
+ - qcom,kaanapali-m31-eusb2-phy
+ - const: qcom,sm8750-m31-eusb2-phy
+ - const: qcom,sm8750-m31-eusb2-phy
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml
new file mode 100644
index 000000000000..efb465c71c1b
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml
@@ -0,0 +1,111 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,qcs615-qmp-usb3dp-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QMP USB3-DP PHY controller (DP, QCS615)
+
+maintainers:
+ - Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
+
+description:
+ The QMP PHY controller supports physical layer functionality for both USB3
+ and DisplayPort over USB-C. While it enables mode switching between USB3 and
+ DisplayPort, but does not support combo mode.
+
+properties:
+ compatible:
+ enum:
+ - qcom,qcs615-qmp-usb3-dp-phy
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 4
+
+ clock-names:
+ items:
+ - const: aux
+ - const: ref
+ - const: cfg_ahb
+ - const: pipe
+
+ resets:
+ maxItems: 2
+
+ reset-names:
+ items:
+ - const: phy_phy
+ - const: dp_phy
+
+ vdda-phy-supply: true
+
+ vdda-pll-supply: true
+
+ "#clock-cells":
+ const: 1
+ description:
+ See include/dt-bindings/phy/phy-qcom-qmp.h
+
+ "#phy-cells":
+ const: 1
+ description:
+ See include/dt-bindings/phy/phy-qcom-qmp.h
+
+ qcom,tcsr-reg:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ - items:
+ - description: phandle to TCSR hardware block
+ - description: offset of the VLS CLAMP register
+ - description: offset of the PHY mode register
+ description: Clamp and PHY mode register present in the TCSR
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - vdda-phy-supply
+ - vdda-pll-supply
+ - "#clock-cells"
+ - "#phy-cells"
+ - qcom,tcsr-reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,qcs615-gcc.h>
+ #include <dt-bindings/clock/qcom,rpmh.h>
+
+ phy@88e8000 {
+ compatible = "qcom,qcs615-qmp-usb3-dp-phy";
+ reg = <0x88e8000 0x2000>;
+
+ clocks = <&gcc GCC_USB2_SEC_PHY_AUX_CLK>,
+ <&gcc GCC_USB3_SEC_CLKREF_CLK>,
+ <&gcc GCC_AHB2PHY_WEST_CLK>,
+ <&gcc GCC_USB2_SEC_PHY_PIPE_CLK>;
+ clock-names = "aux",
+ "ref",
+ "cfg_ahb",
+ "pipe";
+
+ resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>,
+ <&gcc GCC_USB3_DP_PHY_SEC_BCR>;
+ reset-names = "phy_phy",
+ "dp_phy";
+
+ vdda-phy-supply = <&vreg_l5a>;
+ vdda-pll-supply = <&vreg_l12a>;
+
+ #clock-cells = <1>;
+ #phy-cells = <1>;
+
+ qcom,tcsr-reg = <&tcsr 0xbff0 0xb24c>;
+ };
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
index f5068df20cfe..3a35120a77ec 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
@@ -16,7 +16,9 @@ description:
properties:
compatible:
enum:
+ - qcom,glymur-qmp-gen4x2-pcie-phy
- qcom,glymur-qmp-gen5x4-pcie-phy
+ - qcom,kaanapali-qmp-gen3x2-pcie-phy
- qcom,qcs615-qmp-gen3x1-pcie-phy
- qcom,qcs8300-qmp-gen4x2-pcie-phy
- qcom,sa8775p-qmp-gen4x2-pcie-phy
@@ -146,6 +148,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,kaanapali-qmp-gen3x2-pcie-phy
- qcom,qcs615-qmp-gen3x1-pcie-phy
- qcom,sar2130p-qmp-gen3x2-pcie-phy
- qcom,sc8180x-qmp-pcie-phy
@@ -178,6 +181,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,glymur-qmp-gen4x2-pcie-phy
- qcom,glymur-qmp-gen5x4-pcie-phy
- qcom,qcs8300-qmp-gen4x2-pcie-phy
- qcom,sa8775p-qmp-gen4x2-pcie-phy
@@ -202,7 +206,9 @@ allOf:
compatible:
contains:
enum:
+ - qcom,glymur-qmp-gen4x2-pcie-phy
- qcom,glymur-qmp-gen5x4-pcie-phy
+ - qcom,kaanapali-qmp-gen3x2-pcie-phy
- qcom,sm8550-qmp-gen4x2-pcie-phy
- qcom,sm8650-qmp-gen4x2-pcie-phy
- qcom,x1e80100-qmp-gen3x2-pcie-phy
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
index fba7b2549dde..a1731b08c9d1 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
@@ -22,6 +22,10 @@ properties:
- const: qcom,sm6115-qmp-ufs-phy
- items:
- enum:
+ - qcom,x1e80100-qmp-ufs-phy
+ - const: qcom,sm8550-qmp-ufs-phy
+ - items:
+ - enum:
- qcom,qcs8300-qmp-ufs-phy
- const: qcom,sa8775p-qmp-ufs-phy
- items:
@@ -29,6 +33,7 @@ properties:
- qcom,kaanapali-qmp-ufs-phy
- const: qcom,sm8750-qmp-ufs-phy
- enum:
+ - qcom,milos-qmp-ufs-phy
- qcom,msm8996-qmp-ufs-phy
- qcom,msm8998-qmp-ufs-phy
- qcom,sa8775p-qmp-ufs-phy
@@ -98,6 +103,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,milos-qmp-ufs-phy
- qcom,msm8998-qmp-ufs-phy
- qcom,sa8775p-qmp-ufs-phy
- qcom,sc7180-qmp-ufs-phy
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
index 863a1a446739..623c2f8c7d22 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml
@@ -16,6 +16,7 @@ description:
properties:
compatible:
enum:
+ - qcom,glymur-qmp-usb3-uni-phy
- qcom,ipq5424-qmp-usb3-phy
- qcom,ipq6018-qmp-usb3-phy
- qcom,ipq8074-qmp-usb3-phy
@@ -61,6 +62,8 @@ properties:
vdda-pll-supply: true
+ refgen-supply: true
+
"#clock-cells":
const: 0
@@ -113,6 +116,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,glymur-qmp-usb3-uni-phy
- qcom,qcs8300-qmp-usb3-uni-phy
- qcom,qdu1000-qmp-usb3-uni-phy
- qcom,sa8775p-qmp-usb3-uni-phy
@@ -156,6 +160,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,glymur-qmp-usb3-uni-phy
- qcom,sa8775p-qmp-usb3-uni-phy
- qcom,sc8180x-qmp-usb3-uni-phy
- qcom,sc8280xp-qmp-usb3-uni-phy
@@ -164,6 +169,19 @@ allOf:
required:
- power-domains
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,glymur-qmp-usb3-uni-phy
+ then:
+ required:
+ - refgen-supply
+ else:
+ properties:
+ refgen-supply: false
+
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml
index e0ec45b96bf5..3d537b7f9985 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml
@@ -15,22 +15,28 @@ description:
properties:
compatible:
- enum:
- - qcom,sar2130p-qmp-usb3-dp-phy
- - 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,sm6350-qmp-usb3-dp-phy
- - qcom,sm8150-qmp-usb3-dp-phy
- - qcom,sm8250-qmp-usb3-dp-phy
- - qcom,sm8350-qmp-usb3-dp-phy
- - qcom,sm8450-qmp-usb3-dp-phy
- - qcom,sm8550-qmp-usb3-dp-phy
- - qcom,sm8650-qmp-usb3-dp-phy
- - qcom,sm8750-qmp-usb3-dp-phy
- - qcom,x1e80100-qmp-usb3-dp-phy
+ oneOf:
+ - items:
+ - enum:
+ - qcom,kaanapali-qmp-usb3-dp-phy
+ - const: qcom,sm8750-qmp-usb3-dp-phy
+ - enum:
+ - qcom,glymur-qmp-usb3-dp-phy
+ - qcom,sar2130p-qmp-usb3-dp-phy
+ - 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,sm6350-qmp-usb3-dp-phy
+ - qcom,sm8150-qmp-usb3-dp-phy
+ - qcom,sm8250-qmp-usb3-dp-phy
+ - qcom,sm8350-qmp-usb3-dp-phy
+ - qcom,sm8450-qmp-usb3-dp-phy
+ - qcom,sm8550-qmp-usb3-dp-phy
+ - qcom,sm8650-qmp-usb3-dp-phy
+ - qcom,sm8750-qmp-usb3-dp-phy
+ - qcom,x1e80100-qmp-usb3-dp-phy
reg:
maxItems: 1
@@ -63,6 +69,8 @@ properties:
vdda-pll-supply: true
+ refgen-supply: true
+
"#clock-cells":
const: 1
description:
@@ -194,14 +202,16 @@ allOf:
- if:
properties:
compatible:
- enum:
- - qcom,sar2130p-qmp-usb3-dp-phy
- - qcom,sc8280xp-qmp-usb43dp-phy
- - qcom,sm6350-qmp-usb3-dp-phy
- - qcom,sm8550-qmp-usb3-dp-phy
- - qcom,sm8650-qmp-usb3-dp-phy
- - qcom,sm8750-qmp-usb3-dp-phy
- - qcom,x1e80100-qmp-usb3-dp-phy
+ contains:
+ enum:
+ - qcom,glymur-qmp-usb3-dp-phy
+ - qcom,sar2130p-qmp-usb3-dp-phy
+ - qcom,sc8280xp-qmp-usb43dp-phy
+ - qcom,sm6350-qmp-usb3-dp-phy
+ - qcom,sm8550-qmp-usb3-dp-phy
+ - qcom,sm8650-qmp-usb3-dp-phy
+ - qcom,sm8750-qmp-usb3-dp-phy
+ - qcom,x1e80100-qmp-usb3-dp-phy
then:
required:
- power-domains
@@ -209,6 +219,18 @@ allOf:
properties:
power-domains: false
+ - if:
+ properties:
+ compatible:
+ enum:
+ - qcom,glymur-qmp-usb3-dp-phy
+ then:
+ required:
+ - refgen-supply
+ else:
+ properties:
+ refgen-supply: false
+
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml
index 5bf0d6c9c025..f29fc335f3f5 100644
--- a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml
@@ -24,6 +24,7 @@ properties:
- qcom,pm8550b-eusb2-repeater
- qcom,pmiv0104-eusb2-repeater
- qcom,smb2360-eusb2-repeater
+ - qcom,smb2370-eusb2-repeater
reg:
maxItems: 1
@@ -59,6 +60,14 @@ properties:
minimum: 0
maximum: 7
+ qcom,squelch-detector-bp:
+ description:
+ This adjusts the voltage level for the threshold used to detect valid
+ high-speed data.
+ minimum: -6000
+ maximum: 1000
+ multipleOf: 1000
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/phy/renesas,rzg3e-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/renesas,rzg3e-usb3-phy.yaml
index b86dc7a291a4..6d97e038a927 100644
--- a/Documentation/devicetree/bindings/phy/renesas,rzg3e-usb3-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/renesas,rzg3e-usb3-phy.yaml
@@ -11,7 +11,14 @@ maintainers:
properties:
compatible:
- const: renesas,r9a09g047-usb3-phy
+ oneOf:
+ - const: renesas,r9a09g047-usb3-phy # RZ/G3E
+
+ - items:
+ - enum:
+ - renesas,r9a09g056-usb3-phy # RZ/V2N
+ - renesas,r9a09g057-usb3-phy # RZ/V2H(P)
+ - const: renesas,r9a09g047-usb3-phy
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml b/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml
index 2bbec8702a1e..9740e5b335f9 100644
--- a/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml
@@ -41,7 +41,9 @@ properties:
- const: renesas,rzg2l-usb2-phy
- items:
- - const: renesas,usb2-phy-r9a09g056 # RZ/V2N
+ - enum:
+ - renesas,usb2-phy-r9a09g047 # RZ/G3E
+ - renesas,usb2-phy-r9a09g056 # RZ/V2N
- const: renesas,usb2-phy-r9a09g057
- const: renesas,usb2-phy-r9a09g077 # RZ/T2H
@@ -89,6 +91,12 @@ properties:
Phandle to a regulator that provides power to the VBUS. This regulator
will be managed during the PHY power on/off sequence.
+ vbus-regulator:
+ $ref: /schemas/regulator/regulator.yaml#
+ description: USB VBUS internal regulator
+ type: object
+ unevaluatedProperties: false
+
renesas,no-otg-pins:
$ref: /schemas/types.yaml#/definitions/flag
description: |
@@ -96,6 +104,11 @@ properties:
dr_mode: true
+ mux-states:
+ description:
+ phandle to a mux controller node that select the source for USB VBUS.
+ maxItems: 1
+
if:
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml
index d70ffeb6e824..2b20c0a5e509 100644
--- a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml
@@ -36,6 +36,9 @@ properties:
minItems: 1
maxItems: 4
+ power-domains:
+ maxItems: 1
+
samsung,pmu-syscon:
$ref: /schemas/types.yaml#/definitions/phandle-array
maxItems: 1
diff --git a/Documentation/devicetree/bindings/phy/samsung,usb3-drd-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,usb3-drd-phy.yaml
index ea1135c91fb7..4562e0468f4f 100644
--- a/Documentation/devicetree/bindings/phy/samsung,usb3-drd-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/samsung,usb3-drd-phy.yaml
@@ -34,6 +34,9 @@ properties:
- samsung,exynos7870-usbdrd-phy
- samsung,exynos850-usbdrd-phy
- samsung,exynos990-usbdrd-phy
+ - samsung,exynosautov920-usb31drd-combo-ssphy
+ - samsung,exynosautov920-usbdrd-combo-hsphy
+ - samsung,exynosautov920-usbdrd-phy
clocks:
minItems: 1
@@ -51,6 +54,9 @@ properties:
settings register. For Exynos5420 this is given as 'sclk_usbphy30'
in the CMU. It's not needed for Exynos2200.
+ power-domains:
+ maxItems: 1
+
"#phy-cells":
const: 1
@@ -110,6 +116,15 @@ properties:
vddh-usbdp-supply:
description: VDDh power supply for the USB DP phy.
+ dvdd-supply:
+ description: 0.75V power supply for the USB phy.
+
+ vdd18-supply:
+ description: 1.8V power supply for the USB phy.
+
+ vdd33-supply:
+ description: 3.3V power supply for the USB phy.
+
required:
- compatible
- clocks
@@ -221,6 +236,9 @@ allOf:
- samsung,exynos7870-usbdrd-phy
- samsung,exynos850-usbdrd-phy
- samsung,exynos990-usbdrd-phy
+ - samsung,exynosautov920-usb31drd-combo-ssphy
+ - samsung,exynosautov920-usbdrd-combo-hsphy
+ - samsung,exynosautov920-usbdrd-phy
then:
properties:
clocks:
@@ -238,6 +256,39 @@ allOf:
reg-names:
maxItems: 1
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - samsung,exynosautov920-usb31drd-combo-ssphy
+ - samsung,exynosautov920-usbdrd-combo-hsphy
+ - samsung,exynosautov920-usbdrd-phy
+ then:
+ required:
+ - dvdd-supply
+ - vdd18-supply
+
+ else:
+ properties:
+ dvdd-supply: false
+ vdd18-supply: false
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - samsung,exynosautov920-usbdrd-combo-hsphy
+ - samsung,exynosautov920-usbdrd-phy
+ then:
+ required:
+ - vdd33-supply
+
+ else:
+ properties:
+ vdd33-supply: false
+
unevaluatedProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/phy/spacemit,k1-combo-phy.yaml b/Documentation/devicetree/bindings/phy/spacemit,k1-combo-phy.yaml
new file mode 100644
index 000000000000..b59476cd78b5
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/spacemit,k1-combo-phy.yaml
@@ -0,0 +1,114 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/spacemit,k1-combo-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SpacemiT K1 PCIe/USB3 Combo PHY
+
+maintainers:
+ - Alex Elder <elder@riscstar.com>
+
+description: >
+ Of the three PHYs on the SpacemiT K1 SoC capable of being used for
+ PCIe, one is a combo PHY that can also be configured for use by a
+ USB 3 controller. Using PCIe or USB 3 is a board design decision.
+
+ The combo PHY is also the only PCIe PHY that is able to determine
+ PCIe calibration values to use, and this must be determined before
+ the other two PCIe PHYs can be used. This calibration must be
+ performed with the combo PHY in PCIe mode, and is this is done
+ when the combo PHY is probed.
+
+ The combo PHY uses an external oscillator as a reference clock.
+ During normal operation, the PCIe or USB port driver is responsible
+ for ensuring all other clocks needed by a PHY are enabled, and all
+ resets affecting the PHY are deasserted. However, for the combo
+ PHY to perform calibration independent of whether it's later used
+ for PCIe or USB, all PCIe mode clocks and resets must be defined.
+
+properties:
+ compatible:
+ const: spacemit,k1-combo-phy
+
+ reg:
+ items:
+ - description: PHY control registers
+
+ clocks:
+ items:
+ - description: External oscillator used by the PHY PLL
+ - description: DWC PCIe Data Bus Interface (DBI) clock
+ - description: DWC PCIe application AXI-bus Master interface clock
+ - description: DWC PCIe application AXI-bus slave interface clock
+
+ clock-names:
+ items:
+ - const: refclk
+ - const: dbi
+ - const: mstr
+ - const: slv
+
+ resets:
+ items:
+ - description: PHY reset; remains deasserted after initialization
+ - description: DWC PCIe Data Bus Interface (DBI) reset
+ - description: DWC PCIe application AXI-bus Master interface reset
+ - description: DWC PCIe application AXI-bus slave interface reset
+
+ reset-names:
+ items:
+ - const: phy
+ - const: dbi
+ - const: mstr
+ - const: slv
+
+ spacemit,apmu:
+ description:
+ A phandle that refers to the APMU system controller, whose
+ regmap is used in setting the mode
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ "#phy-cells":
+ const: 1
+ description:
+ The argument value (PHY_TYPE_PCIE or PHY_TYPE_USB3) determines
+ whether the PHY operates in PCIe or USB3 mode.
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - spacemit,apmu
+ - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/spacemit,k1-syscon.h>
+ phy@c0b10000 {
+ compatible = "spacemit,k1-combo-phy";
+ reg = <0xc0b10000 0x1000>;
+ clocks = <&vctcxo_24m>,
+ <&syscon_apmu CLK_PCIE0_DBI>,
+ <&syscon_apmu CLK_PCIE0_MASTER>,
+ <&syscon_apmu CLK_PCIE0_SLAVE>;
+ clock-names = "refclk",
+ "dbi",
+ "mstr",
+ "slv";
+ resets = <&syscon_apmu RESET_PCIE0_GLOBAL>,
+ <&syscon_apmu RESET_PCIE0_DBI>,
+ <&syscon_apmu RESET_PCIE0_MASTER>,
+ <&syscon_apmu RESET_PCIE0_SLAVE>;
+ reset-names = "phy",
+ "dbi",
+ "mstr",
+ "slv";
+ spacemit,apmu = <&syscon_apmu>;
+ #phy-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/phy/spacemit,k1-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/spacemit,k1-pcie-phy.yaml
new file mode 100644
index 000000000000..019b28349be7
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/spacemit,k1-pcie-phy.yaml
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/spacemit,k1-pcie-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SpacemiT K1 PCIe PHY
+
+maintainers:
+ - Alex Elder <elder@riscstar.com>
+
+description: >
+ Two PHYs on the SpacemiT K1 SoC used for only for PCIe. These
+ PHYs must be configured using calibration values that are
+ determined by a third "combo PHY". The combo PHY determines
+ these calibration values during probe so they can be used for
+ the two PCIe-only PHYs.
+
+ The PHY uses an external oscillator as a reference clock. During
+ normal operation, the PCIe host driver is responsible for ensuring
+ all other clocks needed by a PHY are enabled, and all resets
+ affecting the PHY are deasserted.
+
+properties:
+ compatible:
+ const: spacemit,k1-pcie-phy
+
+ reg:
+ items:
+ - description: PHY control registers
+
+ clocks:
+ items:
+ - description: External oscillator used by the PHY PLL
+
+ clock-names:
+ const: refclk
+
+ resets:
+ items:
+ - description: PHY reset; remains deasserted after initialization
+
+ reset-names:
+ const: phy
+
+ "#phy-cells":
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/spacemit,k1-syscon.h>
+ phy@c0c10000 {
+ compatible = "spacemit,k1-pcie-phy";
+ reg = <0xc0c10000 0x1000>;
+ clocks = <&vctcxo_24m>;
+ clock-names = "refclk";
+ resets = <&syscon_apmu RESET_PCIE1_GLOBAL>;
+ reset-names = "phy";
+ #phy-cells = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/phy/spacemit,usb2-phy.yaml b/Documentation/devicetree/bindings/phy/spacemit,usb2-phy.yaml
new file mode 100644
index 000000000000..43eaca90d88c
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/spacemit,usb2-phy.yaml
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/spacemit,usb2-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SpacemiT K1 SoC USB 2.0 PHY
+
+maintainers:
+ - Ze Huang <huang.ze@linux.dev>
+
+properties:
+ compatible:
+ const: spacemit,k1-usb2-phy
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ "#phy-cells":
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ usb-phy@c09c0000 {
+ compatible = "spacemit,k1-usb2-phy";
+ reg = <0xc09c0000 0x200>;
+ clocks = <&syscon_apmu 15>;
+ #phy-cells = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/phy/ti,control-phy-otghs.yaml b/Documentation/devicetree/bindings/phy/ti,control-phy-otghs.yaml
new file mode 100644
index 000000000000..4ecb1611ee65
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/ti,control-phy-otghs.yaml
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/ti,control-phy-otghs.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI OMAP Control PHY Module
+
+maintainers:
+ - Roger Quadros <rogerq@ti.com>
+
+description:
+ The TI OMAP Control PHY module is a hardware block within the system
+ control module (SCM) of Texas Instruments OMAP SoCs. It provides
+ centralized control over power, configuration, and auxiliary features
+ for multiple on-chip PHYs. This module is essential for proper PHY
+ operation in power-constrained embedded systems.
+
+properties:
+ $nodename:
+ pattern: "^phy@[0-9a-f]+$"
+
+ compatible:
+ enum:
+ - ti,control-phy-otghs
+ - ti,control-phy-pcie
+ - ti,control-phy-pipe3
+ - ti,control-phy-usb2
+ - ti,control-phy-usb2-am437
+ - ti,control-phy-usb2-dra7
+
+ reg:
+ minItems: 1
+ maxItems: 3
+
+ reg-names:
+ minItems: 1
+ maxItems: 3
+ items:
+ enum: [otghs_control, power, pcie_pcs, control_sma]
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - ti,control-phy-otghs
+ then:
+ properties:
+ reg-names:
+ const: otghs_control
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - ti,control-phy-pcie
+ then:
+ properties:
+ reg:
+ minItems: 3
+
+ reg-names:
+ items:
+ - const: power
+ - const: pcie_pcs
+ - const: control_sma
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - ti,control-phy-usb2
+ - ti,control-phy-usb2-dra7
+ - ti,control-phy-usb2-am437
+ - ti,control-phy-pipe3
+ then:
+ properties:
+ reg-names:
+ const: power
+
+required:
+ - reg
+ - compatible
+ - reg-names
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ phy@4a00233c {
+ compatible = "ti,control-phy-otghs";
+ reg = <0x4a00233c 0x4>;
+ reg-names = "otghs_control";
+ };
+...
diff --git a/Documentation/devicetree/bindings/phy/ti,phy-usb3.yaml b/Documentation/devicetree/bindings/phy/ti,phy-usb3.yaml
new file mode 100644
index 000000000000..84f538aa587c
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/ti,phy-usb3.yaml
@@ -0,0 +1,138 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/ti,phy-usb3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI PIPE3 PHY Module
+
+maintainers:
+ - Roger Quadros <rogerq@ti.com>
+
+description:
+ The TI PIPE3 PHY is a high-speed SerDes (Serializer/Deserializer)
+ transceiver integrated in OMAP5, DRA7xx/AM57xx, and similar SoCs.
+ It supports multiple protocols (USB3, SATA, PCIe) using the PIPE3
+ interface standard, which defines a common physical layer for
+ high-speed serial interfaces.
+
+properties:
+ $nodename:
+ pattern: "^(pcie-phy|usb3-phy|phy)@[0-9a-f]+$"
+
+ compatible:
+ enum:
+ - ti,omap-usb3
+ - ti,phy-pipe3-pcie
+ - ti,phy-pipe3-sata
+ - ti,phy-usb3
+
+ reg:
+ minItems: 2
+ maxItems: 3
+
+ reg-names:
+ minItems: 2
+ items:
+ - const: phy_rx
+ - const: phy_tx
+ - const: pll_ctrl
+
+ "#phy-cells":
+ const: 0
+
+ clocks:
+ minItems: 2
+ maxItems: 7
+
+ clock-names:
+ minItems: 2
+ maxItems: 7
+ items:
+ enum: [wkupclk, sysclk, refclk, dpll_ref,
+ dpll_ref_m2, phy-div, div-clk]
+
+ syscon-phy-power:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ maxItems: 1
+ items:
+ items:
+ - description: Phandle to the system control module
+ - description: Register offset controlling PHY power
+
+ syscon-pllreset:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ maxItems: 1
+ items:
+ items:
+ - description: Phandle to the system control module
+ - description: Register offset of CTRL_CORE_SMA_SW_0
+
+ syscon-pcs:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ maxItems: 1
+ items:
+ items:
+ - description: Phandle to the system control module
+ - description: Register offset for PCS delay programming
+
+ ctrl-module:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ Phandle of control module for PHY power on.
+ deprecated: true
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: ti,phy-pipe3-sata
+ then:
+ properties:
+ syscon-pllreset: true
+ else:
+ properties:
+ syscon-pllreset: false
+
+required:
+ - reg
+ - compatible
+ - reg-names
+ - "#phy-cells"
+ - clocks
+ - clock-names
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ /* TI PIPE3 USB3 PHY */
+ usb3-phy@4a084400 {
+ compatible = "ti,phy-usb3";
+ reg = <0x4a084400 0x80>,
+ <0x4a084800 0x64>,
+ <0x4a084c00 0x40>;
+ reg-names = "phy_rx", "phy_tx", "pll_ctrl";
+ #phy-cells = <0>;
+ clocks = <&usb_phy_cm_clk32k>,
+ <&sys_clkin>,
+ <&usb_otg_ss_refclk960m>;
+ clock-names = "wkupclk", "sysclk", "refclk";
+ ctrl-module = <&omap_control_usb>;
+ };
+
+ - |
+ /* TI PIPE3 SATA PHY */
+ phy@4a096000 {
+ compatible = "ti,phy-pipe3-sata";
+ reg = <0x4a096000 0x80>, /* phy_rx */
+ <0x4a096400 0x64>, /* phy_tx */
+ <0x4a096800 0x40>; /* pll_ctrl */
+ reg-names = "phy_rx", "phy_tx", "pll_ctrl";
+ clocks = <&sys_clkin1>, <&sata_ref_clk>;
+ clock-names = "sysclk", "refclk";
+ syscon-pllreset = <&scm_conf 0x3fc>;
+ #phy-cells = <0>;
+ };
+...
diff --git a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml
index c686d06f5f56..9f5c37ca6496 100644
--- a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml
+++ b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml
@@ -20,6 +20,9 @@ properties:
- microchip,ata6561
- ti,tcan1051
- const: ti,tcan1042
+ - items:
+ - const: ti,tcan1046
+ - const: nxp,tja1048
- enum:
- ti,tcan1042
- ti,tcan1043
diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt
deleted file mode 100644
index 7c7936b89f2c..000000000000
--- a/Documentation/devicetree/bindings/phy/ti-phy.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-TI PHY: DT DOCUMENTATION FOR PHYs in TI PLATFORMs
-
-OMAP CONTROL PHY
-
-Required properties:
- - compatible: Should be one of
- "ti,control-phy-otghs" - if it has otghs_control mailbox register as on OMAP4.
- "ti,control-phy-usb2" - if it has Power down bit in control_dev_conf register
- e.g. USB2_PHY on OMAP5.
- "ti,control-phy-pipe3" - if it has DPLL and individual Rx & Tx power control
- e.g. USB3 PHY and SATA PHY on OMAP5.
- "ti,control-phy-pcie" - for pcie to support external clock for pcie and to
- set PCS delay value.
- e.g. PCIE PHY in DRA7x
- "ti,control-phy-usb2-dra7" - if it has power down register like USB2 PHY on
- DRA7 platform.
- "ti,control-phy-usb2-am437" - if it has power down register like USB2 PHY on
- AM437 platform.
- - reg : register ranges as listed in the reg-names property
- - reg-names: "otghs_control" for control-phy-otghs
- "power", "pcie_pcs" and "control_sma" for control-phy-pcie
- "power" for all other types
-
-omap_control_usb: omap-control-usb@4a002300 {
- compatible = "ti,control-phy-otghs";
- reg = <0x4a00233c 0x4>;
- reg-names = "otghs_control";
-};
-
-TI PIPE3 PHY
-
-Required properties:
- - compatible: Should be "ti,phy-usb3", "ti,phy-pipe3-sata" or
- "ti,phy-pipe3-pcie. "ti,omap-usb3" is deprecated.
- - reg : Address and length of the register set for the device.
- - reg-names: The names of the register addresses corresponding to the registers
- filled in "reg".
- - #phy-cells: determine the number of cells that should be given in the
- phandle while referencing this phy.
- - clocks: a list of phandles and clock-specifier pairs, one for each entry in
- clock-names.
- - clock-names: should include:
- * "wkupclk" - wakeup clock.
- * "sysclk" - system clock.
- * "refclk" - reference clock.
- * "dpll_ref" - external dpll ref clk
- * "dpll_ref_m2" - external dpll ref clk
- * "phy-div" - divider for apll
- * "div-clk" - apll clock
-
-Optional properties:
- - id: If there are multiple instance of the same type, in order to
- differentiate between each instance "id" can be used (e.g., multi-lane PCIe
- PHY). If "id" is not provided, it is set to default value of '1'.
- - syscon-pllreset: Handle to system control region that contains the
- CTRL_CORE_SMA_SW_0 register and register offset to the CTRL_CORE_SMA_SW_0
- register that contains the SATA_PLL_SOFT_RESET bit. Only valid for sata_phy.
- - syscon-pcs : phandle/offset pair. Phandle to the system control module and the
- register offset to write the PCS delay value.
-
-Deprecated properties:
- - ctrl-module : phandle of the control module used by PHY driver to power on
- the PHY.
-
-Recommended properties:
- - syscon-phy-power : phandle/offset pair. Phandle to the system control
- module and the register offset to power on/off the PHY.
-
-This is usually a subnode of ocp2scp to which it is connected.
-
-usb3phy@4a084400 {
- compatible = "ti,phy-usb3";
- reg = <0x4a084400 0x80>,
- <0x4a084800 0x64>,
- <0x4a084c00 0x40>;
- reg-names = "phy_rx", "phy_tx", "pll_ctrl";
- ctrl-module = <&omap_control_usb>;
- #phy-cells = <0>;
- clocks = <&usb_phy_cm_clk32k>,
- <&sys_clkin>,
- <&usb_otg_ss_refclk960m>;
- clock-names = "wkupclk",
- "sysclk",
- "refclk";
-};
-
-sata_phy: phy@4a096000 {
- compatible = "ti,phy-pipe3-sata";
- reg = <0x4A096000 0x80>, /* phy_rx */
- <0x4A096400 0x64>, /* phy_tx */
- <0x4A096800 0x40>; /* pll_ctrl */
- reg-names = "phy_rx", "phy_tx", "pll_ctrl";
- ctrl-module = <&omap_control_sata>;
- clocks = <&sys_clkin1>, <&sata_ref_clk>;
- clock-names = "sysclk", "refclk";
- syscon-pllreset = <&scm_conf 0x3fc>;
- #phy-cells = <0>;
-};
diff --git a/MAINTAINERS b/MAINTAINERS
index 45b71e0713a8..a7c0463aaa95 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2520,6 +2520,7 @@ F: Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml
F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml
F: Documentation/devicetree/bindings/nvmem/apple,spmi-nvmem.yaml
F: Documentation/devicetree/bindings/pci/apple,pcie.yaml
+F: Documentation/devicetree/bindings/phy/apple,atcphy.yaml
F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
F: Documentation/devicetree/bindings/power/apple*
F: Documentation/devicetree/bindings/power/reset/apple,smc-reboot.yaml
@@ -2548,6 +2549,7 @@ F: drivers/mfd/macsmc.c
F: drivers/nvme/host/apple.c
F: drivers/nvmem/apple-efuses.c
F: drivers/nvmem/apple-spmi-nvmem.c
+F: drivers/phy/apple/
F: drivers/pinctrl/pinctrl-apple-gpio.c
F: drivers/power/reset/macsmc-reboot.c
F: drivers/pwm/pwm-apple.c
@@ -10858,10 +10860,12 @@ S: Maintained
P: Documentation/process/maintainer-soc-clean-dts.rst
C: irc://irc.oftc.net/pixel6-kernel-dev
F: Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
+F: Documentation/devicetree/bindings/phy/google,lga-usb-phy.yaml
F: Documentation/devicetree/bindings/soc/google/google,gs101-pmu-intr-gen.yaml
F: Documentation/devicetree/bindings/usb/google,lga-dwc3.yaml
F: arch/arm64/boot/dts/exynos/google/
F: drivers/clk/samsung/clk-gs101.c
+F: drivers/phy/phy-google-usb.c
F: drivers/soc/samsung/gs101-pmu.c
F: drivers/phy/samsung/phy-gs101-ufs.c
F: drivers/usb/dwc3/dwc3-google.c
diff --git a/drivers/Makefile b/drivers/Makefile
index ccc05f1eae3e..53fbd2e0acdd 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -10,7 +10,7 @@ obj-y += cache/
obj-y += irqchip/
obj-y += bus/
-obj-$(CONFIG_GENERIC_PHY) += phy/
+obj-y += phy/
# GPIO must come after pinctrl as gpios may need to mux pins etc
obj-$(CONFIG_PINCTRL) += pinctrl/
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 62153a3924b9..02467dfd4fb0 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -47,6 +47,17 @@ config GENERIC_PHY_MIPI_DPHY
Provides a number of helpers a core functions for MIPI D-PHY
drivers to us.
+config PHY_GOOGLE_USB
+ tristate "Google Tensor SoC USB PHY driver"
+ select GENERIC_PHY
+ depends on TYPEC
+ help
+ Enable support for the USB PHY on Google Tensor SoCs, starting with
+ the G5 generation (Laguna). This driver provides the PHY interfaces
+ to interact with the SNPS eUSB2 and USB 3.2/DisplayPort Combo PHY,
+ both of which are integrated with the DWC3 USB DRD controller.
+ This driver currently supports USB high-speed.
+
config PHY_LPC18XX_USB_OTG
tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver"
depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
@@ -123,8 +134,21 @@ config PHY_NXP_PTN3222
schemes. It supports all three USB 2.0 data rates: Low Speed, Full
Speed and High Speed.
+config PHY_SPACEMIT_K1_PCIE
+ tristate "PCIe and combo PHY driver for the SpacemiT K1 SoC"
+ depends on ARCH_SPACEMIT || COMPILE_TEST
+ depends on COMMON_CLK
+ depends on HAS_IOMEM
+ depends on OF
+ select GENERIC_PHY
+ default ARCH_SPACEMIT
+ help
+ Enable support for the PCIe and USB 3 combo PHY and two
+ PCIe-only PHYs used in the SpacemiT K1 SoC.
+
source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/amlogic/Kconfig"
+source "drivers/phy/apple/Kconfig"
source "drivers/phy/broadcom/Kconfig"
source "drivers/phy/cadence/Kconfig"
source "drivers/phy/freescale/Kconfig"
@@ -145,6 +169,7 @@ source "drivers/phy/rockchip/Kconfig"
source "drivers/phy/samsung/Kconfig"
source "drivers/phy/socionext/Kconfig"
source "drivers/phy/sophgo/Kconfig"
+source "drivers/phy/spacemit/Kconfig"
source "drivers/phy/st/Kconfig"
source "drivers/phy/starfive/Kconfig"
source "drivers/phy/sunplus/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 30b150d68de7..a648c2e02a83 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_COMMON_PROPS_TEST) += phy-common-props-test.o
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o
obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o
+obj-$(CONFIG_PHY_GOOGLE_USB) += phy-google-usb.o
obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
@@ -15,8 +16,10 @@ obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o
obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o
obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o
obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o
-obj-y += allwinner/ \
+obj-$(CONFIG_PHY_SPACEMIT_K1_PCIE) += phy-spacemit-k1-pcie.o
+obj-$(CONFIG_GENERIC_PHY) += allwinner/ \
amlogic/ \
+ apple/ \
broadcom/ \
cadence/ \
freescale/ \
@@ -38,6 +41,7 @@ obj-y += allwinner/ \
samsung/ \
socionext/ \
sophgo/ \
+ spacemit/ \
st/ \
starfive/ \
sunplus/ \
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index 59d38d88efb0..e2fbf8ccf99e 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -359,7 +359,7 @@ static int sun4i_usb_phy_init(struct phy *_phy)
/* Force ISCR and cable state updates */
data->id_det = -1;
data->vbus_det = -1;
- queue_delayed_work(system_wq, &data->detect, 0);
+ queue_delayed_work(system_percpu_wq, &data->detect, 0);
}
return 0;
@@ -482,7 +482,7 @@ static int sun4i_usb_phy_power_on(struct phy *_phy)
/* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */
if (phy->index == 0 && sun4i_usb_phy0_poll(data))
- mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
+ mod_delayed_work(system_percpu_wq, &data->detect, DEBOUNCE_TIME);
return 0;
}
@@ -503,7 +503,7 @@ static int sun4i_usb_phy_power_off(struct phy *_phy)
* Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan.
*/
if (phy->index == 0 && !sun4i_usb_phy0_poll(data))
- mod_delayed_work(system_wq, &data->detect, POLL_TIME);
+ mod_delayed_work(system_percpu_wq, &data->detect, POLL_TIME);
return 0;
}
@@ -542,7 +542,7 @@ static int sun4i_usb_phy_set_mode(struct phy *_phy,
data->id_det = -1; /* Force reprocessing of id */
data->force_session_end = true;
- queue_delayed_work(system_wq, &data->detect, 0);
+ queue_delayed_work(system_percpu_wq, &data->detect, 0);
return 0;
}
@@ -654,7 +654,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
extcon_set_state_sync(data->extcon, EXTCON_USB, vbus_det);
if (sun4i_usb_phy0_poll(data))
- queue_delayed_work(system_wq, &data->detect, POLL_TIME);
+ queue_delayed_work(system_percpu_wq, &data->detect, POLL_TIME);
}
static irqreturn_t sun4i_usb_phy0_id_vbus_det_irq(int irq, void *dev_id)
@@ -662,7 +662,7 @@ static irqreturn_t sun4i_usb_phy0_id_vbus_det_irq(int irq, void *dev_id)
struct sun4i_usb_phy_data *data = dev_id;
/* vbus or id changed, let the pins settle and then scan them */
- mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
+ mod_delayed_work(system_percpu_wq, &data->detect, DEBOUNCE_TIME);
return IRQ_HANDLED;
}
@@ -676,7 +676,7 @@ static int sun4i_usb_phy0_vbus_notify(struct notifier_block *nb,
/* Properties on the vbus_power_supply changed, scan vbus_det */
if (val == PSY_EVENT_PROP_CHANGED && psy == data->vbus_power_supply)
- mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
+ mod_delayed_work(system_percpu_wq, &data->detect, DEBOUNCE_TIME);
return NOTIFY_OK;
}
diff --git a/drivers/phy/apple/Kconfig b/drivers/phy/apple/Kconfig
new file mode 100644
index 000000000000..d82d6f291a75
--- /dev/null
+++ b/drivers/phy/apple/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+config PHY_APPLE_ATC
+ tristate "Apple Type-C PHY"
+ depends on (ARM64 && ARCH_APPLE) || (COMPILE_TEST && !GENERIC_ATOMIC64)
+ depends on TYPEC
+ select GENERIC_PHY
+ select APPLE_TUNABLE
+ help
+ Enable this to add support for the Apple Type-C PHY found in
+ Apple Silicon M-series SoCs. This PHY supports USB2,
+ USB3, USB4, Thunderbolt, and DisplayPort.
+
+ If M is selected the module will be called 'phy-apple-atc'.
diff --git a/drivers/phy/apple/Makefile b/drivers/phy/apple/Makefile
new file mode 100644
index 000000000000..e02836a63df3
--- /dev/null
+++ b/drivers/phy/apple/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+
+obj-$(CONFIG_PHY_APPLE_ATC) += phy-apple-atc.o
+phy-apple-atc-y := atc.o
diff --git a/drivers/phy/apple/atc.c b/drivers/phy/apple/atc.c
new file mode 100644
index 000000000000..dc867f368b68
--- /dev/null
+++ b/drivers/phy/apple/atc.c
@@ -0,0 +1,2295 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * Apple Type-C PHY driver
+ *
+ * The Apple Type-C PHY (ATCPHY) is a combined PHY for USB 2.0, USB 3.x,
+ * USB4/Thunderbolt, and DisplayPort connectivity via Type-C ports found in
+ * Apple Silicon SoCs.
+ *
+ * The PHY handles muxing between these different protocols and also provides the
+ * reset controller for the attached DWC3 USB controller.
+ *
+ * No documentation for this PHY is available and its operation has been
+ * reverse engineered by observing the XNU's MMIO access using a thin hypervisor
+ * and correlating register access to XNU's very verbose debug output. Most
+ * register names comes from this debug output as well.
+ *
+ * In order to correctly setup the high speed lanes for the various modes
+ * calibration values copied from Apple's firmware by our bootloader m1n1 are
+ * required. Without these only USB2 operation is possible.
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ * Author: Sven Peter <sven@kernel.org>
+ */
+
+#include <dt-bindings/phy/phy.h>
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/soc/apple/tunable.h>
+#include <linux/types.h>
+#include <linux/usb/pd.h>
+#include <linux/usb/typec.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
+#include <linux/usb/typec_tbt.h>
+
+#define AUSPLL_FSM_CTRL 0x1014
+
+#define AUSPLL_APB_CMD_OVERRIDE 0x2000
+#define AUSPLL_APB_CMD_OVERRIDE_REQ BIT(0)
+#define AUSPLL_APB_CMD_OVERRIDE_ACK BIT(1)
+#define AUSPLL_APB_CMD_OVERRIDE_UNK28 BIT(28)
+#define AUSPLL_APB_CMD_OVERRIDE_CMD GENMASK(27, 3)
+
+#define AUSPLL_FREQ_DESC_A 0x2080
+#define AUSPLL_FD_FREQ_COUNT_TARGET GENMASK(9, 0)
+#define AUSPLL_FD_FBDIVN_HALF BIT(10)
+#define AUSPLL_FD_REV_DIVN GENMASK(13, 11)
+#define AUSPLL_FD_KI_MAN GENMASK(17, 14)
+#define AUSPLL_FD_KI_EXP GENMASK(21, 18)
+#define AUSPLL_FD_KP_MAN GENMASK(25, 22)
+#define AUSPLL_FD_KP_EXP GENMASK(29, 26)
+#define AUSPLL_FD_KPKI_SCALE_HBW GENMASK(31, 30)
+
+#define AUSPLL_FREQ_DESC_B 0x2084
+#define AUSPLL_FD_FBDIVN_FRAC_DEN GENMASK(13, 0)
+#define AUSPLL_FD_FBDIVN_FRAC_NUM GENMASK(27, 14)
+
+#define AUSPLL_FREQ_DESC_C 0x2088
+#define AUSPLL_FD_SDM_SSC_STEP GENMASK(7, 0)
+#define AUSPLL_FD_SDM_SSC_EN BIT(8)
+#define AUSPLL_FD_PCLK_DIV_SEL GENMASK(13, 9)
+#define AUSPLL_FD_LFSDM_DIV GENMASK(15, 14)
+#define AUSPLL_FD_LFCLK_CTRL GENMASK(19, 16)
+#define AUSPLL_FD_VCLK_OP_DIVN GENMASK(21, 20)
+#define AUSPLL_FD_VCLK_PRE_DIVN BIT(22)
+
+#define AUSPLL_DCO_EFUSE_SPARE 0x222c
+#define AUSPLL_RODCO_ENCAP_EFUSE GENMASK(10, 9)
+#define AUSPLL_RODCO_BIAS_ADJUST_EFUSE GENMASK(14, 12)
+
+#define AUSPLL_FRACN_CAN 0x22a4
+#define AUSPLL_DLL_START_CAPCODE GENMASK(18, 17)
+
+#define AUSPLL_CLKOUT_MASTER 0x2200
+#define AUSPLL_CLKOUT_MASTER_PCLK_DRVR_EN BIT(2)
+#define AUSPLL_CLKOUT_MASTER_PCLK2_DRVR_EN BIT(4)
+#define AUSPLL_CLKOUT_MASTER_REFBUFCLK_DRVR_EN BIT(6)
+
+#define AUSPLL_CLKOUT_DIV 0x2208
+#define AUSPLL_CLKOUT_PLLA_REFBUFCLK_DI GENMASK(20, 16)
+
+#define AUSPLL_BGR 0x2214
+#define AUSPLL_BGR_CTRL_AVAIL BIT(0)
+
+#define AUSPLL_CLKOUT_DTC_VREG 0x2220
+#define AUSPLL_DTC_VREG_ADJUST GENMASK(16, 14)
+#define AUSPLL_DTC_VREG_BYPASS BIT(7)
+
+#define AUSPLL_FREQ_CFG 0x2224
+#define AUSPLL_FREQ_REFCLK GENMASK(1, 0)
+
+#define AUS_COMMON_SHIM_BLK_VREG 0x0a04
+#define AUS_VREG_TRIM GENMASK(6, 2)
+
+#define AUS_UNK_A20 0x0a20
+#define AUS_UNK_A20_TX_CAL_CODE GENMASK(23, 20)
+
+#define ACIOPHY_CMN_SHM_STS_REG0 0x0a74
+#define ACIOPHY_CMN_SHM_STS_REG0_CMD_READY BIT(0)
+
+#define CIO3PLL_CLK_CTRL 0x2a00
+#define CIO3PLL_CLK_PCLK_EN BIT(1)
+#define CIO3PLL_CLK_REFCLK_EN BIT(5)
+
+#define CIO3PLL_DCO_NCTRL 0x2a38
+#define CIO3PLL_DCO_COARSEBIN_EFUSE0 GENMASK(6, 0)
+#define CIO3PLL_DCO_COARSEBIN_EFUSE1 GENMASK(23, 17)
+
+#define CIO3PLL_FRACN_CAN 0x2aa4
+#define CIO3PLL_DLL_CAL_START_CAPCODE GENMASK(18, 17)
+
+#define CIO3PLL_DTC_VREG 0x2a20
+#define CIO3PLL_DTC_VREG_ADJUST GENMASK(16, 14)
+
+#define ACIOPHY_CFG0 0x08
+#define ACIOPHY_CFG0_COMMON_BIG_OV BIT(1)
+#define ACIOPHY_CFG0_COMMON_SMALL_OV BIT(3)
+#define ACIOPHY_CFG0_COMMON_CLAMP_OV BIT(5)
+#define ACIOPHY_CFG0_RX_SMALL_OV GENMASK(9, 8)
+#define ACIOPHY_CFG0_RX_BIG_OV GENMASK(13, 12)
+#define ACIOPHY_CFG0_RX_CLAMP_OV GENMASK(17, 16)
+
+#define ACIOPHY_CROSSBAR 0x4c
+#define ACIOPHY_CROSSBAR_PROTOCOL GENMASK(4, 0)
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB4 0x0
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB4_SWAPPED 0x1
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB3 0xa
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB3_SWAPPED 0xb
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP 0x10
+#define ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP_SWAPPED 0x11
+#define ACIOPHY_CROSSBAR_PROTOCOL_DP 0x14
+#define ACIOPHY_CROSSBAR_DP_SINGLE_PMA GENMASK(16, 5)
+#define ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE 0x0000
+#define ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK100 0x100
+#define ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008 0x008
+#define ACIOPHY_CROSSBAR_DP_BOTH_PMA BIT(17)
+
+#define ACIOPHY_LANE_MODE 0x48
+#define ACIOPHY_LANE_MODE_RX0 GENMASK(2, 0)
+#define ACIOPHY_LANE_MODE_TX0 GENMASK(5, 3)
+#define ACIOPHY_LANE_MODE_RX1 GENMASK(8, 6)
+#define ACIOPHY_LANE_MODE_TX1 GENMASK(11, 9)
+
+enum atcphy_lane_mode {
+ ACIOPHY_LANE_MODE_USB4 = 0,
+ ACIOPHY_LANE_MODE_USB3 = 1,
+ ACIOPHY_LANE_MODE_DP = 2,
+ ACIOPHY_LANE_MODE_OFF = 3,
+};
+
+#define ACIOPHY_TOP_BIST_CIOPHY_CFG1 0x84
+#define ACIOPHY_TOP_BIST_CIOPHY_CFG1_CLK_EN BIT(27)
+#define ACIOPHY_TOP_BIST_CIOPHY_CFG1_BIST_EN BIT(28)
+
+#define ACIOPHY_TOP_BIST_OV_CFG 0x8c
+#define ACIOPHY_TOP_BIST_OV_CFG_LN0_RESET_N_OV BIT(13)
+#define ACIOPHY_TOP_BIST_OV_CFG_LN0_PWR_DOWN_OV BIT(25)
+
+#define ACIOPHY_TOP_BIST_READ_CTRL 0x90
+#define ACIOPHY_TOP_BIST_READ_CTRL_LN0_PHY_STATUS_RE BIT(2)
+
+#define ACIOPHY_TOP_PHY_STAT 0x9c
+#define ACIOPHY_TOP_PHY_STAT_LN0_UNK0 BIT(0)
+#define ACIOPHY_TOP_PHY_STAT_LN0_UNK23 BIT(23)
+
+#define ACIOPHY_TOP_BIST_PHY_CFG0 0xa8
+#define ACIOPHY_TOP_BIST_PHY_CFG0_LN0_RESET_N BIT(0)
+
+#define ACIOPHY_TOP_BIST_PHY_CFG1 0xac
+#define ACIOPHY_TOP_BIST_PHY_CFG1_LN0_PWR_DOWN GENMASK(13, 10)
+
+#define ACIOPHY_SLEEP_CTRL 0x1b0
+#define ACIOPHY_SLEEP_CTRL_TX_BIG_OV GENMASK(3, 2)
+#define ACIOPHY_SLEEP_CTRL_TX_SMALL_OV GENMASK(7, 6)
+#define ACIOPHY_SLEEP_CTRL_TX_CLAMP_OV GENMASK(11, 10)
+
+#define ACIOPHY_PLL_PCTL_FSM_CTRL1 0x1014
+#define ACIOPHY_PLL_APB_REQ_OV_SEL GENMASK(21, 13)
+#define ACIOPHY_PLL_COMMON_CTRL 0x1028
+#define ACIOPHY_PLL_WAIT_FOR_CMN_READY_BEFORE_RESET_EXIT BIT(24)
+
+#define ATCPHY_POWER_CTRL 0x20000
+#define ATCPHY_POWER_STAT 0x20004
+#define ATCPHY_POWER_SLEEP_SMALL BIT(0)
+#define ATCPHY_POWER_SLEEP_BIG BIT(1)
+#define ATCPHY_POWER_CLAMP_EN BIT(2)
+#define ATCPHY_POWER_APB_RESET_N BIT(3)
+#define ATCPHY_POWER_PHY_RESET_N BIT(4)
+
+#define ATCPHY_MISC 0x20008
+#define ATCPHY_MISC_RESET_N BIT(0)
+#define ATCPHY_MISC_LANE_SWAP BIT(2)
+
+#define ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0 0x7000
+#define DP_PMA_BYTECLK_RESET BIT(0)
+#define DP_MAC_DIV20_CLK_SEL BIT(1)
+#define DPTXPHY_PMA_LANE_RESET_N BIT(2)
+#define DPTXPHY_PMA_LANE_RESET_N_OV BIT(3)
+#define DPTX_PCLK1_SELECT GENMASK(6, 4)
+#define DPTX_PCLK2_SELECT GENMASK(9, 7)
+#define DPRX_PCLK_SELECT GENMASK(12, 10)
+#define DPTX_PCLK1_ENABLE BIT(13)
+#define DPTX_PCLK2_ENABLE BIT(14)
+#define DPRX_PCLK_ENABLE BIT(15)
+
+#define ACIOPHY_DP_PCLK_STAT 0x7044
+#define ACIOPHY_AUSPLL_LOCK BIT(3)
+
+#define LN0_AUSPMA_RX_TOP 0x9000
+#define LN0_AUSPMA_RX_EQ 0xA000
+#define LN0_AUSPMA_RX_SHM 0xB000
+#define LN0_AUSPMA_TX_TOP 0xC000
+#define LN0_AUSPMA_TX_SHM 0xD000
+
+#define LN1_AUSPMA_RX_TOP 0x10000
+#define LN1_AUSPMA_RX_EQ 0x11000
+#define LN1_AUSPMA_RX_SHM 0x12000
+#define LN1_AUSPMA_TX_TOP 0x13000
+#define LN1_AUSPMA_TX_SHM 0x14000
+
+#define LN_AUSPMA_RX_TOP_PMAFSM 0x0010
+#define LN_AUSPMA_RX_TOP_PMAFSM_PCS_OV BIT(0)
+#define LN_AUSPMA_RX_TOP_PMAFSM_PCS_REQ BIT(9)
+
+#define LN_AUSPMA_RX_TOP_TJ_CFG_RX_TXMODE 0x00F0
+#define LN_RX_TXMODE BIT(0)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_CTLE_CTRL0 0x00
+#define LN_TX_CLK_EN BIT(20)
+#define LN_TX_CLK_EN_OV BIT(21)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_AFE_CTRL1 0x04
+#define LN_RX_DIV20_RESET_N_OV BIT(29)
+#define LN_RX_DIV20_RESET_N BIT(30)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL2 0x08
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL3 0x0C
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL4 0x10
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL5 0x14
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL6 0x18
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL7 0x1C
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL8 0x20
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL9 0x24
+#define LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL10 0x28
+#define LN_DTVREG_ADJUST GENMASK(31, 27)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL11 0x2C
+#define LN_DTVREG_BIG_EN BIT(23)
+#define LN_DTVREG_BIG_EN_OV BIT(24)
+#define LN_DTVREG_SML_EN BIT(25)
+#define LN_DTVREG_SML_EN_OV BIT(26)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12 0x30
+#define LN_TX_BYTECLK_RESET_SYNC_CLR BIT(22)
+#define LN_TX_BYTECLK_RESET_SYNC_CLR_OV BIT(23)
+#define LN_TX_BYTECLK_RESET_SYNC_EN BIT(24)
+#define LN_TX_BYTECLK_RESET_SYNC_EN_OV BIT(25)
+#define LN_TX_HRCLK_SEL BIT(28)
+#define LN_TX_HRCLK_SEL_OV BIT(29)
+#define LN_TX_PBIAS_EN BIT(30)
+#define LN_TX_PBIAS_EN_OV BIT(31)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13 0x34
+#define LN_TX_PRE_EN BIT(0)
+#define LN_TX_PRE_EN_OV BIT(1)
+#define LN_TX_PST1_EN BIT(2)
+#define LN_TX_PST1_EN_OV BIT(3)
+#define LN_DTVREG_ADJUST_OV BIT(15)
+
+#define LN_AUSPMA_RX_SHM_TJ_UNK_CTRL14A 0x38
+#define LN_AUSPMA_RX_SHM_TJ_UNK_CTRL14B 0x3C
+#define LN_AUSPMA_RX_SHM_TJ_UNK_CTRL15A 0x40
+#define LN_AUSPMA_RX_SHM_TJ_UNK_CTRL15B 0x44
+#define LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16 0x48
+#define LN_RXTERM_EN BIT(21)
+#define LN_RXTERM_EN_OV BIT(22)
+#define LN_RXTERM_PULLUP_LEAK_EN BIT(23)
+#define LN_RXTERM_PULLUP_LEAK_EN_OV BIT(24)
+#define LN_TX_CAL_CODE GENMASK(29, 25)
+#define LN_TX_CAL_CODE_OV BIT(30)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17 0x4C
+#define LN_TX_MARGIN GENMASK(19, 15)
+#define LN_TX_MARGIN_OV BIT(20)
+#define LN_TX_MARGIN_LSB BIT(21)
+#define LN_TX_MARGIN_LSB_OV BIT(22)
+#define LN_TX_MARGIN_P1 GENMASK(26, 23)
+#define LN_TX_MARGIN_P1_OV BIT(27)
+#define LN_TX_MARGIN_P1_LSB GENMASK(29, 28)
+#define LN_TX_MARGIN_P1_LSB_OV BIT(30)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18 0x50
+#define LN_TX_P1_CODE GENMASK(3, 0)
+#define LN_TX_P1_CODE_OV BIT(4)
+#define LN_TX_P1_LSB_CODE GENMASK(6, 5)
+#define LN_TX_P1_LSB_CODE_OV BIT(7)
+#define LN_TX_MARGIN_PRE GENMASK(10, 8)
+#define LN_TX_MARGIN_PRE_OV BIT(11)
+#define LN_TX_MARGIN_PRE_LSB GENMASK(13, 12)
+#define LN_TX_MARGIN_PRE_LSB_OV BIT(14)
+#define LN_TX_PRE_LSB_CODE GENMASK(16, 15)
+#define LN_TX_PRE_LSB_CODE_OV BIT(17)
+#define LN_TX_PRE_CODE GENMASK(21, 18)
+#define LN_TX_PRE_CODE_OV BIT(22)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19 0x54
+#define LN_TX_TEST_EN BIT(21)
+#define LN_TX_TEST_EN_OV BIT(22)
+#define LN_TX_EN BIT(23)
+#define LN_TX_EN_OV BIT(24)
+#define LN_TX_CLK_DLY_CTRL_TAPGEN GENMASK(27, 25)
+#define LN_TX_CLK_DIV2_EN BIT(28)
+#define LN_TX_CLK_DIV2_EN_OV BIT(29)
+#define LN_TX_CLK_DIV2_RST BIT(30)
+#define LN_TX_CLK_DIV2_RST_OV BIT(31)
+
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL20 0x58
+#define LN_AUSPMA_RX_SHM_TJ_RXA_UNK_CTRL21 0x5C
+#define LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22 0x60
+#define LN_VREF_ADJUST_GRAY GENMASK(11, 7)
+#define LN_VREF_ADJUST_GRAY_OV BIT(12)
+#define LN_VREF_BIAS_SEL GENMASK(14, 13)
+#define LN_VREF_BIAS_SEL_OV BIT(15)
+#define LN_VREF_BOOST_EN BIT(16)
+#define LN_VREF_BOOST_EN_OV BIT(17)
+#define LN_VREF_EN BIT(18)
+#define LN_VREF_EN_OV BIT(19)
+#define LN_VREF_LPBKIN_DATA GENMASK(29, 28)
+#define LN_VREF_TEST_RXLPBKDT_EN BIT(30)
+#define LN_VREF_TEST_RXLPBKDT_EN_OV BIT(31)
+
+#define LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0 0x00
+#define LN_BYTECLK_RESET_SYNC_EN_OV BIT(2)
+#define LN_BYTECLK_RESET_SYNC_EN BIT(3)
+#define LN_BYTECLK_RESET_SYNC_CLR_OV BIT(4)
+#define LN_BYTECLK_RESET_SYNC_CLR BIT(5)
+#define LN_BYTECLK_RESET_SYNC_SEL_OV BIT(6)
+
+#define LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1 0x04
+#define LN_TXA_DIV2_EN_OV BIT(8)
+#define LN_TXA_DIV2_EN BIT(9)
+#define LN_TXA_DIV2_RESET_OV BIT(10)
+#define LN_TXA_DIV2_RESET BIT(11)
+#define LN_TXA_CLK_EN_OV BIT(22)
+#define LN_TXA_CLK_EN BIT(23)
+
+#define LN_AUSPMA_TX_SHM_TXA_IMP_REG0 0x08
+#define LN_TXA_CAL_CTRL_OV BIT(0)
+#define LN_TXA_CAL_CTRL GENMASK(18, 1)
+#define LN_TXA_CAL_CTRL_BASE_OV BIT(19)
+#define LN_TXA_CAL_CTRL_BASE GENMASK(23, 20)
+#define LN_TXA_HIZ_OV BIT(29)
+#define LN_TXA_HIZ BIT(30)
+
+#define LN_AUSPMA_TX_SHM_TXA_IMP_REG1 0x0C
+#define LN_AUSPMA_TX_SHM_TXA_IMP_REG2 0x10
+#define LN_TXA_MARGIN_OV BIT(0)
+#define LN_TXA_MARGIN GENMASK(18, 1)
+#define LN_TXA_MARGIN_2R_OV BIT(19)
+#define LN_TXA_MARGIN_2R BIT(20)
+
+#define LN_AUSPMA_TX_SHM_TXA_IMP_REG3 0x14
+#define LN_TXA_MARGIN_POST_OV BIT(0)
+#define LN_TXA_MARGIN_POST GENMASK(10, 1)
+#define LN_TXA_MARGIN_POST_2R_OV BIT(11)
+#define LN_TXA_MARGIN_POST_2R BIT(12)
+#define LN_TXA_MARGIN_POST_4R_OV BIT(13)
+#define LN_TXA_MARGIN_POST_4R BIT(14)
+#define LN_TXA_MARGIN_PRE_OV BIT(15)
+#define LN_TXA_MARGIN_PRE GENMASK(21, 16)
+#define LN_TXA_MARGIN_PRE_2R_OV BIT(22)
+#define LN_TXA_MARGIN_PRE_2R BIT(23)
+#define LN_TXA_MARGIN_PRE_4R_OV BIT(24)
+#define LN_TXA_MARGIN_PRE_4R BIT(25)
+
+#define LN_AUSPMA_TX_SHM_TXA_UNK_REG0 0x18
+#define LN_AUSPMA_TX_SHM_TXA_UNK_REG1 0x1C
+#define LN_AUSPMA_TX_SHM_TXA_UNK_REG2 0x20
+
+#define LN_AUSPMA_TX_SHM_TXA_LDOCLK 0x24
+#define LN_LDOCLK_BYPASS_SML_OV BIT(8)
+#define LN_LDOCLK_BYPASS_SML BIT(9)
+#define LN_LDOCLK_BYPASS_BIG_OV BIT(10)
+#define LN_LDOCLK_BYPASS_BIG BIT(11)
+#define LN_LDOCLK_EN_SML_OV BIT(12)
+#define LN_LDOCLK_EN_SML BIT(13)
+#define LN_LDOCLK_EN_BIG_OV BIT(14)
+#define LN_LDOCLK_EN_BIG BIT(15)
+
+/* LPDPTX registers */
+#define LPDPTX_AUX_CFG_BLK_AUX_CTRL 0x0000
+#define LPDPTX_BLK_AUX_CTRL_PWRDN BIT(4)
+#define LPDPTX_BLK_AUX_RXOFFSET GENMASK(25, 22)
+
+#define LPDPTX_AUX_CFG_BLK_AUX_LDO_CTRL 0x0008
+
+#define LPDPTX_AUX_CFG_BLK_AUX_MARGIN 0x000c
+#define LPDPTX_MARGIN_RCAL_RXOFFSET_EN BIT(5)
+#define LPDPTX_AUX_MARGIN_RCAL_TXSWING GENMASK(10, 6)
+
+#define LPDPTX_AUX_SHM_CFG_BLK_AUX_CTRL_REG0 0x0204
+#define LPDPTX_CFG_PMA_AUX_SEL_LF_DATA BIT(15)
+
+#define LPDPTX_AUX_SHM_CFG_BLK_AUX_CTRL_REG1 0x0208
+#define LPDPTX_CFG_PMA_PHYS_ADJ GENMASK(22, 20)
+#define LPDPTX_CFG_PMA_PHYS_ADJ_OV BIT(19)
+
+#define LPDPTX_AUX_CONTROL 0x4000
+#define LPDPTX_AUX_PWN_DOWN 0x10
+#define LPDPTX_AUX_CLAMP_EN 0x04
+#define LPDPTX_SLEEP_B_BIG_IN 0x02
+#define LPDPTX_SLEEP_B_SML_IN 0x01
+#define LPDPTX_TXTERM_CODEMSB 0x400
+#define LPDPTX_TXTERM_CODE GENMASK(9, 5)
+
+/* pipehandler registers */
+#define PIPEHANDLER_OVERRIDE 0x00
+#define PIPEHANDLER_OVERRIDE_RXVALID BIT(0)
+#define PIPEHANDLER_OVERRIDE_RXDETECT BIT(2)
+
+#define PIPEHANDLER_OVERRIDE_VALUES 0x04
+#define PIPEHANDLER_OVERRIDE_VAL_RXDETECT0 BIT(1)
+#define PIPEHANDLER_OVERRIDE_VAL_RXDETECT1 BIT(2)
+#define PIPEHANDLER_OVERRIDE_VAL_PHY_STATUS BIT(4)
+
+#define PIPEHANDLER_MUX_CTRL 0x0c
+#define PIPEHANDLER_MUX_CTRL_CLK GENMASK(5, 3)
+#define PIPEHANDLER_MUX_CTRL_DATA GENMASK(2, 0)
+#define PIPEHANDLER_MUX_CTRL_CLK_OFF 0
+#define PIPEHANDLER_MUX_CTRL_CLK_USB3 1
+#define PIPEHANDLER_MUX_CTRL_CLK_USB4 2
+#define PIPEHANDLER_MUX_CTRL_CLK_DUMMY 4
+
+#define PIPEHANDLER_MUX_CTRL_DATA_USB3 0
+#define PIPEHANDLER_MUX_CTRL_DATA_USB4 1
+#define PIPEHANDLER_MUX_CTRL_DATA_DUMMY 2
+
+#define PIPEHANDLER_LOCK_REQ 0x10
+#define PIPEHANDLER_LOCK_ACK 0x14
+#define PIPEHANDLER_LOCK_EN BIT(0)
+
+#define PIPEHANDLER_AON_GEN 0x1C
+#define PIPEHANDLER_AON_GEN_DWC3_FORCE_CLAMP_EN BIT(4)
+#define PIPEHANDLER_AON_GEN_DWC3_RESET_N BIT(0)
+
+#define PIPEHANDLER_NONSELECTED_OVERRIDE 0x20
+#define PIPEHANDLER_NATIVE_RESET BIT(12)
+#define PIPEHANDLER_DUMMY_PHY_EN BIT(15)
+#define PIPEHANDLER_NATIVE_POWER_DOWN GENMASK(3, 0)
+
+#define PIPEHANDLER_LOCK_ACK_TIMEOUT_US 1000
+
+/* USB2 PHY regs */
+#define USB2PHY_USBCTL 0x00
+#define USB2PHY_USBCTL_RUN 2
+#define USB2PHY_USBCTL_ISOLATION 4
+
+#define USB2PHY_CTL 0x04
+#define USB2PHY_CTL_RESET BIT(0)
+#define USB2PHY_CTL_PORT_RESET BIT(1)
+#define USB2PHY_CTL_APB_RESET_N BIT(2)
+#define USB2PHY_CTL_SIDDQ BIT(3)
+
+#define USB2PHY_SIG 0x08
+#define USB2PHY_SIG_VBUSDET_FORCE_VAL BIT(0)
+#define USB2PHY_SIG_VBUSDET_FORCE_EN BIT(1)
+#define USB2PHY_SIG_VBUSVLDEXT_FORCE_VAL BIT(2)
+#define USB2PHY_SIG_VBUSVLDEXT_FORCE_EN BIT(3)
+#define USB2PHY_SIG_HOST (7 << 12)
+
+#define USB2PHY_MISCTUNE 0x1c
+#define USB2PHY_MISCTUNE_APBCLK_GATE_OFF BIT(29)
+#define USB2PHY_MISCTUNE_REFCLK_GATE_OFF BIT(30)
+
+enum atcphy_dp_link_rate {
+ ATCPHY_DP_LINK_RATE_RBR,
+ ATCPHY_DP_LINK_RATE_HBR,
+ ATCPHY_DP_LINK_RATE_HBR2,
+ ATCPHY_DP_LINK_RATE_HBR3,
+};
+
+/**
+ * enum atcphy_pipehandler_state - States of the PIPE mux interface ("pipehandler")
+ * @ATCPHY_PIPEHANDLER_STATE_DUMMY: "Dummy PHY" (disables USB3, USB2 only)
+ * @ATCPHY_PIPEHANDLER_STATE_USB3: USB3 directly connected to the Type-C port
+ * @ATCPHY_PIPEHANDLER_STATE_USB4: USB3 tunneled via USB4/Thunderbolt
+ *
+ * DWC3's USB3 PIPE interface is connected to a multiplexer inside this PHY
+ * which can switch between a dummy state (which effectively disables any USB3
+ * support and falls back to USB2 only operation via the separate ULPI interface),
+ * a USB3 state (for regular USB3 or USB3+DisplayPort operation) and a USB4 state
+ * (for USB3 tunneled via USB4/Thunderbolt).
+ */
+enum atcphy_pipehandler_state {
+ ATCPHY_PIPEHANDLER_STATE_DUMMY,
+ ATCPHY_PIPEHANDLER_STATE_USB3,
+ ATCPHY_PIPEHANDLER_STATE_USB4,
+};
+
+/**
+ * enum atcphy_mode - Operating modes of the PHY
+ * @APPLE_ATCPHY_MODE_OFF: all PHYs powered off
+ * @APPLE_ATCPHY_MODE_USB2: Nothing on the four SS lanes (i.e. USB2 only on D-/+)
+ * @APPLE_ATCPHY_MODE_USB3: USB3 on two lanes, nothing on the other two
+ * @APPLE_ATCPHY_MODE_USB3_DP: USB3 on two lanes and DisplayPort on the other two
+ * @APPLE_ATCPHY_MODE_TBT: Thunderbolt on all lanes
+ * @APPLE_ATCPHY_MODE_USB4: USB4 on all lanes
+ * @APPLE_ATCPHY_MODE_DP: DisplayPort on all lanes
+ */
+enum atcphy_mode {
+ APPLE_ATCPHY_MODE_OFF,
+ APPLE_ATCPHY_MODE_USB2,
+ APPLE_ATCPHY_MODE_USB3,
+ APPLE_ATCPHY_MODE_USB3_DP,
+ APPLE_ATCPHY_MODE_TBT,
+ APPLE_ATCPHY_MODE_USB4,
+ APPLE_ATCPHY_MODE_DP,
+};
+
+enum atcphy_lane {
+ APPLE_ATCPHY_LANE_0,
+ APPLE_ATCPHY_LANE_1,
+};
+
+/* Link rate configuration, field names are taken from XNU debug output or register names */
+struct atcphy_dp_link_rate_configuration {
+ u16 freqinit_count_target;
+ u16 fbdivn_frac_den;
+ u16 fbdivn_frac_num;
+ u16 pclk_div_sel;
+ u8 lfclk_ctrl;
+ u8 vclk_op_divn;
+ bool plla_clkout_vreg_bypass;
+ bool txa_ldoclk_bypass;
+ bool txa_div2_en;
+};
+
+/* Crossbar and lane configuration */
+struct atcphy_mode_configuration {
+ u32 crossbar;
+ u32 crossbar_dp_single_pma;
+ bool crossbar_dp_both_pma;
+ enum atcphy_lane_mode lane_mode[2];
+ bool dp_lane[2];
+ bool set_swap;
+};
+
+/**
+ * struct apple_atcphy - Apple Type-C PHY device struct
+ * @np: Device node pointer
+ * @dev: Device pointer
+ * @tunables: Firmware-provided tunable parameters
+ * @tunables.axi2af: AXI to AF interface tunables
+ * @tunables.common: Common tunables for all lanes
+ * @tunables.lane_usb3: USB3 lane-specific tunables
+ * @tunables.lane_dp: DisplayPort lane-specific tunables
+ * @tunables.lane_usb4: USB4 lane-specific tunables
+ * @mode: Current PHY operating mode
+ * @swap_lanes: True if lanes must be swapped due to cable orientation
+ * @dp_link_rate: DisplayPort link rate
+ * @pipehandler_up: True if the PIPE mux ("pipehandler") is set to USB3 or USB4 mode
+ * @regs: Memory-mapped registers
+ * @regs.core: Core registers
+ * @regs.axi2af: AXI to Apple Fabric interface registers
+ * @regs.usb2phy: USB2 PHY registers
+ * @regs.pipehandler: USB3 PIPE interface ("pipehandler") registers
+ * @regs.lpdptx: DisplayPort registers
+ * @res: Resources for memory-mapped registers, used to verify that tunables aren't out of bounds
+ * @res.core: Core register resource
+ * @res.axi2af: AXI to Apple Fabric interface resource
+ * @phys: PHY instances
+ * @phys.usb2: USB2 PHY instance
+ * @phys.usb3: USB3 PHY instance
+ * @phys.dp: DisplayPort PHY instance
+ * @phy_provider: PHY provider instance
+ * @rcdev: Reset controller device
+ * @sw: Type-C switch instance
+ * @mux: Type-C mux instance
+ * @lock: Mutex for synchronizing register access across PHY, Type-C switch/mux and reset controller
+ */
+struct apple_atcphy {
+ struct device_node *np;
+ struct device *dev;
+
+ struct {
+ struct apple_tunable *axi2af;
+ struct apple_tunable *common[2];
+ struct apple_tunable *lane_usb3[2];
+ struct apple_tunable *lane_dp[2];
+ struct apple_tunable *lane_usb4[2];
+ } tunables;
+
+ enum atcphy_mode mode;
+ bool swap_lanes;
+ int dp_link_rate;
+ bool pipehandler_up;
+
+ struct {
+ void __iomem *core;
+ void __iomem *axi2af;
+ void __iomem *usb2phy;
+ void __iomem *pipehandler;
+ void __iomem *lpdptx;
+ } regs;
+
+ struct {
+ struct resource *core;
+ struct resource *axi2af;
+ } res;
+
+ struct {
+ struct phy *usb2;
+ struct phy *usb3;
+ struct phy *dp;
+ } phys;
+ struct phy_provider *phy_provider;
+
+ struct reset_controller_dev rcdev;
+
+ struct typec_switch *sw;
+ struct typec_mux *mux;
+
+ struct mutex lock;
+};
+
+static const struct {
+ const struct atcphy_mode_configuration normal;
+ const struct atcphy_mode_configuration swapped;
+ bool enable_dp_aux;
+ enum atcphy_pipehandler_state pipehandler_state;
+} atcphy_modes[] = {
+ [APPLE_ATCPHY_MODE_OFF] = {
+ .normal = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_OFF, ACIOPHY_LANE_MODE_OFF},
+ .dp_lane = {false, false},
+ .set_swap = false,
+ },
+ .swapped = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_SWAPPED,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_OFF, ACIOPHY_LANE_MODE_OFF},
+ .dp_lane = {false, false},
+ .set_swap = false, /* doesn't matter since the SS lanes are off */
+ },
+ .enable_dp_aux = false,
+ .pipehandler_state = ATCPHY_PIPEHANDLER_STATE_DUMMY,
+ },
+ [APPLE_ATCPHY_MODE_USB2] = {
+ .normal = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_OFF, ACIOPHY_LANE_MODE_OFF},
+ .dp_lane = {false, false},
+ .set_swap = false,
+ },
+ .swapped = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_SWAPPED,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_OFF, ACIOPHY_LANE_MODE_OFF},
+ .dp_lane = {false, false},
+ .set_swap = false, /* doesn't matter since the SS lanes are off */
+ },
+ .enable_dp_aux = false,
+ .pipehandler_state = ATCPHY_PIPEHANDLER_STATE_DUMMY,
+ },
+ [APPLE_ATCPHY_MODE_USB3] = {
+ /*
+ * Setting up the lanes as DP/USB3 is intentional here, USB3/USB3 does not work
+ * and isn't required since this PHY does not support 20GBps mode anyway.
+ * The only difference to APPLE_ATCPHY_MODE_USB3_DP is that DP Aux is not enabled.
+ */
+ .normal = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_USB3, ACIOPHY_LANE_MODE_DP},
+ .dp_lane = {false, true},
+ .set_swap = false,
+ },
+ .swapped = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP_SWAPPED,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_DP, ACIOPHY_LANE_MODE_USB3},
+ .dp_lane = {true, false},
+ .set_swap = true,
+ },
+ .enable_dp_aux = false,
+ .pipehandler_state = ATCPHY_PIPEHANDLER_STATE_USB3,
+ },
+ [APPLE_ATCPHY_MODE_USB3_DP] = {
+ .normal = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_USB3, ACIOPHY_LANE_MODE_DP},
+ .dp_lane = {false, true},
+ .set_swap = false,
+ },
+ .swapped = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB3_DP_SWAPPED,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_DP, ACIOPHY_LANE_MODE_USB3},
+ .dp_lane = {true, false},
+ .set_swap = true,
+ },
+ .enable_dp_aux = true,
+ .pipehandler_state = ATCPHY_PIPEHANDLER_STATE_USB3,
+ },
+ [APPLE_ATCPHY_MODE_TBT] = {
+ .normal = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB4,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_USB4, ACIOPHY_LANE_MODE_USB4},
+ .dp_lane = {false, false},
+ .set_swap = false,
+ },
+ .swapped = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB4_SWAPPED,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_USB4, ACIOPHY_LANE_MODE_USB4},
+ .dp_lane = {false, false},
+ .set_swap = false, /* intentionally false */
+ },
+ .enable_dp_aux = false,
+ .pipehandler_state = ATCPHY_PIPEHANDLER_STATE_DUMMY,
+ },
+ [APPLE_ATCPHY_MODE_USB4] = {
+ .normal = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB4,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_USB4, ACIOPHY_LANE_MODE_USB4},
+ .dp_lane = {false, false},
+ .set_swap = false,
+ },
+ .swapped = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_USB4_SWAPPED,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_NONE,
+ .crossbar_dp_both_pma = false,
+ .lane_mode = {ACIOPHY_LANE_MODE_USB4, ACIOPHY_LANE_MODE_USB4},
+ .dp_lane = {false, false},
+ .set_swap = false, /* intentionally false */
+ },
+ .enable_dp_aux = false,
+ .pipehandler_state = ATCPHY_PIPEHANDLER_STATE_USB4,
+ },
+ [APPLE_ATCPHY_MODE_DP] = {
+ .normal = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_DP,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK100,
+ .crossbar_dp_both_pma = true,
+ .lane_mode = {ACIOPHY_LANE_MODE_DP, ACIOPHY_LANE_MODE_DP},
+ .dp_lane = {true, true},
+ .set_swap = false,
+ },
+ .swapped = {
+ .crossbar = ACIOPHY_CROSSBAR_PROTOCOL_DP,
+ .crossbar_dp_single_pma = ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008,
+ .crossbar_dp_both_pma = false, /* intentionally false */
+ .lane_mode = {ACIOPHY_LANE_MODE_DP, ACIOPHY_LANE_MODE_DP},
+ .dp_lane = {true, true},
+ .set_swap = false, /* intentionally false */
+ },
+ .enable_dp_aux = true,
+ .pipehandler_state = ATCPHY_PIPEHANDLER_STATE_DUMMY,
+ },
+};
+
+static const struct atcphy_dp_link_rate_configuration dp_lr_config[] = {
+ [ATCPHY_DP_LINK_RATE_RBR] = {
+ .freqinit_count_target = 0x21c,
+ .fbdivn_frac_den = 0x0,
+ .fbdivn_frac_num = 0x0,
+ .pclk_div_sel = 0x13,
+ .lfclk_ctrl = 0x5,
+ .vclk_op_divn = 0x2,
+ .plla_clkout_vreg_bypass = true,
+ .txa_ldoclk_bypass = true,
+ .txa_div2_en = true,
+ },
+ [ATCPHY_DP_LINK_RATE_HBR] = {
+ .freqinit_count_target = 0x1c2,
+ .fbdivn_frac_den = 0x3ffe,
+ .fbdivn_frac_num = 0x1fff,
+ .pclk_div_sel = 0x9,
+ .lfclk_ctrl = 0x5,
+ .vclk_op_divn = 0x2,
+ .plla_clkout_vreg_bypass = true,
+ .txa_ldoclk_bypass = true,
+ .txa_div2_en = false,
+ },
+ [ATCPHY_DP_LINK_RATE_HBR2] = {
+ .freqinit_count_target = 0x1c2,
+ .fbdivn_frac_den = 0x3ffe,
+ .fbdivn_frac_num = 0x1fff,
+ .pclk_div_sel = 0x4,
+ .lfclk_ctrl = 0x5,
+ .vclk_op_divn = 0x0,
+ .plla_clkout_vreg_bypass = true,
+ .txa_ldoclk_bypass = true,
+ .txa_div2_en = false,
+ },
+ [ATCPHY_DP_LINK_RATE_HBR3] = {
+ .freqinit_count_target = 0x2a3,
+ .fbdivn_frac_den = 0x3ffc,
+ .fbdivn_frac_num = 0x2ffd,
+ .pclk_div_sel = 0x4,
+ .lfclk_ctrl = 0x6,
+ .vclk_op_divn = 0x0,
+ .plla_clkout_vreg_bypass = false,
+ .txa_ldoclk_bypass = false,
+ .txa_div2_en = false,
+ },
+};
+
+static inline void mask32(void __iomem *reg, u32 mask, u32 set)
+{
+ u32 value = readl(reg);
+
+ value &= ~mask;
+ value |= set;
+ writel(value, reg);
+}
+
+static inline void core_mask32(struct apple_atcphy *atcphy, u32 reg, u32 mask, u32 set)
+{
+ mask32(atcphy->regs.core + reg, mask, set);
+}
+
+static inline void set32(void __iomem *reg, u32 set)
+{
+ mask32(reg, 0, set);
+}
+
+static inline void core_set32(struct apple_atcphy *atcphy, u32 reg, u32 set)
+{
+ core_mask32(atcphy, reg, 0, set);
+}
+
+static inline void clear32(void __iomem *reg, u32 clear)
+{
+ mask32(reg, clear, 0);
+}
+
+static inline void core_clear32(struct apple_atcphy *atcphy, u32 reg, u32 clear)
+{
+ core_mask32(atcphy, reg, clear, 0);
+}
+
+static const struct atcphy_mode_configuration *atcphy_get_mode_config(struct apple_atcphy *atcphy,
+ enum atcphy_mode mode)
+{
+ if (atcphy->swap_lanes)
+ return &atcphy_modes[mode].swapped;
+ else
+ return &atcphy_modes[mode].normal;
+}
+
+static void atcphy_apply_tunables(struct apple_atcphy *atcphy, enum atcphy_mode mode)
+{
+ const int lane0 = atcphy->swap_lanes ? 1 : 0;
+ const int lane1 = atcphy->swap_lanes ? 0 : 1;
+
+ apple_tunable_apply(atcphy->regs.core, atcphy->tunables.common[0]);
+ apple_tunable_apply(atcphy->regs.axi2af, atcphy->tunables.axi2af);
+ apple_tunable_apply(atcphy->regs.core, atcphy->tunables.common[1]);
+
+ switch (mode) {
+ /*
+ * USB 3.2 Gen 2x2 / SuperSpeed 20Gbps is not supported by this hardware and applying USB3
+ * tunables to both lanes does not result in a working PHY configuration. Thus, both
+ * USB3-only and USB3/DP get the same tunable setup here.
+ */
+ case APPLE_ATCPHY_MODE_USB3:
+ case APPLE_ATCPHY_MODE_USB3_DP:
+ apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_usb3[lane0]);
+ apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_dp[lane1]);
+ break;
+
+ case APPLE_ATCPHY_MODE_DP:
+ apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_dp[lane0]);
+ apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_dp[lane1]);
+ break;
+
+ /*
+ * Even though the various Thunderbolt versions and USB4 are different protocols they need
+ * the same tunables. The actual protocol-specific setup happens inside the Thunderbolt/USB4
+ * native host interface.
+ */
+ case APPLE_ATCPHY_MODE_TBT:
+ case APPLE_ATCPHY_MODE_USB4:
+ apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_usb4[lane0]);
+ apple_tunable_apply(atcphy->regs.core, atcphy->tunables.lane_usb4[lane1]);
+ break;
+
+ case APPLE_ATCPHY_MODE_OFF:
+ case APPLE_ATCPHY_MODE_USB2:
+ break;
+ }
+}
+
+static int atcphy_pipehandler_lock(struct apple_atcphy *atcphy)
+{
+ int ret;
+ u32 reg;
+
+ if (readl(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ) & PIPEHANDLER_LOCK_EN) {
+ dev_warn(atcphy->dev, "Pipehandler already locked\n");
+ return 0;
+ }
+
+ set32(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ, PIPEHANDLER_LOCK_EN);
+
+ ret = readl_poll_timeout(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_ACK, reg,
+ reg & PIPEHANDLER_LOCK_EN, 10, PIPEHANDLER_LOCK_ACK_TIMEOUT_US);
+ if (ret) {
+ clear32(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ, 1);
+ dev_warn(atcphy->dev, "Pipehandler lock not acked.\n");
+ }
+
+ return ret;
+}
+
+static int atcphy_pipehandler_unlock(struct apple_atcphy *atcphy)
+{
+ int ret;
+ u32 reg;
+
+ clear32(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_REQ, PIPEHANDLER_LOCK_EN);
+ ret = readl_poll_timeout(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_ACK, reg,
+ !(reg & PIPEHANDLER_LOCK_EN), 10, PIPEHANDLER_LOCK_ACK_TIMEOUT_US);
+ if (ret)
+ dev_warn(atcphy->dev, "Pipehandler lock release not acked.\n");
+
+ return ret;
+}
+
+static int atcphy_pipehandler_check(struct apple_atcphy *atcphy)
+{
+ int ret;
+
+ lockdep_assert_held(&atcphy->lock);
+
+ if (readl(atcphy->regs.pipehandler + PIPEHANDLER_LOCK_ACK) & PIPEHANDLER_LOCK_EN) {
+ dev_warn(atcphy->dev, "Pipehandler already locked\n");
+
+ ret = atcphy_pipehandler_unlock(atcphy);
+ if (ret) {
+ dev_err(atcphy->dev, "Failed to unlock pipehandler\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int atcphy_configure_pipehandler_usb3(struct apple_atcphy *atcphy, bool host)
+{
+ int ret;
+ u32 reg;
+
+ ret = atcphy_pipehandler_check(atcphy);
+ if (ret)
+ return ret;
+
+ /*
+ * Only host mode requires this unknown BIST sequence to work correctly, possibly due to
+ * some hardware quirk. Guest mode breaks if we try to apply this sequence.
+ */
+ if (host) {
+ /* Force disable link detection */
+ clear32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE_VALUES,
+ PIPEHANDLER_OVERRIDE_VAL_RXDETECT0 | PIPEHANDLER_OVERRIDE_VAL_RXDETECT1);
+ set32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE,
+ PIPEHANDLER_OVERRIDE_RXVALID);
+ set32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE,
+ PIPEHANDLER_OVERRIDE_RXDETECT);
+
+ ret = atcphy_pipehandler_lock(atcphy);
+ if (ret) {
+ dev_err(atcphy->dev, "Failed to lock pipehandler");
+ return ret;
+ }
+
+ /* BIST dance */
+ core_set32(atcphy, ACIOPHY_TOP_BIST_PHY_CFG0,
+ ACIOPHY_TOP_BIST_PHY_CFG0_LN0_RESET_N);
+ core_set32(atcphy, ACIOPHY_TOP_BIST_OV_CFG, ACIOPHY_TOP_BIST_OV_CFG_LN0_RESET_N_OV);
+ ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
+ !(reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK23), 10, 10000);
+ if (ret)
+ dev_warn(atcphy->dev,
+ "Timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK23\n");
+
+ core_set32(atcphy, ACIOPHY_TOP_BIST_READ_CTRL,
+ ACIOPHY_TOP_BIST_READ_CTRL_LN0_PHY_STATUS_RE);
+ core_clear32(atcphy, ACIOPHY_TOP_BIST_READ_CTRL,
+ ACIOPHY_TOP_BIST_READ_CTRL_LN0_PHY_STATUS_RE);
+
+ core_mask32(atcphy, ACIOPHY_TOP_BIST_PHY_CFG1,
+ ACIOPHY_TOP_BIST_PHY_CFG1_LN0_PWR_DOWN,
+ FIELD_PREP(ACIOPHY_TOP_BIST_PHY_CFG1_LN0_PWR_DOWN, 3));
+
+ core_set32(atcphy, ACIOPHY_TOP_BIST_OV_CFG,
+ ACIOPHY_TOP_BIST_OV_CFG_LN0_PWR_DOWN_OV);
+ core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+ ACIOPHY_TOP_BIST_CIOPHY_CFG1_CLK_EN);
+ core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+ ACIOPHY_TOP_BIST_CIOPHY_CFG1_BIST_EN);
+ writel(0, atcphy->regs.core + ACIOPHY_TOP_BIST_CIOPHY_CFG1);
+
+ ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
+ (reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK0), 10, 10000);
+ if (ret)
+ dev_warn(atcphy->dev,
+ "timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK0\n");
+
+ ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
+ !(reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK23), 10, 10000);
+ if (ret)
+ dev_warn(atcphy->dev,
+ "timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK23\n");
+
+ /* Clear reset for non-selected USB3 PHY (?) */
+ mask32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
+ PIPEHANDLER_NATIVE_POWER_DOWN, FIELD_PREP(PIPEHANDLER_NATIVE_POWER_DOWN, 3));
+ clear32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
+ PIPEHANDLER_NATIVE_RESET);
+
+ /* More BIST stuff (?) */
+ writel(0, atcphy->regs.core + ACIOPHY_TOP_BIST_OV_CFG);
+ core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+ ACIOPHY_TOP_BIST_CIOPHY_CFG1_CLK_EN);
+ core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+ ACIOPHY_TOP_BIST_CIOPHY_CFG1_BIST_EN);
+ }
+
+ /* Configure PIPE mux to USB3 PHY */
+ mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+ FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_OFF));
+ udelay(10);
+ mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_DATA,
+ FIELD_PREP(PIPEHANDLER_MUX_CTRL_DATA, PIPEHANDLER_MUX_CTRL_DATA_USB3));
+ udelay(10);
+ mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+ FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_USB3));
+ udelay(10);
+
+ /* Remove link detection override */
+ clear32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE, PIPEHANDLER_OVERRIDE_RXVALID);
+ clear32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE, PIPEHANDLER_OVERRIDE_RXDETECT);
+
+ /* Pipehandler was only locked when the BIST sequence was applied for host mode */
+ if (host) {
+ ret = atcphy_pipehandler_unlock(atcphy);
+ if (ret)
+ dev_warn(atcphy->dev, "Failed to unlock pipehandler");
+ }
+
+ return 0;
+}
+
+static int atcphy_configure_pipehandler_dummy(struct apple_atcphy *atcphy)
+{
+ int ret;
+
+ ret = atcphy_pipehandler_check(atcphy);
+ if (ret)
+ return ret;
+
+ /* Force disable link detection */
+ clear32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE_VALUES,
+ PIPEHANDLER_OVERRIDE_VAL_RXDETECT0 | PIPEHANDLER_OVERRIDE_VAL_RXDETECT1);
+ set32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE, PIPEHANDLER_OVERRIDE_RXVALID);
+ set32(atcphy->regs.pipehandler + PIPEHANDLER_OVERRIDE, PIPEHANDLER_OVERRIDE_RXDETECT);
+
+ ret = atcphy_pipehandler_lock(atcphy);
+ if (ret)
+ dev_warn(atcphy->dev, "Failed to lock pipehandler");
+
+ /* Switch to dummy PHY */
+ mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+ FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_OFF));
+ udelay(10);
+ mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_DATA,
+ FIELD_PREP(PIPEHANDLER_MUX_CTRL_DATA, PIPEHANDLER_MUX_CTRL_DATA_DUMMY));
+ udelay(10);
+ mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+ FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_DUMMY));
+ udelay(10);
+
+ ret = atcphy_pipehandler_unlock(atcphy);
+ if (ret)
+ dev_warn(atcphy->dev, "Failed to unlock pipehandler");
+
+ mask32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
+ PIPEHANDLER_NATIVE_POWER_DOWN, FIELD_PREP(PIPEHANDLER_NATIVE_POWER_DOWN, 2));
+ set32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
+ PIPEHANDLER_NATIVE_RESET);
+
+ return 0;
+}
+
+static int atcphy_configure_pipehandler(struct apple_atcphy *atcphy, bool host)
+{
+ int ret;
+
+ lockdep_assert_held(&atcphy->lock);
+
+ switch (atcphy_modes[atcphy->mode].pipehandler_state) {
+ case ATCPHY_PIPEHANDLER_STATE_USB3:
+ ret = atcphy_configure_pipehandler_usb3(atcphy, host);
+ atcphy->pipehandler_up = true;
+ break;
+ case ATCPHY_PIPEHANDLER_STATE_USB4:
+ dev_warn(atcphy->dev,
+ "ATCPHY_PIPEHANDLER_STATE_USB4 not implemented; falling back to USB2\n");
+ ret = atcphy_configure_pipehandler_dummy(atcphy);
+ atcphy->pipehandler_up = false;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void atcphy_setup_pipehandler(struct apple_atcphy *atcphy)
+{
+ lockdep_assert_held(&atcphy->lock);
+
+ mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+ FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_OFF));
+ udelay(10);
+ mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_DATA,
+ FIELD_PREP(PIPEHANDLER_MUX_CTRL_DATA, PIPEHANDLER_MUX_CTRL_DATA_DUMMY));
+ udelay(10);
+ mask32(atcphy->regs.pipehandler + PIPEHANDLER_MUX_CTRL, PIPEHANDLER_MUX_CTRL_CLK,
+ FIELD_PREP(PIPEHANDLER_MUX_CTRL_CLK, PIPEHANDLER_MUX_CTRL_CLK_DUMMY));
+ udelay(10);
+}
+
+static void atcphy_configure_lanes(struct apple_atcphy *atcphy, enum atcphy_mode mode)
+{
+ const struct atcphy_mode_configuration *mode_cfg = atcphy_get_mode_config(atcphy, mode);
+
+ core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_RX0,
+ FIELD_PREP(ACIOPHY_LANE_MODE_RX0, mode_cfg->lane_mode[0]));
+ core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_TX0,
+ FIELD_PREP(ACIOPHY_LANE_MODE_TX0, mode_cfg->lane_mode[0]));
+ core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_RX1,
+ FIELD_PREP(ACIOPHY_LANE_MODE_RX1, mode_cfg->lane_mode[1]));
+ core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_TX1,
+ FIELD_PREP(ACIOPHY_LANE_MODE_TX1, mode_cfg->lane_mode[1]));
+ core_mask32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_PROTOCOL,
+ FIELD_PREP(ACIOPHY_CROSSBAR_PROTOCOL, mode_cfg->crossbar));
+
+ if (mode_cfg->set_swap)
+ core_set32(atcphy, ATCPHY_MISC, ATCPHY_MISC_LANE_SWAP);
+ else
+ core_clear32(atcphy, ATCPHY_MISC, ATCPHY_MISC_LANE_SWAP);
+
+ core_mask32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_DP_SINGLE_PMA,
+ FIELD_PREP(ACIOPHY_CROSSBAR_DP_SINGLE_PMA, mode_cfg->crossbar_dp_single_pma));
+ if (mode_cfg->crossbar_dp_both_pma)
+ core_set32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_DP_BOTH_PMA);
+ else
+ core_clear32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_DP_BOTH_PMA);
+
+ if (mode_cfg->dp_lane[0]) {
+ core_set32(atcphy, LN0_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+ LN_AUSPMA_RX_TOP_PMAFSM_PCS_OV);
+ udelay(10);
+ core_clear32(atcphy, LN0_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+ LN_AUSPMA_RX_TOP_PMAFSM_PCS_REQ);
+ } else {
+ core_clear32(atcphy, LN0_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+ LN_AUSPMA_RX_TOP_PMAFSM_PCS_OV);
+ udelay(10);
+ }
+
+ if (mode_cfg->dp_lane[1]) {
+ core_set32(atcphy, LN1_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+ LN_AUSPMA_RX_TOP_PMAFSM_PCS_OV);
+ udelay(10);
+ core_clear32(atcphy, LN1_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+ LN_AUSPMA_RX_TOP_PMAFSM_PCS_REQ);
+ } else {
+ core_clear32(atcphy, LN1_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
+ LN_AUSPMA_RX_TOP_PMAFSM_PCS_OV);
+ udelay(10);
+ }
+}
+
+static void atcphy_enable_dp_aux(struct apple_atcphy *atcphy)
+{
+ core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTXPHY_PMA_LANE_RESET_N);
+ core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTXPHY_PMA_LANE_RESET_N_OV);
+
+ core_mask32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPRX_PCLK_SELECT,
+ FIELD_PREP(DPRX_PCLK_SELECT, 1));
+ core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPRX_PCLK_ENABLE);
+
+ core_mask32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK1_SELECT,
+ FIELD_PREP(DPTX_PCLK1_SELECT, 1));
+ core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK1_ENABLE);
+
+ core_mask32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK2_SELECT,
+ FIELD_PREP(DPTX_PCLK2_SELECT, 1));
+ core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK2_ENABLE);
+
+ core_set32(atcphy, ACIOPHY_PLL_COMMON_CTRL,
+ ACIOPHY_PLL_WAIT_FOR_CMN_READY_BEFORE_RESET_EXIT);
+
+ set32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_AUX_CLAMP_EN);
+ set32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_SLEEP_B_SML_IN);
+ udelay(10);
+ set32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_SLEEP_B_BIG_IN);
+ udelay(10);
+ clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_AUX_CLAMP_EN);
+ clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_AUX_PWN_DOWN);
+ clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_TXTERM_CODEMSB);
+ mask32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_TXTERM_CODE,
+ FIELD_PREP(LPDPTX_TXTERM_CODE, 0x16));
+
+ set32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_LDO_CTRL, 0x1c00);
+ mask32(atcphy->regs.lpdptx + LPDPTX_AUX_SHM_CFG_BLK_AUX_CTRL_REG1, LPDPTX_CFG_PMA_PHYS_ADJ,
+ FIELD_PREP(LPDPTX_CFG_PMA_PHYS_ADJ, 5));
+ set32(atcphy->regs.lpdptx + LPDPTX_AUX_SHM_CFG_BLK_AUX_CTRL_REG1,
+ LPDPTX_CFG_PMA_PHYS_ADJ_OV);
+
+ clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_MARGIN,
+ LPDPTX_MARGIN_RCAL_RXOFFSET_EN);
+
+ clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_CTRL, LPDPTX_BLK_AUX_CTRL_PWRDN);
+ set32(atcphy->regs.lpdptx + LPDPTX_AUX_SHM_CFG_BLK_AUX_CTRL_REG0,
+ LPDPTX_CFG_PMA_AUX_SEL_LF_DATA);
+ mask32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_CTRL, LPDPTX_BLK_AUX_RXOFFSET,
+ FIELD_PREP(LPDPTX_BLK_AUX_RXOFFSET, 3));
+
+ mask32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_MARGIN, LPDPTX_AUX_MARGIN_RCAL_TXSWING,
+ FIELD_PREP(LPDPTX_AUX_MARGIN_RCAL_TXSWING, 12));
+
+ atcphy->dp_link_rate = -1;
+}
+
+static void atcphy_disable_dp_aux(struct apple_atcphy *atcphy)
+{
+ set32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_AUX_PWN_DOWN);
+ set32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_CTRL, LPDPTX_BLK_AUX_CTRL_PWRDN);
+ set32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_AUX_CLAMP_EN);
+ clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_SLEEP_B_SML_IN);
+ udelay(10);
+ clear32(atcphy->regs.lpdptx + LPDPTX_AUX_CONTROL, LPDPTX_SLEEP_B_BIG_IN);
+ udelay(10);
+
+ core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTXPHY_PMA_LANE_RESET_N);
+ core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPRX_PCLK_ENABLE);
+ core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK1_ENABLE);
+ core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK2_ENABLE);
+}
+
+static int atcphy_dp_configure_lane(struct apple_atcphy *atcphy, enum atcphy_lane lane,
+ const struct atcphy_dp_link_rate_configuration *cfg)
+{
+ void __iomem *tx_shm, *rx_shm, *rx_top;
+ unsigned int tx_cal_code;
+
+ lockdep_assert_held(&atcphy->lock);
+
+ switch (lane) {
+ case APPLE_ATCPHY_LANE_0:
+ tx_shm = atcphy->regs.core + LN0_AUSPMA_TX_SHM;
+ rx_shm = atcphy->regs.core + LN0_AUSPMA_RX_SHM;
+ rx_top = atcphy->regs.core + LN0_AUSPMA_RX_TOP;
+ break;
+ case APPLE_ATCPHY_LANE_1:
+ tx_shm = atcphy->regs.core + LN1_AUSPMA_TX_SHM;
+ rx_shm = atcphy->regs.core + LN1_AUSPMA_RX_SHM;
+ rx_top = atcphy->regs.core + LN1_AUSPMA_RX_TOP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_EN_SML);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_EN_SML_OV);
+ udelay(10);
+
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_EN_BIG);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_EN_BIG_OV);
+ udelay(10);
+
+ if (cfg->txa_ldoclk_bypass) {
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_SML);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_SML_OV);
+ udelay(10);
+
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_BIG);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_BIG_OV);
+ udelay(10);
+ } else {
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_SML);
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_SML_OV);
+ udelay(10);
+
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_BIG);
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_BYPASS_BIG_OV);
+ udelay(10);
+ }
+
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0, LN_BYTECLK_RESET_SYNC_SEL_OV);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0, LN_BYTECLK_RESET_SYNC_EN);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0, LN_BYTECLK_RESET_SYNC_EN_OV);
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0, LN_BYTECLK_RESET_SYNC_CLR);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG0, LN_BYTECLK_RESET_SYNC_CLR_OV);
+
+ if (cfg->txa_div2_en)
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_DIV2_EN);
+ else
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_DIV2_EN);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_DIV2_EN_OV);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_CLK_EN);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_CLK_EN_OV);
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_DIV2_RESET);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_CFG_MAIN_REG1, LN_TXA_DIV2_RESET_OV);
+
+ mask32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_CAL_CTRL_BASE,
+ FIELD_PREP(LN_TXA_CAL_CTRL_BASE, 0xf));
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_CAL_CTRL_BASE_OV);
+
+ tx_cal_code = FIELD_GET(AUS_UNK_A20_TX_CAL_CODE, readl(atcphy->regs.core + AUS_UNK_A20));
+ mask32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_CAL_CTRL,
+ FIELD_PREP(LN_TXA_CAL_CTRL, (1 << tx_cal_code) - 1));
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_CAL_CTRL_OV);
+
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG2, LN_TXA_MARGIN);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG2, LN_TXA_MARGIN_OV);
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG2, LN_TXA_MARGIN_2R);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG2, LN_TXA_MARGIN_2R_OV);
+
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST_OV);
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST_2R);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST_2R_OV);
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST_4R);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_POST_4R_OV);
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE_OV);
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE_2R);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE_2R_OV);
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE_4R);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG3, LN_TXA_MARGIN_PRE_4R_OV);
+
+ clear32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_HIZ);
+ set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_IMP_REG0, LN_TXA_HIZ_OV);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_AFE_CTRL1, LN_RX_DIV20_RESET_N);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_AFE_CTRL1, LN_RX_DIV20_RESET_N_OV);
+ udelay(10);
+
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_AFE_CTRL1, LN_RX_DIV20_RESET_N);
+
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_BYTECLK_RESET_SYNC_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_BYTECLK_RESET_SYNC_EN_OV);
+
+ mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_TX_CAL_CODE,
+ FIELD_PREP(LN_TX_CAL_CODE, tx_cal_code));
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_TX_CAL_CODE_OV);
+
+ mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DLY_CTRL_TAPGEN,
+ FIELD_PREP(LN_TX_CLK_DLY_CTRL_TAPGEN, 3));
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL10, LN_DTVREG_ADJUST);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_DTVREG_ADJUST_OV);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_RXTERM_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_RXTERM_EN_OV);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_TEST_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_TEST_EN_OV);
+
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_TEST_RXLPBKDT_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_TEST_RXLPBKDT_EN_OV);
+ mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_LPBKIN_DATA,
+ FIELD_PREP(LN_VREF_LPBKIN_DATA, 3));
+ mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BIAS_SEL,
+ FIELD_PREP(LN_VREF_BIAS_SEL, 2));
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BIAS_SEL_OV);
+ mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_ADJUST_GRAY,
+ FIELD_PREP(LN_VREF_ADJUST_GRAY, 0x18));
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_ADJUST_GRAY_OV);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_EN_OV);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BOOST_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BOOST_EN_OV);
+ udelay(10);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BOOST_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_VREF_CTRL22, LN_VREF_BOOST_EN_OV);
+ udelay(10);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_TX_PRE_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_TX_PRE_EN_OV);
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_TX_PST1_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_TX_PST1_EN_OV);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_PBIAS_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_PBIAS_EN_OV);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_RXTERM_PULLUP_LEAK_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_SAVOS_CTRL16, LN_RXTERM_PULLUP_LEAK_EN_OV);
+
+ set32(rx_top + LN_AUSPMA_RX_TOP_TJ_CFG_RX_TXMODE, LN_RX_TXMODE);
+
+ if (cfg->txa_div2_en)
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DIV2_EN);
+ else
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DIV2_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DIV2_EN_OV);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DIV2_RST);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_CLK_DIV2_RST_OV);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_HRCLK_SEL);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_HRCLK_SEL_OV);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_OV);
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_LSB);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_LSB_OV);
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_P1);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_P1_OV);
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_P1_LSB);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL17, LN_TX_MARGIN_P1_LSB_OV);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_P1_CODE);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_P1_CODE_OV);
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_P1_LSB_CODE);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_P1_LSB_CODE_OV);
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_MARGIN_PRE);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_MARGIN_PRE_OV);
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_MARGIN_PRE_LSB);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_MARGIN_PRE_LSB_OV);
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_PRE_LSB_CODE);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_PRE_LSB_CODE_OV);
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_PRE_CODE);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TX_CTRL18, LN_TX_PRE_CODE_OV);
+
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL11, LN_DTVREG_SML_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL11, LN_DTVREG_SML_EN_OV);
+ udelay(10);
+
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL11, LN_DTVREG_BIG_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL11, LN_DTVREG_BIG_EN_OV);
+ udelay(10);
+
+ mask32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL10, LN_DTVREG_ADJUST,
+ FIELD_PREP(LN_DTVREG_ADJUST, 0xa));
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL13, LN_DTVREG_ADJUST_OV);
+ udelay(10);
+
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_TERM_CTRL19, LN_TX_EN_OV);
+ udelay(10);
+
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_CTLE_CTRL0, LN_TX_CLK_EN);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_CTLE_CTRL0, LN_TX_CLK_EN_OV);
+
+ clear32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_BYTECLK_RESET_SYNC_CLR);
+ set32(rx_shm + LN_AUSPMA_RX_SHM_TJ_RXA_DFE_CTRL12, LN_TX_BYTECLK_RESET_SYNC_CLR_OV);
+
+ return 0;
+}
+
+static int atcphy_auspll_apb_command(struct apple_atcphy *atcphy, u32 command)
+{
+ int ret;
+ u32 reg;
+
+ reg = readl(atcphy->regs.core + AUSPLL_APB_CMD_OVERRIDE);
+ reg &= ~AUSPLL_APB_CMD_OVERRIDE_CMD;
+ reg |= FIELD_PREP(AUSPLL_APB_CMD_OVERRIDE_CMD, command);
+ reg |= AUSPLL_APB_CMD_OVERRIDE_REQ;
+ reg |= AUSPLL_APB_CMD_OVERRIDE_UNK28;
+ writel(reg, atcphy->regs.core + AUSPLL_APB_CMD_OVERRIDE);
+
+ ret = readl_poll_timeout(atcphy->regs.core + AUSPLL_APB_CMD_OVERRIDE, reg,
+ (reg & AUSPLL_APB_CMD_OVERRIDE_ACK), 10, 10000);
+ if (ret)
+ dev_warn(atcphy->dev, "AUSPLL APB command was not acked\n");
+
+ core_clear32(atcphy, AUSPLL_APB_CMD_OVERRIDE, AUSPLL_APB_CMD_OVERRIDE_REQ);
+
+ return 0;
+}
+
+static int atcphy_dp_configure(struct apple_atcphy *atcphy, enum atcphy_dp_link_rate lr)
+{
+ const struct atcphy_dp_link_rate_configuration *cfg;
+ const struct atcphy_mode_configuration *mode_cfg;
+ int ret;
+ u32 reg;
+
+ guard(mutex)(&atcphy->lock);
+ mode_cfg = atcphy_get_mode_config(atcphy, atcphy->mode);
+ cfg = &dp_lr_config[lr];
+
+ if (atcphy->dp_link_rate == lr)
+ return 0;
+
+ ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_CMN_SHM_STS_REG0, reg,
+ (reg & ACIOPHY_CMN_SHM_STS_REG0_CMD_READY), 10, 10000);
+ if (ret) {
+ dev_err(atcphy->dev, "ACIOPHY_CMN_SHM_STS_REG0_CMD_READY not set.\n");
+ return ret;
+ }
+
+ core_clear32(atcphy, AUSPLL_FREQ_CFG, AUSPLL_FREQ_REFCLK);
+
+ core_mask32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_FREQ_COUNT_TARGET,
+ FIELD_PREP(AUSPLL_FD_FREQ_COUNT_TARGET, cfg->freqinit_count_target));
+ core_clear32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_FBDIVN_HALF);
+ core_clear32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_REV_DIVN);
+ core_mask32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_KI_MAN, FIELD_PREP(AUSPLL_FD_KI_MAN, 8));
+ core_mask32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_KI_EXP, FIELD_PREP(AUSPLL_FD_KI_EXP, 3));
+ core_mask32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_KP_MAN, FIELD_PREP(AUSPLL_FD_KP_MAN, 8));
+ core_mask32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_KP_EXP, FIELD_PREP(AUSPLL_FD_KP_EXP, 7));
+ core_clear32(atcphy, AUSPLL_FREQ_DESC_A, AUSPLL_FD_KPKI_SCALE_HBW);
+
+ core_mask32(atcphy, AUSPLL_FREQ_DESC_B, AUSPLL_FD_FBDIVN_FRAC_DEN,
+ FIELD_PREP(AUSPLL_FD_FBDIVN_FRAC_DEN, cfg->fbdivn_frac_den));
+ core_mask32(atcphy, AUSPLL_FREQ_DESC_B, AUSPLL_FD_FBDIVN_FRAC_NUM,
+ FIELD_PREP(AUSPLL_FD_FBDIVN_FRAC_NUM, cfg->fbdivn_frac_num));
+
+ core_clear32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_SDM_SSC_STEP);
+ core_clear32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_SDM_SSC_EN);
+ core_mask32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_PCLK_DIV_SEL,
+ FIELD_PREP(AUSPLL_FD_PCLK_DIV_SEL, cfg->pclk_div_sel));
+ core_mask32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_LFSDM_DIV,
+ FIELD_PREP(AUSPLL_FD_LFSDM_DIV, 1));
+ core_mask32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_LFCLK_CTRL,
+ FIELD_PREP(AUSPLL_FD_LFCLK_CTRL, cfg->lfclk_ctrl));
+ core_mask32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_VCLK_OP_DIVN,
+ FIELD_PREP(AUSPLL_FD_VCLK_OP_DIVN, cfg->vclk_op_divn));
+ core_set32(atcphy, AUSPLL_FREQ_DESC_C, AUSPLL_FD_VCLK_PRE_DIVN);
+
+ core_mask32(atcphy, AUSPLL_CLKOUT_DIV, AUSPLL_CLKOUT_PLLA_REFBUFCLK_DI,
+ FIELD_PREP(AUSPLL_CLKOUT_PLLA_REFBUFCLK_DI, 7));
+
+ if (cfg->plla_clkout_vreg_bypass)
+ core_set32(atcphy, AUSPLL_CLKOUT_DTC_VREG, AUSPLL_DTC_VREG_BYPASS);
+ else
+ core_clear32(atcphy, AUSPLL_CLKOUT_DTC_VREG, AUSPLL_DTC_VREG_BYPASS);
+
+ core_set32(atcphy, AUSPLL_BGR, AUSPLL_BGR_CTRL_AVAIL);
+
+ core_set32(atcphy, AUSPLL_CLKOUT_MASTER, AUSPLL_CLKOUT_MASTER_PCLK_DRVR_EN);
+ core_set32(atcphy, AUSPLL_CLKOUT_MASTER, AUSPLL_CLKOUT_MASTER_PCLK2_DRVR_EN);
+ core_set32(atcphy, AUSPLL_CLKOUT_MASTER, AUSPLL_CLKOUT_MASTER_REFBUFCLK_DRVR_EN);
+
+ ret = atcphy_auspll_apb_command(atcphy, 0);
+ if (ret)
+ return ret;
+
+ ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_DP_PCLK_STAT, reg,
+ (reg & ACIOPHY_AUSPLL_LOCK), 10, 10000);
+ if (ret) {
+ dev_err(atcphy->dev, "ACIOPHY_DP_PCLK did not lock.\n");
+ return ret;
+ }
+
+ ret = atcphy_auspll_apb_command(atcphy, 0x2800);
+ if (ret)
+ return ret;
+
+ if (mode_cfg->dp_lane[0]) {
+ ret = atcphy_dp_configure_lane(atcphy, APPLE_ATCPHY_LANE_0, cfg);
+ if (ret)
+ return ret;
+ }
+
+ if (mode_cfg->dp_lane[1]) {
+ ret = atcphy_dp_configure_lane(atcphy, APPLE_ATCPHY_LANE_1, cfg);
+ if (ret)
+ return ret;
+ }
+
+ core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DP_PMA_BYTECLK_RESET);
+ core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DP_MAC_DIV20_CLK_SEL);
+
+ atcphy->dp_link_rate = lr;
+ return 0;
+}
+
+static void atcphy_usb2_power_off(struct apple_atcphy *atcphy)
+{
+ /* Disable the PHY, this clears USB2PHY_USBCTL_RUN */
+ writel(USB2PHY_USBCTL_ISOLATION, atcphy->regs.usb2phy + USB2PHY_USBCTL);
+ udelay(10);
+
+ /* Switch the PHY to low power mode */
+ set32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_SIDDQ);
+ udelay(10);
+
+ /* Enable all resets */
+ set32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_PORT_RESET);
+ udelay(10);
+ set32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_RESET);
+ udelay(10);
+ clear32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_APB_RESET_N);
+ udelay(10);
+ set32(atcphy->regs.usb2phy + USB2PHY_MISCTUNE, USB2PHY_MISCTUNE_APBCLK_GATE_OFF);
+ set32(atcphy->regs.usb2phy + USB2PHY_MISCTUNE, USB2PHY_MISCTUNE_REFCLK_GATE_OFF);
+}
+
+static int atcphy_power_off(struct apple_atcphy *atcphy)
+{
+ u32 reg;
+ int ret;
+
+ atcphy_disable_dp_aux(atcphy);
+
+ /* Enable all reset lines */
+ core_clear32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_PHY_RESET_N);
+ core_set32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_CLAMP_EN);
+ core_clear32(atcphy, ATCPHY_MISC, ATCPHY_MISC_RESET_N | ATCPHY_MISC_LANE_SWAP);
+ core_clear32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_APB_RESET_N);
+
+ core_clear32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_SLEEP_BIG);
+ ret = readl_poll_timeout(atcphy->regs.core + ATCPHY_POWER_STAT, reg,
+ !(reg & ATCPHY_POWER_SLEEP_BIG), 10, 1000);
+ if (ret) {
+ dev_err(atcphy->dev, "Failed to sleep atcphy \"big\"\n");
+ return ret;
+ }
+
+ core_clear32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_SLEEP_SMALL);
+ ret = readl_poll_timeout(atcphy->regs.core + ATCPHY_POWER_STAT, reg,
+ !(reg & ATCPHY_POWER_SLEEP_SMALL), 10, 1000);
+ if (ret) {
+ dev_err(atcphy->dev, "Failed to sleep atcphy \"small\"\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void atcphy_usb2_power_on(struct apple_atcphy *atcphy)
+{
+ set32(atcphy->regs.usb2phy + USB2PHY_SIG,
+ USB2PHY_SIG_VBUSDET_FORCE_VAL | USB2PHY_SIG_VBUSDET_FORCE_EN |
+ USB2PHY_SIG_VBUSVLDEXT_FORCE_VAL | USB2PHY_SIG_VBUSVLDEXT_FORCE_EN);
+ udelay(10);
+
+ /* Take the PHY out of its low power state */
+ clear32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_SIDDQ);
+ udelay(10);
+
+ /* Release reset */
+ clear32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_RESET);
+ udelay(10);
+ clear32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_PORT_RESET);
+ udelay(10);
+ set32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_APB_RESET_N);
+ udelay(10);
+ clear32(atcphy->regs.usb2phy + USB2PHY_MISCTUNE, USB2PHY_MISCTUNE_APBCLK_GATE_OFF);
+ clear32(atcphy->regs.usb2phy + USB2PHY_MISCTUNE, USB2PHY_MISCTUNE_REFCLK_GATE_OFF);
+
+ /* Enable the PHY */
+ writel(USB2PHY_USBCTL_RUN, atcphy->regs.usb2phy + USB2PHY_USBCTL);
+}
+
+static int atcphy_power_on(struct apple_atcphy *atcphy)
+{
+ u32 reg;
+ int ret;
+
+ atcphy_usb2_power_on(atcphy);
+
+ core_set32(atcphy, ATCPHY_MISC, ATCPHY_MISC_RESET_N);
+
+ core_set32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_SLEEP_SMALL);
+ ret = readl_poll_timeout(atcphy->regs.core + ATCPHY_POWER_STAT, reg,
+ reg & ATCPHY_POWER_SLEEP_SMALL, 100, 100000);
+ if (ret) {
+ dev_err(atcphy->dev, "failed to wakeup atcphy \"small\"\n");
+ return ret;
+ }
+
+ core_set32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_SLEEP_BIG);
+ ret = readl_poll_timeout(atcphy->regs.core + ATCPHY_POWER_STAT, reg,
+ reg & ATCPHY_POWER_SLEEP_BIG, 100, 100000);
+ if (ret) {
+ dev_err(atcphy->dev, "failed to wakeup atcphy \"big\"\n");
+ return ret;
+ }
+
+ core_clear32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_CLAMP_EN);
+ core_set32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_APB_RESET_N);
+
+ return 0;
+}
+
+static int atcphy_configure(struct apple_atcphy *atcphy, enum atcphy_mode mode)
+{
+ int ret = 0;
+
+ lockdep_assert_held(&atcphy->lock);
+
+ if (mode == APPLE_ATCPHY_MODE_OFF) {
+ ret = atcphy_power_off(atcphy);
+ atcphy->mode = mode;
+ return ret;
+ }
+
+ ret = atcphy_power_on(atcphy);
+ if (ret)
+ return ret;
+
+ atcphy_apply_tunables(atcphy, mode);
+
+ core_set32(atcphy, AUSPLL_FSM_CTRL, 0x1fe000);
+ core_set32(atcphy, AUSPLL_APB_CMD_OVERRIDE, AUSPLL_APB_CMD_OVERRIDE_UNK28);
+
+ set32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_SMALL_OV);
+ udelay(10);
+ set32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_BIG_OV);
+ udelay(10);
+ set32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_CLAMP_OV);
+ udelay(10);
+
+ mask32(atcphy->regs.core + ACIOPHY_SLEEP_CTRL, ACIOPHY_SLEEP_CTRL_TX_SMALL_OV,
+ FIELD_PREP(ACIOPHY_SLEEP_CTRL_TX_SMALL_OV, 3));
+ udelay(10);
+ mask32(atcphy->regs.core + ACIOPHY_SLEEP_CTRL, ACIOPHY_SLEEP_CTRL_TX_BIG_OV,
+ FIELD_PREP(ACIOPHY_SLEEP_CTRL_TX_BIG_OV, 3));
+ udelay(10);
+ mask32(atcphy->regs.core + ACIOPHY_SLEEP_CTRL, ACIOPHY_SLEEP_CTRL_TX_CLAMP_OV,
+ FIELD_PREP(ACIOPHY_SLEEP_CTRL_TX_CLAMP_OV, 3));
+ udelay(10);
+
+ mask32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_RX_BIG_OV,
+ FIELD_PREP(ACIOPHY_CFG0_RX_BIG_OV, 3));
+ udelay(10);
+ mask32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_RX_SMALL_OV,
+ FIELD_PREP(ACIOPHY_CFG0_RX_SMALL_OV, 3));
+ udelay(10);
+ mask32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_RX_CLAMP_OV,
+ FIELD_PREP(ACIOPHY_CFG0_RX_CLAMP_OV, 3));
+ udelay(10);
+
+ /* Setup AUX channel if DP altmode is requested */
+ if (atcphy_modes[mode].enable_dp_aux)
+ atcphy_enable_dp_aux(atcphy);
+
+ /* Enable clocks and configure lanes */
+ core_set32(atcphy, CIO3PLL_CLK_CTRL, CIO3PLL_CLK_PCLK_EN);
+ core_set32(atcphy, CIO3PLL_CLK_CTRL, CIO3PLL_CLK_REFCLK_EN);
+ atcphy_configure_lanes(atcphy, mode);
+
+ /* Take the USB3 PHY out of reset */
+ core_set32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_PHY_RESET_N);
+
+ atcphy->mode = mode;
+
+ return 0;
+}
+
+static int atcphy_usb2_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ struct apple_atcphy *atcphy = phy_get_drvdata(phy);
+
+ guard(mutex)(&atcphy->lock);
+
+ switch (mode) {
+ case PHY_MODE_USB_HOST:
+ set32(atcphy->regs.usb2phy + USB2PHY_SIG, USB2PHY_SIG_HOST);
+ break;
+ case PHY_MODE_USB_DEVICE:
+ clear32(atcphy->regs.usb2phy + USB2PHY_SIG, USB2PHY_SIG_HOST);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct phy_ops apple_atc_usb2_phy_ops = {
+ .owner = THIS_MODULE,
+ .set_mode = atcphy_usb2_set_mode,
+};
+
+static int atcphy_usb3_power_off(struct phy *phy)
+{
+ struct apple_atcphy *atcphy = phy_get_drvdata(phy);
+ int ret;
+
+ guard(mutex)(&atcphy->lock);
+
+ ret = atcphy_configure_pipehandler_dummy(atcphy);
+ if (ret)
+ dev_warn(atcphy->dev, "Failed to switch pipe to dummy: %d", ret);
+
+ atcphy->pipehandler_up = false;
+
+ if (atcphy->mode != APPLE_ATCPHY_MODE_OFF)
+ atcphy_configure(atcphy, APPLE_ATCPHY_MODE_OFF);
+
+ return 0;
+}
+
+static int atcphy_usb3_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ struct apple_atcphy *atcphy = phy_get_drvdata(phy);
+
+ guard(mutex)(&atcphy->lock);
+
+ /*
+ * We may get multiple calls to set_mode (for host mode e.g. at least one from the dwc3 glue
+ * driver and then another one from the generic xhci code) but must only configure the
+ * PIPE handler once.
+ */
+ if (atcphy->pipehandler_up)
+ return 0;
+
+ switch (mode) {
+ case PHY_MODE_USB_HOST:
+ return atcphy_configure_pipehandler(atcphy, true);
+ case PHY_MODE_USB_DEVICE:
+ return atcphy_configure_pipehandler(atcphy, false);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct phy_ops apple_atc_usb3_phy_ops = {
+ .owner = THIS_MODULE,
+ .power_off = atcphy_usb3_power_off,
+ .set_mode = atcphy_usb3_set_mode,
+};
+
+static int atcphy_dpphy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ /* Nothing to do here since the setup already happened in mux_set */
+ if (mode == PHY_MODE_DP && submode == 0)
+ return 0;
+ return -EINVAL;
+}
+
+static int atcphy_dpphy_validate(struct phy *phy, enum phy_mode mode, int submode,
+ union phy_configure_opts *opts_)
+{
+ struct phy_configure_opts_dp *opts = &opts_->dp;
+ struct apple_atcphy *atcphy = phy_get_drvdata(phy);
+
+ if (mode != PHY_MODE_DP)
+ return -EINVAL;
+ if (submode != 0)
+ return -EINVAL;
+
+ switch (atcphy->mode) {
+ case APPLE_ATCPHY_MODE_USB3_DP:
+ opts->lanes = 2;
+ break;
+ case APPLE_ATCPHY_MODE_DP:
+ opts->lanes = 4;
+ break;
+ default:
+ opts->lanes = 0;
+ }
+
+ return 0;
+}
+
+static int atcphy_dpphy_configure(struct phy *phy, union phy_configure_opts *opts_)
+{
+ struct phy_configure_opts_dp *opts = &opts_->dp;
+ struct apple_atcphy *atcphy = phy_get_drvdata(phy);
+ enum atcphy_dp_link_rate link_rate;
+
+ if (opts->set_voltages)
+ return -EINVAL;
+ if (opts->set_lanes)
+ return -EINVAL;
+
+ if (opts->set_rate) {
+ switch (opts->link_rate) {
+ case 1620:
+ link_rate = ATCPHY_DP_LINK_RATE_RBR;
+ break;
+ case 2700:
+ link_rate = ATCPHY_DP_LINK_RATE_HBR;
+ break;
+ case 5400:
+ link_rate = ATCPHY_DP_LINK_RATE_HBR2;
+ break;
+ case 8100:
+ link_rate = ATCPHY_DP_LINK_RATE_HBR3;
+ break;
+ case 0:
+ return 0;
+ default:
+ dev_err(atcphy->dev, "Unsupported link rate: %d\n", opts->link_rate);
+ return -EINVAL;
+ }
+
+ return atcphy_dp_configure(atcphy, link_rate);
+ }
+
+ return 0;
+}
+
+static const struct phy_ops apple_atc_dp_phy_ops = {
+ .owner = THIS_MODULE,
+ .configure = atcphy_dpphy_configure,
+ .validate = atcphy_dpphy_validate,
+ .set_mode = atcphy_dpphy_set_mode,
+};
+
+static struct phy *atcphy_xlate(struct device *dev, const struct of_phandle_args *args)
+{
+ struct apple_atcphy *atcphy = dev_get_drvdata(dev);
+
+ switch (args->args[0]) {
+ case PHY_TYPE_USB2:
+ return atcphy->phys.usb2;
+ case PHY_TYPE_USB3:
+ return atcphy->phys.usb3;
+ case PHY_TYPE_DP:
+ return atcphy->phys.dp;
+ }
+ return ERR_PTR(-ENODEV);
+}
+
+static int atcphy_probe_phy(struct apple_atcphy *atcphy)
+{
+ struct {
+ struct phy **phy;
+ const struct phy_ops *ops;
+ } phys[] = {
+ { &atcphy->phys.usb2, &apple_atc_usb2_phy_ops },
+ { &atcphy->phys.usb3, &apple_atc_usb3_phy_ops },
+ { &atcphy->phys.dp, &apple_atc_dp_phy_ops },
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(phys); i++) {
+ *phys[i].phy = devm_phy_create(atcphy->dev, NULL, phys[i].ops);
+ if (IS_ERR(*phys[i].phy))
+ return PTR_ERR(*phys[i].phy);
+ phy_set_drvdata(*phys[i].phy, atcphy);
+ }
+
+ atcphy->phy_provider = devm_of_phy_provider_register(atcphy->dev, atcphy_xlate);
+ if (IS_ERR(atcphy->phy_provider))
+ return PTR_ERR(atcphy->phy_provider);
+ return 0;
+}
+
+static void _atcphy_dwc3_reset_assert(struct apple_atcphy *atcphy)
+{
+ lockdep_assert_held(&atcphy->lock);
+
+ clear32(atcphy->regs.pipehandler + PIPEHANDLER_AON_GEN, PIPEHANDLER_AON_GEN_DWC3_RESET_N);
+ set32(atcphy->regs.pipehandler + PIPEHANDLER_AON_GEN,
+ PIPEHANDLER_AON_GEN_DWC3_FORCE_CLAMP_EN);
+}
+
+static int atcphy_dwc3_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct apple_atcphy *atcphy = container_of(rcdev, struct apple_atcphy, rcdev);
+ int ret;
+
+ guard(mutex)(&atcphy->lock);
+
+ _atcphy_dwc3_reset_assert(atcphy);
+
+ if (atcphy->pipehandler_up) {
+ ret = atcphy_configure_pipehandler_dummy(atcphy);
+ if (ret)
+ dev_warn(atcphy->dev, "Failed to switch PIPE to dummy: %d\n", ret);
+ else
+ atcphy->pipehandler_up = false;
+ }
+
+ atcphy_usb2_power_off(atcphy);
+
+ return 0;
+}
+
+static int atcphy_dwc3_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct apple_atcphy *atcphy = container_of(rcdev, struct apple_atcphy, rcdev);
+
+ guard(mutex)(&atcphy->lock);
+
+ clear32(atcphy->regs.pipehandler + PIPEHANDLER_AON_GEN,
+ PIPEHANDLER_AON_GEN_DWC3_FORCE_CLAMP_EN);
+ set32(atcphy->regs.pipehandler + PIPEHANDLER_AON_GEN, PIPEHANDLER_AON_GEN_DWC3_RESET_N);
+
+ return 0;
+}
+
+const struct reset_control_ops atcphy_dwc3_reset_ops = {
+ .assert = atcphy_dwc3_reset_assert,
+ .deassert = atcphy_dwc3_reset_deassert,
+};
+
+static int atcphy_reset_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ return 0;
+}
+
+static int atcphy_probe_rcdev(struct apple_atcphy *atcphy)
+{
+ atcphy->rcdev.owner = THIS_MODULE;
+ atcphy->rcdev.nr_resets = 1;
+ atcphy->rcdev.ops = &atcphy_dwc3_reset_ops;
+ atcphy->rcdev.of_node = atcphy->dev->of_node;
+ atcphy->rcdev.of_reset_n_cells = 0;
+ atcphy->rcdev.of_xlate = atcphy_reset_xlate;
+
+ return devm_reset_controller_register(atcphy->dev, &atcphy->rcdev);
+}
+
+static int atcphy_sw_set(struct typec_switch_dev *sw, enum typec_orientation orientation)
+{
+ struct apple_atcphy *atcphy = typec_switch_get_drvdata(sw);
+
+ guard(mutex)(&atcphy->lock);
+
+ switch (orientation) {
+ case TYPEC_ORIENTATION_NONE:
+ break;
+ case TYPEC_ORIENTATION_NORMAL:
+ atcphy->swap_lanes = false;
+ break;
+ case TYPEC_ORIENTATION_REVERSE:
+ atcphy->swap_lanes = true;
+ break;
+ }
+
+ return 0;
+}
+
+static int atcphy_probe_switch(struct apple_atcphy *atcphy)
+{
+ struct typec_switch_desc sw_desc = {
+ .drvdata = atcphy,
+ .fwnode = atcphy->dev->fwnode,
+ .set = atcphy_sw_set,
+ };
+
+ return PTR_ERR_OR_ZERO(typec_switch_register(atcphy->dev, &sw_desc));
+}
+
+static int atcphy_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
+{
+ struct apple_atcphy *atcphy = typec_mux_get_drvdata(mux);
+ enum atcphy_mode target_mode;
+
+ guard(mutex)(&atcphy->lock);
+
+ if (state->mode == TYPEC_STATE_SAFE) {
+ target_mode = APPLE_ATCPHY_MODE_OFF;
+ } else if (state->mode == TYPEC_STATE_USB) {
+ target_mode = APPLE_ATCPHY_MODE_USB3;
+ } else if (!state->alt && state->mode == TYPEC_MODE_USB4) {
+ struct enter_usb_data *data = state->data;
+ u32 eudo_usb_mode = FIELD_GET(EUDO_USB_MODE_MASK, data->eudo);
+
+ switch (eudo_usb_mode) {
+ case EUDO_USB_MODE_USB2:
+ target_mode = APPLE_ATCPHY_MODE_USB2;
+ break;
+ case EUDO_USB_MODE_USB3:
+ target_mode = APPLE_ATCPHY_MODE_USB3;
+ break;
+ case EUDO_USB_MODE_USB4:
+ target_mode = APPLE_ATCPHY_MODE_USB4;
+ break;
+ default:
+ dev_warn(atcphy->dev, "Unsupported EUDO USB mode: 0x%x.\n", eudo_usb_mode);
+ target_mode = APPLE_ATCPHY_MODE_OFF;
+ }
+ } else if (state->alt && state->alt->svid == USB_TYPEC_TBT_SID) {
+ target_mode = APPLE_ATCPHY_MODE_TBT;
+ } else if (state->alt && state->alt->svid == USB_TYPEC_DP_SID) {
+ switch (state->mode) {
+ case TYPEC_DP_STATE_C:
+ case TYPEC_DP_STATE_E:
+ target_mode = APPLE_ATCPHY_MODE_DP;
+ break;
+ case TYPEC_DP_STATE_D:
+ target_mode = APPLE_ATCPHY_MODE_USB3_DP;
+ break;
+ default:
+ dev_err(atcphy->dev,
+ "Unsupported DP pin assignment: 0x%lx, your connected device will not work.\n",
+ state->mode);
+ target_mode = APPLE_ATCPHY_MODE_OFF;
+ }
+ } else if (state->alt) {
+ dev_err(atcphy->dev,
+ "Unknown alternate mode SVID: 0x%x, your connected device will not work.\n",
+ state->alt->svid);
+ target_mode = APPLE_ATCPHY_MODE_OFF;
+ } else {
+ dev_err(atcphy->dev, "Unknown mode: 0x%lx, your connected device will not work.\n",
+ state->mode);
+ target_mode = APPLE_ATCPHY_MODE_OFF;
+ }
+
+ if (atcphy->mode == target_mode)
+ return 0;
+
+ /*
+ * If the pipehandler is still/already up here there's a bug somewhere so make sure to
+ * complain loudly. We can still try to switch modes and hope for the best though,
+ * in the worst case the hardware will fall back to USB2-only.
+ */
+ WARN_ON_ONCE(atcphy->pipehandler_up);
+ return atcphy_configure(atcphy, target_mode);
+}
+
+static int atcphy_probe_mux(struct apple_atcphy *atcphy)
+{
+ struct typec_mux_desc mux_desc = {
+ .drvdata = atcphy,
+ .fwnode = atcphy->dev->fwnode,
+ .set = atcphy_mux_set,
+ };
+
+ return PTR_ERR_OR_ZERO(typec_mux_register(atcphy->dev, &mux_desc));
+}
+
+static int atcphy_load_tunables(struct apple_atcphy *atcphy)
+{
+ struct {
+ const char *dt_name;
+ struct apple_tunable **tunable;
+ struct resource *res;
+ } tunables[] = {
+ { "apple,tunable-axi2af", &atcphy->tunables.axi2af, atcphy->res.axi2af },
+ { "apple,tunable-common-a", &atcphy->tunables.common[0], atcphy->res.core },
+ { "apple,tunable-common-b", &atcphy->tunables.common[1], atcphy->res.core },
+ { "apple,tunable-lane0-usb", &atcphy->tunables.lane_usb3[0], atcphy->res.core },
+ { "apple,tunable-lane1-usb", &atcphy->tunables.lane_usb3[1], atcphy->res.core },
+ { "apple,tunable-lane0-cio", &atcphy->tunables.lane_usb4[0], atcphy->res.core },
+ { "apple,tunable-lane1-cio", &atcphy->tunables.lane_usb4[1], atcphy->res.core },
+ { "apple,tunable-lane0-dp", &atcphy->tunables.lane_dp[0], atcphy->res.core },
+ { "apple,tunable-lane1-dp", &atcphy->tunables.lane_dp[1], atcphy->res.core },
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(tunables); i++) {
+ *tunables[i].tunable = devm_apple_tunable_parse(
+ atcphy->dev, atcphy->np, tunables[i].dt_name, tunables[i].res);
+ if (IS_ERR(*tunables[i].tunable)) {
+ dev_err(atcphy->dev, "Failed to read tunable %s: %ld\n",
+ tunables[i].dt_name, PTR_ERR(*tunables[i].tunable));
+ return PTR_ERR(*tunables[i].tunable);
+ }
+ }
+
+ return 0;
+}
+
+static int atcphy_map_resources(struct platform_device *pdev, struct apple_atcphy *atcphy)
+{
+ struct {
+ const char *name;
+ void __iomem **addr;
+ struct resource **res;
+ } resources[] = {
+ { "core", &atcphy->regs.core, &atcphy->res.core },
+ { "lpdptx", &atcphy->regs.lpdptx, NULL },
+ { "axi2af", &atcphy->regs.axi2af, &atcphy->res.axi2af },
+ { "usb2phy", &atcphy->regs.usb2phy, NULL },
+ { "pipehandler", &atcphy->regs.pipehandler, NULL },
+ };
+ struct resource *res;
+
+ for (int i = 0; i < ARRAY_SIZE(resources); i++) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, resources[i].name);
+ *resources[i].addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(resources[i].addr))
+ return dev_err_probe(atcphy->dev, PTR_ERR(resources[i].addr),
+ "Unable to map %s regs", resources[i].name);
+
+ if (resources[i].res)
+ *resources[i].res = res;
+ }
+
+ return 0;
+}
+
+static int atcphy_probe_finalize(struct apple_atcphy *atcphy)
+{
+ int ret;
+
+ guard(mutex)(&atcphy->lock);
+
+ /* Reset dwc3 on probe, let dwc3 (consumer) deassert it */
+ _atcphy_dwc3_reset_assert(atcphy);
+
+ /* Reset atcphy to clear any state potentially left by the bootloader */
+ atcphy_usb2_power_off(atcphy);
+ atcphy_power_off(atcphy);
+ atcphy_setup_pipehandler(atcphy);
+
+ ret = atcphy_probe_rcdev(atcphy);
+ if (ret)
+ return dev_err_probe(atcphy->dev, ret, "Probing rcdev failed");
+ ret = atcphy_probe_mux(atcphy);
+ if (ret)
+ return dev_err_probe(atcphy->dev, ret, "Probing mux failed");
+ ret = atcphy_probe_switch(atcphy);
+ if (ret)
+ return dev_err_probe(atcphy->dev, ret, "Probing switch failed");
+ ret = atcphy_probe_phy(atcphy);
+ if (ret)
+ return dev_err_probe(atcphy->dev, ret, "Probing phy failed");
+
+ return 0;
+}
+
+static int atcphy_probe(struct platform_device *pdev)
+{
+ struct apple_atcphy *atcphy;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ atcphy = devm_kzalloc(&pdev->dev, sizeof(*atcphy), GFP_KERNEL);
+ if (!atcphy)
+ return -ENOMEM;
+
+ atcphy->dev = dev;
+ atcphy->np = dev->of_node;
+ mutex_init(&atcphy->lock);
+ platform_set_drvdata(pdev, atcphy);
+
+ ret = atcphy_map_resources(pdev, atcphy);
+ if (ret)
+ return ret;
+ ret = atcphy_load_tunables(atcphy);
+ if (ret)
+ return ret;
+
+ atcphy->mode = APPLE_ATCPHY_MODE_OFF;
+ atcphy->pipehandler_up = false;
+
+ return atcphy_probe_finalize(atcphy);
+}
+
+static const struct of_device_id atcphy_match[] = {
+ { .compatible = "apple,t8103-atcphy" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, atcphy_match);
+
+static struct platform_driver atcphy_driver = {
+ .driver = {
+ .name = "phy-apple-atc",
+ .of_match_table = atcphy_match,
+ },
+ .probe = atcphy_probe,
+};
+module_platform_driver(atcphy_driver);
+
+MODULE_AUTHOR("Sven Peter <sven@kernel.org>");
+MODULE_DESCRIPTION("Apple Type-C PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
index 37fa4bad6bd7..d446a0f97688 100644
--- a/drivers/phy/cadence/phy-cadence-torrent.c
+++ b/drivers/phy/cadence/phy-cadence-torrent.c
@@ -300,6 +300,7 @@ enum cdns_torrent_phy_type {
TYPE_USB,
TYPE_USXGMII,
TYPE_PCIE_ML,
+ TYPE_XAUI,
};
enum cdns_torrent_ref_clk {
@@ -320,14 +321,14 @@ enum cdns_torrent_ssc_mode {
/* Unique key id for vals table entry
* REFCLK0_RATE | REFCLK1_RATE | LINK0_TYPE | LINK1_TYPE | SSC_TYPE
*/
-#define REFCLK0_SHIFT 12
-#define REFCLK0_MASK GENMASK(14, 12)
-#define REFCLK1_SHIFT 9
-#define REFCLK1_MASK GENMASK(11, 9)
-#define LINK0_SHIFT 6
-#define LINK0_MASK GENMASK(8, 6)
+#define REFCLK0_SHIFT 15
+#define REFCLK0_MASK GENMASK(18, 15)
+#define REFCLK1_SHIFT 11
+#define REFCLK1_MASK GENMASK(14, 11)
+#define LINK0_SHIFT 7
+#define LINK0_MASK GENMASK(10, 7)
#define LINK1_SHIFT 3
-#define LINK1_MASK GENMASK(5, 3)
+#define LINK1_MASK GENMASK(6, 3)
#define SSC_SHIFT 0
#define SSC_MASK GENMASK(2, 0)
@@ -397,6 +398,7 @@ struct cdns_torrent_refclk_driver {
struct clk_hw hw;
struct regmap_field *cmn_fields[REFCLK_OUT_NUM_CMN_CONFIG];
struct clk_init_data clk_data;
+ u8 parent_index;
};
#define to_cdns_torrent_refclk_driver(_hw) \
@@ -708,6 +710,8 @@ static const char *cdns_torrent_get_phy_type(enum cdns_torrent_phy_type phy_type
return "USB";
case TYPE_USXGMII:
return "USXGMII";
+ case TYPE_XAUI:
+ return "XAUI";
default:
return "None";
}
@@ -3020,6 +3024,9 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
case PHY_TYPE_USXGMII:
cdns_phy->phys[node].phy_type = TYPE_USXGMII;
break;
+ case PHY_TYPE_XAUI:
+ cdns_phy->phys[node].phy_type = TYPE_XAUI;
+ break;
default:
dev_err(dev, "Unsupported protocol\n");
ret = -EINVAL;
@@ -3326,11 +3333,29 @@ static const struct cdns_torrent_vals sgmii_qsgmii_xcvr_diag_ln_vals = {
.num_regs = ARRAY_SIZE(sgmii_qsgmii_xcvr_diag_ln_regs),
};
+static void cdns_torrent_refclk_driver_suspend(struct cdns_torrent_phy *cdns_phy)
+{
+ struct clk_hw *hw = cdns_phy->clk_hw_data->hws[CDNS_TORRENT_REFCLK_DRIVER];
+ struct cdns_torrent_refclk_driver *refclk_driver = to_cdns_torrent_refclk_driver(hw);
+
+ refclk_driver->parent_index = cdns_torrent_refclk_driver_get_parent(hw);
+}
+
+static int cdns_torrent_refclk_driver_resume(struct cdns_torrent_phy *cdns_phy)
+{
+ struct clk_hw *hw = cdns_phy->clk_hw_data->hws[CDNS_TORRENT_REFCLK_DRIVER];
+ struct cdns_torrent_refclk_driver *refclk_driver = to_cdns_torrent_refclk_driver(hw);
+
+ return cdns_torrent_refclk_driver_set_parent(hw, refclk_driver->parent_index);
+}
+
static int cdns_torrent_phy_suspend_noirq(struct device *dev)
{
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(dev);
int i;
+ cdns_torrent_refclk_driver_suspend(cdns_phy);
+
reset_control_assert(cdns_phy->phy_rst);
reset_control_assert(cdns_phy->apb_rst);
for (i = 0; i < cdns_phy->nsubnodes; i++)
@@ -3352,6 +3377,10 @@ static int cdns_torrent_phy_resume_noirq(struct device *dev)
int node = cdns_phy->nsubnodes;
int ret, i;
+ ret = cdns_torrent_refclk_driver_resume(cdns_phy);
+ if (ret)
+ return ret;
+
ret = cdns_torrent_clk(cdns_phy);
if (ret)
return ret;
@@ -3382,6 +3411,95 @@ static DEFINE_NOIRQ_DEV_PM_OPS(cdns_torrent_phy_pm_ops,
cdns_torrent_phy_suspend_noirq,
cdns_torrent_phy_resume_noirq);
+/* PCIe and XAUI link configuration */
+static const struct cdns_reg_pairs pcie_xaui_link_cmn_regs[] = {
+ {0x0003, PHY_PLL_CFG},
+ {0x0600, CMN_PDIAG_PLL1_CLK_SEL_M0}
+};
+
+static const struct cdns_reg_pairs xaui_pcie_xcvr_diag_ln_regs[] = {
+ {0x0011, XCVR_DIAG_HSCLK_SEL},
+ {0x0089, XCVR_DIAG_PLLDRC_CTRL}
+};
+
+static const struct cdns_torrent_vals pcie_xaui_link_cmn_vals = {
+ .reg_pairs = pcie_xaui_link_cmn_regs,
+ .num_regs = ARRAY_SIZE(pcie_xaui_link_cmn_regs),
+};
+
+static const struct cdns_torrent_vals xaui_pcie_xcvr_diag_ln_vals = {
+ .reg_pairs = xaui_pcie_xcvr_diag_ln_regs,
+ .num_regs = ARRAY_SIZE(xaui_pcie_xcvr_diag_ln_regs),
+};
+
+/* XAUI 100 MHz Ref clk, no SSC */
+static const struct cdns_reg_pairs xaui_100_no_ssc_cmn_regs[] = {
+ {0x0004, CMN_PLL1_DSM_DIAG_M0},
+ {0x0B17, CMN_PDIAG_PLL1_CP_PADJ_M0},
+ {0x0E01, CMN_PDIAG_PLL1_CP_IADJ_M0},
+ {0x0D05, CMN_PDIAG_PLL1_FILT_PADJ_M0},
+ {0x003E, CMN_PLL1_INTDIV_M0},
+ {0x8000, CMN_PLL1_FRACDIVL_M0},
+ {0x0002, CMN_PLL1_FRACDIVH_M0},
+ {0x002A, CMN_PLL1_HIGH_THR_M0},
+ {0x3102, CMN_PDIAG_PLL1_CTRL_M0},
+ {0x007F, CMN_TXPUCAL_TUNE},
+ {0x007F, CMN_TXPDCAL_TUNE}
+};
+
+static const struct cdns_reg_pairs xaui_100_no_ssc_tx_ln_regs[] = {
+ {0x00F3, TX_PSC_A0},
+ {0x04A2, TX_PSC_A2},
+ {0x04A2, TX_PSC_A3 },
+ {0x0000, TX_TXCC_CPOST_MULT_00}
+};
+
+static const struct cdns_reg_pairs ti_xaui_100_no_ssc_tx_ln_regs[] = {
+ {0x00F3, TX_PSC_A0},
+ {0x04A2, TX_PSC_A2},
+ {0x04A2, TX_PSC_A3 },
+ {0x0000, TX_TXCC_CPOST_MULT_00},
+ {0x4000, XCVR_DIAG_RXCLK_CTRL}
+};
+
+static const struct cdns_reg_pairs xaui_100_no_ssc_rx_ln_regs[] = {
+ {0x091D, RX_PSC_A0},
+ {0x0900, RX_PSC_A2},
+ {0x0100, RX_PSC_A3},
+ {0x03C7, RX_REE_GCSM1_EQENM_PH1},
+ {0x01C7, RX_REE_GCSM1_EQENM_PH2},
+ {0x0000, RX_DIAG_DFE_CTRL},
+ {0x0019, RX_REE_TAP1_CLIP},
+ {0x0019, RX_REE_TAP2TON_CLIP},
+ {0x0098, RX_DIAG_NQST_CTRL},
+ {0x0C01, RX_DIAG_DFE_AMP_TUNE_2},
+ {0x0000, RX_DIAG_DFE_AMP_TUNE_3},
+ {0x0000, RX_DIAG_PI_CAP},
+ {0x0031, RX_DIAG_PI_RATE},
+ {0x0001, RX_DIAG_ACYA},
+ {0x018C, RX_CDRLF_CNFG},
+};
+
+static const struct cdns_torrent_vals xaui_100_no_ssc_cmn_vals = {
+ .reg_pairs = xaui_100_no_ssc_cmn_regs,
+ .num_regs = ARRAY_SIZE(xaui_100_no_ssc_cmn_regs),
+};
+
+static const struct cdns_torrent_vals xaui_100_no_ssc_tx_ln_vals = {
+ .reg_pairs = xaui_100_no_ssc_tx_ln_regs,
+ .num_regs = ARRAY_SIZE(xaui_100_no_ssc_tx_ln_regs),
+};
+
+static const struct cdns_torrent_vals ti_xaui_100_no_ssc_tx_ln_vals = {
+ .reg_pairs = ti_xaui_100_no_ssc_tx_ln_regs,
+ .num_regs = ARRAY_SIZE(ti_xaui_100_no_ssc_tx_ln_regs),
+};
+
+static const struct cdns_torrent_vals xaui_100_no_ssc_rx_ln_vals = {
+ .reg_pairs = xaui_100_no_ssc_rx_ln_regs,
+ .num_regs = ARRAY_SIZE(xaui_100_no_ssc_rx_ln_regs),
+};
+
/* USB and DP link configuration */
static const struct cdns_reg_pairs usb_dp_link_cmn_regs[] = {
{0x0002, PHY_PLL_CFG},
@@ -4853,6 +4971,7 @@ static const struct cdns_torrent_vals_entry link_cmn_vals_entries[] = {
{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USB), &pcie_usb_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_DP), &pcie_dp_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USXGMII), &pcie_usxgmii_link_cmn_vals},
+ {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_XAUI), &pcie_xaui_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE_ML, TYPE_USB), &ml_pcie_usb_link_cmn_vals},
@@ -4879,6 +4998,8 @@ static const struct cdns_torrent_vals_entry link_cmn_vals_entries[] = {
{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &pcie_usxgmii_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &usxgmii_sgmii_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &usxgmii_sgmii_link_cmn_vals},
+
+ {CDNS_TORRENT_KEY_ANYCLK(TYPE_XAUI, TYPE_PCIE), &pcie_xaui_link_cmn_vals},
};
static const struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = {
@@ -4893,6 +5014,7 @@ static const struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = {
{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USB), &pcie_usb_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_DP), &pcie_dp_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USXGMII), &pcie_usxgmii_xcvr_diag_ln_vals},
+ {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_XAUI), NULL},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE_ML, TYPE_USB), &ml_pcie_usb_xcvr_diag_ln_vals},
@@ -4919,6 +5041,8 @@ static const struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = {
{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &usxgmii_pcie_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &usxgmii_sgmii_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &usxgmii_sgmii_xcvr_diag_ln_vals},
+
+ {CDNS_TORRENT_KEY_ANYCLK(TYPE_XAUI, TYPE_PCIE), &xaui_pcie_xcvr_diag_ln_vals},
};
static const struct cdns_torrent_vals_entry pcs_cmn_vals_entries[] = {
@@ -4960,6 +5084,8 @@ static const struct cdns_torrent_vals_entry cmn_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), NULL},
+
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &ml_pcie_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &ml_pcie_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &ml_pcie_100_int_ssc_cmn_vals},
@@ -5010,6 +5136,8 @@ static const struct cdns_torrent_vals_entry cmn_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_cmn_vals},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &xaui_100_no_ssc_cmn_vals},
+
{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &sl_usxgmii_156_25_no_ssc_cmn_vals},
/* Dual refclk */
@@ -5054,6 +5182,8 @@ static const struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), NULL},
+
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), NULL},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), NULL},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), NULL},
@@ -5104,6 +5234,8 @@ static const struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &xaui_100_no_ssc_tx_ln_vals},
+
{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals},
/* Dual refclk */
@@ -5148,6 +5280,8 @@ static const struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), &pcie_100_no_ssc_rx_ln_vals},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), &ml_pcie_100_no_ssc_rx_ln_vals},
+
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &ml_pcie_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &ml_pcie_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &ml_pcie_100_no_ssc_rx_ln_vals},
@@ -5198,6 +5332,8 @@ static const struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_rx_ln_vals},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &xaui_100_no_ssc_rx_ln_vals},
+
{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals},
/* Dual refclk */
@@ -5278,6 +5414,8 @@ static const struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), NULL},
+
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), NULL},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), NULL},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), NULL},
@@ -5328,6 +5466,8 @@ static const struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &ti_xaui_100_no_ssc_tx_ln_vals},
+
{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals},
/* Dual refclk */
@@ -5406,6 +5546,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_cmn_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), NULL},
+
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &ml_pcie_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &ml_pcie_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &ml_pcie_100_int_ssc_cmn_vals},
@@ -5456,6 +5598,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_cmn_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_cmn_vals},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &xaui_100_no_ssc_cmn_vals},
+
{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &sl_usxgmii_156_25_no_ssc_cmn_vals},
/* Dual refclk */
@@ -5500,6 +5644,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), NULL},
+
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), NULL},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), NULL},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), NULL},
@@ -5550,6 +5696,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &ti_xaui_100_no_ssc_tx_ln_vals},
+
{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals},
/* Dual refclk */
@@ -5594,6 +5742,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_rx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), &pcie_100_no_ssc_rx_ln_vals},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_XAUI, NO_SSC), &pcie_100_no_ssc_rx_ln_vals},
+
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, NO_SSC), &pcie_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE_ML, TYPE_USB, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals},
@@ -5644,6 +5794,8 @@ static const struct cdns_torrent_vals_entry ti_j7200_rx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_rx_ln_vals},
+ {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_XAUI, TYPE_PCIE, NO_SSC), &xaui_100_no_ssc_rx_ln_vals},
+
{CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals},
/* Dual refclk */
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index 91b3e62743d3..b05d80e849a1 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -17,6 +17,10 @@
#define PHY_CTRL0_FSEL_MASK GENMASK(10, 5)
#define PHY_CTRL0_FSEL_24M 0x2a
#define PHY_CTRL0_FSEL_100M 0x27
+#define PHY_CTRL0_SSC_RANGE_MASK GENMASK(23, 21)
+#define PHY_CTRL0_SSC_RANGE_4003PPM 0x2
+#define PHY_CTRL0_SSC_RANGE_4492PPM 0x1
+#define PHY_CTRL0_SSC_RANGE_4980PPM 0x0
#define PHY_CTRL1 0x4
#define PHY_CTRL1_RESET BIT(0)
@@ -47,6 +51,7 @@
#define PHY_CTRL5_PCS_TX_SWING_FULL_MASK GENMASK(6, 0)
#define PHY_CTRL6 0x18
+#define PHY_CTRL6_RXTERM_OVERRIDE_SEL BIT(29)
#define PHY_CTRL6_ALT_CLK_EN BIT(1)
#define PHY_CTRL6_ALT_CLK_SEL BIT(0)
@@ -587,6 +592,9 @@ static int imx8mp_usb_phy_init(struct phy *phy)
value = readl(imx_phy->base + PHY_CTRL0);
value |= PHY_CTRL0_REF_SSP_EN;
+ value &= ~PHY_CTRL0_SSC_RANGE_MASK;
+ value |= FIELD_PREP(PHY_CTRL0_SSC_RANGE_MASK,
+ PHY_CTRL0_SSC_RANGE_4003PPM);
writel(value, imx_phy->base + PHY_CTRL0);
value = readl(imx_phy->base + PHY_CTRL2);
@@ -610,6 +618,7 @@ static int imx8mp_usb_phy_init(struct phy *phy)
static int imx8mq_phy_power_on(struct phy *phy)
{
struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
+ u32 value;
int ret;
ret = regulator_enable(imx_phy->vbus);
@@ -626,12 +635,23 @@ static int imx8mq_phy_power_on(struct phy *phy)
return ret;
}
- return ret;
+ /* Disable rx term override */
+ value = readl(imx_phy->base + PHY_CTRL6);
+ value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
+ writel(value, imx_phy->base + PHY_CTRL6);
+
+ return 0;
}
static int imx8mq_phy_power_off(struct phy *phy)
{
struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
+ u32 value;
+
+ /* Override rx term to be 0 */
+ value = readl(imx_phy->base + PHY_CTRL6);
+ value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
+ writel(value, imx_phy->base + PHY_CTRL6);
clk_disable_unprepare(imx_phy->alt_clk);
clk_disable_unprepare(imx_phy->clk);
@@ -676,6 +696,8 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
if (!imx_phy)
return -ENOMEM;
+ platform_set_drvdata(pdev, imx_phy);
+
imx_phy->clk = devm_clk_get(dev, "phy");
if (IS_ERR(imx_phy->clk)) {
dev_err(dev, "failed to get imx8mq usb phy clock\n");
@@ -730,6 +752,7 @@ static struct platform_driver imx8mq_usb_phy_driver = {
.driver = {
.name = "imx8mq-usb-phy",
.of_match_table = imx8mq_usb_phy_of_match,
+ .suppress_bind_attrs = true,
}
};
module_platform_driver(imx8mq_usb_phy_driver);
diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c
index 977d21d753a5..279b8ac7822d 100644
--- a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c
+++ b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c
@@ -251,7 +251,7 @@ static void imx_hsio_configure_clk_pad(struct phy *phy)
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
- if (strncmp(priv->refclk_pad, "output", 6) == 0) {
+ if (priv->refclk_pad && strncmp(priv->refclk_pad, "output", 6) == 0) {
pll = true;
regmap_update_bits(priv->misc, HSIO_CTRL0,
HSIO_IOB_A_0_TXOE | HSIO_IOB_A_0_M1M0_MASK,
diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
index 7aef2f59e8eb..ece357443521 100644
--- a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
+++ b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
@@ -286,11 +286,9 @@ static int mixel_lvds_phy_reset(struct device *dev)
regmap_write(priv->regmap, PHY_CTRL, CTRL_RESET_VAL);
- ret = pm_runtime_put(dev);
- if (ret < 0)
- dev_err(dev, "failed to put PM runtime: %d\n", ret);
+ pm_runtime_put(dev);
- return ret;
+ return 0;
}
static struct phy *mixel_lvds_phy_xlate(struct device *dev,
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index c20d2636c5e9..2b0fd95ba62f 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021-2022 NXP. */
+#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy.h>
@@ -11,100 +12,408 @@
#define LYNX_28G_NUM_LANE 8
#define LYNX_28G_NUM_PLL 2
-/* General registers per SerDes block */
-#define LYNX_28G_PCC8 0x10a0
-#define LYNX_28G_PCC8_SGMII 0x1
-#define LYNX_28G_PCC8_SGMII_DIS 0x0
-
-#define LYNX_28G_PCCC 0x10b0
-#define LYNX_28G_PCCC_10GBASER 0x9
-#define LYNX_28G_PCCC_USXGMII 0x1
-#define LYNX_28G_PCCC_SXGMII_DIS 0x0
-
-#define LYNX_28G_LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))
+/* SoC IP wrapper for protocol converters */
+#define PCC8 0x10a0
+#define PCC8_SGMIIa_KX BIT(3)
+#define PCC8_SGMIIa_CFG BIT(0)
+
+#define PCCC 0x10b0
+#define PCCC_SXGMIIn_XFI BIT(3)
+#define PCCC_SXGMIIn_CFG BIT(0)
+
+#define PCCD 0x10b4
+#define PCCD_E25Gn_CFG BIT(0)
+
+#define PCCE 0x10b8
+#define PCCE_E40Gn_LRV BIT(3)
+#define PCCE_E40Gn_CFG BIT(0)
+#define PCCE_E50Gn_LRV BIT(3)
+#define PCCE_E50GnCFG BIT(0)
+#define PCCE_E100Gn_LRV BIT(3)
+#define PCCE_E100Gn_CFG BIT(0)
+
+#define SGMII_CFG(id) (28 - (id) * 4) /* Offset into PCC8 */
+#define SXGMII_CFG(id) (28 - (id) * 4) /* Offset into PCCC */
+#define E25G_CFG(id) (28 - (id) * 4) /* Offset into PCCD */
+#define E40G_CFG(id) (28 - (id) * 4) /* Offset into PCCE */
+#define E50G_CFG(id) (20 - (id) * 4) /* Offset into PCCE */
+#define E100G_CFG(id) (12 - (id) * 4) /* Offset into PCCE */
/* Per PLL registers */
-#define LYNX_28G_PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
-#define LYNX_28G_PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24)
-#define LYNX_28G_PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)
-
-#define LYNX_28G_PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)
-#define LYNX_28G_PLLnCR0_REFCLK_SEL(cr0) (((cr0) & GENMASK(20, 16)))
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_100MHZ 0x0
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_125MHZ 0x10000
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_156MHZ 0x20000
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_150MHZ 0x30000
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_161MHZ 0x40000
-
-#define LYNX_28G_PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8)
-#define LYNX_28G_PLLnCR1_FRATE_SEL(cr1) (((cr1) & GENMASK(28, 24)))
-#define LYNX_28G_PLLnCR1_FRATE_5G_10GVCO 0x0
-#define LYNX_28G_PLLnCR1_FRATE_5G_25GVCO 0x10000000
-#define LYNX_28G_PLLnCR1_FRATE_10G_20GVCO 0x6000000
+#define PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
+#define PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24)
+#define PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)
+
+#define PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)
+#define PLLnCR0_REFCLK_SEL GENMASK(20, 16)
+#define PLLnCR0_REFCLK_SEL_100MHZ 0x0
+#define PLLnCR0_REFCLK_SEL_125MHZ 0x1
+#define PLLnCR0_REFCLK_SEL_156MHZ 0x2
+#define PLLnCR0_REFCLK_SEL_150MHZ 0x3
+#define PLLnCR0_REFCLK_SEL_161MHZ 0x4
+
+#define PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8)
+#define PLLnCR1_FRATE_SEL GENMASK(28, 24)
+#define PLLnCR1_FRATE_5G_10GVCO 0x0
+#define PLLnCR1_FRATE_5G_25GVCO 0x10
+#define PLLnCR1_FRATE_10G_20GVCO 0x6
/* Per SerDes lane registers */
/* Lane a General Control Register */
-#define LYNX_28G_LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0)
-#define LYNX_28G_LNaGCR0_PROTO_SEL_MSK GENMASK(7, 3)
-#define LYNX_28G_LNaGCR0_PROTO_SEL_SGMII 0x8
-#define LYNX_28G_LNaGCR0_PROTO_SEL_XFI 0x50
-#define LYNX_28G_LNaGCR0_IF_WIDTH_MSK GENMASK(2, 0)
-#define LYNX_28G_LNaGCR0_IF_WIDTH_10_BIT 0x0
-#define LYNX_28G_LNaGCR0_IF_WIDTH_20_BIT 0x2
+#define LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0)
+#define LNaGCR0_PROTO_SEL GENMASK(7, 3)
+#define LNaGCR0_PROTO_SEL_SGMII 0x1
+#define LNaGCR0_PROTO_SEL_XFI 0xa
+#define LNaGCR0_IF_WIDTH GENMASK(2, 0)
+#define LNaGCR0_IF_WIDTH_10_BIT 0x0
+#define LNaGCR0_IF_WIDTH_20_BIT 0x2
/* Lane a Tx Reset Control Register */
-#define LYNX_28G_LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
-#define LYNX_28G_LNaTRSTCTL_HLT_REQ BIT(27)
-#define LYNX_28G_LNaTRSTCTL_RST_DONE BIT(30)
-#define LYNX_28G_LNaTRSTCTL_RST_REQ BIT(31)
+#define LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
+#define LNaTRSTCTL_HLT_REQ BIT(27)
+#define LNaTRSTCTL_RST_DONE BIT(30)
+#define LNaTRSTCTL_RST_REQ BIT(31)
/* Lane a Tx General Control Register */
-#define LYNX_28G_LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)
-#define LYNX_28G_LNaTGCR0_USE_PLLF 0x0
-#define LYNX_28G_LNaTGCR0_USE_PLLS BIT(28)
-#define LYNX_28G_LNaTGCR0_USE_PLL_MSK BIT(28)
-#define LYNX_28G_LNaTGCR0_N_RATE_FULL 0x0
-#define LYNX_28G_LNaTGCR0_N_RATE_HALF 0x1000000
-#define LYNX_28G_LNaTGCR0_N_RATE_QUARTER 0x2000000
-#define LYNX_28G_LNaTGCR0_N_RATE_MSK GENMASK(26, 24)
-
-#define LYNX_28G_LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
+#define LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)
+#define LNaTGCR0_USE_PLL BIT(28)
+#define LNaTGCR0_USE_PLLF 0x0
+#define LNaTGCR0_USE_PLLS 0x1
+#define LNaTGCR0_N_RATE GENMASK(26, 24)
+#define LNaTGCR0_N_RATE_FULL 0x0
+#define LNaTGCR0_N_RATE_HALF 0x1
+#define LNaTGCR0_N_RATE_QUARTER 0x2
+
+#define LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
+#define LNaTECR0_EQ_TYPE GENMASK(30, 28)
+#define LNaTECR0_EQ_SGN_PREQ BIT(23)
+#define LNaTECR0_EQ_PREQ GENMASK(19, 16)
+#define LNaTECR0_EQ_SGN_POST1Q BIT(15)
+#define LNaTECR0_EQ_POST1Q GENMASK(12, 8)
+#define LNaTECR0_EQ_AMP_RED GENMASK(5, 0)
+
+#define LNaTECR1(lane) (0x800 + (lane) * 0x100 + 0x34)
+#define LNaTECR1_EQ_ADPT_EQ_DRVR_DIS BIT(31)
+#define LNaTECR1_EQ_ADPT_EQ GENMASK(29, 24)
/* Lane a Rx Reset Control Register */
-#define LYNX_28G_LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
-#define LYNX_28G_LNaRRSTCTL_HLT_REQ BIT(27)
-#define LYNX_28G_LNaRRSTCTL_RST_DONE BIT(30)
-#define LYNX_28G_LNaRRSTCTL_RST_REQ BIT(31)
-#define LYNX_28G_LNaRRSTCTL_CDR_LOCK BIT(12)
+#define LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
+#define LNaRRSTCTL_HLT_REQ BIT(27)
+#define LNaRRSTCTL_RST_DONE BIT(30)
+#define LNaRRSTCTL_RST_REQ BIT(31)
+#define LNaRRSTCTL_CDR_LOCK BIT(12)
/* Lane a Rx General Control Register */
-#define LYNX_28G_LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44)
-#define LYNX_28G_LNaRGCR0_USE_PLLF 0x0
-#define LYNX_28G_LNaRGCR0_USE_PLLS BIT(28)
-#define LYNX_28G_LNaRGCR0_USE_PLL_MSK BIT(28)
-#define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
-#define LYNX_28G_LNaRGCR0_N_RATE_FULL 0x0
-#define LYNX_28G_LNaRGCR0_N_RATE_HALF 0x1000000
-#define LYNX_28G_LNaRGCR0_N_RATE_QUARTER 0x2000000
-#define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
-
-#define LYNX_28G_LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
-
-#define LYNX_28G_LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50)
-#define LYNX_28G_LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54)
-#define LYNX_28G_LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58)
-
-#define LYNX_28G_LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
-
-#define LYNX_28G_LNaPSS(lane) (0x1000 + (lane) * 0x4)
-#define LYNX_28G_LNaPSS_TYPE(pss) (((pss) & GENMASK(30, 24)) >> 24)
-#define LYNX_28G_LNaPSS_TYPE_SGMII 0x4
-#define LYNX_28G_LNaPSS_TYPE_XFI 0x28
-
-#define LYNX_28G_SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
-#define LYNX_28G_SGMIIaCR1_SGPCS_EN BIT(11)
-#define LYNX_28G_SGMIIaCR1_SGPCS_DIS 0x0
-#define LYNX_28G_SGMIIaCR1_SGPCS_MSK BIT(11)
+#define LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44)
+#define LNaRGCR0_USE_PLL BIT(28)
+#define LNaRGCR0_USE_PLLF 0x0
+#define LNaRGCR0_USE_PLLS 0x1
+#define LNaRGCR0_N_RATE GENMASK(26, 24)
+#define LNaRGCR0_N_RATE_FULL 0x0
+#define LNaRGCR0_N_RATE_HALF 0x1
+#define LNaRGCR0_N_RATE_QUARTER 0x2
+
+#define LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
+#define LNaRGCR1_RX_ORD_ELECIDLE BIT(31)
+#define LNaRGCR1_DATA_LOST_FLT BIT(30)
+#define LNaRGCR1_DATA_LOST BIT(29)
+#define LNaRGCR1_IDLE_CONFIG BIT(28)
+#define LNaRGCR1_ENTER_IDLE_FLT_SEL GENMASK(26, 24)
+#define LNaRGCR1_EXIT_IDLE_FLT_SEL GENMASK(22, 20)
+#define LNaRGCR1_DATA_LOST_TH_SEL GENMASK(18, 16)
+#define LNaRGCR1_EXT_REC_CLK_SEL GENMASK(10, 8)
+#define LNaRGCR1_WAKE_TX_DIS BIT(5)
+#define LNaRGCR1_PHY_RDY BIT(4)
+#define LNaRGCR1_CHANGE_RX_CLK BIT(3)
+#define LNaRGCR1_PWR_MGT GENMASK(2, 0)
+
+#define LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50)
+#define LNaRECR0_EQ_GAINK2_HF_OV_EN BIT(31)
+#define LNaRECR0_EQ_GAINK2_HF_OV GENMASK(28, 24)
+#define LNaRECR0_EQ_GAINK3_MF_OV_EN BIT(23)
+#define LNaRECR0_EQ_GAINK3_MF_OV GENMASK(20, 16)
+#define LNaRECR0_EQ_GAINK4_LF_OV_EN BIT(7)
+#define LNaRECR0_EQ_GAINK4_LF_DIS BIT(6)
+#define LNaRECR0_EQ_GAINK4_LF_OV GENMASK(4, 0)
+
+#define LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54)
+#define LNaRECR1_EQ_BLW_OV_EN BIT(31)
+#define LNaRECR1_EQ_BLW_OV GENMASK(28, 24)
+#define LNaRECR1_EQ_OFFSET_OV_EN BIT(23)
+#define LNaRECR1_EQ_OFFSET_OV GENMASK(21, 16)
+
+#define LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58)
+#define LNaRECR2_EQ_OFFSET_RNG_DBL BIT(31)
+#define LNaRECR2_EQ_BOOST GENMASK(29, 28)
+#define LNaRECR2_EQ_BLW_SEL GENMASK(25, 24)
+#define LNaRECR2_EQ_ZERO GENMASK(17, 16)
+#define LNaRECR2_EQ_IND GENMASK(13, 12)
+#define LNaRECR2_EQ_BIN_DATA_AVG_TC GENMASK(5, 4)
+#define LNaRECR2_SPARE_IN GENMASK(1, 0)
+
+#define LNaRECR3(lane) (0x800 + (lane) * 0x100 + 0x5c)
+#define LNaRECR3_EQ_SNAP_START BIT(31)
+#define LNaRECR3_EQ_SNAP_DONE BIT(30)
+#define LNaRECR3_EQ_GAINK2_HF_STAT GENMASK(28, 24)
+#define LNaRECR3_EQ_GAINK3_MF_STAT GENMASK(20, 16)
+#define LNaRECR3_SPARE_OUT GENMASK(13, 12)
+#define LNaRECR3_EQ_GAINK4_LF_STAT GENMASK(4, 0)
+
+#define LNaRECR4(lane) (0x800 + (lane) * 0x100 + 0x60)
+#define LNaRECR4_BLW_STAT GENMASK(28, 24)
+#define LNaRECR4_EQ_OFFSET_STAT GENMASK(21, 16)
+#define LNaRECR4_EQ_BIN_DATA_SEL GENMASK(15, 12)
+#define LNaRECR4_EQ_BIN_DATA GENMASK(8, 0) /* bit 9 is reserved */
+#define LNaRECR4_EQ_BIN_DATA_SGN BIT(8)
+
+#define LNaRCCR0(lane) (0x800 + (lane) * 0x100 + 0x68)
+#define LNaRCCR0_CAL_EN BIT(31)
+#define LNaRCCR0_MEAS_EN BIT(30)
+#define LNaRCCR0_CAL_BIN_SEL BIT(28)
+#define LNaRCCR0_CAL_DC3_DIS BIT(27)
+#define LNaRCCR0_CAL_DC2_DIS BIT(26)
+#define LNaRCCR0_CAL_DC1_DIS BIT(25)
+#define LNaRCCR0_CAL_DC0_DIS BIT(24)
+#define LNaRCCR0_CAL_AC3_OV_EN BIT(15)
+#define LNaRCCR0_CAL_AC3_OV GENMASK(11, 8)
+#define LNaRCCR0_CAL_AC2_OV_EN BIT(7)
+
+#define LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
+#define LNaRSCCR0_SMP_OFF_EN BIT(31)
+#define LNaRSCCR0_SMP_OFF_OV_EN BIT(30)
+#define LNaRSCCR0_SMP_MAN_OFF_EN BIT(29)
+#define LNaRSCCR0_SMP_OFF_RNG_OV_EN BIT(27)
+#define LNaRSCCR0_SMP_OFF_RNG_4X_OV BIT(25)
+#define LNaRSCCR0_SMP_OFF_RNG_2X_OV BIT(24)
+#define LNaRSCCR0_SMP_AUTOZ_PD BIT(23)
+#define LNaRSCCR0_SMP_AUTOZ_CTRL GENMASK(19, 16)
+#define LNaRSCCR0_SMP_AUTOZ_D1R GENMASK(13, 12)
+#define LNaRSCCR0_SMP_AUTOZ_D1F GENMASK(9, 8)
+#define LNaRSCCR0_SMP_AUTOZ_EG1R GENMASK(5, 4)
+#define LNaRSCCR0_SMP_AUTOZ_EG1F GENMASK(1, 0)
+
+#define LNaTTLCR0(lane) (0x800 + (lane) * 0x100 + 0x80)
+#define LNaTTLCR0_TTL_FLT_SEL GENMASK(29, 24)
+#define LNaTTLCR0_TTL_SLO_PM_BYP BIT(22)
+#define LNaTTLCR0_STALL_DET_DIS BIT(21)
+#define LNaTTLCR0_INACT_MON_DIS BIT(20)
+#define LNaTTLCR0_CDR_OV GENMASK(18, 16)
+#define LNaTTLCR0_DATA_IN_SSC BIT(15)
+#define LNaTTLCR0_CDR_MIN_SMP_ON GENMASK(1, 0)
+
+#define LNaTCSR0(lane) (0x800 + (lane) * 0x100 + 0xa0)
+#define LNaTCSR0_SD_STAT_OBS_EN BIT(31)
+#define LNaTCSR0_SD_LPBK_SEL GENMASK(29, 28)
+
+#define LNaPSS(lane) (0x1000 + (lane) * 0x4)
+#define LNaPSS_TYPE GENMASK(30, 24)
+#define LNaPSS_TYPE_SGMII (PROTO_SEL_SGMII_BASEX_KX << 2)
+#define LNaPSS_TYPE_XFI (PROTO_SEL_XFI_10GBASER_KR_SXGMII << 2)
+#define LNaPSS_TYPE_40G ((PROTO_SEL_XFI_10GBASER_KR_SXGMII << 2) | 3)
+#define LNaPSS_TYPE_25G (PROTO_SEL_25G_50G_100G << 2)
+#define LNaPSS_TYPE_100G ((PROTO_SEL_25G_50G_100G << 2) | 2)
+
+/* MDEV_PORT is at the same bitfield address for all protocol converters */
+#define MDEV_PORT GENMASK(31, 27)
+
+#define SGMIIaCR0(lane) (0x1800 + (lane) * 0x10)
+#define SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
+#define SGMIIaCR1_SGPCS_EN BIT(11)
+
+#define ANLTaCR0(lane) (0x1a00 + (lane) * 0x10)
+#define ANLTaCR1(lane) (0x1a04 + (lane) * 0x10)
+
+#define SXGMIIaCR0(lane) (0x1a80 + (lane) * 0x10)
+#define SXGMIIaCR0_RST BIT(31)
+#define SXGMIIaCR0_PD BIT(30)
+
+#define SXGMIIaCR1(lane) (0x1a84 + (lane) * 0x10)
+
+#define E25GaCR0(lane) (0x1b00 + (lane) * 0x10)
+#define E25GaCR0_RST BIT(31)
+#define E25GaCR0_PD BIT(30)
+
+#define E25GaCR1(lane) (0x1b04 + (lane) * 0x10)
+
+#define E25GaCR2(lane) (0x1b08 + (lane) * 0x10)
+#define E25GaCR2_FEC_ENA BIT(23)
+#define E25GaCR2_FEC_ERR_ENA BIT(22)
+#define E25GaCR2_FEC91_ENA BIT(20)
+
+#define E40GaCR0(pcvt) (0x1b40 + (pcvt) * 0x20)
+#define E40GaCR1(pcvt) (0x1b44 + (pcvt) * 0x20)
+
+#define E50GaCR1(pcvt) (0x1b84 + (pcvt) * 0x10)
+
+#define E100GaCR1(pcvt) (0x1c04 + (pcvt) * 0x20)
+
+#define CR(x) ((x) * 4)
+
+enum lynx_28g_eq_type {
+ EQ_TYPE_NO_EQ = 0,
+ EQ_TYPE_2TAP = 1,
+ EQ_TYPE_3TAP = 2,
+};
+
+enum lynx_28g_proto_sel {
+ PROTO_SEL_PCIE = 0,
+ PROTO_SEL_SGMII_BASEX_KX = 1,
+ PROTO_SEL_SATA = 2,
+ PROTO_SEL_XAUI = 4,
+ PROTO_SEL_XFI_10GBASER_KR_SXGMII = 0xa,
+ PROTO_SEL_25G_50G_100G = 0x1a,
+};
+
+enum lynx_lane_mode {
+ LANE_MODE_UNKNOWN,
+ LANE_MODE_1000BASEX_SGMII,
+ LANE_MODE_10GBASER,
+ LANE_MODE_USXGMII,
+ LANE_MODE_MAX,
+};
+
+struct lynx_28g_proto_conf {
+ /* LNaGCR0 */
+ int proto_sel;
+ int if_width;
+ /* LNaTECR0 */
+ int teq_type;
+ int sgn_preq;
+ int ratio_preq;
+ int sgn_post1q;
+ int ratio_post1q;
+ int amp_red;
+ /* LNaTECR1 */
+ int adpt_eq;
+ /* LNaRGCR1 */
+ int enter_idle_flt_sel;
+ int exit_idle_flt_sel;
+ int data_lost_th_sel;
+ /* LNaRECR0 */
+ int gk2ovd;
+ int gk3ovd;
+ int gk4ovd;
+ int gk2ovd_en;
+ int gk3ovd_en;
+ int gk4ovd_en;
+ /* LNaRECR1 ? */
+ int eq_offset_ovd;
+ int eq_offset_ovd_en;
+ /* LNaRECR2 */
+ int eq_offset_rng_dbl;
+ int eq_blw_sel;
+ int eq_boost;
+ int spare_in;
+ /* LNaRSCCR0 */
+ int smp_autoz_d1r;
+ int smp_autoz_eg1r;
+ /* LNaRCCR0 */
+ int rccr0;
+ /* LNaTTLCR0 */
+ int ttlcr0;
+};
+
+static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
+ [LANE_MODE_1000BASEX_SGMII] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_SGMII,
+ .if_width = LNaGCR0_IF_WIDTH_10_BIT,
+ .teq_type = EQ_TYPE_NO_EQ,
+ .sgn_preq = 1,
+ .ratio_preq = 0,
+ .sgn_post1q = 1,
+ .ratio_post1q = 0,
+ .amp_red = 6,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 4,
+ .exit_idle_flt_sel = 3,
+ .data_lost_th_sel = 1,
+ .gk2ovd = 0x1f,
+ .gk3ovd = 0,
+ .gk4ovd = 0,
+ .gk2ovd_en = 1,
+ .gk3ovd_en = 1,
+ .gk4ovd_en = 0,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 0,
+ .eq_blw_sel = 0,
+ .eq_boost = 0,
+ .spare_in = 0,
+ .smp_autoz_d1r = 0,
+ .smp_autoz_eg1r = 0,
+ .rccr0 = LNaRCCR0_CAL_EN,
+ .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP |
+ LNaTTLCR0_DATA_IN_SSC,
+ },
+ [LANE_MODE_USXGMII] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_XFI,
+ .if_width = LNaGCR0_IF_WIDTH_20_BIT,
+ .teq_type = EQ_TYPE_2TAP,
+ .sgn_preq = 1,
+ .ratio_preq = 0,
+ .sgn_post1q = 1,
+ .ratio_post1q = 3,
+ .amp_red = 7,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 0,
+ .exit_idle_flt_sel = 0,
+ .data_lost_th_sel = 0,
+ .gk2ovd = 0,
+ .gk3ovd = 0,
+ .gk4ovd = 0,
+ .gk2ovd_en = 0,
+ .gk3ovd_en = 0,
+ .gk4ovd_en = 0,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 1,
+ .eq_blw_sel = 1,
+ .eq_boost = 0,
+ .spare_in = 0,
+ .smp_autoz_d1r = 2,
+ .smp_autoz_eg1r = 0,
+ .rccr0 = LNaRCCR0_CAL_EN,
+ .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP |
+ LNaTTLCR0_DATA_IN_SSC,
+ },
+ [LANE_MODE_10GBASER] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_XFI,
+ .if_width = LNaGCR0_IF_WIDTH_20_BIT,
+ .teq_type = EQ_TYPE_2TAP,
+ .sgn_preq = 1,
+ .ratio_preq = 0,
+ .sgn_post1q = 1,
+ .ratio_post1q = 3,
+ .amp_red = 7,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 0,
+ .exit_idle_flt_sel = 0,
+ .data_lost_th_sel = 0,
+ .gk2ovd = 0,
+ .gk3ovd = 0,
+ .gk4ovd = 0,
+ .gk2ovd_en = 0,
+ .gk3ovd_en = 0,
+ .gk4ovd_en = 0,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 1,
+ .eq_blw_sel = 1,
+ .eq_boost = 0,
+ .spare_in = 0,
+ .smp_autoz_d1r = 2,
+ .smp_autoz_eg1r = 0,
+ .rccr0 = LNaRCCR0_CAL_EN,
+ .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP |
+ LNaTTLCR0_DATA_IN_SSC,
+ },
+};
+
+struct lynx_pccr {
+ int offset;
+ int width;
+ int shift;
+};
struct lynx_28g_priv;
@@ -112,7 +421,7 @@ struct lynx_28g_pll {
struct lynx_28g_priv *priv;
u32 rstctl, cr0, cr1;
int id;
- DECLARE_PHY_INTERFACE_MASK(supported);
+ DECLARE_BITMAP(supported, LANE_MODE_MAX);
};
struct lynx_28g_lane {
@@ -121,7 +430,7 @@ struct lynx_28g_lane {
bool powered_up;
bool init;
unsigned int id;
- phy_interface_t interface;
+ enum lynx_lane_mode mode;
};
struct lynx_28g_priv {
@@ -149,23 +458,58 @@ static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
iowrite32(tmp, reg);
}
+#define lynx_28g_read(priv, off) \
+ ioread32((priv)->base + (off))
+#define lynx_28g_write(priv, off, val) \
+ iowrite32(val, (priv)->base + (off))
#define lynx_28g_lane_rmw(lane, reg, val, mask) \
- lynx_28g_rmw((lane)->priv, LYNX_28G_##reg(lane->id), \
- LYNX_28G_##reg##_##val, LYNX_28G_##reg##_##mask)
+ lynx_28g_rmw((lane)->priv, reg(lane->id), val, mask)
#define lynx_28g_lane_read(lane, reg) \
- ioread32((lane)->priv->base + LYNX_28G_##reg((lane)->id))
+ ioread32((lane)->priv->base + reg((lane)->id))
+#define lynx_28g_lane_write(lane, reg, val) \
+ iowrite32(val, (lane)->priv->base + reg((lane)->id))
#define lynx_28g_pll_read(pll, reg) \
- ioread32((pll)->priv->base + LYNX_28G_##reg((pll)->id))
+ ioread32((pll)->priv->base + reg((pll)->id))
-static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
+static const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ return "1000Base-X/SGMII";
+ case LANE_MODE_10GBASER:
+ return "10GBase-R";
+ case LANE_MODE_USXGMII:
+ return "USXGMII";
+ default:
+ return "unknown";
+ }
+}
+
+static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf)
+{
+ switch (intf) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ return LANE_MODE_1000BASEX_SGMII;
+ case PHY_INTERFACE_MODE_10GBASER:
+ return LANE_MODE_10GBASER;
+ case PHY_INTERFACE_MODE_USXGMII:
+ return LANE_MODE_USXGMII;
+ default:
+ return LANE_MODE_UNKNOWN;
+ }
+}
+
+static bool lynx_28g_supports_lane_mode(struct lynx_28g_priv *priv,
+ enum lynx_lane_mode mode)
{
int i;
for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
- if (LYNX_28G_PLLnRSTCTL_DIS(priv->pll[i].rstctl))
+ if (PLLnRSTCTL_DIS(priv->pll[i].rstctl))
continue;
- if (test_bit(intf, priv->pll[i].supported))
+ if (test_bit(mode, priv->pll[i].supported))
return true;
}
@@ -173,7 +517,7 @@ static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
}
static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
- phy_interface_t intf)
+ enum lynx_lane_mode mode)
{
struct lynx_28g_pll *pll;
int i;
@@ -181,43 +525,51 @@ static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
pll = &priv->pll[i];
- if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
+ if (PLLnRSTCTL_DIS(pll->rstctl))
continue;
- if (test_bit(intf, pll->supported))
+ if (test_bit(mode, pll->supported))
return pll;
}
/* no pll supports requested mode, either caller forgot to check
* lynx_28g_supports_lane_mode, or this is a bug.
*/
- dev_WARN_ONCE(priv->dev, 1, "no pll for interface %s\n", phy_modes(intf));
+ dev_WARN_ONCE(priv->dev, 1, "no pll for lane mode %s\n",
+ lynx_lane_mode_str(mode));
return NULL;
}
static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
struct lynx_28g_pll *pll,
- phy_interface_t intf)
+ enum lynx_lane_mode lane_mode)
{
- switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
- case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
- case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
- switch (intf) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_QUARTER, N_RATE_MSK);
+ switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) {
+ case PLLnCR1_FRATE_5G_10GVCO:
+ case PLLnCR1_FRATE_5G_25GVCO:
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_QUARTER),
+ LNaTGCR0_N_RATE);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_QUARTER),
+ LNaRGCR0_N_RATE);
break;
default:
break;
}
break;
- case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
- switch (intf) {
- case PHY_INTERFACE_MODE_10GBASER:
- case PHY_INTERFACE_MODE_USXGMII:
- lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_FULL, N_RATE_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_FULL, N_RATE_MSK);
+ case PLLnCR1_FRATE_10G_20GVCO:
+ switch (lane_mode) {
+ case LANE_MODE_10GBASER:
+ case LANE_MODE_USXGMII:
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_FULL),
+ LNaTGCR0_N_RATE);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_FULL),
+ LNaRGCR0_N_RATE);
break;
default:
break;
@@ -232,163 +584,356 @@ static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
struct lynx_28g_pll *pll)
{
if (pll->id == 0) {
- lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLF, USE_PLL_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLF, USE_PLL_MSK);
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_USE_PLL, LNaTGCR0_USE_PLLF),
+ LNaTGCR0_USE_PLL);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_USE_PLL, LNaRGCR0_USE_PLLF),
+ LNaRGCR0_USE_PLL);
} else {
- lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLS, USE_PLL_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLS, USE_PLL_MSK);
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_USE_PLL, LNaTGCR0_USE_PLLS),
+ LNaTGCR0_USE_PLL);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_USE_PLL, LNaRGCR0_USE_PLLS),
+ LNaRGCR0_USE_PLL);
}
}
-static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
+static int lynx_28g_power_off(struct phy *phy)
{
- u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
- struct lynx_28g_priv *priv = lane->priv;
+ struct lynx_28g_lane *lane = phy_get_drvdata(phy);
+ u32 trstctl, rrstctl;
- /* Cleanup the protocol configuration registers of the current protocol */
- switch (lane->interface) {
- case PHY_INTERFACE_MODE_10GBASER:
- lynx_28g_rmw(priv, LYNX_28G_PCCC,
- LYNX_28G_PCCC_SXGMII_DIS << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ if (!lane->powered_up)
+ return 0;
+
+ /* Issue a halt request */
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_HLT_REQ,
+ LNaTRSTCTL_HLT_REQ);
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_HLT_REQ,
+ LNaRRSTCTL_HLT_REQ);
+
+ /* Wait until the halting process is complete */
+ do {
+ trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
+ rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
+ } while ((trstctl & LNaTRSTCTL_HLT_REQ) ||
+ (rrstctl & LNaRRSTCTL_HLT_REQ));
+
+ lane->powered_up = false;
+
+ return 0;
+}
+
+static int lynx_28g_power_on(struct phy *phy)
+{
+ struct lynx_28g_lane *lane = phy_get_drvdata(phy);
+ u32 trstctl, rrstctl;
+
+ if (lane->powered_up)
+ return 0;
+
+ /* Issue a reset request on the lane */
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_RST_REQ,
+ LNaTRSTCTL_RST_REQ);
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ,
+ LNaRRSTCTL_RST_REQ);
+
+ /* Wait until the reset sequence is completed */
+ do {
+ trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
+ rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
+ } while (!(trstctl & LNaTRSTCTL_RST_DONE) ||
+ !(rrstctl & LNaRRSTCTL_RST_DONE));
+
+ lane->powered_up = true;
+
+ return 0;
+}
+
+static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane,
+ struct lynx_pccr *pccr)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ pccr->offset = PCC8;
+ pccr->width = 4;
+ pccr->shift = SGMII_CFG(lane);
break;
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- lynx_28g_rmw(priv, LYNX_28G_PCC8,
- LYNX_28G_PCC8_SGMII_DIS << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ case LANE_MODE_USXGMII:
+ case LANE_MODE_10GBASER:
+ pccr->offset = PCCC;
+ pccr->width = 4;
+ pccr->shift = SXGMII_CFG(lane);
break;
default:
- break;
+ return -EOPNOTSUPP;
}
+
+ return 0;
}
-static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
+static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ return SGMIIaCR0(lane);
+ case LANE_MODE_USXGMII:
+ case LANE_MODE_10GBASER:
+ return SXGMIIaCR0(lane);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int lynx_pccr_read(struct lynx_28g_lane *lane, enum lynx_lane_mode mode,
+ u32 *val)
{
- u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
struct lynx_28g_priv *priv = lane->priv;
- struct lynx_28g_pll *pll;
+ struct lynx_pccr pccr;
+ u32 tmp;
+ int err;
- lynx_28g_cleanup_lane(lane);
+ err = lynx_28g_get_pccr(mode, lane->id, &pccr);
+ if (err)
+ return err;
- /* Setup the lane to run in SGMII */
- lynx_28g_rmw(priv, LYNX_28G_PCC8,
- LYNX_28G_PCC8_SGMII << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ tmp = lynx_28g_read(priv, pccr.offset);
+ *val = (tmp >> pccr.shift) & GENMASK(pccr.width - 1, 0);
- /* Setup the protocol select and SerDes parallel interface width */
- lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK);
- lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK);
+ return 0;
+}
- /* Find the PLL that works with this interface type */
- pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII);
- if (unlikely(pll == NULL))
- return;
+static int lynx_pccr_write(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode, u32 val)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ struct lynx_pccr pccr;
+ u32 old, tmp, mask;
+ int err;
- /* Switch to the PLL that works with this interface type */
- lynx_28g_lane_set_pll(lane, pll);
+ err = lynx_28g_get_pccr(lane_mode, lane->id, &pccr);
+ if (err)
+ return err;
- /* Choose the portion of clock net to be used on this lane */
- lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII);
-
- /* Enable the SGMII PCS */
- lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK);
-
- /* Configure the appropriate equalization parameters for the protocol */
- iowrite32(0x00808006, priv->base + LYNX_28G_LNaTECR0(lane->id));
- iowrite32(0x04310000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
- iowrite32(0x9f800000, priv->base + LYNX_28G_LNaRECR0(lane->id));
- iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
- iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR2(lane->id));
- iowrite32(0x00000000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
+ old = lynx_28g_read(priv, pccr.offset);
+ mask = GENMASK(pccr.width - 1, 0) << pccr.shift;
+ tmp = (old & ~mask) | (val << pccr.shift);
+ lynx_28g_write(priv, pccr.offset, tmp);
+
+ dev_dbg(&lane->phy->dev, "PCCR@0x%x: 0x%x -> 0x%x\n",
+ pccr.offset, old, tmp);
+
+ return 0;
}
-static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
+static int lynx_pcvt_read(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode, int cr, u32 *val)
{
- u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
struct lynx_28g_priv *priv = lane->priv;
- struct lynx_28g_pll *pll;
+ int offset;
+
+ offset = lynx_28g_get_pcvt_offset(lane->id, lane_mode);
+ if (offset < 0)
+ return offset;
+
+ *val = lynx_28g_read(priv, offset + cr);
+
+ return 0;
+}
+
+static int lynx_pcvt_write(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode, int cr, u32 val)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ int offset;
+
+ offset = lynx_28g_get_pcvt_offset(lane->id, lane_mode);
+ if (offset < 0)
+ return offset;
- lynx_28g_cleanup_lane(lane);
+ lynx_28g_write(priv, offset + cr, val);
- /* Enable the SXGMII lane */
- lynx_28g_rmw(priv, LYNX_28G_PCCC,
- LYNX_28G_PCCC_10GBASER << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ return 0;
+}
+
+static int lynx_pcvt_rmw(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode,
+ int cr, u32 val, u32 mask)
+{
+ int err;
+ u32 tmp;
+
+ err = lynx_pcvt_read(lane, lane_mode, cr, &tmp);
+ if (err)
+ return err;
+
+ tmp &= ~mask;
+ tmp |= val;
- /* Setup the protocol select and SerDes parallel interface width */
- lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK);
- lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK);
+ return lynx_pcvt_write(lane, lane_mode, cr, tmp);
+}
- /* Find the PLL that works with this interface type */
- pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER);
+static void lynx_28g_lane_remap_pll(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ struct lynx_28g_pll *pll;
+
+ /* Switch to the PLL that works with this interface type */
+ pll = lynx_28g_pll_get(priv, lane_mode);
if (unlikely(pll == NULL))
return;
- /* Switch to the PLL that works with this interface type */
lynx_28g_lane_set_pll(lane, pll);
/* Choose the portion of clock net to be used on this lane */
- lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER);
-
- /* Disable the SGMII PCS */
- lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK);
-
- /* Configure the appropriate equalization parameters for the protocol */
- iowrite32(0x10808307, priv->base + LYNX_28G_LNaTECR0(lane->id));
- iowrite32(0x10000000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
- iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR0(lane->id));
- iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
- iowrite32(0x81000020, priv->base + LYNX_28G_LNaRECR2(lane->id));
- iowrite32(0x00002000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
+ lynx_28g_lane_set_nrate(lane, pll, lane_mode);
}
-static int lynx_28g_power_off(struct phy *phy)
+static void lynx_28g_lane_change_proto_conf(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode)
{
- struct lynx_28g_lane *lane = phy_get_drvdata(phy);
- u32 trstctl, rrstctl;
+ const struct lynx_28g_proto_conf *conf = &lynx_28g_proto_conf[lane_mode];
+
+ lynx_28g_lane_rmw(lane, LNaGCR0,
+ FIELD_PREP(LNaGCR0_PROTO_SEL, conf->proto_sel) |
+ FIELD_PREP(LNaGCR0_IF_WIDTH, conf->if_width),
+ LNaGCR0_PROTO_SEL | LNaGCR0_IF_WIDTH);
+
+ lynx_28g_lane_rmw(lane, LNaTECR0,
+ FIELD_PREP(LNaTECR0_EQ_TYPE, conf->teq_type) |
+ FIELD_PREP(LNaTECR0_EQ_SGN_PREQ, conf->sgn_preq) |
+ FIELD_PREP(LNaTECR0_EQ_PREQ, conf->ratio_preq) |
+ FIELD_PREP(LNaTECR0_EQ_SGN_POST1Q, conf->sgn_post1q) |
+ FIELD_PREP(LNaTECR0_EQ_POST1Q, conf->ratio_post1q) |
+ FIELD_PREP(LNaTECR0_EQ_AMP_RED, conf->amp_red),
+ LNaTECR0_EQ_TYPE |
+ LNaTECR0_EQ_SGN_PREQ |
+ LNaTECR0_EQ_PREQ |
+ LNaTECR0_EQ_SGN_POST1Q |
+ LNaTECR0_EQ_POST1Q |
+ LNaTECR0_EQ_AMP_RED);
+
+ lynx_28g_lane_rmw(lane, LNaTECR1,
+ FIELD_PREP(LNaTECR1_EQ_ADPT_EQ, conf->adpt_eq),
+ LNaTECR1_EQ_ADPT_EQ);
+
+ lynx_28g_lane_rmw(lane, LNaRGCR1,
+ FIELD_PREP(LNaRGCR1_ENTER_IDLE_FLT_SEL, conf->enter_idle_flt_sel) |
+ FIELD_PREP(LNaRGCR1_EXIT_IDLE_FLT_SEL, conf->exit_idle_flt_sel) |
+ FIELD_PREP(LNaRGCR1_DATA_LOST_TH_SEL, conf->data_lost_th_sel),
+ LNaRGCR1_ENTER_IDLE_FLT_SEL |
+ LNaRGCR1_EXIT_IDLE_FLT_SEL |
+ LNaRGCR1_DATA_LOST_TH_SEL);
+
+ lynx_28g_lane_rmw(lane, LNaRECR0,
+ FIELD_PREP(LNaRECR0_EQ_GAINK2_HF_OV_EN, conf->gk2ovd_en) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK3_MF_OV_EN, conf->gk3ovd_en) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK4_LF_OV_EN, conf->gk4ovd_en) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK2_HF_OV, conf->gk2ovd) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK3_MF_OV, conf->gk3ovd) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK4_LF_OV, conf->gk4ovd),
+ LNaRECR0_EQ_GAINK2_HF_OV |
+ LNaRECR0_EQ_GAINK3_MF_OV |
+ LNaRECR0_EQ_GAINK4_LF_OV |
+ LNaRECR0_EQ_GAINK2_HF_OV_EN |
+ LNaRECR0_EQ_GAINK3_MF_OV_EN |
+ LNaRECR0_EQ_GAINK4_LF_OV_EN);
+
+ lynx_28g_lane_rmw(lane, LNaRECR1,
+ FIELD_PREP(LNaRECR1_EQ_OFFSET_OV, conf->eq_offset_ovd) |
+ FIELD_PREP(LNaRECR1_EQ_OFFSET_OV_EN, conf->eq_offset_ovd_en),
+ LNaRECR1_EQ_OFFSET_OV |
+ LNaRECR1_EQ_OFFSET_OV_EN);
+
+ lynx_28g_lane_rmw(lane, LNaRECR2,
+ FIELD_PREP(LNaRECR2_EQ_OFFSET_RNG_DBL, conf->eq_offset_rng_dbl) |
+ FIELD_PREP(LNaRECR2_EQ_BLW_SEL, conf->eq_blw_sel) |
+ FIELD_PREP(LNaRECR2_EQ_BOOST, conf->eq_boost) |
+ FIELD_PREP(LNaRECR2_SPARE_IN, conf->spare_in),
+ LNaRECR2_EQ_OFFSET_RNG_DBL |
+ LNaRECR2_EQ_BLW_SEL |
+ LNaRECR2_EQ_BOOST |
+ LNaRECR2_SPARE_IN);
+
+ lynx_28g_lane_rmw(lane, LNaRSCCR0,
+ FIELD_PREP(LNaRSCCR0_SMP_AUTOZ_D1R, conf->smp_autoz_d1r) |
+ FIELD_PREP(LNaRSCCR0_SMP_AUTOZ_EG1R, conf->smp_autoz_eg1r),
+ LNaRSCCR0_SMP_AUTOZ_D1R |
+ LNaRSCCR0_SMP_AUTOZ_EG1R);
+
+ lynx_28g_lane_write(lane, LNaRCCR0, conf->rccr0);
+ lynx_28g_lane_write(lane, LNaTTLCR0, conf->ttlcr0);
+}
- if (!lane->powered_up)
- return 0;
+static int lynx_28g_lane_disable_pcvt(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ int err;
- /* Issue a halt request */
- lynx_28g_lane_rmw(lane, LNaTRSTCTL, HLT_REQ, HLT_REQ);
- lynx_28g_lane_rmw(lane, LNaRRSTCTL, HLT_REQ, HLT_REQ);
+ spin_lock(&priv->pcc_lock);
- /* Wait until the halting process is complete */
- do {
- trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
- rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- } while ((trstctl & LYNX_28G_LNaTRSTCTL_HLT_REQ) ||
- (rrstctl & LYNX_28G_LNaRRSTCTL_HLT_REQ));
+ err = lynx_pccr_write(lane, lane_mode, 0);
+ if (err)
+ goto out;
- lane->powered_up = false;
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ err = lynx_pcvt_rmw(lane, lane_mode, CR(1), 0,
+ SGMIIaCR1_SGPCS_EN);
+ break;
+ default:
+ err = 0;
+ }
- return 0;
+out:
+ spin_unlock(&priv->pcc_lock);
+
+ return err;
}
-static int lynx_28g_power_on(struct phy *phy)
+static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode)
{
- struct lynx_28g_lane *lane = phy_get_drvdata(phy);
- u32 trstctl, rrstctl;
+ struct lynx_28g_priv *priv = lane->priv;
+ u32 val;
+ int err;
- if (lane->powered_up)
- return 0;
+ spin_lock(&priv->pcc_lock);
- /* Issue a reset request on the lane */
- lynx_28g_lane_rmw(lane, LNaTRSTCTL, RST_REQ, RST_REQ);
- lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ err = lynx_pcvt_rmw(lane, lane_mode, CR(1), SGMIIaCR1_SGPCS_EN,
+ SGMIIaCR1_SGPCS_EN);
+ break;
+ default:
+ err = 0;
+ }
- /* Wait until the reset sequence is completed */
- do {
- trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
- rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- } while (!(trstctl & LYNX_28G_LNaTRSTCTL_RST_DONE) ||
- !(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
+ val = 0;
- lane->powered_up = true;
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ val |= PCC8_SGMIIa_CFG;
+ break;
+ case LANE_MODE_10GBASER:
+ val |= PCCC_SXGMIIn_XFI;
+ fallthrough;
+ case LANE_MODE_USXGMII:
+ val |= PCCC_SXGMIIn_CFG;
+ break;
+ default:
+ break;
+ }
- return 0;
+ err = lynx_pccr_write(lane, lane_mode, val);
+
+ spin_unlock(&priv->pcc_lock);
+
+ return err;
}
static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
@@ -396,44 +941,39 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
struct lynx_28g_priv *priv = lane->priv;
int powered_up = lane->powered_up;
+ enum lynx_lane_mode lane_mode;
int err = 0;
if (mode != PHY_MODE_ETHERNET)
return -EOPNOTSUPP;
- if (lane->interface == PHY_INTERFACE_MODE_NA)
+ if (lane->mode == LANE_MODE_UNKNOWN)
return -EOPNOTSUPP;
- if (!lynx_28g_supports_interface(priv, submode))
+ lane_mode = phy_interface_to_lane_mode(submode);
+ if (!lynx_28g_supports_lane_mode(priv, lane_mode))
return -EOPNOTSUPP;
+ if (lane_mode == lane->mode)
+ return 0;
+
/* If the lane is powered up, put the lane into the halt state while
* the reconfiguration is being done.
*/
if (powered_up)
lynx_28g_power_off(phy);
- spin_lock(&priv->pcc_lock);
-
- switch (submode) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- lynx_28g_lane_set_sgmii(lane);
- break;
- case PHY_INTERFACE_MODE_10GBASER:
- lynx_28g_lane_set_10gbaser(lane);
- break;
- default:
- err = -EOPNOTSUPP;
+ err = lynx_28g_lane_disable_pcvt(lane, lane->mode);
+ if (err)
goto out;
- }
- lane->interface = submode;
+ lynx_28g_lane_change_proto_conf(lane, lane_mode);
+ lynx_28g_lane_remap_pll(lane, lane_mode);
+ WARN_ON(lynx_28g_lane_enable_pcvt(lane, lane_mode));
-out:
- spin_unlock(&priv->pcc_lock);
+ lane->mode = lane_mode;
- /* Power up the lane if necessary */
+out:
if (powered_up)
lynx_28g_power_on(phy);
@@ -445,11 +985,13 @@ static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode,
{
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
struct lynx_28g_priv *priv = lane->priv;
+ enum lynx_lane_mode lane_mode;
if (mode != PHY_MODE_ETHERNET)
return -EOPNOTSUPP;
- if (!lynx_28g_supports_interface(priv, submode))
+ lane_mode = phy_interface_to_lane_mode(submode);
+ if (!lynx_28g_supports_lane_mode(priv, lane_mode))
return -EOPNOTSUPP;
return 0;
@@ -495,19 +1037,19 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0);
pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1);
- if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
+ if (PLLnRSTCTL_DIS(pll->rstctl))
continue;
- switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
- case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
- case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
+ switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) {
+ case PLLnCR1_FRATE_5G_10GVCO:
+ case PLLnCR1_FRATE_5G_25GVCO:
/* 5GHz clock net */
- __set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported);
- __set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported);
+ __set_bit(LANE_MODE_1000BASEX_SGMII, pll->supported);
break;
- case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
+ case PLLnCR1_FRATE_10G_20GVCO:
/* 10.3125GHz clock net */
- __set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported);
+ __set_bit(LANE_MODE_10GBASER, pll->supported);
+ __set_bit(LANE_MODE_USXGMII, pll->supported);
break;
default:
/* 6GHz, 12.890625GHz, 8GHz */
@@ -536,11 +1078,12 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
}
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) {
- lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
+ if (!(rrstctl & LNaRRSTCTL_CDR_LOCK)) {
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ,
+ LNaRRSTCTL_RST_REQ);
do {
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- } while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
+ } while (!(rrstctl & LNaRRSTCTL_RST_DONE));
}
mutex_unlock(&lane->phy->mutex);
@@ -551,19 +1094,23 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
{
- u32 pss, protocol;
+ u32 pccr, pss, protocol;
pss = lynx_28g_lane_read(lane, LNaPSS);
- protocol = LYNX_28G_LNaPSS_TYPE(pss);
+ protocol = FIELD_GET(LNaPSS_TYPE, pss);
switch (protocol) {
- case LYNX_28G_LNaPSS_TYPE_SGMII:
- lane->interface = PHY_INTERFACE_MODE_SGMII;
+ case LNaPSS_TYPE_SGMII:
+ lane->mode = LANE_MODE_1000BASEX_SGMII;
break;
- case LYNX_28G_LNaPSS_TYPE_XFI:
- lane->interface = PHY_INTERFACE_MODE_10GBASER;
+ case LNaPSS_TYPE_XFI:
+ lynx_pccr_read(lane, LANE_MODE_10GBASER, &pccr);
+ if (pccr & PCCC_SXGMIIn_XFI)
+ lane->mode = LANE_MODE_10GBASER;
+ else
+ lane->mode = LANE_MODE_USXGMII;
break;
default:
- lane->interface = PHY_INTERFACE_MODE_NA;
+ lane->mode = LANE_MODE_UNKNOWN;
}
}
@@ -571,7 +1118,14 @@ static struct phy *lynx_28g_xlate(struct device *dev,
const struct of_phandle_args *args)
{
struct lynx_28g_priv *priv = dev_get_drvdata(dev);
- int idx = args->args[0];
+ int idx;
+
+ if (args->args_count == 0)
+ return of_phy_simple_xlate(dev, args);
+ else if (args->args_count != 1)
+ return ERR_PTR(-ENODEV);
+
+ idx = args->args[0];
if (WARN_ON(idx >= LYNX_28G_NUM_LANE))
return ERR_PTR(-EINVAL);
@@ -579,17 +1133,41 @@ static struct phy *lynx_28g_xlate(struct device *dev,
return priv->lane[idx].phy;
}
+static int lynx_28g_probe_lane(struct lynx_28g_priv *priv, int id,
+ struct device_node *dn)
+{
+ struct lynx_28g_lane *lane = &priv->lane[id];
+ struct phy *phy;
+
+ phy = devm_phy_create(priv->dev, dn, &lynx_28g_ops);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ lane->priv = priv;
+ lane->phy = phy;
+ lane->id = id;
+ phy_set_drvdata(phy, lane);
+ lynx_28g_lane_read_configuration(lane);
+
+ return 0;
+}
+
static int lynx_28g_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct phy_provider *provider;
struct lynx_28g_priv *priv;
- int i;
+ struct device_node *dn;
+ int err;
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->dev = &pdev->dev;
+
+ priv->dev = dev;
+ dev_set_drvdata(dev, priv);
+ spin_lock_init(&priv->pcc_lock);
+ INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
@@ -597,35 +1175,51 @@ static int lynx_28g_probe(struct platform_device *pdev)
lynx_28g_pll_read_configuration(priv);
- for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
- struct lynx_28g_lane *lane = &priv->lane[i];
- struct phy *phy;
-
- memset(lane, 0, sizeof(*lane));
-
- phy = devm_phy_create(&pdev->dev, NULL, &lynx_28g_ops);
- if (IS_ERR(phy))
- return PTR_ERR(phy);
-
- lane->priv = priv;
- lane->phy = phy;
- lane->id = i;
- phy_set_drvdata(phy, lane);
- lynx_28g_lane_read_configuration(lane);
+ dn = dev_of_node(dev);
+ if (of_get_child_count(dn)) {
+ struct device_node *child;
+
+ for_each_available_child_of_node(dn, child) {
+ u32 reg;
+
+ /* PHY subnode name must be 'phy'. */
+ if (!(of_node_name_eq(child, "phy")))
+ continue;
+
+ if (of_property_read_u32(child, "reg", &reg)) {
+ dev_err(dev, "No \"reg\" property for %pOF\n", child);
+ of_node_put(child);
+ return -EINVAL;
+ }
+
+ if (reg >= LYNX_28G_NUM_LANE) {
+ dev_err(dev, "\"reg\" property out of range for %pOF\n", child);
+ of_node_put(child);
+ return -EINVAL;
+ }
+
+ err = lynx_28g_probe_lane(priv, reg, child);
+ if (err) {
+ of_node_put(child);
+ return err;
+ }
+ }
+ } else {
+ for (int i = 0; i < LYNX_28G_NUM_LANE; i++) {
+ err = lynx_28g_probe_lane(priv, i, NULL);
+ if (err)
+ return err;
+ }
}
- dev_set_drvdata(dev, priv);
-
- spin_lock_init(&priv->pcc_lock);
- INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
+ provider = devm_of_phy_provider_register(dev, lynx_28g_xlate);
+ if (IS_ERR(provider))
+ return PTR_ERR(provider);
queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
msecs_to_jiffies(1000));
- dev_set_drvdata(&pdev->dev, priv);
- provider = devm_of_phy_provider_register(&pdev->dev, lynx_28g_xlate);
-
- return PTR_ERR_OR_ZERO(provider);
+ return 0;
}
static void lynx_28g_remove(struct platform_device *pdev)
diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
index 191c282246d9..d010fec15671 100644
--- a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
+++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
@@ -570,17 +570,20 @@ const struct phy_config *fsl_samsung_hdmi_phy_find_settings(struct fsl_samsung_h
return fract_div_phy;
}
-static long fsl_samsung_hdmi_phy_clk_round_rate(struct clk_hw *hw,
- unsigned long rate, unsigned long *parent_rate)
+static int fsl_samsung_hdmi_phy_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw);
- const struct phy_config *target_settings = fsl_samsung_hdmi_phy_find_settings(phy, rate);
+ const struct phy_config *target_settings = fsl_samsung_hdmi_phy_find_settings(phy,
+ req->rate);
if (target_settings == NULL)
return -EINVAL;
dev_dbg(phy->dev, "round_rate, closest rate = %u\n", target_settings->pixclk);
- return target_settings->pixclk;
+ req->rate = target_settings->pixclk;
+
+ return 0;
}
static int fsl_samsung_hdmi_phy_clk_set_rate(struct clk_hw *hw,
@@ -599,7 +602,7 @@ static int fsl_samsung_hdmi_phy_clk_set_rate(struct clk_hw *hw,
static const struct clk_ops phy_clk_ops = {
.recalc_rate = phy_clk_recalc_rate,
- .round_rate = fsl_samsung_hdmi_phy_clk_round_rate,
+ .determine_rate = fsl_samsung_hdmi_phy_clk_determine_rate,
.set_rate = fsl_samsung_hdmi_phy_clk_set_rate,
};
diff --git a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c
index 59903f86b13f..dd3e515a8e86 100644
--- a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c
+++ b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c
@@ -338,7 +338,7 @@ static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev)
return -ENOMEM;
}
- port->dr_mode = of_usb_get_dr_mode_by_phy(child, -1);
+ port->dr_mode = of_usb_get_dr_mode_by_phy(child, 0);
if ((port->dr_mode != USB_DR_MODE_HOST) &&
(port->dr_mode != USB_DR_MODE_PERIPHERAL)) {
dev_err(&pdev->dev,
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c
index e51b2d13eab4..b0b6497e7eed 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c
+++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c
@@ -90,10 +90,10 @@ static void mtk_hdmi_pll_unprepare(struct clk_hw *hw)
usleep_range(80, 100);
}
-static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int mtk_hdmi_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- return rate;
+ return 0;
}
static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -170,7 +170,7 @@ static const struct clk_ops mtk_hdmi_phy_pll_ops = {
.prepare = mtk_hdmi_pll_prepare,
.unprepare = mtk_hdmi_pll_unprepare,
.set_rate = mtk_hdmi_pll_set_rate,
- .round_rate = mtk_hdmi_pll_round_rate,
+ .determine_rate = mtk_hdmi_pll_determine_rate,
.recalc_rate = mtk_hdmi_pll_recalc_rate,
};
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c
index d04758396046..58c6596c8c20 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c
+++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c
@@ -118,18 +118,18 @@ static void mtk_hdmi_pll_unprepare(struct clk_hw *hw)
usleep_range(100, 150);
}
-static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int mtk_hdmi_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
- hdmi_phy->pll_rate = rate;
- if (rate <= 74250000)
- *parent_rate = rate;
+ hdmi_phy->pll_rate = req->rate;
+ if (req->rate <= 74250000)
+ req->best_parent_rate = req->rate;
else
- *parent_rate = rate / 2;
+ req->best_parent_rate = req->rate / 2;
- return rate;
+ return 0;
}
static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -223,7 +223,7 @@ static const struct clk_ops mtk_hdmi_phy_pll_ops = {
.prepare = mtk_hdmi_pll_prepare,
.unprepare = mtk_hdmi_pll_unprepare,
.set_rate = mtk_hdmi_pll_set_rate,
- .round_rate = mtk_hdmi_pll_round_rate,
+ .determine_rate = mtk_hdmi_pll_determine_rate,
.recalc_rate = mtk_hdmi_pll_recalc_rate,
};
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c
index b38f3ae26b3f..1426a2db984d 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c
+++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c
@@ -418,13 +418,13 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
return mtk_hdmi_pll_calc(hdmi_phy, hw, rate, parent_rate);
}
-static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int mtk_hdmi_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
- hdmi_phy->pll_rate = rate;
- return rate;
+ hdmi_phy->pll_rate = req->rate;
+ return 0;
}
static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw,
@@ -439,7 +439,7 @@ static const struct clk_ops mtk_hdmi_pll_ops = {
.prepare = mtk_hdmi_pll_prepare,
.unprepare = mtk_hdmi_pll_unprepare,
.set_rate = mtk_hdmi_pll_set_rate,
- .round_rate = mtk_hdmi_pll_round_rate,
+ .determine_rate = mtk_hdmi_pll_determine_rate,
.recalc_rate = mtk_hdmi_pll_recalc_rate,
};
diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c
index 673cb0f08959..438ff3605d90 100644
--- a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c
+++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c
@@ -237,16 +237,18 @@ static void mtk_mipi_tx_pll_unprepare(struct clk_hw *hw)
mtk_phy_clear_bits(base + MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_DIV_MSK);
}
-static long mtk_mipi_tx_pll_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int mtk_mipi_tx_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- return clamp_val(rate, 50000000, 1250000000);
+ req->rate = clamp_val(req->rate, 50000000, 1250000000);
+
+ return 0;
}
static const struct clk_ops mtk_mipi_tx_pll_ops = {
.prepare = mtk_mipi_tx_pll_prepare,
.unprepare = mtk_mipi_tx_pll_unprepare,
- .round_rate = mtk_mipi_tx_pll_round_rate,
+ .determine_rate = mtk_mipi_tx_pll_determine_rate,
.set_rate = mtk_mipi_tx_pll_set_rate,
.recalc_rate = mtk_mipi_tx_pll_recalc_rate,
};
diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c
index 553725e1269c..a54d44ef70ab 100644
--- a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c
+++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c
@@ -97,16 +97,18 @@ static void mtk_mipi_tx_pll_disable(struct clk_hw *hw)
mtk_phy_clear_bits(base + MIPITX_PLL_PWR, AD_DSI_PLL_SDM_PWR_ON);
}
-static long mtk_mipi_tx_pll_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int mtk_mipi_tx_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- return clamp_val(rate, 125000000, 1600000000);
+ req->rate = clamp_val(req->rate, 125000000, 1600000000);
+
+ return 0;
}
static const struct clk_ops mtk_mipi_tx_pll_ops = {
.enable = mtk_mipi_tx_pll_enable,
.disable = mtk_mipi_tx_pll_disable,
- .round_rate = mtk_mipi_tx_pll_round_rate,
+ .determine_rate = mtk_mipi_tx_pll_determine_rate,
.set_rate = mtk_mipi_tx_pll_set_rate,
.recalc_rate = mtk_mipi_tx_pll_recalc_rate,
};
diff --git a/drivers/phy/mediatek/phy-mtk-xfi-tphy.c b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
index 1a0b7484f525..100a50d0e861 100644
--- a/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
+++ b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
@@ -353,7 +353,7 @@ static int mtk_xfi_tphy_power_on(struct phy *phy)
* Disable and unprepare all clocks previously enabled.
*
* Return:
- * See clk_bulk_prepare_disable().
+ * See clk_bulk_disable_unprepare().
*/
static int mtk_xfi_tphy_power_off(struct phy *phy)
{
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 8d227890a345..4ad396214d0c 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -138,17 +138,14 @@ static struct phy *phy_find(struct device *dev, const char *con_id)
static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
{
struct phy_provider *phy_provider;
- struct device_node *child;
list_for_each_entry(phy_provider, &phy_provider_list, list) {
if (phy_provider->dev->of_node == node)
return phy_provider;
- for_each_child_of_node(phy_provider->children, child)
- if (child == node) {
- of_node_put(child);
+ for_each_child_of_node_scoped(phy_provider->children, child)
+ if (child == node)
return phy_provider;
- }
}
return ERR_PTR(-EPROBE_DEFER);
@@ -190,15 +187,15 @@ int phy_pm_runtime_get_sync(struct phy *phy)
}
EXPORT_SYMBOL_GPL(phy_pm_runtime_get_sync);
-int phy_pm_runtime_put(struct phy *phy)
+void phy_pm_runtime_put(struct phy *phy)
{
if (!phy)
- return 0;
+ return;
if (!pm_runtime_enabled(&phy->dev))
- return -ENOTSUPP;
+ return;
- return pm_runtime_put(&phy->dev);
+ pm_runtime_put(&phy->dev);
}
EXPORT_SYMBOL_GPL(phy_pm_runtime_put);
diff --git a/drivers/phy/phy-google-usb.c b/drivers/phy/phy-google-usb.c
new file mode 100644
index 000000000000..ab20bc20f19e
--- /dev/null
+++ b/drivers/phy/phy-google-usb.c
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-google-usb.c - Google USB PHY driver
+ *
+ * Copyright (C) 2025, Google LLC
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/usb/typec_mux.h>
+
+#define USBCS_USB2PHY_CFG19_OFFSET 0x0
+#define USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV GENMASK(19, 8)
+
+#define USBCS_USB2PHY_CFG21_OFFSET 0x8
+#define USBCS_USB2PHY_CFG21_PHY_ENABLE BIT(12)
+#define USBCS_USB2PHY_CFG21_REF_FREQ_SEL GENMASK(15, 13)
+#define USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL BIT(19)
+
+#define USBCS_PHY_CFG1_OFFSET 0x28
+#define USBCS_PHY_CFG1_SYS_VBUSVALID BIT(17)
+
+enum google_usb_phy_id {
+ GOOGLE_USB2_PHY,
+ GOOGLE_USB_PHY_NUM,
+};
+
+struct google_usb_phy_instance {
+ struct google_usb_phy *parent;
+ unsigned int index;
+ struct phy *phy;
+ unsigned int num_clks;
+ struct clk_bulk_data *clks;
+ unsigned int num_rsts;
+ struct reset_control_bulk_data *rsts;
+};
+
+struct google_usb_phy {
+ struct device *dev;
+ struct regmap *usb_cfg_regmap;
+ unsigned int usb2_cfg_offset;
+ void __iomem *usbdp_top_base;
+ struct google_usb_phy_instance *insts;
+ /*
+ * Protect phy registers from concurrent access, specifically via
+ * google_usb_set_orientation callback.
+ */
+ struct mutex phy_mutex;
+ struct typec_switch_dev *sw;
+ enum typec_orientation orientation;
+};
+
+static void set_vbus_valid(struct google_usb_phy *gphy)
+{
+ u32 reg;
+
+ if (gphy->orientation == TYPEC_ORIENTATION_NONE) {
+ reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ reg &= ~USBCS_PHY_CFG1_SYS_VBUSVALID;
+ writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ } else {
+ reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ reg |= USBCS_PHY_CFG1_SYS_VBUSVALID;
+ writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ }
+}
+
+static int google_usb_set_orientation(struct typec_switch_dev *sw,
+ enum typec_orientation orientation)
+{
+ struct google_usb_phy *gphy = typec_switch_get_drvdata(sw);
+
+ dev_dbg(gphy->dev, "set orientation %d\n", orientation);
+
+ gphy->orientation = orientation;
+
+ if (pm_runtime_suspended(gphy->dev))
+ return 0;
+
+ guard(mutex)(&gphy->phy_mutex);
+
+ set_vbus_valid(gphy);
+
+ return 0;
+}
+
+static int google_usb2_phy_init(struct phy *_phy)
+{
+ struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+ struct google_usb_phy *gphy = inst->parent;
+ u32 reg;
+ int ret;
+
+ dev_dbg(gphy->dev, "initializing usb2 phy\n");
+
+ guard(mutex)(&gphy->phy_mutex);
+
+ regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+ reg &= ~USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL;
+ reg &= ~USBCS_USB2PHY_CFG21_REF_FREQ_SEL;
+ reg |= FIELD_PREP(USBCS_USB2PHY_CFG21_REF_FREQ_SEL, 0);
+ regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+ regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, &reg);
+ reg &= ~USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV;
+ reg |= FIELD_PREP(USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV, 368);
+ regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, reg);
+
+ set_vbus_valid(gphy);
+
+ ret = clk_bulk_prepare_enable(inst->num_clks, inst->clks);
+ if (ret)
+ return ret;
+
+ ret = reset_control_bulk_deassert(inst->num_rsts, inst->rsts);
+ if (ret) {
+ clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+ return ret;
+ }
+
+ regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+ reg |= USBCS_USB2PHY_CFG21_PHY_ENABLE;
+ regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+ return 0;
+}
+
+static int google_usb2_phy_exit(struct phy *_phy)
+{
+ struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+ struct google_usb_phy *gphy = inst->parent;
+ u32 reg;
+
+ dev_dbg(gphy->dev, "exiting usb2 phy\n");
+
+ guard(mutex)(&gphy->phy_mutex);
+
+ regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, &reg);
+ reg &= ~USBCS_USB2PHY_CFG21_PHY_ENABLE;
+ regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+
+ reset_control_bulk_assert(inst->num_rsts, inst->rsts);
+ clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+
+ return 0;
+}
+
+static const struct phy_ops google_usb2_phy_ops = {
+ .init = google_usb2_phy_init,
+ .exit = google_usb2_phy_exit,
+};
+
+static struct phy *google_usb_phy_xlate(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ struct google_usb_phy *gphy = dev_get_drvdata(dev);
+
+ if (args->args[0] >= GOOGLE_USB_PHY_NUM) {
+ dev_err(dev, "invalid PHY index requested from DT\n");
+ return ERR_PTR(-ENODEV);
+ }
+ return gphy->insts[args->args[0]].phy;
+}
+
+static int google_usb_phy_probe(struct platform_device *pdev)
+{
+ struct typec_switch_desc sw_desc = { };
+ struct google_usb_phy_instance *inst;
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct google_usb_phy *gphy;
+ struct phy *phy;
+ u32 args[1];
+ int ret;
+
+ gphy = devm_kzalloc(dev, sizeof(*gphy), GFP_KERNEL);
+ if (!gphy)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, gphy);
+ gphy->dev = dev;
+
+ ret = devm_mutex_init(dev, &gphy->phy_mutex);
+ if (ret)
+ return ret;
+
+ gphy->usb_cfg_regmap =
+ syscon_regmap_lookup_by_phandle_args(dev->of_node,
+ "google,usb-cfg-csr",
+ ARRAY_SIZE(args), args);
+ if (IS_ERR(gphy->usb_cfg_regmap)) {
+ return dev_err_probe(dev, PTR_ERR(gphy->usb_cfg_regmap),
+ "invalid usb cfg csr\n");
+ }
+
+ gphy->usb2_cfg_offset = args[0];
+
+ gphy->usbdp_top_base = devm_platform_ioremap_resource_byname(pdev,
+ "usbdp_top");
+ if (IS_ERR(gphy->usbdp_top_base))
+ return dev_err_probe(dev, PTR_ERR(gphy->usbdp_top_base),
+ "invalid usbdp top\n");
+
+ gphy->insts = devm_kcalloc(dev, GOOGLE_USB_PHY_NUM, sizeof(*gphy->insts), GFP_KERNEL);
+ if (!gphy->insts)
+ return -ENOMEM;
+
+ inst = &gphy->insts[GOOGLE_USB2_PHY];
+ inst->parent = gphy;
+ inst->index = GOOGLE_USB2_PHY;
+ phy = devm_phy_create(dev, NULL, &google_usb2_phy_ops);
+ if (IS_ERR(phy))
+ return dev_err_probe(dev, PTR_ERR(phy),
+ "failed to create usb2 phy instance\n");
+ inst->phy = phy;
+ phy_set_drvdata(phy, inst);
+
+ inst->num_clks = 2;
+ inst->clks = devm_kcalloc(dev, inst->num_clks, sizeof(*inst->clks), GFP_KERNEL);
+ if (!inst->clks)
+ return -ENOMEM;
+ inst->clks[0].id = "usb2";
+ inst->clks[1].id = "usb2_apb";
+ ret = devm_clk_bulk_get(dev, inst->num_clks, inst->clks);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get u2 phy clks\n");
+
+ inst->num_rsts = 2;
+ inst->rsts = devm_kcalloc(dev, inst->num_rsts, sizeof(*inst->rsts), GFP_KERNEL);
+ if (!inst->rsts)
+ return -ENOMEM;
+ inst->rsts[0].id = "usb2";
+ inst->rsts[1].id = "usb2_apb";
+ ret = devm_reset_control_bulk_get_exclusive(dev, inst->num_rsts, inst->rsts);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get u2 phy resets\n");
+
+ phy_provider = devm_of_phy_provider_register(dev, google_usb_phy_xlate);
+ if (IS_ERR(phy_provider))
+ return dev_err_probe(dev, PTR_ERR(phy_provider),
+ "failed to register phy provider\n");
+
+ pm_runtime_enable(dev);
+
+ sw_desc.fwnode = dev_fwnode(dev);
+ sw_desc.drvdata = gphy;
+ sw_desc.name = fwnode_get_name(dev_fwnode(dev));
+ sw_desc.set = google_usb_set_orientation;
+
+ gphy->sw = typec_switch_register(dev, &sw_desc);
+ if (IS_ERR(gphy->sw))
+ return dev_err_probe(dev, PTR_ERR(gphy->sw),
+ "failed to register typec switch\n");
+
+ return 0;
+}
+
+static void google_usb_phy_remove(struct platform_device *pdev)
+{
+ struct google_usb_phy *gphy = dev_get_drvdata(&pdev->dev);
+
+ typec_switch_unregister(gphy->sw);
+ pm_runtime_disable(&pdev->dev);
+}
+
+static const struct of_device_id google_usb_phy_of_match[] = {
+ {
+ .compatible = "google,lga-usb-phy",
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, google_usb_phy_of_match);
+
+static struct platform_driver google_usb_phy = {
+ .probe = google_usb_phy_probe,
+ .remove = google_usb_phy_remove,
+ .driver = {
+ .name = "google-usb-phy",
+ .of_match_table = google_usb_phy_of_match,
+ }
+};
+
+module_platform_driver(google_usb_phy);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Google USB phy driver");
diff --git a/drivers/phy/phy-spacemit-k1-pcie.c b/drivers/phy/phy-spacemit-k1-pcie.c
new file mode 100644
index 000000000000..75477bea7f70
--- /dev/null
+++ b/drivers/phy/phy-spacemit-k1-pcie.c
@@ -0,0 +1,670 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SpacemiT K1 PCIe and PCIe/USB 3 combo PHY driver
+ *
+ * Copyright (C) 2025 by RISCstar Solutions Corporation. All rights reserved.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include <dt-bindings/phy/phy.h>
+
+/*
+ * Three PCIe ports are supported in the SpacemiT K1 SoC, and this driver
+ * supports their PHYs.
+ *
+ * The PHY for PCIe port A is different from the PHYs for ports B and C:
+ * - It has one lane, while ports B and C have two
+ * - It is a combo PHY can be used for PCIe or USB 3
+ * - It can automatically calibrate PCIe TX and RX termination settings
+ *
+ * The PHY functionality for PCIe ports B and C is identical:
+ * - They have two PCIe lanes (but can be restricted to 1 via device tree)
+ * - They are used for PCIe only
+ * - They are configured using TX and RX values computed for port A
+ *
+ * A given board is designed to use the combo PHY for either PCIe or USB 3.
+ * Whether the combo PHY is configured for PCIe or USB 3 is specified in
+ * device tree using a phandle plus an argument. The argument indicates
+ * the type (either PHY_TYPE_PCIE or PHY_TYPE_USB3).
+ *
+ * Each PHY has a reset that it gets and deasserts during initialization.
+ * Each depends also on other clocks and resets provided by the controller
+ * hardware (PCIe or USB) it is associated with. The controller drivers
+ * are required to enable any clocks and de-assert any resets that affect
+ * PHY operation. In addition each PHY implements an internal PLL, driven
+ * by an external (24 MHz) oscillator.
+ *
+ * PCIe PHYs must be programmed with RX and TX calibration values. The
+ * combo PHY is the only one that can determine these values. They are
+ * determined by temporarily enabling the combo PHY in PCIe mode at probe
+ * time (if necessary). This calibration only needs to be done once, and
+ * when it has completed the TX and RX values are saved.
+ *
+ * To allow the combo PHY to be enabled for calibration, the resets and
+ * clocks it uses in PCIe mode must be supplied.
+ */
+
+struct k1_pcie_phy {
+ struct device *dev; /* PHY provider device */
+ struct phy *phy;
+ void __iomem *regs;
+ u32 pcie_lanes; /* Max (1 or 2) unless limited by DT */
+ struct clk *pll;
+ struct clk_hw pll_hw; /* Private PLL clock */
+
+ /* The remaining fields are only used for the combo PHY */
+ u32 type; /* PHY_TYPE_PCIE or PHY_TYPE_USB3 */
+ struct regmap *pmu; /* MMIO regmap (no errors) */
+};
+
+#define CALIBRATION_TIMEOUT 500000 /* For combo PHY (usec) */
+#define PLL_TIMEOUT 500000 /* For PHY PLL lock (usec) */
+#define POLL_DELAY 500 /* Time between polls (usec) */
+
+/* Selecting the combo PHY operating mode requires APMU regmap access */
+#define SYSCON_APMU "spacemit,apmu"
+
+/* PMU space, for selecting between PCIe and USB 3 mode (combo PHY only) */
+
+#define PMUA_USB_PHY_CTRL0 0x0110
+#define COMBO_PHY_SEL BIT(3) /* 0: PCIe; 1: USB 3 */
+
+#define PCIE_CLK_RES_CTRL 0x03cc
+#define PCIE_APP_HOLD_PHY_RST BIT(30)
+
+/* PHY register space */
+
+/* Offset between lane 0 and lane 1 registers when there are two */
+#define PHY_LANE_OFFSET 0x0400
+
+/* PHY PLL configuration */
+#define PCIE_PU_ADDR_CLK_CFG 0x0008
+#define PLL_READY BIT(0) /* read-only */
+#define CFG_INTERNAL_TIMER_ADJ GENMASK(10, 7)
+#define TIMER_ADJ_USB 0x2
+#define TIMER_ADJ_PCIE 0x6
+#define CFG_SW_PHY_INIT_DONE BIT(11) /* We set after PLL config */
+
+#define PCIE_RC_DONE_STATUS 0x0018
+#define CFG_FORCE_RCV_RETRY BIT(10) /* Used for PCIe */
+
+/* PCIe PHY lane calibration; assumes 24MHz input clock */
+#define PCIE_RC_CAL_REG2 0x0020
+#define RC_CAL_TOGGLE BIT(22)
+#define CLKSEL GENMASK(31, 29)
+#define CLKSEL_24M 0x3
+
+/* Additional PHY PLL configuration (USB 3 and PCIe) */
+#define PCIE_PU_PLL_1 0x0048
+#define REF_100_WSSC BIT(12) /* 1: input is 100MHz, SSC */
+#define FREF_SEL GENMASK(15, 13)
+#define FREF_24M 0x1
+#define SSC_DEP_SEL GENMASK(19, 16)
+#define SSC_DEP_NONE 0x0
+#define SSC_DEP_5000PPM 0xa
+
+/* PCIe PHY configuration */
+#define PCIE_PU_PLL_2 0x004c
+#define GEN_REF100 BIT(4) /* 1: generate 100MHz clk */
+
+#define PCIE_RX_REG1 0x0050
+#define EN_RTERM BIT(3)
+#define AFE_RTERM_REG GENMASK(11, 8)
+
+#define PCIE_RX_REG2 0x0054
+#define RX_RTERM_SEL BIT(5) /* 0: use AFE_RTERM_REG value */
+
+#define PCIE_LTSSM_DIS_ENTRY 0x005c
+#define CFG_REFCLK_MODE GENMASK(9, 8)
+#define RFCLK_MODE_DRIVER 0x1
+#define OVRD_REFCLK_MODE BIT(10) /* 1: use CFG_RFCLK_MODE */
+
+#define PCIE_TX_REG1 0x0064
+#define TX_RTERM_REG GENMASK(15, 12)
+#define TX_RTERM_SEL BIT(25) /* 1: use TX_RTERM_REG */
+
+/* Zeroed for the combo PHY operating in USB mode */
+#define USB3_TEST_CTRL 0x0068
+
+/* PHY calibration values, determined by the combo PHY at probe time */
+#define PCIE_RCAL_RESULT 0x0084 /* Port A PHY only */
+#define RTERM_VALUE_RX GENMASK(3, 0)
+#define RTERM_VALUE_TX GENMASK(7, 4)
+#define R_TUNE_DONE BIT(10)
+
+static u32 k1_phy_rterm = ~0; /* Invalid initial value */
+
+/* Save the RX and TX receiver termination values */
+static void k1_phy_rterm_set(u32 val)
+{
+ k1_phy_rterm = val & (RTERM_VALUE_RX | RTERM_VALUE_TX);
+}
+
+static bool k1_phy_rterm_valid(void)
+{
+ /* Valid if no bits outside those we care about are set */
+ return !(k1_phy_rterm & ~(RTERM_VALUE_RX | RTERM_VALUE_TX));
+}
+
+static u32 k1_phy_rterm_rx(void)
+{
+ return FIELD_GET(RTERM_VALUE_RX, k1_phy_rterm);
+}
+
+static u32 k1_phy_rterm_tx(void)
+{
+ return FIELD_GET(RTERM_VALUE_TX, k1_phy_rterm);
+}
+
+/* Only the combo PHY has a PMU pointer defined */
+static bool k1_phy_port_a(struct k1_pcie_phy *k1_phy)
+{
+ return !!k1_phy->pmu;
+}
+
+/* The PLL clocks are driven by the external oscillator */
+static const struct clk_parent_data k1_pcie_phy_data[] = {
+ { .fw_name = "refclk", },
+};
+
+static struct k1_pcie_phy *clk_hw_to_k1_phy(struct clk_hw *clk_hw)
+{
+ return container_of(clk_hw, struct k1_pcie_phy, pll_hw);
+}
+
+/* USB mode only works on the combo PHY, which has only one lane */
+static void k1_pcie_phy_pll_prepare_usb(struct k1_pcie_phy *k1_phy)
+{
+ void __iomem *regs = k1_phy->regs;
+ u32 val;
+
+ val = readl(regs + PCIE_PU_ADDR_CLK_CFG);
+ val &= ~CFG_INTERNAL_TIMER_ADJ;
+ val |= FIELD_PREP(CFG_INTERNAL_TIMER_ADJ, TIMER_ADJ_USB);
+ writel(val, regs + PCIE_PU_ADDR_CLK_CFG);
+
+ val = readl(regs + PCIE_PU_PLL_1);
+ val &= ~SSC_DEP_SEL;
+ val |= FIELD_PREP(SSC_DEP_SEL, SSC_DEP_5000PPM);
+ writel(val, regs + PCIE_PU_PLL_1);
+}
+
+/* Perform PCIe-specific register updates before starting the PLL clock */
+static void k1_pcie_phy_pll_prepare_pcie(struct k1_pcie_phy *k1_phy)
+{
+ void __iomem *regs = k1_phy->regs;
+ u32 val;
+ u32 i;
+
+ for (i = 0; i < k1_phy->pcie_lanes; i++) {
+ val = readl(regs + PCIE_PU_ADDR_CLK_CFG);
+ val &= ~CFG_INTERNAL_TIMER_ADJ;
+ val |= FIELD_PREP(CFG_INTERNAL_TIMER_ADJ, TIMER_ADJ_PCIE);
+ writel(val, regs + PCIE_PU_ADDR_CLK_CFG);
+
+ regs += PHY_LANE_OFFSET; /* Next lane */
+ }
+
+ regs = k1_phy->regs;
+ val = readl(regs + PCIE_RC_DONE_STATUS);
+ val |= CFG_FORCE_RCV_RETRY;
+ writel(val, regs + PCIE_RC_DONE_STATUS);
+
+ val = readl(regs + PCIE_PU_PLL_1);
+ val &= ~SSC_DEP_SEL;
+ val |= FIELD_PREP(SSC_DEP_SEL, SSC_DEP_NONE);
+ writel(val, regs + PCIE_PU_PLL_1);
+
+ val = readl(regs + PCIE_PU_PLL_2);
+ val |= GEN_REF100; /* Enable 100 MHz PLL output clock */
+ writel(val, regs + PCIE_PU_PLL_2);
+}
+
+static int k1_pcie_phy_pll_prepare(struct clk_hw *clk_hw)
+{
+ struct k1_pcie_phy *k1_phy = clk_hw_to_k1_phy(clk_hw);
+ void __iomem *regs = k1_phy->regs;
+ u32 val;
+ u32 i;
+
+ if (k1_phy_port_a(k1_phy) && k1_phy->type == PHY_TYPE_USB3)
+ k1_pcie_phy_pll_prepare_usb(k1_phy);
+ else
+ k1_pcie_phy_pll_prepare_pcie(k1_phy);
+
+ /*
+ * Disable 100 MHz input reference with spread-spectrum
+ * clocking and select the 24 MHz clock input frequency
+ */
+ val = readl(regs + PCIE_PU_PLL_1);
+ val &= ~REF_100_WSSC;
+ val &= ~FREF_SEL;
+ val |= FIELD_PREP(FREF_SEL, FREF_24M);
+ writel(val, regs + PCIE_PU_PLL_1);
+
+ /* Mark PLL configuration done on all lanes */
+ for (i = 0; i < k1_phy->pcie_lanes; i++) {
+ val = readl(regs + PCIE_PU_ADDR_CLK_CFG);
+ val |= CFG_SW_PHY_INIT_DONE;
+ writel(val, regs + PCIE_PU_ADDR_CLK_CFG);
+
+ regs += PHY_LANE_OFFSET; /* Next lane */
+ }
+
+ /*
+ * Wait for indication the PHY PLL is locked. Lanes for ports
+ * B and C share a PLL, so it's enough to sample just lane 0.
+ */
+ return readl_poll_timeout(k1_phy->regs + PCIE_PU_ADDR_CLK_CFG,
+ val, val & PLL_READY,
+ POLL_DELAY, PLL_TIMEOUT);
+}
+
+/* Prepare implies enable, and once enabled, it's always on */
+static const struct clk_ops k1_pcie_phy_pll_ops = {
+ .prepare = k1_pcie_phy_pll_prepare,
+};
+
+/* We represent the PHY PLL as a private clock */
+static int k1_pcie_phy_pll_setup(struct k1_pcie_phy *k1_phy)
+{
+ struct clk_hw *hw = &k1_phy->pll_hw;
+ struct device *dev = k1_phy->dev;
+ struct clk_init_data init = { };
+ char *name;
+ int ret;
+
+ name = kasprintf(GFP_KERNEL, "pcie%u_phy_pll", k1_phy->phy->id);
+ if (!name)
+ return -ENOMEM;
+
+ init.name = name;
+ init.ops = &k1_pcie_phy_pll_ops;
+ init.parent_data = k1_pcie_phy_data;
+ init.num_parents = ARRAY_SIZE(k1_pcie_phy_data);
+
+ hw->init = &init;
+
+ ret = devm_clk_hw_register(dev, hw);
+
+ kfree(name); /* __clk_register() duplicates the name we provide */
+
+ if (ret)
+ return ret;
+
+ k1_phy->pll = devm_clk_hw_get_clk(dev, hw, "pll");
+ if (IS_ERR(k1_phy->pll))
+ return PTR_ERR(k1_phy->pll);
+
+ return 0;
+}
+
+/* Select PCIe or USB 3 mode for the combo PHY. */
+static void k1_combo_phy_sel(struct k1_pcie_phy *k1_phy, bool usb)
+{
+ struct regmap *pmu = k1_phy->pmu;
+
+ /* Only change it if it's not already in the desired state */
+ if (!regmap_test_bits(pmu, PMUA_USB_PHY_CTRL0, COMBO_PHY_SEL) == usb)
+ regmap_assign_bits(pmu, PMUA_USB_PHY_CTRL0, COMBO_PHY_SEL, usb);
+}
+
+static void k1_pcie_phy_init_pcie(struct k1_pcie_phy *k1_phy)
+{
+ u32 rx_rterm = k1_phy_rterm_rx();
+ u32 tx_rterm = k1_phy_rterm_tx();
+ void __iomem *regs;
+ u32 val;
+ int i;
+
+ /* For the combo PHY, set PHY to PCIe mode */
+ if (k1_phy_port_a(k1_phy))
+ k1_combo_phy_sel(k1_phy, false);
+
+ regs = k1_phy->regs;
+ for (i = 0; i < k1_phy->pcie_lanes; i++) {
+ val = readl(regs + PCIE_RX_REG1);
+
+ /* Set RX analog front-end receiver termination value */
+ val &= ~AFE_RTERM_REG;
+ val |= FIELD_PREP(AFE_RTERM_REG, rx_rterm);
+
+ /* And enable refclock receiver termination */
+ val |= EN_RTERM;
+ writel(val, regs + PCIE_RX_REG1);
+
+ val = readl(regs + PCIE_RX_REG2);
+ /* Use PCIE_RX_REG1 AFE_RTERM_REG value */
+ val &= ~RX_RTERM_SEL;
+ writel(val, regs + PCIE_RX_REG2);
+
+ val = readl(regs + PCIE_TX_REG1);
+
+ /* Set TX driver termination value */
+ val &= ~TX_RTERM_REG;
+ val |= FIELD_PREP(TX_RTERM_REG, tx_rterm);
+
+ /* Use PCIE_TX_REG1 TX_RTERM_REG value */
+ val |= TX_RTERM_SEL;
+ writel(val, regs + PCIE_TX_REG1);
+
+ /* Set the input clock to 24 MHz, and clear RC_CAL_TOGGLE */
+ val = readl(regs + PCIE_RC_CAL_REG2);
+ val &= CLKSEL;
+ val |= FIELD_PREP(CLKSEL, CLKSEL_24M);
+ val &= ~RC_CAL_TOGGLE;
+ writel(val, regs + PCIE_RC_CAL_REG2);
+
+ /* Now trigger recalibration by setting RC_CAL_TOGGLE again */
+ val |= RC_CAL_TOGGLE;
+ writel(val, regs + PCIE_RC_CAL_REG2);
+
+ val = readl(regs + PCIE_LTSSM_DIS_ENTRY);
+ /* Override the reference clock; set to refclk driver mode */
+ val |= OVRD_REFCLK_MODE;
+ val &= ~CFG_REFCLK_MODE;
+ val |= FIELD_PREP(CFG_REFCLK_MODE, RFCLK_MODE_DRIVER);
+ writel(val, regs + PCIE_LTSSM_DIS_ENTRY);
+
+ regs += PHY_LANE_OFFSET; /* Next lane */
+ }
+}
+
+/* Only called for combo PHY */
+static void k1_pcie_phy_init_usb(struct k1_pcie_phy *k1_phy)
+{
+ k1_combo_phy_sel(k1_phy, true);
+
+ /* We're not doing any testing */
+ writel(0, k1_phy->regs + USB3_TEST_CTRL);
+}
+
+static int k1_pcie_phy_init(struct phy *phy)
+{
+ struct k1_pcie_phy *k1_phy = phy_get_drvdata(phy);
+
+ /* Note: port type is only valid for port A (both checks needed) */
+ if (k1_phy_port_a(k1_phy) && k1_phy->type == PHY_TYPE_USB3)
+ k1_pcie_phy_init_usb(k1_phy);
+ else
+ k1_pcie_phy_init_pcie(k1_phy);
+
+
+ return clk_prepare_enable(k1_phy->pll);
+}
+
+static int k1_pcie_phy_exit(struct phy *phy)
+{
+ struct k1_pcie_phy *k1_phy = phy_get_drvdata(phy);
+
+ clk_disable_unprepare(k1_phy->pll);
+
+ return 0;
+}
+
+static const struct phy_ops k1_pcie_phy_ops = {
+ .init = k1_pcie_phy_init,
+ .exit = k1_pcie_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Get values needed for calibrating PHYs operating in PCIe mode. Only
+ * the combo PHY is able to do this, and its calibration values are used
+ * for configuring all PCIe PHYs.
+ *
+ * We always need to de-assert the "global" reset on the combo PHY,
+ * because the USB driver depends on it. If used for PCIe, that driver
+ * will (also) de-assert this, but by leaving it de-asserted for the
+ * combo PHY, the USB driver doesn't have to do this. Note: although
+ * SpacemiT refers to this as the global reset, we name the "phy" reset.
+ *
+ * In addition, we guarantee the APP_HOLD_PHY_RESET bit is clear for the
+ * combo PHY, so the USB driver doesn't have to manage that either. The
+ * PCIe driver is free to change this bit for normal operation.
+ *
+ * Calibration only needs to be done once. It's possible calibration has
+ * already completed (e.g., it might have happened in the boot loader, or
+ * -EPROBE_DEFER might result in this function being called again). So we
+ * check that early too, to avoid doing it more than once.
+ *
+ * Otherwise we temporarily power up the PHY using the PCIe app clocks
+ * and resets, wait for the hardware to indicate calibration is done,
+ * grab the value, then shut the PHY down again.
+ */
+static int k1_pcie_combo_phy_calibrate(struct k1_pcie_phy *k1_phy)
+{
+ struct reset_control_bulk_data resets[] = {
+ { .id = "dbi", },
+ { .id = "mstr", },
+ { .id = "slv", },
+ };
+ struct clk_bulk_data clocks[] = {
+ { .id = "dbi", },
+ { .id = "mstr", },
+ { .id = "slv", },
+ };
+ struct device *dev = k1_phy->dev;
+ int ret = 0;
+ int val;
+
+ /* Nothing to do if we already set the receiver termination value */
+ if (k1_phy_rterm_valid())
+ return 0;
+
+ /*
+ * We also guarantee the APP_HOLD_PHY_RESET bit is clear. We can
+ * leave this bit clear even if an error happens below.
+ */
+ regmap_assign_bits(k1_phy->pmu, PCIE_CLK_RES_CTRL,
+ PCIE_APP_HOLD_PHY_RST, false);
+
+ /* If the calibration already completed (e.g. by U-Boot), we're done */
+ val = readl(k1_phy->regs + PCIE_RCAL_RESULT);
+ if (val & R_TUNE_DONE)
+ goto out_tune_done;
+
+ /* Put the PHY into PCIe mode */
+ k1_combo_phy_sel(k1_phy, false);
+
+ /* Get and enable the PCIe app clocks */
+ ret = clk_bulk_get(dev, ARRAY_SIZE(clocks), clocks);
+ if (ret < 0)
+ goto out_tune_done;
+ ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks);
+ if (ret)
+ goto out_put_clocks;
+
+ /* Get the PCIe application resets (not the PHY reset) */
+ ret = reset_control_bulk_get_shared(dev, ARRAY_SIZE(resets), resets);
+ if (ret)
+ goto out_disable_clocks;
+
+ /* De-assert the PCIe application resets */
+ ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
+ if (ret)
+ goto out_put_resets;
+
+ /*
+ * This is the core activity here. Wait for the hardware to
+ * signal that it has completed calibration/tuning. Once it
+ * has, the register value will contain the values we'll
+ * use to configure PCIe PHYs.
+ */
+ ret = readl_poll_timeout(k1_phy->regs + PCIE_RCAL_RESULT,
+ val, val & R_TUNE_DONE,
+ POLL_DELAY, CALIBRATION_TIMEOUT);
+
+ /* Clean up. We're done with the resets and clocks */
+ reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
+out_put_resets:
+ reset_control_bulk_put(ARRAY_SIZE(resets), resets);
+out_disable_clocks:
+ clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks);
+out_put_clocks:
+ clk_bulk_put(ARRAY_SIZE(clocks), clocks);
+out_tune_done:
+ /* If we got the value without timing out, set k1_phy_rterm */
+ if (!ret)
+ k1_phy_rterm_set(val);
+
+ return ret;
+}
+
+static struct phy *
+k1_pcie_combo_phy_xlate(struct device *dev, const struct of_phandle_args *args)
+{
+ struct k1_pcie_phy *k1_phy = dev_get_drvdata(dev);
+ u32 type;
+
+ /* The argument specifying the PHY mode is required */
+ if (args->args_count != 1)
+ return ERR_PTR(-EINVAL);
+
+ /* We only support PCIe and USB 3 mode */
+ type = args->args[0];
+ if (type != PHY_TYPE_PCIE && type != PHY_TYPE_USB3)
+ return ERR_PTR(-EINVAL);
+
+ /* This PHY can only be used once */
+ if (k1_phy->type != PHY_NONE)
+ return ERR_PTR(-EBUSY);
+
+ k1_phy->type = type;
+
+ return k1_phy->phy;
+}
+
+/* Use the maximum number of PCIe lanes unless limited by device tree */
+static u32 k1_pcie_num_lanes(struct k1_pcie_phy *k1_phy, bool port_a)
+{
+ struct device *dev = k1_phy->dev;
+ u32 count = 0;
+ u32 max;
+ int ret;
+
+ ret = of_property_read_u32(dev_of_node(dev), "num-lanes", &count);
+ if (count == 1)
+ return 1;
+
+ if (count == 2 && !port_a)
+ return 2;
+
+ max = port_a ? 1 : 2;
+ if (ret != -EINVAL)
+ dev_warn(dev, "bad lane count %u for port; using %u\n",
+ count, max);
+
+ return max;
+}
+
+static int k1_pcie_combo_phy_probe(struct k1_pcie_phy *k1_phy)
+{
+ struct device *dev = k1_phy->dev;
+ struct regmap *regmap;
+ int ret;
+
+ /* Setting the PHY mode requires access to the PMU regmap */
+ regmap = syscon_regmap_lookup_by_phandle(dev_of_node(dev), SYSCON_APMU);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "failed to get PMU\n");
+ k1_phy->pmu = regmap;
+
+ ret = k1_pcie_combo_phy_calibrate(k1_phy);
+ if (ret)
+ return dev_err_probe(dev, ret, "calibration failed\n");
+
+ /* Needed by k1_pcie_combo_phy_xlate(), which also sets k1_phy->type */
+ dev_set_drvdata(dev, k1_phy);
+
+ return 0;
+}
+
+static int k1_pcie_phy_probe(struct platform_device *pdev)
+{
+ struct phy *(*xlate)(struct device *dev,
+ const struct of_phandle_args *args);
+ struct device *dev = &pdev->dev;
+ struct reset_control *phy_reset;
+ struct phy_provider *provider;
+ struct k1_pcie_phy *k1_phy;
+ bool probing_port_a;
+ int ret;
+
+ xlate = of_device_get_match_data(dev);
+ probing_port_a = xlate == k1_pcie_combo_phy_xlate;
+
+ /* Only the combo PHY can calibrate, so it must probe first */
+ if (!k1_phy_rterm_valid() && !probing_port_a)
+ return -EPROBE_DEFER;
+
+ k1_phy = devm_kzalloc(dev, sizeof(*k1_phy), GFP_KERNEL);
+ if (!k1_phy)
+ return -ENOMEM;
+ k1_phy->dev = dev;
+
+ k1_phy->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(k1_phy->regs))
+ return dev_err_probe(dev, PTR_ERR(k1_phy->regs),
+ "error mapping registers\n");
+
+ /* De-assert the PHY (global) reset and leave it that way */
+ phy_reset = devm_reset_control_get_exclusive_deasserted(dev, "phy");
+ if (IS_ERR(phy_reset))
+ return PTR_ERR(phy_reset);
+
+ if (probing_port_a) {
+ ret = k1_pcie_combo_phy_probe(k1_phy);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "error probing combo phy\n");
+ }
+
+ k1_phy->pcie_lanes = k1_pcie_num_lanes(k1_phy, probing_port_a);
+
+ k1_phy->phy = devm_phy_create(dev, NULL, &k1_pcie_phy_ops);
+ if (IS_ERR(k1_phy->phy))
+ return dev_err_probe(dev, PTR_ERR(k1_phy->phy),
+ "error creating phy\n");
+ phy_set_drvdata(k1_phy->phy, k1_phy);
+
+ ret = k1_pcie_phy_pll_setup(k1_phy);
+ if (ret)
+ return dev_err_probe(dev, ret, "error initializing clock\n");
+
+ provider = devm_of_phy_provider_register(dev, xlate);
+ if (IS_ERR(provider))
+ return dev_err_probe(dev, PTR_ERR(provider),
+ "error registering provider\n");
+ return 0;
+}
+
+static const struct of_device_id k1_pcie_phy_of_match[] = {
+ { .compatible = "spacemit,k1-combo-phy", k1_pcie_combo_phy_xlate, },
+ { .compatible = "spacemit,k1-pcie-phy", of_phy_simple_xlate, },
+ { },
+};
+MODULE_DEVICE_TABLE(of, k1_pcie_phy_of_match);
+
+static struct platform_driver k1_pcie_phy_driver = {
+ .probe = k1_pcie_phy_probe,
+ .driver = {
+ .of_match_table = k1_pcie_phy_of_match,
+ .name = "spacemit-k1-pcie-phy",
+ }
+};
+module_platform_driver(k1_pcie_phy_driver);
+
+MODULE_DESCRIPTION("SpacemiT K1 PCIe and USB 3 PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c
index f1b51018683d..7372de05a0b8 100644
--- a/drivers/phy/qualcomm/phy-qcom-edp.c
+++ b/drivers/phy/qualcomm/phy-qcom-edp.c
@@ -26,13 +26,15 @@
#include "phy-qcom-qmp-qserdes-com-v4.h"
#include "phy-qcom-qmp-qserdes-com-v6.h"
+#include "phy-qcom-qmp-qserdes-dp-com-v8.h"
+
/* EDP_PHY registers */
#define DP_PHY_CFG 0x0010
#define DP_PHY_CFG_1 0x0014
#define DP_PHY_PD_CTL 0x001c
#define DP_PHY_MODE 0x0020
-#define DP_AUX_CFG_SIZE 10
+#define DP_AUX_CFG_SIZE 13
#define DP_PHY_AUX_CFG(n) (0x24 + (0x04 * (n)))
#define DP_PHY_AUX_INTERRUPT_MASK 0x0058
@@ -76,6 +78,7 @@ struct phy_ver_ops {
int (*com_power_on)(const struct qcom_edp *edp);
int (*com_resetsm_cntrl)(const struct qcom_edp *edp);
int (*com_bias_en_clkbuflr)(const struct qcom_edp *edp);
+ int (*com_clk_fwd_cfg)(const struct qcom_edp *edp);
int (*com_configure_pll)(const struct qcom_edp *edp);
int (*com_configure_ssc)(const struct qcom_edp *edp);
};
@@ -83,6 +86,7 @@ struct phy_ver_ops {
struct qcom_edp_phy_cfg {
bool is_edp;
const u8 *aux_cfg;
+ const u8 *vco_div_cfg;
const struct qcom_edp_swing_pre_emph_cfg *swing_pre_emph_cfg;
const struct phy_ver_ops *ver_ops;
};
@@ -103,7 +107,9 @@ struct qcom_edp {
struct phy_configure_opts_dp dp_opts;
- struct clk_bulk_data clks[2];
+ struct clk_bulk_data *clks;
+ int num_clks;
+
struct regulator_bulk_data supplies[2];
bool is_edp;
@@ -179,8 +185,12 @@ static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg = {
.pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3,
};
-static const u8 edp_phy_aux_cfg_v4[10] = {
- 0x00, 0x13, 0x24, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03
+static const u8 edp_phy_aux_cfg_v4[DP_AUX_CFG_SIZE] = {
+ 0x00, 0x13, 0x24, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03, 0x02, 0x02, 0x00,
+};
+
+static const u8 edp_phy_vco_div_cfg_v4[4] = {
+ 0x01, 0x01, 0x02, 0x00,
};
static const u8 edp_pre_emp_hbr_rbr_v5[4][4] = {
@@ -204,8 +214,16 @@ static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg_v5 =
.pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3_v5,
};
-static const u8 edp_phy_aux_cfg_v5[10] = {
- 0x00, 0x13, 0xa4, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03
+static const u8 edp_phy_aux_cfg_v5[DP_AUX_CFG_SIZE] = {
+ 0x00, 0x13, 0xa4, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03, 0x02, 0x02, 0x00,
+};
+
+static const u8 edp_phy_aux_cfg_v8[DP_AUX_CFG_SIZE] = {
+ 0x00, 0x00, 0xa0, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03, 0x02, 0x02, 0x04,
+};
+
+static const u8 edp_phy_vco_div_cfg_v8[4] = {
+ 0x00, 0x00, 0x02, 0x01,
};
static int qcom_edp_phy_init(struct phy *phy)
@@ -218,12 +236,16 @@ static int qcom_edp_phy_init(struct phy *phy)
if (ret)
return ret;
- ret = clk_bulk_prepare_enable(ARRAY_SIZE(edp->clks), edp->clks);
+ ret = clk_bulk_prepare_enable(edp->num_clks, edp->clks);
if (ret)
goto out_disable_supplies;
memcpy(aux_cfg, edp->cfg->aux_cfg, sizeof(aux_cfg));
+ ret = edp->cfg->ver_ops->com_clk_fwd_cfg(edp);
+ if (ret)
+ return ret;
+
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,
edp->edp + DP_PHY_PD_CTL);
@@ -343,22 +365,22 @@ static int qcom_edp_set_vco_div(const struct qcom_edp *edp, unsigned long *pixel
switch (dp_opts->link_rate) {
case 1620:
- vco_div = 0x1;
+ vco_div = edp->cfg->vco_div_cfg[0];
*pixel_freq = 1620000000UL / 2;
break;
case 2700:
- vco_div = 0x1;
+ vco_div = edp->cfg->vco_div_cfg[1];
*pixel_freq = 2700000000UL / 2;
break;
case 5400:
- vco_div = 0x2;
+ vco_div = edp->cfg->vco_div_cfg[2];
*pixel_freq = 5400000000UL / 4;
break;
case 8100:
- vco_div = 0x0;
+ vco_div = edp->cfg->vco_div_cfg[3];
*pixel_freq = 8100000000UL / 6;
break;
@@ -396,6 +418,11 @@ static int qcom_edp_phy_com_resetsm_cntrl_v4(const struct qcom_edp *edp)
val, val & BIT(0), 500, 10000);
}
+static int qcom_edp_com_clk_fwd_cfg_v4(const struct qcom_edp *edp)
+{
+ return 0;
+}
+
static int qcom_edp_com_bias_en_clkbuflr_v4(const struct qcom_edp *edp)
{
/* Turn on BIAS current for PHY/PLL */
@@ -528,6 +555,7 @@ static const struct phy_ver_ops qcom_edp_phy_ops_v4 = {
.com_power_on = qcom_edp_phy_power_on_v4,
.com_resetsm_cntrl = qcom_edp_phy_com_resetsm_cntrl_v4,
.com_bias_en_clkbuflr = qcom_edp_com_bias_en_clkbuflr_v4,
+ .com_clk_fwd_cfg = qcom_edp_com_clk_fwd_cfg_v4,
.com_configure_pll = qcom_edp_com_configure_pll_v4,
.com_configure_ssc = qcom_edp_com_configure_ssc_v4,
};
@@ -535,17 +563,20 @@ static const struct phy_ver_ops qcom_edp_phy_ops_v4 = {
static const struct qcom_edp_phy_cfg sa8775p_dp_phy_cfg = {
.is_edp = false,
.aux_cfg = edp_phy_aux_cfg_v5,
+ .vco_div_cfg = edp_phy_vco_div_cfg_v4,
.swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg_v5,
.ver_ops = &qcom_edp_phy_ops_v4,
};
static const struct qcom_edp_phy_cfg sc7280_dp_phy_cfg = {
.aux_cfg = edp_phy_aux_cfg_v4,
+ .vco_div_cfg = edp_phy_vco_div_cfg_v4,
.ver_ops = &qcom_edp_phy_ops_v4,
};
static const struct qcom_edp_phy_cfg sc8280xp_dp_phy_cfg = {
.aux_cfg = edp_phy_aux_cfg_v4,
+ .vco_div_cfg = edp_phy_vco_div_cfg_v4,
.swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg,
.ver_ops = &qcom_edp_phy_ops_v4,
};
@@ -553,6 +584,7 @@ static const struct qcom_edp_phy_cfg sc8280xp_dp_phy_cfg = {
static const struct qcom_edp_phy_cfg sc8280xp_edp_phy_cfg = {
.is_edp = true,
.aux_cfg = edp_phy_aux_cfg_v4,
+ .vco_div_cfg = edp_phy_vco_div_cfg_v4,
.swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg,
.ver_ops = &qcom_edp_phy_ops_v4,
};
@@ -726,16 +758,197 @@ static const struct phy_ver_ops qcom_edp_phy_ops_v6 = {
.com_power_on = qcom_edp_phy_power_on_v6,
.com_resetsm_cntrl = qcom_edp_phy_com_resetsm_cntrl_v6,
.com_bias_en_clkbuflr = qcom_edp_com_bias_en_clkbuflr_v6,
+ .com_clk_fwd_cfg = qcom_edp_com_clk_fwd_cfg_v4,
.com_configure_pll = qcom_edp_com_configure_pll_v6,
.com_configure_ssc = qcom_edp_com_configure_ssc_v6,
};
static struct qcom_edp_phy_cfg x1e80100_phy_cfg = {
.aux_cfg = edp_phy_aux_cfg_v4,
+ .vco_div_cfg = edp_phy_vco_div_cfg_v4,
.swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg,
.ver_ops = &qcom_edp_phy_ops_v6,
};
+static int qcom_edp_com_configure_ssc_v8(const struct qcom_edp *edp)
+{
+ const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
+ u32 step1;
+ u32 step2;
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ case 2700:
+ case 8100:
+ step1 = 0x5b;
+ step2 = 0x02;
+ break;
+
+ case 5400:
+ step1 = 0x5b;
+ step2 = 0x02;
+ break;
+
+ default:
+ /* Other link rates aren't supported */
+ return -EINVAL;
+ }
+
+ writel(0x01, edp->pll + DP_QSERDES_V8_COM_SSC_EN_CENTER);
+ writel(0x00, edp->pll + DP_QSERDES_V8_COM_SSC_ADJ_PER1);
+ writel(0x6b, edp->pll + DP_QSERDES_V8_COM_SSC_PER1);
+ writel(0x02, edp->pll + DP_QSERDES_V8_COM_SSC_PER2);
+ writel(step1, edp->pll + DP_QSERDES_V8_COM_SSC_STEP_SIZE1_MODE0);
+ writel(step2, edp->pll + DP_QSERDES_V8_COM_SSC_STEP_SIZE2_MODE0);
+
+ return 0;
+}
+
+static int qcom_edp_com_configure_pll_v8(const struct qcom_edp *edp)
+{
+ const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
+ u32 div_frac_start2_mode0;
+ u32 div_frac_start3_mode0;
+ u32 dec_start_mode0;
+ u32 lock_cmp1_mode0;
+ u32 lock_cmp2_mode0;
+ u32 code1_mode0;
+ u32 code2_mode0;
+ u32 hsclk_sel;
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ hsclk_sel = 0x5;
+ dec_start_mode0 = 0x34;
+ div_frac_start2_mode0 = 0xc0;
+ div_frac_start3_mode0 = 0x0b;
+ lock_cmp1_mode0 = 0x37;
+ lock_cmp2_mode0 = 0x04;
+ code1_mode0 = 0x71;
+ code2_mode0 = 0x0c;
+ break;
+
+ case 2700:
+ hsclk_sel = 0x3;
+ dec_start_mode0 = 0x34;
+ div_frac_start2_mode0 = 0xc0;
+ div_frac_start3_mode0 = 0x0b;
+ lock_cmp1_mode0 = 0x07;
+ lock_cmp2_mode0 = 0x07;
+ code1_mode0 = 0x71;
+ code2_mode0 = 0x0c;
+ break;
+
+ case 5400:
+ case 8100:
+ hsclk_sel = 0x2;
+ dec_start_mode0 = 0x4f;
+ div_frac_start2_mode0 = 0xa0;
+ div_frac_start3_mode0 = 0x01;
+ lock_cmp1_mode0 = 0x18;
+ lock_cmp2_mode0 = 0x15;
+ code1_mode0 = 0x14;
+ code2_mode0 = 0x25;
+ break;
+
+ default:
+ /* Other link rates aren't supported */
+ return -EINVAL;
+ }
+
+ writel(0x01, edp->pll + DP_QSERDES_V8_COM_SVS_MODE_CLK_SEL);
+ writel(0x3b, edp->pll + DP_QSERDES_V8_COM_SYSCLK_EN_SEL);
+ writel(0x02, edp->pll + DP_QSERDES_V8_COM_SYS_CLK_CTRL);
+ writel(0x0c, edp->pll + DP_QSERDES_V8_COM_CLK_ENABLE1);
+ writel(0x06, edp->pll + DP_QSERDES_V8_COM_SYSCLK_BUF_ENABLE);
+ writel(0x30, edp->pll + DP_QSERDES_V8_COM_CLK_SELECT);
+ writel(hsclk_sel, edp->pll + DP_QSERDES_V8_COM_HSCLK_SEL_1);
+ writel(0x07, edp->pll + DP_QSERDES_V8_COM_PLL_IVCO);
+ writel(0x00, edp->pll + DP_QSERDES_V8_COM_LOCK_CMP_EN);
+ writel(0x36, edp->pll + DP_QSERDES_V8_COM_PLL_CCTRL_MODE0);
+ writel(0x16, edp->pll + DP_QSERDES_V8_COM_PLL_RCTRL_MODE0);
+ writel(0x06, edp->pll + DP_QSERDES_V8_COM_CP_CTRL_MODE0);
+ writel(dec_start_mode0, edp->pll + DP_QSERDES_V8_COM_DEC_START_MODE0);
+ writel(0x00, edp->pll + DP_QSERDES_V8_COM_DIV_FRAC_START1_MODE0);
+ writel(div_frac_start2_mode0, edp->pll + DP_QSERDES_V8_COM_DIV_FRAC_START2_MODE0);
+ writel(div_frac_start3_mode0, edp->pll + DP_QSERDES_V8_COM_DIV_FRAC_START3_MODE0);
+ writel(0x96, edp->pll + DP_QSERDES_V8_COM_CMN_CONFIG_1);
+ writel(0x3f, edp->pll + DP_QSERDES_V8_COM_INTEGLOOP_GAIN0_MODE0);
+ writel(0x00, edp->pll + DP_QSERDES_V8_COM_INTEGLOOP_GAIN1_MODE0);
+ writel(0x00, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE_MAP);
+ writel(lock_cmp1_mode0, edp->pll + DP_QSERDES_V8_COM_LOCK_CMP1_MODE0);
+ writel(lock_cmp2_mode0, edp->pll + DP_QSERDES_V8_COM_LOCK_CMP2_MODE0);
+
+ writel(0x0a, edp->pll + DP_QSERDES_V8_COM_BG_TIMER);
+ writel(0x0a, edp->pll + DP_QSERDES_V8_COM_CORECLK_DIV_MODE0);
+ writel(0x00, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE_CTRL);
+ writel(0x1f, edp->pll + DP_QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN);
+ writel(0x00, edp->pll + DP_QSERDES_V8_COM_CORE_CLK_EN);
+ writel(0xa0, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE1_MODE0);
+ writel(0x01, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE2_MODE0);
+
+ writel(code1_mode0, edp->pll + DP_QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE0);
+ writel(code2_mode0, edp->pll + DP_QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE0);
+
+ return 0;
+}
+
+
+static int qcom_edp_phy_com_resetsm_cntrl_v8(const struct qcom_edp *edp)
+{
+ u32 val;
+
+ writel(0x20, edp->pll + DP_QSERDES_V8_COM_RESETSM_CNTRL);
+
+ return readl_poll_timeout(edp->pll + DP_QSERDES_V8_COM_C_READY_STATUS,
+ val, val & BIT(0), 500, 10000);
+}
+
+static int qcom_edp_com_clk_fwd_cfg_v8(const struct qcom_edp *edp)
+{
+ writel(0x3f, edp->pll + DP_QSERDES_V8_COM_CLK_FWD_CONFIG_1);
+
+ return 0;
+}
+
+static int qcom_edp_com_bias_en_clkbuflr_v8(const struct qcom_edp *edp)
+{
+ /* Turn on BIAS current for PHY/PLL */
+ writel(0x1f, edp->pll + DP_QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN);
+
+ return 0;
+}
+
+static int qcom_edp_phy_power_on_v8(const struct qcom_edp *edp)
+{
+ u32 val;
+
+ 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,
+ edp->edp + DP_PHY_PD_CTL);
+ writel(0xfc, edp->edp + DP_PHY_MODE);
+
+ return readl_poll_timeout(edp->pll + DP_QSERDES_V8_COM_CMN_STATUS,
+ val, val & BIT(7), 5, 200);
+}
+
+static const struct phy_ver_ops qcom_edp_phy_ops_v8 = {
+ .com_power_on = qcom_edp_phy_power_on_v8,
+ .com_resetsm_cntrl = qcom_edp_phy_com_resetsm_cntrl_v8,
+ .com_bias_en_clkbuflr = qcom_edp_com_bias_en_clkbuflr_v8,
+ .com_clk_fwd_cfg = qcom_edp_com_clk_fwd_cfg_v8,
+ .com_configure_pll = qcom_edp_com_configure_pll_v8,
+ .com_configure_ssc = qcom_edp_com_configure_ssc_v8,
+};
+
+static struct qcom_edp_phy_cfg glymur_phy_cfg = {
+ .aux_cfg = edp_phy_aux_cfg_v8,
+ .vco_div_cfg = edp_phy_vco_div_cfg_v8,
+ .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg_v5,
+ .ver_ops = &qcom_edp_phy_ops_v8,
+};
+
static int qcom_edp_phy_power_on(struct phy *phy)
{
const struct qcom_edp *edp = phy_get_drvdata(phy);
@@ -885,7 +1098,7 @@ static int qcom_edp_phy_exit(struct phy *phy)
{
struct qcom_edp *edp = phy_get_drvdata(phy);
- clk_bulk_disable_unprepare(ARRAY_SIZE(edp->clks), edp->clks);
+ clk_bulk_disable_unprepare(edp->num_clks, edp->clks);
regulator_bulk_disable(ARRAY_SIZE(edp->supplies), edp->supplies);
return 0;
@@ -1092,11 +1305,9 @@ static int qcom_edp_phy_probe(struct platform_device *pdev)
if (IS_ERR(edp->pll))
return PTR_ERR(edp->pll);
- edp->clks[0].id = "aux";
- edp->clks[1].id = "cfg_ahb";
- ret = devm_clk_bulk_get(dev, ARRAY_SIZE(edp->clks), edp->clks);
- if (ret)
- return ret;
+ edp->num_clks = devm_clk_bulk_get_all(dev, &edp->clks);
+ if (edp->num_clks < 0)
+ return dev_err_probe(dev, edp->num_clks, "failed to get clocks\n");
edp->supplies[0].supply = "vdda-phy";
edp->supplies[1].supply = "vdda-pll";
@@ -1133,6 +1344,7 @@ static int qcom_edp_phy_probe(struct platform_device *pdev)
}
static const struct of_device_id qcom_edp_phy_match_table[] = {
+ { .compatible = "qcom,glymur-dp-phy", .data = &glymur_phy_cfg, },
{ .compatible = "qcom,sa8775p-edp-phy", .data = &sa8775p_dp_phy_cfg, },
{ .compatible = "qcom,sc7280-edp-phy", .data = &sc7280_dp_phy_cfg, },
{ .compatible = "qcom,sc8180x-edp-phy", .data = &sc7280_dp_phy_cfg, },
diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
index 651a12b59bc8..efeec4709a15 100644
--- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
+++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
@@ -37,6 +37,17 @@
#define EUSB2_TUNE_EUSB_EQU 0x5A
#define EUSB2_TUNE_EUSB_HS_COMP_CUR 0x5B
+static const int squelch_detector[] = {
+ [0] = -6000,
+ [1] = -5000,
+ [2] = -4000,
+ [3] = -3000,
+ [4] = -2000,
+ [5] = -1000,
+ [6] = 0,
+ [7] = 1000,
+};
+
struct eusb2_repeater_init_tbl_reg {
unsigned int reg;
unsigned int value;
@@ -75,6 +86,13 @@ static const struct eusb2_repeater_init_tbl_reg smb2360_init_tbl[] = {
{ EUSB2_TUNE_USB2_PREEM, 0x2 },
};
+static const struct eusb2_repeater_init_tbl_reg smb2370_init_tbl[] = {
+ { EUSB2_TUNE_IUSB2, 0x4 },
+ { EUSB2_TUNE_SQUELCH_U, 0x3 },
+ { EUSB2_TUNE_USB2_SLEW, 0x7 },
+ { EUSB2_TUNE_USB2_PREEM, 0x0 },
+};
+
static const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = {
.init_tbl = pm8550b_init_tbl,
.init_tbl_num = ARRAY_SIZE(pm8550b_init_tbl),
@@ -97,6 +115,13 @@ static const struct eusb2_repeater_cfg smb2360_eusb2_cfg = {
.num_vregs = ARRAY_SIZE(pm8550b_vreg_l),
};
+static const struct eusb2_repeater_cfg smb2370_eusb2_cfg = {
+ .init_tbl = smb2370_init_tbl,
+ .init_tbl_num = ARRAY_SIZE(smb2370_init_tbl),
+ .vreg_list = pm8550b_vreg_l,
+ .num_vregs = ARRAY_SIZE(pm8550b_vreg_l),
+};
+
static int eusb2_repeater_init_vregs(struct eusb2_repeater *rptr)
{
int num = rptr->cfg->num_vregs;
@@ -120,7 +145,9 @@ static int eusb2_repeater_init(struct phy *phy)
struct regmap *regmap = rptr->regmap;
u32 base = rptr->base;
u32 poll_val;
+ s32 dt_val;
int ret;
+ int i;
u8 val;
ret = regulator_bulk_enable(rptr->cfg->num_vregs, rptr->vregs);
@@ -147,6 +174,15 @@ static int eusb2_repeater_init(struct phy *phy)
if (!of_property_read_u8(np, "qcom,tune-res-fsdif", &val))
regmap_write(regmap, base + EUSB2_TUNE_RES_FSDIF, val);
+ if (!of_property_read_s32(np, "qcom,squelch-detector-bp", &dt_val)) {
+ for (i = 0; i < ARRAY_SIZE(squelch_detector); i++) {
+ if (squelch_detector[i] == dt_val) {
+ regmap_write(regmap, base + EUSB2_TUNE_SQUELCH_U, i);
+ break;
+ }
+ }
+ }
+
/* Wait for status OK */
ret = regmap_read_poll_timeout(regmap, base + EUSB2_RPTR_STATUS, poll_val,
poll_val & RPTR_OK, 10, 5);
@@ -278,6 +314,10 @@ static const struct of_device_id eusb2_repeater_of_match_table[] = {
.compatible = "qcom,smb2360-eusb2-repeater",
.data = &smb2360_eusb2_cfg,
},
+ {
+ .compatible = "qcom,smb2370-eusb2-repeater",
+ .data = &smb2370_eusb2_cfg,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, eusb2_repeater_of_match_table);
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index 9e2a6c5d0f58..93f1aa10d400 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -30,7 +30,12 @@
#include "phy-qcom-qmp-common.h"
#include "phy-qcom-qmp.h"
+#include "phy-qcom-qmp-pcs-aon-v6.h"
+#include "phy-qcom-qmp-pcs-aon-v8.h"
#include "phy-qcom-qmp-pcs-misc-v3.h"
+#include "phy-qcom-qmp-pcs-misc-v4.h"
+#include "phy-qcom-qmp-pcs-misc-v5.h"
+#include "phy-qcom-qmp-pcs-misc-v8.h"
#include "phy-qcom-qmp-pcs-usb-v4.h"
#include "phy-qcom-qmp-pcs-usb-v5.h"
#include "phy-qcom-qmp-pcs-usb-v6.h"
@@ -43,6 +48,9 @@
#include "phy-qcom-qmp-dp-phy-v4.h"
#include "phy-qcom-qmp-dp-phy-v5.h"
#include "phy-qcom-qmp-dp-phy-v6.h"
+#include "phy-qcom-qmp-dp-phy-v8.h"
+
+#include "phy-qcom-qmp-usb43-pcs-v8.h"
/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */
/* DP PHY soft reset */
@@ -61,6 +69,7 @@
/* QPHY_V3_DP_COM_TYPEC_CTRL register bits */
#define SW_PORTSELECT_VAL BIT(0)
#define SW_PORTSELECT_MUX BIT(1)
+#define INVERT_CC_POLARITY BIT(2)
#define PHY_INIT_COMPLETE_TIMEOUT 10000
@@ -79,6 +88,7 @@ enum qphy_reg_layout {
QPHY_PCS_AUTONOMOUS_MODE_CTRL,
QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR,
QPHY_PCS_POWER_DOWN_CONTROL,
+ QPHY_PCS_CLAMP_ENABLE,
QPHY_COM_RESETSM_CNTRL,
QPHY_COM_C_READY_STATUS,
@@ -94,6 +104,8 @@ enum qphy_reg_layout {
QPHY_TX_HIGHZ_DRVR_EN,
QPHY_TX_TRANSCEIVER_BIAS_EN,
+ QPHY_AON_TOGGLE_ENABLE,
+ QPHY_DP_AON_TOGGLE_ENABLE,
/* Keep last to ensure regs_layout arrays are properly initialized */
QPHY_LAYOUT_SIZE
};
@@ -106,6 +118,8 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL,
[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR,
+ [QPHY_PCS_CLAMP_ENABLE] = QPHY_V3_PCS_MISC_CLAMP_ENABLE,
+
[QPHY_COM_RESETSM_CNTRL] = QSERDES_V3_COM_RESETSM_CNTRL,
[QPHY_COM_C_READY_STATUS] = QSERDES_V3_COM_C_READY_STATUS,
[QPHY_COM_CMN_STATUS] = QSERDES_V3_COM_CMN_STATUS,
@@ -131,6 +145,8 @@ static const unsigned int qmp_v45_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL,
[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR,
+ [QPHY_PCS_CLAMP_ENABLE] = QPHY_V4_PCS_MISC_CLAMP_ENABLE,
+
[QPHY_COM_RESETSM_CNTRL] = QSERDES_V4_COM_RESETSM_CNTRL,
[QPHY_COM_C_READY_STATUS] = QSERDES_V4_COM_C_READY_STATUS,
[QPHY_COM_CMN_STATUS] = QSERDES_V4_COM_CMN_STATUS,
@@ -156,6 +172,8 @@ static const unsigned int qmp_v5_5nm_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V5_PCS_USB3_AUTONOMOUS_MODE_CTRL,
[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V5_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR,
+ [QPHY_PCS_CLAMP_ENABLE] = QPHY_V5_PCS_MISC_CLAMP_ENABLE,
+
[QPHY_COM_RESETSM_CNTRL] = QSERDES_V5_COM_RESETSM_CNTRL,
[QPHY_COM_C_READY_STATUS] = QSERDES_V5_COM_C_READY_STATUS,
[QPHY_COM_CMN_STATUS] = QSERDES_V5_COM_CMN_STATUS,
@@ -181,6 +199,8 @@ static const unsigned int qmp_v6_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V6_PCS_USB3_AUTONOMOUS_MODE_CTRL,
[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V6_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR,
+ [QPHY_PCS_CLAMP_ENABLE] = QPHY_V6_PCS_AON_CLAMP_ENABLE,
+
[QPHY_COM_RESETSM_CNTRL] = QSERDES_V6_COM_RESETSM_CNTRL,
[QPHY_COM_C_READY_STATUS] = QSERDES_V6_COM_C_READY_STATUS,
[QPHY_COM_CMN_STATUS] = QSERDES_V6_COM_CMN_STATUS,
@@ -206,6 +226,8 @@ static const unsigned int qmp_v6_n4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V6_PCS_USB3_AUTONOMOUS_MODE_CTRL,
[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V6_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR,
+ [QPHY_PCS_CLAMP_ENABLE] = QPHY_V6_PCS_AON_CLAMP_ENABLE,
+
[QPHY_COM_RESETSM_CNTRL] = QSERDES_V6_COM_RESETSM_CNTRL,
[QPHY_COM_C_READY_STATUS] = QSERDES_V6_COM_C_READY_STATUS,
[QPHY_COM_CMN_STATUS] = QSERDES_V6_COM_CMN_STATUS,
@@ -246,6 +268,237 @@ static const unsigned int qmp_v8_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V8_TX_TRANSCEIVER_BIAS_EN,
};
+static const unsigned int qmp_v8_n3_usb43dpphy_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_SW_RESET] = QPHY_V8_USB43_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V8_USB43_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V8_USB43_PCS_PCS_STATUS1,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V8_USB43_PCS_POWER_DOWN_CONTROL,
+
+ /* In PCS_USB */
+ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V8_PCS_USB_AUTONOMOUS_MODE_CTRL,
+ [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V8_PCS_USB_LFPS_RXTERM_IRQ_CLEAR,
+
+ [QPHY_PCS_CLAMP_ENABLE] = QPHY_V8_PCS_AON_USB3_AON_CLAMP_ENABLE,
+ [QPHY_AON_TOGGLE_ENABLE] = QPHY_V8_PCS_AON_USB3_AON_TOGGLE_ENABLE,
+ [QPHY_DP_AON_TOGGLE_ENABLE] = QPHY_V8_PCS_AON_DP_AON_TOGGLE_ENABLE,
+
+ [QPHY_COM_RESETSM_CNTRL] = QSERDES_V8_COM_RESETSM_CNTRL,
+ [QPHY_COM_C_READY_STATUS] = QSERDES_V8_COM_C_READY_STATUS,
+ [QPHY_COM_CMN_STATUS] = QSERDES_V8_COM_CMN_STATUS,
+ [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN,
+
+ [QPHY_DP_PHY_STATUS] = QSERDES_V8_DP_PHY_STATUS,
+ [QPHY_DP_PHY_VCO_DIV] = QSERDES_V8_DP_PHY_VCO_DIV,
+
+ [QPHY_TX_TX_DRV_LVL] = QSERDES_V8_LALB_TX0_DRV_LVL,
+ [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V8_LALB_TX0_EMP_POST1_LVL,
+ [QPHY_TX_HIGHZ_DRVR_EN] = QSERDES_V8_LALB_HIGHZ_DRVR_EN,
+ [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V8_LALB_TRANSMITTER_EN_CTRL,
+};
+
+static const struct qmp_phy_init_tbl glymur_usb43dp_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE1, 0xe1),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_STEP_SIZE2_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CP_CTRL_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CORECLK_DIV_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP1_MODE1, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP2_MODE1, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DEC_START_MODE1, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DEC_START_MSB_MODE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START1_MODE1, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE1, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_HSCLK_SEL_1, 0x13),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_INTEGLOOP_GAIN0_MODE1, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE1_MODE1, 0x4d),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE2_MODE1, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0x95),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x4b),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE0, 0xe1),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_STEP_SIZE2_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CORECLK_DIV_MODE0, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP1_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP2_MODE0, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DEC_START_MODE0, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DEC_START_MSB_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START1_MODE0, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE0, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE1_MODE0, 0x4d),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE2_MODE0, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BG_TIMER, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_EN_CENTER, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_PER1, 0x62),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_PER2, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SYSCLK_BUF_ENABLE, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_IVCO_MODE1, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SYSCLK_EN_SEL, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP_EN, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP_CFG, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE_MAP, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CORE_CLK_EN, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CMN_CONFIG_1, 0x76),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SVS_MODE_CLK_SEL, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_SPARE_FOR_ECO, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DCC_CAL_1, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DCC_CAL_2, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DCC_CAL_3, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PSM_CAL_EN, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_1, 0x33),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_IP_CTRL_AND_DP_SEL, 0xaf),
+};
+
+static const struct qmp_phy_init_tbl glymur_usb43dp_pcs_misc_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_MISC_PCS_MISC_CONFIG1, 0x01),
+};
+
+static const struct qmp_phy_init_tbl glymur_usb43dp_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG1, 0xc4),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG2, 0x89),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG3, 0x20),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG6, 0x13),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_REFGEN_REQ_CONFIG1, 0x21),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_RX_SIGDET_LVL, 0x55),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_TSYNC_RSYNC_TIME, 0xa4),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_RX_CONFIG, 0x0a),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_TSYNC_DLY_TIME, 0x04),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_ALIGN_DETECT_CONFIG1, 0xd4),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_ALIGN_DETECT_CONFIG2, 0x30),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_PCS_TX_RX_CONFIG, 0x0c),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_EQ_CONFIG1, 0x4b),
+ QMP_PHY_INIT_CFG(QPHY_V8_USB43_PCS_EQ_CONFIG5, 0x10),
+};
+
+static const struct qmp_phy_init_tbl glymur_usb43dp_pcs_usb_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_USB_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_USB_RXEQTRAINING_DFE_TIME_S2, 0x07),
+};
+
+static const struct qmp_phy_init_tbl glymur_usb43dp_lalb_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CLKBUF_ENABLE, 0x81),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX_LVL_UPDATE_CTRL, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL3, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL4, 0x8D),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TRANSMITTER_EN_CTRL, 0x13),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_LANE_MODE_1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_LANE_MODE_2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_LANE_MODE_3, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_LANE_MODE_4, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX0_RESTRIM_CAL_CTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX1_RESTRIM_CAL_CTRL, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX0_RESTRIM_POST_CAL_OFFSET, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX0_RESTRIM_VREF_SEL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX1_RESTRIM_VREF_SEL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_ANA_INTERFACE_SELECT2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_PCS_INTERFACE_SELECT1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE_0_1_B0, 0xa4),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE_0_1_B1, 0xa2),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE_0_1_B2, 0x6e),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE_0_1_B3, 0x51),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE_0_1_B4, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE_0_1_B5, 0x26),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE_0_1_B6, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE_0_1_B7, 0x2a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE2_B0, 0x4c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE2_B1, 0xc4),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE2_B2, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE2_B3, 0x64),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE2_B4, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE2_B5, 0x4b),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE2_B6, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_MODE_RATE2_B7, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX_DCC_ANA_CTRL2, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT1_RATE1, 0x26),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT2_RATE1, 0x26),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT1_RATE2, 0x26),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT2_RATE2, 0x26),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KVCO_INIT_RATE_0_1, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KVCO_INIT_RATE_2_3, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KVCO_CODE_OVRD_RATE1, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KVCO_CODE_OVRD_RATE2, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF1_RATE1, 0x15),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF2_RATE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF1_RATE2, 0x22),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF2_RATE2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KP_CODE_OVRD_RATE_2_3, 0x22),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND1_RATE1, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND2_RATE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND1_RATE2, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND2_RATE2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KP_CAL_LOWER_FREQ_DIFF_BND_RATE1, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_KP_CAL_LOWER_FREQ_DIFF_BND_RATE2, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_SUMMER_CAL_SPD_MODE_RATE_0123, 0x2f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_IVCM_CAL_CODE_OVERRIDE_RATE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_IVCM_CAL_CODE_OVERRIDE_RATE2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_IVCM_CAL_CTRL2, 0x85),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_IVCM_CAL_CTRL3, 0x45),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_IVCM_POSTCAL_OFFSET_RATE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_IVCM_POSTCAL_OFFSET_RATE2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_SIGDET_ENABLES, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_SIGDET_CNTRL, 0xa3),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_SIGDET_LVL, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_SIGDET_DEGLITCH_CNTRL, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_SIGDET_CAL_CTRL1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_SIGDET_CAL_CTRL2_AND_CDR_LOCK_EDGE, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_SIGDET_CAL_TRIM, 0x66),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_FREQ_LOCK_DET_DLY_RATE1, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_FREQ_LOCK_DET_DLY_RATE2, 0x32),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_CP_CUR_FLL_RATE1, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_CP_CUR_FLL_RATE2, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_CP_CUR_PLL_RATE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_CP_CUR_PLL_RATE2, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_LOOP_CCODE_RATE_01, 0x76),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_LOOP_CCODE_RATE_23, 0x67),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_LOOP_RCODE_FAST_RATE_0_1, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_LOOP_RCODE_FAST_RATE_2_3, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_LOOP_RCODE_FLL_RATE_0_1, 0x33),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_LOOP_RCODE_FLL_RATE_2_3, 0x43),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_LOOP_RCODE_PLL_RATE_0_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_LOOP_RCODE_PLL_RATE_2_3, 0x51),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_FLL_DIV_RATIO_RATE_0123, 0xe5),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_VCO_CAP_CODE_RATE_0123, 0xf5),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_VCO_TYPE_CONFIG, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_VCO_EN_LOWFREQ, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_LOOP_FUNC_CTRL, 0xd0),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_GM_CAL_EN, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_GM_CAL_RES_RATE0_1, 0x88),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_GM_CAL_RES_RATE2_3, 0x88),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_AUX_CLK_CTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_EOM_CTRL1, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_EQU_ADAPTOR_CNTRL2, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_EQU_ADAPTOR_CNTRL3, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RX_EQU_ADAPTOR_CNTRL4, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CTLE_POST_CAL_OFFSET_RATE_0_1_2, 0x77),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_VGA_CAL_CNTRL1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_VGA_CAL_MAN_VAL_RATE0_1, 0xdd),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_VGA_CAL_MAN_VAL_RATE2_3, 0xd8),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_DFE_TAP1_DAC_ENABLE, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_DFE_TAP2_DAC_ENABLE, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_DFE_TAP345_DAC_ENABLE, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_DFE_TAP67_DAC_ENABLE, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_IQTUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_IQTUNE_MAN_INDEX, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_IQTUNE_DIV2_CTRL_RATE0123, 0x1C),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CDR_VCO_CAP_CODE_OVRD_MUXES, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_DIG_BKUP_CTRL16, 0x37),
+};
+
static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),
@@ -1132,6 +1385,38 @@ static const struct qmp_phy_init_tbl qmp_v6_n4_dp_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0x0f),
};
+static const struct qmp_phy_init_tbl qmp_v8_dp_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_STEP_SIZE2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_RCTRL_MODE1, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_CCTRL_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CORECLK_DIV_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BG_TIMER, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_EN_CENTER, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_ADJ_PER1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_PER1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_PER2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CLK_ENABLE1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SYS_CLK_CTRL, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SYSCLK_BUF_ENABLE, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_IVCO, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SYSCLK_EN_SEL, 0x3b),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE_MAP, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CLK_SELECT, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CORE_CLK_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CMN_CONFIG_1, 0x56),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SVS_MODE_CLK_SEL, 0x15),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CMN_MODE_CONTD1, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DCC_CAL_1, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DCC_CAL_3, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PSM_CAL_EN, 0x01),
+};
+
static const struct qmp_phy_init_tbl qmp_v6_dp_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V6_TX_VMODE_CTRL1, 0x40),
QMP_PHY_INIT_CFG(QSERDES_V6_TX_PRE_STALL_LDO_BOOST_EN, 0x30),
@@ -1159,6 +1444,33 @@ static const struct qmp_phy_init_tbl qmp_v6_n4_dp_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_TX_BAND, 0x1),
};
+static const struct qmp_phy_init_tbl qmp_v8_n3p_dp_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TRANSMITTER_EN_CTRL, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_VMODE_CTRL1, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_ANA_INTERFACE_SELECT1, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_ANA_INTERFACE_SELECT2, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_PCS_INTERFACE_SELECT1, 0x50),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_LANE_MODE_1, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_CLKBUF_ENABLE, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_RESET_TSYNC_EN_CTRL, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX_LVL_UPDATE_CTRL, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TRAN_DRVR_EMP_EN, 0x5f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX0_EMP_POST1_LVL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX1_EMP_POST1_LVL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX0_PRE1_EMPH, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX1_PRE1_EMPH, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX0_DRV_LVL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX1_DRV_LVL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_HIGHZ_DRVR_EN, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_LANE_MODE_2, 0x50),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_LANE_MODE_3, 0x51),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX_DCC_ANA_CTRL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX0_RESTRIM_CAL_CTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX1_RESTRIM_CAL_CTRL, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX0_RESTRIM_POST_CAL_OFFSET, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V8_LALB_TX1_RESTRIM_POST_CAL_OFFSET, 0x10),
+};
+
static const struct qmp_phy_init_tbl qmp_v6_dp_serdes_tbl_rbr[] = {
QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x05),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x34),
@@ -1275,6 +1587,109 @@ static const struct qmp_phy_init_tbl qmp_v6_n4_dp_serdes_tbl_hbr3[] = {
QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01),
};
+static const struct qmp_phy_init_tbl qmp_v8_dp_serdes_tbl_rbr[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_HSCLK_SEL_1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x7a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE0, 0x83),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP1_MODE0, 0x37),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP2_MODE0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DEC_START_MODE0, 0x54),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE1_MODE0, 0xfe),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CMN_MODE_CONTD3, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_1, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_IP_CTRL_AND_DP_SEL, 0xa4),
+};
+
+static const struct qmp_phy_init_tbl qmp_v8_dp_serdes_tbl_hbr[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_HSCLK_SEL_1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x21),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP1_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP2_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DEC_START_MODE0, 0x46),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE0, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE1_MODE0, 0xae),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE2_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CMN_MODE_CONTD3, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_1, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_IP_CTRL_AND_DP_SEL, 0xa3),
+};
+
+static const struct qmp_phy_init_tbl qmp_v8_dp_serdes_tbl_hbr2[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_HSCLK_SEL_1, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xf6),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE0, 0x0),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP1_MODE0, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP2_MODE0, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DEC_START_MODE0, 0x46),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE0, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE1_MODE0, 0xae),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE2_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_IP_CTRL_AND_DP_SEL, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIAS_EN_CLKBUFLR_EN, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_RESETSM_CNTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CMN_MODE_CONTD3, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_1, 0x3f),
+};
+
+static const struct qmp_phy_init_tbl qmp_v8_dp_serdes_tbl_hbr3[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_HSCLK_SEL_1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x63),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE0, 0x5b),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_STEP_SIZE2_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CORECLK_DIV_MODE0, 0x0a),
+
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP1_MODE0, 0x17),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_LOCK_CMP2_MODE0, 0x15),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DEC_START_MODE0, 0x4f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE0, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE1_MODE0, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE2_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_ADJ_PER1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_PER1, 0x6b),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SSC_PER2, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CLK_ENABLE1, 0x0c),
+
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SYS_CLK_CTRL, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SYSCLK_BUF_ENABLE, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_PLL_IVCO, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SYSCLK_EN_SEL, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_VCO_TUNE_MAP, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CLK_SELECT, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CORE_CLK_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_SVS_MODE_CLK_SEL, 0x15),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_1, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIAS_EN_CLKBUFLR_EN, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CMN_MODE_CONTD3, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_CMN_MODE_CONTD1, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_USB43_COM_IP_CTRL_AND_DP_SEL, 0x84),
+};
+
static const struct qmp_phy_init_tbl sc8280xp_usb43dp_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER1, 0x31),
@@ -1649,6 +2064,12 @@ static struct regulator_bulk_data qmp_phy_vreg_l[] = {
{ .supply = "vdda-pll", .init_load_uA = 36000, },
};
+static struct regulator_bulk_data qmp_phy_vreg_refgen[] = {
+ { .supply = "vdda-phy", .init_load_uA = 21800 },
+ { .supply = "vdda-pll", .init_load_uA = 36000 },
+ { .supply = "refgen", .init_load_uA = 3270 },
+};
+
static const u8 qmp_dp_v3_pre_emphasis_hbr3_hbr2[4][4] = {
{ 0x00, 0x0c, 0x15, 0x1a },
{ 0x02, 0x0e, 0x16, 0xff },
@@ -1771,6 +2192,7 @@ struct qmp_combo_offsets {
u16 usb3_serdes;
u16 usb3_pcs_misc;
u16 usb3_pcs;
+ u16 usb3_pcs_aon;
u16 usb3_pcs_usb;
u16 dp_serdes;
u16 dp_txa;
@@ -1792,6 +2214,8 @@ struct qmp_phy_cfg {
int pcs_tbl_num;
const struct qmp_phy_init_tbl *pcs_usb_tbl;
int pcs_usb_tbl_num;
+ const struct qmp_phy_init_tbl *pcs_misc_tbl;
+ int pcs_misc_tbl_num;
const struct qmp_phy_init_tbl *dp_serdes_tbl;
int dp_serdes_tbl_num;
@@ -1815,6 +2239,7 @@ struct qmp_phy_cfg {
const u8 (*pre_emphasis_hbr3_hbr2)[4][4];
/* DP PHY callbacks */
+ int (*configure_dp_clocks)(struct qmp_combo *qmp);
int (*configure_dp_phy)(struct qmp_combo *qmp);
void (*configure_dp_tx)(struct qmp_combo *qmp);
int (*calibrate_dp_phy)(struct qmp_combo *qmp);
@@ -1836,6 +2261,7 @@ struct qmp_phy_cfg {
/* Offset from PCS to PCS_USB region */
unsigned int pcs_usb_offset;
+ bool invert_cc_polarity;
};
struct qmp_combo {
@@ -1852,6 +2278,7 @@ struct qmp_combo {
void __iomem *tx2;
void __iomem *rx2;
void __iomem *pcs_misc;
+ void __iomem *pcs_aon;
void __iomem *pcs_usb;
void __iomem *dp_serdes;
@@ -1891,6 +2318,7 @@ struct qmp_combo {
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_clocks(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);
@@ -1899,6 +2327,10 @@ 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 void qmp_v8_dp_aux_init(struct qmp_combo *qmp);
+static int qmp_v8_configure_dp_clocks(struct qmp_combo *qmp);
+static int qmp_v8_configure_dp_phy(struct qmp_combo *qmp);
+
static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
{
u32 reg;
@@ -1976,6 +2408,7 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v8 = {
.usb3_serdes = 0x1000,
.usb3_pcs_misc = 0x1c00,
.usb3_pcs = 0x1e00,
+ .usb3_pcs_aon = 0x2000,
.usb3_pcs_usb = 0x2100,
.dp_serdes = 0x3000,
.dp_txa = 0x3400,
@@ -1983,6 +2416,19 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v8 = {
.dp_dp_phy = 0x3c00,
};
+static const struct qmp_combo_offsets qmp_combo_usb43dp_offsets_v8 = {
+ .com = 0x0000,
+ .usb3_pcs_aon = 0x0100,
+ .usb3_serdes = 0x1000,
+ .usb3_pcs_misc = 0x1400,
+ .usb3_pcs = 0x1600,
+ .usb3_pcs_usb = 0x1900,
+ .dp_serdes = 0x2000,
+ .dp_dp_phy = 0x2400,
+ .txa = 0x4000,
+ .txb = 0x5000,
+};
+
static const struct qmp_phy_cfg sar2130p_usb3dpphy_cfg = {
.offsets = &qmp_combo_offsets_v3,
@@ -2018,6 +2464,7 @@ static const struct qmp_phy_cfg sar2130p_usb3dpphy_cfg = {
.dp_aux_init = qmp_v4_dp_aux_init,
.configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
.calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2026,6 +2473,7 @@ static const struct qmp_phy_cfg sar2130p_usb3dpphy_cfg = {
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .invert_cc_polarity = true,
};
static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = {
@@ -2153,6 +2601,7 @@ static const struct qmp_phy_cfg sc8180x_usb3dpphy_cfg = {
.dp_aux_init = qmp_v4_dp_aux_init,
.configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
.calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2199,6 +2648,7 @@ static const struct qmp_phy_cfg sc8280xp_usb43dpphy_cfg = {
.dp_aux_init = qmp_v4_dp_aux_init,
.configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
.calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2244,6 +2694,7 @@ static const struct qmp_phy_cfg x1e80100_usb3dpphy_cfg = {
.dp_aux_init = qmp_v4_dp_aux_init,
.configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
.calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2332,6 +2783,7 @@ static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = {
.dp_aux_init = qmp_v4_dp_aux_init,
.configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
.calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2380,6 +2832,7 @@ static const struct qmp_phy_cfg sm8350_usb3dpphy_cfg = {
.dp_aux_init = qmp_v4_dp_aux_init,
.configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
.calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2427,6 +2880,7 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = {
.dp_aux_init = qmp_v4_dp_aux_init,
.configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
.calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2472,6 +2926,7 @@ static const struct qmp_phy_cfg sm8650_usb3dpphy_cfg = {
.dp_aux_init = qmp_v4_dp_aux_init,
.configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
.calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2517,6 +2972,7 @@ static const struct qmp_phy_cfg sm8750_usb3dpphy_cfg = {
.dp_aux_init = qmp_v4_dp_aux_init,
.configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
.calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2527,6 +2983,52 @@ static const struct qmp_phy_cfg sm8750_usb3dpphy_cfg = {
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
};
+static const struct qmp_phy_cfg glymur_usb3dpphy_cfg = {
+ .offsets = &qmp_combo_usb43dp_offsets_v8,
+
+ .serdes_tbl = glymur_usb43dp_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(glymur_usb43dp_serdes_tbl),
+ .tx_tbl = glymur_usb43dp_lalb_tbl,
+ .tx_tbl_num = ARRAY_SIZE(glymur_usb43dp_lalb_tbl),
+ .pcs_tbl = glymur_usb43dp_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(glymur_usb43dp_pcs_tbl),
+ .pcs_usb_tbl = glymur_usb43dp_pcs_usb_tbl,
+ .pcs_usb_tbl_num = ARRAY_SIZE(glymur_usb43dp_pcs_usb_tbl),
+ .pcs_misc_tbl = glymur_usb43dp_pcs_misc_tbl,
+ .pcs_misc_tbl_num = ARRAY_SIZE(glymur_usb43dp_pcs_misc_tbl),
+
+ .dp_serdes_tbl = qmp_v8_dp_serdes_tbl,
+ .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v8_dp_serdes_tbl),
+ .dp_tx_tbl = qmp_v8_n3p_dp_tx_tbl,
+ .dp_tx_tbl_num = ARRAY_SIZE(qmp_v8_n3p_dp_tx_tbl),
+
+ .serdes_tbl_rbr = qmp_v8_dp_serdes_tbl_rbr,
+ .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v8_dp_serdes_tbl_rbr),
+ .serdes_tbl_hbr = qmp_v8_dp_serdes_tbl_hbr,
+ .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v8_dp_serdes_tbl_hbr),
+ .serdes_tbl_hbr2 = qmp_v8_dp_serdes_tbl_hbr2,
+ .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v8_dp_serdes_tbl_hbr2),
+ .serdes_tbl_hbr3 = qmp_v8_dp_serdes_tbl_hbr3,
+ .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v8_dp_serdes_tbl_hbr3),
+
+ .swing_hbr_rbr = &qmp_dp_v6_voltage_swing_hbr_rbr,
+ .pre_emphasis_hbr_rbr = &qmp_dp_v6_pre_emphasis_hbr_rbr,
+ .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_v8_dp_aux_init,
+ .configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_clocks = qmp_v8_configure_dp_clocks,
+ .configure_dp_phy = qmp_v8_configure_dp_phy,
+ .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
+
+ .regs = qmp_v8_n3_usb43dpphy_regs_layout,
+ .reset_list = msm8996_usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
+ .vreg_list = qmp_phy_vreg_refgen,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_refgen),
+};
+
static int qmp_combo_dp_serdes_init(struct qmp_combo *qmp)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -2689,7 +3191,7 @@ static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp)
return reverse;
}
-static int qmp_combo_configure_dp_clocks(struct qmp_combo *qmp)
+static int qmp_v3_configure_dp_clocks(struct qmp_combo *qmp)
{
const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
u32 phy_vco_div;
@@ -2736,7 +3238,7 @@ static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp)
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);
- ret = qmp_combo_configure_dp_clocks(qmp);
+ ret = qmp_v3_configure_dp_clocks(qmp);
if (ret)
return ret;
@@ -2822,6 +3324,35 @@ static void qmp_v4_dp_aux_init(struct qmp_combo *qmp)
qmp->dp_dp_phy + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK);
}
+static void qmp_v8_dp_aux_init(struct qmp_combo *qmp)
+{
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+
+ 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,
+ qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ /* Turn on BIAS current for PHY/PLL */
+ writel(0x1c, qmp->dp_serdes + cfg->regs[QPHY_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(0x06, 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,
+ qmp->dp_dp_phy + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK);
+}
+
static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -2836,6 +3367,58 @@ static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp)
qmp_combo_configure_dp_swing(qmp);
}
+static int qmp_v8_configure_dp_clocks(struct qmp_combo *qmp)
+{
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+ u32 phy_vco_div;
+ unsigned long pixel_freq;
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ phy_vco_div = 0x4;
+ pixel_freq = 1620000000UL / 2;
+ break;
+ case 2700:
+ phy_vco_div = 0x2;
+ pixel_freq = 2700000000UL / 2;
+ break;
+ case 5400:
+ phy_vco_div = 0x4;
+ pixel_freq = 5400000000UL / 4;
+ break;
+ case 8100:
+ phy_vco_div = 0x3;
+ pixel_freq = 8100000000UL / 6;
+ break;
+ default:
+ /* Other link rates aren't supported */
+ return -EINVAL;
+ }
+ writel(phy_vco_div, qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_VCO_DIV]);
+
+ /* disable core reset tsync */
+ writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+
+ writel(0x04, qmp->dp_dp_phy + QSERDES_V8_DP_PHY_AUXLESS_SETUP_CYC);
+ writel(0x08, qmp->dp_dp_phy + QSERDES_V8_DP_PHY_AUXLESS_SILENCE_CYC);
+ writel(0x08, qmp->dp_dp_phy + QSERDES_V8_DP_PHY_LFPS_CYC);
+ writel(0x11, qmp->dp_dp_phy + QSERDES_V8_DP_PHY_LFPS_PERIOD);
+
+ writel(0x3e, qmp->dp_dp_phy + QSERDES_V8_DP_PHY_TSYNC_OVRD);
+ writel(0x05, qmp->dp_dp_phy + QSERDES_V8_DP_PHY_TX2_TX3_LANE_CTL);
+ writel(0x05, qmp->dp_dp_phy + QSERDES_V8_DP_PHY_TX0_TX1_LANE_CTL);
+ writel(0x01, qmp->dp_dp_phy + QSERDES_V8_DP_PHY_AUXLESS_CFG1);
+ writel(0x11, qmp->dp_dp_phy + QSERDES_V8_DP_PHY_LFPS_PERIOD);
+ writel(0x1f, qmp->dp_dp_phy + QSERDES_V8_DP_PHY_LN0_DRV_LVL);
+ writel(0x1f, qmp->dp_dp_phy + QSERDES_V8_DP_PHY_LN1_DRV_LVL);
+
+ clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000);
+ clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq);
+
+ return 0;
+}
+
static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -2852,7 +3435,7 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp)
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);
- ret = qmp_combo_configure_dp_clocks(qmp);
+ ret = qmp->cfg->configure_dp_clocks(qmp);
if (ret)
return ret;
@@ -2966,6 +3549,62 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp)
return 0;
}
+static int qmp_v8_configure_dp_phy(struct qmp_combo *qmp)
+{
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+ u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
+ u32 status;
+ int ret;
+
+ ret = qmp_v456_configure_dp_phy(qmp);
+ if (ret < 0)
+ return ret;
+
+ if (dp_opts->lanes == 1) {
+ bias0_en = reverse ? 0x3e : 0x15;
+ bias1_en = reverse ? 0x15 : 0x3e;
+ drvr0_en = reverse ? 0x13 : 0x10;
+ drvr1_en = reverse ? 0x10 : 0x13;
+ } else if (dp_opts->lanes == 2) {
+ bias0_en = reverse ? 0x3f : 0x15;
+ bias1_en = reverse ? 0x15 : 0x3f;
+ drvr0_en = 0x10;
+ drvr1_en = 0x10;
+ } else {
+ bias0_en = 0x3f;
+ bias1_en = 0x3f;
+ drvr0_en = 0x34;
+ drvr1_en = 0x34;
+ }
+
+ writel(drvr0_en, qmp->dp_tx + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]);
+ writel(bias0_en, qmp->dp_tx + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]);
+ writel(drvr1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]);
+ writel(bias1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]);
+
+ writel(0x08, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ udelay(100);
+ writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ udelay(500);
+
+ if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS],
+ status,
+ ((status & BIT(1)) > 0),
+ 500,
+ 10000))
+ return -ETIMEDOUT;
+
+ writel(0x00, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]);
+ writel(0x00, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]);
+
+ writel(0x2b, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]);
+ writel(0x2b, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]);
+
+ return 0;
+}
+
/*
* We need to calibrate the aux setting here as many times
* as the caller tries
@@ -3023,6 +3662,7 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *com = qmp->com;
+ void __iomem *pcs_aon = qmp->pcs_aon;
int ret;
u32 val;
@@ -3058,10 +3698,20 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force)
SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
+ /* override hardware control for reset of qmp phy */
+ if (pcs_aon && cfg->regs[QPHY_AON_TOGGLE_ENABLE]) {
+ qphy_clrbits(pcs_aon, cfg->regs[QPHY_AON_TOGGLE_ENABLE], 0x1);
+ qphy_clrbits(pcs_aon, cfg->regs[QPHY_DP_AON_TOGGLE_ENABLE], 0x1);
+ }
+
/* Use software based port select and switch on typec orientation */
val = SW_PORTSELECT_MUX;
if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
val |= SW_PORTSELECT_VAL;
+
+ if (cfg->invert_cc_polarity)
+ val |= INVERT_CC_POLARITY;
+
writel(val, com + QPHY_V3_DP_COM_TYPEC_CTRL);
switch (qmp->qmpphy_mode) {
@@ -3235,6 +3885,8 @@ static int qmp_combo_usb_power_on(struct phy *phy)
qmp_configure_lane(qmp->dev, rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
qmp_configure(qmp->dev, pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
+ qmp_configure(qmp->dev, qmp->pcs_misc, cfg->pcs_misc_tbl, cfg->pcs_misc_tbl_num);
+
if (pcs_usb)
qmp_configure(qmp->dev, pcs_usb, cfg->pcs_usb_tbl,
@@ -3361,6 +4013,7 @@ static void qmp_combo_enable_autonomous_mode(struct qmp_combo *qmp)
const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs;
void __iomem *pcs_misc = qmp->pcs_misc;
+ void __iomem *pcs_aon = qmp->pcs_aon;
u32 intr_mask;
if (qmp->phy_mode == PHY_MODE_USB_HOST_SS ||
@@ -3380,9 +4033,14 @@ static void qmp_combo_enable_autonomous_mode(struct qmp_combo *qmp)
/* Enable required PHY autonomous mode interrupts */
qphy_setbits(pcs_usb, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask);
- /* Enable i/o clamp_n for autonomous mode */
- if (pcs_misc)
- qphy_clrbits(pcs_misc, QPHY_V3_PCS_MISC_CLAMP_ENABLE, CLAMP_EN);
+ /*
+ * Enable i/o clamp_n for autonomous mode
+ * V6 and later versions use pcs aon clamp register
+ */
+ if (pcs_aon)
+ qphy_clrbits(pcs_aon, cfg->regs[QPHY_PCS_CLAMP_ENABLE], CLAMP_EN);
+ else if (pcs_misc)
+ qphy_clrbits(pcs_misc, cfg->regs[QPHY_PCS_CLAMP_ENABLE], CLAMP_EN);
}
static void qmp_combo_disable_autonomous_mode(struct qmp_combo *qmp)
@@ -3390,10 +4048,13 @@ static void qmp_combo_disable_autonomous_mode(struct qmp_combo *qmp)
const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs;
void __iomem *pcs_misc = qmp->pcs_misc;
+ void __iomem *pcs_aon = qmp->pcs_aon;
/* Disable i/o clamp_n on resume for normal mode */
- if (pcs_misc)
- qphy_setbits(pcs_misc, QPHY_V3_PCS_MISC_CLAMP_ENABLE, CLAMP_EN);
+ if (pcs_aon)
+ qphy_setbits(pcs_aon, cfg->regs[QPHY_PCS_CLAMP_ENABLE], CLAMP_EN);
+ else if (pcs_misc)
+ qphy_setbits(pcs_misc, cfg->regs[QPHY_PCS_CLAMP_ENABLE], CLAMP_EN);
qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL],
ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN);
@@ -4058,6 +4719,8 @@ static int qmp_combo_parse_dt(struct qmp_combo *qmp)
qmp->serdes = base + offs->usb3_serdes;
qmp->pcs_misc = base + offs->usb3_pcs_misc;
qmp->pcs = base + offs->usb3_pcs;
+ if (offs->usb3_pcs_aon)
+ qmp->pcs_aon = base + offs->usb3_pcs_aon;
qmp->pcs_usb = base + offs->usb3_pcs_usb;
qmp->dp_serdes = base + offs->dp_serdes;
@@ -4320,6 +4983,10 @@ err_node_put:
static const struct of_device_id qmp_combo_of_match_table[] = {
{
+ .compatible = "qcom,glymur-qmp-usb3-dp-phy",
+ .data = &glymur_usb3dpphy_cfg,
+ },
+ {
.compatible = "qcom,sar2130p-qmp-usb3-dp-phy",
.data = &sar2130p_usb3dpphy_cfg,
},
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h
new file mode 100644
index 000000000000..8b9572d3cdeb
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v2.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_DP_PHY_V2_H_
+#define QCOM_PHY_QMP_DP_PHY_V2_H_
+
+// /* Only for QMP V2 PHY - DP PHY registers */
+#define QSERDES_V2_DP_PHY_AUX_INTERRUPT_MASK 0x048
+#define QSERDES_V2_DP_PHY_AUX_INTERRUPT_CLEAR 0x04c
+#define QSERDES_V2_DP_PHY_AUX_BIST_CFG 0x050
+
+#define QSERDES_V2_DP_PHY_VCO_DIV 0x068
+#define QSERDES_V2_DP_PHY_TX0_TX1_LANE_CTL 0x06c
+#define QSERDES_V2_DP_PHY_TX2_TX3_LANE_CTL 0x088
+
+#define QSERDES_V2_DP_PHY_SPARE0 0x0ac
+#define QSERDES_V2_DP_PHY_STATUS 0x0c0
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v8.h
new file mode 100644
index 000000000000..b6a8ab59c2ff
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v8.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_DP_PHY_V8_H_
+#define QCOM_PHY_QMP_DP_PHY_V8_H_
+
+/* Only for QMP V8 PHY - DP PHY registers */
+#define QSERDES_V8_DP_PHY_VCO_DIV 0x070
+#define QSERDES_V8_DP_PHY_AUX_INTERRUPT_STATUS 0x0e0
+#define QSERDES_V8_DP_PHY_TSYNC_OVRD 0x074
+#define QSERDES_V8_DP_PHY_TX0_TX1_LANE_CTL 0x078
+#define QSERDES_V8_DP_PHY_TX2_TX3_LANE_CTL 0x0bc
+#define QSERDES_V8_DP_PHY_AUXLESS_CFG1 0x0c8
+#define QSERDES_V8_DP_PHY_LFPS_PERIOD 0x0d0
+#define QSERDES_V8_DP_PHY_LFPS_CYC 0x0d4
+#define QSERDES_V8_DP_PHY_AUXLESS_SETUP_CYC 0x0d8
+#define QSERDES_V8_DP_PHY_AUXLESS_SILENCE_CYC 0x0d8
+#define QSERDES_V8_DP_PHY_LN0_DRV_LVL 0x0e0
+#define QSERDES_V8_DP_PHY_LN1_DRV_LVL 0x0e4
+#define QSERDES_V8_DP_PHY_STATUS 0x114
+
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-qserdes-com-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-qserdes-com-v8.h
new file mode 100644
index 000000000000..2bef1eecdc56
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-qserdes-com-v8.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 Linaro Ltd.
+ */
+
+#ifndef QCOM_PHY_QMP_DP_QSERDES_COM_V8_H_
+#define QCOM_PHY_QMP_DP_QSERDES_COM_V8_H_
+
+/* Only for DP QMP V8 PHY - QSERDES COM registers */
+#define DP_QSERDES_V8_COM_HSCLK_SEL_1 0x03c
+#define DP_QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x058
+#define DP_QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x05c
+#define DP_QSERDES_V8_COM_SSC_STEP_SIZE1_MODE0 0x060
+#define DP_QSERDES_V8_COM_SSC_STEP_SIZE2_MODE0 0x064
+#define DP_QSERDES_V8_COM_CP_CTRL_MODE0 0x070
+#define DP_QSERDES_V8_COM_PLL_RCTRL_MODE0 0x074
+#define DP_QSERDES_V8_COM_PLL_CCTRL_MODE0 0x078
+#define DP_QSERDES_V8_COM_CORECLK_DIV_MODE0 0x07c
+#define DP_QSERDES_V8_COM_LOCK_CMP1_MODE0 0x080
+#define DP_QSERDES_V8_COM_LOCK_CMP2_MODE0 0x084
+#define DP_QSERDES_V8_COM_DEC_START_MODE0 0x088
+#define DP_QSERDES_V8_COM_DIV_FRAC_START1_MODE0 0x090
+#define DP_QSERDES_V8_COM_DIV_FRAC_START2_MODE0 0x094
+#define DP_QSERDES_V8_COM_DIV_FRAC_START3_MODE0 0x098
+#define DP_QSERDES_V8_COM_INTEGLOOP_GAIN0_MODE0 0x0a0
+#define DP_QSERDES_V8_COM_VCO_TUNE1_MODE0 0x0a8
+#define DP_QSERDES_V8_COM_INTEGLOOP_GAIN1_MODE0 0x0a4
+#define DP_QSERDES_V8_COM_VCO_TUNE2_MODE0 0x0ac
+#define DP_QSERDES_V8_COM_BG_TIMER 0x0bc
+#define DP_QSERDES_V8_COM_SSC_EN_CENTER 0x0c0
+#define DP_QSERDES_V8_COM_SSC_ADJ_PER1 0x0c4
+#define DP_QSERDES_V8_COM_SSC_PER1 0x0cc
+#define DP_QSERDES_V8_COM_SSC_PER2 0x0d0
+#define DP_QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN 0x0dc
+#define DP_QSERDES_V8_COM_CLK_ENABLE1 0x0e0
+#define DP_QSERDES_V8_COM_SYS_CLK_CTRL 0x0e4
+#define DP_QSERDES_V8_COM_SYSCLK_BUF_ENABLE 0x0e8
+#define DP_QSERDES_V8_COM_PLL_IVCO 0x0f4
+#define DP_QSERDES_V8_COM_SYSCLK_EN_SEL 0x110
+#define DP_QSERDES_V8_COM_RESETSM_CNTRL 0x118
+#define DP_QSERDES_V8_COM_LOCK_CMP_EN 0x120
+#define DP_QSERDES_V8_COM_VCO_TUNE_CTRL 0x13c
+#define DP_QSERDES_V8_COM_VCO_TUNE_MAP 0x140
+#define DP_QSERDES_V8_COM_CLK_SELECT 0x164
+#define DP_QSERDES_V8_COM_CORE_CLK_EN 0x170
+#define DP_QSERDES_V8_COM_CMN_CONFIG_1 0x174
+#define DP_QSERDES_V8_COM_SVS_MODE_CLK_SEL 0x180
+#define DP_QSERDES_V8_COM_CLK_FWD_CONFIG_1 0x2f4
+#define DP_QSERDES_V8_COM_CMN_STATUS 0x314
+#define DP_QSERDES_V8_COM_C_READY_STATUS 0x33c
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
index 86b1b7e2da86..fed2fc9bb311 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
@@ -37,6 +37,9 @@
#include "phy-qcom-qmp-pcs-pcie-v6_30.h"
#include "phy-qcom-qmp-pcs-v6_30.h"
#include "phy-qcom-qmp-pcie-qhp.h"
+#include "phy-qcom-qmp-qserdes-com-v8.h"
+#include "phy-qcom-qmp-pcs-pcie-v8.h"
+#include "phy-qcom-qmp-qserdes-txrx-pcie-v8.h"
#define PHY_INIT_COMPLETE_TIMEOUT 10000
@@ -100,6 +103,13 @@ static const unsigned int pciephy_v7_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V7_PCS_POWER_DOWN_CONTROL,
};
+static const unsigned int pciephy_v8_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_SW_RESET] = QPHY_V8_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V8_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V8_PCS_PCS_STATUS1,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V8_PCS_POWER_DOWN_CONTROL,
+};
+
static const unsigned int pciephy_v8_50_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_START_CTRL] = QPHY_V8_50_PCS_START_CONTROL,
[QPHY_PCS_STATUS] = QPHY_V8_50_PCS_STATUS1,
@@ -3067,6 +3077,149 @@ static const struct qmp_phy_init_tbl sar2130p_qmp_gen3x2_pcie_ep_pcs_misc_tbl[]
QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG4, 0x07),
};
+static const struct qmp_phy_init_tbl kaanapali_qmp_gen3x2_pcie_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_STEP_SIZE1_MODE1, 0x93),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_STEP_SIZE2_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CORECLK_DIV_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP1_MODE1, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP2_MODE1, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DEC_START_MODE1, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START1_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START2_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START3_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_HSCLK_SEL_1, 0x01),
+
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_STEP_SIZE1_MODE0, 0xf8),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_STEP_SIZE2_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CORECLK_DIV_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP1_MODE0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP2_MODE0, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DEC_START_MODE0, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START1_MODE0, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START2_MODE0, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START3_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_BG_TIMER, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_PER1, 0x62),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_PER2, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CLK_ENABLE1, 0x90),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SYS_CLK_CTRL, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SYSCLK_EN_SEL, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP_EN, 0x46),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP_CFG, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_VCO_TUNE_MAP, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CLK_SELECT, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CORE_CLK_EN, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CMN_MISC_1, 0x88),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CMN_MODE, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_VCO_DC_LEVEL_CTRL, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_SPARE_FOR_ECO, 0x02),
+};
+
+static const struct qmp_phy_init_tbl kaanapali_qmp_gen3x2_pcie_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_RES_CODE_LANE_OFFSET_TX, 0x1b),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_RES_CODE_LANE_OFFSET_RX, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_LANE_MODE_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_LANE_MODE_2, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_LANE_MODE_3, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_TRAN_DRVR_EMP_EN, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_TX_BAND0, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_TX_BAND1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_SEL_10B_8B, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_SEL_20B_10B, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_PARRATE_REC_DETECT_IDLE_EN, 0x90),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_TX_ADAPT_POST_THRESH1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_TX_ADAPT_POST_THRESH2, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_EQ_RCF_CTRL_RATE3, 0x53),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_EQ_RCF_CTRL_RATE4, 0x54),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_TX_PHPRE_CTRL, 0x20),
+};
+
+static const struct qmp_phy_init_tbl kaanapali_qmp_gen3x2_pcie_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_UCDR_FO_GAIN_RATE4, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_UCDR_SO_GAIN_RATE3, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_UCDR_SO_GAIN_RATE4, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_UCDR_PI_CONTROLS, 0x15),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_VGA_CAL_CNTRL1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_VGA_CAL_MAN_VAL, 0x89),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_EQU_ADAPTOR_CNTRL4, 0x2d),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_SIGDET_ENABLES, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_SIGDET_LVL, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RXCLK_DIV2_CTRL, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_BAND_CTRL0, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_TERM_BW_CTRL0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_TERM_BW_CTRL1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_SVS_MODE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_UCDR_PI_CTRL1, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_UCDR_PI_CTRL2, 0x42),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_UCDR_SB2_THRESH2_RATE3, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_UCDR_SB2_GAIN1_RATE3, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_UCDR_SB2_GAIN2_RATE3, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE_0_1_B0, 0xc2),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE_0_1_B1, 0xc2),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE_0_1_B2, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE_0_1_B4, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE_0_1_B7, 0x62),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE3_B0, 0xe4),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE3_B1, 0x63),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE3_B2, 0xd8),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE3_B3, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE3_B4, 0x67),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B0, 0xa4),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B1, 0xa4),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B2, 0x28),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B3, 0x9f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B4, 0x48),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B5, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_Q_PI_INTRINSIC_BIAS_RATE32, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_Q_PI_INTRINSIC_BIAS_RATE4, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_EOM_MAX_ERR_LIMIT_LSB, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_EOM_MAX_ERR_LIMIT_MSB, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_AUXDATA_BIN_RATE23, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_AUXDATA_BIN_RATE4, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_VTHRESH_CAL_MAN_VAL_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_VTHRESH_CAL_MAN_VAL_RATE4, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_PCIE_RX_GM_CAL, 0x0d),
+};
+
+static const struct qmp_phy_init_tbl kaanapali_qmp_gen3x2_pcie_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_G12S1_TXDEEMPH_M6DB, 0x17),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_G3S2_PRE_GAIN, 0x2e),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_RX_SIGDET_LVL, 0xcc),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_ELECIDLE_DLY_SEL, 0x40),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_PCS_TX_RX_CONFIG1, 0x04),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_PCS_TX_RX_CONFIG2, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_EQ_CONFIG4, 0x00),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_EQ_CONFIG5, 0x22),
+};
+
+static const struct qmp_phy_init_tbl kaanapali_qmp_gen3x2_pcie_pcs_misc_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_TX_RX_CONFIG, 0xc0),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_POWER_STATE_CONFIG2, 0x1d),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_ENDPOINT_REFCLK_DRIVE, 0xc1),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_OSC_DTCT_ACTIONS, 0x00),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_EQ_CONFIG1, 0x16),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_G3_RXEQEVAL_TIME, 0x27),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_G4_RXEQEVAL_TIME, 0x27),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_G4_EQ_CONFIG5, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_G4_PRE_GAIN, 0x2e),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_RX_MARGINING_CONFIG1, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_RX_MARGINING_CONFIG3, 0x28),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_RX_MARGINING_CONFIG5, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_G3_FOM_EQ_CONFIG5, 0xf2),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_G4_FOM_EQ_CONFIG5, 0xf2),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V8_PCS_POWER_STATE_CONFIG6, 0x1f),
+};
+
struct qmp_pcie_offsets {
u16 serdes;
u16 pcs;
@@ -3363,6 +3516,16 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_30 = {
.ln_shrd = 0x8000,
};
+static const struct qmp_pcie_offsets qmp_pcie_offsets_v8_0 = {
+ .serdes = 0x1000,
+ .pcs = 0x1400,
+ .pcs_misc = 0x1800,
+ .tx = 0x0000,
+ .rx = 0x0200,
+ .tx2 = 0x0800,
+ .rx2 = 0x0a00,
+};
+
static const struct qmp_pcie_offsets qmp_pcie_offsets_v8_50 = {
.serdes = 0x8000,
.pcs = 0x9000,
@@ -4425,6 +4588,34 @@ static const struct qmp_phy_cfg qmp_v6_gen4x4_pciephy_cfg = {
.phy_status = PHYSTATUS_4_20,
};
+static const struct qmp_phy_cfg qmp_v8_gen3x2_pciephy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_pcie_offsets_v8_0,
+
+ .tbls = {
+ .serdes = kaanapali_qmp_gen3x2_pcie_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(kaanapali_qmp_gen3x2_pcie_serdes_tbl),
+ .tx = kaanapali_qmp_gen3x2_pcie_tx_tbl,
+ .tx_num = ARRAY_SIZE(kaanapali_qmp_gen3x2_pcie_tx_tbl),
+ .rx = kaanapali_qmp_gen3x2_pcie_rx_tbl,
+ .rx_num = ARRAY_SIZE(kaanapali_qmp_gen3x2_pcie_rx_tbl),
+ .pcs = kaanapali_qmp_gen3x2_pcie_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(kaanapali_qmp_gen3x2_pcie_pcs_tbl),
+ .pcs_misc = kaanapali_qmp_gen3x2_pcie_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(kaanapali_qmp_gen3x2_pcie_pcs_misc_tbl),
+ },
+
+ .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 = pciephy_v8_regs_layout,
+
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS_4_20,
+};
+
static const struct qmp_phy_cfg glymur_qmp_gen5x4_pciephy_cfg = {
.lanes = 4,
@@ -4441,6 +4632,22 @@ static const struct qmp_phy_cfg glymur_qmp_gen5x4_pciephy_cfg = {
.phy_status = PHYSTATUS_4_20,
};
+static const struct qmp_phy_cfg glymur_qmp_gen4x2_pciephy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_pcie_offsets_v8_0,
+
+ .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 = pciephy_v8_regs_layout,
+
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS_4_20,
+};
+
static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -5192,6 +5399,9 @@ err_node_put:
static const struct of_device_id qmp_pcie_of_match_table[] = {
{
+ .compatible = "qcom,glymur-qmp-gen4x2-pcie-phy",
+ .data = &glymur_qmp_gen4x2_pciephy_cfg,
+ }, {
.compatible = "qcom,glymur-qmp-gen5x4-pcie-phy",
.data = &glymur_qmp_gen5x4_pciephy_cfg,
}, {
@@ -5210,6 +5420,9 @@ static const struct of_device_id qmp_pcie_of_match_table[] = {
.compatible = "qcom,ipq9574-qmp-gen3x2-pcie-phy",
.data = &ipq9574_gen3x2_pciephy_cfg,
}, {
+ .compatible = "qcom,kaanapali-qmp-gen3x2-pcie-phy",
+ .data = &qmp_v8_gen3x2_pciephy_cfg,
+ }, {
.compatible = "qcom,msm8998-qmp-pcie-phy",
.data = &msm8998_pciephy_cfg,
}, {
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v6.h
new file mode 100644
index 000000000000..52db31a7cf22
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v6.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_AON_V6_H_
+#define QCOM_PHY_QMP_PCS_AON_V6_H_
+
+/* Only for QMP V6 PHY - PCS_AON registers */
+#define QPHY_V6_PCS_AON_CLAMP_ENABLE 0x00
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v8.h
new file mode 100644
index 000000000000..f6a275c0938f
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v8.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_AON_V8_H_
+#define QCOM_PHY_QMP_PCS_AON_V8_H_
+
+/* Only for QMP V8 PHY - PCS_AON registers */
+#define QPHY_V8_PCS_AON_USB3_AON_CLAMP_ENABLE 0x00
+#define QPHY_V8_PCS_AON_USB4_AON_CLAMP_ENABLE 0x04
+#define QPHY_V8_PCS_AON_USB3_AON_TOGGLE_ENABLE 0x08
+#define QPHY_V8_PCS_AON_USB4_AON_TOGGLE_ENABLE 0x0c
+#define QPHY_V8_PCS_AON_DP_AON_TOGGLE_ENABLE 0x10
+#define QPHY_V8_PCS_AON_DUMMY_STATUS 0x14
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v5.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v5.h
new file mode 100644
index 000000000000..77d04c6a1644
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v5.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_MISC_V5_H_
+#define QCOM_PHY_QMP_PCS_MISC_V5_H_
+
+/* Only for QMP V5 PHY - PCS_MISC registers */
+#define QPHY_V5_PCS_MISC_CLAMP_ENABLE 0x0c
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v8.h
new file mode 100644
index 000000000000..a93ef2faa894
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v8.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_MISC_V8_H_
+#define QCOM_PHY_QMP_PCS_MISC_V8_H_
+
+/* Only for QMP V8 PHY - PCS_MISC registers */
+#define QPHY_V8_PCS_MISC_PCS_MISC_CONFIG1 0x08
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v8.h
new file mode 100644
index 000000000000..1e06aa9d73d5
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v8.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_PCIE_V8_H_
+#define QCOM_PHY_QMP_PCS_PCIE_V8_H_
+
+/* Only for QMP V8 PHY - PCIE PCS registers */
+
+#define QPHY_PCIE_V8_PCS_POWER_STATE_CONFIG2 0x00c
+#define QPHY_PCIE_V8_PCS_TX_RX_CONFIG 0x018
+#define QPHY_PCIE_V8_PCS_ENDPOINT_REFCLK_DRIVE 0x01c
+#define QPHY_PCIE_V8_PCS_OSC_DTCT_ACTIONS 0x090
+#define QPHY_PCIE_V8_PCS_EQ_CONFIG1 0x0a0
+#define QPHY_PCIE_V8_PCS_G3_RXEQEVAL_TIME 0x0f0
+#define QPHY_PCIE_V8_PCS_G4_RXEQEVAL_TIME 0x0f4
+#define QPHY_PCIE_V8_PCS_G4_EQ_CONFIG5 0x108
+#define QPHY_PCIE_V8_PCS_G4_PRE_GAIN 0x15c
+#define QPHY_PCIE_V8_PCS_G12S1_TXDEEMPH_M6DB 0x170
+#define QPHY_PCIE_V8_PCS_G3S2_PRE_GAIN 0x178
+#define QPHY_PCIE_V8_PCS_RX_MARGINING_CONFIG1 0x17c
+#define QPHY_PCIE_V8_PCS_RX_MARGINING_CONFIG3 0x184
+#define QPHY_PCIE_V8_PCS_RX_MARGINING_CONFIG5 0x18c
+#define QPHY_PCIE_V8_PCS_RX_SIGDET_LVL 0x190
+#define QPHY_PCIE_V8_PCS_G3_FOM_EQ_CONFIG5 0x1ac
+#define QPHY_PCIE_V8_PCS_ELECIDLE_DLY_SEL 0x1b8
+#define QPHY_PCIE_V8_PCS_G4_FOM_EQ_CONFIG5 0x1c0
+#define QPHY_PCIE_V8_PCS_POWER_STATE_CONFIG6 0x1d0
+#define QPHY_PCIE_V8_PCS_PCS_TX_RX_CONFIG1 0x1dc
+#define QPHY_PCIE_V8_PCS_PCS_TX_RX_CONFIG2 0x1e0
+#define QPHY_PCIE_V8_PCS_EQ_CONFIG4 0x1f8
+#define QPHY_PCIE_V8_PCS_EQ_CONFIG5 0x1fc
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h
new file mode 100644
index 000000000000..3ea1884f35dd
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v2.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_COM_V2_H_
+#define QCOM_PHY_QMP_QSERDES_COM_V2_H_
+
+/* Only for QMP V2 PHY - QSERDES COM registers */
+#define QSERDES_V2_COM_ATB_SEL1 0x000
+#define QSERDES_V2_COM_ATB_SEL2 0x004
+#define QSERDES_V2_COM_FREQ_UPDATE 0x008
+#define QSERDES_V2_COM_BG_TIMER 0x00c
+#define QSERDES_V2_COM_SSC_EN_CENTER 0x010
+#define QSERDES_V2_COM_SSC_ADJ_PER1 0x014
+#define QSERDES_V2_COM_SSC_ADJ_PER2 0x018
+#define QSERDES_V2_COM_SSC_PER1 0x01c
+#define QSERDES_V2_COM_SSC_PER2 0x020
+#define QSERDES_V2_COM_SSC_STEP_SIZE1 0x024
+#define QSERDES_V2_COM_SSC_STEP_SIZE2 0x028
+#define QSERDES_V2_COM_POST_DIV 0x02c
+#define QSERDES_V2_COM_POST_DIV_MUX 0x030
+#define QSERDES_V2_COM_BIAS_EN_CLKBUFLR_EN 0x034
+#define QSERDES_V2_COM_CLK_ENABLE1 0x038
+#define QSERDES_V2_COM_SYS_CLK_CTRL 0x03c
+#define QSERDES_V2_COM_SYSCLK_BUF_ENABLE 0x040
+#define QSERDES_V2_COM_PLL_EN 0x044
+#define QSERDES_V2_COM_PLL_IVCO 0x048
+#define QSERDES_V2_COM_LOCK_CMP1_MODE0 0x04c
+#define QSERDES_V2_COM_LOCK_CMP2_MODE0 0x050
+#define QSERDES_V2_COM_LOCK_CMP3_MODE0 0x054
+#define QSERDES_V2_COM_LOCK_CMP1_MODE1 0x058
+#define QSERDES_V2_COM_LOCK_CMP2_MODE1 0x05c
+#define QSERDES_V2_COM_LOCK_CMP3_MODE1 0x060
+#define QSERDES_V2_COM_EP_CLOCK_DETECT_CTR 0x068
+#define QSERDES_V2_COM_SYSCLK_DET_COMP_STATUS 0x06c
+#define QSERDES_V2_COM_CLK_EP_DIV 0x074
+#define QSERDES_V2_COM_CP_CTRL_MODE0 0x078
+#define QSERDES_V2_COM_CP_CTRL_MODE1 0x07c
+#define QSERDES_V2_COM_PLL_RCTRL_MODE0 0x084
+#define QSERDES_V2_COM_PLL_RCTRL_MODE1 0x088
+#define QSERDES_V2_COM_PLL_CCTRL_MODE0 0x090
+#define QSERDES_V2_COM_PLL_CCTRL_MODE1 0x094
+#define QSERDES_V2_COM_PLL_CNTRL 0x09c
+#define QSERDES_V2_COM_BIAS_EN_CTRL_BY_PSM 0x0a8
+#define QSERDES_V2_COM_SYSCLK_EN_SEL 0x0ac
+#define QSERDES_V2_COM_CML_SYSCLK_SEL 0x0b0
+#define QSERDES_V2_COM_RESETSM_CNTRL 0x0b4
+#define QSERDES_V2_COM_RESETSM_CNTRL2 0x0b8
+#define QSERDES_V2_COM_LOCK_CMP_EN 0x0c8
+#define QSERDES_V2_COM_LOCK_CMP_CFG 0x0cc
+#define QSERDES_V2_COM_DEC_START_MODE0 0x0d0
+#define QSERDES_V2_COM_DEC_START_MODE1 0x0d4
+#define QSERDES_V2_COM_VCOCAL_DEADMAN_CTRL 0x0d8
+#define QSERDES_V2_COM_DIV_FRAC_START1_MODE0 0x0dc
+#define QSERDES_V2_COM_DIV_FRAC_START2_MODE0 0x0e0
+#define QSERDES_V2_COM_DIV_FRAC_START3_MODE0 0x0e4
+#define QSERDES_V2_COM_DIV_FRAC_START1_MODE1 0x0e8
+#define QSERDES_V2_COM_DIV_FRAC_START2_MODE1 0x0ec
+#define QSERDES_V2_COM_DIV_FRAC_START3_MODE1 0x0f0
+#define QSERDES_V2_COM_VCO_TUNE_MINVAL1 0x0f4
+#define QSERDES_V2_COM_VCO_TUNE_MINVAL2 0x0f8
+#define QSERDES_V2_COM_INTEGLOOP_INITVAL 0x100
+#define QSERDES_V2_COM_INTEGLOOP_EN 0x104
+#define QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE0 0x108
+#define QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE0 0x10c
+#define QSERDES_V2_COM_INTEGLOOP_GAIN0_MODE1 0x110
+#define QSERDES_V2_COM_INTEGLOOP_GAIN1_MODE1 0x114
+#define QSERDES_V2_COM_VCO_TUNE_MAXVAL1 0x118
+#define QSERDES_V2_COM_VCO_TUNE_MAXVAL2 0x11c
+#define QSERDES_V2_COM_VCO_TUNE_CTRL 0x124
+#define QSERDES_V2_COM_VCO_TUNE_MAP 0x128
+#define QSERDES_V2_COM_VCO_TUNE1_MODE0 0x12c
+#define QSERDES_V2_COM_VCO_TUNE2_MODE0 0x130
+#define QSERDES_V2_COM_VCO_TUNE1_MODE1 0x134
+#define QSERDES_V2_COM_VCO_TUNE2_MODE1 0x138
+#define QSERDES_V2_COM_VCO_TUNE_INITVAL1 0x13c
+#define QSERDES_V2_COM_VCO_TUNE_INITVAL2 0x140
+#define QSERDES_V2_COM_VCO_TUNE_TIMER1 0x144
+#define QSERDES_V2_COM_VCO_TUNE_TIMER2 0x148
+#define QSERDES_V2_COM_CMN_STATUS 0x15c
+#define QSERDES_V2_COM_RESET_SM_STATUS 0x160
+#define QSERDES_V2_COM_RESTRIM_CODE_STATUS 0x164
+#define QSERDES_V2_COM_PLLCAL_CODE1_STATUS 0x168
+#define QSERDES_V2_COM_PLLCAL_CODE2_STATUS 0x16c
+#define QSERDES_V2_COM_CLK_SELECT 0x174
+#define QSERDES_V2_COM_HSCLK_SEL 0x178
+#define QSERDES_V2_COM_INTEGLOOP_BINCODE_STATUS 0x17c
+#define QSERDES_V2_COM_PLL_ANALOG 0x180
+#define QSERDES_V2_COM_CORECLK_DIV 0x184
+#define QSERDES_V2_COM_SW_RESET 0x188
+#define QSERDES_V2_COM_CORE_CLK_EN 0x18c
+#define QSERDES_V2_COM_C_READY_STATUS 0x190
+#define QSERDES_V2_COM_CMN_CONFIG 0x194
+#define QSERDES_V2_COM_CMN_RATE_OVERRIDE 0x198
+#define QSERDES_V2_COM_SVS_MODE_CLK_SEL 0x19c
+#define QSERDES_V2_COM_DEBUG_BUS0 0x1a0
+#define QSERDES_V2_COM_DEBUG_BUS1 0x1a4
+#define QSERDES_V2_COM_DEBUG_BUS2 0x1a8
+#define QSERDES_V2_COM_DEBUG_BUS3 0x1ac
+#define QSERDES_V2_COM_DEBUG_BUS_SEL 0x1b0
+#define QSERDES_V2_COM_CMN_MISC1 0x1b4
+#define QSERDES_V2_COM_CMN_MISC2 0x1b8
+#define QSERDES_V2_COM_CORECLK_DIV_MODE1 0x1bc
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v8.h
index d3b2292257bc..d8ac4c4a2c31 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v8.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v8.h
@@ -33,6 +33,7 @@
#define QSERDES_V8_COM_CP_CTRL_MODE0 0x070
#define QSERDES_V8_COM_PLL_RCTRL_MODE0 0x074
#define QSERDES_V8_COM_PLL_CCTRL_MODE0 0x078
+#define QSERDES_V8_COM_CORECLK_DIV_MODE0 0x07c
#define QSERDES_V8_COM_LOCK_CMP1_MODE0 0x080
#define QSERDES_V8_COM_LOCK_CMP2_MODE0 0x084
#define QSERDES_V8_COM_DEC_START_MODE0 0x088
@@ -40,6 +41,7 @@
#define QSERDES_V8_COM_DIV_FRAC_START1_MODE0 0x090
#define QSERDES_V8_COM_DIV_FRAC_START2_MODE0 0x094
#define QSERDES_V8_COM_DIV_FRAC_START3_MODE0 0x098
+#define QSERDES_V8_COM_HSCLK_HS_SWITCH_SEL_1 0x09c
#define QSERDES_V8_COM_VCO_TUNE1_MODE0 0x0a8
#define QSERDES_V8_COM_VCO_TUNE2_MODE0 0x0ac
#define QSERDES_V8_COM_BG_TIMER 0x0bc
@@ -47,13 +49,22 @@
#define QSERDES_V8_COM_SSC_PER1 0x0cc
#define QSERDES_V8_COM_SSC_PER2 0x0d0
#define QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN 0x0dc
+#define QSERDES_V8_COM_CLK_ENABLE1 0x0e0
+#define QSERDES_V8_COM_SYS_CLK_CTRL 0x0e4
+#define QSERDES_V8_COM_PLL_IVCO 0x0f4
#define QSERDES_V8_COM_SYSCLK_BUF_ENABLE 0x0e8
#define QSERDES_V8_COM_SYSCLK_EN_SEL 0x110
#define QSERDES_V8_COM_RESETSM_CNTRL 0x118
+#define QSERDES_V8_COM_LOCK_CMP_EN 0x120
#define QSERDES_V8_COM_LOCK_CMP_CFG 0x124
#define QSERDES_V8_COM_VCO_TUNE_MAP 0x140
+#define QSERDES_V8_COM_CLK_SELECT 0x164
#define QSERDES_V8_COM_CORE_CLK_EN 0x170
#define QSERDES_V8_COM_CMN_CONFIG_1 0x174
+#define QSERDES_V8_COM_CMN_MISC_1 0x184
+#define QSERDES_V8_COM_CMN_MODE 0x188
+#define QSERDES_V8_COM_VCO_DC_LEVEL_CTRL 0x198
+#define QSERDES_V8_COM_PLL_SPARE_FOR_ECO 0x2b4
#define QSERDES_V8_COM_AUTO_GAIN_ADJ_CTRL_1 0x1a4
#define QSERDES_V8_COM_AUTO_GAIN_ADJ_CTRL_2 0x1a8
#define QSERDES_V8_COM_AUTO_GAIN_ADJ_CTRL_3 0x1ac
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-dp-com-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-dp-com-v8.h
new file mode 100644
index 000000000000..93edabb830af
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-dp-com-v8.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 Linaro Ltd.
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_DP_COM_V8_H_
+#define QCOM_PHY_QMP_QSERDES_DP_COM_V8_H_
+
+/* Only for DP QMP V8 PHY - QSERDES COM registers */
+#define DP_QSERDES_V8_COM_HSCLK_SEL_1 0x03c
+#define DP_QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x058
+#define DP_QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x05c
+#define DP_QSERDES_V8_COM_SSC_STEP_SIZE1_MODE0 0x060
+#define DP_QSERDES_V8_COM_SSC_STEP_SIZE2_MODE0 0x064
+#define DP_QSERDES_V8_COM_CP_CTRL_MODE0 0x070
+#define DP_QSERDES_V8_COM_PLL_RCTRL_MODE0 0x074
+#define DP_QSERDES_V8_COM_PLL_CCTRL_MODE0 0x078
+#define DP_QSERDES_V8_COM_CORECLK_DIV_MODE0 0x07c
+#define DP_QSERDES_V8_COM_LOCK_CMP1_MODE0 0x080
+#define DP_QSERDES_V8_COM_LOCK_CMP2_MODE0 0x084
+#define DP_QSERDES_V8_COM_DEC_START_MODE0 0x088
+#define DP_QSERDES_V8_COM_DIV_FRAC_START1_MODE0 0x090
+#define DP_QSERDES_V8_COM_DIV_FRAC_START2_MODE0 0x094
+#define DP_QSERDES_V8_COM_DIV_FRAC_START3_MODE0 0x098
+#define DP_QSERDES_V8_COM_INTEGLOOP_GAIN0_MODE0 0x0a0
+#define DP_QSERDES_V8_COM_VCO_TUNE1_MODE0 0x0a8
+#define DP_QSERDES_V8_COM_INTEGLOOP_GAIN1_MODE0 0x0a4
+#define DP_QSERDES_V8_COM_VCO_TUNE2_MODE0 0x0ac
+#define DP_QSERDES_V8_COM_BG_TIMER 0x0bc
+#define DP_QSERDES_V8_COM_SSC_EN_CENTER 0x0c0
+#define DP_QSERDES_V8_COM_SSC_ADJ_PER1 0x0c4
+#define DP_QSERDES_V8_COM_SSC_PER1 0x0cc
+#define DP_QSERDES_V8_COM_SSC_PER2 0x0d0
+#define DP_QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN 0x0dc
+#define DP_QSERDES_V8_COM_CLK_ENABLE1 0x0e0
+#define DP_QSERDES_V8_COM_SYS_CLK_CTRL 0x0e4
+#define DP_QSERDES_V8_COM_SYSCLK_BUF_ENABLE 0x0e8
+#define DP_QSERDES_V8_COM_PLL_IVCO 0x0f4
+#define DP_QSERDES_V8_COM_SYSCLK_EN_SEL 0x110
+#define DP_QSERDES_V8_COM_RESETSM_CNTRL 0x118
+#define DP_QSERDES_V8_COM_LOCK_CMP_EN 0x120
+#define DP_QSERDES_V8_COM_VCO_TUNE_CTRL 0x13c
+#define DP_QSERDES_V8_COM_VCO_TUNE_MAP 0x140
+#define DP_QSERDES_V8_COM_CLK_SELECT 0x164
+#define DP_QSERDES_V8_COM_CORE_CLK_EN 0x170
+#define DP_QSERDES_V8_COM_CMN_CONFIG_1 0x174
+#define DP_QSERDES_V8_COM_SVS_MODE_CLK_SEL 0x180
+#define DP_QSERDES_V8_COM_CLK_FWD_CONFIG_1 0x2f4
+#define DP_QSERDES_V8_COM_CMN_STATUS 0x314
+#define DP_QSERDES_V8_COM_C_READY_STATUS 0x33c
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-lalb-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-lalb-v8.h
new file mode 100644
index 000000000000..60ba730620f8
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-lalb-v8.h
@@ -0,0 +1,639 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_V8_LALBH_
+#define QCOM_PHY_QMP_QSERDES_V8_LALBH_
+
+#define QSERDES_V8_LALB_BIST_MODE_LANENO 0x0
+#define QSERDES_V8_LALB_BIST_INVERT 0x4
+#define QSERDES_V8_LALB_PERL_LENGTH1 0x8
+#define QSERDES_V8_LALB_PERL_LENGTH2 0xc
+#define QSERDES_V8_LALB_BIST_PATTERN1 0x10
+#define QSERDES_V8_LALB_BIST_PATTERN2 0x14
+#define QSERDES_V8_LALB_BIST_PATTERN3 0x18
+#define QSERDES_V8_LALB_BIST_PATTERN4 0x1c
+#define QSERDES_V8_LALB_BIST_PATTERN5 0x20
+#define QSERDES_V8_LALB_BIST_PATTERN6 0x24
+#define QSERDES_V8_LALB_BIST_PATTERN7 0x28
+#define QSERDES_V8_LALB_BIST_PATTERN8 0x2c
+#define QSERDES_V8_LALB_PRBS_SEED1 0x30
+#define QSERDES_V8_LALB_PRBS_SEED2 0x34
+#define QSERDES_V8_LALB_PRBS_SEED3 0x38
+#define QSERDES_V8_LALB_PRBS_SEED4 0x3c
+#define QSERDES_V8_LALB_PRBS_SEED5 0x40
+#define QSERDES_V8_LALB_PRBS_SEED6 0x44
+#define QSERDES_V8_LALB_PRBS_SEED7 0x48
+#define QSERDES_V8_LALB_SW_RESET_PWRDNB 0x4c
+#define QSERDES_V8_LALB_RESET_GEN 0x50
+#define QSERDES_V8_LALB_RESET_TSYNC_EN_CTRL 0x54
+#define QSERDES_V8_LALB_CDR_EN_RXEQ_RESET 0x58
+#define QSERDES_V8_LALB_CLKBUF_ENABLE 0x5c
+#define QSERDES_V8_LALB_TX0_EMP_POST1_LVL 0x60
+#define QSERDES_V8_LALB_TX1_EMP_POST1_LVL 0x64
+#define QSERDES_V8_LALB_TX0_IDLE_CTRL 0x68
+#define QSERDES_V8_LALB_TX1_IDLE_CTRL 0x6c
+#define QSERDES_V8_LALB_TX0_DRV_LVL 0x70
+#define QSERDES_V8_LALB_TX0_DRV_LVL_OFFSET 0x74
+#define QSERDES_V8_LALB_TX1_DRV_LVL 0x78
+#define QSERDES_V8_LALB_TX1_DRV_LVL_OFFSET 0x7c
+#define QSERDES_V8_LALB_TRAN_DRVR_EMP_EN 0x80
+#define QSERDES_V8_LALB_TX_LVL_UPDATE_CTRL 0x84
+#define QSERDES_V8_LALB_TX0_PRE1_EMPH 0x88
+#define QSERDES_V8_LALB_TX1_PRE1_EMPH 0x8c
+#define QSERDES_V8_LALB_TX0_PRE2_EMPH 0x90
+#define QSERDES_V8_LALB_TX1_PRE2_EMPH 0x94
+#define QSERDES_V8_LALB_STALL_LDO_BOOST_EN 0x98
+#define QSERDES_V8_LALB_PRE_EMPH_EN_CTRL 0x9c
+#define QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL1 0xa0
+#define QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL2 0xa4
+#define QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL3 0xa8
+#define QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL4 0xac
+#define QSERDES_V8_LALB_TRANSMITTER_EN_CTRL 0xb0
+#define QSERDES_V8_LALB_HIGHZ_DRVR_EN 0xb4
+#define QSERDES_V8_LALB_TX_MISC_CTRL1 0xb8
+#define QSERDES_V8_LALB_LPB_EN_CTRL1 0xbc
+#define QSERDES_V8_LALB_LBP_EN_CTRL2 0xc0
+#define QSERDES_V8_LALB_TX0_SERDES_BYP_CTRL 0xc4
+#define QSERDES_V8_LALB_TX1_SERDES_BYP_CTRL 0xc8
+#define QSERDES_V8_LALB_LANE_MODE_1 0xcc
+#define QSERDES_V8_LALB_LANE_MODE_2 0xd0
+#define QSERDES_V8_LALB_LANE_MODE_3 0xd4
+#define QSERDES_V8_LALB_LANE_MODE_4 0xd8
+#define QSERDES_V8_LALB_ATB_SEL1 0xdc
+#define QSERDES_V8_LALB_ATB_SEL2 0xe0
+#define QSERDES_V8_LALB_TX0_RES_CODE_LANE 0xe4
+#define QSERDES_V8_LALB_TX0_RESTRIM_ICAL_OVRD 0xe8
+#define QSERDES_V8_LALB_TX0_RESTRIM_CAL_CTRL 0xec
+#define QSERDES_V8_LALB_TX0_RESTRIM_INIT_CODE 0xf0
+#define QSERDES_V8_LALB_TX0_RESTRIM_POST_CAL_OFFSET 0xf4
+#define QSERDES_V8_LALB_TX1_RES_CODE_LANE 0xf8
+#define QSERDES_V8_LALB_TX1_RESTRIM_ICAL_OVRD 0xfc
+#define QSERDES_V8_LALB_TX1_RESTRIM_CAL_CTRL 0x100
+#define QSERDES_V8_LALB_TX1_RESTRIM_INIT_CODE 0x104
+#define QSERDES_V8_LALB_TX1_RESTRIM_POST_CAL_OFFSET 0x108
+#define QSERDES_V8_LALB_TX0_RESTRIM_VREF_SEL 0x10c
+#define QSERDES_V8_LALB_TX1_RESTRIM_VREF_SEL 0x110
+#define QSERDES_V8_LALB_VMODE_CTRL1 0x114
+#define QSERDES_V8_LALB_SLEW_CNTL_RATE01 0x118
+#define QSERDES_V8_LALB_SLEW_CNTL_RATE23 0x11c
+#define QSERDES_V8_LALB_SLEW_CNTL_RATE4 0x120
+#define QSERDES_V8_LALB_ANA_INTERFACE_SELECT1 0x124
+#define QSERDES_V8_LALB_ANA_INTERFACE_SELECT2 0x128
+#define QSERDES_V8_LALB_ANA_INTERFACE_SELECT3 0x12c
+#define QSERDES_V8_LALB_PCS_INTERFACE_SELECT1 0x130
+#define QSERDES_V8_LALB_PCS_INTERFACE_SELECT2 0x134
+#define QSERDES_V8_LALB_LDO_TIMER_CTRL 0x138
+#define QSERDES_V8_LALB_AC_JTAG_ENABLE 0x13c
+#define QSERDES_V8_LALB_AC_JTAG_INITP 0x140
+#define QSERDES_V8_LALB_AC_JTAG_INITN 0x144
+#define QSERDES_V8_LALB_AC_JTAG_LVL 0x148
+#define QSERDES_V8_LALB_AC_JTAG_MODE 0x14c
+#define QSERDES_V8_LALB_AC_JTAG_RESET 0x150
+#define QSERDES_V8_LALB_RX_MODE_RATE_0_1_B0 0x154
+#define QSERDES_V8_LALB_RX_MODE_RATE_0_1_B1 0x158
+#define QSERDES_V8_LALB_RX_MODE_RATE_0_1_B2 0x15c
+#define QSERDES_V8_LALB_RX_MODE_RATE_0_1_B3 0x160
+#define QSERDES_V8_LALB_RX_MODE_RATE_0_1_B4 0x164
+#define QSERDES_V8_LALB_RX_MODE_RATE_0_1_B5 0x168
+#define QSERDES_V8_LALB_RX_MODE_RATE_0_1_B6 0x16c
+#define QSERDES_V8_LALB_RX_MODE_RATE_0_1_B7 0x170
+#define QSERDES_V8_LALB_RX_MODE_RATE2_B0 0x174
+#define QSERDES_V8_LALB_RX_MODE_RATE2_B1 0x178
+#define QSERDES_V8_LALB_RX_MODE_RATE2_B2 0x17c
+#define QSERDES_V8_LALB_RX_MODE_RATE2_B3 0x180
+#define QSERDES_V8_LALB_RX_MODE_RATE2_B4 0x184
+#define QSERDES_V8_LALB_RX_MODE_RATE2_B5 0x188
+#define QSERDES_V8_LALB_RX_MODE_RATE2_B6 0x18c
+#define QSERDES_V8_LALB_RX_MODE_RATE2_B7 0x190
+#define QSERDES_V8_LALB_RX_MODE_RATE3_B0 0x194
+#define QSERDES_V8_LALB_RX_MODE_RATE3_B1 0x198
+#define QSERDES_V8_LALB_RX_MODE_RATE3_B2 0x19c
+#define QSERDES_V8_LALB_RX_MODE_RATE3_B3 0x1a0
+#define QSERDES_V8_LALB_RX_MODE_RATE3_B4 0x1a4
+#define QSERDES_V8_LALB_RX_MODE_RATE3_B5 0x1a8
+#define QSERDES_V8_LALB_RX_MODE_RATE3_B6 0x1ac
+#define QSERDES_V8_LALB_RX_MODE_RATE3_B7 0x1b0
+#define QSERDES_V8_LALB_RX_MODE_RATE4_B0 0x1b4
+#define QSERDES_V8_LALB_RX_MODE_RATE4_B1 0x1b8
+#define QSERDES_V8_LALB_RX_MODE_RATE4_B2 0x1bc
+#define QSERDES_V8_LALB_RX_MODE_RATE4_B3 0x1c0
+#define QSERDES_V8_LALB_RX_MODE_RATE4_B4 0x1c4
+#define QSERDES_V8_LALB_RX_MODE_RATE4_B5 0x1c8
+#define QSERDES_V8_LALB_RX_MODE_RATE4_B6 0x1cc
+#define QSERDES_V8_LALB_RX_MODE_RATE4_B7 0x1d0
+#define QSERDES_V8_LALB_TX_DCC_ANA_CTRL1 0x1d4
+#define QSERDES_V8_LALB_TX_DCC_ANA_CTRL2 0x1d8
+#define QSERDES_V8_LALB_CMUX_DCC_CTRL1 0x1dc
+#define QSERDES_V8_LALB_CMUX_DCC_POSTCAL_OFFSET 0x1e0
+#define QSERDES_V8_LALB_CMUX_DCC_OVRD 0x1e4
+#define QSERDES_V8_LALB_TX_DCC_CTRL 0x1e8
+#define QSERDES_V8_LALB_TX0_CTUNE_DCC_CONFIG 0x1ec
+#define QSERDES_V8_LALB_TX0_CTUNE_DCC_POSTCAL_OFFSET 0x1f0
+#define QSERDES_V8_LALB_TX0_CTUNE_DCC_OVRD 0x1f4
+#define QSERDES_V8_LALB_TX0_FTUNE_MSB_DCC_CONFIG 0x1f8
+#define QSERDES_V8_LALB_TX0_FTUNE_MSB_DCC_OFFSET_AND_OVRD 0x1fc
+#define QSERDES_V8_LALB_TX0_FTUNE_LSB_DCC_CONFIG 0x200
+#define QSERDES_V8_LALB_TX0_FTUNE_LSB_DCC_OFFSET_AND_OVRD 0x204
+#define QSERDES_V8_LALB_TX1_CTUNE_DCC_CONFIG 0x208
+#define QSERDES_V8_LALB_TX1_CTUNE_DCC_POSTCAL_OFFSET 0x20c
+#define QSERDES_V8_LALB_TX1_CTUNE_DCC_OVRD 0x210
+#define QSERDES_V8_LALB_TX1_FTUNE_MSB_DCC_CONFIG 0x214
+#define QSERDES_V8_LALB_TX1_FTUNE_MSB_DCC_OFFSET_AND_OVRD 0x218
+#define QSERDES_V8_LALB_TX1_FTUNE_LSB_DCC_CONFIG 0x21c
+#define QSERDES_V8_LALB_TX1_FTUNE_LSB_DCC_OFFSET_AND_OVRD 0x220
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_CTRL 0x224
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_CODE_OVRD_RATE0 0x228
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_CODE_OVRD_RATE1 0x22c
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_CODE_OVRD_RATE2 0x230
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_CODE_OVRD_RATE3 0x234
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_CODE_OVRD_RATE4 0x238
+#define QSERDES_V8_LALB_CDR_VCO_CAL_CTRL 0x23c
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT1_RATE0 0x240
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT2_RATE0 0x244
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT1_RATE1 0x248
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT2_RATE1 0x24c
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT1_RATE2 0x250
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT2_RATE2 0x254
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT1_RATE3 0x258
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT2_RATE3 0x25c
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT1_RATE4 0x260
+#define QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT2_RATE4 0x264
+#define QSERDES_V8_LALB_CDR_VCTRL_RATE_0_1 0x268
+#define QSERDES_V8_LALB_CDR_VCTRL_RATE_2_3 0x26c
+#define QSERDES_V8_LALB_CDR_VCTRL_RATE_4 0x270
+#define QSERDES_V8_LALB_KVCO_INIT_RATE_0_1 0x274
+#define QSERDES_V8_LALB_KVCO_INIT_RATE_2_3 0x278
+#define QSERDES_V8_LALB_KVCO_INIT_RATE_4 0x27c
+#define QSERDES_V8_LALB_KVCO_CODE_OVRD_RATE0 0x280
+#define QSERDES_V8_LALB_KVCO_CODE_OVRD_RATE1 0x284
+#define QSERDES_V8_LALB_KVCO_CODE_OVRD_RATE2 0x288
+#define QSERDES_V8_LALB_KVCO_CODE_OVRD_RATE3 0x28c
+#define QSERDES_V8_LALB_KVCO_CODE_OVRD_RATE4 0x290
+#define QSERDES_V8_LALB_KVCO_CAL_VCTRL_HIGH_RATE_0_1 0x294
+#define QSERDES_V8_LALB_KVCO_CAL_VCTRL_HIGH_RATE_2_3 0x298
+#define QSERDES_V8_LALB_KVCO_CAL_VCTRL_HIGH_RATE_4 0x29c
+#define QSERDES_V8_LALB_KVCO_CAL_VCTRL_LOW_RATE_0_1 0x2a0
+#define QSERDES_V8_LALB_KVCO_CAL_VCTRL_LOW_RATE_2_3 0x2a4
+#define QSERDES_V8_LALB_KVCO_CAL_VCTRL_LOW_RATE_4 0x2a8
+#define QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF1_RATE0 0x2ac
+#define QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF2_RATE0 0x2b0
+#define QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF1_RATE1 0x2b4
+#define QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF2_RATE1 0x2b8
+#define QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF1_RATE2 0x2bc
+#define QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF2_RATE2 0x2c0
+#define QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF1_RATE3 0x2c4
+#define QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF2_RATE3 0x2c8
+#define QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF1_RATE4 0x2cc
+#define QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF2_RATE4 0x2d0
+#define QSERDES_V8_LALB_KP_CDR_UP_DN 0x2d4
+#define QSERDES_V8_LALB_KP_CODE_OVRD_RATE_0_1 0x2d8
+#define QSERDES_V8_LALB_KP_CODE_OVRD_RATE_2_3 0x2dc
+#define QSERDES_V8_LALB_KP_CODE_OVRD_RATE4 0x2e0
+#define QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND1_RATE0 0x2e4
+#define QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND2_RATE0 0x2e8
+#define QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND1_RATE1 0x2ec
+#define QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND2_RATE1 0x2f0
+#define QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND1_RATE2 0x2f4
+#define QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND2_RATE2 0x2f8
+#define QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND1_RATE3 0x2fc
+#define QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND2_RATE3 0x300
+#define QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND1_RATE4 0x304
+#define QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND2_RATE4 0x308
+#define QSERDES_V8_LALB_KP_CAL_LOWER_FREQ_DIFF_BND_RATE0 0x30c
+#define QSERDES_V8_LALB_KP_CAL_LOWER_FREQ_DIFF_BND_RATE1 0x310
+#define QSERDES_V8_LALB_KP_CAL_LOWER_FREQ_DIFF_BND_RATE2 0x314
+#define QSERDES_V8_LALB_KP_CAL_LOWER_FREQ_DIFF_BND_RATE3 0x318
+#define QSERDES_V8_LALB_KP_CAL_LOWER_FREQ_DIFF_BND_RATE4 0x31c
+#define QSERDES_V8_LALB_CDR_KVCO_KP_CAL_FREQ_MEAS_CTRL 0x320
+#define QSERDES_V8_LALB_PLLLOCK_CMP_DEBUG_CTRL 0x324
+#define QSERDES_V8_LALB_PLLLOCK_CMP_DEBUG_CNT1 0x328
+#define QSERDES_V8_LALB_PLLLOCK_CMP_DEBUG_CNT2 0x32c
+#define QSERDES_V8_LALB_PLLLOCK_CMP_DEBUG_CNT3 0x330
+#define QSERDES_V8_LALB_RX_SUMMER_CAL_SPD_MODE_RATE_0123 0x334
+#define QSERDES_V8_LALB_RX_SUMMER_CAL_SPD_MODE_RATE_4 0x338
+#define QSERDES_V8_LALB_RX_IVCM_CAL_CODE_OVERRIDE_RATE0 0x33c
+#define QSERDES_V8_LALB_RX_IVCM_CAL_CODE_OVERRIDE_RATE1 0x340
+#define QSERDES_V8_LALB_RX_IVCM_CAL_CODE_OVERRIDE_RATE2 0x344
+#define QSERDES_V8_LALB_RX_IVCM_CAL_CODE_OVERRIDE_RATE3 0x348
+#define QSERDES_V8_LALB_RX_IVCM_CAL_CODE_OVERRIDE_RATE4 0x34c
+#define QSERDES_V8_LALB_RX_IVCM_CAL_CTRL1 0x350
+#define QSERDES_V8_LALB_RX_IVCM_CAL_CTRL2 0x354
+#define QSERDES_V8_LALB_RX_IVCM_CAL_CTRL3 0x358
+#define QSERDES_V8_LALB_RX_IVCM_CAL_CTRL4 0x35c
+#define QSERDES_V8_LALB_RX_IVCM_POSTCAL_OFFSET_RATE0 0x360
+#define QSERDES_V8_LALB_RX_IVCM_POSTCAL_OFFSET_RATE1 0x364
+#define QSERDES_V8_LALB_RX_IVCM_POSTCAL_OFFSET_RATE2 0x368
+#define QSERDES_V8_LALB_RX_IVCM_POSTCAL_OFFSET_RATE3 0x36c
+#define QSERDES_V8_LALB_RX_IVCM_POSTCAL_OFFSET_RATE4 0x370
+#define QSERDES_V8_LALB_RX_IDAC_I0_DC_OFFSETS 0x374
+#define QSERDES_V8_LALB_RX_IDAC_I0BAR_DC_OFFSETS 0x378
+#define QSERDES_V8_LALB_RX_IDAC_I1_DC_OFFSETS 0x37c
+#define QSERDES_V8_LALB_RX_IDAC_I1BAR_DC_OFFSETS 0x380
+#define QSERDES_V8_LALB_RX_IDAC_Q_DC_OFFSETS 0x384
+#define QSERDES_V8_LALB_RX_IDAC_QBAR_DC_OFFSETS 0x388
+#define QSERDES_V8_LALB_RX_IDAC_A_DC_OFFSETS 0x38c
+#define QSERDES_V8_LALB_RX_IDAC_ABAR_DC_OFFSETS 0x390
+#define QSERDES_V8_LALB_RX_IDAC_EN 0x394
+#define QSERDES_V8_LALB_DATA_SLICER_INIT_TIMER_CTRL 0x398
+#define QSERDES_V8_LALB_RX_IDAC_ENABLES 0x39c
+#define QSERDES_V8_LALB_RX_IDAC_SIGN 0x3a0
+#define QSERDES_V8_LALB_RX_IDAC_TSETTLE 0x3a4
+#define QSERDES_V8_LALB_SIGDET_ENABLES 0x3a8
+#define QSERDES_V8_LALB_SIGDET_CNTRL 0x3ac
+#define QSERDES_V8_LALB_SIGDET_LVL 0x3b0
+#define QSERDES_V8_LALB_SIGDET_DEGLITCH_CNTRL 0x3b4
+#define QSERDES_V8_LALB_SIGDET_CAL_CTRL1 0x3b8
+#define QSERDES_V8_LALB_SIGDET_CAL_CTRL2_AND_CDR_LOCK_EDGE 0x3bc
+#define QSERDES_V8_LALB_SIGDET_CAL_TRIM 0x3c0
+#define QSERDES_V8_LALB_IA_OFFSET_CENTER_CAL_CTRL 0x3c4
+#define QSERDES_V8_LALB_FREQ_LOCK_DET_DLY_RATE0 0x3c8
+#define QSERDES_V8_LALB_FREQ_LOCK_DET_DLY_RATE1 0x3cc
+#define QSERDES_V8_LALB_FREQ_LOCK_DET_DLY_RATE2 0x3d0
+#define QSERDES_V8_LALB_FREQ_LOCK_DET_DLY_RATE3 0x3d4
+#define QSERDES_V8_LALB_FREQ_LOCK_DET_DLY_RATE4 0x3d8
+#define QSERDES_V8_LALB_CDR_PHASE_LOCK_CNT_RATE0 0x3dc
+#define QSERDES_V8_LALB_CDR_PHASE_LOCK_CNT_RATE1 0x3e0
+#define QSERDES_V8_LALB_CDR_PHASE_LOCK_CNT_RATE2 0x3e4
+#define QSERDES_V8_LALB_CDR_PHASE_LOCK_CNT_RATE3 0x3e8
+#define QSERDES_V8_LALB_CDR_PHASE_LOCK_CNT_RATE4 0x3ec
+#define QSERDES_V8_LALB_CDR_LOCK_CTRL 0x3f0
+#define QSERDES_V8_LALB_CDR_CP_CUR_FLL_RATE0 0x3f4
+#define QSERDES_V8_LALB_CDR_CP_CUR_FLL_RATE1 0x3f8
+#define QSERDES_V8_LALB_CDR_CP_CUR_FLL_RATE2 0x3fc
+#define QSERDES_V8_LALB_CDR_CP_CUR_FLL_RATE3 0x400
+#define QSERDES_V8_LALB_CDR_CP_CUR_FLL_RATE4 0x404
+#define QSERDES_V8_LALB_CDR_CP_CUR_PLL_RATE0 0x408
+#define QSERDES_V8_LALB_CDR_CP_CUR_PLL_RATE1 0x40c
+#define QSERDES_V8_LALB_CDR_CP_CUR_PLL_RATE2 0x410
+#define QSERDES_V8_LALB_CDR_CP_CUR_PLL_RATE3 0x414
+#define QSERDES_V8_LALB_CDR_CP_CUR_PLL_RATE4 0x418
+#define QSERDES_V8_LALB_CDR_FLL_DIV_RATIO_RATE_0123 0x41c
+#define QSERDES_V8_LALB_CDR_FLL_DIV_RATIO_RATE4 0x420
+#define QSERDES_V8_LALB_CDR_LOOP_CCODE_RATE_01 0x424
+#define QSERDES_V8_LALB_CDR_LOOP_CCODE_RATE_23 0x428
+#define QSERDES_V8_LALB_CDR_LOOP_CCODE_RATE4 0x42c
+#define QSERDES_V8_LALB_CDR_LOOP_RCODE_FAST_RATE_0_1 0x430
+#define QSERDES_V8_LALB_CDR_LOOP_RCODE_FAST_RATE_2_3 0x434
+#define QSERDES_V8_LALB_CDR_LOOP_RCODE_FAST_RATE4 0x438
+#define QSERDES_V8_LALB_CDR_LOOP_RCODE_FLL_RATE_0_1 0x43c
+#define QSERDES_V8_LALB_CDR_LOOP_RCODE_FLL_RATE_2_3 0x440
+#define QSERDES_V8_LALB_CDR_LOOP_RCODE_FLL_RATE4 0x444
+#define QSERDES_V8_LALB_CDR_LOOP_RCODE_PLL_RATE_0_1 0x448
+#define QSERDES_V8_LALB_CDR_LOOP_RCODE_PLL_RATE_2_3 0x44c
+#define QSERDES_V8_LALB_CDR_LOOP_RCODE_PLL_RATE4 0x450
+#define QSERDES_V8_LALB_CDR_VCO_CAP_CODE_RATE_0123 0x454
+#define QSERDES_V8_LALB_CDR_VCO_CAP_CODE_RATE4 0x458
+#define QSERDES_V8_LALB_CDR_VCO_TYPE_CONFIG 0x45c
+#define QSERDES_V8_LALB_CDR_VCO_EN_LOWFREQ 0x460
+#define QSERDES_V8_LALB_CDR_FAST_SLOW_VCO_OVRD 0x464
+#define QSERDES_V8_LALB_CDR_LOOP_FUNC_CTRL 0x468
+#define QSERDES_V8_LALB_CDR_FAST_LOCK_EN_CTRL 0x46c
+#define QSERDES_V8_LALB_RX_RCVR_EN 0x470
+#define QSERDES_V8_LALB_LANE_RATE_CTRL 0x474
+#define QSERDES_V8_LALB_RX_TERM_RCVR_CTRL 0x478
+#define QSERDES_V8_LALB_REC_DETECT_CTRL 0x47c
+#define QSERDES_V8_LALB_RCV_DETECT_LVL 0x480
+#define QSERDES_V8_LALB_GM_CAL_EN 0x484
+#define QSERDES_V8_LALB_GM_CAL_RES_RATE0_1 0x488
+#define QSERDES_V8_LALB_GM_CAL_RES_RATE2_3 0x48c
+#define QSERDES_V8_LALB_GM_CAL_RES_RATE4 0x490
+#define QSERDES_V8_LALB_RX_TERM_BW_RATE_0123 0x494
+#define QSERDES_V8_LALB_RX_TERM_BW_RATE4 0x498
+#define QSERDES_V8_LALB_AUX_CLK_CTRL 0x49c
+#define QSERDES_V8_LALB_AUX_OFFSET_CONTROL 0x4a0
+#define QSERDES_V8_LALB_AUXDATA_TB 0x4a4
+#define QSERDES_V8_LALB_EOM_CTRL1 0x4a8
+#define QSERDES_V8_LALB_EOM_CTRL2 0x4ac
+#define QSERDES_V8_LALB_EOM_CTRL3 0x4b0
+#define QSERDES_V8_LALB_EOM_CTRL4 0x4b4
+#define QSERDES_V8_LALB_DFE_EN_TIMER 0x4b8
+#define QSERDES_V8_LALB_RX_EQ_OFFSET_LSB 0x4bc
+#define QSERDES_V8_LALB_RX_EQ_OFFSET_MSB 0x4c0
+#define QSERDES_V8_LALB_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x4c4
+#define QSERDES_V8_LALB_RX_OFFSET_ADAPTOR_CNTRL2 0x4c8
+#define QSERDES_V8_LALB_RX_OFFSET_ADAPTOR_CNTRL3 0x4cc
+#define QSERDES_V8_LALB_RX_EQU_ADAPTOR_CNTRL1 0x4d0
+#define QSERDES_V8_LALB_RX_EQU_ADAPTOR_CNTRL2 0x4d4
+#define QSERDES_V8_LALB_RX_EQU_ADAPTOR_CNTRL3 0x4d8
+#define QSERDES_V8_LALB_RX_EQU_ADAPTOR_CNTRL4 0x4dc
+#define QSERDES_V8_LALB_RX_EQU_ADAPTOR_CNTRL5 0x4e0
+#define QSERDES_V8_LALB_RX_EQU_KEQ_UP_LSB 0x4e4
+#define QSERDES_V8_LALB_RX_EQU_KEQ_UP_MSB 0x4e8
+#define QSERDES_V8_LALB_RX_EQU_KEQ_DN_LSB 0x4ec
+#define QSERDES_V8_LALB_RX_EQU_KEQ_DN_MSB 0x4f0
+#define QSERDES_V8_LALB_CTLE_ADP_RESET_INIT_CODE_RATE_0_1_2 0x4f4
+#define QSERDES_V8_LALB_CTLE_ADP_RESET_INIT_CODE_RATE_3_4 0x4f8
+#define QSERDES_V8_LALB_CTLE_POST_CAL_OFFSET_RATE_0_1_2 0x4fc
+#define QSERDES_V8_LALB_CTLE_POST_CAL_OFFSET_RATE_3_4 0x500
+#define QSERDES_V8_LALB_RX_VGA_GAIN2_BLK1 0x504
+#define QSERDES_V8_LALB_RX_VGA_GAIN2_BLK2 0x508
+#define QSERDES_V8_LALB_VGA_CAL_CNTRL1 0x50c
+#define QSERDES_V8_LALB_VGA_CAL_CNTRL2 0x510
+#define QSERDES_V8_LALB_VGA_CAL_MAN_VAL_RATE0_1 0x514
+#define QSERDES_V8_LALB_VGA_CAL_MAN_VAL_RATE2_3 0x518
+#define QSERDES_V8_LALB_VGA_CAL_MAN_VAL_RATE4 0x51c
+#define QSERDES_V8_LALB_KVGA_CTRL1 0x520
+#define QSERDES_V8_LALB_KVGA_CTRL2 0x524
+#define QSERDES_V8_LALB_VTHRESH_CAL_CNTRL1 0x528
+#define QSERDES_V8_LALB_VTHRESH_CAL_CNTRL2 0x52c
+#define QSERDES_V8_LALB_VTHRESH_CAL_MAN_VAL_RATE0 0x530
+#define QSERDES_V8_LALB_VTHRESH_CAL_MAN_VAL_RATE1 0x534
+#define QSERDES_V8_LALB_VTHRESH_CAL_MAN_VAL_RATE2 0x538
+#define QSERDES_V8_LALB_VTHRESH_CAL_MAN_VAL_RATE3 0x53c
+#define QSERDES_V8_LALB_VTHRESH_CAL_MAN_VAL_RATE4 0x540
+#define QSERDES_V8_LALB_VTHRESH_CAL_MAN_CAL_PAM3 0x544
+#define QSERDES_V8_LALB_VTH_POST_CAL_OFFSET_RATE_0_1 0x548
+#define QSERDES_V8_LALB_VTH_POST_CAL_OFFSET_RATE_2_3 0x54c
+#define QSERDES_V8_LALB_VTH_POST_CAL_OFFSET_RATE4 0x550
+#define QSERDES_V8_LALB_DFE_TAP1_CTRL 0x554
+#define QSERDES_V8_LALB_DFE_TAP1_MANVAL_KTAP 0x558
+#define QSERDES_V8_LALB_DFE_TAP1_POST_CAL_OFFSET_RATE_0_1_2 0x55c
+#define QSERDES_V8_LALB_DFE_TAP1_POST_CAL_OFFSET_RATE_3_4 0x560
+#define QSERDES_V8_LALB_DFE_TAP2_CTRL 0x564
+#define QSERDES_V8_LALB_DFE_TAP2_MANVAL_KTAP 0x568
+#define QSERDES_V8_LALB_DFE_TAP3_CTRL 0x56c
+#define QSERDES_V8_LALB_DFE_TAP3_MANVAL_KTAP 0x570
+#define QSERDES_V8_LALB_DFE_TAP4_CTRL 0x574
+#define QSERDES_V8_LALB_DFE_TAP4_MANVAL_KTAP 0x578
+#define QSERDES_V8_LALB_DFE_TAP5_CTRL 0x57c
+#define QSERDES_V8_LALB_DFE_TAP5_MANVAL_KTAP 0x580
+#define QSERDES_V8_LALB_DFE_TAP6_CTRL 0x584
+#define QSERDES_V8_LALB_DFE_TAP6_MANVAL_KTAP 0x588
+#define QSERDES_V8_LALB_DFE_TAP7_CTRL 0x58c
+#define QSERDES_V8_LALB_DFE_TAP7_MANVAL_KTAP 0x590
+#define QSERDES_V8_LALB_DFE_TAP1_DAC_ENABLE 0x594
+#define QSERDES_V8_LALB_DFE_TAP2_DAC_ENABLE 0x598
+#define QSERDES_V8_LALB_DFE_TAP345_DAC_ENABLE 0x59c
+#define QSERDES_V8_LALB_DFE_TAP67_DAC_ENABLE 0x5a0
+#define QSERDES_V8_LALB_CDR_IQTUNE_CTRL 0x5a4
+#define QSERDES_V8_LALB_CDR_IQTUNE_GAIN 0x5a8
+#define QSERDES_V8_LALB_CDR_IQTUNE_MAN_INDEX 0x5ac
+#define QSERDES_V8_LALB_CDR_IQTUNE_FILTER_CAL_CTRL1 0x5b0
+#define QSERDES_V8_LALB_CDR_IQTUNE_FILTER_CAL_CTRL2 0x5b4
+#define QSERDES_V8_LALB_CDR_IQTUNE_CLK0_CAL_CODE_RATE0 0x5b8
+#define QSERDES_V8_LALB_CDR_IQTUNE_CLK0_CAL_CODE_RATE1 0x5bc
+#define QSERDES_V8_LALB_CDR_IQTUNE_CLK0_CAL_CODE_RATE2 0x5c0
+#define QSERDES_V8_LALB_CDR_IQTUNE_CLK0_CAL_CODE_RATE3 0x5c4
+#define QSERDES_V8_LALB_CDR_IQTUNE_CLK0_CAL_CODE_RATE4 0x5c8
+#define QSERDES_V8_LALB_CDR_IQTUNE_CLK90_CAL_CODE_RATE0 0x5cc
+#define QSERDES_V8_LALB_CDR_IQTUNE_CLK90_CAL_CODE_RATE1 0x5d0
+#define QSERDES_V8_LALB_CDR_IQTUNE_CLK90_CAL_CODE_RATE2 0x5d4
+#define QSERDES_V8_LALB_CDR_IQTUNE_CLK90_CAL_CODE_RATE3 0x5d8
+#define QSERDES_V8_LALB_CDR_IQTUNE_CLK90_CAL_CODE_RATE4 0x5dc
+#define QSERDES_V8_LALB_CDR_IQTUNE_ANA_CTRL 0x5e0
+#define QSERDES_V8_LALB_CDR_IQTUNE_VDCC_CTRL 0x5e4
+#define QSERDES_V8_LALB_CDR_IQTUNE_DIV2_CTRL_RATE0123 0x5e8
+#define QSERDES_V8_LALB_CDR_IQTUNE_DIV2_CTRL_RATE4 0x5ec
+#define QSERDES_V8_LALB_BLW_CTRL 0x5f0
+#define QSERDES_V8_LALB_BLW_ANA_VER_CTRL 0x5f4
+#define QSERDES_V8_LALB_BLW_GAIN_CAL_CTRL 0x5f8
+#define QSERDES_V8_LALB_BLW_GAIN_FORCE_CODE 0x5fc
+#define QSERDES_V8_LALB_BLW_MAN_VAL_RATE3 0x600
+#define QSERDES_V8_LALB_BLW_MAN_VAL_RATE4 0x604
+#define QSERDES_V8_LALB_IVTH_CAL_CTRL1 0x608
+#define QSERDES_V8_LALB_IVTH_CAL_CTRL2 0x60c
+#define QSERDES_V8_LALB_IVTH_CAL_CTRL3 0x610
+#define QSERDES_V8_LALB_VTH_I_UP_CNTRL_VAL 0x614
+#define QSERDES_V8_LALB_VTH_I_DN_CNTRL_VAL 0x618
+#define QSERDES_V8_LALB_NRZ_EYE_HEIGHT_SEL_VAL 0x61c
+#define QSERDES_V8_LALB_IVTH_CAL_VAL_OVRD_MUX 0x620
+#define QSERDES_V8_LALB_CDR_VCO_CAP_CODE_OVRD_MUXES 0x624
+#define QSERDES_V8_LALB_VCO_CTUNE_LOWER_BND_RATE0 0x628
+#define QSERDES_V8_LALB_VCO_CTUNE_LOWER_BND_RATE1 0x62c
+#define QSERDES_V8_LALB_VCO_CTUNE_LOWER_BND_RATE2 0x630
+#define QSERDES_V8_LALB_VCO_CTUNE_LOWER_BND_RATE3 0x634
+#define QSERDES_V8_LALB_VCO_CTUNE_LOWER_BND_RATE4 0x638
+#define QSERDES_V8_LALB_VCO_CTUNE_UPPER_BND_RATE0 0x63c
+#define QSERDES_V8_LALB_VCO_CTUNE_UPPER_BND_RATE1 0x640
+#define QSERDES_V8_LALB_VCO_CTUNE_UPPER_BND_RATE2 0x644
+#define QSERDES_V8_LALB_VCO_CTUNE_UPPER_BND_RATE3 0x648
+#define QSERDES_V8_LALB_VCO_CTUNE_UPPER_BND_RATE4 0x64c
+#define QSERDES_V8_LALB_CDR_LOCK_KVCO_OFFSET_RATE0 0x650
+#define QSERDES_V8_LALB_CDR_LOCK_KVCO_OFFSET_RATE1 0x654
+#define QSERDES_V8_LALB_CDR_LOCK_KVCO_OFFSET_RATE2 0x658
+#define QSERDES_V8_LALB_CDR_LOCK_KVCO_OFFSET_RATE3 0x65c
+#define QSERDES_V8_LALB_CDR_LOCK_KVCO_OFFSET_RATE4 0x660
+#define QSERDES_V8_LALB_CDR_LOCK_KP_OFFSET_RATE0 0x664
+#define QSERDES_V8_LALB_CDR_LOCK_KP_OFFSET_RATE1 0x668
+#define QSERDES_V8_LALB_CDR_LOCK_KP_OFFSET_RATE2 0x66c
+#define QSERDES_V8_LALB_CDR_LOCK_KP_OFFSET_RATE3 0x670
+#define QSERDES_V8_LALB_CDR_LOCK_KP_OFFSET_RATE4 0x674
+#define QSERDES_V8_LALB_CDR_FASTLOCK_CP_CUR_PLL_RATE0 0x678
+#define QSERDES_V8_LALB_CDR_FASTLOCK_CP_CUR_PLL_RATE1 0x67c
+#define QSERDES_V8_LALB_CDR_FASTLOCK_CP_CUR_PLL_RATE2 0x680
+#define QSERDES_V8_LALB_CDR_FASTLOCK_CP_CUR_PLL_RATE3 0x684
+#define QSERDES_V8_LALB_CDR_FASTLOCK_CP_CUR_PLL_RATE4 0x688
+#define QSERDES_V8_LALB_DEBUG_BUS_SEL 0x68c
+#define QSERDES_V8_LALB_BIST_STATUS 0x690
+#define QSERDES_V8_LALB_BIST_ERROR_COUNT1 0x694
+#define QSERDES_V8_LALB_BIST_ERROR_COUNT2 0x698
+#define QSERDES_V8_LALB_AC_JTAG_OUTP 0x69c
+#define QSERDES_V8_LALB_AC_JTAG_OUTN 0x6a0
+#define QSERDES_V8_LALB_DATA_SLICER_DEBUG_STATUS 0x6a4
+#define QSERDES_V8_LALB_DATA_SLICER_TIMER1_STATUS 0x6a8
+#define QSERDES_V8_LALB_DATA_SLICER_TIMER2_STATUS 0x6ac
+#define QSERDES_V8_LALB_TX0_RESTRIM_CODE_STATUS 0x6b0
+#define QSERDES_V8_LALB_TX0_RESTRIM_ICAL_CODE_STATUS 0x6b4
+#define QSERDES_V8_LALB_TX0_RESTRIM_CAL_STATUS 0x6b8
+#define QSERDES_V8_LALB_TX1_RESTRIM_CODE_STATUS 0x6bc
+#define QSERDES_V8_LALB_TX1_RESTRIM_ICAL_CODE_STATUS 0x6c0
+#define QSERDES_V8_LALB_TX1_RESTRIM_CAL_STATUS 0x6c4
+#define QSERDES_V8_LALB_CMUX_DCC_CAL_FSM_STATUS 0x6c8
+#define QSERDES_V8_LALB_CMUX_DCC_READCODE_STATUS 0x6cc
+#define QSERDES_V8_LALB_TX_DCC_CAL_ANA_STATUS 0x6d0
+#define QSERDES_V8_LALB_TX0_CTUNE_DCC_FSM_DEBUG_STATUS 0x6d4
+#define QSERDES_V8_LALB_TX0_COARSE_DCC_READCODE_STATUS 0x6d8
+#define QSERDES_V8_LALB_TX0_FTUNE_MSB_DCC_FSM_DEBUG_STATUS 0x6dc
+#define QSERDES_V8_LALB_TX0_FTUNE_LSB_DCC_FSM_DEBUG_STATUS 0x6e0
+#define QSERDES_V8_LALB_TX0_FINE_DCC_READCODE_STATUS 0x6e4
+#define QSERDES_V8_LALB_TX1_CTUNE_DCC_FSM_DEBUG_STATUS 0x6e8
+#define QSERDES_V8_LALB_TX1_COARSE_DCC_READCODE_STATUS 0x6ec
+#define QSERDES_V8_LALB_TX1_FTUNE_MSB_DCC_FSM_DEBUG_STATUS 0x6f0
+#define QSERDES_V8_LALB_TX1_FTUNE_LSB_DCC_FSM_DEBUG_STATUS 0x6f4
+#define QSERDES_V8_LALB_TX1_FINE_DCC_READCODE_STATUS 0x6f8
+#define QSERDES_V8_LALB_CDR_VCO_CAL_STATUS 0x6fc
+#define QSERDES_V8_LALB_CDR_VCTRL_STATUS 0x700
+#define QSERDES_V8_LALB_CDR_VCO_CAP_CODE_STATUS 0x704
+#define QSERDES_V8_LALB_KVCO_CAL_DEBUG1_STATUS 0x708
+#define QSERDES_V8_LALB_KVCO_CAL_DEBUG2_STATUS 0x70c
+#define QSERDES_V8_LALB_KP_CAL_DEBUG1_STATUS 0x710
+#define QSERDES_V8_LALB_KP_CAL_DEBUG2_STATUS 0x714
+#define QSERDES_V8_LALB_CDR_VCO_FREQ_DEBUG1_STATUS 0x718
+#define QSERDES_V8_LALB_CDR_VCO_FREQ_DEBUG2_STATUS 0x71c
+#define QSERDES_V8_LALB_CDR_VCO_FREQ_DEBUG3_STATUS 0x720
+#define QSERDES_V8_LALB_CDR_VCO_FREQ_DEBUG4_STATUS 0x724
+#define QSERDES_V8_LALB_IVCM_CAL_STATUS 0x728
+#define QSERDES_V8_LALB_IVCM_CAL_DEBUG_STATUS 0x72c
+#define QSERDES_V8_LALB_IDAC_STATUS_I0 0x730
+#define QSERDES_V8_LALB_IDAC_STATUS_I0BAR 0x734
+#define QSERDES_V8_LALB_IDAC_STATUS_I1 0x738
+#define QSERDES_V8_LALB_IDAC_STATUS_I1BAR 0x73c
+#define QSERDES_V8_LALB_IDAC_STATUS_Q 0x740
+#define QSERDES_V8_LALB_IDAC_STATUS_QBAR 0x744
+#define QSERDES_V8_LALB_IDAC_STATUS_A 0x748
+#define QSERDES_V8_LALB_IDAC_STATUS_ABAR 0x74c
+#define QSERDES_V8_LALB_IDAC_STATUS_SM_ON 0x750
+#define QSERDES_V8_LALB_IDAC_STATUS_SIGNERROR 0x754
+#define QSERDES_V8_LALB_RX_SIGDET_STATUS 0x758
+#define QSERDES_V8_LALB_SIGDET_CAL_CODE_STATUS 0x75c
+#define QSERDES_V8_LALB_SIGDET_CAL_FSM_DEBUG_STATUS 0x760
+#define QSERDES_V8_LALB_CDR_FREQ_LOCK_CNT_STATUS 0x764
+#define QSERDES_V8_LALB_CDR_PHASE_LOCK_CNT_STATUS 0x768
+#define QSERDES_V8_LALB_CDR_LOCK_DEBUG_STATUS 0x76c
+#define QSERDES_V8_LALB_IDATA_HIGH_STATUS1 0x770
+#define QSERDES_V8_LALB_IDATA_HIGH_STATUS2 0x774
+#define QSERDES_V8_LALB_IDATA_HIGH_STATUS3 0x778
+#define QSERDES_V8_LALB_IDATA_HIGH_STATUS4 0x77c
+#define QSERDES_V8_LALB_IDATA_LOW_STATUS1 0x780
+#define QSERDES_V8_LALB_IDATA_LOW_STATUS2 0x784
+#define QSERDES_V8_LALB_IDATA_LOW_STATUS3 0x788
+#define QSERDES_V8_LALB_IDATA_LOW_STATUS4 0x78c
+#define QSERDES_V8_LALB_QDATA_STATUS1 0x790
+#define QSERDES_V8_LALB_QDATA_STATUS2 0x794
+#define QSERDES_V8_LALB_QDATA_STATUS3 0x798
+#define QSERDES_V8_LALB_QDATA_STATUS4 0x79c
+#define QSERDES_V8_LALB_IA_ERROR_COUNTER_LOW 0x7a0
+#define QSERDES_V8_LALB_IA_ERROR_COUNTER_HIGH 0x7a4
+#define QSERDES_V8_LALB_EOM_ERR_CNT_LSB_STATUS 0x7a8
+#define QSERDES_V8_LALB_EOM_ERR_CNT_MSB_STATUS 0x7ac
+#define QSERDES_V8_LALB_EOM_OP_STATUS 0x7b0
+#define QSERDES_V8_LALB_AUX_MIXER_INDEX_STATUS 0x7b4
+#define QSERDES_V8_LALB_AUX_OFFSET_STATUS 0x7b8
+#define QSERDES_V8_LALB_AUXDATA_TB_STATUS 0x7bc
+#define QSERDES_V8_LALB_AUX_MIXER_CTRL_0_STATUS 0x7c0
+#define QSERDES_V8_LALB_AUX_MIXER_CTRL_90_STATUS 0x7c4
+#define QSERDES_V8_LALB_AUX_MIXER_CTRL_180_STATUS 0x7c8
+#define QSERDES_V8_LALB_IQ_MIXER_INDEX_STATUS 0x7cc
+#define QSERDES_V8_LALB_IQTUNE_FLTR_INDEX_STATUS 0x7d0
+#define QSERDES_V8_LALB_IQ_MIXER_CTRL_0_STATUS 0x7d4
+#define QSERDES_V8_LALB_IQ_MIXER_CTRL_90_STATUS 0x7d8
+#define QSERDES_V8_LALB_IQ_MIXER_CTRL_180_STATUS 0x7dc
+#define QSERDES_V8_LALB_READ_EQCODE 0x7e0
+#define QSERDES_V8_LALB_READ_OFFSETCODE 0x7e4
+#define QSERDES_V8_LALB_VGA_READ_CODE 0x7e8
+#define QSERDES_V8_LALB_VTHRESH_READ_CODE 0x7ec
+#define QSERDES_V8_LALB_DFE_TAP1_READ_CODE 0x7f0
+#define QSERDES_V8_LALB_DFE_TAP2_READ_CODE 0x7f4
+#define QSERDES_V8_LALB_DFE_TAP3_READ_CODE 0x7f8
+#define QSERDES_V8_LALB_DFE_TAP4_READ_CODE 0x7fc
+#define QSERDES_V8_LALB_DFE_TAP5_READ_CODE 0x800
+#define QSERDES_V8_LALB_DFE_TAP6_READ_CODE 0x804
+#define QSERDES_V8_LALB_DFE_TAP7_READ_CODE 0x808
+#define QSERDES_V8_LALB_CDR_IQTUNE_FILTER_BIN_CODE 0x80c
+#define QSERDES_V8_LALB_CDR_IQTUNE_FILTER_CLK0_CODE 0x810
+#define QSERDES_V8_LALB_CDR_IQTUNE_FILTER_CLK90_CODE 0x814
+#define QSERDES_V8_LALB_BLW_READ_CODE 0x818
+#define QSERDES_V8_LALB_IA_OFFSET_CAL_DEBUG_STATUS 0x81c
+#define QSERDES_V8_LALB_IA_OFFSET_CAL_STATUS 0x820
+#define QSERDES_V8_LALB_IVTH_CAL_STATUS 0x824
+#define QSERDES_V8_LALB_IVTH_NRZ_EYE_HEIGHT_STATUS 0x828
+#define QSERDES_V8_LALB_IVTH_UPPER_EYE_MAX_STATUS 0x82c
+#define QSERDES_V8_LALB_IVTH_UPPER_EYE_MIN_STATUS 0x830
+#define QSERDES_V8_LALB_IVTH_LOWER_EYE_MAX_STATUS 0x834
+#define QSERDES_V8_LALB_IVTH_LOWER_EYE_MIN_STATUS 0x838
+#define QSERDES_V8_LALB_IVTH_UP_INIT_CTR_STATUS 0x83c
+#define QSERDES_V8_LALB_VTH_I_UP_CNTRL_STATUS 0x840
+#define QSERDES_V8_LALB_VTH_I_DN_CNTRL_STATUS 0x844
+#define QSERDES_V8_LALB_NRZ_EYE_HEIGHT_SEL_STATUS 0x848
+#define QSERDES_V8_LALB_DEBUG_BUS0 0x84c
+#define QSERDES_V8_LALB_DEBUG_BUS1 0x850
+#define QSERDES_V8_LALB_DEBUG_BUS2 0x854
+#define QSERDES_V8_LALB_DEBUG_BUS3 0x858
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL1 0x85c
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL2 0x860
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL3 0x864
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL4 0x868
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL5 0x86c
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL6 0x870
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL7 0x874
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL8 0x878
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL9 0x87c
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL10 0x880
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL11 0x884
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL12 0x888
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL13 0x88c
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL14 0x890
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL15 0x894
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL16 0x898
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL17 0x89c
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL18 0x8a0
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL19 0x8a4
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL20 0x8a8
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL21 0x8ac
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL22 0x8b0
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL23 0x8b4
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL24 0x8b8
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL25 0x8bc
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL26 0x8c0
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL27 0x8c4
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL28 0x8c8
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL29 0x8cc
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL30 0x8d0
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL31 0x8d4
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL32 0x8d8
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL_V2_1 0x8dc
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL_V2_2 0x8e0
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL_V2_3 0x8e4
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL_V2_4 0x8e8
+#define QSERDES_V8_LALB_DIG_BKUP_CTRL_V2_5 0x8ec
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS1 0x8f0
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS2 0x8f4
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS3 0x8f8
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS4 0x8fc
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS5 0x900
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS6 0x904
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS7 0x908
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS8 0x90c
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS9 0x910
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS10 0x914
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS11 0x918
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS12 0x91c
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS13 0x920
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS14 0x924
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS15 0x928
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS16 0x92c
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS17 0x930
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS18 0x934
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS19 0x938
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS20 0x93c
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS21 0x940
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS22 0x944
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS23 0x948
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS24 0x94c
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS25 0x950
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS26 0x954
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS27 0x958
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS28 0x95c
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS29 0x960
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS30 0x964
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS31 0x968
+#define QSERDES_V8_LALB_DIG_BKUP_RO_BUS32 0x96c
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS1 0x970
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS2 0x974
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS3 0x978
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS4 0x97c
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS5 0x980
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS6 0x984
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS7 0x988
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS8 0x98c
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS9 0x990
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS10 0x994
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS11 0x998
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS12 0x99c
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS13 0x9a0
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS14 0x9a4
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS15 0x9a8
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS16 0x9ac
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS17 0x9b0
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS18 0x9b4
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS19 0x9b8
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS20 0x9bc
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS21 0x9c0
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS22 0x9c4
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS23 0x9c8
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS24 0x9cc
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS25 0x9d0
+#define QSERDES_V8_LALB_DIG_BKUP_RO_V2_BUS26 0x9d4
+#endif /* QCOM_PHY_QMP_QSERDES_V8_LALBH_ */
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-pcie-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-pcie-v8.h
new file mode 100644
index 000000000000..181846e08c0f
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-pcie-v8.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_TXRX_PCIE_V8_H_
+#define QCOM_PHY_QMP_QSERDES_TXRX_PCIE_V8_H_
+
+#define QSERDES_V8_PCIE_TX_RES_CODE_LANE_OFFSET_TX 0x030
+#define QSERDES_V8_PCIE_TX_RES_CODE_LANE_OFFSET_RX 0x034
+#define QSERDES_V8_PCIE_TX_LANE_MODE_1 0x07c
+#define QSERDES_V8_PCIE_TX_LANE_MODE_2 0x080
+#define QSERDES_V8_PCIE_TX_LANE_MODE_3 0x084
+#define QSERDES_V8_PCIE_TX_TRAN_DRVR_EMP_EN 0x0b4
+#define QSERDES_V8_PCIE_TX_TX_BAND0 0x0e0
+#define QSERDES_V8_PCIE_TX_TX_BAND1 0x0e4
+#define QSERDES_V8_PCIE_TX_SEL_10B_8B 0x0f4
+#define QSERDES_V8_PCIE_TX_SEL_20B_10B 0x0f8
+#define QSERDES_V8_PCIE_TX_PARRATE_REC_DETECT_IDLE_EN 0x058
+#define QSERDES_V8_PCIE_TX_TX_ADAPT_POST_THRESH1 0x118
+#define QSERDES_V8_PCIE_TX_TX_ADAPT_POST_THRESH2 0x11c
+#define QSERDES_V8_PCIE_TX_PHPRE_CTRL 0x128
+#define QSERDES_V8_PCIE_TX_EQ_RCF_CTRL_RATE3 0x148
+#define QSERDES_V8_PCIE_TX_EQ_RCF_CTRL_RATE4 0x14c
+
+#define QSERDES_V8_PCIE_RX_UCDR_FO_GAIN_RATE4 0x0dc
+#define QSERDES_V8_PCIE_RX_UCDR_SO_GAIN_RATE3 0x0ec
+#define QSERDES_V8_PCIE_RX_UCDR_SO_GAIN_RATE4 0x0f0
+#define QSERDES_V8_PCIE_RX_UCDR_PI_CONTROLS 0x0f4
+#define QSERDES_V8_PCIE_RX_VGA_CAL_CNTRL1 0x170
+#define QSERDES_V8_PCIE_RX_VGA_CAL_MAN_VAL 0x178
+#define QSERDES_V8_PCIE_RX_RX_EQU_ADAPTOR_CNTRL4 0x1b4
+#define QSERDES_V8_PCIE_RX_SIGDET_ENABLES 0x1d8
+#define QSERDES_V8_PCIE_RX_SIGDET_LVL 0x1e0
+#define QSERDES_V8_PCIE_RX_RXCLK_DIV2_CTRL 0x0b8
+#define QSERDES_V8_PCIE_RX_RX_BAND_CTRL0 0x0bc
+#define QSERDES_V8_PCIE_RX_RX_TERM_BW_CTRL0 0x0c4
+#define QSERDES_V8_PCIE_RX_RX_TERM_BW_CTRL1 0x0c8
+#define QSERDES_V8_PCIE_RX_SVS_MODE_CTRL 0x0b4
+#define QSERDES_V8_PCIE_RX_UCDR_PI_CTRL1 0x058
+#define QSERDES_V8_PCIE_RX_UCDR_PI_CTRL2 0x05c
+#define QSERDES_V8_PCIE_RX_UCDR_SB2_THRESH2_RATE3 0x084
+#define QSERDES_V8_PCIE_RX_UCDR_SB2_GAIN1_RATE3 0x098
+#define QSERDES_V8_PCIE_RX_UCDR_SB2_GAIN2_RATE3 0x0ac
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE_0_1_B0 0x218
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE_0_1_B1 0x21c
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE_0_1_B2 0x220
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE_0_1_B4 0x228
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE_0_1_B7 0x234
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE3_B0 0x260
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE3_B1 0x264
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE3_B2 0x268
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE3_B3 0x26c
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE3_B4 0x270
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B0 0x284
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B1 0x288
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B2 0x28c
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B3 0x290
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B4 0x294
+#define QSERDES_V8_PCIE_RX_RX_MODE_RATE4_SA_B5 0x298
+#define QSERDES_V8_PCIE_RX_Q_PI_INTRINSIC_BIAS_RATE32 0x31c
+#define QSERDES_V8_PCIE_RX_Q_PI_INTRINSIC_BIAS_RATE4 0x320
+#define QSERDES_V8_PCIE_RX_EOM_MAX_ERR_LIMIT_LSB 0x11c
+#define QSERDES_V8_PCIE_RX_EOM_MAX_ERR_LIMIT_MSB 0x120
+#define QSERDES_V8_PCIE_RX_AUXDATA_BIN_RATE23 0x108
+#define QSERDES_V8_PCIE_RX_AUXDATA_BIN_RATE4 0x10c
+#define QSERDES_V8_PCIE_RX_VTHRESH_CAL_MAN_VAL_RATE3 0x198
+#define QSERDES_V8_PCIE_RX_VTHRESH_CAL_MAN_VAL_RATE4 0x19c
+#define QSERDES_V8_PCIE_RX_GM_CAL 0x1a0
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h
new file mode 100644
index 000000000000..34919720b7bc
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v2.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_TXRX_V2_H_
+#define QCOM_PHY_QMP_QSERDES_TXRX_V2_H_
+
+/* Only for QMP V2 PHY - TX registers */
+#define QSERDES_V2_TX_BIST_MODE_LANENO 0x000
+#define QSERDES_V2_TX_CLKBUF_ENABLE 0x008
+#define QSERDES_V2_TX_TX_EMP_POST1_LVL 0x00c
+#define QSERDES_V2_TX_TX_DRV_LVL 0x01c
+#define QSERDES_V2_TX_RESET_TSYNC_EN 0x024
+#define QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN 0x028
+#define QSERDES_V2_TX_TX_BAND 0x02c
+#define QSERDES_V2_TX_SLEW_CNTL 0x030
+#define QSERDES_V2_TX_INTERFACE_SELECT 0x034
+#define QSERDES_V2_TX_RES_CODE_LANE_TX 0x03c
+#define QSERDES_V2_TX_RES_CODE_LANE_RX 0x040
+#define QSERDES_V2_TX_RES_CODE_LANE_OFFSET_TX 0x044
+#define QSERDES_V2_TX_RES_CODE_LANE_OFFSET_RX 0x048
+#define QSERDES_V2_TX_DEBUG_BUS_SEL 0x058
+#define QSERDES_V2_TX_TRANSCEIVER_BIAS_EN 0x05c
+#define QSERDES_V2_TX_HIGHZ_DRVR_EN 0x060
+#define QSERDES_V2_TX_TX_POL_INV 0x064
+#define QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN 0x068
+#define QSERDES_V2_TX_LANE_MODE_1 0x08c
+#define QSERDES_V2_TX_LANE_MODE_2 0x090
+#define QSERDES_V2_TX_LANE_MODE_3 0x094
+#define QSERDES_V2_TX_RCV_DETECT_LVL_2 0x0a4
+#define QSERDES_V2_TX_TRAN_DRVR_EMP_EN 0x0c0
+#define QSERDES_V2_TX_TX_INTERFACE_MODE 0x0c4
+#define QSERDES_V2_TX_VMODE_CTRL1 0x0f0
+
+/* Only for QMP V2 PHY - RX registers */
+#define QSERDES_V2_RX_UCDR_FO_GAIN 0x008
+#define QSERDES_V2_RX_UCDR_SO_GAIN_HALF 0x00c
+#define QSERDES_V2_RX_UCDR_SO_GAIN 0x014
+#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_HALF 0x024
+#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028
+#define QSERDES_V2_RX_UCDR_SVS_SO_GAIN 0x02c
+#define QSERDES_V2_RX_UCDR_FASTLOCK_FO_GAIN 0x030
+#define QSERDES_V2_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034
+#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c
+#define QSERDES_V2_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040
+#define QSERDES_V2_RX_UCDR_PI_CONTROLS 0x044
+#define QSERDES_V2_RX_RX_TERM_BW 0x07c
+#define QSERDES_V2_RX_VGA_CAL_CNTRL1 0x0bc
+#define QSERDES_V2_RX_VGA_CAL_CNTRL2 0x0c0
+#define QSERDES_V2_RX_RX_EQ_GAIN2_LSB 0x0c8
+#define QSERDES_V2_RX_RX_EQ_GAIN2_MSB 0x0cc
+#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL1 0x0d0
+#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d4
+#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL3 0x0d8
+#define QSERDES_V2_RX_RX_EQU_ADAPTOR_CNTRL4 0x0dc
+#define QSERDES_V2_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x0f8
+#define QSERDES_V2_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x0fc
+#define QSERDES_V2_RX_SIGDET_ENABLES 0x100
+#define QSERDES_V2_RX_SIGDET_CNTRL 0x104
+#define QSERDES_V2_RX_SIGDET_LVL 0x108
+#define QSERDES_V2_RX_SIGDET_DEGLITCH_CNTRL 0x10c
+#define QSERDES_V2_RX_RX_BAND 0x110
+#define QSERDES_V2_RX_RX_INTERFACE_MODE 0x11c
+#define QSERDES_V2_RX_RX_MODE_00 0x164
+#define QSERDES_V2_RX_RX_MODE_01 0x168
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index 8a280433a42b..df138a5442eb 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -84,6 +84,68 @@ static const unsigned int ufsphy_v6_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_UFS_POWER_DOWN_CONTROL,
};
+static const struct qmp_phy_init_tbl milos_ufsphy_serdes[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x17),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x98),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x32),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x0f),
+};
+
+static const struct qmp_phy_init_tbl milos_ufsphy_tx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_RX, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0xcc),
+};
+
+static const struct qmp_phy_init_tbl milos_ufsphy_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x3e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xce),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xce),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B2, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B4, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B3, 0x9e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B6, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B3, 0x9e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B4, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B5, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CTRL1, 0x94),
+};
+
+static const struct qmp_phy_init_tbl milos_ufsphy_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x0b),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x68),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
+};
+
static const struct qmp_phy_init_tbl msm8996_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e),
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0xd7),
@@ -1165,6 +1227,11 @@ static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val)
}
/* Regulator bulk data with load values for specific configurations */
+static const struct regulator_bulk_data milos_ufsphy_vreg_l[] = {
+ { .supply = "vdda-phy", .init_load_uA = 140120 },
+ { .supply = "vdda-pll", .init_load_uA = 18340 },
+};
+
static const struct regulator_bulk_data msm8996_ufsphy_vreg_l[] = {
{ .supply = "vdda-phy", .init_load_uA = 51400 },
{ .supply = "vdda-pll", .init_load_uA = 14600 },
@@ -1258,6 +1325,32 @@ static const struct qmp_ufs_offsets qmp_ufs_offsets_v6 = {
.rx2 = 0x1a00,
};
+static const struct qmp_phy_cfg milos_ufsphy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_ufs_offsets_v6,
+ .max_supported_gear = UFS_HS_G4,
+
+ .tbls = {
+ .serdes = milos_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(milos_ufsphy_serdes),
+ .tx = milos_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(milos_ufsphy_tx),
+ .rx = milos_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(milos_ufsphy_rx),
+ .pcs = milos_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(milos_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sm8550_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes),
+ },
+
+ .vreg_list = milos_ufsphy_vreg_l,
+ .num_vregs = ARRAY_SIZE(milos_ufsphy_vreg_l),
+ .regs = ufsphy_v6_regs_layout,
+};
+
static const struct qmp_phy_cfg msm8996_ufsphy_cfg = {
.lanes = 1,
@@ -2166,6 +2259,9 @@ err_node_put:
static const struct of_device_id qmp_ufs_of_match_table[] = {
{
+ .compatible = "qcom,milos-qmp-ufs-phy",
+ .data = &milos_ufsphy_cfg,
+ }, {
.compatible = "qcom,msm8996-qmp-ufs-phy",
.data = &msm8996_ufsphy_cfg,
}, {
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
index ed646a7e705b..b0ecd5ba2464 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
@@ -28,6 +28,7 @@
#include "phy-qcom-qmp-pcs-usb-v5.h"
#include "phy-qcom-qmp-pcs-usb-v6.h"
#include "phy-qcom-qmp-pcs-usb-v7.h"
+#include "phy-qcom-qmp-pcs-usb-v8.h"
#define PHY_INIT_COMPLETE_TIMEOUT 10000
@@ -109,6 +110,139 @@ static const unsigned int qmp_v7_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V7_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR,
};
+static const struct qmp_phy_init_tbl glymur_usb3_uniphy_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_STEP_SIZE1_MODE1, 0xc0),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_STEP_SIZE2_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CORECLK_DIV_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP1_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP2_MODE1, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DEC_START_MODE1, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DEC_START_MSB_MODE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START1_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START2_MODE1, 0x75),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START3_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_HSCLK_SEL_1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_VCO_TUNE1_MODE1, 0x25),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_VCO_TUNE2_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0x5c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x5c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_STEP_SIZE1_MODE0, 0xc0),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_STEP_SIZE2_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP1_MODE0, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP2_MODE0, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DEC_START_MODE0, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DEC_START_MSB_MODE0, 0x00),
+
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START1_MODE0, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START2_MODE0, 0x75),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DIV_FRAC_START3_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_VCO_TUNE1_MODE0, 0x25),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_VCO_TUNE2_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_BG_TIMER, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_EN_CENTER, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_PER1, 0x62),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SSC_PER2, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SYSCLK_BUF_ENABLE, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SYSCLK_EN_SEL, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP_CFG, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CORE_CLK_EN, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_AUTO_GAIN_ADJ_CTRL_1, 0xb6),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_AUTO_GAIN_ADJ_CTRL_2, 0x4a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_AUTO_GAIN_ADJ_CTRL_3, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_ADDITIONAL_MISC, 0x0c),
+};
+
+static const struct qmp_phy_init_tbl glymur_usb3_uniphy_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_LOCK_DETECT_CONFIG1, 0xc4),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_LOCK_DETECT_CONFIG2, 0x89),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_LOCK_DETECT_CONFIG3, 0x20),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_LOCK_DETECT_CONFIG6, 0x13),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_REFGEN_REQ_CONFIG1, 0x21),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_RX_SIGDET_LVL, 0x55),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_CDR_RESET_TIME, 0x0a),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_ALIGN_DETECT_CONFIG1, 0xd4),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_ALIGN_DETECT_CONFIG2, 0x30),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_PCS_TX_RX_CONFIG, 0x0c),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_EQ_CONFIG1, 0x4b),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_EQ_CONFIG5, 0x10),
+};
+
+static const struct qmp_phy_init_tbl glymur_usb3_uniphy_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_TX_RES_CODE_LANE_TX, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_TX_RES_CODE_LANE_RX, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_TX_RES_CODE_LANE_OFFSET_TX, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_TX_RES_CODE_LANE_OFFSET_RX, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V8_TX_LANE_MODE_1, 0xf5),
+ QMP_PHY_INIT_CFG(QSERDES_V8_TX_LANE_MODE_3, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V8_TX_LANE_MODE_4, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V8_TX_LANE_MODE_5, 0x5f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_TX_RCV_DETECT_LVL_2, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V8_TX_PI_QEC_CTRL, 0x21),
+};
+
+static const struct qmp_phy_init_tbl glymur_usb3_uniphy_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_UCDR_FO_GAIN, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_UCDR_SO_GAIN, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_UCDR_PI_CONTROLS, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_UCDR_SB2_THRESH1, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_UCDR_SB2_THRESH2, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_UCDR_SB2_GAIN1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_UCDR_SB2_GAIN2, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_AUX_DATA_TCOARSE_TFINE, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_VGA_CAL_CNTRL1, 0x54),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_VGA_CAL_CNTRL2, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_GM_CAL, 0x1b),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_IDAC_TSETTLE_LOW, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_IDAC_TSETTLE_HIGH, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x27),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_SIGDET_ENABLES, 0x0c),
+
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_SIGDET_CNTRL, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_SIGDET_DEGLITCH_CNTRL, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_MODE_00_LOW, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_MODE_00_HIGH, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_MODE_00_HIGH2, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_MODE_00_HIGH3, 0xdf),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_MODE_00_HIGH4, 0xed),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_MODE_01_LOW, 0x19),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_MODE_01_HIGH, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_MODE_01_HIGH2, 0x91),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_MODE_01_HIGH3, 0xb7),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_RX_MODE_01_HIGH4, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_DFE_EN_TIMER, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_DCC_CTRL1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_VTH_CODE, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_SIGDET_CAL_CTRL1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V8_RX_SIGDET_CAL_TRIM, 0x08),
+};
+
+static const struct qmp_phy_init_tbl glymur_usb3_uniphy_pcs_usb_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_USB_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_USB_RXEQTRAINING_DFE_TIME_S2, 0x07),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_USB_RXEQTRAINING_WAIT_TIME, 0x75),
+ QMP_PHY_INIT_CFG(QPHY_V8_PCS_USB_RCVR_DTCT_DLY_U3_L, 0x40),
+};
+
static const struct qmp_phy_init_tbl ipq9574_usb3_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x1a),
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
@@ -1266,7 +1400,7 @@ struct qmp_phy_cfg {
int pcs_usb_tbl_num;
/* regulators to be requested */
- const char * const *vreg_list;
+ const struct regulator_bulk_data *vreg_list;
int num_vregs;
/* array of registers with different offsets */
@@ -1344,8 +1478,9 @@ static const char * const usb3phy_reset_l[] = {
};
/* list of regulators */
-static const char * const qmp_phy_vreg_l[] = {
- "vdda-phy", "vdda-pll",
+static const struct regulator_bulk_data qmp_phy_vreg_l[] = {
+ { .supply = "vdda-phy", .init_load_uA = 21800, },
+ { .supply = "vdda-pll", .init_load_uA = 36000, },
};
static const struct qmp_usb_offsets qmp_usb_offsets_v3 = {
@@ -1403,6 +1538,14 @@ static const struct qmp_usb_offsets qmp_usb_offsets_v7 = {
.rx = 0x1000,
};
+static const struct qmp_usb_offsets qmp_usb_offsets_v8 = {
+ .serdes = 0,
+ .pcs = 0x0400,
+ .pcs_usb = 0x1200,
+ .tx = 0x0e00,
+ .rx = 0x1000,
+};
+
static const struct qmp_phy_cfg ipq6018_usb3phy_cfg = {
.offsets = &qmp_usb_offsets_v3,
@@ -1704,6 +1847,24 @@ static const struct qmp_phy_cfg x1e80100_usb3_uniphy_cfg = {
.regs = qmp_v7_usb3phy_regs_layout,
};
+static const struct qmp_phy_cfg glymur_usb3_uniphy_cfg = {
+ .offsets = &qmp_usb_offsets_v8,
+
+ .serdes_tbl = glymur_usb3_uniphy_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(glymur_usb3_uniphy_serdes_tbl),
+ .tx_tbl = glymur_usb3_uniphy_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(glymur_usb3_uniphy_tx_tbl),
+ .rx_tbl = glymur_usb3_uniphy_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(glymur_usb3_uniphy_rx_tbl),
+ .pcs_tbl = glymur_usb3_uniphy_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(glymur_usb3_uniphy_pcs_tbl),
+ .pcs_usb_tbl = glymur_usb3_uniphy_pcs_usb_tbl,
+ .pcs_usb_tbl_num = ARRAY_SIZE(glymur_usb3_uniphy_pcs_usb_tbl),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = qmp_v7_usb3phy_regs_layout,
+};
+
static int qmp_usb_serdes_init(struct qmp_usb *qmp)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -1986,23 +2147,6 @@ static const struct dev_pm_ops qmp_usb_pm_ops = {
qmp_usb_runtime_resume, NULL)
};
-static int qmp_usb_vreg_init(struct qmp_usb *qmp)
-{
- const struct qmp_phy_cfg *cfg = qmp->cfg;
- struct device *dev = qmp->dev;
- int num = cfg->num_vregs;
- int i;
-
- qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL);
- if (!qmp->vregs)
- return -ENOMEM;
-
- for (i = 0; i < num; i++)
- qmp->vregs[i].supply = cfg->vreg_list[i];
-
- return devm_regulator_bulk_get(dev, num, qmp->vregs);
-}
-
static int qmp_usb_reset_init(struct qmp_usb *qmp,
const char *const *reset_list,
int num_resets)
@@ -2251,7 +2395,8 @@ static int qmp_usb_probe(struct platform_device *pdev)
if (!qmp->cfg)
return -EINVAL;
- ret = qmp_usb_vreg_init(qmp);
+ ret = devm_regulator_bulk_get_const(dev, qmp->cfg->num_vregs,
+ qmp->cfg->vreg_list, &qmp->vregs);
if (ret)
return ret;
@@ -2302,6 +2447,9 @@ err_node_put:
static const struct of_device_id qmp_usb_of_match_table[] = {
{
+ .compatible = "qcom,glymur-qmp-usb3-uni-phy",
+ .data = &glymur_usb3_uniphy_cfg,
+ }, {
.compatible = "qcom,ipq5424-qmp-usb3-phy",
.data = &ipq9574_usb3phy_cfg,
}, {
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb43-pcs-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-usb43-pcs-v8.h
new file mode 100644
index 000000000000..4f387c8ed9e5
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb43-pcs-v8.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_USB43_PCS_V8_H_
+#define QCOM_PHY_QMP_USB43_PCS_V8_H_
+
+#define QPHY_V8_USB43_PCS_SW_RESET 0x000
+#define QPHY_V8_USB43_PCS_PCS_STATUS1 0x014
+#define QPHY_V8_USB43_PCS_POWER_DOWN_CONTROL 0x040
+#define QPHY_V8_USB43_PCS_START_CONTROL 0x044
+#define QPHY_V8_USB43_PCS_POWER_STATE_CONFIG1 0x090
+#define QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG1 0x0c4
+#define QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG2 0x0c8
+#define QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG3 0x0cc
+#define QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG6 0x0d8
+#define QPHY_V8_USB43_PCS_REFGEN_REQ_CONFIG1 0x0dc
+#define QPHY_V8_USB43_PCS_RX_SIGDET_LVL 0x188
+#define QPHY_V8_USB43_PCS_RCVR_DTCT_DLY_P1U2_L 0x190
+#define QPHY_V8_USB43_PCS_RCVR_DTCT_DLY_P1U2_H 0x194
+#define QPHY_V8_USB43_PCS_RATE_SLEW_CNTRL1 0x198
+#define QPHY_V8_USB43_PCS_TSYNC_RSYNC_TIME 0x1ac
+#define QPHY_V8_USB43_PCS_RX_CONFIG 0x1b0
+#define QPHY_V8_USB43_PCS_TSYNC_DLY_TIME 0x1b4
+#define QPHY_V8_USB43_PCS_ALIGN_DETECT_CONFIG1 0x1c0
+#define QPHY_V8_USB43_PCS_ALIGN_DETECT_CONFIG2 0x1c4
+#define QPHY_V8_USB43_PCS_PCS_TX_RX_CONFIG 0x1d0
+#define QPHY_V8_USB43_PCS_EQ_CONFIG1 0x1dc
+#define QPHY_V8_USB43_PCS_EQ_CONFIG2 0x1e0
+#define QPHY_V8_USB43_PCS_EQ_CONFIG5 0x1ec
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb43-qserdes-com-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-usb43-qserdes-com-v8.h
new file mode 100644
index 000000000000..e9c743fce9d1
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb43-qserdes-com-v8.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_USB43_QSERDES_COM_V8_H_
+#define QCOM_PHY_QMP_USB43_QSERDES_COM_V8_H_
+
+#define QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE1 0x000
+#define QSERDES_V8_USB43_COM_SSC_STEP_SIZE2_MODE1 0x004
+#define QSERDES_V8_USB43_COM_SSC_STEP_SIZE3_MODE1 0x008
+#define QSERDES_V8_USB43_COM_CLK_EP_DIV_MODE1 0x00c
+#define QSERDES_V8_USB43_COM_CP_CTRL_MODE1 0x010
+#define QSERDES_V8_USB43_COM_PLL_RCTRL_MODE1 0x014
+#define QSERDES_V8_USB43_COM_PLL_CCTRL_MODE1 0x018
+#define QSERDES_V8_USB43_COM_CORECLK_DIV_MODE1 0x01c
+#define QSERDES_V8_USB43_COM_LOCK_CMP1_MODE1 0x020
+#define QSERDES_V8_USB43_COM_LOCK_CMP2_MODE1 0x024
+#define QSERDES_V8_USB43_COM_DEC_START_MODE1 0x028
+#define QSERDES_V8_USB43_COM_DEC_START_MSB_MODE1 0x02c
+#define QSERDES_V8_USB43_COM_DIV_FRAC_START1_MODE1 0x030
+#define QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE1 0x034
+#define QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE1 0x038
+#define QSERDES_V8_USB43_COM_HSCLK_SEL_1 0x03c
+#define QSERDES_V8_USB43_COM_INTEGLOOP_GAIN0_MODE1 0x040
+#define QSERDES_V8_USB43_COM_INTEGLOOP_GAIN1_MODE1 0x044
+#define QSERDES_V8_USB43_COM_VCO_TUNE1_MODE1 0x048
+#define QSERDES_V8_USB43_COM_VCO_TUNE2_MODE1 0x04c
+#define QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE1 0x050
+#define QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE1 0x054
+#define QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x058
+#define QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x05c
+#define QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE0 0x060
+#define QSERDES_V8_USB43_COM_SSC_STEP_SIZE2_MODE0 0x064
+#define QSERDES_V8_USB43_COM_SSC_STEP_SIZE3_MODE0 0x068
+#define QSERDES_V8_USB43_COM_CLK_EP_DIV_MODE0 0x06c
+#define QSERDES_V8_USB43_COM_CP_CTRL_MODE0 0x070
+#define QSERDES_V8_USB43_COM_PLL_RCTRL_MODE0 0x074
+#define QSERDES_V8_USB43_COM_PLL_CCTRL_MODE0 0x078
+#define QSERDES_V8_USB43_COM_CORECLK_DIV_MODE0 0x07c
+#define QSERDES_V8_USB43_COM_LOCK_CMP1_MODE0 0x080
+#define QSERDES_V8_USB43_COM_LOCK_CMP2_MODE0 0x084
+#define QSERDES_V8_USB43_COM_DEC_START_MODE0 0x088
+#define QSERDES_V8_USB43_COM_DEC_START_MSB_MODE0 0x08c
+#define QSERDES_V8_USB43_COM_DIV_FRAC_START1_MODE0 0x090
+#define QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE0 0x094
+#define QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE0 0x098
+#define QSERDES_V8_USB43_COM_HSCLK_HS_SWITCH_SEL_1 0x09c
+#define QSERDES_V8_USB43_COM_INTEGLOOP_GAIN0_MODE0 0x0a0
+#define QSERDES_V8_USB43_COM_INTEGLOOP_GAIN1_MODE0 0x0a4
+#define QSERDES_V8_USB43_COM_VCO_TUNE1_MODE0 0x0a8
+#define QSERDES_V8_USB43_COM_VCO_TUNE2_MODE0 0x0ac
+#define QSERDES_V8_USB43_COM_ATB_SEL1 0x0b0
+#define QSERDES_V8_USB43_COM_ATB_SEL2 0x0b4
+#define QSERDES_V8_USB43_COM_FREQ_UPDATE 0x0b8
+#define QSERDES_V8_USB43_COM_BG_TIMER 0x0bc
+#define QSERDES_V8_USB43_COM_SSC_EN_CENTER 0x0c0
+#define QSERDES_V8_USB43_COM_SSC_ADJ_PER1 0x0c4
+#define QSERDES_V8_USB43_COM_SSC_ADJ_PER2 0x0c8
+#define QSERDES_V8_USB43_COM_SSC_PER1 0x0cc
+#define QSERDES_V8_USB43_COM_SSC_PER2 0x0d0
+#define QSERDES_V8_USB43_COM_POST_DIV 0x0d4
+#define QSERDES_V8_USB43_COM_POST_DIV_MUX 0x0d8
+#define QSERDES_V8_USB43_COM_BIAS_EN_CLKBUFLR_EN 0x0dc
+#define QSERDES_V8_USB43_COM_CLK_ENABLE1 0x0e0
+#define QSERDES_V8_USB43_COM_SYS_CLK_CTRL 0x0e4
+#define QSERDES_V8_USB43_COM_SYSCLK_BUF_ENABLE 0x0e8
+#define QSERDES_V8_USB43_COM_PLL_EN 0x0ec
+#define QSERDES_V8_USB43_COM_DEBUG_BUS_OVRD 0x0f0
+#define QSERDES_V8_USB43_COM_PLL_IVCO 0x0f4
+#define QSERDES_V8_USB43_COM_PLL_IVCO_MODE1 0x0f8
+#define QSERDES_V8_USB43_COM_CMN_IETRIM 0x0fc
+#define QSERDES_V8_USB43_COM_CMN_IPTRIM 0x100
+#define QSERDES_V8_USB43_COM_EP_CLOCK_DETECT_CTRL 0x104
+#define QSERDES_V8_USB43_COM_PLL_CNTRL 0x108
+#define QSERDES_V8_USB43_COM_BIAS_EN_CTRL_BY_PSM 0x10c
+#define QSERDES_V8_USB43_COM_SYSCLK_EN_SEL 0x110
+#define QSERDES_V8_USB43_COM_CML_SYSCLK_SEL 0x114
+#define QSERDES_V8_USB43_COM_RESETSM_CNTRL 0x118
+#define QSERDES_V8_USB43_COM_RESETSM_CNTRL2 0x11c
+#define QSERDES_V8_USB43_COM_LOCK_CMP_EN 0x120
+#define QSERDES_V8_USB43_COM_LOCK_CMP_CFG 0x124
+#define QSERDES_V8_USB43_COM_INTEGLOOP_INITVAL 0x128
+#define QSERDES_V8_USB43_COM_INTEGLOOP_EN 0x12c
+#define QSERDES_V8_USB43_COM_INTEGLOOP_P_PATH_GAIN0 0x130
+#define QSERDES_V8_USB43_COM_INTEGLOOP_P_PATH_GAIN1 0x134
+#define QSERDES_V8_USB43_COM_VCOCAL_DEADMAN_CTRL 0x138
+#define QSERDES_V8_USB43_COM_VCO_TUNE_CTRL 0x13c
+#define QSERDES_V8_USB43_COM_VCO_TUNE_MAP 0x140
+#define QSERDES_V8_USB43_COM_VCO_TUNE_INITVAL1 0x144
+#define QSERDES_V8_USB43_COM_VCO_TUNE_INITVAL2 0x148
+#define QSERDES_V8_USB43_COM_VCO_TUNE_MINVAL1 0x14c
+#define QSERDES_V8_USB43_COM_VCO_TUNE_MINVAL2 0x150
+#define QSERDES_V8_USB43_COM_VCO_TUNE_MAXVAL1 0x154
+#define QSERDES_V8_USB43_COM_VCO_TUNE_MAXVAL2 0x158
+#define QSERDES_V8_USB43_COM_VCO_TUNE_TIMER1 0x15c
+#define QSERDES_V8_USB43_COM_VCO_TUNE_TIMER2 0x160
+#define QSERDES_V8_USB43_COM_CLK_SELECT 0x164
+#define QSERDES_V8_USB43_COM_PLL_ANALOG 0x168
+#define QSERDES_V8_USB43_COM_SW_RESET 0x16c
+#define QSERDES_V8_USB43_COM_CORE_CLK_EN 0x170
+#define QSERDES_V8_USB43_COM_CMN_CONFIG_1 0x174
+#define QSERDES_V8_USB43_COM_CMN_CONFIG_3 0x178
+#define QSERDES_V8_USB43_COM_CMN_RATE_OVERRIDE 0x17c
+#define QSERDES_V8_USB43_COM_SVS_MODE_CLK_SEL 0x180
+#define QSERDES_V8_USB43_COM_DEBUG_BUS_SEL 0x184
+#define QSERDES_V8_USB43_COM_CMN_MISC1 0x188
+#define QSERDES_V8_USB43_COM_CMN_MODE 0x18c
+#define QSERDES_V8_USB43_COM_CMN_MODE_CONTD 0x190
+#define QSERDES_V8_USB43_COM_CMN_MODE_CONTD1 0x194
+#define QSERDES_V8_USB43_COM_CMN_MODE_CONTD2 0x198
+#define QSERDES_V8_USB43_COM_VCO_DC_LEVEL_CTRL 0x19c
+#define QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_1 0x1a0
+#define QSERDES_V8_USB43_COM_ADDITIONAL_CTRL_1 0x1a4
+#define QSERDES_V8_USB43_COM_AUTO_GAIN_ADJ_CTRL_1 0x1a8
+#define QSERDES_V8_USB43_COM_AUTO_GAIN_ADJ_CTRL_2 0x1ac
+#define QSERDES_V8_USB43_COM_AUTO_GAIN_ADJ_CTRL_3 0x1b0
+#define QSERDES_V8_USB43_COM_AUTO_GAIN_ADJ_CTRL_4 0x1b4
+#define QSERDES_V8_USB43_COM_ADDITIONAL_MISC 0x1b8
+#define QSERDES_V8_USB43_COM_ADDITIONAL_MISC_2 0x1bc
+#define QSERDES_V8_USB43_COM_ADDITIONAL_MISC_3 0x1c0
+#define QSERDES_V8_USB43_COM_ADDITIONAL_MISC_4 0x1c4
+#define QSERDES_V8_USB43_COM_ADDITIONAL_MISC_5 0x1c8
+#define QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE2 0x1cc
+#define QSERDES_V8_USB43_COM_SSC_STEP_SIZE2_MODE2 0x1d0
+#define QSERDES_V8_USB43_COM_SSC_STEP_SIZE3_MODE2 0x1d4
+#define QSERDES_V8_USB43_COM_CLK_EP_DIV_MODE2 0x1d8
+#define QSERDES_V8_USB43_COM_CP_CTRL_MODE2 0x1dc
+#define QSERDES_V8_USB43_COM_PLL_RCTRL_MODE2 0x1e0
+#define QSERDES_V8_USB43_COM_PLL_CCTRL_MODE2 0x1e4
+#define QSERDES_V8_USB43_COM_CORECLK_DIV_MODE2 0x1e8
+#define QSERDES_V8_USB43_COM_LOCK_CMP1_MODE2 0x1ec
+#define QSERDES_V8_USB43_COM_LOCK_CMP2_MODE2 0x1f0
+#define QSERDES_V8_USB43_COM_DEC_START_MODE2 0x1f4
+#define QSERDES_V8_USB43_COM_DEC_START_MSB_MODE2 0x1f8
+#define QSERDES_V8_USB43_COM_DIV_FRAC_START1_MODE2 0x1fc
+#define QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE2 0x200
+#define QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE2 0x204
+#define QSERDES_V8_USB43_COM_INTEGLOOP_GAIN0_MODE2 0x208
+#define QSERDES_V8_USB43_COM_INTEGLOOP_GAIN1_MODE2 0x20c
+#define QSERDES_V8_USB43_COM_VCO_TUNE1_MODE2 0x210
+#define QSERDES_V8_USB43_COM_VCO_TUNE2_MODE2 0x214
+#define QSERDES_V8_USB43_COM_PLL_IVCO_MODE2 0x218
+#define QSERDES_V8_USB43_COM_HSCLK_SEL_2 0x21c
+#define QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE2 0x220
+#define QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE2 0x224
+#define QSERDES_V8_USB43_COM_HSCLK_HS_SWITCH_SEL_2 0x228
+#define QSERDES_V8_USB43_COM_CMN_CONFIG_2 0x22c
+#define QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_2 0x230
+#define QSERDES_V8_USB43_COM_IVCOCAL_CONFIG_0 0x234
+#define QSERDES_V8_USB43_COM_IVCOCAL_CONFIG_1 0x238
+#define QSERDES_V8_USB43_COM_IVCOCAL_CONFIG_2 0x23c
+#define QSERDES_V8_USB43_COM_IVCOCAL_CONFIG_3 0x240
+#define QSERDES_V8_USB43_COM_IVCOCAL_CONFIG_4 0x244
+#define QSERDES_V8_USB43_COM_IVCOCAL_CONFIG_5 0x248
+#define QSERDES_V8_USB43_COM_LOCK_CMP1_EARLY_MODE0 0x24c
+#define QSERDES_V8_USB43_COM_LOCK_CMP2_EARLY_MODE0 0x250
+#define QSERDES_V8_USB43_COM_LOCK_CMP1_EARLY_MODE1 0x254
+#define QSERDES_V8_USB43_COM_LOCK_CMP2_EARLY_MODE1 0x258
+#define QSERDES_V8_USB43_COM_LOCK_CMP1_EARLY_MODE2 0x25c
+#define QSERDES_V8_USB43_COM_LOCK_CMP2_EARLY_MODE2 0x260
+#define QSERDES_V8_USB43_COM_EARLY_LOCK_CONFIG_0 0x264
+#define QSERDES_V8_USB43_COM_EARLY_LOCK_CONFIG_1 0x268
+#define QSERDES_V8_USB43_COM_ADAPTIVE_ANALOG_CONFIG 0x26c
+#define QSERDES_V8_USB43_COM_CP_CTRL_ADAPTIVE_MODE0 0x270
+#define QSERDES_V8_USB43_COM_PLL_RCCTRL_ADAPTIVE_MODE0 0x274
+#define QSERDES_V8_USB43_COM_PLL_CCTRL_ADAPTIVE_MODE0 0x278
+#define QSERDES_V8_USB43_COM_CP_CTRL_ADAPTIVE_MODE1 0x27c
+#define QSERDES_V8_USB43_COM_PLL_RCCTRL_ADAPTIVE_MODE1 0x280
+#define QSERDES_V8_USB43_COM_PLL_CCTRL_ADAPTIVE_MODE1 0x284
+#define QSERDES_V8_USB43_COM_CP_CTRL_ADAPTIVE_MODE2 0x288
+#define QSERDES_V8_USB43_COM_PLL_RCCTRL_ADAPTIVE_MODE2 0x28c
+#define QSERDES_V8_USB43_COM_PLL_CCTRL_ADAPTIVE_MODE2 0x290
+#define QSERDES_V8_USB43_COM_CMN_MODE_CONTD3 0x294
+#define QSERDES_V8_USB43_COM_CMN_MODE_CONTD4 0x298
+#define QSERDES_V8_USB43_COM_CMN_MODE_CONTD5 0x29c
+#define QSERDES_V8_USB43_COM_CMN_MODE_CONTD6 0x2a0
+#define QSERDES_V8_USB43_COM_ADDITIONAL_MISC_6 0x2a4
+#define QSERDES_V8_USB43_COM_ADDITIONAL_MISC_7 0x2a8
+#define QSERDES_V8_USB43_COM_VCO_WAIT_CYCLES 0x2ac
+#define QSERDES_V8_USB43_COM_BIAS_WAIT_CYCLES 0x2b0
+#define QSERDES_V8_USB43_COM_AUX_CLK_PSM_ENABLE 0x2b4
+#define QSERDES_V8_USB43_COM_PLL_SPARE_FOR_ECO 0x2b8
+#define QSERDES_V8_USB43_COM_PLL_SPARE_FOR_ECO_1 0x2bc
+#define QSERDES_V8_USB43_COM_PLL_SPARE_FOR_ECO_2 0x2c0
+#define QSERDES_V8_USB43_COM_LDO_CAL_1 0x2c4
+#define QSERDES_V8_USB43_COM_LDO_CAL_2 0x2c8
+#define QSERDES_V8_USB43_COM_LDO_CAL_3 0x2cc
+#define QSERDES_V8_USB43_COM_LDO_CAL_4 0x2d0
+#define QSERDES_V8_USB43_COM_LDO_CAL_5 0x2d4
+#define QSERDES_V8_USB43_COM_DCC_CAL_1 0x2d8
+#define QSERDES_V8_USB43_COM_DCC_CAL_2 0x2dc
+#define QSERDES_V8_USB43_COM_DCC_CAL_3 0x2e0
+#define QSERDES_V8_USB43_COM_DCC_CAL_4 0x2e4
+#define QSERDES_V8_USB43_COM_DCC_CAL_5 0x2e8
+#define QSERDES_V8_USB43_COM_DCC_CAL_6 0x2ec
+#define QSERDES_V8_USB43_COM_PSM_CAL_EN 0x2f0
+#define QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_1 0x2f4
+#define QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_2 0x2f8
+#define QSERDES_V8_USB43_COM_IP_CTRL_AND_DP_SEL 0x2fc
+#define QSERDES_V8_USB43_COM_DCC_CAL_7 0x300
+#define QSERDES_V8_USB43_COM_DCC_CAL_8 0x304
+#define QSERDES_V8_USB43_COM_DCC_CAL_9 0x308
+#define QSERDES_V8_USB43_COM_MODE_OPERATION_STATUS 0x30c
+#define QSERDES_V8_USB43_COM_SYSCLK_DET_COMP_STATUS 0x310
+#define QSERDES_V8_USB43_COM_CMN_STATUS 0x314
+#define QSERDES_V8_USB43_COM_RESET_SM_STATUS 0x318
+#define QSERDES_V8_USB43_COM_RESTRIM_CODE_STATUS 0x31c
+#define QSERDES_V8_USB43_COM_PLLCAL_CODE1_STATUS 0x320
+#define QSERDES_V8_USB43_COM_PLLCAL_CODE2_STATUS 0x324
+#define QSERDES_V8_USB43_COM_INTEGLOOP_BINCODE_STATUS 0x328
+#define QSERDES_V8_USB43_COM_DEBUG_BUS0 0x32c
+#define QSERDES_V8_USB43_COM_DEBUG_BUS1 0x330
+#define QSERDES_V8_USB43_COM_DEBUG_BUS2 0x334
+#define QSERDES_V8_USB43_COM_DEBUG_BUS3 0x338
+#define QSERDES_V8_USB43_COM_C_READY_STATUS 0x33c
+#define QSERDES_V8_USB43_COM_READ_DUMMY_1 0x340
+#define QSERDES_V8_USB43_COM_READ_DUMMY_2 0x344
+#define QSERDES_V8_USB43_COM_READ_DUMMY_3 0x348
+#define QSERDES_V8_USB43_COM_IVCO_CAL_CODE_STATUS 0x34c
+#define QSERDES_V8_USB43_COM_PLL_LDO_CAL_STATUS_2 0x350
+#define QSERDES_V8_USB43_COM_PLL_LDO_CAL_STATUS_3 0x354
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index 5e7fcb26744a..14feb77789b3 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -22,13 +22,19 @@
#include <linux/slab.h>
#include <linux/usb/typec.h>
#include <linux/usb/typec_mux.h>
+#include <dt-bindings/phy/phy-qcom-qmp.h>
#include "phy-qcom-qmp-common.h"
#include "phy-qcom-qmp.h"
#include "phy-qcom-qmp-pcs-misc-v3.h"
+#include "phy-qcom-qmp-dp-phy.h"
+#include "phy-qcom-qmp-dp-phy-v2.h"
+
#define PHY_INIT_COMPLETE_TIMEOUT 10000
+#define SW_PORTSELECT_VAL BIT(0)
+#define SW_PORTSELECT_MUX BIT(1)
/* set of registers with offsets different per-PHY */
enum qphy_reg_layout {
@@ -284,6 +290,83 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88),
};
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x37),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BG_CTRL, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x02),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_rbr[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x2c),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x21),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr2[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x8c),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x70),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRANSCEIVER_BIAS_EN, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_VMODE_CTRL1, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_INTERFACE_SELECT, 0x3d),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_CLKBUF_ENABLE, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_RESET_TSYNC_EN, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRAN_DRVR_EMP_EN, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_INTERFACE_MODE, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_EMP_POST1_LVL, 0x2b),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_DRV_LVL, 0x2f),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_BAND, 0x4),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_TX, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_RX, 0x12),
+};
+
struct qmp_usbc_offsets {
u16 serdes;
u16 pcs;
@@ -293,13 +376,18 @@ struct qmp_usbc_offsets {
/* for PHYs with >= 2 lanes */
u16 tx2;
u16 rx2;
+
+ u16 dp_serdes;
+ u16 dp_txa;
+ u16 dp_txb;
+ u16 dp_dp_phy;
};
-/* struct qmp_phy_cfg - per-PHY initialization config */
+struct qmp_usbc;
struct qmp_phy_cfg {
const struct qmp_usbc_offsets *offsets;
- /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
+ /* Init sequence for USB PHY blocks - serdes, tx, rx, pcs */
const struct qmp_phy_init_tbl *serdes_tbl;
int serdes_tbl_num;
const struct qmp_phy_init_tbl *tx_tbl;
@@ -309,8 +397,30 @@ struct qmp_phy_cfg {
const struct qmp_phy_init_tbl *pcs_tbl;
int pcs_tbl_num;
- /* regulators to be requested */
- const char * const *vreg_list;
+ /* Init sequence for DP PHY blocks - serdes, tx, rbr, hbr, hbr2 */
+ 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;
+ const struct qmp_phy_init_tbl *serdes_tbl_rbr;
+ int serdes_tbl_rbr_num;
+ const struct qmp_phy_init_tbl *serdes_tbl_hbr;
+ int serdes_tbl_hbr_num;
+ const struct qmp_phy_init_tbl *serdes_tbl_hbr2;
+ int serdes_tbl_hbr2_num;
+
+ const u8 (*swing_tbl)[4][4];
+ const u8 (*pre_emphasis_tbl)[4][4];
+
+ /* DP PHY callbacks */
+ void (*dp_aux_init)(struct qmp_usbc *qmp);
+ void (*configure_dp_tx)(struct qmp_usbc *qmp);
+ int (*configure_dp_phy)(struct qmp_usbc *qmp);
+ int (*calibrate_dp_phy)(struct qmp_usbc *qmp);
+
+ const char * const *reset_list;
+ int num_resets;
+ const struct regulator_bulk_data *vreg_list;
int num_vregs;
/* array of registers with different offsets */
@@ -329,25 +439,36 @@ struct qmp_usbc {
void __iomem *rx;
void __iomem *tx2;
void __iomem *rx2;
-
- struct regmap *tcsr_map;
- u32 vls_clamp_reg;
+ void __iomem *dp_dp_phy;
+ void __iomem *dp_tx;
+ void __iomem *dp_tx2;
+ void __iomem *dp_serdes;
struct clk *pipe_clk;
+ struct clk_fixed_rate pipe_clk_fixed;
+
+ struct clk_hw dp_link_hw;
+ struct clk_hw dp_pixel_hw;
struct clk_bulk_data *clks;
int num_clks;
int num_resets;
struct reset_control_bulk_data *resets;
struct regulator_bulk_data *vregs;
+ struct regmap *tcsr_map;
+ u32 vls_clamp_reg;
+ u32 dp_phy_mode_reg;
+
struct mutex phy_mutex;
+ struct phy *usb_phy;
enum phy_mode mode;
unsigned int usb_init_count;
- struct phy *phy;
-
- struct clk_fixed_rate pipe_clk_fixed;
+ struct phy *dp_phy;
+ unsigned int dp_aux_cfg;
+ struct phy_configure_opts_dp dp_opts;
+ unsigned int dp_init_count;
struct typec_switch_dev *sw;
enum typec_orientation orientation;
@@ -391,9 +512,23 @@ static const char * const usb3phy_reset_l[] = {
"phy_phy", "phy",
};
-/* list of regulators */
-static const char * const qmp_phy_vreg_l[] = {
- "vdda-phy", "vdda-pll",
+static const char * const usb3dpphy_reset_l[] = {
+ "phy_phy", "dp_phy",
+};
+
+static const struct regulator_bulk_data qmp_phy_msm8998_vreg_l[] = {
+ { .supply = "vdda-phy", .init_load_uA = 68600 },
+ { .supply = "vdda-pll", .init_load_uA = 14200 },
+};
+
+static const struct regulator_bulk_data qmp_phy_sm2290_vreg_l[] = {
+ { .supply = "vdda-phy", .init_load_uA = 66100 },
+ { .supply = "vdda-pll", .init_load_uA = 13300 },
+};
+
+static const struct regulator_bulk_data qmp_phy_qcs615_vreg_l[] = {
+ { .supply = "vdda-phy", .init_load_uA = 50000 },
+ { .supply = "vdda-pll", .init_load_uA = 20000 },
};
static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
@@ -406,6 +541,34 @@ static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
.rx2 = 0x800,
};
+static const struct qmp_usbc_offsets qmp_usbc_usb3dp_offsets_qcs615 = {
+ .serdes = 0x0,
+ .pcs = 0xc00,
+ .pcs_misc = 0xa00,
+ .tx = 0x200,
+ .rx = 0x400,
+ .tx2 = 0x600,
+ .rx2 = 0x800,
+ .dp_serdes = 0x1c00,
+ .dp_txa = 0x1400,
+ .dp_txb = 0x1800,
+ .dp_dp_phy = 0x1000,
+};
+
+static const u8 qmp_v2_dp_pre_emphasis_hbr2_rbr[4][4] = {
+ {0x00, 0x0b, 0x12, 0xff},
+ {0x00, 0x0a, 0x12, 0xff},
+ {0x00, 0x0c, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff}
+};
+
+static const u8 qmp_v2_dp_voltage_swing_hbr2_rbr[4][4] = {
+ {0x07, 0x0f, 0x14, 0xff},
+ {0x11, 0x1d, 0x1f, 0xff},
+ {0x18, 0x1f, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff}
+};
+
static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
.offsets = &qmp_usbc_offsets_v3_qcm2290,
@@ -417,8 +580,10 @@ static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
.rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl),
.pcs_tbl = msm8998_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl),
- .vreg_list = qmp_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .reset_list = usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(usb3phy_reset_l),
+ .vreg_list = qmp_phy_msm8998_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout,
};
@@ -433,8 +598,10 @@ static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
.rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl),
.pcs_tbl = qcm2290_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
- .vreg_list = qmp_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .reset_list = usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(usb3phy_reset_l),
+ .vreg_list = qmp_phy_sm2290_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_sm2290_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout_qcm2290,
};
@@ -449,17 +616,86 @@ static const struct qmp_phy_cfg sdm660_usb3phy_cfg = {
.rx_tbl_num = ARRAY_SIZE(sdm660_usb3_rx_tbl),
.pcs_tbl = qcm2290_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
- .vreg_list = qmp_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .reset_list = usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(usb3phy_reset_l),
+ .vreg_list = qmp_phy_msm8998_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_msm8998_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout_qcm2290,
};
-static int qmp_usbc_init(struct phy *phy)
+static const struct qmp_phy_cfg qcs615_usb3phy_cfg = {
+ .offsets = &qmp_usbc_offsets_v3_qcm2290,
+
+ .serdes_tbl = qcm2290_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
+ .tx_tbl = qcm2290_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl),
+ .rx_tbl = qcm2290_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl),
+ .pcs_tbl = qcm2290_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
+ .reset_list = usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(usb3phy_reset_l),
+ .vreg_list = qmp_phy_qcs615_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l),
+ .regs = qmp_v3_usb3phy_regs_layout_qcm2290,
+};
+
+static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp);
+static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp);
+static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp);
+static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp);
+
+static const struct qmp_phy_cfg qcs615_usb3dp_phy_cfg = {
+ .offsets = &qmp_usbc_usb3dp_offsets_qcs615,
+
+ .serdes_tbl = qcm2290_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
+ .tx_tbl = qcm2290_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl),
+ .rx_tbl = qcm2290_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl),
+ .pcs_tbl = qcm2290_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
+
+ .regs = qmp_v3_usb3phy_regs_layout_qcm2290,
+
+ .dp_serdes_tbl = qmp_v2_dp_serdes_tbl,
+ .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl),
+ .dp_tx_tbl = qmp_v2_dp_tx_tbl,
+ .dp_tx_tbl_num = ARRAY_SIZE(qmp_v2_dp_tx_tbl),
+
+ .serdes_tbl_rbr = qmp_v2_dp_serdes_tbl_rbr,
+ .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_rbr),
+ .serdes_tbl_hbr = qmp_v2_dp_serdes_tbl_hbr,
+ .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr),
+ .serdes_tbl_hbr2 = qmp_v2_dp_serdes_tbl_hbr2,
+ .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr2),
+
+ .swing_tbl = &qmp_v2_dp_voltage_swing_hbr2_rbr,
+ .pre_emphasis_tbl = &qmp_v2_dp_pre_emphasis_hbr2_rbr,
+
+ .dp_aux_init = qmp_v2_dp_aux_init,
+ .configure_dp_tx = qmp_v2_configure_dp_tx,
+ .configure_dp_phy = qmp_v2_configure_dp_phy,
+ .calibrate_dp_phy = qmp_v2_calibrate_dp_phy,
+
+ .reset_list = usb3dpphy_reset_l,
+ .num_resets = ARRAY_SIZE(usb3dpphy_reset_l),
+ .vreg_list = qmp_phy_qcs615_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l),
+};
+
+static void qmp_usbc_set_phy_mode(struct qmp_usbc *qmp, bool is_dp)
+{
+ if (qmp->tcsr_map && qmp->dp_phy_mode_reg)
+ regmap_write(qmp->tcsr_map, qmp->dp_phy_mode_reg, is_dp);
+}
+
+static int qmp_usbc_com_init(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg;
- void __iomem *pcs = qmp->pcs;
- u32 val = 0;
int ret;
ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
@@ -484,16 +720,6 @@ static int qmp_usbc_init(struct phy *phy)
if (ret)
goto err_assert_reset;
- qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN);
-
-#define SW_PORTSELECT_VAL BIT(0)
-#define SW_PORTSELECT_MUX BIT(1)
- /* Use software based port select and switch on typec orientation */
- val = SW_PORTSELECT_MUX;
- if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
- val |= SW_PORTSELECT_VAL;
- writel(val, qmp->pcs_misc);
-
return 0;
err_assert_reset:
@@ -504,7 +730,7 @@ err_disable_regulators:
return ret;
}
-static int qmp_usbc_exit(struct phy *phy)
+static int qmp_usbc_com_exit(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -518,7 +744,254 @@ static int qmp_usbc_exit(struct phy *phy)
return 0;
}
-static int qmp_usbc_power_on(struct phy *phy)
+static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp)
+{
+ writel(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,
+ 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,
+ qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0);
+ writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+ writel(0x00, 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,
+ qmp->dp_dp_phy + QSERDES_V2_DP_PHY_AUX_INTERRUPT_MASK);
+}
+
+static int qmp_v2_configure_dp_swing(struct qmp_usbc *qmp)
+{
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+ void __iomem *tx = qmp->dp_tx;
+ void __iomem *tx2 = qmp->dp_tx2;
+ unsigned int v_level = 0, p_level = 0;
+ u8 voltage_swing_cfg, pre_emphasis_cfg;
+ int i;
+
+ if (dp_opts->lanes > 4) {
+ dev_err(qmp->dev, "Invalid lane_num(%d)\n", dp_opts->lanes);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < dp_opts->lanes; i++) {
+ v_level = max(v_level, dp_opts->voltage[i]);
+ p_level = max(p_level, dp_opts->pre[i]);
+ }
+
+ if (v_level > 4 || p_level > 4) {
+ dev_err(qmp->dev, "Invalid v(%d) | p(%d) level)\n",
+ v_level, p_level);
+ return -EINVAL;
+ }
+
+ voltage_swing_cfg = (*cfg->swing_tbl)[v_level][p_level];
+ pre_emphasis_cfg = (*cfg->pre_emphasis_tbl)[v_level][p_level];
+
+ voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN;
+ pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN;
+
+ if (voltage_swing_cfg == 0xff && pre_emphasis_cfg == 0xff)
+ return -EINVAL;
+
+ writel(voltage_swing_cfg, tx + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(pre_emphasis_cfg, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+ writel(voltage_swing_cfg, tx2 + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(pre_emphasis_cfg, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+
+ return 0;
+}
+
+static void qmp_usbc_configure_dp_mode(struct qmp_usbc *qmp)
+{
+ bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
+ u32 val;
+
+ val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
+ DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN;
+
+ writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ if (reverse)
+ writel(0xc9, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE);
+ else
+ writel(0xd9, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE);
+}
+
+static int qmp_usbc_configure_dp_clocks(struct qmp_usbc *qmp)
+{
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+ u32 phy_vco_div;
+ unsigned long pixel_freq;
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ phy_vco_div = 0x1;
+ pixel_freq = 1620000000UL / 2;
+ break;
+ case 2700:
+ phy_vco_div = 0x1;
+ pixel_freq = 2700000000UL / 2;
+ break;
+ case 5400:
+ phy_vco_div = 0x2;
+ pixel_freq = 5400000000UL / 4;
+ break;
+ default:
+ dev_err(qmp->dev, "link rate:%d not supported\n", dp_opts->link_rate);
+ return -EINVAL;
+ }
+ writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_VCO_DIV);
+
+ clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000);
+ clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq);
+
+ return 0;
+}
+
+static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp)
+{
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+ void __iomem *tx = qmp->dp_tx;
+ void __iomem *tx2 = qmp->dp_tx2;
+
+ /* program default setting first */
+ writel(0x2a, tx + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(0x20, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+ writel(0x2a, tx2 + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(0x20, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+
+ if (dp_opts->link_rate >= 2700) {
+ writel(0xc4, tx + QSERDES_V2_TX_LANE_MODE_1);
+ writel(0xc4, tx2 + QSERDES_V2_TX_LANE_MODE_1);
+ } else {
+ writel(0xc6, tx + QSERDES_V2_TX_LANE_MODE_1);
+ writel(0xc6, tx2 + QSERDES_V2_TX_LANE_MODE_1);
+ }
+
+ qmp_v2_configure_dp_swing(qmp);
+}
+
+static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp)
+{
+ u32 status;
+ int ret;
+
+ qmp_usbc_configure_dp_mode(qmp);
+
+ writel(0x05, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_TX0_TX1_LANE_CTL);
+ writel(0x05, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_TX2_TX3_LANE_CTL);
+
+ ret = qmp_usbc_configure_dp_clocks(qmp);
+ if (ret)
+ return ret;
+
+ 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, qmp->dp_serdes + QSERDES_COM_RESETSM_CNTRL);
+
+ if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_C_READY_STATUS,
+ status,
+ ((status & BIT(0)) > 0),
+ 500,
+ 10000)) {
+ dev_err(qmp->dev, "C_READY not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS,
+ status,
+ ((status & BIT(0)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "FREQ_DONE not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS,
+ status,
+ ((status & BIT(1)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "PLL_LOCKED not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+
+ if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS,
+ status,
+ ((status & BIT(0)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "TSYNC_DONE not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS,
+ status,
+ ((status & BIT(1)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "PHY_READY not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN);
+ writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN);
+ writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV);
+ writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN);
+ writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN);
+ writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV);
+
+ writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+
+ if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS,
+ status,
+ ((status & BIT(1)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "PHY_READY not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp)
+{
+ static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d};
+ u8 val;
+
+ qmp->dp_aux_cfg++;
+ qmp->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
+ val = cfg1_settings[qmp->dp_aux_cfg];
+
+ writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+
+ return 0;
+}
+
+static int qmp_usbc_usb_power_on(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -526,6 +999,14 @@ static int qmp_usbc_power_on(struct phy *phy)
unsigned int val;
int ret;
+ qphy_setbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN);
+
+ /* Use software based port select and switch on typec orientation */
+ val = SW_PORTSELECT_MUX;
+ if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
+ val |= SW_PORTSELECT_VAL;
+ writel(val, qmp->pcs_misc);
+
qmp_configure(qmp->dev, qmp->serdes, cfg->serdes_tbl,
cfg->serdes_tbl_num);
@@ -566,7 +1047,7 @@ err_disable_pipe_clk:
return ret;
}
-static int qmp_usbc_power_off(struct phy *phy)
+static int qmp_usbc_usb_power_off(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -587,20 +1068,39 @@ static int qmp_usbc_power_off(struct phy *phy)
return 0;
}
-static int qmp_usbc_enable(struct phy *phy)
+static int qmp_usbc_check_phy_status(struct qmp_usbc *qmp, bool is_dp)
+{
+ if ((is_dp && qmp->usb_init_count) ||
+ (!is_dp && qmp->dp_init_count)) {
+ dev_err(qmp->dev,
+ "PHY is configured for %s, can not enable %s\n",
+ is_dp ? "USB" : "DP", is_dp ? "DP" : "USB");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int qmp_usbc_usb_enable(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
int ret;
mutex_lock(&qmp->phy_mutex);
- ret = qmp_usbc_init(phy);
+ ret = qmp_usbc_check_phy_status(qmp, false);
+ if (ret)
+ goto out_unlock;
+
+ ret = qmp_usbc_com_init(phy);
if (ret)
goto out_unlock;
- ret = qmp_usbc_power_on(phy);
+ qmp_usbc_set_phy_mode(qmp, false);
+
+ ret = qmp_usbc_usb_power_on(phy);
if (ret) {
- qmp_usbc_exit(phy);
+ qmp_usbc_com_exit(phy);
goto out_unlock;
}
@@ -611,19 +1111,19 @@ out_unlock:
return ret;
}
-static int qmp_usbc_disable(struct phy *phy)
+static int qmp_usbc_usb_disable(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
int ret;
qmp->usb_init_count--;
- ret = qmp_usbc_power_off(phy);
+ ret = qmp_usbc_usb_power_off(phy);
if (ret)
return ret;
- return qmp_usbc_exit(phy);
+ return qmp_usbc_com_exit(phy);
}
-static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+static int qmp_usbc_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
@@ -632,10 +1132,185 @@ static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode)
return 0;
}
-static const struct phy_ops qmp_usbc_phy_ops = {
- .init = qmp_usbc_enable,
- .exit = qmp_usbc_disable,
- .set_mode = qmp_usbc_set_mode,
+static int qmp_usbc_dp_enable(struct phy *phy)
+{
+ struct qmp_usbc *qmp = phy_get_drvdata(phy);
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ int ret;
+
+ if (qmp->dp_init_count) {
+ dev_err(qmp->dev, "DP already inited\n");
+ return 0;
+ }
+
+ mutex_lock(&qmp->phy_mutex);
+
+ ret = qmp_usbc_check_phy_status(qmp, true);
+ if (ret)
+ goto dp_init_unlock;
+
+ ret = qmp_usbc_com_init(phy);
+ if (ret)
+ goto dp_init_unlock;
+
+ qmp_usbc_set_phy_mode(qmp, true);
+
+ cfg->dp_aux_init(qmp);
+
+ qmp->dp_init_count++;
+
+dp_init_unlock:
+ mutex_unlock(&qmp->phy_mutex);
+ return ret;
+}
+
+static int qmp_usbc_dp_disable(struct phy *phy)
+{
+ struct qmp_usbc *qmp = phy_get_drvdata(phy);
+
+ mutex_lock(&qmp->phy_mutex);
+
+ qmp_usbc_com_exit(phy);
+
+ qmp->dp_init_count--;
+
+ mutex_unlock(&qmp->phy_mutex);
+
+ return 0;
+}
+
+static int qmp_usbc_dp_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+ const struct phy_configure_opts_dp *dp_opts = &opts->dp;
+ struct qmp_usbc *qmp = phy_get_drvdata(phy);
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+
+ mutex_lock(&qmp->phy_mutex);
+
+ 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;
+ }
+
+ mutex_unlock(&qmp->phy_mutex);
+
+ return 0;
+}
+
+static int qmp_usbc_dp_calibrate(struct phy *phy)
+{
+ struct qmp_usbc *qmp = phy_get_drvdata(phy);
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ int ret = 0;
+
+ mutex_lock(&qmp->phy_mutex);
+
+ if (cfg->calibrate_dp_phy) {
+ ret = cfg->calibrate_dp_phy(qmp);
+ if (ret) {
+ dev_err(qmp->dev, "dp calibrate err(%d)\n", ret);
+ mutex_unlock(&qmp->phy_mutex);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&qmp->phy_mutex);
+ return 0;
+}
+
+static int qmp_usbc_dp_serdes_init(struct qmp_usbc *qmp)
+{
+ 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_configure(qmp->dev, serdes, cfg->dp_serdes_tbl,
+ cfg->dp_serdes_tbl_num);
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_rbr,
+ cfg->serdes_tbl_rbr_num);
+ break;
+ case 2700:
+ qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr,
+ cfg->serdes_tbl_hbr_num);
+ break;
+ case 5400:
+ qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr2,
+ cfg->serdes_tbl_hbr2_num);
+ break;
+ default:
+ /* Other link rates aren't supported */
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int qmp_usbc_dp_power_on(struct phy *phy)
+{
+ struct qmp_usbc *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;
+
+ /*
+ * FIXME: SW_PORTSELECT handling for DP orientation flip is not implemented.
+ * Expected:
+ * - For standard lane mapping: configure SW_PORTSELECT in QSERDES_DP_PHY_CFG_1.
+ * - For non-standard mapping: pass orientation to dp_ctrl and handle flip
+ * via logical2physical lane remapping.
+ */
+
+ mutex_lock(&qmp->phy_mutex);
+
+ qmp_usbc_dp_serdes_init(qmp);
+
+ qmp_configure_lane(qmp->dev, tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1);
+ qmp_configure_lane(qmp->dev, 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);
+
+ mutex_unlock(&qmp->phy_mutex);
+
+ return 0;
+}
+
+static int qmp_usbc_dp_power_off(struct phy *phy)
+{
+ struct qmp_usbc *qmp = phy_get_drvdata(phy);
+
+ mutex_lock(&qmp->phy_mutex);
+
+ /* Assert DP PHY power down */
+ writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ mutex_unlock(&qmp->phy_mutex);
+
+ return 0;
+}
+
+static const struct phy_ops qmp_usbc_usb_phy_ops = {
+ .init = qmp_usbc_usb_enable,
+ .exit = qmp_usbc_usb_disable,
+ .set_mode = qmp_usbc_usb_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static const struct phy_ops qmp_usbc_dp_phy_ops = {
+ .init = qmp_usbc_dp_enable,
+ .exit = qmp_usbc_dp_disable,
+ .configure = qmp_usbc_dp_configure,
+ .calibrate = qmp_usbc_dp_calibrate,
+ .power_on = qmp_usbc_dp_power_on,
+ .power_off = qmp_usbc_dp_power_off,
.owner = THIS_MODULE,
};
@@ -690,7 +1365,7 @@ static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev)
dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);
- if (!qmp->phy->init_count) {
+ if (!qmp->usb_init_count && !qmp->dp_init_count) {
dev_vdbg(dev, "PHY not initialized, bailing out\n");
return 0;
}
@@ -710,7 +1385,7 @@ static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)
dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
- if (!qmp->phy->init_count) {
+ if (!qmp->usb_init_count && !qmp->dp_init_count) {
dev_vdbg(dev, "PHY not initialized, bailing out\n");
return 0;
}
@@ -736,23 +1411,6 @@ static const struct dev_pm_ops qmp_usbc_pm_ops = {
qmp_usbc_runtime_resume, NULL)
};
-static int qmp_usbc_vreg_init(struct qmp_usbc *qmp)
-{
- const struct qmp_phy_cfg *cfg = qmp->cfg;
- struct device *dev = qmp->dev;
- int num = cfg->num_vregs;
- int i;
-
- qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL);
- if (!qmp->vregs)
- return -ENOMEM;
-
- for (i = 0; i < num; i++)
- qmp->vregs[i].supply = cfg->vreg_list[i];
-
- return devm_regulator_bulk_get(dev, num, qmp->vregs);
-}
-
static int qmp_usbc_reset_init(struct qmp_usbc *qmp,
const char *const *reset_list,
int num_resets)
@@ -796,9 +1454,23 @@ static int qmp_usbc_clk_init(struct qmp_usbc *qmp)
return devm_clk_bulk_get_optional(dev, num, qmp->clks);
}
-static void phy_clk_release_provider(void *res)
+static struct clk_hw *qmp_usbc_clks_hw_get(struct of_phandle_args *clkspec, void *data)
{
- of_clk_del_provider(res);
+ struct qmp_usbc *qmp = data;
+
+ if (clkspec->args_count == 0)
+ return &qmp->pipe_clk_fixed.hw;
+
+ 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);
}
/*
@@ -823,12 +1495,14 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np)
{
struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;
struct clk_init_data init = { };
+ char name[64];
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;
+ /* Clock name is not mandatory. */
+ snprintf(name, sizeof(name), "%s::pipe_clk", dev_name(qmp->dev));
+ init.name = name;
}
init.ops = &clk_fixed_rate_ops;
@@ -837,10 +1511,183 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np)
fixed->fixed_rate = 125000000;
fixed->hw.init = &init;
- ret = devm_clk_hw_register(qmp->dev, &fixed->hw);
+ return devm_clk_hw_register(qmp->dev, &fixed->hw);
+}
+
+/*
+ * Display Port PLL driver block diagram for branch clocks
+ *
+ * +------------------------------+
+ * | DP_VCO_CLK |
+ * | |
+ * | +-------------------+ |
+ * | | (DP PLL/VCO) | |
+ * | +---------+---------+ |
+ * | v |
+ * | +----------+-----------+ |
+ * | | hsclk_divsel_clk_src | |
+ * | +----------+-----------+ |
+ * +------------------------------+
+ * |
+ * +---------<---------v------------>----------+
+ * | |
+ * +--------v----------------+ |
+ * | dp_phy_pll_link_clk | |
+ * | link_clk | |
+ * +--------+----------------+ |
+ * | |
+ * | |
+ * v v
+ * Input to DISPCC block |
+ * for link clk, crypto clk |
+ * and interface clock |
+ * |
+ * |
+ * +--------<------------+-----------------+---<---+
+ * | | |
+ * +----v---------+ +--------v-----+ +--------v------+
+ * | vco_divided | | vco_divided | | vco_divided |
+ * | _clk_src | | _clk_src | | _clk_src |
+ * | | | | | |
+ * |divsel_six | | divsel_two | | divsel_four |
+ * +-------+------+ +-----+--------+ +--------+------+
+ * | | |
+ * v---->----------v-------------<------v
+ * |
+ * +----------+-----------------+
+ * | dp_phy_pll_vco_div_clk |
+ * +---------+------------------+
+ * |
+ * v
+ * Input to DISPCC block
+ * for DP pixel clock
+ *
+ */
+static int qmp_dp_pixel_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ switch (req->rate) {
+ case 1620000000UL / 2:
+ case 2700000000UL / 2:
+ /* 5.4 is same link rate as 2.7GHz, i.e. div 4 */
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static unsigned long qmp_dp_pixel_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ const struct qmp_usbc *qmp;
+ const struct phy_configure_opts_dp *dp_opts;
+
+ qmp = container_of(hw, struct qmp_usbc, dp_pixel_hw);
+
+ dp_opts = &qmp->dp_opts;
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ return 1620000000UL / 2;
+ case 2700:
+ return 2700000000UL / 2;
+ case 5400:
+ return 5400000000UL / 4;
+ default:
+ return 0;
+ }
+}
+
+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 qmp_dp_link_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ switch (req->rate) {
+ case 162000000:
+ case 270000000:
+ case 540000000:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static unsigned long qmp_dp_link_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ const struct qmp_usbc *qmp;
+ const struct phy_configure_opts_dp *dp_opts;
+
+ qmp = container_of(hw, struct qmp_usbc, dp_link_hw);
+ dp_opts = &qmp->dp_opts;
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ case 2700:
+ case 5400:
+ return dp_opts->link_rate * 100000;
+ default:
+ return 0;
+ }
+}
+
+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 int phy_dp_clks_register(struct qmp_usbc *qmp, struct device_node *np)
+{
+ struct clk_init_data init = { };
+ char name[64];
+ int ret;
+
+ snprintf(name, sizeof(name), "%s::link_clk", dev_name(qmp->dev));
+ init.ops = &qmp_dp_link_clk_ops;
+ init.name = name;
+ qmp->dp_link_hw.init = &init;
+ ret = devm_clk_hw_register(qmp->dev, &qmp->dp_link_hw);
+ if (ret < 0) {
+ dev_err(qmp->dev, "link clk reg fail ret=%d\n", ret);
+ return ret;
+ }
+
+ snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(qmp->dev));
+ init.ops = &qmp_dp_pixel_clk_ops;
+ init.name = name;
+ qmp->dp_pixel_hw.init = &init;
+ ret = devm_clk_hw_register(qmp->dev, &qmp->dp_pixel_hw);
+ if (ret) {
+ dev_err(qmp->dev, "pxl clk reg fail ret=%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void phy_clk_release_provider(void *res)
+{
+ of_clk_del_provider(res);
+}
+
+static int qmp_usbc_register_clocks(struct qmp_usbc *qmp, struct device_node *np)
+{
+ struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;
+ int ret;
+
+ ret = phy_pipe_clk_register(qmp, np);
if (ret)
return ret;
+ if (qmp->dp_serdes != 0) {
+ ret = phy_dp_clks_register(qmp, np);
+ if (ret)
+ return ret;
+ }
+
+ if (np == qmp->dev->of_node)
+ return devm_of_clk_add_hw_provider(qmp->dev, qmp_usbc_clks_hw_get, qmp);
+
ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw);
if (ret)
return ret;
@@ -865,11 +1712,12 @@ static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,
qmp->orientation = orientation;
if (qmp->usb_init_count) {
- qmp_usbc_power_off(qmp->phy);
- qmp_usbc_exit(qmp->phy);
+ qmp_usbc_usb_power_off(qmp->usb_phy);
+ qmp_usbc_com_exit(qmp->usb_phy);
- qmp_usbc_init(qmp->phy);
- qmp_usbc_power_on(qmp->phy);
+ qmp_usbc_com_init(qmp->usb_phy);
+ qmp_usbc_set_phy_mode(qmp, false);
+ qmp_usbc_usb_power_on(qmp->usb_phy);
}
mutex_unlock(&qmp->phy_mutex);
@@ -985,6 +1833,13 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
if (IS_ERR(base))
return PTR_ERR(base);
+ if (offs->dp_serdes != 0) {
+ qmp->dp_serdes = base + offs->dp_serdes;
+ qmp->dp_tx = base + offs->dp_txa;
+ qmp->dp_tx2 = base + offs->dp_txb;
+ qmp->dp_dp_phy = base + offs->dp_dp_phy;
+ }
+
qmp->serdes = base + offs->serdes;
qmp->pcs = base + offs->pcs;
if (offs->pcs_misc)
@@ -1005,23 +1860,23 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)
"failed to get pipe clock\n");
}
- ret = qmp_usbc_reset_init(qmp, usb3phy_reset_l,
- ARRAY_SIZE(usb3phy_reset_l));
+ ret = qmp_usbc_reset_init(qmp, cfg->reset_list, cfg->num_resets);
if (ret)
return ret;
return 0;
}
-static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp)
+static int qmp_usbc_parse_tcsr(struct qmp_usbc *qmp)
{
struct of_phandle_args tcsr_args;
struct device *dev = qmp->dev;
- int ret;
+ int ret, args_count;
- /* for backwards compatibility ignore if there is no property */
- ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg", 1, 0,
- &tcsr_args);
+ args_count = of_property_count_u32_elems(dev->of_node, "qcom,tcsr-reg");
+ args_count = args_count - 1;
+ ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg",
+ args_count, 0, &tcsr_args);
if (ret == -ENOENT)
return 0;
else if (ret < 0)
@@ -1034,9 +1889,29 @@ static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp)
qmp->vls_clamp_reg = tcsr_args.args[0];
+ if (args_count > 1)
+ qmp->dp_phy_mode_reg = tcsr_args.args[1];
+
return 0;
}
+static struct phy *qmp_usbc_phy_xlate(struct device *dev, const struct of_phandle_args *args)
+{
+ struct qmp_usbc *qmp = dev_get_drvdata(dev);
+
+ if (args->args_count == 0)
+ return qmp->usb_phy;
+
+ switch (args->args[0]) {
+ case QMP_USB43DP_USB3_PHY:
+ return qmp->usb_phy;
+ case QMP_USB43DP_DP_PHY:
+ return qmp->dp_phy ?: ERR_PTR(-ENODEV);
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
static int qmp_usbc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1060,7 +1935,8 @@ static int qmp_usbc_probe(struct platform_device *pdev)
mutex_init(&qmp->phy_mutex);
- ret = qmp_usbc_vreg_init(qmp);
+ ret = devm_regulator_bulk_get_const(qmp->dev, qmp->cfg->num_vregs,
+ qmp->cfg->vreg_list, &qmp->vregs);
if (ret)
return ret;
@@ -1068,7 +1944,7 @@ static int qmp_usbc_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = qmp_usbc_parse_vls_clamp(qmp);
+ ret = qmp_usbc_parse_tcsr(qmp);
if (ret)
return ret;
@@ -1093,22 +1969,32 @@ static int qmp_usbc_probe(struct platform_device *pdev)
*/
pm_runtime_forbid(dev);
- ret = phy_pipe_clk_register(qmp, np);
+ ret = qmp_usbc_register_clocks(qmp, np);
if (ret)
goto err_node_put;
- qmp->phy = devm_phy_create(dev, np, &qmp_usbc_phy_ops);
- if (IS_ERR(qmp->phy)) {
- ret = PTR_ERR(qmp->phy);
+ qmp->usb_phy = devm_phy_create(dev, np, &qmp_usbc_usb_phy_ops);
+ if (IS_ERR(qmp->usb_phy)) {
+ ret = PTR_ERR(qmp->usb_phy);
dev_err(dev, "failed to create PHY: %d\n", ret);
goto err_node_put;
}
- phy_set_drvdata(qmp->phy, qmp);
+ phy_set_drvdata(qmp->usb_phy, qmp);
+
+ if (qmp->dp_serdes != 0) {
+ qmp->dp_phy = devm_phy_create(dev, np, &qmp_usbc_dp_phy_ops);
+ if (IS_ERR(qmp->dp_phy)) {
+ ret = PTR_ERR(qmp->dp_phy);
+ dev_err(dev, "failed to create PHY: %d\n", ret);
+ goto err_node_put;
+ }
+ phy_set_drvdata(qmp->dp_phy, qmp);
+ }
of_node_put(np);
- phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ phy_provider = devm_of_phy_provider_register(dev, qmp_usbc_phy_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
@@ -1125,8 +2011,11 @@ static const struct of_device_id qmp_usbc_of_match_table[] = {
.compatible = "qcom,qcm2290-qmp-usb3-phy",
.data = &qcm2290_usb3phy_cfg,
}, {
+ .compatible = "qcom,qcs615-qmp-usb3-dp-phy",
+ .data = &qcs615_usb3dp_phy_cfg,
+ }, {
.compatible = "qcom,qcs615-qmp-usb3-phy",
- .data = &qcm2290_usb3phy_cfg,
+ .data = &qcs615_usb3phy_cfg,
}, {
.compatible = "qcom,sdm660-qmp-usb3-phy",
.data = &sdm660_usb3phy_cfg,
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h
index da2a7ad2cdcc..a873bdd7bffe 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.h
@@ -9,6 +9,9 @@
#include "phy-qcom-qmp-qserdes-com.h"
#include "phy-qcom-qmp-qserdes-txrx.h"
+#include "phy-qcom-qmp-qserdes-com-v2.h"
+#include "phy-qcom-qmp-qserdes-txrx-v2.h"
+
#include "phy-qcom-qmp-qserdes-com-v3.h"
#include "phy-qcom-qmp-qserdes-txrx-v3.h"
@@ -32,7 +35,9 @@
#include "phy-qcom-qmp-qserdes-txrx-v7.h"
#include "phy-qcom-qmp-qserdes-com-v8.h"
+#include "phy-qcom-qmp-usb43-qserdes-com-v8.h"
#include "phy-qcom-qmp-qserdes-txrx-v8.h"
+#include "phy-qcom-qmp-qserdes-lalb-v8.h"
#include "phy-qcom-qmp-qserdes-pll.h"
diff --git a/drivers/phy/renesas/Kconfig b/drivers/phy/renesas/Kconfig
index 16211072098e..90a9ca2db7fc 100644
--- a/drivers/phy/renesas/Kconfig
+++ b/drivers/phy/renesas/Kconfig
@@ -29,7 +29,9 @@ config PHY_RCAR_GEN3_USB2
depends on ARCH_RENESAS
depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in
depends on USB_SUPPORT
+ depends on REGULATOR
select GENERIC_PHY
+ select MULTIPLEXER
select USB_COMMON
help
Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs.
diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c
index c0221e7258c0..6c671254c625 100644
--- a/drivers/phy/renesas/phy-rcar-gen2.c
+++ b/drivers/phy/renesas/phy-rcar-gen2.c
@@ -85,7 +85,7 @@ static int rcar_gen2_phy_init(struct phy *p)
* Try to acquire exclusive access to PHY. The first driver calling
* phy_init() on a given channel wins, and all attempts to use another
* PHY on this channel will fail until phy_exit() is called by the first
- * driver. Achieving this with cmpxcgh() should be SMP-safe.
+ * driver. Achieving this with cmpxchg() should be SMP-safe.
*/
if (cmpxchg(&channel->selected_phy, -1, phy->number) != -1)
return -EBUSY;
@@ -337,7 +337,6 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct rcar_gen2_phy_driver *drv;
struct phy_provider *provider;
- struct device_node *np;
void __iomem *base;
struct clk *clk;
const struct rcar_gen2_phy_data *data;
@@ -379,7 +378,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
if (!drv->channels)
return -ENOMEM;
- for_each_child_of_node(dev->of_node, np) {
+ for_each_child_of_node_scoped(dev->of_node, np) {
struct rcar_gen2_channel *channel = drv->channels + i;
u32 channel_num;
int error, n;
@@ -391,7 +390,6 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
error = of_property_read_u32(np, "reg", &channel_num);
if (error || channel_num >= data->num_channels) {
dev_err(dev, "Invalid \"reg\" property\n");
- of_node_put(np);
return error;
}
channel->select_mask = select_mask[channel_num];
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
index 582de10d5beb..cfc2a8d9028d 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -17,11 +17,13 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/mux/consumer.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
#include <linux/reset.h>
#include <linux/string.h>
#include <linux/usb/of.h>
@@ -141,6 +143,7 @@ struct rcar_gen3_chan {
bool extcon_host;
bool is_otg_channel;
bool uses_otg_pins;
+ bool otg_internal_reg;
};
struct rcar_gen3_phy_drv_data {
@@ -204,28 +207,43 @@ static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm)
writel(val, usb2_base + USB2_LINECTRL1);
}
-static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus)
+static void rcar_gen3_phy_usb2_set_vbus(struct rcar_gen3_chan *ch,
+ u32 vbus_ctrl_reg,
+ u32 vbus_ctrl_val,
+ bool enable)
{
void __iomem *usb2_base = ch->base;
- u32 vbus_ctrl_reg = USB2_ADPCTRL;
- u32 vbus_ctrl_val = USB2_ADPCTRL_DRVVBUS;
u32 val;
+ val = readl(usb2_base + vbus_ctrl_reg);
+ if (enable)
+ val |= vbus_ctrl_val;
+ else
+ val &= ~vbus_ctrl_val;
+ writel(val, usb2_base + vbus_ctrl_reg);
+
+ dev_vdbg(ch->dev, "%s: reg=0x%08x, val=%08x, enable=%d\n",
+ __func__, vbus_ctrl_reg, val, enable);
+}
+
+static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus)
+{
+ if (ch->otg_internal_reg) {
+ regulator_hardware_enable(ch->vbus, vbus);
+ return;
+ }
+
if (ch->phy_data->no_adp_ctrl || ch->phy_data->vblvl_ctrl) {
if (ch->vbus)
regulator_hardware_enable(ch->vbus, vbus);
- vbus_ctrl_reg = USB2_VBCTRL;
- vbus_ctrl_val = USB2_VBCTRL_VBOUT;
+ rcar_gen3_phy_usb2_set_vbus(ch, USB2_VBCTRL,
+ USB2_VBCTRL_VBOUT, vbus);
+ return;
}
- val = readl(usb2_base + vbus_ctrl_reg);
- if (vbus)
- val |= vbus_ctrl_val;
- else
- val &= ~vbus_ctrl_val;
- dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus);
- writel(val, usb2_base + vbus_ctrl_reg);
+ rcar_gen3_phy_usb2_set_vbus(ch, USB2_ADPCTRL,
+ USB2_ADPCTRL_DRVVBUS, vbus);
}
static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable)
@@ -583,7 +601,7 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
u32 val;
int ret = 0;
- if (channel->vbus) {
+ if (channel->vbus && !channel->otg_internal_reg) {
ret = regulator_enable(channel->vbus);
if (ret)
return ret;
@@ -624,7 +642,7 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
}
}
- if (channel->vbus)
+ if (channel->vbus && !channel->otg_internal_reg)
ret = regulator_disable(channel->vbus);
return ret;
@@ -799,11 +817,149 @@ static int rcar_gen3_phy_usb2_init_bus(struct rcar_gen3_chan *channel)
return 0;
}
+static int rcar_gen3_phy_usb2_regulator_endisable(struct regulator_dev *rdev,
+ bool enable)
+{
+ struct rcar_gen3_chan *channel = rdev_get_drvdata(rdev);
+ struct device *dev = channel->dev;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0) {
+ dev_warn(dev, "pm_runtime_get failed: %i\n", ret);
+ return ret;
+ }
+
+ rcar_gen3_phy_usb2_set_vbus(channel, USB2_VBCTRL,
+ USB2_VBCTRL_VBOUT, enable);
+ pm_runtime_put_noidle(dev);
+
+ return ret;
+}
+
+static int rcar_gen3_phy_usb2_regulator_enable(struct regulator_dev *rdev)
+{
+ return rcar_gen3_phy_usb2_regulator_endisable(rdev, true);
+}
+
+static int rcar_gen3_phy_usb2_regulator_disable(struct regulator_dev *rdev)
+{
+ return rcar_gen3_phy_usb2_regulator_endisable(rdev, false);
+}
+
+static int rcar_gen3_phy_usb2_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct rcar_gen3_chan *channel = rdev_get_drvdata(rdev);
+ void __iomem *usb2_base = channel->base;
+ struct device *dev = channel->dev;
+ u32 vbus_ctrl_reg = USB2_VBCTRL;
+ u32 val;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0) {
+ dev_warn(dev, "pm_runtime_get failed: %i\n", ret);
+ return ret;
+ }
+
+ val = readl(usb2_base + vbus_ctrl_reg);
+
+ pm_runtime_put_noidle(dev);
+ dev_dbg(channel->dev, "%s: %08x\n", __func__, val);
+
+ return (val & USB2_VBCTRL_VBOUT) ? 1 : 0;
+}
+
+static const struct regulator_ops rcar_gen3_phy_usb2_regulator_ops = {
+ .enable = rcar_gen3_phy_usb2_regulator_enable,
+ .disable = rcar_gen3_phy_usb2_regulator_disable,
+ .is_enabled = rcar_gen3_phy_usb2_regulator_is_enabled,
+};
+
+static const struct regulator_desc rcar_gen3_phy_usb2_regulator = {
+ .name = "otg-vbus-regulator",
+ .of_match = of_match_ptr("vbus-regulator"),
+ .ops = &rcar_gen3_phy_usb2_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .fixed_uV = 5000000,
+ .n_voltages = 1,
+};
+
+static void rcar_gen3_phy_usb2_vbus_disable_action(void *data)
+{
+ struct regulator *vbus = data;
+
+ regulator_disable(vbus);
+}
+
+static int rcar_gen3_phy_usb2_vbus_regulator_get_exclusive_enable(struct rcar_gen3_chan *channel,
+ bool enable)
+{
+ struct device *dev = channel->dev;
+ int ret;
+
+ channel->vbus = devm_regulator_get_exclusive(dev, "vbus");
+ if (IS_ERR(channel->vbus))
+ return PTR_ERR(channel->vbus);
+
+ if (!enable)
+ return 0;
+
+ ret = regulator_enable(channel->vbus);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, rcar_gen3_phy_usb2_vbus_disable_action,
+ channel->vbus);
+}
+
+static int rcar_gen3_phy_usb2_vbus_regulator_register(struct rcar_gen3_chan *channel)
+{
+ struct device *dev = channel->dev;
+ struct regulator_config rcfg = { .dev = dev, };
+ struct regulator_dev *rdev;
+ bool enable = false;
+
+ rcfg.of_node = of_get_available_child_by_name(dev->of_node,
+ "vbus-regulator");
+ if (rcfg.of_node) {
+ rcfg.driver_data = channel;
+ rdev = devm_regulator_register(dev, &rcar_gen3_phy_usb2_regulator,
+ &rcfg);
+ of_node_put(rcfg.of_node);
+ if (IS_ERR(rdev))
+ return dev_err_probe(dev, PTR_ERR(rdev),
+ "Failed to create vbus-regulator\n");
+
+ channel->otg_internal_reg = true;
+ enable = true;
+ }
+
+ return rcar_gen3_phy_usb2_vbus_regulator_get_exclusive_enable(channel, enable);
+}
+
+/* Temporary wrapper until the multiplexer subsystem supports optional muxes */
+static inline struct mux_state *
+devm_mux_state_get_optional(struct device *dev, const char *mux_name)
+{
+ if (!of_property_present(dev->of_node, "mux-states"))
+ return NULL;
+
+ return devm_mux_state_get(dev, mux_name);
+}
+
+static void rcar_gen3_phy_mux_state_deselect(void *data)
+{
+ mux_state_deselect(data);
+}
+
static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rcar_gen3_chan *channel;
struct phy_provider *provider;
+ struct mux_state *mux_state;
int ret = 0, i, irq;
if (!dev->of_node) {
@@ -852,78 +1008,87 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
* devm_phy_create() will call pm_runtime_enable(&phy->dev);
* And then, phy-core will manage runtime pm for this device.
*/
- pm_runtime_enable(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable pm_runtime\n");
channel->phy_data = of_device_get_match_data(dev);
- if (!channel->phy_data) {
- ret = -EINVAL;
- goto error;
- }
+ if (!channel->phy_data)
+ return -EINVAL;
platform_set_drvdata(pdev, channel);
channel->dev = dev;
ret = rcar_gen3_phy_usb2_init_bus(channel);
if (ret)
- goto error;
+ return ret;
spin_lock_init(&channel->lock);
for (i = 0; i < NUM_OF_PHYS; i++) {
channel->rphys[i].phy = devm_phy_create(dev, NULL,
channel->phy_data->phy_usb2_ops);
- if (IS_ERR(channel->rphys[i].phy)) {
- dev_err(dev, "Failed to create USB2 PHY\n");
- ret = PTR_ERR(channel->rphys[i].phy);
- goto error;
- }
+ if (IS_ERR(channel->rphys[i].phy))
+ return dev_err_probe(dev, PTR_ERR(channel->rphys[i].phy),
+ "Failed to create USB2 PHY\n");
+
channel->rphys[i].ch = channel;
channel->rphys[i].int_enable_bits = rcar_gen3_int_enable[i];
phy_set_drvdata(channel->rphys[i].phy, &channel->rphys[i]);
}
- if (channel->phy_data->no_adp_ctrl && channel->is_otg_channel)
- channel->vbus = devm_regulator_get_exclusive(dev, "vbus");
- else
+ mux_state = devm_mux_state_get_optional(dev, NULL);
+ if (IS_ERR(mux_state))
+ return PTR_ERR(mux_state);
+ if (mux_state) {
+ ret = mux_state_select(mux_state);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to select USB mux\n");
+
+ ret = devm_add_action_or_reset(dev, rcar_gen3_phy_mux_state_deselect,
+ mux_state);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to register USB mux state deselect\n");
+ }
+
+ if (channel->phy_data->no_adp_ctrl && channel->is_otg_channel) {
+ ret = rcar_gen3_phy_usb2_vbus_regulator_register(channel);
+ if (ret)
+ return ret;
+ } else {
channel->vbus = devm_regulator_get_optional(dev, "vbus");
+ }
if (IS_ERR(channel->vbus)) {
- if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) {
- ret = PTR_ERR(channel->vbus);
- goto error;
- }
+ if (PTR_ERR(channel->vbus) == -EPROBE_DEFER)
+ return PTR_ERR(channel->vbus);
+
channel->vbus = NULL;
}
irq = platform_get_irq_optional(pdev, 0);
if (irq < 0 && irq != -ENXIO) {
- ret = irq;
- goto error;
+ return irq;
} else if (irq > 0) {
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
ret = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
IRQF_SHARED, dev_name(dev), channel);
- if (ret < 0) {
- dev_err(dev, "Failed to request irq (%d)\n", irq);
- goto error;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to request irq (%d)\n",
+ irq);
}
provider = devm_of_phy_provider_register(dev, rcar_gen3_phy_usb2_xlate);
if (IS_ERR(provider)) {
- dev_err(dev, "Failed to register PHY provider\n");
- ret = PTR_ERR(provider);
- goto error;
+ return dev_err_probe(dev, PTR_ERR(provider),
+ "Failed to register PHY provider\n");
} else if (channel->is_otg_channel) {
ret = device_create_file(dev, &dev_attr_role);
if (ret < 0)
- goto error;
+ return ret;
}
return 0;
-
-error:
- pm_runtime_disable(dev);
-
- return ret;
}
static void rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
@@ -932,8 +1097,6 @@ static void rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
if (channel->is_otg_channel)
device_remove_file(&pdev->dev, &dev_attr_role);
-
- pm_runtime_disable(&pdev->dev);
}
static int rcar_gen3_phy_usb2_suspend(struct device *dev)
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
index 8dcc2bb777b5..1483907413fa 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -749,22 +749,23 @@ unsigned long inno_hdmi_phy_rk3228_clk_recalc_rate(struct clk_hw *hw,
return vco;
}
-static long inno_hdmi_phy_rk3228_clk_round_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long *parent_rate)
+static int inno_hdmi_phy_rk3228_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
const struct pre_pll_config *cfg = pre_pll_cfg_table;
- rate = (rate / 1000) * 1000;
+ req->rate = (req->rate / 1000) * 1000;
for (; cfg->pixclock != 0; cfg++)
- if (cfg->pixclock == rate && !cfg->fracdiv)
+ if (cfg->pixclock == req->rate && !cfg->fracdiv)
break;
if (cfg->pixclock == 0)
return -EINVAL;
- return cfg->pixclock;
+ req->rate = cfg->pixclock;
+
+ return 0;
}
static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw,
@@ -835,7 +836,7 @@ static const struct clk_ops inno_hdmi_phy_rk3228_clk_ops = {
.unprepare = inno_hdmi_phy_rk3228_clk_unprepare,
.is_prepared = inno_hdmi_phy_rk3228_clk_is_prepared,
.recalc_rate = inno_hdmi_phy_rk3228_clk_recalc_rate,
- .round_rate = inno_hdmi_phy_rk3228_clk_round_rate,
+ .determine_rate = inno_hdmi_phy_rk3228_clk_determine_rate,
.set_rate = inno_hdmi_phy_rk3228_clk_set_rate,
};
@@ -906,22 +907,23 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw,
return inno->pixclock;
}
-static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long *parent_rate)
+static int inno_hdmi_phy_rk3328_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
const struct pre_pll_config *cfg = pre_pll_cfg_table;
- rate = (rate / 1000) * 1000;
+ req->rate = (req->rate / 1000) * 1000;
for (; cfg->pixclock != 0; cfg++)
- if (cfg->pixclock == rate)
+ if (cfg->pixclock == req->rate)
break;
if (cfg->pixclock == 0)
return -EINVAL;
- return cfg->pixclock;
+ req->rate = cfg->pixclock;
+
+ return 0;
}
static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
@@ -989,7 +991,7 @@ static const struct clk_ops inno_hdmi_phy_rk3328_clk_ops = {
.unprepare = inno_hdmi_phy_rk3328_clk_unprepare,
.is_prepared = inno_hdmi_phy_rk3328_clk_is_prepared,
.recalc_rate = inno_hdmi_phy_rk3328_clk_recalc_rate,
- .round_rate = inno_hdmi_phy_rk3328_clk_round_rate,
+ .determine_rate = inno_hdmi_phy_rk3328_clk_determine_rate,
.set_rate = inno_hdmi_phy_rk3328_clk_set_rate,
};
diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
index 7f8fc8e6d489..b60d6bf3f33c 100644
--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
@@ -529,7 +529,7 @@ static int rk3528_combphy_cfg(struct rockchip_combphy_priv *priv)
return -EINVAL;
}
- if (device_property_read_bool(priv->dev, "rockchip,ext-refclk")) {
+ if (priv->ext_refclk) {
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true);
if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) {
@@ -554,11 +554,9 @@ static int rk3528_combphy_cfg(struct rockchip_combphy_priv *priv)
}
}
- if (priv->type == PHY_TYPE_PCIE) {
- if (device_property_read_bool(priv->dev, "rockchip,enable-ssc"))
- rockchip_combphy_updatel(priv, RK3528_PHYREG40_SSC_EN,
- RK3528_PHYREG40_SSC_EN, RK3528_PHYREG40);
- }
+ if (priv->type == PHY_TYPE_PCIE && priv->enable_ssc)
+ rockchip_combphy_updatel(priv, RK3528_PHYREG40_SSC_EN,
+ RK3528_PHYREG40_SSC_EN, RK3528_PHYREG40);
return 0;
}
@@ -582,7 +580,7 @@ static const struct rockchip_combphy_grfcfg rk3528_combphy_grfcfgs = {
.con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x101 },
.con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 },
/* pipe-grf */
- .u3otg0_port_en = { 0x0044, 15, 0, 0x0181, 0x1100 },
+ .u3otg0_port_en = { 0x0044, 15, 0, 0x0181, 0x1100 },
};
static const struct rockchip_combphy_cfg rk3528_combphy_cfgs = {
diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
index 4508a3147272..0f69060aa5d5 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
@@ -1508,7 +1508,9 @@ static int samsung_mipi_dcphy_exit(struct phy *phy)
{
struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy);
- return pm_runtime_put(samsung->dev);
+ pm_runtime_put(samsung->dev);
+
+ return 0;
}
static const struct phy_ops samsung_mipi_dcphy_ops = {
diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 29de2f7bdae8..2d973bc37f07 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -22,6 +22,7 @@
#include <linux/reset.h>
#define GRF_HDPTX_CON0 0x00
+#define LC_REF_CLK_SEL BIT(11)
#define HDPTX_I_PLL_EN BIT(7)
#define HDPTX_I_BIAS_EN BIT(6)
#define HDPTX_I_BGR_EN BIT(5)
@@ -32,17 +33,17 @@
#define HDPTX_O_PHY_RDY BIT(1)
#define HDPTX_O_SB_RDY BIT(0)
-#define HDTPX_REG(_n, _min, _max) \
+#define HDPTX_REG(_n, _min, _max) \
( \
BUILD_BUG_ON_ZERO((0x##_n) < (0x##_min)) + \
BUILD_BUG_ON_ZERO((0x##_n) > (0x##_max)) + \
((0x##_n) * 4) \
)
-#define CMN_REG(n) HDTPX_REG(n, 0000, 00a7)
-#define SB_REG(n) HDTPX_REG(n, 0100, 0129)
-#define LNTOP_REG(n) HDTPX_REG(n, 0200, 0229)
-#define LANE_REG(n) HDTPX_REG(n, 0300, 062d)
+#define CMN_REG(n) HDPTX_REG(n, 0000, 00a7)
+#define SB_REG(n) HDPTX_REG(n, 0100, 0129)
+#define LNTOP_REG(n) HDPTX_REG(n, 0200, 0229)
+#define LANE_REG(n) HDPTX_REG(n, 0300, 062d)
/* CMN_REG(0008) */
#define OVRD_LCPLL_EN_MASK BIT(7)
@@ -322,6 +323,9 @@
#define HDMI14_MAX_RATE 340000000
#define HDMI20_MAX_RATE 600000000
+#define FRL_3G3L_RATE 900000000
+#define FRL_6G3L_RATE 1800000000
+#define FRL_8G4L_RATE 3200000000
enum dp_link_rate {
DP_BW_RBR,
@@ -329,6 +333,22 @@ enum dp_link_rate {
DP_BW_HBR2,
};
+struct lcpll_config {
+ unsigned long long rate;
+ u8 lcvco_mode_en;
+ u8 pi_en;
+ u8 clk_en_100m;
+ u8 pms_mdiv;
+ u8 pms_mdiv_afc;
+ u8 pms_pdiv;
+ u8 pms_refdiv;
+ u8 pms_sdiv;
+ u8 sdm_deno;
+ u8 sdm_num_sign;
+ u8 sdm_num;
+ u8 sdc_n;
+};
+
struct ropll_config {
unsigned long long rate;
u8 pms_mdiv;
@@ -336,27 +356,13 @@ struct ropll_config {
u8 pms_pdiv;
u8 pms_refdiv;
u8 pms_sdiv;
- u8 pms_iqdiv_rstn;
- u8 ref_clk_sel;
u8 sdm_en;
- u8 sdm_rstn;
- u8 sdc_frac_en;
- u8 sdc_rstn;
- u8 sdm_clk_div;
u8 sdm_deno;
u8 sdm_num_sign;
u8 sdm_num;
u8 sdc_n;
u8 sdc_num;
u8 sdc_deno;
- u8 sdc_ndiv_rstn;
- u8 ssc_en;
- u8 ssc_fm_dev;
- u8 ssc_fm_freq;
- u8 ssc_clk_div_sel;
- u8 ana_cpp_ctrl;
- u8 ana_lpf_c_sel;
- u8 cd_tx_ser_rate_sel;
};
struct tx_drv_ctrl {
@@ -387,6 +393,12 @@ struct rk_hdptx_phy_cfg {
unsigned int phy_ids[MAX_HDPTX_PHY_NUM];
};
+struct rk_hdptx_hdmi_cfg {
+ enum phy_hdmi_mode mode;
+ unsigned long long rate;
+ unsigned int bpc;
+};
+
struct rk_hdptx_phy {
struct device *dev;
struct regmap *regmap;
@@ -394,14 +406,13 @@ struct rk_hdptx_phy {
int phy_id;
struct phy *phy;
- struct phy_configure_opts_hdmi hdmi_cfg;
+ struct rk_hdptx_hdmi_cfg hdmi_cfg;
struct clk_bulk_data *clks;
int nr_clks;
struct reset_control_bulk_data rsts[RST_MAX];
/* clk provider */
struct clk_hw hw;
- unsigned long hw_rate;
bool restrict_rate_change;
atomic_t usage_count;
@@ -411,52 +422,44 @@ struct rk_hdptx_phy {
unsigned int lanes;
};
-static const struct ropll_config ropll_tmds_cfg[] = {
- { 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
- 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
- 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
- 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 162000000ULL, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10,
- 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 185625000ULL, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
- 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 154000000ULL, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1,
- 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 148500000ULL, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5,
- 0x10, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 146250000ULL, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1,
- 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 119000000ULL, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1,
- 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 106500000ULL, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1,
- 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 108000000ULL, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
- 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 85500000ULL, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1,
- 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 83500000ULL, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0,
- 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 92812500ULL, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
- 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 74250000ULL, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
- 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 65000000ULL, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1,
- 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 50250000ULL, 84, 84, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 11, 1, 4, 5,
- 4, 11, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 33750000ULL, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5,
- 1, 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 40000000ULL, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
- 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 27000000ULL, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
- 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
- { 25175000ULL, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, 1,
- 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
+static const struct lcpll_config rk_hdptx_frl_lcpll_cfg[] = {
+ /* | pms | sdm | */
+ /* rate, lcen, pien, cken, mdiv, mdafc, pdiv, rdiv, sdiv, deno, nsig, num, sdcn, */
+ { 4800000000ULL, 1, 0, 0, 125, 125, 1, 1, 0, 1, 0, 0, 2, },
+ { 4000000000ULL, 1, 1, 0, 104, 104, 1, 1, 0, 9, 0, 1, 1, },
+ { 2400000000ULL, 1, 0, 0, 125, 125, 1, 1, 1, 1, 0, 0, 2, },
+ { 1800000000ULL, 1, 0, 0, 125, 125, 1, 1, 1, 1, 0, 0, 2, },
+ { 900000000ULL, 1, 0, 0, 125, 125, 1, 1, 3, 1, 0, 0, 2, },
+};
+
+static const struct ropll_config rk_hdptx_tmds_ropll_cfg[] = {
+ /* | pms | sdm | sdc | */
+ /* rate, mdiv, mdafc, pdiv, rdiv, sdiv, en, deno, nsig, num, n, num, deno, */
+ { 594000000ULL, 124, 124, 1, 1, 0, 1, 62, 1, 16, 5, 0, 1, },
+ { 461101250ULL, 97, 97, 1, 1, 0, 1, 71, 1, 53, 2, 6, 35, },
+ { 371250000ULL, 155, 155, 1, 1, 1, 1, 62, 1, 16, 5, 0, 1, },
+ { 297000000ULL, 124, 124, 1, 1, 1, 1, 62, 1, 16, 5, 0, 1, },
+ { 185625000ULL, 155, 155, 1, 1, 3, 1, 62, 1, 16, 5, 0, 1, },
+ { 162000000ULL, 135, 135, 1, 1, 3, 0, 4, 0, 3, 5, 5, 16, },
+ { 154000000ULL, 193, 193, 1, 1, 5, 1, 193, 1, 32, 2, 1, 1, },
+ { 148500000ULL, 123, 123, 1, 1, 3, 1, 4, 0, 3, 5, 5, 16, },
+ { 146250000ULL, 122, 122, 1, 1, 3, 1, 244, 1, 16, 2, 1, 1, },
+ { 119000000ULL, 149, 149, 1, 1, 5, 1, 149, 1, 16, 2, 1, 1, },
+ { 108000000ULL, 135, 135, 1, 1, 5, 0, 9, 0, 5, 0, 20, 24, },
+ { 106500000ULL, 89, 89, 1, 1, 3, 1, 89, 1, 16, 1, 0, 1, },
+ { 92812500ULL, 155, 155, 1, 1, 7, 1, 62, 1, 16, 5, 0, 1, },
+ { 85500000ULL, 214, 214, 1, 1, 11, 1, 214, 1, 16, 2, 1, 1, },
+ { 83500000ULL, 105, 105, 1, 1, 5, 1, 42, 1, 16, 1, 0, 1, },
+ { 74250000ULL, 124, 124, 1, 1, 7, 1, 62, 1, 16, 5, 0, 1, },
+ { 65000000ULL, 162, 162, 1, 1, 11, 1, 54, 0, 16, 4, 1, 1, },
+ { 50250000ULL, 84, 84, 1, 1, 7, 1, 11, 1, 4, 5, 4, 11, },
+ { 40000000ULL, 100, 100, 1, 1, 11, 0, 9, 0, 5, 0, 20, 24, },
+ { 33750000ULL, 112, 112, 1, 1, 15, 1, 2, 0, 1, 5, 1, 1, },
+ { 27000000ULL, 90, 90, 1, 1, 15, 0, 9, 0, 5, 0, 20, 24, },
+ { 25175000ULL, 84, 84, 1, 1, 15, 1, 168, 1, 16, 4, 1, 1, },
};
-static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {
+static const struct reg_sequence rk_hdptx_common_cmn_init_seq[] = {
REG_SEQ0(CMN_REG(0009), 0x0c),
REG_SEQ0(CMN_REG(000a), 0x83),
REG_SEQ0(CMN_REG(000b), 0x06),
@@ -465,13 +468,11 @@ static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {
REG_SEQ0(CMN_REG(000e), 0x0f),
REG_SEQ0(CMN_REG(000f), 0x0f),
REG_SEQ0(CMN_REG(0010), 0x04),
- REG_SEQ0(CMN_REG(0011), 0x00),
REG_SEQ0(CMN_REG(0012), 0x26),
REG_SEQ0(CMN_REG(0013), 0x22),
REG_SEQ0(CMN_REG(0014), 0x24),
REG_SEQ0(CMN_REG(0015), 0x77),
REG_SEQ0(CMN_REG(0016), 0x08),
- REG_SEQ0(CMN_REG(0017), 0x00),
REG_SEQ0(CMN_REG(0018), 0x04),
REG_SEQ0(CMN_REG(0019), 0x48),
REG_SEQ0(CMN_REG(001a), 0x01),
@@ -479,13 +480,7 @@ static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {
REG_SEQ0(CMN_REG(001c), 0x01),
REG_SEQ0(CMN_REG(001d), 0x64),
REG_SEQ0(CMN_REG(001f), 0x00),
- REG_SEQ0(CMN_REG(0026), 0x53),
REG_SEQ0(CMN_REG(0029), 0x01),
- REG_SEQ0(CMN_REG(0030), 0x00),
- REG_SEQ0(CMN_REG(0031), 0x20),
- REG_SEQ0(CMN_REG(0032), 0x30),
- REG_SEQ0(CMN_REG(0033), 0x0b),
- REG_SEQ0(CMN_REG(0034), 0x23),
REG_SEQ0(CMN_REG(0035), 0x00),
REG_SEQ0(CMN_REG(0038), 0x00),
REG_SEQ0(CMN_REG(0039), 0x00),
@@ -496,7 +491,6 @@ static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {
REG_SEQ0(CMN_REG(003f), 0x83),
REG_SEQ0(CMN_REG(0040), 0x06),
REG_SEQ0(CMN_REG(0041), 0x20),
- REG_SEQ0(CMN_REG(0042), 0xb8),
REG_SEQ0(CMN_REG(0043), 0x00),
REG_SEQ0(CMN_REG(0044), 0x46),
REG_SEQ0(CMN_REG(0045), 0x24),
@@ -506,14 +500,9 @@ static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {
REG_SEQ0(CMN_REG(004b), 0x00),
REG_SEQ0(CMN_REG(004c), 0x01),
REG_SEQ0(CMN_REG(004d), 0x64),
- REG_SEQ0(CMN_REG(004e), 0x14),
REG_SEQ0(CMN_REG(004f), 0x00),
REG_SEQ0(CMN_REG(0050), 0x00),
- REG_SEQ0(CMN_REG(005d), 0x0c),
REG_SEQ0(CMN_REG(005f), 0x01),
- REG_SEQ0(CMN_REG(006b), 0x04),
- REG_SEQ0(CMN_REG(0073), 0x30),
- REG_SEQ0(CMN_REG(0074), 0x00),
REG_SEQ0(CMN_REG(0075), 0x20),
REG_SEQ0(CMN_REG(0076), 0x30),
REG_SEQ0(CMN_REG(0077), 0x08),
@@ -525,13 +514,10 @@ static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {
REG_SEQ0(CMN_REG(007e), 0x00),
REG_SEQ0(CMN_REG(007f), 0x00),
REG_SEQ0(CMN_REG(0080), 0x00),
- REG_SEQ0(CMN_REG(0081), 0x09),
REG_SEQ0(CMN_REG(0082), 0x04),
REG_SEQ0(CMN_REG(0083), 0x24),
REG_SEQ0(CMN_REG(0084), 0x20),
REG_SEQ0(CMN_REG(0085), 0x03),
- REG_SEQ0(CMN_REG(0086), 0x01),
- REG_SEQ0(CMN_REG(0087), 0x0c),
REG_SEQ0(CMN_REG(008a), 0x55),
REG_SEQ0(CMN_REG(008b), 0x25),
REG_SEQ0(CMN_REG(008c), 0x2c),
@@ -543,10 +529,113 @@ static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = {
REG_SEQ0(CMN_REG(0092), 0x00),
REG_SEQ0(CMN_REG(0093), 0x00),
REG_SEQ0(CMN_REG(009a), 0x11),
+};
+
+static const struct reg_sequence rk_hdptx_frl_lcpll_cmn_init_seq[] = {
+ REG_SEQ0(CMN_REG(0011), 0x00),
+ REG_SEQ0(CMN_REG(0017), 0x00),
+ REG_SEQ0(CMN_REG(0025), 0x10),
+ REG_SEQ0(CMN_REG(0026), 0x53),
+ REG_SEQ0(CMN_REG(0027), 0x01),
+ REG_SEQ0(CMN_REG(0028), 0x0d),
+ REG_SEQ0(CMN_REG(002e), 0x02),
+ REG_SEQ0(CMN_REG(002f), 0x0d),
+ REG_SEQ0(CMN_REG(0030), 0x00),
+ REG_SEQ0(CMN_REG(0031), 0x20),
+ REG_SEQ0(CMN_REG(0032), 0x30),
+ REG_SEQ0(CMN_REG(0033), 0x0b),
+ REG_SEQ0(CMN_REG(0034), 0x23),
+ REG_SEQ0(CMN_REG(003d), 0x00),
+ REG_SEQ0(CMN_REG(0042), 0xb8),
+ REG_SEQ0(CMN_REG(0046), 0xff),
+ REG_SEQ0(CMN_REG(0048), 0x44),
+ REG_SEQ0(CMN_REG(004e), 0x14),
+ REG_SEQ0(CMN_REG(0051), 0x00),
+ REG_SEQ0(CMN_REG(0055), 0x00),
+ REG_SEQ0(CMN_REG(0059), 0x11),
+ REG_SEQ0(CMN_REG(005a), 0x03),
+ REG_SEQ0(CMN_REG(005c), 0x05),
+ REG_SEQ0(CMN_REG(005d), 0x0c),
+ REG_SEQ0(CMN_REG(005e), 0x07),
+ REG_SEQ0(CMN_REG(0060), 0x01),
+ REG_SEQ0(CMN_REG(0064), 0x07),
+ REG_SEQ0(CMN_REG(0065), 0x00),
+ REG_SEQ0(CMN_REG(0069), 0x00),
+ REG_SEQ0(CMN_REG(006b), 0x04),
+ REG_SEQ0(CMN_REG(006c), 0x00),
+ REG_SEQ0(CMN_REG(0070), 0x01),
+ REG_SEQ0(CMN_REG(0073), 0x30),
+ REG_SEQ0(CMN_REG(0074), 0x00),
+ REG_SEQ0(CMN_REG(0081), 0x09),
+ REG_SEQ0(CMN_REG(0086), 0x01),
+ REG_SEQ0(CMN_REG(0087), 0x0c),
+ REG_SEQ0(CMN_REG(0089), 0x02),
+ REG_SEQ0(CMN_REG(0095), 0x00),
+ REG_SEQ0(CMN_REG(0097), 0x00),
+ REG_SEQ0(CMN_REG(0099), 0x00),
+ REG_SEQ0(CMN_REG(009b), 0x10),
+};
+
+static const struct reg_sequence rk_hdptx_frl_lcpll_ropll_cmn_init_seq[] = {
+ REG_SEQ0(CMN_REG(0008), 0xd0),
+ REG_SEQ0(CMN_REG(0011), 0x00),
+ REG_SEQ0(CMN_REG(0017), 0x00),
+ REG_SEQ0(CMN_REG(001e), 0x35),
+ REG_SEQ0(CMN_REG(0020), 0x6b),
+ REG_SEQ0(CMN_REG(0021), 0x6b),
+ REG_SEQ0(CMN_REG(0022), 0x11),
+ REG_SEQ0(CMN_REG(0024), 0x00),
+ REG_SEQ0(CMN_REG(0025), 0x10),
+ REG_SEQ0(CMN_REG(0026), 0x53),
+ REG_SEQ0(CMN_REG(0027), 0x15),
+ REG_SEQ0(CMN_REG(0028), 0x0d),
+ REG_SEQ0(CMN_REG(002a), 0x09),
+ REG_SEQ0(CMN_REG(002b), 0x01),
+ REG_SEQ0(CMN_REG(002c), 0x02),
+ REG_SEQ0(CMN_REG(002d), 0x02),
+ REG_SEQ0(CMN_REG(002e), 0x0d),
+ REG_SEQ0(CMN_REG(002f), 0x61),
+ REG_SEQ0(CMN_REG(0030), 0x00),
+ REG_SEQ0(CMN_REG(0031), 0x20),
+ REG_SEQ0(CMN_REG(0032), 0x30),
+ REG_SEQ0(CMN_REG(0033), 0x0b),
+ REG_SEQ0(CMN_REG(0034), 0x23),
+ REG_SEQ0(CMN_REG(0037), 0x00),
+ REG_SEQ0(CMN_REG(003d), 0xc0),
+ REG_SEQ0(CMN_REG(0042), 0xb8),
+ REG_SEQ0(CMN_REG(0046), 0xff),
+ REG_SEQ0(CMN_REG(0048), 0x44),
+ REG_SEQ0(CMN_REG(004e), 0x14),
+ REG_SEQ0(CMN_REG(0054), 0x19),
+ REG_SEQ0(CMN_REG(0058), 0x19),
+ REG_SEQ0(CMN_REG(0059), 0x11),
+ REG_SEQ0(CMN_REG(005b), 0x30),
+ REG_SEQ0(CMN_REG(005c), 0x25),
+ REG_SEQ0(CMN_REG(005d), 0x14),
+ REG_SEQ0(CMN_REG(005e), 0x0e),
+ REG_SEQ0(CMN_REG(0063), 0x01),
+ REG_SEQ0(CMN_REG(0064), 0x0e),
+ REG_SEQ0(CMN_REG(0068), 0x00),
+ REG_SEQ0(CMN_REG(0069), 0x02),
+ REG_SEQ0(CMN_REG(006b), 0x00),
+ REG_SEQ0(CMN_REG(006f), 0x00),
+ REG_SEQ0(CMN_REG(0073), 0x02),
+ REG_SEQ0(CMN_REG(0074), 0x00),
+ REG_SEQ0(CMN_REG(007a), 0x00),
+ REG_SEQ0(CMN_REG(0081), 0x09),
+ REG_SEQ0(CMN_REG(0086), 0x11),
+ REG_SEQ0(CMN_REG(0087), 0x0c),
+ REG_SEQ0(CMN_REG(0089), 0x00),
+ REG_SEQ0(CMN_REG(0095), 0x03),
+ REG_SEQ0(CMN_REG(0097), 0x00),
+ REG_SEQ0(CMN_REG(0099), 0x00),
REG_SEQ0(CMN_REG(009b), 0x10),
+ REG_SEQ0(CMN_REG(009e), 0x03),
+ REG_SEQ0(CMN_REG(009f), 0xff),
+ REG_SEQ0(CMN_REG(00a0), 0x60),
};
-static const struct reg_sequence rk_hdtpx_tmds_cmn_init_seq[] = {
+static const struct reg_sequence rk_hdptx_tmds_cmn_init_seq[] = {
REG_SEQ0(CMN_REG(0008), 0x00),
REG_SEQ0(CMN_REG(0011), 0x01),
REG_SEQ0(CMN_REG(0017), 0x20),
@@ -577,9 +666,13 @@ static const struct reg_sequence rk_hdtpx_tmds_cmn_init_seq[] = {
REG_SEQ0(CMN_REG(0048), 0x11),
REG_SEQ0(CMN_REG(004e), 0x34),
REG_SEQ0(CMN_REG(005c), 0x25),
+ REG_SEQ0(CMN_REG(005d), 0x0c),
REG_SEQ0(CMN_REG(005e), 0x4f),
+ REG_SEQ0(CMN_REG(006b), 0x04),
+ REG_SEQ0(CMN_REG(0073), 0x30),
REG_SEQ0(CMN_REG(0074), 0x04),
REG_SEQ0(CMN_REG(0081), 0x01),
+ REG_SEQ0(CMN_REG(0086), 0x01),
REG_SEQ0(CMN_REG(0087), 0x04),
REG_SEQ0(CMN_REG(0089), 0x00),
REG_SEQ0(CMN_REG(0095), 0x00),
@@ -588,14 +681,24 @@ static const struct reg_sequence rk_hdtpx_tmds_cmn_init_seq[] = {
REG_SEQ0(CMN_REG(009b), 0x00),
};
-static const struct reg_sequence rk_hdtpx_common_sb_init_seq[] = {
+static const struct reg_sequence rk_hdptx_common_sb_init_seq[] = {
REG_SEQ0(SB_REG(0114), 0x00),
REG_SEQ0(SB_REG(0115), 0x00),
REG_SEQ0(SB_REG(0116), 0x00),
REG_SEQ0(SB_REG(0117), 0x00),
};
-static const struct reg_sequence rk_hdtpx_tmds_lntop_highbr_seq[] = {
+static const struct reg_sequence rk_hdptx_frl_lntop_init_seq[] = {
+ REG_SEQ0(LNTOP_REG(0200), 0x04),
+ REG_SEQ0(LNTOP_REG(0201), 0x00),
+ REG_SEQ0(LNTOP_REG(0202), 0x00),
+ REG_SEQ0(LNTOP_REG(0203), 0xf0),
+ REG_SEQ0(LNTOP_REG(0204), 0xff),
+ REG_SEQ0(LNTOP_REG(0205), 0xff),
+ REG_SEQ0(LNTOP_REG(0206), 0x05),
+};
+
+static const struct reg_sequence rk_hdptx_tmds_lntop_highbr_seq[] = {
REG_SEQ0(LNTOP_REG(0201), 0x00),
REG_SEQ0(LNTOP_REG(0202), 0x00),
REG_SEQ0(LNTOP_REG(0203), 0x0f),
@@ -603,7 +706,7 @@ static const struct reg_sequence rk_hdtpx_tmds_lntop_highbr_seq[] = {
REG_SEQ0(LNTOP_REG(0205), 0xff),
};
-static const struct reg_sequence rk_hdtpx_tmds_lntop_lowbr_seq[] = {
+static const struct reg_sequence rk_hdptx_tmds_lntop_lowbr_seq[] = {
REG_SEQ0(LNTOP_REG(0201), 0x07),
REG_SEQ0(LNTOP_REG(0202), 0xc1),
REG_SEQ0(LNTOP_REG(0203), 0xf0),
@@ -611,7 +714,7 @@ static const struct reg_sequence rk_hdtpx_tmds_lntop_lowbr_seq[] = {
REG_SEQ0(LNTOP_REG(0205), 0x1f),
};
-static const struct reg_sequence rk_hdtpx_common_lane_init_seq[] = {
+static const struct reg_sequence rk_hdptx_common_lane_init_seq[] = {
REG_SEQ0(LANE_REG(0303), 0x0c),
REG_SEQ0(LANE_REG(0307), 0x20),
REG_SEQ0(LANE_REG(030a), 0x17),
@@ -666,7 +769,39 @@ static const struct reg_sequence rk_hdtpx_common_lane_init_seq[] = {
REG_SEQ0(LANE_REG(0620), 0xa0),
};
-static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = {
+static const struct reg_sequence rk_hdptx_frl_lane_init_seq[] = {
+ REG_SEQ0(LANE_REG(0312), 0x3c),
+ REG_SEQ0(LANE_REG(0412), 0x3c),
+ REG_SEQ0(LANE_REG(0512), 0x3c),
+ REG_SEQ0(LANE_REG(0612), 0x3c),
+ REG_SEQ0(LANE_REG(0303), 0x2f),
+ REG_SEQ0(LANE_REG(0403), 0x2f),
+ REG_SEQ0(LANE_REG(0503), 0x2f),
+ REG_SEQ0(LANE_REG(0603), 0x2f),
+ REG_SEQ0(LANE_REG(0305), 0x03),
+ REG_SEQ0(LANE_REG(0405), 0x03),
+ REG_SEQ0(LANE_REG(0505), 0x03),
+ REG_SEQ0(LANE_REG(0605), 0x03),
+ REG_SEQ0(LANE_REG(0306), 0xfc),
+ REG_SEQ0(LANE_REG(0406), 0xfc),
+ REG_SEQ0(LANE_REG(0506), 0xfc),
+ REG_SEQ0(LANE_REG(0606), 0xfc),
+ REG_SEQ0(LANE_REG(0305), 0x4f),
+ REG_SEQ0(LANE_REG(0405), 0x4f),
+ REG_SEQ0(LANE_REG(0505), 0x4f),
+ REG_SEQ0(LANE_REG(0605), 0x4f),
+ REG_SEQ0(LANE_REG(0304), 0x14),
+ REG_SEQ0(LANE_REG(0404), 0x14),
+ REG_SEQ0(LANE_REG(0504), 0x14),
+ REG_SEQ0(LANE_REG(0604), 0x14),
+ /* Keep Inter-Pair Skew in the limits */
+ REG_SEQ0(LANE_REG(031e), 0x02),
+ REG_SEQ0(LANE_REG(041e), 0x02),
+ REG_SEQ0(LANE_REG(051e), 0x02),
+ REG_SEQ0(LANE_REG(061e), 0x02),
+};
+
+static const struct reg_sequence rk_hdptx_tmds_lane_init_seq[] = {
REG_SEQ0(LANE_REG(0312), 0x00),
REG_SEQ0(LANE_REG(0412), 0x00),
REG_SEQ0(LANE_REG(0512), 0x00),
@@ -829,6 +964,13 @@ static int rk_hdptx_post_enable_lane(struct rk_hdptx_phy *hdptx)
HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN;
regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
+ /* 3 lanes FRL mode */
+ if (hdptx->hdmi_cfg.rate == FRL_6G3L_RATE ||
+ hdptx->hdmi_cfg.rate == FRL_3G3L_RATE)
+ regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x07);
+ else
+ regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f);
+
ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val,
(val & HDPTX_O_PHY_RDY) &&
(val & HDPTX_O_PLL_LOCK_DONE),
@@ -882,6 +1024,7 @@ static void rk_hdptx_phy_disable(struct rk_hdptx_phy *hdptx)
usleep_range(20, 30);
reset_control_deassert(hdptx->rsts[RST_APB].rstc);
+ regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0);
regmap_write(hdptx->regmap, LANE_REG(0300), 0x82);
regmap_write(hdptx->regmap, SB_REG(010f), 0xc1);
regmap_write(hdptx->regmap, SB_REG(0110), 0x1);
@@ -970,25 +1113,99 @@ static bool rk_hdptx_phy_clk_pll_calc(unsigned long long rate,
return true;
}
-static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx)
+static int rk_hdptx_frl_lcpll_cmn_config(struct rk_hdptx_phy *hdptx)
+{
+ const struct lcpll_config *cfg = NULL;
+ int i;
+
+ dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.rate);
+
+ for (i = 0; i < ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg); i++) {
+ if (hdptx->hdmi_cfg.rate == rk_hdptx_frl_lcpll_cfg[i].rate) {
+ cfg = &rk_hdptx_frl_lcpll_cfg[i];
+ break;
+ }
+ }
+
+ if (!cfg) {
+ dev_err(hdptx->dev, "%s cannot find pll cfg for rate=%llu\n",
+ __func__, hdptx->hdmi_cfg.rate);
+ return -EINVAL;
+ }
+
+ rk_hdptx_pre_power_up(hdptx);
+
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0, LC_REF_CLK_SEL << 16);
+
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq);
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lcpll_cmn_init_seq);
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0008),
+ LCPLL_EN_MASK | LCPLL_LCVCO_MODE_EN_MASK,
+ FIELD_PREP(LCPLL_EN_MASK, 1) |
+ FIELD_PREP(LCPLL_LCVCO_MODE_EN_MASK, cfg->lcvco_mode_en));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(001e),
+ LCPLL_PI_EN_MASK | LCPLL_100M_CLK_EN_MASK,
+ FIELD_PREP(LCPLL_PI_EN_MASK, cfg->pi_en) |
+ FIELD_PREP(LCPLL_100M_CLK_EN_MASK, cfg->clk_en_100m));
+
+ regmap_write(hdptx->regmap, CMN_REG(0020), cfg->pms_mdiv);
+ regmap_write(hdptx->regmap, CMN_REG(0021), cfg->pms_mdiv_afc);
+ regmap_write(hdptx->regmap, CMN_REG(0022),
+ (cfg->pms_pdiv << 4) | cfg->pms_refdiv);
+ regmap_write(hdptx->regmap, CMN_REG(0023),
+ (cfg->pms_sdiv << 4) | cfg->pms_sdiv);
+ regmap_write(hdptx->regmap, CMN_REG(002a), cfg->sdm_deno);
+ regmap_write(hdptx->regmap, CMN_REG(002b), cfg->sdm_num_sign);
+ regmap_write(hdptx->regmap, CMN_REG(002c), cfg->sdm_num);
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(002d), LCPLL_SDC_N_MASK,
+ FIELD_PREP(LCPLL_SDC_N_MASK, cfg->sdc_n));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK,
+ FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv));
+ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_SEL_MASK,
+ FIELD_PREP(PLL_PCG_CLK_SEL_MASK, (hdptx->hdmi_cfg.bpc - 8) >> 1));
+
+ return rk_hdptx_post_enable_pll(hdptx);
+}
+
+static int rk_hdptx_frl_lcpll_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
+{
+ dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.rate);
+
+ rk_hdptx_pre_power_up(hdptx);
+
+ /* ROPLL input reference clock from LCPLL (cascade mode) */
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+ (LC_REF_CLK_SEL << 16) | LC_REF_CLK_SEL);
+
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq);
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lcpll_ropll_cmn_init_seq);
+
+ return rk_hdptx_post_enable_pll(hdptx);
+}
+
+static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
{
const struct ropll_config *cfg = NULL;
struct ropll_config rc = {0};
- int ret, i;
+ int i;
- if (!hdptx->hdmi_cfg.tmds_char_rate)
+ if (!hdptx->hdmi_cfg.rate)
return 0;
- for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
- if (hdptx->hdmi_cfg.tmds_char_rate == ropll_tmds_cfg[i].rate) {
- cfg = &ropll_tmds_cfg[i];
+ for (i = 0; i < ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg); i++)
+ if (hdptx->hdmi_cfg.rate == rk_hdptx_tmds_ropll_cfg[i].rate) {
+ cfg = &rk_hdptx_tmds_ropll_cfg[i];
break;
}
if (!cfg) {
- if (!rk_hdptx_phy_clk_pll_calc(hdptx->hdmi_cfg.tmds_char_rate, &rc)) {
+ if (!rk_hdptx_phy_clk_pll_calc(hdptx->hdmi_cfg.rate, &rc)) {
dev_err(hdptx->dev, "%s cannot find pll cfg for rate=%llu\n",
- __func__, hdptx->hdmi_cfg.tmds_char_rate);
+ __func__, hdptx->hdmi_cfg.rate);
return -EINVAL;
}
@@ -996,13 +1213,15 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx)
}
dev_dbg(hdptx->dev, "%s rate=%llu mdiv=%u sdiv=%u sdm_en=%u k_sign=%u k=%u lc=%u\n",
- __func__, hdptx->hdmi_cfg.tmds_char_rate, cfg->pms_mdiv, cfg->pms_sdiv + 1,
+ __func__, hdptx->hdmi_cfg.rate, cfg->pms_mdiv, cfg->pms_sdiv + 1,
cfg->sdm_en, cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno);
rk_hdptx_pre_power_up(hdptx);
- rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_cmn_init_seq);
- rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_cmn_init_seq);
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0, LC_REF_CLK_SEL << 16);
+
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq);
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_cmn_init_seq);
regmap_write(hdptx->regmap, CMN_REG(0051), cfg->pms_mdiv);
regmap_write(hdptx->regmap, CMN_REG(0055), cfg->pms_mdiv_afc);
@@ -1036,33 +1255,49 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx)
regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN_MASK,
FIELD_PREP(PLL_PCG_CLK_EN_MASK, 0x1));
- ret = rk_hdptx_post_enable_pll(hdptx);
- if (!ret)
- hdptx->hw_rate = DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8,
- hdptx->hdmi_cfg.bpc);
+ return rk_hdptx_post_enable_pll(hdptx);
+}
- return ret;
+static int rk_hdptx_pll_cmn_config(struct rk_hdptx_phy *hdptx)
+{
+ if (hdptx->hdmi_cfg.rate <= HDMI20_MAX_RATE)
+ return rk_hdptx_tmds_ropll_cmn_config(hdptx);
+
+ if (hdptx->hdmi_cfg.rate == FRL_8G4L_RATE)
+ return rk_hdptx_frl_lcpll_ropll_cmn_config(hdptx);
+
+ return rk_hdptx_frl_lcpll_cmn_config(hdptx);
}
-static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx)
+static int rk_hdptx_frl_lcpll_mode_config(struct rk_hdptx_phy *hdptx)
{
- rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq);
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_sb_init_seq);
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lntop_init_seq);
+
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_lane_init_seq);
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_frl_lane_init_seq);
+
+ return rk_hdptx_post_enable_lane(hdptx);
+}
+
+static int rk_hdptx_tmds_ropll_mode_config(struct rk_hdptx_phy *hdptx)
+{
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_sb_init_seq);
regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06);
- if (hdptx->hdmi_cfg.tmds_char_rate > HDMI14_MAX_RATE) {
+ if (hdptx->hdmi_cfg.rate > HDMI14_MAX_RATE) {
/* For 1/40 bitrate clk */
- rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_highbr_seq);
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_lntop_highbr_seq);
} else {
/* For 1/10 bitrate clk */
- rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_lowbr_seq);
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_lntop_lowbr_seq);
}
regmap_write(hdptx->regmap, LNTOP_REG(0206), 0x07);
- regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f);
- rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_lane_init_seq);
- rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lane_init_seq);
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_lane_init_seq);
+ rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_lane_init_seq);
return rk_hdptx_post_enable_lane(hdptx);
}
@@ -1074,7 +1309,7 @@ static void rk_hdptx_dp_reset(struct rk_hdptx_phy *hdptx)
reset_control_assert(hdptx->rsts[RST_INIT].rstc);
reset_control_assert(hdptx->rsts[RST_APB].rstc);
- udelay(10);
+ usleep_range(10, 15);
reset_control_deassert(hdptx->rsts[RST_APB].rstc);
regmap_update_bits(hdptx->regmap, LANE_REG(0301),
@@ -1121,7 +1356,7 @@ static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx)
if (mode == PHY_MODE_DP) {
rk_hdptx_dp_reset(hdptx);
} else {
- ret = rk_hdptx_ropll_tmds_cmn_config(hdptx);
+ ret = rk_hdptx_pll_cmn_config(hdptx);
if (ret)
goto dec_usage;
}
@@ -1422,19 +1657,19 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
int ret, lane;
if (mode != PHY_MODE_DP) {
- if (!hdptx->hdmi_cfg.tmds_char_rate) {
+ if (!hdptx->hdmi_cfg.rate && hdptx->hdmi_cfg.mode != PHY_HDMI_MODE_FRL) {
/*
* FIXME: Temporary workaround to setup TMDS char rate
* from the RK DW HDMI QP bridge driver.
* Will be removed as soon the switch to the HDMI PHY
* configuration API has been completed on both ends.
*/
- hdptx->hdmi_cfg.tmds_char_rate = phy_get_bus_width(hdptx->phy) & 0xfffffff;
- hdptx->hdmi_cfg.tmds_char_rate *= 100;
+ hdptx->hdmi_cfg.rate = phy_get_bus_width(hdptx->phy) & 0xfffffff;
+ hdptx->hdmi_cfg.rate *= 100;
}
dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
- hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc);
+ hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
}
ret = rk_hdptx_phy_consumer_get(hdptx);
@@ -1468,7 +1703,11 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
regmap_write(hdptx->grf, GRF_HDPTX_CON0,
HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
- ret = rk_hdptx_ropll_tmds_mode_config(hdptx);
+ if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
+ ret = rk_hdptx_frl_lcpll_mode_config(hdptx);
+ else
+ ret = rk_hdptx_tmds_ropll_mode_config(hdptx);
+
if (ret)
rk_hdptx_phy_consumer_put(hdptx, true);
}
@@ -1484,25 +1723,57 @@ static int rk_hdptx_phy_power_off(struct phy *phy)
}
static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx,
- struct phy_configure_opts_hdmi *hdmi)
+ struct phy_configure_opts_hdmi *hdmi_in,
+ struct rk_hdptx_hdmi_cfg *hdmi_out)
{
int i;
- if (!hdmi->tmds_char_rate || hdmi->tmds_char_rate > HDMI20_MAX_RATE)
- return -EINVAL;
+ if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) {
+ unsigned long long frl_rate = 100000000ULL * hdmi_in->frl.lanes *
+ hdmi_in->frl.rate_per_lane;
- for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
- if (hdmi->tmds_char_rate == ropll_tmds_cfg[i].rate)
+ switch (hdmi_in->frl.rate_per_lane) {
+ case 3:
+ case 6:
+ case 8:
+ case 10:
+ case 12:
break;
+ default:
+ return -EINVAL;
+ }
- if (i == ARRAY_SIZE(ropll_tmds_cfg) &&
- !rk_hdptx_phy_clk_pll_calc(hdmi->tmds_char_rate, NULL))
- return -EINVAL;
+ if (!hdmi_in->frl.lanes || hdmi_in->frl.lanes > 4)
+ return -EINVAL;
- if (!hdmi->bpc)
- hdmi->bpc = 8;
+ if (frl_rate != FRL_8G4L_RATE) {
+ for (i = 0; i < ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg); i++)
+ if (frl_rate == rk_hdptx_frl_lcpll_cfg[i].rate)
+ break;
+ if (i == ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg))
+ return -EINVAL;
+ }
- switch (hdmi->bpc) {
+ if (hdmi_out)
+ hdmi_out->rate = frl_rate;
+ } else {
+ if (!hdmi_in->tmds_char_rate || hdmi_in->tmds_char_rate > HDMI20_MAX_RATE)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg); i++)
+ if (hdmi_in->tmds_char_rate == rk_hdptx_tmds_ropll_cfg[i].rate)
+ break;
+
+ if (i == ARRAY_SIZE(rk_hdptx_tmds_ropll_cfg) &&
+ !rk_hdptx_phy_clk_pll_calc(hdmi_in->tmds_char_rate, NULL))
+ return -EINVAL;
+
+ if (hdmi_out)
+ hdmi_out->rate = hdmi_in->tmds_char_rate;
+ }
+
+ switch (hdmi_in->bpc) {
+ case 0:
case 8:
case 10:
case 12:
@@ -1512,6 +1783,9 @@ static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx,
return -EINVAL;
}
+ if (hdmi_out)
+ hdmi_out->bpc = hdmi_in->bpc ?: 8;
+
return 0;
}
@@ -1656,11 +1930,11 @@ static void rk_hdptx_phy_set_voltage(struct rk_hdptx_phy *hdptx,
regmap_update_bits(hdptx->regmap, LANE_REG(030a) + offset,
LN_TX_JEQ_EVEN_CTRL_RBR_MASK,
FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_RBR_MASK,
- ctrl->tx_jeq_even_ctrl));
+ ctrl->tx_jeq_even_ctrl));
regmap_update_bits(hdptx->regmap, LANE_REG(030c) + offset,
LN_TX_JEQ_ODD_CTRL_RBR_MASK,
FIELD_PREP(LN_TX_JEQ_ODD_CTRL_RBR_MASK,
- ctrl->tx_jeq_odd_ctrl));
+ ctrl->tx_jeq_odd_ctrl));
regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset,
LN_TX_SER_40BIT_EN_RBR_MASK,
FIELD_PREP(LN_TX_SER_40BIT_EN_RBR_MASK, 0x1));
@@ -1670,11 +1944,11 @@ static void rk_hdptx_phy_set_voltage(struct rk_hdptx_phy *hdptx,
regmap_update_bits(hdptx->regmap, LANE_REG(030b) + offset,
LN_TX_JEQ_EVEN_CTRL_HBR_MASK,
FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_HBR_MASK,
- ctrl->tx_jeq_even_ctrl));
+ ctrl->tx_jeq_even_ctrl));
regmap_update_bits(hdptx->regmap, LANE_REG(030d) + offset,
LN_TX_JEQ_ODD_CTRL_HBR_MASK,
FIELD_PREP(LN_TX_JEQ_ODD_CTRL_HBR_MASK,
- ctrl->tx_jeq_odd_ctrl));
+ ctrl->tx_jeq_odd_ctrl));
regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset,
LN_TX_SER_40BIT_EN_HBR_MASK,
FIELD_PREP(LN_TX_SER_40BIT_EN_HBR_MASK, 0x1));
@@ -1685,11 +1959,11 @@ static void rk_hdptx_phy_set_voltage(struct rk_hdptx_phy *hdptx,
regmap_update_bits(hdptx->regmap, LANE_REG(030b) + offset,
LN_TX_JEQ_EVEN_CTRL_HBR2_MASK,
FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_HBR2_MASK,
- ctrl->tx_jeq_even_ctrl));
+ ctrl->tx_jeq_even_ctrl));
regmap_update_bits(hdptx->regmap, LANE_REG(030d) + offset,
LN_TX_JEQ_ODD_CTRL_HBR2_MASK,
FIELD_PREP(LN_TX_JEQ_ODD_CTRL_HBR2_MASK,
- ctrl->tx_jeq_odd_ctrl));
+ ctrl->tx_jeq_odd_ctrl));
regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset,
LN_TX_SER_40BIT_EN_HBR2_MASK,
FIELD_PREP(LN_TX_SER_40BIT_EN_HBR2_MASK, 0x1));
@@ -1770,6 +2044,31 @@ static int rk_hdptx_phy_set_voltages(struct rk_hdptx_phy *hdptx,
return 0;
}
+static int rk_hdptx_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
+
+ if (mode == PHY_MODE_DP)
+ return 0;
+
+ if (mode != PHY_MODE_HDMI) {
+ dev_err(&phy->dev, "invalid PHY mode: %d\n", mode);
+ return -EINVAL;
+ }
+
+ switch (submode) {
+ case PHY_HDMI_MODE_TMDS:
+ case PHY_HDMI_MODE_FRL:
+ hdptx->hdmi_cfg.mode = submode;
+ break;
+ default:
+ dev_err(&phy->dev, "invalid HDMI mode: %d\n", submode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opts)
{
struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
@@ -1777,16 +2076,15 @@ static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opt
int ret;
if (mode != PHY_MODE_DP) {
- ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi);
+ ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi, &hdptx->hdmi_cfg);
if (ret) {
dev_err(hdptx->dev, "invalid hdmi params for phy configure\n");
} else {
- hdptx->hdmi_cfg = opts->hdmi;
hdptx->restrict_rate_change = true;
+ dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
+ hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
}
- dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
- hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc);
return ret;
}
@@ -1830,7 +2128,7 @@ static int rk_hdptx_phy_validate(struct phy *phy, enum phy_mode mode,
struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
if (mode != PHY_MODE_DP)
- return rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi);
+ return rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi, NULL);
return rk_hdptx_phy_verify_dp_config(hdptx, &opts->dp);
}
@@ -1838,6 +2136,7 @@ static int rk_hdptx_phy_validate(struct phy *phy, enum phy_mode mode,
static const struct phy_ops rk_hdptx_phy_ops = {
.power_on = rk_hdptx_phy_power_on,
.power_off = rk_hdptx_phy_power_off,
+ .set_mode = rk_hdptx_phy_set_mode,
.configure = rk_hdptx_phy_configure,
.validate = rk_hdptx_phy_validate,
.owner = THIS_MODULE,
@@ -1862,34 +2161,170 @@ static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw)
rk_hdptx_phy_consumer_put(hdptx, true);
}
+#define PLL_REF_CLK 24000000ULL
+
+static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
+{
+ struct lcpll_config lcpll_hw;
+ struct ropll_config ropll_hw;
+ u64 fout, sdm;
+ u32 mode, val;
+ int ret, i;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(0008), &mode);
+ if (ret)
+ return 0;
+
+ if (mode & LCPLL_LCVCO_MODE_EN_MASK) {
+ ret = regmap_read(hdptx->regmap, CMN_REG(0020), &val);
+ if (ret)
+ return 0;
+ lcpll_hw.pms_mdiv = val;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(0023), &val);
+ if (ret)
+ return 0;
+ lcpll_hw.pms_sdiv = val & 0xf;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(002B), &val);
+ if (ret)
+ return 0;
+ lcpll_hw.sdm_num_sign = val;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(002C), &val);
+ if (ret)
+ return 0;
+ lcpll_hw.sdm_num = val;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(002A), &val);
+ if (ret)
+ return 0;
+ lcpll_hw.sdm_deno = val;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(002D), &val);
+ if (ret)
+ return 0;
+ lcpll_hw.sdc_n = (val & LCPLL_SDC_N_MASK) >> 1;
+
+ for (i = 0; i < ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg); i++) {
+ const struct lcpll_config *cfg = &rk_hdptx_frl_lcpll_cfg[i];
+
+ if (cfg->pms_mdiv == lcpll_hw.pms_mdiv &&
+ cfg->pms_sdiv == lcpll_hw.pms_sdiv &&
+ cfg->sdm_num_sign == lcpll_hw.sdm_num_sign &&
+ cfg->sdm_num == lcpll_hw.sdm_num &&
+ cfg->sdm_deno == lcpll_hw.sdm_deno &&
+ cfg->sdc_n == lcpll_hw.sdc_n)
+ return cfg->rate;
+ }
+
+ dev_dbg(hdptx->dev, "%s no FRL match found\n", __func__);
+ return 0;
+ }
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(0051), &val);
+ if (ret)
+ return 0;
+ ropll_hw.pms_mdiv = val;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(005E), &val);
+ if (ret)
+ return 0;
+ ropll_hw.sdm_en = val & ROPLL_SDM_EN_MASK;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(0064), &val);
+ if (ret)
+ return 0;
+ ropll_hw.sdm_num_sign = val & ROPLL_SDM_NUM_SIGN_RBR_MASK;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(0065), &val);
+ if (ret)
+ return 0;
+ ropll_hw.sdm_num = val;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(0060), &val);
+ if (ret)
+ return 0;
+ ropll_hw.sdm_deno = val;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(0069), &val);
+ if (ret)
+ return 0;
+ ropll_hw.sdc_n = (val & ROPLL_SDC_N_RBR_MASK) + 3;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(006c), &val);
+ if (ret)
+ return 0;
+ ropll_hw.sdc_num = val;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(0070), &val);
+ if (ret)
+ return 0;
+ ropll_hw.sdc_deno = val;
+
+ ret = regmap_read(hdptx->regmap, CMN_REG(0086), &val);
+ if (ret)
+ return 0;
+ ropll_hw.pms_sdiv = ((val & PLL_PCG_POSTDIV_SEL_MASK) >> 4) + 1;
+
+ fout = PLL_REF_CLK * ropll_hw.pms_mdiv;
+ if (ropll_hw.sdm_en) {
+ sdm = div_u64(PLL_REF_CLK * ropll_hw.sdc_deno *
+ ropll_hw.pms_mdiv * ropll_hw.sdm_num,
+ 16 * ropll_hw.sdm_deno *
+ (ropll_hw.sdc_deno * ropll_hw.sdc_n - ropll_hw.sdc_num));
+
+ if (ropll_hw.sdm_num_sign)
+ fout = fout - sdm;
+ else
+ fout = fout + sdm;
+ }
+
+ return div_u64(fout * 2, ropll_hw.pms_sdiv * 10);
+}
+
static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
+ u32 status;
+ u64 rate;
+ int ret;
+
+ ret = regmap_read(hdptx->grf, GRF_HDPTX_CON0, &status);
+ if (ret || !(status & HDPTX_I_PLL_EN))
+ return 0;
- return hdptx->hw_rate;
+ rate = rk_hdptx_phy_clk_calc_rate_from_pll_cfg(hdptx);
+
+ if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
+ return rate;
+
+ return DIV_ROUND_CLOSEST_ULL(rate * 8, hdptx->hdmi_cfg.bpc);
}
-static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int rk_hdptx_phy_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
+ if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
+ return hdptx->hdmi_cfg.rate;
+
/*
* FIXME: Temporarily allow altering TMDS char rate via CCF.
* To be dropped as soon as the RK DW HDMI QP bridge driver
* switches to make use of phy_configure().
*/
- if (!hdptx->restrict_rate_change && rate != hdptx->hdmi_cfg.tmds_char_rate) {
+ if (!hdptx->restrict_rate_change && req->rate != hdptx->hdmi_cfg.rate) {
struct phy_configure_opts_hdmi hdmi = {
- .tmds_char_rate = rate,
+ .tmds_char_rate = req->rate,
};
- int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi);
+
+ int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi, &hdptx->hdmi_cfg);
if (ret)
return ret;
-
- hdptx->hdmi_cfg = hdmi;
}
/*
@@ -1897,37 +2332,42 @@ static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
* hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with
* a different rate argument.
*/
- return DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.tmds_char_rate * 8, hdptx->hdmi_cfg.bpc);
+ req->rate = DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.rate * 8, hdptx->hdmi_cfg.bpc);
+
+ return 0;
}
static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
- unsigned long long tmds_rate = DIV_ROUND_CLOSEST_ULL(rate * hdptx->hdmi_cfg.bpc, 8);
+ unsigned long long link_rate = rate;
+
+ if (hdptx->hdmi_cfg.mode != PHY_HDMI_MODE_FRL)
+ link_rate = DIV_ROUND_CLOSEST_ULL(rate * hdptx->hdmi_cfg.bpc, 8);
- /* Revert any unlikely TMDS char rate change since round_rate() */
- if (hdptx->hdmi_cfg.tmds_char_rate != tmds_rate) {
+ /* Revert any unlikely link rate change since determine_rate() */
+ if (hdptx->hdmi_cfg.rate != link_rate) {
dev_warn(hdptx->dev, "Reverting unexpected rate change from %llu to %llu\n",
- tmds_rate, hdptx->hdmi_cfg.tmds_char_rate);
- hdptx->hdmi_cfg.tmds_char_rate = tmds_rate;
+ link_rate, hdptx->hdmi_cfg.rate);
+ hdptx->hdmi_cfg.rate = link_rate;
}
/*
- * The TMDS char rate would be normally programmed in HW during
+ * The link rate would be normally programmed in HW during
* phy_ops.power_on() or clk_ops.prepare() callbacks, but it might
* happen that the former gets fired too late, i.e. after this call,
* while the latter being executed only once, i.e. when clock remains
* in the prepared state during rate changes.
*/
- return rk_hdptx_ropll_tmds_cmn_config(hdptx);
+ return rk_hdptx_pll_cmn_config(hdptx);
}
static const struct clk_ops hdptx_phy_clk_ops = {
.prepare = rk_hdptx_phy_clk_prepare,
.unprepare = rk_hdptx_phy_clk_unprepare,
.recalc_rate = rk_hdptx_phy_clk_recalc_rate,
- .round_rate = rk_hdptx_phy_clk_round_rate,
+ .determine_rate = rk_hdptx_phy_clk_determine_rate,
.set_rate = rk_hdptx_phy_clk_set_rate,
};
diff --git a/drivers/phy/rockchip/phy-rockchip-usb.c b/drivers/phy/rockchip/phy-rockchip-usb.c
index c3c30df29c3e..cef96739cf3f 100644
--- a/drivers/phy/rockchip/phy-rockchip-usb.c
+++ b/drivers/phy/rockchip/phy-rockchip-usb.c
@@ -446,7 +446,6 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct rockchip_usb_phy_base *phy_base;
struct phy_provider *phy_provider;
- struct device_node *child;
int err;
phy_base = devm_kzalloc(dev, sizeof(*phy_base), GFP_KERNEL);
@@ -472,12 +471,10 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy_base->reg_base);
}
- for_each_available_child_of_node(dev->of_node, child) {
+ for_each_available_child_of_node_scoped(dev->of_node, child) {
err = rockchip_usb_phy_init(phy_base, child);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
}
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c
index 1c8bf80119f1..5a181cb4597e 100644
--- a/drivers/phy/samsung/phy-exynos5-usbdrd.c
+++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c
@@ -41,6 +41,13 @@
#define EXYNOS2200_CLKRST_LINK_PCLK_SEL BIT(1)
#define EXYNOS2200_DRD_UTMI 0x10
+
+/* ExynosAutov920 bits */
+#define UTMICTL_FORCE_UTMI_SUSPEND BIT(13)
+#define UTMICTL_FORCE_UTMI_SLEEP BIT(12)
+#define UTMICTL_FORCE_DPPULLDOWN BIT(9)
+#define UTMICTL_FORCE_DMPULLDOWN BIT(8)
+
#define EXYNOS2200_UTMI_FORCE_VBUSVALID BIT(1)
#define EXYNOS2200_UTMI_FORCE_BVALID BIT(0)
@@ -250,6 +257,52 @@
#define EXYNOS850_DRD_HSP_TEST 0x5c
#define HSP_TEST_SIDDQ BIT(24)
+#define EXYNOSAUTOV920_DRD_HSP_CLKRST 0x100
+#define HSPCLKRST_PHY20_SW_PORTRESET BIT(3)
+#define HSPCLKRST_PHY20_SW_POR BIT(1)
+#define HSPCLKRST_PHY20_SW_POR_SEL BIT(0)
+
+#define EXYNOSAUTOV920_DRD_HSPCTL 0x104
+#define HSPCTRL_VBUSVLDEXTSEL BIT(13)
+#define HSPCTRL_VBUSVLDEXT BIT(12)
+#define HSPCTRL_EN_UTMISUSPEND BIT(9)
+#define HSPCTRL_COMMONONN BIT(8)
+
+#define EXYNOSAUTOV920_DRD_HSP_TEST 0x10c
+
+#define EXYNOSAUTOV920_DRD_HSPPLLTUNE 0x110
+#define HSPPLLTUNE_FSEL GENMASK(18, 16)
+
+/* ExynosAutov920 phy usb31drd port reg */
+#define EXYNOSAUTOV920_USB31DRD_PHY_RST_CTRL 0x000
+#define PHY_RST_CTRL_PIPE_LANE0_RESET_N_OVRD_EN BIT(5)
+#define PHY_RST_CTRL_PIPE_LANE0_RESET_N BIT(4)
+#define PHY_RST_CTRL_PHY_RESET_OVRD_EN BIT(1)
+#define PHY_RST_CTRL_PHY_RESET BIT(0)
+
+#define EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0 0x0004
+#define PHY_CR_PARA_CON0_PHY0_CR_PARA_ADDR GENMASK(31, 16)
+#define PHY_CR_PARA_CON0_PHY0_CR_PARA_CLK BIT(8)
+#define PHY_CR_PARA_CON0_PHY0_CR_PARA_ACK BIT(4)
+#define PHY_CR_PARA_CON0_PHY0_CR_PARA_SEL BIT(0)
+
+#define EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON1 0x0008
+
+#define EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON2 0x000c
+#define PHY_CR_PARA_CON2_PHY0_CR_PARA_WR_EN BIT(0)
+#define PHY_CR_PARA_CON2_PHY0_CR_PARA_WR_DATA GENMASK(31, 16)
+
+#define EXYNOSAUTOV920_USB31DRD_PHY_CONFIG0 0x100
+#define PHY_CONFIG0_PHY0_PMA_PWR_STABLE BIT(14)
+#define PHY_CONFIG0_PHY0_PCS_PWR_STABLE BIT(13)
+#define PHY_CONFIG0_PHY0_ANA_PWR_EN BIT(1)
+
+#define EXYNOSAUTOV920_USB31DRD_PHY_CONFIG7 0x11c
+#define PHY_CONFIG7_PHY_TEST_POWERDOWN BIT(24)
+
+#define EXYNOSAUTOV920_USB31DRD_PHY_CONFIG4 0x110
+#define PHY_CONFIG4_PIPE_RX0_SRIS_MODE_EN BIT(2)
+
/* Exynos9 - GS101 */
#define EXYNOS850_DRD_SECPMACTL 0x48
#define SECPMACTL_PMA_ROPLL_REF_CLK_SEL GENMASK(13, 12)
@@ -2054,6 +2107,595 @@ static const struct exynos5_usbdrd_phy_drvdata exynos990_usbdrd_phy = {
.n_regulators = ARRAY_SIZE(exynos5_regulator_names),
};
+static void
+exynosautov920_usb31drd_cr_clk(struct exynos5_usbdrd_phy *phy_drd, bool high)
+{
+ void __iomem *reg_phy = phy_drd->reg_phy;
+ u32 reg;
+
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0);
+ if (high)
+ reg |= PHY_CR_PARA_CON0_PHY0_CR_PARA_CLK;
+ else
+ reg &= ~PHY_CR_PARA_CON0_PHY0_CR_PARA_CLK;
+
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0);
+ fsleep(1);
+}
+
+static void
+exynosautov920_usb31drd_port_phy_ready(struct exynos5_usbdrd_phy *phy_drd)
+{
+ struct device *dev = phy_drd->dev;
+ void __iomem *reg_phy = phy_drd->reg_phy;
+ static const unsigned int timeout_us = 20000;
+ static const unsigned int sleep_us = 40;
+ u32 reg;
+ int err;
+
+ /* Clear cr_para_con */
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0);
+ reg &= ~(PHY_CR_PARA_CON0_PHY0_CR_PARA_CLK |
+ PHY_CR_PARA_CON0_PHY0_CR_PARA_ADDR);
+ reg |= PHY_CR_PARA_CON0_PHY0_CR_PARA_SEL;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0);
+ writel(0x0, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON1);
+ writel(0x0, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON2);
+
+ exynosautov920_usb31drd_cr_clk(phy_drd, true);
+ exynosautov920_usb31drd_cr_clk(phy_drd, false);
+
+ /*
+ * The maximum time from phy reset de-assertion to de-assertion of
+ * tx/rx_ack can be as high as 5ms in fast simulation mode.
+ * Time to phy ready is < 20ms
+ */
+ err = readl_poll_timeout(reg_phy +
+ EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0,
+ reg, !(reg & PHY_CR_PARA_CON0_PHY0_CR_PARA_ACK),
+ sleep_us, timeout_us);
+ if (err)
+ dev_err(dev, "timed out waiting for rx/tx_ack: %#.8x\n", reg);
+
+ reg &= ~PHY_CR_PARA_CON0_PHY0_CR_PARA_CLK;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0);
+}
+
+static void
+exynosautov920_usb31drd_cr_write(struct exynos5_usbdrd_phy *phy_drd,
+ u16 addr, u16 data)
+{
+ void __iomem *reg_phy = phy_drd->reg_phy;
+ u32 cnt = 0;
+ u32 reg;
+
+ /* Pre Clocking */
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0);
+ reg |= PHY_CR_PARA_CON0_PHY0_CR_PARA_SEL;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0);
+
+ /*
+ * tx clks must be available prior to assertion of tx req.
+ * tx pstate p2 to p0 transition directly is not permitted.
+ * tx clk ready must be asserted synchronously on tx clk prior
+ * to internal transmit clk alignment sequence in the phy
+ * when entering from p2 to p1 to p0.
+ */
+ do {
+ exynosautov920_usb31drd_cr_clk(phy_drd, true);
+ exynosautov920_usb31drd_cr_clk(phy_drd, false);
+ cnt++;
+ } while (cnt < 15);
+
+ reg &= ~PHY_CR_PARA_CON0_PHY0_CR_PARA_SEL;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0);
+
+ /*
+ * tx data path is active when tx lane is in p0 state
+ * and tx data en asserted. enable cr_para_wr_en.
+ */
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON2);
+ reg &= ~PHY_CR_PARA_CON2_PHY0_CR_PARA_WR_DATA;
+ reg |= FIELD_PREP(PHY_CR_PARA_CON2_PHY0_CR_PARA_WR_DATA, data) |
+ PHY_CR_PARA_CON2_PHY0_CR_PARA_WR_EN;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON2);
+
+ /* write addr */
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0);
+ reg &= ~PHY_CR_PARA_CON0_PHY0_CR_PARA_ADDR;
+ reg |= FIELD_PREP(PHY_CR_PARA_CON0_PHY0_CR_PARA_ADDR, addr) |
+ PHY_CR_PARA_CON0_PHY0_CR_PARA_CLK |
+ PHY_CR_PARA_CON0_PHY0_CR_PARA_SEL;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0);
+
+ /* check cr_para_ack*/
+ cnt = 0;
+ do {
+ /*
+ * data symbols are captured by phy on rising edge of the
+ * tx_clk when tx data enabled.
+ * completion of the write cycle is acknowledged by assertion
+ * of the cr_para_ack.
+ */
+ exynosautov920_usb31drd_cr_clk(phy_drd, true);
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CR_PARA_CON0);
+ if ((reg & PHY_CR_PARA_CON0_PHY0_CR_PARA_ACK))
+ break;
+
+ exynosautov920_usb31drd_cr_clk(phy_drd, false);
+
+ /*
+ * wait for minimum of 10 cr_para_clk cycles after phy reset
+ * is negated, before accessing control regs to allow for
+ * internal resets.
+ */
+ cnt++;
+ } while (cnt < 10);
+
+ if (cnt < 10)
+ exynosautov920_usb31drd_cr_clk(phy_drd, false);
+}
+
+static void
+exynosautov920_usb31drd_phy_reset(struct exynos5_usbdrd_phy *phy_drd, int val)
+{
+ void __iomem *reg_phy = phy_drd->reg_phy;
+ u32 reg;
+
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_RST_CTRL);
+ reg &= ~PHY_RST_CTRL_PHY_RESET_OVRD_EN;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_RST_CTRL);
+
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_RST_CTRL);
+ if (val)
+ reg |= PHY_RST_CTRL_PHY_RESET;
+ else
+ reg &= ~PHY_RST_CTRL_PHY_RESET;
+
+ reg |= PHY_RST_CTRL_PHY_RESET_OVRD_EN;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_RST_CTRL);
+}
+
+static void
+exynosautov920_usb31drd_lane0_reset(struct exynos5_usbdrd_phy *phy_drd, int val)
+{
+ void __iomem *reg_phy = phy_drd->reg_phy;
+ u32 reg;
+
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_RST_CTRL);
+ reg |= PHY_RST_CTRL_PIPE_LANE0_RESET_N_OVRD_EN;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_RST_CTRL);
+
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_RST_CTRL);
+ if (val)
+ reg &= ~PHY_RST_CTRL_PIPE_LANE0_RESET_N;
+ else
+ reg |= PHY_RST_CTRL_PIPE_LANE0_RESET_N;
+
+ reg &= ~PHY_RST_CTRL_PIPE_LANE0_RESET_N_OVRD_EN;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_RST_CTRL);
+}
+
+static void
+exynosautov920_usb31drd_pipe3_init(struct exynos5_usbdrd_phy *phy_drd)
+{
+ void __iomem *reg_phy = phy_drd->reg_phy;
+ u32 reg;
+
+ /*
+ * Phy and Pipe Lane reset assert.
+ * assert reset (phy_reset = 1).
+ * The lane-ack outputs are asserted during reset (tx_ack = rx_ack = 1)
+ */
+ exynosautov920_usb31drd_phy_reset(phy_drd, 1);
+ exynosautov920_usb31drd_lane0_reset(phy_drd, 1);
+
+ /*
+ * ANA Power En, PCS & PMA PWR Stable Set
+ * ramp-up power suppiles
+ */
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CONFIG0);
+ reg |= PHY_CONFIG0_PHY0_ANA_PWR_EN | PHY_CONFIG0_PHY0_PCS_PWR_STABLE |
+ PHY_CONFIG0_PHY0_PMA_PWR_STABLE;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CONFIG0);
+
+ fsleep(10);
+
+ /*
+ * phy is not functional in test_powerdown mode, test_powerdown to be
+ * de-asserted for normal operation
+ */
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CONFIG7);
+ reg &= ~PHY_CONFIG7_PHY_TEST_POWERDOWN;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CONFIG7);
+
+ /*
+ * phy reset signal be asserted for minimum 10us after power
+ * supplies are ramped-up
+ */
+ fsleep(10);
+
+ /*
+ * Phy and Pipe Lane reset assert de-assert
+ */
+ exynosautov920_usb31drd_phy_reset(phy_drd, 0);
+ exynosautov920_usb31drd_lane0_reset(phy_drd, 0);
+
+ /* Pipe_rx0_sris_mode_en = 1 */
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CONFIG4);
+ reg |= PHY_CONFIG4_PIPE_RX0_SRIS_MODE_EN;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CONFIG4);
+
+ /*
+ * wait for lane ack outputs to de-assert (tx_ack = rx_ack = 0)
+ * Exit from the reset state is indicated by de-assertion of *_ack
+ */
+ exynosautov920_usb31drd_port_phy_ready(phy_drd);
+
+ /* override values for level settings */
+ exynosautov920_usb31drd_cr_write(phy_drd, 0x22, 0x00F5);
+}
+
+static void
+exynosautov920_usb31drd_ssphy_disable(struct exynos5_usbdrd_phy *phy_drd)
+{
+ void __iomem *reg_phy = phy_drd->reg_phy;
+ u32 reg;
+
+ /* 1. Assert reset (phy_reset = 1) */
+ exynosautov920_usb31drd_lane0_reset(phy_drd, 1);
+ exynosautov920_usb31drd_phy_reset(phy_drd, 1);
+
+ /* phy test power down */
+ reg = readl(reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CONFIG7);
+ reg |= PHY_CONFIG7_PHY_TEST_POWERDOWN;
+ writel(reg, reg_phy + EXYNOSAUTOV920_USB31DRD_PHY_CONFIG7);
+}
+
+static void
+exynosautov920_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
+{
+ void __iomem *reg_phy = phy_drd->reg_phy;
+ u32 reg;
+
+ /*
+ * Disable HWACG (hardware auto clock gating control). This
+ * forces QACTIVE signal in Q-Channel interface to HIGH level,
+ * to make sure the PHY clock is not gated by the hardware.
+ */
+ reg = readl(reg_phy + EXYNOS850_DRD_LINKCTRL);
+ reg |= LINKCTRL_FORCE_QACT;
+ writel(reg, reg_phy + EXYNOS850_DRD_LINKCTRL);
+
+ /* De-assert link reset */
+ reg = readl(reg_phy + EXYNOS2200_DRD_CLKRST);
+ reg &= ~CLKRST_LINK_SW_RST;
+ writel(reg, reg_phy + EXYNOS2200_DRD_CLKRST);
+
+ /* Set PHY POR High */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSP_CLKRST);
+ reg |= HSPCLKRST_PHY20_SW_POR | HSPCLKRST_PHY20_SW_POR_SEL;
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSP_CLKRST);
+
+ /* Enable UTMI+ */
+ reg = readl(reg_phy + EXYNOS2200_DRD_UTMI);
+ reg &= ~(UTMICTL_FORCE_UTMI_SUSPEND | UTMICTL_FORCE_UTMI_SLEEP |
+ UTMICTL_FORCE_DPPULLDOWN | UTMICTL_FORCE_DMPULLDOWN);
+ writel(reg, reg_phy + EXYNOS2200_DRD_UTMI);
+
+ /* set phy clock & control HS phy */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSPCTL);
+ reg |= HSPCTRL_EN_UTMISUSPEND | HSPCTRL_COMMONONN;
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSPCTL);
+
+ fsleep(100);
+
+ /* Set VBUS Valid and DP-Pull up control by VBUS pad usage */
+ reg = readl(reg_phy + EXYNOS850_DRD_LINKCTRL);
+ reg |= FIELD_PREP_CONST(LINKCTRL_BUS_FILTER_BYPASS, 0xf);
+ writel(reg, reg_phy + EXYNOS850_DRD_LINKCTRL);
+
+ reg = readl(reg_phy + EXYNOS2200_DRD_UTMI);
+ reg |= EXYNOS2200_UTMI_FORCE_VBUSVALID | EXYNOS2200_UTMI_FORCE_BVALID;
+ writel(reg, reg_phy + EXYNOS2200_DRD_UTMI);
+
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSPCTL);
+ reg |= HSPCTRL_VBUSVLDEXTSEL | HSPCTRL_VBUSVLDEXT;
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSPCTL);
+
+ /* Setting FSEL for refference clock */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSPPLLTUNE);
+ reg &= ~HSPPLLTUNE_FSEL;
+
+ switch (phy_drd->extrefclk) {
+ case EXYNOS5_FSEL_50MHZ:
+ reg |= FIELD_PREP(HSPPLLTUNE_FSEL, 7);
+ break;
+ case EXYNOS5_FSEL_26MHZ:
+ reg |= FIELD_PREP(HSPPLLTUNE_FSEL, 6);
+ break;
+ case EXYNOS5_FSEL_24MHZ:
+ reg |= FIELD_PREP(HSPPLLTUNE_FSEL, 2);
+ break;
+ case EXYNOS5_FSEL_20MHZ:
+ reg |= FIELD_PREP(HSPPLLTUNE_FSEL, 1);
+ break;
+ case EXYNOS5_FSEL_19MHZ2:
+ reg |= FIELD_PREP(HSPPLLTUNE_FSEL, 0);
+ break;
+ default:
+ dev_warn(phy_drd->dev, "unsupported ref clk: %#.2x\n",
+ phy_drd->extrefclk);
+ break;
+ }
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSPPLLTUNE);
+
+ /* Enable PHY Power Mode */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSP_TEST);
+ reg &= ~HSP_TEST_SIDDQ;
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSP_TEST);
+
+ /* before POR low, 10us delay is needed to Finish PHY reset */
+ fsleep(10);
+
+ /* Set PHY POR Low */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSP_CLKRST);
+ reg |= HSPCLKRST_PHY20_SW_POR_SEL;
+ reg &= ~(HSPCLKRST_PHY20_SW_POR | HSPCLKRST_PHY20_SW_PORTRESET);
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSP_CLKRST);
+
+ /* after POR low and delay 75us, PHYCLOCK is guaranteed. */
+ fsleep(75);
+
+ /* Disable forcing pipe interface */
+ reg = readl(reg_phy + EXYNOS850_DRD_LINKCTRL);
+ reg &= ~LINKCTRL_FORCE_PIPE_EN;
+ writel(reg, reg_phy + EXYNOS850_DRD_LINKCTRL);
+
+ /* Pclk to pipe_clk */
+ reg = readl(reg_phy + EXYNOS2200_DRD_CLKRST);
+ reg |= EXYNOS2200_CLKRST_LINK_PCLK_SEL;
+ writel(reg, reg_phy + EXYNOS2200_DRD_CLKRST);
+}
+
+static void
+exynosautov920_usbdrd_hsphy_disable(struct exynos5_usbdrd_phy *phy_drd)
+{
+ u32 reg;
+ void __iomem *reg_phy = phy_drd->reg_phy;
+
+ /* set phy clock & control HS phy */
+ reg = readl(reg_phy + EXYNOS2200_DRD_UTMI);
+ reg |= UTMICTL_FORCE_UTMI_SUSPEND | UTMICTL_FORCE_UTMI_SLEEP;
+ reg &= ~(UTMICTL_FORCE_DPPULLDOWN | UTMICTL_FORCE_DMPULLDOWN);
+ writel(reg, reg_phy + EXYNOS2200_DRD_UTMI);
+
+ /* Disable PHY Power Mode */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSP_TEST);
+ reg |= HSP_TEST_SIDDQ;
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSP_TEST);
+
+ /* clear force q-channel */
+ reg = readl(reg_phy + EXYNOS850_DRD_LINKCTRL);
+ reg &= ~LINKCTRL_FORCE_QACT;
+ writel(reg, reg_phy + EXYNOS850_DRD_LINKCTRL);
+
+ /* link sw reset is need for USB_DP/DM high-z in host mode */
+ reg = readl(reg_phy + EXYNOS2200_DRD_CLKRST);
+ reg |= CLKRST_LINK_SW_RST;
+ writel(reg, reg_phy + EXYNOS2200_DRD_CLKRST);
+ fsleep(10);
+ reg &= ~CLKRST_LINK_SW_RST;
+ writel(reg, reg_phy + EXYNOS2200_DRD_CLKRST);
+}
+
+static int exynosautov920_usbdrd_phy_init(struct phy *phy)
+{
+ struct phy_usb_instance *inst = phy_get_drvdata(phy);
+ struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+ int ret;
+
+ ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
+ if (ret)
+ return ret;
+
+ /* Bypass PHY isol */
+ inst->phy_cfg->phy_isol(inst, false);
+
+ /* UTMI or PIPE3 specific init */
+ inst->phy_cfg->phy_init(phy_drd);
+
+ clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
+
+ return 0;
+}
+
+static int exynosautov920_usbdrd_phy_exit(struct phy *phy)
+{
+ struct phy_usb_instance *inst = phy_get_drvdata(phy);
+ struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+ int ret;
+
+ ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
+ if (ret)
+ return ret;
+
+ exynos850_usbdrd_phy_exit(phy);
+
+ /* enable PHY isol */
+ inst->phy_cfg->phy_isol(inst, true);
+
+ clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
+
+ return 0;
+}
+
+static int exynosautov920_usbdrd_combo_phy_exit(struct phy *phy)
+{
+ struct phy_usb_instance *inst = phy_get_drvdata(phy);
+ struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+ int ret = 0;
+
+ ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
+ if (ret)
+ return ret;
+
+ if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI)
+ exynosautov920_usbdrd_hsphy_disable(phy_drd);
+ else if (inst->phy_cfg->id == EXYNOS5_DRDPHY_PIPE3)
+ exynosautov920_usb31drd_ssphy_disable(phy_drd);
+
+ /* enable PHY isol */
+ inst->phy_cfg->phy_isol(inst, true);
+
+ clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
+
+ return 0;
+}
+
+static int exynosautov920_usbdrd_phy_power_on(struct phy *phy)
+{
+ struct phy_usb_instance *inst = phy_get_drvdata(phy);
+ struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+ int ret;
+
+ dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n");
+
+ ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_core_clks,
+ phy_drd->core_clks);
+ if (ret)
+ return ret;
+
+ /* Enable supply */
+ ret = regulator_bulk_enable(phy_drd->drv_data->n_regulators,
+ phy_drd->regulators);
+ if (ret) {
+ dev_err(phy_drd->dev, "Failed to enable PHY regulator(s)\n");
+ goto fail_supply;
+ }
+
+ return 0;
+
+fail_supply:
+ clk_bulk_disable_unprepare(phy_drd->drv_data->n_core_clks,
+ phy_drd->core_clks);
+
+ return ret;
+}
+
+static int exynosautov920_usbdrd_phy_power_off(struct phy *phy)
+{
+ struct phy_usb_instance *inst = phy_get_drvdata(phy);
+ struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+ dev_dbg(phy_drd->dev, "Request to power_off usbdrd_phy phy\n");
+
+ /* Disable supply */
+ regulator_bulk_disable(phy_drd->drv_data->n_regulators,
+ phy_drd->regulators);
+
+ clk_bulk_disable_unprepare(phy_drd->drv_data->n_core_clks,
+ phy_drd->core_clks);
+
+ return 0;
+}
+
+static const char * const exynosautov920_usb30_regulators[] = {
+ "dvdd", "vdd18",
+};
+
+static const char * const exynosautov920_usb20_regulators[] = {
+ "dvdd", "vdd18", "vdd33",
+};
+
+static const struct
+exynos5_usbdrd_phy_config usb31drd_phy_cfg_exynosautov920[] = {
+ {
+ .id = EXYNOS5_DRDPHY_PIPE3,
+ .phy_isol = exynos5_usbdrd_phy_isol,
+ .phy_init = exynosautov920_usb31drd_pipe3_init,
+ },
+};
+
+static const struct phy_ops exynosautov920_usb31drd_combo_ssphy_ops = {
+ .init = exynosautov920_usbdrd_phy_init,
+ .exit = exynosautov920_usbdrd_combo_phy_exit,
+ .power_on = exynosautov920_usbdrd_phy_power_on,
+ .power_off = exynosautov920_usbdrd_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static const
+struct exynos5_usbdrd_phy_drvdata exynosautov920_usb31drd_combo_ssphy = {
+ .phy_cfg = usb31drd_phy_cfg_exynosautov920,
+ .phy_ops = &exynosautov920_usb31drd_combo_ssphy_ops,
+ .pmu_offset_usbdrd0_phy = EXYNOSAUTOV920_PHY_CTRL_USB31,
+ .clk_names = exynos5_clk_names,
+ .n_clks = ARRAY_SIZE(exynos5_clk_names),
+ .core_clk_names = exynos5_core_clk_names,
+ .n_core_clks = ARRAY_SIZE(exynos5_core_clk_names),
+ .regulator_names = exynosautov920_usb30_regulators,
+ .n_regulators = ARRAY_SIZE(exynosautov920_usb30_regulators),
+};
+
+static const struct phy_ops exynosautov920_usbdrd_combo_hsphy_ops = {
+ .init = exynosautov920_usbdrd_phy_init,
+ .exit = exynosautov920_usbdrd_combo_phy_exit,
+ .power_on = exynosautov920_usbdrd_phy_power_on,
+ .power_off = exynosautov920_usbdrd_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static const struct
+exynos5_usbdrd_phy_config usbdrd_hsphy_cfg_exynosautov920[] = {
+ {
+ .id = EXYNOS5_DRDPHY_UTMI,
+ .phy_isol = exynos5_usbdrd_phy_isol,
+ .phy_init = exynosautov920_usbdrd_utmi_init,
+ },
+};
+
+static const
+struct exynos5_usbdrd_phy_drvdata exynosautov920_usbdrd_combo_hsphy = {
+ .phy_cfg = usbdrd_hsphy_cfg_exynosautov920,
+ .phy_ops = &exynosautov920_usbdrd_combo_hsphy_ops,
+ .pmu_offset_usbdrd0_phy = EXYNOSAUTOV920_PHY_CTRL_USB20,
+ .clk_names = exynos5_clk_names,
+ .n_clks = ARRAY_SIZE(exynos5_clk_names),
+ .core_clk_names = exynos5_core_clk_names,
+ .n_core_clks = ARRAY_SIZE(exynos5_core_clk_names),
+ .regulator_names = exynosautov920_usb20_regulators,
+ .n_regulators = ARRAY_SIZE(exynosautov920_usb20_regulators),
+};
+
+static const struct phy_ops exynosautov920_usbdrd_phy_ops = {
+ .init = exynosautov920_usbdrd_phy_init,
+ .exit = exynosautov920_usbdrd_phy_exit,
+ .power_on = exynosautov920_usbdrd_phy_power_on,
+ .power_off = exynosautov920_usbdrd_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static const struct exynos5_usbdrd_phy_config phy_cfg_exynosautov920[] = {
+ {
+ .id = EXYNOS5_DRDPHY_UTMI,
+ .phy_isol = exynos5_usbdrd_phy_isol,
+ .phy_init = exynos850_usbdrd_utmi_init,
+ },
+};
+
+static const struct exynos5_usbdrd_phy_drvdata exynosautov920_usbdrd_phy = {
+ .phy_cfg = phy_cfg_exynosautov920,
+ .phy_ops = &exynosautov920_usbdrd_phy_ops,
+ .pmu_offset_usbdrd0_phy = EXYNOSAUTOV920_PHY_CTRL_USB20,
+ .clk_names = exynos5_clk_names,
+ .n_clks = ARRAY_SIZE(exynos5_clk_names),
+ .core_clk_names = exynos5_core_clk_names,
+ .n_core_clks = ARRAY_SIZE(exynos5_core_clk_names),
+ .regulator_names = exynosautov920_usb20_regulators,
+ .n_regulators = ARRAY_SIZE(exynosautov920_usb20_regulators),
+};
+
static const struct exynos5_usbdrd_phy_config phy_cfg_gs101[] = {
{
.id = EXYNOS5_DRDPHY_UTMI,
@@ -2260,6 +2902,15 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
}, {
.compatible = "samsung,exynos990-usbdrd-phy",
.data = &exynos990_usbdrd_phy
+ }, {
+ .compatible = "samsung,exynosautov920-usb31drd-combo-ssphy",
+ .data = &exynosautov920_usb31drd_combo_ssphy
+ }, {
+ .compatible = "samsung,exynosautov920-usbdrd-combo-hsphy",
+ .data = &exynosautov920_usbdrd_combo_hsphy
+ }, {
+ .compatible = "samsung,exynosautov920-usbdrd-phy",
+ .data = &exynosautov920_usbdrd_phy
},
{ },
};
diff --git a/drivers/phy/socionext/phy-uniphier-usb2.c b/drivers/phy/socionext/phy-uniphier-usb2.c
index 21c201717d95..c49d432e526b 100644
--- a/drivers/phy/socionext/phy-uniphier-usb2.c
+++ b/drivers/phy/socionext/phy-uniphier-usb2.c
@@ -106,7 +106,7 @@ static const struct phy_ops uniphier_u2phy_ops = {
static int uniphier_u2phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *parent, *child;
+ struct device_node *parent;
struct uniphier_u2phy_priv *priv = NULL, *next = NULL;
struct phy_provider *phy_provider;
struct regmap *regmap;
@@ -129,34 +129,31 @@ static int uniphier_u2phy_probe(struct platform_device *pdev)
return PTR_ERR(regmap);
}
- for_each_child_of_node(dev->of_node, child) {
+ for_each_child_of_node_scoped(dev->of_node, child) {
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- ret = -ENOMEM;
- goto out_put_child;
- }
+ if (!priv)
+ return -ENOMEM;
+
priv->regmap = regmap;
priv->vbus = devm_regulator_get_optional(dev, "vbus");
if (IS_ERR(priv->vbus)) {
- if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) {
- ret = PTR_ERR(priv->vbus);
- goto out_put_child;
- }
+ if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
+ return PTR_ERR(priv->vbus);
+
priv->vbus = NULL;
}
priv->phy = devm_phy_create(dev, child, &uniphier_u2phy_ops);
if (IS_ERR(priv->phy)) {
dev_err(dev, "Failed to create phy\n");
- ret = PTR_ERR(priv->phy);
- goto out_put_child;
+ return PTR_ERR(priv->phy);
}
ret = of_property_read_u32(child, "reg", &data_idx);
if (ret) {
dev_err(dev, "Failed to get reg property\n");
- goto out_put_child;
+ return ret;
}
if (data_idx < ndatas)
@@ -174,11 +171,6 @@ static int uniphier_u2phy_probe(struct platform_device *pdev)
phy_provider = devm_of_phy_provider_register(dev,
uniphier_u2phy_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
-
-out_put_child:
- of_node_put(child);
-
- return ret;
}
static const struct uniphier_u2phy_soc_data uniphier_pro4_data[] = {
diff --git a/drivers/phy/spacemit/Kconfig b/drivers/phy/spacemit/Kconfig
new file mode 100644
index 000000000000..0136aee2e8a2
--- /dev/null
+++ b/drivers/phy/spacemit/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Phy drivers for SpacemiT platforms
+#
+config PHY_SPACEMIT_K1_USB2
+ tristate "SpacemiT K1 USB 2.0 PHY support"
+ depends on (ARCH_SPACEMIT || COMPILE_TEST) && OF
+ depends on COMMON_CLK
+ depends on USB_COMMON
+ select GENERIC_PHY
+ help
+ Enable this to support K1 USB 2.0 PHY driver. This driver takes care of
+ enabling and clock setup and will be used by K1 udc/ehci/otg/xhci driver.
diff --git a/drivers/phy/spacemit/Makefile b/drivers/phy/spacemit/Makefile
new file mode 100644
index 000000000000..fec0b425a948
--- /dev/null
+++ b/drivers/phy/spacemit/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_PHY_SPACEMIT_K1_USB2) += phy-k1-usb2.o
diff --git a/drivers/phy/spacemit/phy-k1-usb2.c b/drivers/phy/spacemit/phy-k1-usb2.c
new file mode 100644
index 000000000000..342061380012
--- /dev/null
+++ b/drivers/phy/spacemit/phy-k1-usb2.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SpacemiT K1 USB 2.0 PHY driver
+ *
+ * Copyright (C) 2025 SpacemiT (Hangzhou) Technology Co. Ltd
+ * Copyright (C) 2025 Ze Huang <huang.ze@linux.dev>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/usb/of.h>
+
+#define PHY_RST_MODE_CTRL 0x04
+#define PHY_PLL_RDY BIT(0)
+#define PHY_CLK_CDR_EN BIT(1)
+#define PHY_CLK_PLL_EN BIT(2)
+#define PHY_CLK_MAC_EN BIT(3)
+#define PHY_MAC_RSTN BIT(5)
+#define PHY_CDR_RSTN BIT(6)
+#define PHY_PLL_RSTN BIT(7)
+/*
+ * hs line state sel (Bit 13):
+ * - 1 (Default): Internal HS line state is set to 01 when usb_hs_tx_en is valid.
+ * - 0: Internal HS line state is always driven by usb_hs_lstate.
+ *
+ * fs line state sel (Bit 14):
+ * - 1 (Default): FS line state is determined by the output data
+ * (usb_fs_datain/b).
+ * - 0: FS line state is always determined by the input data (dmo/dpo).
+ */
+#define PHY_HS_LINE_TX_MODE BIT(13)
+#define PHY_FS_LINE_TX_MODE BIT(14)
+
+#define PHY_INIT_MODE_BITS (PHY_FS_LINE_TX_MODE | PHY_HS_LINE_TX_MODE)
+#define PHY_CLK_ENABLE_BITS (PHY_CLK_PLL_EN | PHY_CLK_CDR_EN | \
+ PHY_CLK_MAC_EN)
+#define PHY_DEASSERT_RST_BITS (PHY_PLL_RSTN | PHY_CDR_RSTN | \
+ PHY_MAC_RSTN)
+
+#define PHY_TX_HOST_CTRL 0x10
+#define PHY_HST_DISC_AUTO_CLR BIT(2) /* autoclear hs host disc when re-connect */
+
+#define PHY_HSTXP_HW_CTRL 0x34
+#define PHY_HSTXP_RSTN BIT(2) /* generate reset for clock hstxp */
+#define PHY_CLK_HSTXP_EN BIT(3) /* clock hstxp enable */
+#define PHY_HSTXP_MODE BIT(4) /* 0: force en_txp to be 1; 1: no force */
+
+#define PHY_PLL_DIV_CFG 0x98
+#define PHY_FDIV_FRACT_8_15 GENMASK(7, 0)
+#define PHY_FDIV_FRACT_16_19 GENMASK(11, 8)
+#define PHY_FDIV_FRACT_20_21 BIT(12) /* fdiv_reg<21>, <20>, bit21 == bit20 */
+/*
+ * freq_sel<1:0>
+ * if ref clk freq=24.0MHz-->freq_sel<2:0> == 3b'001, then internal divider value == 80
+ */
+#define PHY_FDIV_FRACT_0_1 GENMASK(14, 13)
+/*
+ * pll divider value selection
+ * 1: divider value will choose internal default value ,dependent on freq_sel<1:0>
+ * 0: divider value will be over ride by fdiv_reg<21:0>
+ */
+#define PHY_DIV_LOCAL_EN BIT(15)
+
+#define PHY_SEL_FREQ_24MHZ 0x01
+#define FDIV_REG_MASK (PHY_FDIV_FRACT_20_21 | PHY_FDIV_FRACT_16_19 | \
+ PHY_FDIV_FRACT_8_15)
+#define FDIV_REG_VAL 0x1ec4 /* 0x100 selects 24MHz, rest are default */
+
+#define K1_USB2PHY_RESET_TIME_MS 50
+
+struct spacemit_usb2phy {
+ struct phy *phy;
+ struct clk *clk;
+ struct regmap *regmap_base;
+};
+
+static const struct regmap_config phy_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x200,
+};
+
+static int spacemit_usb2phy_init(struct phy *phy)
+{
+ struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);
+ struct regmap *map = sphy->regmap_base;
+ u32 val;
+ int ret;
+
+ ret = clk_enable(sphy->clk);
+ if (ret) {
+ dev_err(&phy->dev, "failed to enable clock\n");
+ clk_disable(sphy->clk);
+ return ret;
+ }
+
+ /*
+ * make sure the usb controller is not under reset process before
+ * any configuration
+ */
+ usleep_range(150, 200);
+
+ /* 24M ref clk */
+ val = FIELD_PREP(FDIV_REG_MASK, FDIV_REG_VAL) |
+ FIELD_PREP(PHY_FDIV_FRACT_0_1, PHY_SEL_FREQ_24MHZ) |
+ PHY_DIV_LOCAL_EN;
+ regmap_write(map, PHY_PLL_DIV_CFG, val);
+
+ ret = regmap_read_poll_timeout(map, PHY_RST_MODE_CTRL, val,
+ (val & PHY_PLL_RDY),
+ 500, K1_USB2PHY_RESET_TIME_MS * 1000);
+ if (ret) {
+ dev_err(&phy->dev, "wait PLLREADY timeout\n");
+ clk_disable(sphy->clk);
+ return ret;
+ }
+
+ /* release usb2 phy internal reset and enable clock gating */
+ val = (PHY_INIT_MODE_BITS | PHY_CLK_ENABLE_BITS | PHY_DEASSERT_RST_BITS);
+ regmap_write(map, PHY_RST_MODE_CTRL, val);
+
+ val = (PHY_HSTXP_RSTN | PHY_CLK_HSTXP_EN | PHY_HSTXP_MODE);
+ regmap_write(map, PHY_HSTXP_HW_CTRL, val);
+
+ /* auto clear host disc */
+ regmap_update_bits(map, PHY_TX_HOST_CTRL, PHY_HST_DISC_AUTO_CLR,
+ PHY_HST_DISC_AUTO_CLR);
+
+ return 0;
+}
+
+static int spacemit_usb2phy_exit(struct phy *phy)
+{
+ struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);
+
+ clk_disable(sphy->clk);
+
+ return 0;
+}
+
+static const struct phy_ops spacemit_usb2phy_ops = {
+ .init = spacemit_usb2phy_init,
+ .exit = spacemit_usb2phy_exit,
+ .owner = THIS_MODULE,
+};
+
+static int spacemit_usb2phy_probe(struct platform_device *pdev)
+{
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct spacemit_usb2phy *sphy;
+ void __iomem *base;
+
+ sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+ if (!sphy)
+ return -ENOMEM;
+
+ sphy->clk = devm_clk_get_prepared(&pdev->dev, NULL);
+ if (IS_ERR(sphy->clk))
+ return dev_err_probe(dev, PTR_ERR(sphy->clk), "Failed to get clock\n");
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ sphy->regmap_base = devm_regmap_init_mmio(dev, base, &phy_regmap_config);
+ if (IS_ERR(sphy->regmap_base))
+ return dev_err_probe(dev, PTR_ERR(sphy->regmap_base), "Failed to init regmap\n");
+
+ sphy->phy = devm_phy_create(dev, NULL, &spacemit_usb2phy_ops);
+ if (IS_ERR(sphy->phy))
+ return dev_err_probe(dev, PTR_ERR(sphy->phy), "Failed to create phy\n");
+
+ phy_set_drvdata(sphy->phy, sphy);
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id spacemit_usb2phy_dt_match[] = {
+ { .compatible = "spacemit,k1-usb2-phy", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, spacemit_usb2phy_dt_match);
+
+static struct platform_driver spacemit_usb2_phy_driver = {
+ .probe = spacemit_usb2phy_probe,
+ .driver = {
+ .name = "spacemit-usb2-phy",
+ .of_match_table = spacemit_usb2phy_dt_match,
+ },
+};
+module_platform_driver(spacemit_usb2_phy_driver);
+
+MODULE_DESCRIPTION("Spacemit USB 2.0 PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h
index d2b5f9565132..cd277d0ed9e1 100644
--- a/drivers/phy/tegra/xusb.h
+++ b/drivers/phy/tegra/xusb.h
@@ -69,7 +69,6 @@ struct tegra_xusb_usb2_lane {
struct tegra_xusb_lane base;
u32 hs_curr_level_offset;
- bool powered_on;
};
static inline struct tegra_xusb_usb2_lane *
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index a8b440c6c46b..6e9ecb88dc8b 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -393,6 +393,7 @@ struct wiz {
struct clk *output_clks[WIZ_MAX_OUTPUT_CLOCKS];
struct clk_onecell_data clk_data;
const struct wiz_data *data;
+ int mux_sel_status[WIZ_MUX_NUM_CLOCKS];
};
static int wiz_reset(struct wiz *wiz)
@@ -934,12 +935,12 @@ static unsigned long wiz_clk_div_recalc_rate(struct clk_hw *hw,
return divider_recalc_rate(hw, parent_rate, val, div->table, 0x0, 2);
}
-static long wiz_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int wiz_clk_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct wiz_clk_divider *div = to_wiz_clk_div(hw);
- return divider_round_rate(hw, rate, prate, div->table, 2, 0x0);
+ return divider_determine_rate(hw, req, div->table, 2, 0x0);
}
static int wiz_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -958,7 +959,7 @@ static int wiz_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops wiz_clk_div_ops = {
.recalc_rate = wiz_clk_div_recalc_rate,
- .round_rate = wiz_clk_div_round_rate,
+ .determine_rate = wiz_clk_div_determine_rate,
.set_rate = wiz_clk_div_set_rate,
};
@@ -1654,11 +1655,25 @@ static void wiz_remove(struct platform_device *pdev)
pm_runtime_disable(dev);
}
+static int wiz_suspend_noirq(struct device *dev)
+{
+ struct wiz *wiz = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++)
+ regmap_field_read(wiz->mux_sel_field[i], &wiz->mux_sel_status[i]);
+
+ return 0;
+}
+
static int wiz_resume_noirq(struct device *dev)
{
struct device_node *node = dev->of_node;
struct wiz *wiz = dev_get_drvdata(dev);
- int ret;
+ int ret, i;
+
+ for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++)
+ regmap_field_write(wiz->mux_sel_field[i], wiz->mux_sel_status[i]);
/* Enable supplemental Control override if available */
if (wiz->sup_legacy_clk_override)
@@ -1680,7 +1695,7 @@ err_wiz_init:
return ret;
}
-static DEFINE_NOIRQ_DEV_PM_OPS(wiz_pm_ops, NULL, wiz_resume_noirq);
+static DEFINE_NOIRQ_DEV_PM_OPS(wiz_pm_ops, wiz_suspend_noirq, wiz_resume_noirq);
static struct platform_driver wiz_driver = {
.probe = wiz_probe,
diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig
index ad6736889231..d0ff32182a2b 100644
--- a/drivers/soc/apple/Kconfig
+++ b/drivers/soc/apple/Kconfig
@@ -38,6 +38,10 @@ config APPLE_SART
Say 'y' here if you have an Apple SoC.
+config APPLE_TUNABLE
+ tristate
+ depends on ARCH_APPLE || COMPILE_TEST
+
endmenu
endif
diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile
index 4d9ab8f3037b..0b85ab61aefe 100644
--- a/drivers/soc/apple/Makefile
+++ b/drivers/soc/apple/Makefile
@@ -8,3 +8,6 @@ apple-rtkit-y = rtkit.o rtkit-crashlog.o
obj-$(CONFIG_APPLE_SART) += apple-sart.o
apple-sart-y = sart.o
+
+obj-$(CONFIG_APPLE_TUNABLE) += apple-tunable.o
+apple-tunable-y = tunable.o
diff --git a/drivers/soc/apple/tunable.c b/drivers/soc/apple/tunable.c
new file mode 100644
index 000000000000..659323839171
--- /dev/null
+++ b/drivers/soc/apple/tunable.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Apple Silicon hardware tunable support
+ *
+ * Each tunable is a list with each entry containing a offset into the MMIO
+ * region, a mask of bits to be cleared and a set of bits to be set. These
+ * tunables are passed along by the previous boot stages and vary from device
+ * to device such that they cannot be hardcoded in the individual drivers.
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/overflow.h>
+#include <linux/soc/apple/tunable.h>
+
+struct apple_tunable *devm_apple_tunable_parse(struct device *dev,
+ struct device_node *np,
+ const char *name,
+ struct resource *res)
+{
+ struct apple_tunable *tunable;
+ struct property *prop;
+ const __be32 *p;
+ size_t sz;
+ int i;
+
+ if (resource_size(res) < 4)
+ return ERR_PTR(-EINVAL);
+
+ prop = of_find_property(np, name, NULL);
+ if (!prop)
+ return ERR_PTR(-ENOENT);
+
+ if (prop->length % (3 * sizeof(u32)))
+ return ERR_PTR(-EINVAL);
+ sz = prop->length / (3 * sizeof(u32));
+
+ tunable = devm_kzalloc(dev, struct_size(tunable, values, sz), GFP_KERNEL);
+ if (!tunable)
+ return ERR_PTR(-ENOMEM);
+ tunable->sz = sz;
+
+ for (i = 0, p = NULL; i < tunable->sz; ++i) {
+ p = of_prop_next_u32(prop, p, &tunable->values[i].offset);
+ p = of_prop_next_u32(prop, p, &tunable->values[i].mask);
+ p = of_prop_next_u32(prop, p, &tunable->values[i].value);
+
+ /* Sanity checks to catch bugs in our bootloader */
+ if (tunable->values[i].offset % 4)
+ return ERR_PTR(-EINVAL);
+ if (tunable->values[i].offset > (resource_size(res) - 4))
+ return ERR_PTR(-EINVAL);
+ }
+
+ return tunable;
+}
+EXPORT_SYMBOL(devm_apple_tunable_parse);
+
+void apple_tunable_apply(void __iomem *regs, struct apple_tunable *tunable)
+{
+ size_t i;
+
+ for (i = 0; i < tunable->sz; ++i) {
+ u32 val, old_val;
+
+ old_val = readl(regs + tunable->values[i].offset);
+ val = old_val & ~tunable->values[i].mask;
+ val |= tunable->values[i].value;
+ if (val != old_val)
+ writel(val, regs + tunable->values[i].offset);
+ }
+}
+EXPORT_SYMBOL(apple_tunable_apply);
+
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_AUTHOR("Sven Peter <sven@kernel.org>");
+MODULE_DESCRIPTION("Apple Silicon hardware tunable support");
diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
index f8d4094f0880..979b5dfd8353 100644
--- a/include/dt-bindings/phy/phy.h
+++ b/include/dt-bindings/phy/phy.h
@@ -23,6 +23,7 @@
#define PHY_TYPE_DPHY 10
#define PHY_TYPE_CPHY 11
#define PHY_TYPE_USXGMII 12
+#define PHY_TYPE_XAUI 13
#define PHY_POL_NORMAL 0
#define PHY_POL_INVERT 1
diff --git a/include/linux/phy/phy-hdmi.h b/include/linux/phy/phy-hdmi.h
index f0ec963c6e84..d4cf4430ee8f 100644
--- a/include/linux/phy/phy-hdmi.h
+++ b/include/linux/phy/phy-hdmi.h
@@ -6,16 +6,31 @@
#ifndef __PHY_HDMI_H_
#define __PHY_HDMI_H_
+#include <linux/types.h>
+
+enum phy_hdmi_mode {
+ PHY_HDMI_MODE_TMDS,
+ PHY_HDMI_MODE_FRL,
+};
+
/**
* struct phy_configure_opts_hdmi - HDMI configuration set
- * @tmds_char_rate: HDMI TMDS Character Rate in Hertz.
* @bpc: Bits per color channel.
+ * @tmds_char_rate: HDMI TMDS Character Rate in Hertz.
+ * @frl.rate_per_lane: HDMI FRL Rate per Lane in Gbps.
+ * @frl.lanes: HDMI FRL lanes count.
*
* This structure is used to represent the configuration state of a HDMI phy.
*/
struct phy_configure_opts_hdmi {
- unsigned long long tmds_char_rate;
unsigned int bpc;
+ union {
+ unsigned long long tmds_char_rate;
+ struct {
+ u8 rate_per_lane;
+ u8 lanes;
+ } frl;
+ };
};
#endif /* __PHY_HDMI_H_ */
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 2af0d01ebb39..ea47975e288a 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -243,7 +243,7 @@ static inline void *phy_get_drvdata(struct phy *phy)
#if IS_ENABLED(CONFIG_GENERIC_PHY)
int phy_pm_runtime_get(struct phy *phy);
int phy_pm_runtime_get_sync(struct phy *phy);
-int phy_pm_runtime_put(struct phy *phy);
+void phy_pm_runtime_put(struct phy *phy);
int phy_pm_runtime_put_sync(struct phy *phy);
int phy_init(struct phy *phy);
int phy_exit(struct phy *phy);
@@ -324,11 +324,8 @@ static inline int phy_pm_runtime_get_sync(struct phy *phy)
return -ENOSYS;
}
-static inline int phy_pm_runtime_put(struct phy *phy)
+static inline void phy_pm_runtime_put(struct phy *phy)
{
- if (!phy)
- return 0;
- return -ENOSYS;
}
static inline int phy_pm_runtime_put_sync(struct phy *phy)
diff --git a/include/linux/soc/apple/tunable.h b/include/linux/soc/apple/tunable.h
new file mode 100644
index 000000000000..531ca814cd02
--- /dev/null
+++ b/include/linux/soc/apple/tunable.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
+/*
+ * Apple Silicon hardware tunable support
+ *
+ * Each tunable is a list with each entry containing a offset into the MMIO
+ * region, a mask of bits to be cleared and a set of bits to be set. These
+ * tunables are passed along by the previous boot stages and vary from device
+ * to device such that they cannot be hardcoded in the individual drivers.
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ */
+
+#ifndef _LINUX_SOC_APPLE_TUNABLE_H_
+#define _LINUX_SOC_APPLE_TUNABLE_H_
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+/**
+ * Struct to store an Apple Silicon hardware tunable.
+ *
+ * Each tunable is a list with each entry containing a offset into the MMIO
+ * region, a mask of bits to be cleared and a set of bits to be set. These
+ * tunables are passed along by the previous boot stages and vary from device
+ * to device such that they cannot be hardcoded in the individual drivers.
+ *
+ * @param sz Number of [offset, mask, value] tuples stored in values.
+ * @param values [offset, mask, value] array.
+ */
+struct apple_tunable {
+ size_t sz;
+ struct {
+ u32 offset;
+ u32 mask;
+ u32 value;
+ } values[] __counted_by(sz);
+};
+
+/**
+ * Parse an array of hardware tunables from the device tree.
+ *
+ * @dev: Device node used for devm_kzalloc internally.
+ * @np: Device node which contains the tunable array.
+ * @name: Name of the device tree property which contains the tunables.
+ * @res: Resource to which the tunables will be applied, used for bound checking
+ *
+ * @return: devres allocated struct on success or PTR_ERR on failure.
+ */
+struct apple_tunable *devm_apple_tunable_parse(struct device *dev,
+ struct device_node *np,
+ const char *name,
+ struct resource *res);
+
+/**
+ * Apply a previously loaded hardware tunable.
+ *
+ * @param regs: MMIO to which the tunable will be applied.
+ * @param tunable: Pointer to the tunable.
+ */
+void apple_tunable_apply(void __iomem *regs, struct apple_tunable *tunable);
+
+#endif
diff --git a/include/linux/soc/samsung/exynos-regs-pmu.h b/include/linux/soc/samsung/exynos-regs-pmu.h
index 532c6c2d1195..db8a7ca81080 100644
--- a/include/linux/soc/samsung/exynos-regs-pmu.h
+++ b/include/linux/soc/samsung/exynos-regs-pmu.h
@@ -1015,4 +1015,7 @@
#define GS101_GRP2_INTR_BID_UPEND (0x0208)
#define GS101_GRP2_INTR_BID_CLEAR (0x020c)
+/* exynosautov920 */
+#define EXYNOSAUTOV920_PHY_CTRL_USB20 (0x0710)
+#define EXYNOSAUTOV920_PHY_CTRL_USB31 (0x0714)
#endif /* __LINUX_SOC_EXYNOS_REGS_PMU_H */