Commit 7afb9d76 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'phy-for-6.5_v2' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy

Pull phy updates from Vinod Koul:
 "New Support:
   - Debugfs support for phy core and mediatek driver
   - Hisilicon inno-usb2-phy driver supporting Hi3798MV100
   - Qualcomm SGMII SerDes PHY driver, SM6115 & QCM2290 QMP-USB support,
     SA8775P USB PHY & USB3 UNI support, QUSB2 support for IPQ9574,
     IPQ9574 USB3 PHY

  UpdatesL
   - Sparx5 serdes phy power optimzation
   - cadence salvo usb properties and updates and torrent DP with PCIe &
     USB support
   - Yaml conversion for Broadcom kona USB bindings and MXS USB binding"

* tag 'phy-for-6.5_v2' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (67 commits)
  dt-bindings: phy: brcm,brcmstb-usb-phy: Fix error in "compatible" conditional schema
  dt-bindings: phy: mixel,mipi-dsi-phy: Remove assigned-clock* properties
  dt-bindings: phy: intel,combo-phy: restrict node name suffixes
  dt-bindings: phy: qcom,usb-hs-phy: Add compatible
  phy: tegra: xusb: check return value of devm_kzalloc()
  phy: qcom: qmp-combo: fix Display Port PHY configuration for SM8550
  phy: qcom: add the SGMII SerDes PHY driver
  dt-bindings: phy: describe the Qualcomm SGMII PHY
  phy: qualcomm: fix indentation in Makefile
  phy: usb: suppress OC condition for 7439b2
  phy: usb: Turn off phy when port is in suspend
  phy: tegra: xusb: Clear the driver reference in usb-phy dev
  dt-bindings: phy: mxs-usb-phy: add imx8ulp and imx8qm compatible
  dt-bindings: phy: mxs-usb-phy: convert to DT schema format
  dt-bindings: phy: qcom,qmp-usb: fix bindings error
  dt-bindings: phy: qcom,qmp-ufs: fix the sc8180x regs
  dt-bindings: phy: qcom,qmp-pcie: fix the sc8180x regs
  phy: mediatek: tphy: add debugfs files
  phy: core: add debugfs files
  phy: fsl-imx8mp-usb: add support for phy tuning
  ...
parents 68433066 a454850a
...@@ -115,8 +115,8 @@ allOf: ...@@ -115,8 +115,8 @@ allOf:
compatible: compatible:
contains: contains:
enum: enum:
- const: brcm,bcm4908-usb-phy - brcm,bcm4908-usb-phy
- const: brcm,brcmstb-usb-phy - brcm,brcmstb-usb-phy
then: then:
properties: properties:
reg: reg:
......
BROADCOM KONA USB2 PHY
Required properties:
- compatible: brcm,kona-usb2-phy
- reg: offset and length of the PHY registers
- #phy-cells: must be 0
Refer to phy/phy-bindings.txt for the generic PHY binding properties
Example:
usbphy: usb-phy@3f130000 {
compatible = "brcm,kona-usb2-phy";
reg = <0x3f130000 0x28>;
#phy-cells = <0>;
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/brcm,kona-usb2-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom Kona family USB 2.0 PHY
maintainers:
- Florian Fainelli <f.fainelli@gmail.com>
properties:
compatible:
const: brcm,kona-usb2-phy
reg:
maxItems: 1
'#phy-cells':
const: 0
required:
- compatible
- reg
- '#phy-cells'
additionalProperties: false
examples:
- |
usb-phy@3f130000 {
compatible = "brcm,kona-usb2-phy";
reg = <0x3f130000 0x28>;
#phy-cells = <0>;
};
...
...@@ -31,6 +31,12 @@ properties: ...@@ -31,6 +31,12 @@ properties:
"#phy-cells": "#phy-cells":
const: 0 const: 0
cdns,usb2-disconnect-threshold-microvolt:
description: The microvolt threshold value utilized for detecting
USB disconnection event.
enum: [575, 610, 645]
default: 575
required: required:
- compatible - compatible
- reg - reg
......
...@@ -35,6 +35,53 @@ properties: ...@@ -35,6 +35,53 @@ properties:
description: description:
A phandle to the regulator for USB VBUS. A phandle to the regulator for USB VBUS.
fsl,phy-tx-vref-tune-percent:
description:
Tunes the HS DC level relative to the nominal level
minimum: 94
maximum: 124
fsl,phy-tx-rise-tune-percent:
description:
Adjusts the rise/fall time duration of the HS waveform relative to
its nominal value
minimum: 97
maximum: 103
fsl,phy-tx-preemp-amp-tune-microamp:
description:
Adjust amount of current sourced to DPn and DMn after a J-to-K
or K-to-J transition. Default is 0 (disabled).
minimum: 0
maximum: 1800
fsl,phy-tx-vboost-level-microvolt:
description:
Adjust the boosted transmit launch pk-pk differential amplitude
minimum: 880
maximum: 1120
fsl,phy-comp-dis-tune-percent:
description:
Adjust the voltage level used to detect a disconnect event at the host
relative to the nominal value
minimum: 91
maximum: 115
fsl,phy-pcs-tx-deemph-3p5db-attenuation-db:
description:
Adjust TX de-emphasis attenuation in dB at nominal
3.5dB point as per USB specification
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 36
fsl,phy-pcs-tx-swing-full-percent:
description:
Scaling of the voltage defined by fsl,phy-tx-vboost-level-microvolt
minimum: 0
maximum: 100
required: required:
- compatible - compatible
- reg - reg
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/fsl,mxs-usbphy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale MXS USB Phy Device
maintainers:
- Xu Yang <xu.yang_2@nxp.com>
properties:
compatible:
oneOf:
- enum:
- fsl,imx23-usbphy
- fsl,imx7ulp-usbphy
- fsl,vf610-usbphy
- items:
- enum:
- fsl,imx28-usbphy
- fsl,imx6ul-usbphy
- fsl,imx6sl-usbphy
- fsl,imx6sx-usbphy
- fsl,imx6q-usbphy
- const: fsl,imx23-usbphy
- items:
- const: fsl,imx6sll-usbphy
- const: fsl,imx6ul-usbphy
- const: fsl,imx23-usbphy
- items:
- enum:
- fsl,imx8dxl-usbphy
- fsl,imx8qm-usbphy
- fsl,imx8ulp-usbphy
- const: fsl,imx7ulp-usbphy
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
'#phy-cells':
const: 0
power-domains:
maxItems: 1
fsl,anatop:
description:
phandle for anatop register, it is only for imx6 SoC series.
$ref: /schemas/types.yaml#/definitions/phandle
phy-3p0-supply:
description:
One of USB PHY's power supply. Can be used to keep a good signal
quality.
fsl,tx-cal-45-dn-ohms:
description:
Resistance (in ohms) of switchable high-speed trimming resistor
connected in parallel with the 45 ohm resistor that terminates
the DN output signal.
minimum: 35
maximum: 54
default: 45
fsl,tx-cal-45-dp-ohms:
description:
Resistance (in ohms) of switchable high-speed trimming resistor
connected in parallel with the 45 ohm resistor that terminates
the DP output signal.
minimum: 35
maximum: 54
default: 45
fsl,tx-d-cal:
description:
Current trimming value (as a percentage) of the 17.78 mA TX
reference current.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 79
maximum: 119
default: 100
required:
- compatible
- reg
- clocks
allOf:
- if:
properties:
compatible:
oneOf:
- enum:
- fsl,imx6q-usbphy
- fsl,imx6sl-usbphy
- fsl,imx6sx-usbphy
- fsl,imx6sll-usbphy
- fsl,vf610-usbphy
- items:
- const: fsl,imx6ul-usbphy
- const: fsl,imx23-usbphy
then:
required:
- fsl,anatop
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/imx6qdl-clock.h>
usbphy1: usb-phy@20c9000 {
compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
reg = <0x020c9000 0x1000>;
clocks = <&clks IMX6QDL_CLK_USBPHY1>;
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
fsl,anatop = <&anatop>;
};
...
...@@ -15,7 +15,7 @@ description: | ...@@ -15,7 +15,7 @@ description: |
properties: properties:
$nodename: $nodename:
pattern: "combophy(@.*|-[0-9a-f])*$" pattern: "combophy(@.*|-([0-9]|[1-9][0-9]+))?$"
compatible: compatible:
items: items:
......
...@@ -32,15 +32,6 @@ properties: ...@@ -32,15 +32,6 @@ properties:
clock-names: clock-names:
const: phy_ref const: phy_ref
assigned-clocks:
maxItems: 1
assigned-clock-parents:
maxItems: 1
assigned-clock-rates:
maxItems: 1
"#phy-cells": "#phy-cells":
const: 0 const: 0
......
* Freescale MXS USB Phy Device
Required properties:
- compatible: should contain:
* "fsl,imx23-usbphy" for imx23 and imx28
* "fsl,imx6q-usbphy" for imx6dq and imx6dl
* "fsl,imx6sl-usbphy" for imx6sl
* "fsl,vf610-usbphy" for Vybrid vf610
* "fsl,imx6sx-usbphy" for imx6sx
* "fsl,imx7ulp-usbphy" for imx7ulp
* "fsl,imx8dxl-usbphy" for imx8dxl
"fsl,imx23-usbphy" is still a fallback for other strings
- reg: Should contain registers location and length
- interrupts: Should contain phy interrupt
- fsl,anatop: phandle for anatop register, it is only for imx6 SoC series
Optional properties:
- fsl,tx-cal-45-dn-ohms: Integer [35-54]. Resistance (in ohms) of switchable
high-speed trimming resistor connected in parallel with the 45 ohm resistor
that terminates the DN output signal. Default: 45
- fsl,tx-cal-45-dp-ohms: Integer [35-54]. Resistance (in ohms) of switchable
high-speed trimming resistor connected in parallel with the 45 ohm resistor
that terminates the DP output signal. Default: 45
- fsl,tx-d-cal: Integer [79-119]. Current trimming value (as a percentage) of
the 17.78mA TX reference current. Default: 100
Example:
usbphy1: usb-phy@20c9000 {
compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
reg = <0x020c9000 0x1000>;
interrupts = <0 44 0x04>;
fsl,anatop = <&anatop>;
};
...@@ -43,6 +43,9 @@ properties: ...@@ -43,6 +43,9 @@ properties:
"#phy-cells": "#phy-cells":
const: 0 const: 0
power-domains:
maxItems: 1
vdda-phy-supply: true vdda-phy-supply: true
vdda-pll-supply: true vdda-pll-supply: true
......
...@@ -203,6 +203,7 @@ allOf: ...@@ -203,6 +203,7 @@ allOf:
compatible: compatible:
contains: contains:
enum: enum:
- qcom,sc8180x-qmp-pcie-phy
- qcom,sm8250-qmp-gen3x2-pcie-phy - qcom,sm8250-qmp-gen3x2-pcie-phy
- qcom,sm8250-qmp-modem-pcie-phy - qcom,sm8250-qmp-modem-pcie-phy
- qcom,sm8450-qmp-gen4x2-pcie-phy - qcom,sm8450-qmp-gen4x2-pcie-phy
...@@ -224,7 +225,6 @@ allOf: ...@@ -224,7 +225,6 @@ allOf:
compatible: compatible:
contains: contains:
enum: enum:
- qcom,sc8180x-qmp-pcie-phy
- qcom,sdm845-qmp-pcie-phy - qcom,sdm845-qmp-pcie-phy
- qcom,sdx55-qmp-pcie-phy - qcom,sdx55-qmp-pcie-phy
- qcom,sm8250-qmp-gen3x1-pcie-phy - qcom,sm8250-qmp-gen3x1-pcie-phy
......
...@@ -160,6 +160,7 @@ allOf: ...@@ -160,6 +160,7 @@ allOf:
contains: contains:
enum: enum:
- qcom,msm8998-qmp-ufs-phy - qcom,msm8998-qmp-ufs-phy
- qcom,sc8180x-qmp-ufs-phy
- qcom,sdm845-qmp-ufs-phy - qcom,sdm845-qmp-ufs-phy
- qcom,sm6350-qmp-ufs-phy - qcom,sm6350-qmp-ufs-phy
- qcom,sm8150-qmp-ufs-phy - qcom,sm8150-qmp-ufs-phy
...@@ -178,23 +179,6 @@ allOf: ...@@ -178,23 +179,6 @@ allOf:
- description: TX lane 2 - description: TX lane 2
- description: RX lane 2 - description: RX lane 2
- if:
properties:
compatible:
contains:
enum:
- qcom,sc8180x-qmp-ufs-phy
then:
patternProperties:
"^phy@[0-9a-f]+$":
properties:
reg:
items:
- description: TX
- description: RX
- description: PCS
- description: PCS_MISC
- if: - if:
properties: properties:
compatible: compatible:
......
...@@ -23,14 +23,12 @@ properties: ...@@ -23,14 +23,12 @@ properties:
- qcom,ipq8074-qmp-usb3-phy - qcom,ipq8074-qmp-usb3-phy
- qcom,msm8996-qmp-usb3-phy - qcom,msm8996-qmp-usb3-phy
- qcom,msm8998-qmp-usb3-phy - qcom,msm8998-qmp-usb3-phy
- qcom,qcm2290-qmp-usb3-phy
- qcom,sc7180-qmp-usb3-phy - qcom,sc7180-qmp-usb3-phy
- qcom,sc8180x-qmp-usb3-phy - qcom,sc8180x-qmp-usb3-phy
- qcom,sdm845-qmp-usb3-phy - qcom,sdm845-qmp-usb3-phy
- qcom,sdm845-qmp-usb3-uni-phy - qcom,sdm845-qmp-usb3-uni-phy
- qcom,sdx55-qmp-usb3-uni-phy - qcom,sdx55-qmp-usb3-uni-phy
- qcom,sdx65-qmp-usb3-uni-phy - qcom,sdx65-qmp-usb3-uni-phy
- qcom,sm6115-qmp-usb3-phy
- qcom,sm8150-qmp-usb3-phy - qcom,sm8150-qmp-usb3-phy
- qcom,sm8150-qmp-usb3-uni-phy - qcom,sm8150-qmp-usb3-uni-phy
- qcom,sm8250-qmp-usb3-phy - qcom,sm8250-qmp-usb3-phy
...@@ -248,29 +246,6 @@ allOf: ...@@ -248,29 +246,6 @@ allOf:
- const: phy - const: phy
- const: common - const: common
- if:
properties:
compatible:
contains:
enum:
- qcom,qcm2290-qmp-usb3-phy
- qcom,sm6115-qmp-usb3-phy
then:
properties:
clocks:
maxItems: 3
clock-names:
items:
- const: cfg_ahb
- const: ref
- const: com_aux
resets:
maxItems: 2
reset-names:
items:
- const: phy_phy
- const: phy
- if: - if:
properties: properties:
compatible: compatible:
...@@ -318,12 +293,10 @@ allOf: ...@@ -318,12 +293,10 @@ allOf:
enum: enum:
- qcom,ipq6018-qmp-usb3-phy - qcom,ipq6018-qmp-usb3-phy
- qcom,ipq8074-qmp-usb3-phy - qcom,ipq8074-qmp-usb3-phy
- qcom,qcm2290-qmp-usb3-phy
- qcom,sc7180-qmp-usb3-phy - qcom,sc7180-qmp-usb3-phy
- qcom,sc8180x-qmp-usb3-phy - qcom,sc8180x-qmp-usb3-phy
- qcom,sdx55-qmp-usb3-uni-phy - qcom,sdx55-qmp-usb3-uni-phy
- qcom,sdx65-qmp-usb3-uni-phy - qcom,sdx65-qmp-usb3-uni-phy
- qcom,sm6115-qmp-usb3-phy
- qcom,sm8150-qmp-usb3-uni-phy - qcom,sm8150-qmp-usb3-uni-phy
- qcom,sm8250-qmp-usb3-phy - qcom,sm8250-qmp-usb3-phy
then: then:
......
...@@ -18,13 +18,14 @@ properties: ...@@ -18,13 +18,14 @@ properties:
oneOf: oneOf:
- items: - items:
- enum: - enum:
- qcom,ipq6018-qusb2-phy
- qcom,ipq8074-qusb2-phy - qcom,ipq8074-qusb2-phy
- qcom,ipq9574-qusb2-phy
- qcom,msm8953-qusb2-phy - qcom,msm8953-qusb2-phy
- qcom,msm8996-qusb2-phy - qcom,msm8996-qusb2-phy
- qcom,msm8998-qusb2-phy - qcom,msm8998-qusb2-phy
- qcom,qcm2290-qusb2-phy - qcom,qcm2290-qusb2-phy
- qcom,sdm660-qusb2-phy - qcom,sdm660-qusb2-phy
- qcom,ipq6018-qusb2-phy
- qcom,sm4250-qusb2-phy - qcom,sm4250-qusb2-phy
- qcom,sm6115-qusb2-phy - qcom,sm6115-qusb2-phy
- items: - items:
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/qcom,sa8775p-dwmac-sgmii-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SerDes/SGMII ethernet PHY controller
maintainers:
- Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
description:
The SerDes PHY sits between the MAC and the external PHY and provides
separate Rx Tx lines.
properties:
compatible:
const: qcom,sa8775p-dwmac-sgmii-phy
reg:
items:
- description: serdes
clocks:
maxItems: 1
clock-names:
const: sgmi_ref
phy-supply:
description:
Phandle to a regulator that provides power to the PHY.
"#phy-cells":
const: 0
required:
- compatible
- reg
- "#phy-cells"
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,sa8775p-gcc.h>
serdes_phy: phy@8901000 {
compatible = "qcom,sa8775p-dwmac-sgmii-phy";
reg = <0x08901000 0xe10>;
clocks = <&gcc GCC_SGMI_CLKREF_EN>;
clock-names = "sgmi_ref";
#phy-cells = <0>;
};
...@@ -78,9 +78,9 @@ allOf: ...@@ -78,9 +78,9 @@ allOf:
then: then:
properties: properties:
clocks: clocks:
maxItems: 3 minItems: 3
clock-names: clock-names:
maxItems: 3 minItems: 3
else: else:
properties: properties:
clocks: clocks:
......
...@@ -16,7 +16,11 @@ description: ...@@ -16,7 +16,11 @@ description:
properties: properties:
compatible: compatible:
enum: enum:
- qcom,ipq9574-qmp-usb3-phy
- qcom,qcm2290-qmp-usb3-phy
- qcom,sa8775p-qmp-usb3-uni-phy
- qcom,sc8280xp-qmp-usb3-uni-phy - qcom,sc8280xp-qmp-usb3-uni-phy
- qcom,sm6115-qmp-usb3-phy
reg: reg:
maxItems: 1 maxItems: 1
...@@ -25,11 +29,7 @@ properties: ...@@ -25,11 +29,7 @@ properties:
maxItems: 4 maxItems: 4
clock-names: clock-names:
items: maxItems: 4
- const: aux
- const: ref
- const: com_aux
- const: pipe
power-domains: power-domains:
maxItems: 1 maxItems: 1
...@@ -60,7 +60,6 @@ required: ...@@ -60,7 +60,6 @@ required:
- reg - reg
- clocks - clocks
- clock-names - clock-names
- power-domains
- resets - resets
- reset-names - reset-names
- vdda-phy-supply - vdda-phy-supply
...@@ -69,6 +68,60 @@ required: ...@@ -69,6 +68,60 @@ required:
- clock-output-names - clock-output-names
- "#phy-cells" - "#phy-cells"
allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,ipq9574-qmp-usb3-phy
then:
properties:
clock-names:
items:
- const: aux
- const: ref
- const: cfg_ahb
- const: pipe
- if:
properties:
compatible:
contains:
enum:
- qcom,qcm2290-qmp-usb3-phy
- qcom,sm6115-qmp-usb3-phy
then:
properties:
clocks:
maxItems: 4
clock-names:
items:
- const: cfg_ahb
- const: ref
- const: com_aux
- const: pipe
- if:
properties:
compatible:
contains:
enum:
- qcom,sa8775p-qmp-usb3-uni-phy
- qcom,sc8280xp-qmp-usb3-uni-phy
then:
properties:
clocks:
maxItems: 4
clock-names:
items:
- const: aux
- const: ref
- const: com_aux
- const: pipe
required:
- power-domains
additionalProperties: false additionalProperties: false
examples: examples:
......
...@@ -60,6 +60,26 @@ properties: ...@@ -60,6 +60,26 @@ properties:
description: description:
See include/dt-bindings/dt-bindings/phy/phy-qcom-qmp.h See include/dt-bindings/dt-bindings/phy/phy-qcom-qmp.h
orientation-switch:
description:
Flag the PHY as possible handler of USB Type-C orientation switching
type: boolean
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: /schemas/graph.yaml#/properties/port
description: Output endpoint of the PHY
port@1:
$ref: /schemas/graph.yaml#/properties/port
description: Incoming endpoint from the USB controller
port@2:
$ref: /schemas/graph.yaml#/properties/port
description: Incoming endpoint from the DisplayPort controller
required: required:
- compatible - compatible
- reg - reg
...@@ -98,6 +118,37 @@ examples: ...@@ -98,6 +118,37 @@ examples:
vdda-phy-supply = <&vreg_l9d>; vdda-phy-supply = <&vreg_l9d>;
vdda-pll-supply = <&vreg_l4d>; vdda-pll-supply = <&vreg_l4d>;
orientation-switch;
#clock-cells = <1>; #clock-cells = <1>;
#phy-cells = <1>; #phy-cells = <1>;
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 = <&mdss_dp_out>;
};
};
};
}; };
...@@ -13,7 +13,9 @@ if: ...@@ -13,7 +13,9 @@ if:
properties: properties:
compatible: compatible:
contains: contains:
const: qcom,usb-hs-phy-apq8064 enum:
- qcom,usb-hs-phy-apq8064
- qcom,usb-hs-phy-msm8960
then: then:
properties: properties:
resets: resets:
...@@ -40,6 +42,7 @@ properties: ...@@ -40,6 +42,7 @@ properties:
- qcom,usb-hs-phy-apq8064 - qcom,usb-hs-phy-apq8064
- qcom,usb-hs-phy-msm8226 - qcom,usb-hs-phy-msm8226
- qcom,usb-hs-phy-msm8916 - qcom,usb-hs-phy-msm8916
- qcom,usb-hs-phy-msm8960
- qcom,usb-hs-phy-msm8974 - qcom,usb-hs-phy-msm8974
- const: qcom,usb-hs-phy - const: qcom,usb-hs-phy
......
...@@ -20,6 +20,7 @@ properties: ...@@ -20,6 +20,7 @@ properties:
- qcom,usb-snps-femto-v2-phy - qcom,usb-snps-femto-v2-phy
- items: - items:
- enum: - enum:
- qcom,sa8775p-usb-hs-phy
- qcom,sc8280xp-usb-hs-phy - qcom,sc8280xp-usb-hs-phy
- const: qcom,usb-snps-hs-5nm-phy - const: qcom,usb-snps-hs-5nm-phy
- items: - items:
......
...@@ -24,6 +24,7 @@ properties: ...@@ -24,6 +24,7 @@ properties:
- qcom,msm8998-dwc3 - qcom,msm8998-dwc3
- qcom,qcm2290-dwc3 - qcom,qcm2290-dwc3
- qcom,qcs404-dwc3 - qcom,qcs404-dwc3
- qcom,sa8775p-dwc3
- qcom,sc7180-dwc3 - qcom,sc7180-dwc3
- qcom,sc7280-dwc3 - qcom,sc7280-dwc3
- qcom,sc8280xp-dwc3 - qcom,sc8280xp-dwc3
...@@ -181,6 +182,7 @@ allOf: ...@@ -181,6 +182,7 @@ allOf:
- qcom,msm8953-dwc3 - qcom,msm8953-dwc3
- qcom,msm8996-dwc3 - qcom,msm8996-dwc3
- qcom,msm8998-dwc3 - qcom,msm8998-dwc3
- qcom,sa8775p-dwc3
- qcom,sc7180-dwc3 - qcom,sc7180-dwc3
- qcom,sc7280-dwc3 - qcom,sc7280-dwc3
- qcom,sdm670-dwc3 - qcom,sdm670-dwc3
...@@ -456,6 +458,25 @@ allOf: ...@@ -456,6 +458,25 @@ allOf:
- const: dm_hs_phy_irq - const: dm_hs_phy_irq
- const: ss_phy_irq - const: ss_phy_irq
- if:
properties:
compatible:
contains:
enum:
- qcom,sa8775p-dwc3
then:
properties:
interrupts:
minItems: 3
maxItems: 4
interrupt-names:
minItems: 3
items:
- const: pwr_event
- const: dp_hs_phy_irq
- const: dm_hs_phy_irq
- const: ss_phy_irq
additionalProperties: false additionalProperties: false
examples: examples:
......
...@@ -172,10 +172,16 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) ...@@ -172,10 +172,16 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
int ret; int ret;
unsigned int value; unsigned int value;
ret = reset_control_reset(priv->reset); ret = clk_prepare_enable(priv->clk);
if (ret) if (ret)
return ret; return ret;
ret = reset_control_reset(priv->reset);
if (ret) {
clk_disable_unprepare(priv->clk);
return ret;
}
udelay(RESET_COMPLETE_TIME); udelay(RESET_COMPLETE_TIME);
/* usb2_otg_aca_en == 0 */ /* usb2_otg_aca_en == 0 */
...@@ -277,8 +283,13 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) ...@@ -277,8 +283,13 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
static int phy_meson_g12a_usb2_exit(struct phy *phy) static int phy_meson_g12a_usb2_exit(struct phy *phy)
{ {
struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy); struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy);
int ret;
ret = reset_control_reset(priv->reset);
if (!ret)
clk_disable_unprepare(priv->clk);
return reset_control_reset(priv->reset); return ret;
} }
/* set_mode is not needed, mode setting is handled via the UTMI bus */ /* set_mode is not needed, mode setting is handled via the UTMI bus */
......
...@@ -59,6 +59,8 @@ ...@@ -59,6 +59,8 @@
#define USB_CTLR_TP_DIAG1_wake_MASK BIT(1) #define USB_CTLR_TP_DIAG1_wake_MASK BIT(1)
#define USB_CTRL_CTLR_CSHCR 0x50 #define USB_CTRL_CTLR_CSHCR 0x50
#define USB_CTRL_CTLR_CSHCR_ctl_pme_en_MASK BIT(18) #define USB_CTRL_CTLR_CSHCR_ctl_pme_en_MASK BIT(18)
#define USB_CTRL_P0_U2PHY_CFG1 0x68
#define USB_CTRL_P0_U2PHY_CFG1_COMMONONN_MASK BIT(10)
/* Register definitions for the USB_PHY block in 7211b0 */ /* Register definitions for the USB_PHY block in 7211b0 */
#define USB_PHY_PLL_CTL 0x00 #define USB_PHY_PLL_CTL 0x00
...@@ -90,6 +92,8 @@ ...@@ -90,6 +92,8 @@
#define BDC_EC_AXIRDA_RTS_MASK GENMASK(31, 28) #define BDC_EC_AXIRDA_RTS_MASK GENMASK(31, 28)
#define BDC_EC_AXIRDA_RTS_SHIFT 28 #define BDC_EC_AXIRDA_RTS_SHIFT 28
#define USB_XHCI_GBL_GUSB2PHYCFG 0x100
#define USB_XHCI_GBL_GUSB2PHYCFG_U2_FREECLK_EXISTS_MASK BIT(30)
static void usb_mdio_write_7211b0(struct brcm_usb_init_params *params, static void usb_mdio_write_7211b0(struct brcm_usb_init_params *params,
uint8_t addr, uint16_t data) uint8_t addr, uint16_t data)
...@@ -140,13 +144,17 @@ static void xhci_soft_reset(struct brcm_usb_init_params *params, ...@@ -140,13 +144,17 @@ static void xhci_soft_reset(struct brcm_usb_init_params *params,
int on_off) int on_off)
{ {
void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
void __iomem *xhci_gbl = params->regs[BRCM_REGS_XHCI_GBL];
/* Assert reset */ /* Assert reset */
if (on_off) if (on_off) {
USB_CTRL_UNSET(ctrl, USB_PM, XHC_SOFT_RESETB); USB_CTRL_UNSET(ctrl, USB_PM, XHC_SOFT_RESETB);
/* De-assert reset */ /* De-assert reset */
else } else {
USB_CTRL_SET(ctrl, USB_PM, XHC_SOFT_RESETB); USB_CTRL_SET(ctrl, USB_PM, XHC_SOFT_RESETB);
/* Required for COMMONONN to be set */
USB_XHCI_GBL_UNSET(xhci_gbl, GUSB2PHYCFG, U2_FREECLK_EXISTS);
}
} }
static void usb_init_ipp(struct brcm_usb_init_params *params) static void usb_init_ipp(struct brcm_usb_init_params *params)
...@@ -320,6 +328,9 @@ static void usb_init_common_7216(struct brcm_usb_init_params *params) ...@@ -320,6 +328,9 @@ static void usb_init_common_7216(struct brcm_usb_init_params *params)
/* 1 millisecond - for USB clocks to settle down */ /* 1 millisecond - for USB clocks to settle down */
usleep_range(1000, 2000); usleep_range(1000, 2000);
/* Disable PHY when port is suspended */
USB_CTRL_SET(ctrl, P0_U2PHY_CFG1, COMMONONN);
usb_wake_enable_7216(params, false); usb_wake_enable_7216(params, false);
usb_init_common(params); usb_init_common(params);
} }
......
...@@ -35,6 +35,11 @@ ...@@ -35,6 +35,11 @@
#define USB_CTRL_SETUP_STRAP_IPP_SEL_MASK BIT(25) /* option */ #define USB_CTRL_SETUP_STRAP_IPP_SEL_MASK BIT(25) /* option */
#define USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK BIT(26) /* option */ #define USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK BIT(26) /* option */
#define USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK BIT(27) /* opt */ #define USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK BIT(27) /* opt */
#define USB_CTRL_SETUP_OC_DISABLE_PORT0_MASK BIT(28)
#define USB_CTRL_SETUP_OC_DISABLE_PORT1_MASK BIT(29)
#define USB_CTRL_SETUP_OC_DISABLE_MASK GENMASK(29, 28) /* option */
#define USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK BIT(30)
#define USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK BIT(31)
#define USB_CTRL_SETUP_OC3_DISABLE_MASK GENMASK(31, 30) /* option */ #define USB_CTRL_SETUP_OC3_DISABLE_MASK GENMASK(31, 30) /* option */
#define USB_CTRL_PLL_CTL 0x04 #define USB_CTRL_PLL_CTL 0x04
#define USB_CTRL_PLL_CTL_PLL_SUSPEND_EN_MASK BIT(27) #define USB_CTRL_PLL_CTL_PLL_SUSPEND_EN_MASK BIT(27)
...@@ -114,6 +119,8 @@ enum { ...@@ -114,6 +119,8 @@ enum {
USB_CTRL_SETUP_SCB2_EN_SELECTOR, USB_CTRL_SETUP_SCB2_EN_SELECTOR,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR, USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR,
USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR, USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR,
USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR,
USB_CTRL_SETUP_OC3_DISABLE_SELECTOR, USB_CTRL_SETUP_OC3_DISABLE_SELECTOR,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR, USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR,
USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR, USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR,
...@@ -190,6 +197,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { ...@@ -190,6 +197,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_SCB2_EN_MASK, USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK,
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, USB_CTRL_SETUP_STRAP_IPP_SEL_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
...@@ -232,6 +241,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { ...@@ -232,6 +241,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_SCB2_EN_MASK, USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK,
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK,
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
...@@ -253,6 +264,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { ...@@ -253,6 +264,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK,
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, USB_CTRL_SETUP_STRAP_IPP_SEL_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK,
...@@ -274,6 +287,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { ...@@ -274,6 +287,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_SCB2_EN_MASK, USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK,
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK,
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
...@@ -295,6 +310,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { ...@@ -295,6 +310,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_SCB2_EN_MASK, USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK,
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
...@@ -316,6 +333,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { ...@@ -316,6 +333,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_SCB2_EN_MASK, USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK, USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK,
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
0, /* USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK */
0, /* USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK */
0, /* USB_CTRL_SETUP_OC3_DISABLE_MASK */ 0, /* USB_CTRL_SETUP_OC3_DISABLE_MASK */
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK,
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
...@@ -337,6 +356,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { ...@@ -337,6 +356,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_SCB2_EN_MASK, USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK,
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, USB_CTRL_SETUP_STRAP_IPP_SEL_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK,
...@@ -358,6 +379,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { ...@@ -358,6 +379,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
USB_CTRL_SETUP_SCB2_EN_MASK, USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK, USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK,
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK,
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
...@@ -379,6 +402,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { ...@@ -379,6 +402,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK,
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, USB_CTRL_SETUP_STRAP_IPP_SEL_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK,
...@@ -400,6 +425,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { ...@@ -400,6 +425,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */
0, /*USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK */ 0, /*USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK */
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, USB_CTRL_SETUP_STRAP_IPP_SEL_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK,
USB_CTRL_SETUP_OC3_DISABLE_MASK, USB_CTRL_SETUP_OC3_DISABLE_MASK,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK,
...@@ -872,6 +899,13 @@ static void usb_init_common(struct brcm_usb_init_params *params) ...@@ -872,6 +899,13 @@ static void usb_init_common(struct brcm_usb_init_params *params)
brcmusb_memc_fix(params); brcmusb_memc_fix(params);
/* Workaround for false positive OC for 7439b2 in DRD/Device mode */
if ((params->family_id == 0x74390012) &&
(params->supported_port_modes != USB_CTLR_MODE_HOST)) {
USB_CTRL_SET(ctrl, SETUP, OC_DISABLE_PORT1);
USB_CTRL_SET_FAMILY(params, SETUP, OC3_DISABLE_PORT1);
}
if (USB_CTRL_MASK_FAMILY(params, USB_DEVICE_CTL1, PORT_MODE)) { if (USB_CTRL_MASK_FAMILY(params, USB_DEVICE_CTL1, PORT_MODE)) {
reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1)); reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
reg &= ~USB_CTRL_MASK_FAMILY(params, USB_DEVICE_CTL1, reg &= ~USB_CTRL_MASK_FAMILY(params, USB_DEVICE_CTL1,
......
...@@ -34,6 +34,14 @@ enum brcmusb_reg_sel { ...@@ -34,6 +34,14 @@ enum brcmusb_reg_sel {
brcm_usb_ctrl_unset(USB_CTRL_REG(base, reg), \ brcm_usb_ctrl_unset(USB_CTRL_REG(base, reg), \
USB_CTRL_##reg##_##field##_MASK) USB_CTRL_##reg##_##field##_MASK)
#define USB_XHCI_GBL_REG(base, reg) ((void __iomem *)base + USB_XHCI_GBL_##reg)
#define USB_XHCI_GBL_SET(base, reg, field) \
brcm_usb_ctrl_set(USB_XHCI_GBL_REG(base, reg), \
USB_XHCI_GBL_##reg##_##field##_MASK)
#define USB_XHCI_GBL_UNSET(base, reg, field) \
brcm_usb_ctrl_unset(USB_XHCI_GBL_REG(base, reg), \
USB_XHCI_GBL_##reg##_##field##_MASK)
struct brcm_usb_init_params; struct brcm_usb_init_params;
struct brcm_usb_init_ops { struct brcm_usb_init_ops {
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* Copyright (c) 2019-2020 NXP * Copyright (c) 2019-2020 NXP
*/ */
#include <linux/bitfield.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -15,7 +16,9 @@ ...@@ -15,7 +16,9 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
/* PHY register definition */ #define USB3_PHY_OFFSET 0x0
#define USB2_PHY_OFFSET 0x38000
/* USB3 PHY register definition */
#define PHY_PMA_CMN_CTRL1 0xC800 #define PHY_PMA_CMN_CTRL1 0xC800
#define TB_ADDR_CMN_DIAG_HSCLK_SEL 0x01e0 #define TB_ADDR_CMN_DIAG_HSCLK_SEL 0x01e0
#define TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR 0x0084 #define TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR 0x0084
...@@ -87,8 +90,35 @@ ...@@ -87,8 +90,35 @@
#define TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40f2 #define TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40f2
#define TB_ADDR_TX_RCVDETSC_CTRL 0x4124 #define TB_ADDR_TX_RCVDETSC_CTRL 0x4124
/* USB2 PHY register definition */
#define UTMI_REG15 0xaf
#define UTMI_AFE_RX_REG0 0x0d
#define UTMI_AFE_RX_REG5 0x12
#define UTMI_AFE_BC_REG4 0x29
/* Align UTMI_AFE_RX_REG0 bit[7:6] define */
enum usb2_disconn_threshold {
USB2_DISCONN_THRESHOLD_575 = 0x0,
USB2_DISCONN_THRESHOLD_610 = 0x1,
USB2_DISCONN_THRESHOLD_645 = 0x3,
};
#define RX_USB2_DISCONN_MASK GENMASK(7, 6)
/* TB_ADDR_TX_RCVDETSC_CTRL */ /* TB_ADDR_TX_RCVDETSC_CTRL */
#define RXDET_IN_P3_32KHZ BIT(0) #define RXDET_IN_P3_32KHZ BIT(0)
/*
* UTMI_REG15
*
* Gate how many us for the txvalid signal until analog
* HS/FS transmitters have powered up
*/
#define TXVALID_GATE_THRESHOLD_HS_MASK (BIT(4) | BIT(5))
/* 0us, txvalid is ready just after HS/FS transmitters have powered up */
#define TXVALID_GATE_THRESHOLD_HS_0US (BIT(4) | BIT(5))
#define SET_B_SESSION_VALID (BIT(6) | BIT(5))
#define CLR_B_SESSION_VALID (BIT(6))
struct cdns_reg_pairs { struct cdns_reg_pairs {
u16 val; u16 val;
...@@ -106,19 +136,27 @@ struct cdns_salvo_phy { ...@@ -106,19 +136,27 @@ struct cdns_salvo_phy {
struct clk *clk; struct clk *clk;
void __iomem *base; void __iomem *base;
struct cdns_salvo_data *data; struct cdns_salvo_data *data;
enum usb2_disconn_threshold usb2_disconn;
}; };
static const struct of_device_id cdns_salvo_phy_of_match[]; static const struct of_device_id cdns_salvo_phy_of_match[];
static u16 cdns_salvo_read(struct cdns_salvo_phy *salvo_phy, u32 reg) static const struct cdns_salvo_data cdns_nxp_salvo_data;
static bool cdns_is_nxp_phy(struct cdns_salvo_phy *salvo_phy)
{
return salvo_phy->data == &cdns_nxp_salvo_data;
}
static u16 cdns_salvo_read(struct cdns_salvo_phy *salvo_phy, u32 offset, u32 reg)
{ {
return (u16)readl(salvo_phy->base + return (u16)readl(salvo_phy->base + offset +
reg * (1 << salvo_phy->data->reg_offset_shift)); reg * (1 << salvo_phy->data->reg_offset_shift));
} }
static void cdns_salvo_write(struct cdns_salvo_phy *salvo_phy, static void cdns_salvo_write(struct cdns_salvo_phy *salvo_phy, u32 offset,
u32 reg, u16 val) u32 reg, u16 val)
{ {
writel(val, salvo_phy->base + writel(val, salvo_phy->base + offset +
reg * (1 << salvo_phy->data->reg_offset_shift)); reg * (1 << salvo_phy->data->reg_offset_shift));
} }
...@@ -219,15 +257,27 @@ static int cdns_salvo_phy_init(struct phy *phy) ...@@ -219,15 +257,27 @@ static int cdns_salvo_phy_init(struct phy *phy)
for (i = 0; i < data->init_sequence_length; i++) { for (i = 0; i < data->init_sequence_length; i++) {
const struct cdns_reg_pairs *reg_pair = data->init_sequence_val + i; const struct cdns_reg_pairs *reg_pair = data->init_sequence_val + i;
cdns_salvo_write(salvo_phy, reg_pair->off, reg_pair->val); cdns_salvo_write(salvo_phy, USB3_PHY_OFFSET, reg_pair->off, reg_pair->val);
} }
/* RXDET_IN_P3_32KHZ, Receiver detect slow clock enable */ /* RXDET_IN_P3_32KHZ, Receiver detect slow clock enable */
value = cdns_salvo_read(salvo_phy, TB_ADDR_TX_RCVDETSC_CTRL); value = cdns_salvo_read(salvo_phy, USB3_PHY_OFFSET, TB_ADDR_TX_RCVDETSC_CTRL);
value |= RXDET_IN_P3_32KHZ; value |= RXDET_IN_P3_32KHZ;
cdns_salvo_write(salvo_phy, TB_ADDR_TX_RCVDETSC_CTRL, cdns_salvo_write(salvo_phy, USB3_PHY_OFFSET, TB_ADDR_TX_RCVDETSC_CTRL,
RXDET_IN_P3_32KHZ); RXDET_IN_P3_32KHZ);
value = cdns_salvo_read(salvo_phy, USB2_PHY_OFFSET, UTMI_REG15);
value &= ~TXVALID_GATE_THRESHOLD_HS_MASK;
cdns_salvo_write(salvo_phy, USB2_PHY_OFFSET, UTMI_REG15,
value | TXVALID_GATE_THRESHOLD_HS_0US);
cdns_salvo_write(salvo_phy, USB2_PHY_OFFSET, UTMI_AFE_RX_REG5, 0x5);
value = cdns_salvo_read(salvo_phy, USB2_PHY_OFFSET, UTMI_AFE_RX_REG0);
value &= ~RX_USB2_DISCONN_MASK;
value = FIELD_PREP(RX_USB2_DISCONN_MASK, salvo_phy->usb2_disconn);
cdns_salvo_write(salvo_phy, USB2_PHY_OFFSET, UTMI_AFE_RX_REG0, value);
udelay(10); udelay(10);
clk_disable_unprepare(salvo_phy->clk); clk_disable_unprepare(salvo_phy->clk);
...@@ -251,11 +301,29 @@ static int cdns_salvo_phy_power_off(struct phy *phy) ...@@ -251,11 +301,29 @@ static int cdns_salvo_phy_power_off(struct phy *phy)
return 0; return 0;
} }
static int cdns_salvo_set_mode(struct phy *phy, enum phy_mode mode, int submode)
{
struct cdns_salvo_phy *salvo_phy = phy_get_drvdata(phy);
if (!cdns_is_nxp_phy(salvo_phy))
return 0;
if (mode == PHY_MODE_USB_DEVICE)
cdns_salvo_write(salvo_phy, USB2_PHY_OFFSET, UTMI_AFE_BC_REG4,
SET_B_SESSION_VALID);
else
cdns_salvo_write(salvo_phy, USB2_PHY_OFFSET, UTMI_AFE_BC_REG4,
CLR_B_SESSION_VALID);
return 0;
}
static const struct phy_ops cdns_salvo_phy_ops = { static const struct phy_ops cdns_salvo_phy_ops = {
.init = cdns_salvo_phy_init, .init = cdns_salvo_phy_init,
.power_on = cdns_salvo_phy_power_on, .power_on = cdns_salvo_phy_power_on,
.power_off = cdns_salvo_phy_power_off, .power_off = cdns_salvo_phy_power_off,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.set_mode = cdns_salvo_set_mode,
}; };
static int cdns_salvo_phy_probe(struct platform_device *pdev) static int cdns_salvo_phy_probe(struct platform_device *pdev)
...@@ -264,6 +332,7 @@ static int cdns_salvo_phy_probe(struct platform_device *pdev) ...@@ -264,6 +332,7 @@ static int cdns_salvo_phy_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct cdns_salvo_phy *salvo_phy; struct cdns_salvo_phy *salvo_phy;
struct cdns_salvo_data *data; struct cdns_salvo_data *data;
u32 val;
data = (struct cdns_salvo_data *)of_device_get_match_data(dev); data = (struct cdns_salvo_data *)of_device_get_match_data(dev);
salvo_phy = devm_kzalloc(dev, sizeof(*salvo_phy), GFP_KERNEL); salvo_phy = devm_kzalloc(dev, sizeof(*salvo_phy), GFP_KERNEL);
...@@ -275,6 +344,16 @@ static int cdns_salvo_phy_probe(struct platform_device *pdev) ...@@ -275,6 +344,16 @@ static int cdns_salvo_phy_probe(struct platform_device *pdev)
if (IS_ERR(salvo_phy->clk)) if (IS_ERR(salvo_phy->clk))
return PTR_ERR(salvo_phy->clk); return PTR_ERR(salvo_phy->clk);
if (of_property_read_u32(dev->of_node, "cdns,usb2-disconnect-threshold-microvolt", &val))
val = 575;
if (val < 610)
salvo_phy->usb2_disconn = USB2_DISCONN_THRESHOLD_575;
else if (val < 645)
salvo_phy->usb2_disconn = USB2_DISCONN_THRESHOLD_610;
else
salvo_phy->usb2_disconn = USB2_DISCONN_THRESHOLD_645;
salvo_phy->base = devm_platform_ioremap_resource(pdev, 0); salvo_phy->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(salvo_phy->base)) if (IS_ERR(salvo_phy->base))
return PTR_ERR(salvo_phy->base); return PTR_ERR(salvo_phy->base);
......
...@@ -38,6 +38,9 @@ ...@@ -38,6 +38,9 @@
#define POLL_TIMEOUT_US 5000 #define POLL_TIMEOUT_US 5000
#define PLL_LOCK_TIMEOUT 100000 #define PLL_LOCK_TIMEOUT 100000
#define DP_PLL0 BIT(0)
#define DP_PLL1 BIT(1)
#define TORRENT_COMMON_CDB_OFFSET 0x0 #define TORRENT_COMMON_CDB_OFFSET 0x0
#define TORRENT_TX_LANE_CDB_OFFSET(ln, block_offset, reg_offset) \ #define TORRENT_TX_LANE_CDB_OFFSET(ln, block_offset, reg_offset) \
...@@ -66,16 +69,11 @@ ...@@ -66,16 +69,11 @@
*/ */
#define PHY_AUX_CTRL 0x04 #define PHY_AUX_CTRL 0x04
#define PHY_RESET 0x20 #define PHY_RESET 0x20
#define PMA_TX_ELEC_IDLE_MASK 0xF0U
#define PMA_TX_ELEC_IDLE_SHIFT 4 #define PMA_TX_ELEC_IDLE_SHIFT 4
#define PHY_L00_RESET_N_MASK 0x01U
#define PHY_PMA_XCVR_PLLCLK_EN 0x24 #define PHY_PMA_XCVR_PLLCLK_EN 0x24
#define PHY_PMA_XCVR_PLLCLK_EN_ACK 0x28 #define PHY_PMA_XCVR_PLLCLK_EN_ACK 0x28
#define PHY_PMA_XCVR_POWER_STATE_REQ 0x2c #define PHY_PMA_XCVR_POWER_STATE_REQ 0x2c
#define PHY_POWER_STATE_LN_0 0x0000 #define PHY_POWER_STATE_LN(ln) ((ln) * 8)
#define PHY_POWER_STATE_LN_1 0x0008
#define PHY_POWER_STATE_LN_2 0x0010
#define PHY_POWER_STATE_LN_3 0x0018
#define PMA_XCVR_POWER_STATE_REQ_LN_MASK 0x3FU #define PMA_XCVR_POWER_STATE_REQ_LN_MASK 0x3FU
#define PHY_PMA_XCVR_POWER_STATE_ACK 0x30 #define PHY_PMA_XCVR_POWER_STATE_ACK 0x30
#define PHY_PMA_CMN_READY 0x34 #define PHY_PMA_CMN_READY 0x34
...@@ -323,6 +321,7 @@ struct cdns_torrent_phy { ...@@ -323,6 +321,7 @@ struct cdns_torrent_phy {
void __iomem *base; /* DPTX registers base */ void __iomem *base; /* DPTX registers base */
void __iomem *sd_base; /* SD0801 registers base */ void __iomem *sd_base; /* SD0801 registers base */
u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */ u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */
u32 dp_pll;
struct reset_control *phy_rst; struct reset_control *phy_rst;
struct reset_control *apb_rst; struct reset_control *apb_rst;
struct device *dev; struct device *dev;
...@@ -905,88 +904,129 @@ void cdns_torrent_dp_pma_cmn_vco_cfg_100mhz(struct cdns_torrent_phy *cdns_phy, ...@@ -905,88 +904,129 @@ void cdns_torrent_dp_pma_cmn_vco_cfg_100mhz(struct cdns_torrent_phy *cdns_phy,
/* Setting VCO for 10.8GHz */ /* Setting VCO for 10.8GHz */
case 2700: case 2700:
case 5400: case 5400:
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0028); if (cdns_phy->dp_pll & DP_PLL0)
cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_FBH_OVRD_M0, 0x0022); cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_FBH_OVRD_M0, 0x0022);
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_FBH_OVRD_M0, 0x0022);
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_FBL_OVRD_M0, 0x000C); if (cdns_phy->dp_pll & DP_PLL1) {
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0028);
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_FBH_OVRD_M0, 0x0022);
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_FBL_OVRD_M0, 0x000C);
}
break; break;
/* Setting VCO for 9.72GHz */ /* Setting VCO for 9.72GHz */
case 1620: case 1620:
case 2430: case 2430:
case 3240: case 3240:
cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); if (cdns_phy->dp_pll & DP_PLL0) {
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0061);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x3333);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0061); cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0042);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0061); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x3333); }
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x3333); if (cdns_phy->dp_pll & DP_PLL1) {
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0042); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0042); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002); cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0061);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002); cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x3333);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0042);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
}
break; break;
/* Setting VCO for 8.64GHz */ /* Setting VCO for 8.64GHz */
case 2160: case 2160:
case 4320: case 4320:
cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); if (cdns_phy->dp_pll & DP_PLL0) {
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0056);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x6666);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0056); cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x003A);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0056); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x6666); }
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x6666); if (cdns_phy->dp_pll & DP_PLL1) {
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x003A); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x003A); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002); cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0056);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002); cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x6666);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x003A);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
}
break; break;
/* Setting VCO for 8.1GHz */ /* Setting VCO for 8.1GHz */
case 8100: case 8100:
cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); if (cdns_phy->dp_pll & DP_PLL0) {
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0051);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0036);
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0051); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0051); }
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); if (cdns_phy->dp_pll & DP_PLL1) {
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0036); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0036); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002); cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002); cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0051);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0036);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
}
break; break;
} }
} }
/* Set PLL used for DP configuration */
static int cdns_torrent_dp_get_pll(struct cdns_torrent_phy *cdns_phy,
enum cdns_torrent_phy_type phy_t2)
{
switch (phy_t2) {
case TYPE_PCIE:
case TYPE_USB:
cdns_phy->dp_pll = DP_PLL1;
break;
case TYPE_SGMII:
case TYPE_QSGMII:
cdns_phy->dp_pll = DP_PLL0;
break;
case TYPE_NONE:
cdns_phy->dp_pll = DP_PLL0 | DP_PLL1;
break;
default:
dev_err(cdns_phy->dev, "Unsupported PHY configuration\n");
return -EINVAL;
}
return 0;
}
/* /*
* Enable or disable PLL for selected lanes. * Enable or disable PLL for selected lanes.
*/ */
static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy, static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst,
struct phy_configure_opts_dp *dp, struct phy_configure_opts_dp *dp,
bool enable) bool enable)
{ {
u32 rd_val;
u32 ret;
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
u32 rd_val, pll_ack_val;
int ret;
/* /*
* Used to determine, which bits to check for or enable in * Used to determine, which bits to check for or enable in
...@@ -996,28 +1036,18 @@ static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy, ...@@ -996,28 +1036,18 @@ static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy,
/* Used to enable or disable lanes. */ /* Used to enable or disable lanes. */
u32 pll_val; u32 pll_val;
/* Select values of registers and mask, depending on enabled lane /* Select values of registers and mask, depending on enabled lane count. */
* count. pll_val = cdns_torrent_dp_read(regmap, PHY_PMA_XCVR_PLLCLK_EN);
*/
switch (dp->lanes) {
/* lane 0 */
case (1):
pll_bits = 0x00000001;
break;
/* lanes 0-1 */
case (2):
pll_bits = 0x00000003;
break;
/* lanes 0-3, all */
default:
pll_bits = 0x0000000F;
break;
}
if (enable) if (enable) {
pll_val = pll_bits; pll_bits = ((1 << dp->lanes) - 1);
else pll_val |= pll_bits;
pll_val = 0x00000000; pll_ack_val = pll_bits;
} else {
pll_bits = ((1 << inst->num_lanes) - 1);
pll_val &= (~pll_bits);
pll_ack_val = 0;
}
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_val); cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_val);
...@@ -1025,22 +1055,23 @@ static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy, ...@@ -1025,22 +1055,23 @@ static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy,
ret = regmap_read_poll_timeout(regmap, ret = regmap_read_poll_timeout(regmap,
PHY_PMA_XCVR_PLLCLK_EN_ACK, PHY_PMA_XCVR_PLLCLK_EN_ACK,
rd_val, rd_val,
(rd_val & pll_bits) == pll_val, (rd_val & pll_bits) == pll_ack_val,
0, POLL_TIMEOUT_US); 0, POLL_TIMEOUT_US);
ndelay(100); ndelay(100);
return ret; return ret;
} }
static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy, static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst,
u32 num_lanes, u32 num_lanes,
enum phy_powerstate powerstate) enum phy_powerstate powerstate)
{ {
/* Register value for power state for a single byte. */ /* Register value for power state for a single byte. */
u32 value_part; u32 value_part, i;
u32 value; u32 value = 0;
u32 mask; u32 mask = 0;
u32 read_val; u32 read_val;
u32 ret; int ret;
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
switch (powerstate) { switch (powerstate) {
...@@ -1056,29 +1087,11 @@ static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy, ...@@ -1056,29 +1087,11 @@ static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy,
break; break;
} }
/* Select values of registers and mask, depending on enabled /* Select values of registers and mask, depending on enabled lane count. */
* lane count.
*/ for (i = 0; i < num_lanes; i++) {
switch (num_lanes) { value |= (value_part << PHY_POWER_STATE_LN(i));
/* lane 0 */ mask |= (PMA_XCVR_POWER_STATE_REQ_LN_MASK << PHY_POWER_STATE_LN(i));
case (1):
value = value_part;
mask = 0x0000003FU;
break;
/* lanes 0-1 */
case (2):
value = (value_part
| (value_part << 8));
mask = 0x00003F3FU;
break;
/* lanes 0-3, all */
default:
value = (value_part
| (value_part << 8)
| (value_part << 16)
| (value_part << 24));
mask = 0x3F3F3F3FU;
break;
} }
/* Set power state A<n>. */ /* Set power state A<n>. */
...@@ -1093,7 +1106,8 @@ static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy, ...@@ -1093,7 +1106,8 @@ static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy,
return ret; return ret;
} }
static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes) static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst, u32 num_lanes)
{ {
unsigned int read_val; unsigned int read_val;
int ret; int ret;
...@@ -1114,12 +1128,12 @@ static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes) ...@@ -1114,12 +1128,12 @@ static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes)
ndelay(100); ndelay(100);
ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes, ret = cdns_torrent_dp_set_power_state(cdns_phy, inst, num_lanes,
POWERSTATE_A2); POWERSTATE_A2);
if (ret) if (ret)
return ret; return ret;
ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes, ret = cdns_torrent_dp_set_power_state(cdns_phy, inst, num_lanes,
POWERSTATE_A0); POWERSTATE_A0);
return ret; return ret;
...@@ -1143,6 +1157,7 @@ static int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy) ...@@ -1143,6 +1157,7 @@ static int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy)
} }
static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy, static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst,
u32 rate, u32 num_lanes) u32 rate, u32 num_lanes)
{ {
unsigned int clk_sel_val = 0; unsigned int clk_sel_val = 0;
...@@ -1175,14 +1190,17 @@ static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy, ...@@ -1175,14 +1190,17 @@ static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy,
break; break;
} }
cdns_torrent_phy_write(cdns_phy->regmap_common_cdb, if (cdns_phy->dp_pll & DP_PLL0)
CMN_PDIAG_PLL0_CLK_SEL_M0, clk_sel_val); cdns_torrent_phy_write(cdns_phy->regmap_common_cdb,
cdns_torrent_phy_write(cdns_phy->regmap_common_cdb, CMN_PDIAG_PLL0_CLK_SEL_M0, clk_sel_val);
CMN_PDIAG_PLL1_CLK_SEL_M0, clk_sel_val);
if (cdns_phy->dp_pll & DP_PLL1)
cdns_torrent_phy_write(cdns_phy->regmap_common_cdb,
CMN_PDIAG_PLL1_CLK_SEL_M0, clk_sel_val);
/* PMA lane configuration to deal with multi-link operation */ /* PMA lane configuration to deal with multi-link operation */
for (i = 0; i < num_lanes; i++) for (i = 0; i < num_lanes; i++)
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[i], cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[inst->mlane + i],
XCVR_DIAG_HSCLK_DIV, hsclk_div_val); XCVR_DIAG_HSCLK_DIV, hsclk_div_val);
} }
...@@ -1191,23 +1209,44 @@ static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy, ...@@ -1191,23 +1209,44 @@ static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy,
* set and PLL disable request was processed. * set and PLL disable request was processed.
*/ */
static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy, static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst,
struct phy_configure_opts_dp *dp) struct phy_configure_opts_dp *dp)
{ {
u32 read_val, ret; u32 read_val, field_val;
int ret;
/* Disable the cmn_pll0_en before re-programming the new data rate. */ /*
regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x0); * Disable the associated PLL (cmn_pll0_en or cmn_pll1_en) before
* re-programming the new data rate.
*/
ret = regmap_field_read(cdns_phy->phy_pma_pll_raw_ctrl, &field_val);
if (ret)
return ret;
field_val &= ~(cdns_phy->dp_pll);
regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, field_val);
/* /*
* Wait for PLL ready de-assertion. * Wait for PLL ready de-assertion.
* For PLL0 - PHY_PMA_CMN_CTRL2[2] == 1 * For PLL0 - PHY_PMA_CMN_CTRL2[2] == 1
* For PLL1 - PHY_PMA_CMN_CTRL2[3] == 1
*/ */
ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2, if (cdns_phy->dp_pll & DP_PLL0) {
read_val, ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2,
((read_val >> 2) & 0x01) != 0, read_val,
0, POLL_TIMEOUT_US); ((read_val >> 2) & 0x01) != 0,
if (ret) 0, POLL_TIMEOUT_US);
return ret; if (ret)
return ret;
}
if ((cdns_phy->dp_pll & DP_PLL1) && cdns_phy->nsubnodes != 1) {
ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2,
read_val,
((read_val >> 3) & 0x01) != 0,
0, POLL_TIMEOUT_US);
if (ret)
return ret;
}
ndelay(200); ndelay(200);
/* DP Rate Change - VCO Output settings. */ /* DP Rate Change - VCO Output settings. */
...@@ -1221,19 +1260,35 @@ static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy, ...@@ -1221,19 +1260,35 @@ static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy,
/* PMA common configuration 100MHz */ /* PMA common configuration 100MHz */
cdns_torrent_dp_pma_cmn_vco_cfg_100mhz(cdns_phy, dp->link_rate, dp->ssc); cdns_torrent_dp_pma_cmn_vco_cfg_100mhz(cdns_phy, dp->link_rate, dp->ssc);
cdns_torrent_dp_pma_cmn_rate(cdns_phy, dp->link_rate, dp->lanes); cdns_torrent_dp_pma_cmn_rate(cdns_phy, inst, dp->link_rate, dp->lanes);
/* Enable the cmn_pll0_en. */ /* Enable the associated PLL (cmn_pll0_en or cmn_pll1_en) */
regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x3); ret = regmap_field_read(cdns_phy->phy_pma_pll_raw_ctrl, &field_val);
if (ret)
return ret;
field_val |= cdns_phy->dp_pll;
regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, field_val);
/* /*
* Wait for PLL ready assertion. * Wait for PLL ready assertion.
* For PLL0 - PHY_PMA_CMN_CTRL2[0] == 1 * For PLL0 - PHY_PMA_CMN_CTRL2[0] == 1
* For PLL1 - PHY_PMA_CMN_CTRL2[1] == 1
*/ */
ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2, if (cdns_phy->dp_pll & DP_PLL0) {
read_val, ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2,
(read_val & 0x01) != 0, read_val,
0, POLL_TIMEOUT_US); (read_val & 0x01) != 0,
0, POLL_TIMEOUT_US);
if (ret)
return ret;
}
if ((cdns_phy->dp_pll & DP_PLL1) && cdns_phy->nsubnodes != 1)
ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2,
read_val,
((read_val >> 1) & 0x01) != 0,
0, POLL_TIMEOUT_US);
return ret; return ret;
} }
...@@ -1301,6 +1356,7 @@ static int cdns_torrent_dp_verify_config(struct cdns_torrent_inst *inst, ...@@ -1301,6 +1356,7 @@ static int cdns_torrent_dp_verify_config(struct cdns_torrent_inst *inst,
/* Set power state A0 and PLL clock enable to 0 on enabled lanes. */ /* Set power state A0 and PLL clock enable to 0 on enabled lanes. */
static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy, static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst,
u32 num_lanes) u32 num_lanes)
{ {
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
...@@ -1308,27 +1364,13 @@ static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy, ...@@ -1308,27 +1364,13 @@ static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy,
PHY_PMA_XCVR_POWER_STATE_REQ); PHY_PMA_XCVR_POWER_STATE_REQ);
u32 pll_clk_en = cdns_torrent_dp_read(regmap, u32 pll_clk_en = cdns_torrent_dp_read(regmap,
PHY_PMA_XCVR_PLLCLK_EN); PHY_PMA_XCVR_PLLCLK_EN);
u32 i;
/* Lane 0 is always enabled. */ for (i = 0; i < num_lanes; i++) {
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK
PHY_POWER_STATE_LN_0); << PHY_POWER_STATE_LN(inst->mlane + i));
pll_clk_en &= ~0x01U;
if (num_lanes > 1) {
/* lane 1 */
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
PHY_POWER_STATE_LN_1);
pll_clk_en &= ~(0x01U << 1);
}
if (num_lanes > 2) { pll_clk_en &= ~(0x01U << (inst->mlane + i));
/* lanes 2 and 3 */
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
PHY_POWER_STATE_LN_2);
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
PHY_POWER_STATE_LN_3);
pll_clk_en &= ~(0x01U << 2);
pll_clk_en &= ~(0x01U << 3);
} }
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, pwr_state); cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, pwr_state);
...@@ -1337,36 +1379,57 @@ static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy, ...@@ -1337,36 +1379,57 @@ static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy,
/* Configure lane count as required. */ /* Configure lane count as required. */
static int cdns_torrent_dp_set_lanes(struct cdns_torrent_phy *cdns_phy, static int cdns_torrent_dp_set_lanes(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst,
struct phy_configure_opts_dp *dp) struct phy_configure_opts_dp *dp)
{ {
u32 value; u32 value, i;
u32 ret; int ret;
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
u8 lane_mask = (1 << dp->lanes) - 1; u8 lane_mask = (1 << dp->lanes) - 1;
u8 pma_tx_elec_idle_mask = 0;
u32 clane = inst->mlane;
lane_mask <<= clane;
value = cdns_torrent_dp_read(regmap, PHY_RESET); value = cdns_torrent_dp_read(regmap, PHY_RESET);
/* clear pma_tx_elec_idle_ln_* bits. */ /* clear pma_tx_elec_idle_ln_* bits. */
value &= ~PMA_TX_ELEC_IDLE_MASK; pma_tx_elec_idle_mask = ((1 << inst->num_lanes) - 1) << clane;
pma_tx_elec_idle_mask <<= PMA_TX_ELEC_IDLE_SHIFT;
value &= ~pma_tx_elec_idle_mask;
/* Assert pma_tx_elec_idle_ln_* for disabled lanes. */ /* Assert pma_tx_elec_idle_ln_* for disabled lanes. */
value |= ((~lane_mask) << PMA_TX_ELEC_IDLE_SHIFT) & value |= ((~lane_mask) << PMA_TX_ELEC_IDLE_SHIFT) &
PMA_TX_ELEC_IDLE_MASK; pma_tx_elec_idle_mask;
cdns_torrent_dp_write(regmap, PHY_RESET, value); cdns_torrent_dp_write(regmap, PHY_RESET, value);
/* reset the link by asserting phy_l00_reset_n low */ /* reset the link by asserting master lane phy_l0*_reset_n low */
cdns_torrent_dp_write(regmap, PHY_RESET, cdns_torrent_dp_write(regmap, PHY_RESET,
value & (~PHY_L00_RESET_N_MASK)); value & (~(1 << clane)));
/* /*
* Assert lane reset on unused lanes and lane 0 so they remain in reset * Assert lane reset on unused lanes and master lane so they remain in reset
* and powered down when re-enabling the link * and powered down when re-enabling the link
*/ */
value = (value & 0x0000FFF0) | (0x0000000E & lane_mask); for (i = 0; i < inst->num_lanes; i++)
value &= (~(1 << (clane + i)));
for (i = 1; i < inst->num_lanes; i++)
value |= ((1 << (clane + i)) & lane_mask);
cdns_torrent_dp_write(regmap, PHY_RESET, value); cdns_torrent_dp_write(regmap, PHY_RESET, value);
cdns_torrent_dp_set_a0_pll(cdns_phy, dp->lanes); cdns_torrent_dp_set_a0_pll(cdns_phy, inst, dp->lanes);
/* release phy_l0*_reset_n based on used laneCount */ /* release phy_l0*_reset_n based on used laneCount */
value = (value & 0x0000FFF0) | (0x0000000F & lane_mask); for (i = 0; i < inst->num_lanes; i++)
value &= (~(1 << (clane + i)));
for (i = 0; i < inst->num_lanes; i++)
value |= ((1 << (clane + i)) & lane_mask);
cdns_torrent_dp_write(regmap, PHY_RESET, value); cdns_torrent_dp_write(regmap, PHY_RESET, value);
/* Wait, until PHY gets ready after releasing PHY reset signal. */ /* Wait, until PHY gets ready after releasing PHY reset signal. */
...@@ -1377,41 +1440,44 @@ static int cdns_torrent_dp_set_lanes(struct cdns_torrent_phy *cdns_phy, ...@@ -1377,41 +1440,44 @@ static int cdns_torrent_dp_set_lanes(struct cdns_torrent_phy *cdns_phy,
ndelay(100); ndelay(100);
/* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001); value = cdns_torrent_dp_read(regmap, PHY_PMA_XCVR_PLLCLK_EN);
value |= (1 << clane);
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, value);
ret = cdns_torrent_dp_run(cdns_phy, dp->lanes); ret = cdns_torrent_dp_run(cdns_phy, inst, dp->lanes);
return ret; return ret;
} }
/* Configure link rate as required. */ /* Configure link rate as required. */
static int cdns_torrent_dp_set_rate(struct cdns_torrent_phy *cdns_phy, static int cdns_torrent_dp_set_rate(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst,
struct phy_configure_opts_dp *dp) struct phy_configure_opts_dp *dp)
{ {
u32 ret; int ret;
ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, ret = cdns_torrent_dp_set_power_state(cdns_phy, inst, dp->lanes,
POWERSTATE_A3); POWERSTATE_A3);
if (ret) if (ret)
return ret; return ret;
ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, false); ret = cdns_torrent_dp_set_pll_en(cdns_phy, inst, dp, false);
if (ret) if (ret)
return ret; return ret;
ndelay(200); ndelay(200);
ret = cdns_torrent_dp_configure_rate(cdns_phy, dp); ret = cdns_torrent_dp_configure_rate(cdns_phy, inst, dp);
if (ret) if (ret)
return ret; return ret;
ndelay(200); ndelay(200);
ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, true); ret = cdns_torrent_dp_set_pll_en(cdns_phy, inst, dp, true);
if (ret) if (ret)
return ret; return ret;
ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, ret = cdns_torrent_dp_set_power_state(cdns_phy, inst, dp->lanes,
POWERSTATE_A2); POWERSTATE_A2);
if (ret) if (ret)
return ret; return ret;
ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, ret = cdns_torrent_dp_set_power_state(cdns_phy, inst, dp->lanes,
POWERSTATE_A0); POWERSTATE_A0);
if (ret) if (ret)
return ret; return ret;
...@@ -1422,44 +1488,45 @@ static int cdns_torrent_dp_set_rate(struct cdns_torrent_phy *cdns_phy, ...@@ -1422,44 +1488,45 @@ static int cdns_torrent_dp_set_rate(struct cdns_torrent_phy *cdns_phy,
/* Configure voltage swing and pre-emphasis for all enabled lanes. */ /* Configure voltage swing and pre-emphasis for all enabled lanes. */
static void cdns_torrent_dp_set_voltages(struct cdns_torrent_phy *cdns_phy, static void cdns_torrent_dp_set_voltages(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst,
struct phy_configure_opts_dp *dp) struct phy_configure_opts_dp *dp)
{ {
u8 lane; u8 lane;
u16 val; u16 val;
for (lane = 0; lane < dp->lanes; lane++) { for (lane = 0; lane < dp->lanes; lane++) {
val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane], val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[inst->mlane + lane],
TX_DIAG_ACYA); TX_DIAG_ACYA);
/* /*
* Write 1 to register bit TX_DIAG_ACYA[0] to freeze the * Write 1 to register bit TX_DIAG_ACYA[0] to freeze the
* current state of the analog TX driver. * current state of the analog TX driver.
*/ */
val |= TX_DIAG_ACYA_HBDC_MASK; val |= TX_DIAG_ACYA_HBDC_MASK;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[inst->mlane + lane],
TX_DIAG_ACYA, val); TX_DIAG_ACYA, val);
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[inst->mlane + lane],
TX_TXCC_CTRL, 0x08A4); TX_TXCC_CTRL, 0x08A4);
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].diag_tx_drv; val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].diag_tx_drv;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[inst->mlane + lane],
DRV_DIAG_TX_DRV, val); DRV_DIAG_TX_DRV, val);
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].mgnfs_mult; val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].mgnfs_mult;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[inst->mlane + lane],
TX_TXCC_MGNFS_MULT_000, TX_TXCC_MGNFS_MULT_000,
val); val);
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].cpost_mult; val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].cpost_mult;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[inst->mlane + lane],
TX_TXCC_CPOST_MULT_00, TX_TXCC_CPOST_MULT_00,
val); val);
val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane], val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[inst->mlane + lane],
TX_DIAG_ACYA); TX_DIAG_ACYA);
/* /*
* Write 0 to register bit TX_DIAG_ACYA[0] to allow the state of * Write 0 to register bit TX_DIAG_ACYA[0] to allow the state of
* analog TX driver to reflect the new programmed one. * analog TX driver to reflect the new programmed one.
*/ */
val &= ~TX_DIAG_ACYA_HBDC_MASK; val &= ~TX_DIAG_ACYA_HBDC_MASK;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[inst->mlane + lane],
TX_DIAG_ACYA, val); TX_DIAG_ACYA, val);
} }
}; };
...@@ -1478,7 +1545,7 @@ static int cdns_torrent_dp_configure(struct phy *phy, ...@@ -1478,7 +1545,7 @@ static int cdns_torrent_dp_configure(struct phy *phy,
} }
if (opts->dp.set_lanes) { if (opts->dp.set_lanes) {
ret = cdns_torrent_dp_set_lanes(cdns_phy, &opts->dp); ret = cdns_torrent_dp_set_lanes(cdns_phy, inst, &opts->dp);
if (ret) { if (ret) {
dev_err(&phy->dev, "cdns_torrent_dp_set_lanes failed\n"); dev_err(&phy->dev, "cdns_torrent_dp_set_lanes failed\n");
return ret; return ret;
...@@ -1486,7 +1553,7 @@ static int cdns_torrent_dp_configure(struct phy *phy, ...@@ -1486,7 +1553,7 @@ static int cdns_torrent_dp_configure(struct phy *phy,
} }
if (opts->dp.set_rate) { if (opts->dp.set_rate) {
ret = cdns_torrent_dp_set_rate(cdns_phy, &opts->dp); ret = cdns_torrent_dp_set_rate(cdns_phy, inst, &opts->dp);
if (ret) { if (ret) {
dev_err(&phy->dev, "cdns_torrent_dp_set_rate failed\n"); dev_err(&phy->dev, "cdns_torrent_dp_set_rate failed\n");
return ret; return ret;
...@@ -1494,7 +1561,7 @@ static int cdns_torrent_dp_configure(struct phy *phy, ...@@ -1494,7 +1561,7 @@ static int cdns_torrent_dp_configure(struct phy *phy,
} }
if (opts->dp.set_voltages) if (opts->dp.set_voltages)
cdns_torrent_dp_set_voltages(cdns_phy, &opts->dp); cdns_torrent_dp_set_voltages(cdns_phy, inst, &opts->dp);
return ret; return ret;
} }
...@@ -1562,6 +1629,7 @@ static void cdns_torrent_dp_common_init(struct cdns_torrent_phy *cdns_phy, ...@@ -1562,6 +1629,7 @@ static void cdns_torrent_dp_common_init(struct cdns_torrent_phy *cdns_phy,
{ {
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
unsigned char lane_bits; unsigned char lane_bits;
u32 val;
cdns_torrent_dp_write(regmap, PHY_AUX_CTRL, 0x0003); /* enable AUX */ cdns_torrent_dp_write(regmap, PHY_AUX_CTRL, 0x0003); /* enable AUX */
...@@ -1569,18 +1637,23 @@ static void cdns_torrent_dp_common_init(struct cdns_torrent_phy *cdns_phy, ...@@ -1569,18 +1637,23 @@ static void cdns_torrent_dp_common_init(struct cdns_torrent_phy *cdns_phy,
* Set lines power state to A0 * Set lines power state to A0
* Set lines pll clk enable to 0 * Set lines pll clk enable to 0
*/ */
cdns_torrent_dp_set_a0_pll(cdns_phy, inst->num_lanes); cdns_torrent_dp_set_a0_pll(cdns_phy, inst, inst->num_lanes);
/* /*
* release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on * release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on
* used lanes * used lanes
*/ */
lane_bits = (1 << inst->num_lanes) - 1; lane_bits = (1 << inst->num_lanes) - 1;
cdns_torrent_dp_write(regmap, PHY_RESET,
((0xF & ~lane_bits) << 4) | (0xF & lane_bits)); val = cdns_torrent_dp_read(regmap, PHY_RESET);
val |= (0xF & lane_bits);
val &= ~(lane_bits << 4);
cdns_torrent_dp_write(regmap, PHY_RESET, val);
/* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001); val = cdns_torrent_dp_read(regmap, PHY_PMA_XCVR_PLLCLK_EN);
val |= 1;
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, val);
/* /*
* PHY PMA registers configuration functions * PHY PMA registers configuration functions
...@@ -1599,7 +1672,7 @@ static void cdns_torrent_dp_common_init(struct cdns_torrent_phy *cdns_phy, ...@@ -1599,7 +1672,7 @@ static void cdns_torrent_dp_common_init(struct cdns_torrent_phy *cdns_phy,
cdns_phy->max_bit_rate, cdns_phy->max_bit_rate,
false); false);
cdns_torrent_dp_pma_cmn_rate(cdns_phy, cdns_phy->max_bit_rate, cdns_torrent_dp_pma_cmn_rate(cdns_phy, inst, cdns_phy->max_bit_rate,
inst->num_lanes); inst->num_lanes);
/* take out of reset */ /* take out of reset */
...@@ -1612,13 +1685,15 @@ static int cdns_torrent_dp_start(struct cdns_torrent_phy *cdns_phy, ...@@ -1612,13 +1685,15 @@ static int cdns_torrent_dp_start(struct cdns_torrent_phy *cdns_phy,
{ {
int ret; int ret;
cdns_torrent_phy_on(phy); ret = cdns_torrent_phy_on(phy);
if (ret)
return ret;
ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy); ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy);
if (ret) if (ret)
return ret; return ret;
ret = cdns_torrent_dp_run(cdns_phy, inst->num_lanes); ret = cdns_torrent_dp_run(cdns_phy, inst, inst->num_lanes);
return ret; return ret;
} }
...@@ -1627,6 +1702,7 @@ static int cdns_torrent_dp_init(struct phy *phy) ...@@ -1627,6 +1702,7 @@ static int cdns_torrent_dp_init(struct phy *phy)
{ {
struct cdns_torrent_inst *inst = phy_get_drvdata(phy); struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
int ret;
switch (cdns_phy->ref_clk_rate) { switch (cdns_phy->ref_clk_rate) {
case CLK_19_2_MHZ: case CLK_19_2_MHZ:
...@@ -1639,6 +1715,24 @@ static int cdns_torrent_dp_init(struct phy *phy) ...@@ -1639,6 +1715,24 @@ static int cdns_torrent_dp_init(struct phy *phy)
return -EINVAL; return -EINVAL;
} }
ret = cdns_torrent_dp_get_pll(cdns_phy, TYPE_NONE);
if (ret)
return ret;
cdns_torrent_dp_common_init(cdns_phy, inst);
return cdns_torrent_dp_start(cdns_phy, inst, phy);
}
static int cdns_torrent_dp_multilink_init(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst,
struct phy *phy)
{
if (cdns_phy->ref_clk_rate != CLK_100_MHZ) {
dev_err(cdns_phy->dev, "Unsupported Ref Clock Rate\n");
return -EINVAL;
}
cdns_torrent_dp_common_init(cdns_phy, inst); cdns_torrent_dp_common_init(cdns_phy, inst);
return cdns_torrent_dp_start(cdns_phy, inst, phy); return cdns_torrent_dp_start(cdns_phy, inst, phy);
...@@ -2156,8 +2250,11 @@ static int cdns_torrent_phy_init(struct phy *phy) ...@@ -2156,8 +2250,11 @@ static int cdns_torrent_phy_init(struct phy *phy)
u32 num_regs; u32 num_regs;
int i, j; int i, j;
if (cdns_phy->nsubnodes > 1) if (cdns_phy->nsubnodes > 1) {
if (phy_type == TYPE_DP)
return cdns_torrent_dp_multilink_init(cdns_phy, inst, phy);
return 0; return 0;
}
/** /**
* Spread spectrum generation is not required or supported * Spread spectrum generation is not required or supported
...@@ -2399,6 +2496,12 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) ...@@ -2399,6 +2496,12 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy)
} }
} }
if (phy_t1 == TYPE_DP) {
ret = cdns_torrent_dp_get_pll(cdns_phy, phy_t2);
if (ret)
return ret;
}
reset_control_deassert(cdns_phy->phys[node].lnk_rst); reset_control_deassert(cdns_phy->phys[node].lnk_rst);
} }
...@@ -2794,6 +2897,109 @@ static void cdns_torrent_phy_remove(struct platform_device *pdev) ...@@ -2794,6 +2897,109 @@ static void cdns_torrent_phy_remove(struct platform_device *pdev)
cdns_torrent_clk_cleanup(cdns_phy); cdns_torrent_clk_cleanup(cdns_phy);
} }
/* USB and DP link configuration */
static struct cdns_reg_pairs usb_dp_link_cmn_regs[] = {
{0x0002, PHY_PLL_CFG},
{0x8600, CMN_PDIAG_PLL0_CLK_SEL_M0}
};
static struct cdns_reg_pairs usb_dp_xcvr_diag_ln_regs[] = {
{0x0000, XCVR_DIAG_HSCLK_SEL},
{0x0001, XCVR_DIAG_HSCLK_DIV},
{0x0041, XCVR_DIAG_PLLDRC_CTRL}
};
static struct cdns_reg_pairs dp_usb_xcvr_diag_ln_regs[] = {
{0x0001, XCVR_DIAG_HSCLK_SEL},
{0x0009, XCVR_DIAG_PLLDRC_CTRL}
};
static struct cdns_torrent_vals usb_dp_link_cmn_vals = {
.reg_pairs = usb_dp_link_cmn_regs,
.num_regs = ARRAY_SIZE(usb_dp_link_cmn_regs),
};
static struct cdns_torrent_vals usb_dp_xcvr_diag_ln_vals = {
.reg_pairs = usb_dp_xcvr_diag_ln_regs,
.num_regs = ARRAY_SIZE(usb_dp_xcvr_diag_ln_regs),
};
static struct cdns_torrent_vals dp_usb_xcvr_diag_ln_vals = {
.reg_pairs = dp_usb_xcvr_diag_ln_regs,
.num_regs = ARRAY_SIZE(dp_usb_xcvr_diag_ln_regs),
};
/* PCIe and DP link configuration */
static struct cdns_reg_pairs pcie_dp_link_cmn_regs[] = {
{0x0003, PHY_PLL_CFG},
{0x0601, CMN_PDIAG_PLL0_CLK_SEL_M0},
{0x0400, CMN_PDIAG_PLL0_CLK_SEL_M1}
};
static struct cdns_reg_pairs pcie_dp_xcvr_diag_ln_regs[] = {
{0x0000, XCVR_DIAG_HSCLK_SEL},
{0x0001, XCVR_DIAG_HSCLK_DIV},
{0x0012, XCVR_DIAG_PLLDRC_CTRL}
};
static struct cdns_reg_pairs dp_pcie_xcvr_diag_ln_regs[] = {
{0x0001, XCVR_DIAG_HSCLK_SEL},
{0x0009, XCVR_DIAG_PLLDRC_CTRL}
};
static struct cdns_torrent_vals pcie_dp_link_cmn_vals = {
.reg_pairs = pcie_dp_link_cmn_regs,
.num_regs = ARRAY_SIZE(pcie_dp_link_cmn_regs),
};
static struct cdns_torrent_vals pcie_dp_xcvr_diag_ln_vals = {
.reg_pairs = pcie_dp_xcvr_diag_ln_regs,
.num_regs = ARRAY_SIZE(pcie_dp_xcvr_diag_ln_regs),
};
static struct cdns_torrent_vals dp_pcie_xcvr_diag_ln_vals = {
.reg_pairs = dp_pcie_xcvr_diag_ln_regs,
.num_regs = ARRAY_SIZE(dp_pcie_xcvr_diag_ln_regs),
};
/* DP Multilink, 100 MHz Ref clk, no SSC */
static struct cdns_reg_pairs dp_100_no_ssc_cmn_regs[] = {
{0x007F, CMN_TXPUCAL_TUNE},
{0x007F, CMN_TXPDCAL_TUNE}
};
static struct cdns_reg_pairs dp_100_no_ssc_tx_ln_regs[] = {
{0x00FB, TX_PSC_A0},
{0x04AA, TX_PSC_A2},
{0x04AA, TX_PSC_A3},
{0x000F, XCVR_DIAG_BIDI_CTRL}
};
static struct cdns_reg_pairs dp_100_no_ssc_rx_ln_regs[] = {
{0x0000, RX_PSC_A0},
{0x0000, RX_PSC_A2},
{0x0000, RX_PSC_A3},
{0x0000, RX_PSC_CAL},
{0x0000, RX_REE_GCSM1_CTRL},
{0x0000, RX_REE_GCSM2_CTRL},
{0x0000, RX_REE_PERGCSM_CTRL}
};
static struct cdns_torrent_vals dp_100_no_ssc_cmn_vals = {
.reg_pairs = dp_100_no_ssc_cmn_regs,
.num_regs = ARRAY_SIZE(dp_100_no_ssc_cmn_regs),
};
static struct cdns_torrent_vals dp_100_no_ssc_tx_ln_vals = {
.reg_pairs = dp_100_no_ssc_tx_ln_regs,
.num_regs = ARRAY_SIZE(dp_100_no_ssc_tx_ln_regs),
};
static struct cdns_torrent_vals dp_100_no_ssc_rx_ln_vals = {
.reg_pairs = dp_100_no_ssc_rx_ln_regs,
.num_regs = ARRAY_SIZE(dp_100_no_ssc_rx_ln_regs),
};
/* Single DisplayPort(DP) link configuration */ /* Single DisplayPort(DP) link configuration */
static struct cdns_reg_pairs sl_dp_link_cmn_regs[] = { static struct cdns_reg_pairs sl_dp_link_cmn_regs[] = {
{0x0000, PHY_PLL_CFG}, {0x0000, PHY_PLL_CFG},
...@@ -3736,6 +3942,12 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -3736,6 +3942,12 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[TYPE_NONE] = { [TYPE_NONE] = {
[NO_SSC] = &sl_dp_link_cmn_vals, [NO_SSC] = &sl_dp_link_cmn_vals,
}, },
[TYPE_PCIE] = {
[NO_SSC] = &pcie_dp_link_cmn_vals,
},
[TYPE_USB] = {
[NO_SSC] = &usb_dp_link_cmn_vals,
},
}, },
[TYPE_PCIE] = { [TYPE_PCIE] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -3758,6 +3970,9 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -3758,6 +3970,9 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[EXTERNAL_SSC] = &pcie_usb_link_cmn_vals, [EXTERNAL_SSC] = &pcie_usb_link_cmn_vals,
[INTERNAL_SSC] = &pcie_usb_link_cmn_vals, [INTERNAL_SSC] = &pcie_usb_link_cmn_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &pcie_dp_link_cmn_vals,
},
}, },
[TYPE_SGMII] = { [TYPE_SGMII] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -3810,6 +4025,9 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -3810,6 +4025,9 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals, [EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals,
[INTERNAL_SSC] = &usb_sgmii_link_cmn_vals, [INTERNAL_SSC] = &usb_sgmii_link_cmn_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_dp_link_cmn_vals,
},
}, },
}, },
.xcvr_diag_vals = { .xcvr_diag_vals = {
...@@ -3817,6 +4035,12 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -3817,6 +4035,12 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[TYPE_NONE] = { [TYPE_NONE] = {
[NO_SSC] = &sl_dp_xcvr_diag_ln_vals, [NO_SSC] = &sl_dp_xcvr_diag_ln_vals,
}, },
[TYPE_PCIE] = {
[NO_SSC] = &dp_pcie_xcvr_diag_ln_vals,
},
[TYPE_USB] = {
[NO_SSC] = &dp_usb_xcvr_diag_ln_vals,
},
}, },
[TYPE_PCIE] = { [TYPE_PCIE] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -3839,6 +4063,9 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -3839,6 +4063,9 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[EXTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals, [EXTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals,
[INTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals, [INTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &pcie_dp_xcvr_diag_ln_vals,
},
}, },
[TYPE_SGMII] = { [TYPE_SGMII] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -3891,6 +4118,9 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -3891,6 +4118,9 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[EXTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, [EXTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals,
[INTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, [INTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_dp_xcvr_diag_ln_vals,
},
}, },
}, },
.pcs_cmn_vals = { .pcs_cmn_vals = {
...@@ -3915,6 +4145,9 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -3915,6 +4145,9 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals, [EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals,
[INTERNAL_SSC] = &usb_phy_pcs_cmn_vals, [INTERNAL_SSC] = &usb_phy_pcs_cmn_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_phy_pcs_cmn_vals,
},
}, },
}, },
.cmn_vals = { .cmn_vals = {
...@@ -3937,6 +4170,12 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -3937,6 +4170,12 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[TYPE_NONE] = { [TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_cmn_vals, [NO_SSC] = &sl_dp_100_no_ssc_cmn_vals,
}, },
[TYPE_PCIE] = {
[NO_SSC] = &dp_100_no_ssc_cmn_vals,
},
[TYPE_USB] = {
[NO_SSC] = &sl_dp_100_no_ssc_cmn_vals,
},
}, },
[TYPE_PCIE] = { [TYPE_PCIE] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -3959,6 +4198,9 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -3959,6 +4198,9 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals,
[INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = NULL,
},
}, },
[TYPE_SGMII] = { [TYPE_SGMII] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4011,6 +4253,9 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -4011,6 +4253,9 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals,
[INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_100_no_ssc_cmn_vals,
},
}, },
}, },
}, },
...@@ -4034,6 +4279,12 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -4034,6 +4279,12 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[TYPE_NONE] = { [TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_tx_ln_vals, [NO_SSC] = &sl_dp_100_no_ssc_tx_ln_vals,
}, },
[TYPE_PCIE] = {
[NO_SSC] = &dp_100_no_ssc_tx_ln_vals,
},
[TYPE_USB] = {
[NO_SSC] = &dp_100_no_ssc_tx_ln_vals,
},
}, },
[TYPE_PCIE] = { [TYPE_PCIE] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4056,6 +4307,9 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -4056,6 +4307,9 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[EXTERNAL_SSC] = NULL, [EXTERNAL_SSC] = NULL,
[INTERNAL_SSC] = NULL, [INTERNAL_SSC] = NULL,
}, },
[TYPE_DP] = {
[NO_SSC] = NULL,
},
}, },
[TYPE_SGMII] = { [TYPE_SGMII] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4108,6 +4362,9 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -4108,6 +4362,9 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals,
[INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_100_no_ssc_tx_ln_vals,
},
}, },
}, },
}, },
...@@ -4131,6 +4388,12 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -4131,6 +4388,12 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[TYPE_NONE] = { [TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_rx_ln_vals, [NO_SSC] = &sl_dp_100_no_ssc_rx_ln_vals,
}, },
[TYPE_PCIE] = {
[NO_SSC] = &dp_100_no_ssc_rx_ln_vals,
},
[TYPE_USB] = {
[NO_SSC] = &dp_100_no_ssc_rx_ln_vals,
},
}, },
[TYPE_PCIE] = { [TYPE_PCIE] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4153,6 +4416,9 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -4153,6 +4416,9 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals,
[INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &pcie_100_no_ssc_rx_ln_vals,
},
}, },
[TYPE_SGMII] = { [TYPE_SGMII] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4205,6 +4471,9 @@ static const struct cdns_torrent_data cdns_map_torrent = { ...@@ -4205,6 +4471,9 @@ static const struct cdns_torrent_data cdns_map_torrent = {
[EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals,
[INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_100_no_ssc_rx_ln_vals,
},
}, },
}, },
}, },
...@@ -4218,6 +4487,12 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4218,6 +4487,12 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[TYPE_NONE] = { [TYPE_NONE] = {
[NO_SSC] = &sl_dp_link_cmn_vals, [NO_SSC] = &sl_dp_link_cmn_vals,
}, },
[TYPE_PCIE] = {
[NO_SSC] = &pcie_dp_link_cmn_vals,
},
[TYPE_USB] = {
[NO_SSC] = &usb_dp_link_cmn_vals,
},
}, },
[TYPE_PCIE] = { [TYPE_PCIE] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4240,6 +4515,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4240,6 +4515,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[EXTERNAL_SSC] = &pcie_usb_link_cmn_vals, [EXTERNAL_SSC] = &pcie_usb_link_cmn_vals,
[INTERNAL_SSC] = &pcie_usb_link_cmn_vals, [INTERNAL_SSC] = &pcie_usb_link_cmn_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &pcie_dp_link_cmn_vals,
},
}, },
[TYPE_SGMII] = { [TYPE_SGMII] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4292,6 +4570,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4292,6 +4570,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals, [EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals,
[INTERNAL_SSC] = &usb_sgmii_link_cmn_vals, [INTERNAL_SSC] = &usb_sgmii_link_cmn_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_dp_link_cmn_vals,
},
}, },
}, },
.xcvr_diag_vals = { .xcvr_diag_vals = {
...@@ -4299,6 +4580,12 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4299,6 +4580,12 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[TYPE_NONE] = { [TYPE_NONE] = {
[NO_SSC] = &sl_dp_xcvr_diag_ln_vals, [NO_SSC] = &sl_dp_xcvr_diag_ln_vals,
}, },
[TYPE_PCIE] = {
[NO_SSC] = &dp_pcie_xcvr_diag_ln_vals,
},
[TYPE_USB] = {
[NO_SSC] = &dp_usb_xcvr_diag_ln_vals,
},
}, },
[TYPE_PCIE] = { [TYPE_PCIE] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4321,6 +4608,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4321,6 +4608,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[EXTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals, [EXTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals,
[INTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals, [INTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &pcie_dp_xcvr_diag_ln_vals,
},
}, },
[TYPE_SGMII] = { [TYPE_SGMII] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4373,6 +4663,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4373,6 +4663,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[EXTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, [EXTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals,
[INTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, [INTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_dp_xcvr_diag_ln_vals,
},
}, },
}, },
.pcs_cmn_vals = { .pcs_cmn_vals = {
...@@ -4397,6 +4690,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4397,6 +4690,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals, [EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals,
[INTERNAL_SSC] = &usb_phy_pcs_cmn_vals, [INTERNAL_SSC] = &usb_phy_pcs_cmn_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_phy_pcs_cmn_vals,
},
}, },
}, },
.cmn_vals = { .cmn_vals = {
...@@ -4419,6 +4715,12 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4419,6 +4715,12 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[TYPE_NONE] = { [TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_cmn_vals, [NO_SSC] = &sl_dp_100_no_ssc_cmn_vals,
}, },
[TYPE_PCIE] = {
[NO_SSC] = &dp_100_no_ssc_cmn_vals,
},
[TYPE_USB] = {
[NO_SSC] = &sl_dp_100_no_ssc_cmn_vals,
},
}, },
[TYPE_PCIE] = { [TYPE_PCIE] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4441,6 +4743,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4441,6 +4743,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals,
[INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = NULL,
},
}, },
[TYPE_SGMII] = { [TYPE_SGMII] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4493,6 +4798,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4493,6 +4798,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals,
[INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_100_no_ssc_cmn_vals,
},
}, },
}, },
}, },
...@@ -4516,6 +4824,12 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4516,6 +4824,12 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[TYPE_NONE] = { [TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_tx_ln_vals, [NO_SSC] = &sl_dp_100_no_ssc_tx_ln_vals,
}, },
[TYPE_PCIE] = {
[NO_SSC] = &dp_100_no_ssc_tx_ln_vals,
},
[TYPE_USB] = {
[NO_SSC] = &dp_100_no_ssc_tx_ln_vals,
},
}, },
[TYPE_PCIE] = { [TYPE_PCIE] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4538,6 +4852,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4538,6 +4852,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[EXTERNAL_SSC] = NULL, [EXTERNAL_SSC] = NULL,
[INTERNAL_SSC] = NULL, [INTERNAL_SSC] = NULL,
}, },
[TYPE_DP] = {
[NO_SSC] = NULL,
},
}, },
[TYPE_SGMII] = { [TYPE_SGMII] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4590,6 +4907,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4590,6 +4907,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals,
[INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_100_no_ssc_tx_ln_vals,
},
}, },
}, },
}, },
...@@ -4613,6 +4933,12 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4613,6 +4933,12 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[TYPE_NONE] = { [TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_rx_ln_vals, [NO_SSC] = &sl_dp_100_no_ssc_rx_ln_vals,
}, },
[TYPE_PCIE] = {
[NO_SSC] = &dp_100_no_ssc_rx_ln_vals,
},
[TYPE_USB] = {
[NO_SSC] = &dp_100_no_ssc_rx_ln_vals,
},
}, },
[TYPE_PCIE] = { [TYPE_PCIE] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4635,6 +4961,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4635,6 +4961,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals,
[INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &pcie_100_no_ssc_rx_ln_vals,
},
}, },
[TYPE_SGMII] = { [TYPE_SGMII] = {
[TYPE_NONE] = { [TYPE_NONE] = {
...@@ -4687,6 +5016,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { ...@@ -4687,6 +5016,9 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
[EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals,
[INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals,
}, },
[TYPE_DP] = {
[NO_SSC] = &usb_100_no_ssc_rx_ln_vals,
},
}, },
}, },
}, },
......
...@@ -206,7 +206,6 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev) ...@@ -206,7 +206,6 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct imx8_pcie_phy *imx8_phy; struct imx8_pcie_phy *imx8_phy;
struct resource *res;
imx8_phy = devm_kzalloc(dev, sizeof(*imx8_phy), GFP_KERNEL); imx8_phy = devm_kzalloc(dev, sizeof(*imx8_phy), GFP_KERNEL);
if (!imx8_phy) if (!imx8_phy)
...@@ -259,8 +258,7 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev) ...@@ -259,8 +258,7 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
"Failed to get PCIE PHY PERST control\n"); "Failed to get PCIE PHY PERST control\n");
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); imx8_phy->base = devm_platform_ioremap_resource(pdev, 0);
imx8_phy->base = devm_ioremap_resource(dev, res);
if (IS_ERR(imx8_phy->base)) if (IS_ERR(imx8_phy->base))
return PTR_ERR(imx8_phy->base); return PTR_ERR(imx8_phy->base);
......
...@@ -27,17 +27,231 @@ ...@@ -27,17 +27,231 @@
#define PHY_CTRL2_TXENABLEN0 BIT(8) #define PHY_CTRL2_TXENABLEN0 BIT(8)
#define PHY_CTRL2_OTG_DISABLE BIT(9) #define PHY_CTRL2_OTG_DISABLE BIT(9)
#define PHY_CTRL3 0xc
#define PHY_CTRL3_COMPDISTUNE_MASK GENMASK(2, 0)
#define PHY_CTRL3_TXPREEMP_TUNE_MASK GENMASK(16, 15)
#define PHY_CTRL3_TXRISE_TUNE_MASK GENMASK(21, 20)
#define PHY_CTRL3_TXVREF_TUNE_MASK GENMASK(25, 22)
#define PHY_CTRL3_TX_VBOOST_LEVEL_MASK GENMASK(31, 29)
#define PHY_CTRL4 0x10
#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(20, 15)
#define PHY_CTRL5 0x14
#define PHY_CTRL5_DMPWD_OVERRIDE_SEL BIT(23)
#define PHY_CTRL5_DMPWD_OVERRIDE BIT(22)
#define PHY_CTRL5_DPPWD_OVERRIDE_SEL BIT(21)
#define PHY_CTRL5_DPPWD_OVERRIDE BIT(20)
#define PHY_CTRL5_PCS_TX_SWING_FULL_MASK GENMASK(6, 0)
#define PHY_CTRL6 0x18 #define PHY_CTRL6 0x18
#define PHY_CTRL6_ALT_CLK_EN BIT(1) #define PHY_CTRL6_ALT_CLK_EN BIT(1)
#define PHY_CTRL6_ALT_CLK_SEL BIT(0) #define PHY_CTRL6_ALT_CLK_SEL BIT(0)
#define PHY_TUNE_DEFAULT 0xffffffff
struct imx8mq_usb_phy { struct imx8mq_usb_phy {
struct phy *phy; struct phy *phy;
struct clk *clk; struct clk *clk;
void __iomem *base; void __iomem *base;
struct regulator *vbus; struct regulator *vbus;
u32 pcs_tx_swing_full;
u32 pcs_tx_deemph_3p5db;
u32 tx_vref_tune;
u32 tx_rise_tune;
u32 tx_preemp_amp_tune;
u32 tx_vboost_level;
u32 comp_dis_tune;
}; };
static u32 phy_tx_vref_tune_from_property(u32 percent)
{
percent = clamp(percent, 94U, 124U);
return DIV_ROUND_CLOSEST(percent - 94U, 2);
}
static u32 phy_tx_rise_tune_from_property(u32 percent)
{
switch (percent) {
case 0 ... 98:
return 3;
case 99:
return 2;
case 100 ... 101:
return 1;
default:
return 0;
}
}
static u32 phy_tx_preemp_amp_tune_from_property(u32 microamp)
{
microamp = min(microamp, 1800U);
return microamp / 600;
}
static u32 phy_tx_vboost_level_from_property(u32 microvolt)
{
switch (microvolt) {
case 0 ... 960:
return 0;
case 961 ... 1160:
return 2;
default:
return 3;
}
}
static u32 phy_pcs_tx_deemph_3p5db_from_property(u32 decibel)
{
return min(decibel, 36U);
}
static u32 phy_comp_dis_tune_from_property(u32 percent)
{
switch (percent) {
case 0 ... 92:
return 0;
case 93 ... 95:
return 1;
case 96 ... 97:
return 2;
case 98 ... 102:
return 3;
case 103 ... 105:
return 4;
case 106 ... 109:
return 5;
case 110 ... 113:
return 6;
default:
return 7;
}
}
static u32 phy_pcs_tx_swing_full_from_property(u32 percent)
{
percent = min(percent, 100U);
return (percent * 127) / 100;
}
static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy)
{
struct device *dev = imx_phy->phy->dev.parent;
if (device_property_read_u32(dev, "fsl,phy-tx-vref-tune-percent",
&imx_phy->tx_vref_tune))
imx_phy->tx_vref_tune = PHY_TUNE_DEFAULT;
else
imx_phy->tx_vref_tune =
phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune);
if (device_property_read_u32(dev, "fsl,phy-tx-rise-tune-percent",
&imx_phy->tx_rise_tune))
imx_phy->tx_rise_tune = PHY_TUNE_DEFAULT;
else
imx_phy->tx_rise_tune =
phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune);
if (device_property_read_u32(dev, "fsl,phy-tx-preemp-amp-tune-microamp",
&imx_phy->tx_preemp_amp_tune))
imx_phy->tx_preemp_amp_tune = PHY_TUNE_DEFAULT;
else
imx_phy->tx_preemp_amp_tune =
phy_tx_preemp_amp_tune_from_property(imx_phy->tx_preemp_amp_tune);
if (device_property_read_u32(dev, "fsl,phy-tx-vboost-level-microvolt",
&imx_phy->tx_vboost_level))
imx_phy->tx_vboost_level = PHY_TUNE_DEFAULT;
else
imx_phy->tx_vboost_level =
phy_tx_vboost_level_from_property(imx_phy->tx_vboost_level);
if (device_property_read_u32(dev, "fsl,phy-comp-dis-tune-percent",
&imx_phy->comp_dis_tune))
imx_phy->comp_dis_tune = PHY_TUNE_DEFAULT;
else
imx_phy->comp_dis_tune =
phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune);
if (device_property_read_u32(dev, "fsl,pcs-tx-deemph-3p5db-attenuation-db",
&imx_phy->pcs_tx_deemph_3p5db))
imx_phy->pcs_tx_deemph_3p5db = PHY_TUNE_DEFAULT;
else
imx_phy->pcs_tx_deemph_3p5db =
phy_pcs_tx_deemph_3p5db_from_property(imx_phy->pcs_tx_deemph_3p5db);
if (device_property_read_u32(dev, "fsl,phy-pcs-tx-swing-full-percent",
&imx_phy->pcs_tx_swing_full))
imx_phy->pcs_tx_swing_full = PHY_TUNE_DEFAULT;
else
imx_phy->pcs_tx_swing_full =
phy_pcs_tx_swing_full_from_property(imx_phy->pcs_tx_swing_full);
}
static void imx8m_phy_tune(struct imx8mq_usb_phy *imx_phy)
{
u32 value;
/* PHY tuning */
if (imx_phy->pcs_tx_deemph_3p5db != PHY_TUNE_DEFAULT) {
value = readl(imx_phy->base + PHY_CTRL4);
value &= ~PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK;
value |= FIELD_PREP(PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK,
imx_phy->pcs_tx_deemph_3p5db);
writel(value, imx_phy->base + PHY_CTRL4);
}
if (imx_phy->pcs_tx_swing_full != PHY_TUNE_DEFAULT) {
value = readl(imx_phy->base + PHY_CTRL5);
value |= FIELD_PREP(PHY_CTRL5_PCS_TX_SWING_FULL_MASK,
imx_phy->pcs_tx_swing_full);
writel(value, imx_phy->base + PHY_CTRL5);
}
if ((imx_phy->tx_vref_tune & imx_phy->tx_rise_tune &
imx_phy->tx_preemp_amp_tune & imx_phy->comp_dis_tune &
imx_phy->tx_vboost_level) == PHY_TUNE_DEFAULT)
/* If all are the default values, no need update. */
return;
value = readl(imx_phy->base + PHY_CTRL3);
if (imx_phy->tx_vref_tune != PHY_TUNE_DEFAULT) {
value &= ~PHY_CTRL3_TXVREF_TUNE_MASK;
value |= FIELD_PREP(PHY_CTRL3_TXVREF_TUNE_MASK,
imx_phy->tx_vref_tune);
}
if (imx_phy->tx_rise_tune != PHY_TUNE_DEFAULT) {
value &= ~PHY_CTRL3_TXRISE_TUNE_MASK;
value |= FIELD_PREP(PHY_CTRL3_TXRISE_TUNE_MASK,
imx_phy->tx_rise_tune);
}
if (imx_phy->tx_preemp_amp_tune != PHY_TUNE_DEFAULT) {
value &= ~PHY_CTRL3_TXPREEMP_TUNE_MASK;
value |= FIELD_PREP(PHY_CTRL3_TXPREEMP_TUNE_MASK,
imx_phy->tx_preemp_amp_tune);
}
if (imx_phy->comp_dis_tune != PHY_TUNE_DEFAULT) {
value &= ~PHY_CTRL3_COMPDISTUNE_MASK;
value |= FIELD_PREP(PHY_CTRL3_COMPDISTUNE_MASK,
imx_phy->comp_dis_tune);
}
if (imx_phy->tx_vboost_level != PHY_TUNE_DEFAULT) {
value &= ~PHY_CTRL3_TX_VBOOST_LEVEL_MASK;
value |= FIELD_PREP(PHY_CTRL3_TX_VBOOST_LEVEL_MASK,
imx_phy->tx_vboost_level);
}
writel(value, imx_phy->base + PHY_CTRL3);
}
static int imx8mq_usb_phy_init(struct phy *phy) static int imx8mq_usb_phy_init(struct phy *phy)
{ {
struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
...@@ -99,6 +313,8 @@ static int imx8mp_usb_phy_init(struct phy *phy) ...@@ -99,6 +313,8 @@ static int imx8mp_usb_phy_init(struct phy *phy)
value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET); value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
writel(value, imx_phy->base + PHY_CTRL1); writel(value, imx_phy->base + PHY_CTRL1);
imx8m_phy_tune(imx_phy);
return 0; return 0;
} }
...@@ -182,6 +398,8 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev) ...@@ -182,6 +398,8 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
phy_set_drvdata(imx_phy->phy, imx_phy); phy_set_drvdata(imx_phy->phy, imx_phy);
imx8m_get_phy_tuning_data(imx_phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider); return PTR_ERR_OR_ZERO(phy_provider);
......
...@@ -54,7 +54,7 @@ config PHY_HISTB_COMBPHY ...@@ -54,7 +54,7 @@ config PHY_HISTB_COMBPHY
config PHY_HISI_INNO_USB2 config PHY_HISI_INNO_USB2
tristate "HiSilicon INNO USB2 PHY support" tristate "HiSilicon INNO USB2 PHY support"
depends on (ARCH_HISI && ARM64) || COMPILE_TEST depends on ARCH_HISI || COMPILE_TEST
select GENERIC_PHY select GENERIC_PHY
select MFD_SYSCON select MFD_SYSCON
help help
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/of_device.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/reset.h> #include <linux/reset.h>
...@@ -20,12 +20,25 @@ ...@@ -20,12 +20,25 @@
#define PHY_CLK_STABLE_TIME 2 /* unit:ms */ #define PHY_CLK_STABLE_TIME 2 /* unit:ms */
#define UTMI_RST_COMPLETE_TIME 2 /* unit:ms */ #define UTMI_RST_COMPLETE_TIME 2 /* unit:ms */
#define POR_RST_COMPLETE_TIME 300 /* unit:us */ #define POR_RST_COMPLETE_TIME 300 /* unit:us */
#define PHY_TYPE_0 0
#define PHY_TYPE_1 1
#define PHY_TEST_DATA GENMASK(7, 0) #define PHY_TEST_DATA GENMASK(7, 0)
#define PHY_TEST_ADDR GENMASK(15, 8) #define PHY_TEST_ADDR_OFFSET 8
#define PHY_TEST_PORT GENMASK(18, 16) #define PHY0_TEST_ADDR GENMASK(15, 8)
#define PHY_TEST_WREN BIT(21) #define PHY0_TEST_PORT_OFFSET 16
#define PHY_TEST_CLK BIT(22) /* rising edge active */ #define PHY0_TEST_PORT GENMASK(18, 16)
#define PHY_TEST_RST BIT(23) /* low active */ #define PHY0_TEST_WREN BIT(21)
#define PHY0_TEST_CLK BIT(22) /* rising edge active */
#define PHY0_TEST_RST BIT(23) /* low active */
#define PHY1_TEST_ADDR GENMASK(11, 8)
#define PHY1_TEST_PORT_OFFSET 12
#define PHY1_TEST_PORT BIT(12)
#define PHY1_TEST_WREN BIT(13)
#define PHY1_TEST_CLK BIT(14) /* rising edge active */
#define PHY1_TEST_RST BIT(15) /* low active */
#define PHY_CLK_ENABLE BIT(2) #define PHY_CLK_ENABLE BIT(2)
struct hisi_inno_phy_port { struct hisi_inno_phy_port {
...@@ -37,6 +50,7 @@ struct hisi_inno_phy_priv { ...@@ -37,6 +50,7 @@ struct hisi_inno_phy_priv {
void __iomem *mmio; void __iomem *mmio;
struct clk *ref_clk; struct clk *ref_clk;
struct reset_control *por_rst; struct reset_control *por_rst;
unsigned int type;
struct hisi_inno_phy_port ports[INNO_PHY_PORT_NUM]; struct hisi_inno_phy_port ports[INNO_PHY_PORT_NUM];
}; };
...@@ -45,17 +59,27 @@ static void hisi_inno_phy_write_reg(struct hisi_inno_phy_priv *priv, ...@@ -45,17 +59,27 @@ static void hisi_inno_phy_write_reg(struct hisi_inno_phy_priv *priv,
{ {
void __iomem *reg = priv->mmio; void __iomem *reg = priv->mmio;
u32 val; u32 val;
u32 value;
val = (data & PHY_TEST_DATA) |
((addr << 8) & PHY_TEST_ADDR) | if (priv->type == PHY_TYPE_0)
((port << 16) & PHY_TEST_PORT) | val = (data & PHY_TEST_DATA) |
PHY_TEST_WREN | PHY_TEST_RST; ((addr << PHY_TEST_ADDR_OFFSET) & PHY0_TEST_ADDR) |
((port << PHY0_TEST_PORT_OFFSET) & PHY0_TEST_PORT) |
PHY0_TEST_WREN | PHY0_TEST_RST;
else
val = (data & PHY_TEST_DATA) |
((addr << PHY_TEST_ADDR_OFFSET) & PHY1_TEST_ADDR) |
((port << PHY1_TEST_PORT_OFFSET) & PHY1_TEST_PORT) |
PHY1_TEST_WREN | PHY1_TEST_RST;
writel(val, reg); writel(val, reg);
val |= PHY_TEST_CLK; value = val;
writel(val, reg); if (priv->type == PHY_TYPE_0)
value |= PHY0_TEST_CLK;
else
value |= PHY1_TEST_CLK;
writel(value, reg);
val &= ~PHY_TEST_CLK;
writel(val, reg); writel(val, reg);
} }
...@@ -135,6 +159,8 @@ static int hisi_inno_phy_probe(struct platform_device *pdev) ...@@ -135,6 +159,8 @@ static int hisi_inno_phy_probe(struct platform_device *pdev)
if (IS_ERR(priv->por_rst)) if (IS_ERR(priv->por_rst))
return PTR_ERR(priv->por_rst); return PTR_ERR(priv->por_rst);
priv->type = (uintptr_t) of_device_get_match_data(dev);
for_each_child_of_node(np, child) { for_each_child_of_node(np, child) {
struct reset_control *rst; struct reset_control *rst;
struct phy *phy; struct phy *phy;
...@@ -170,8 +196,12 @@ static int hisi_inno_phy_probe(struct platform_device *pdev) ...@@ -170,8 +196,12 @@ static int hisi_inno_phy_probe(struct platform_device *pdev)
} }
static const struct of_device_id hisi_inno_phy_of_match[] = { static const struct of_device_id hisi_inno_phy_of_match[] = {
{ .compatible = "hisilicon,inno-usb2-phy", }, { .compatible = "hisilicon,inno-usb2-phy",
{ .compatible = "hisilicon,hi3798cv200-usb2-phy", }, .data = (void *) PHY_TYPE_0 },
{ .compatible = "hisilicon,hi3798cv200-usb2-phy",
.data = (void *) PHY_TYPE_0 },
{ .compatible = "hisilicon,hi3798mv100-usb2-phy",
.data = (void *) PHY_TYPE_1 },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, hisi_inno_phy_of_match); MODULE_DEVICE_TABLE(of, hisi_inno_phy_of_match);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <dt-bindings/phy/phy.h> #include <dt-bindings/phy/phy.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
...@@ -264,6 +265,8 @@ ...@@ -264,6 +265,8 @@
#define TPHY_CLKS_CNT 2 #define TPHY_CLKS_CNT 2
#define USER_BUF_LEN(count) min_t(size_t, 8, (count))
enum mtk_phy_version { enum mtk_phy_version {
MTK_PHY_V1 = 1, MTK_PHY_V1 = 1,
MTK_PHY_V2, MTK_PHY_V2,
...@@ -336,6 +339,358 @@ struct mtk_tphy { ...@@ -336,6 +339,358 @@ struct mtk_tphy {
int src_coef; /* coefficient for slew rate calibrate */ int src_coef; /* coefficient for slew rate calibrate */
}; };
#if IS_ENABLED(CONFIG_DEBUG_FS)
enum u2_phy_params {
U2P_EYE_VRT = 0,
U2P_EYE_TERM,
U2P_EFUSE_EN,
U2P_EFUSE_INTR,
U2P_DISCTH,
U2P_PRE_EMPHASIS,
};
enum u3_phy_params {
U3P_EFUSE_EN = 0,
U3P_EFUSE_INTR,
U3P_EFUSE_TX_IMP,
U3P_EFUSE_RX_IMP,
};
static const char *const u2_phy_files[] = {
[U2P_EYE_VRT] = "vrt",
[U2P_EYE_TERM] = "term",
[U2P_EFUSE_EN] = "efuse",
[U2P_EFUSE_INTR] = "intr",
[U2P_DISCTH] = "discth",
[U2P_PRE_EMPHASIS] = "preemph",
};
static const char *const u3_phy_files[] = {
[U3P_EFUSE_EN] = "efuse",
[U3P_EFUSE_INTR] = "intr",
[U3P_EFUSE_TX_IMP] = "tx-imp",
[U3P_EFUSE_RX_IMP] = "rx-imp",
};
static int u2_phy_params_show(struct seq_file *sf, void *unused)
{
struct mtk_phy_instance *inst = sf->private;
const char *fname = file_dentry(sf->file)->d_iname;
struct u2phy_banks *u2_banks = &inst->u2_banks;
void __iomem *com = u2_banks->com;
u32 max = 0;
u32 tmp = 0;
u32 val = 0;
int ret;
ret = match_string(u2_phy_files, ARRAY_SIZE(u2_phy_files), fname);
if (ret < 0)
return ret;
switch (ret) {
case U2P_EYE_VRT:
tmp = readl(com + U3P_USBPHYACR1);
val = FIELD_GET(PA1_RG_VRT_SEL, tmp);
max = FIELD_MAX(PA1_RG_VRT_SEL);
break;
case U2P_EYE_TERM:
tmp = readl(com + U3P_USBPHYACR1);
val = FIELD_GET(PA1_RG_TERM_SEL, tmp);
max = FIELD_MAX(PA1_RG_TERM_SEL);
break;
case U2P_EFUSE_EN:
if (u2_banks->misc) {
tmp = readl(u2_banks->misc + U3P_MISC_REG1);
max = 1;
}
val = !!(tmp & MR1_EFUSE_AUTO_LOAD_DIS);
break;
case U2P_EFUSE_INTR:
tmp = readl(com + U3P_USBPHYACR1);
val = FIELD_GET(PA1_RG_INTR_CAL, tmp);
max = FIELD_MAX(PA1_RG_INTR_CAL);
break;
case U2P_DISCTH:
tmp = readl(com + U3P_USBPHYACR6);
val = FIELD_GET(PA6_RG_U2_DISCTH, tmp);
max = FIELD_MAX(PA6_RG_U2_DISCTH);
break;
case U2P_PRE_EMPHASIS:
tmp = readl(com + U3P_USBPHYACR6);
val = FIELD_GET(PA6_RG_U2_PRE_EMP, tmp);
max = FIELD_MAX(PA6_RG_U2_PRE_EMP);
break;
default:
seq_printf(sf, "invalid, %d\n", ret);
break;
}
seq_printf(sf, "%s : %d [0, %d]\n", fname, val, max);
return 0;
}
static int u2_phy_params_open(struct inode *inode, struct file *file)
{
return single_open(file, u2_phy_params_show, inode->i_private);
}
static ssize_t u2_phy_params_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
const char *fname = file_dentry(file)->d_iname;
struct seq_file *sf = file->private_data;
struct mtk_phy_instance *inst = sf->private;
struct u2phy_banks *u2_banks = &inst->u2_banks;
void __iomem *com = u2_banks->com;
ssize_t rc;
u32 val;
int ret;
rc = kstrtouint_from_user(ubuf, USER_BUF_LEN(count), 0, &val);
if (rc)
return rc;
ret = match_string(u2_phy_files, ARRAY_SIZE(u2_phy_files), fname);
if (ret < 0)
return (ssize_t)ret;
switch (ret) {
case U2P_EYE_VRT:
mtk_phy_update_field(com + U3P_USBPHYACR1, PA1_RG_VRT_SEL, val);
break;
case U2P_EYE_TERM:
mtk_phy_update_field(com + U3P_USBPHYACR1, PA1_RG_TERM_SEL, val);
break;
case U2P_EFUSE_EN:
if (u2_banks->misc)
mtk_phy_update_field(u2_banks->misc + U3P_MISC_REG1,
MR1_EFUSE_AUTO_LOAD_DIS, !!val);
break;
case U2P_EFUSE_INTR:
mtk_phy_update_field(com + U3P_USBPHYACR1, PA1_RG_INTR_CAL, val);
break;
case U2P_DISCTH:
mtk_phy_update_field(com + U3P_USBPHYACR6, PA6_RG_U2_DISCTH, val);
break;
case U2P_PRE_EMPHASIS:
mtk_phy_update_field(com + U3P_USBPHYACR6, PA6_RG_U2_PRE_EMP, val);
break;
default:
break;
}
return count;
}
static const struct file_operations u2_phy_fops = {
.open = u2_phy_params_open,
.write = u2_phy_params_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void u2_phy_dbgfs_files_create(struct mtk_phy_instance *inst)
{
u32 count = ARRAY_SIZE(u2_phy_files);
int i;
for (i = 0; i < count; i++)
debugfs_create_file(u2_phy_files[i], 0644, inst->phy->debugfs,
inst, &u2_phy_fops);
}
static int u3_phy_params_show(struct seq_file *sf, void *unused)
{
struct mtk_phy_instance *inst = sf->private;
const char *fname = file_dentry(sf->file)->d_iname;
struct u3phy_banks *u3_banks = &inst->u3_banks;
u32 val = 0;
u32 max = 0;
u32 tmp;
int ret;
ret = match_string(u3_phy_files, ARRAY_SIZE(u3_phy_files), fname);
if (ret < 0)
return ret;
switch (ret) {
case U3P_EFUSE_EN:
tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RSV);
val = !!(tmp & P3D_RG_EFUSE_AUTO_LOAD_DIS);
max = 1;
break;
case U3P_EFUSE_INTR:
tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG0);
val = FIELD_GET(P3A_RG_IEXT_INTR, tmp);
max = FIELD_MAX(P3A_RG_IEXT_INTR);
break;
case U3P_EFUSE_TX_IMP:
tmp = readl(u3_banks->phyd + U3P_U3_PHYD_IMPCAL0);
val = FIELD_GET(P3D_RG_TX_IMPEL, tmp);
max = FIELD_MAX(P3D_RG_TX_IMPEL);
break;
case U3P_EFUSE_RX_IMP:
tmp = readl(u3_banks->phyd + U3P_U3_PHYD_IMPCAL1);
val = FIELD_GET(P3D_RG_RX_IMPEL, tmp);
max = FIELD_MAX(P3D_RG_RX_IMPEL);
break;
default:
seq_printf(sf, "invalid, %d\n", ret);
break;
}
seq_printf(sf, "%s : %d [0, %d]\n", fname, val, max);
return 0;
}
static int u3_phy_params_open(struct inode *inode, struct file *file)
{
return single_open(file, u3_phy_params_show, inode->i_private);
}
static ssize_t u3_phy_params_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
const char *fname = file_dentry(file)->d_iname;
struct seq_file *sf = file->private_data;
struct mtk_phy_instance *inst = sf->private;
struct u3phy_banks *u3_banks = &inst->u3_banks;
void __iomem *phyd = u3_banks->phyd;
ssize_t rc;
u32 val;
int ret;
rc = kstrtouint_from_user(ubuf, USER_BUF_LEN(count), 0, &val);
if (rc)
return rc;
ret = match_string(u3_phy_files, ARRAY_SIZE(u3_phy_files), fname);
if (ret < 0)
return (ssize_t)ret;
switch (ret) {
case U3P_EFUSE_EN:
mtk_phy_update_field(phyd + U3P_U3_PHYD_RSV,
P3D_RG_EFUSE_AUTO_LOAD_DIS, !!val);
break;
case U3P_EFUSE_INTR:
mtk_phy_update_field(u3_banks->phya + U3P_U3_PHYA_REG0,
P3A_RG_IEXT_INTR, val);
break;
case U3P_EFUSE_TX_IMP:
mtk_phy_update_field(phyd + U3P_U3_PHYD_IMPCAL0, P3D_RG_TX_IMPEL, val);
mtk_phy_set_bits(phyd + U3P_U3_PHYD_IMPCAL0, P3D_RG_FORCE_TX_IMPEL);
break;
case U3P_EFUSE_RX_IMP:
mtk_phy_update_field(phyd + U3P_U3_PHYD_IMPCAL1, P3D_RG_RX_IMPEL, val);
mtk_phy_set_bits(phyd + U3P_U3_PHYD_IMPCAL1, P3D_RG_FORCE_RX_IMPEL);
break;
default:
break;
}
return count;
}
static const struct file_operations u3_phy_fops = {
.open = u3_phy_params_open,
.write = u3_phy_params_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void u3_phy_dbgfs_files_create(struct mtk_phy_instance *inst)
{
u32 count = ARRAY_SIZE(u3_phy_files);
int i;
for (i = 0; i < count; i++)
debugfs_create_file(u3_phy_files[i], 0644, inst->phy->debugfs,
inst, &u3_phy_fops);
}
static int phy_type_show(struct seq_file *sf, void *unused)
{
struct mtk_phy_instance *inst = sf->private;
const char *type;
switch (inst->type) {
case PHY_TYPE_USB2:
type = "USB2";
break;
case PHY_TYPE_USB3:
type = "USB3";
break;
case PHY_TYPE_PCIE:
type = "PCIe";
break;
case PHY_TYPE_SGMII:
type = "SGMII";
break;
case PHY_TYPE_SATA:
type = "SATA";
break;
default:
type = "";
}
seq_printf(sf, "%s\n", type);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(phy_type);
/* these files will be removed when phy is released by phy core */
static void phy_debugfs_init(struct mtk_phy_instance *inst)
{
debugfs_create_file("type", 0444, inst->phy->debugfs, inst, &phy_type_fops);
switch (inst->type) {
case PHY_TYPE_USB2:
u2_phy_dbgfs_files_create(inst);
break;
case PHY_TYPE_USB3:
case PHY_TYPE_PCIE:
u3_phy_dbgfs_files_create(inst);
break;
default:
break;
}
}
#else
static void phy_debugfs_init(struct mtk_phy_instance *inst)
{}
#endif
static void hs_slew_rate_calibrate(struct mtk_tphy *tphy, static void hs_slew_rate_calibrate(struct mtk_tphy *tphy,
struct mtk_phy_instance *instance) struct mtk_phy_instance *instance)
{ {
...@@ -1140,6 +1495,7 @@ static struct phy *mtk_phy_xlate(struct device *dev, ...@@ -1140,6 +1495,7 @@ static struct phy *mtk_phy_xlate(struct device *dev,
phy_parse_property(tphy, instance); phy_parse_property(tphy, instance);
phy_type_set(instance); phy_type_set(instance);
phy_debugfs_init(instance);
return instance->phy; return instance->phy;
} }
......
...@@ -25,12 +25,17 @@ ...@@ -25,12 +25,17 @@
#define SPX5_SERDES_10G_START 13 #define SPX5_SERDES_10G_START 13
#define SPX5_SERDES_25G_START 25 #define SPX5_SERDES_25G_START 25
#define SPX5_SERDES_6G10G_CNT SPX5_SERDES_25G_START
/* Optimal power settings from GUC */
#define SPX5_SERDES_QUIET_MODE_VAL 0x01ef4e0c
enum sparx5_10g28cmu_mode { enum sparx5_10g28cmu_mode {
SPX5_SD10G28_CMU_MAIN = 0, SPX5_SD10G28_CMU_MAIN = 0,
SPX5_SD10G28_CMU_AUX1 = 1, SPX5_SD10G28_CMU_AUX1 = 1,
SPX5_SD10G28_CMU_AUX2 = 3, SPX5_SD10G28_CMU_AUX2 = 3,
SPX5_SD10G28_CMU_NONE = 4, SPX5_SD10G28_CMU_NONE = 4,
SPX5_SD10G28_CMU_MAX,
}; };
enum sparx5_sd25g28_mode_preset_type { enum sparx5_sd25g28_mode_preset_type {
...@@ -922,6 +927,222 @@ static void sparx5_sd10g28_get_params(struct sparx5_serdes_macro *macro, ...@@ -922,6 +927,222 @@ static void sparx5_sd10g28_get_params(struct sparx5_serdes_macro *macro,
*params = init; *params = init;
} }
static int sparx5_cmu_apply_cfg(struct sparx5_serdes_private *priv,
u32 cmu_idx,
void __iomem *cmu_tgt,
void __iomem *cmu_cfg_tgt,
u32 spd10g)
{
void __iomem **regs = priv->regs;
struct device *dev = priv->dev;
int value;
cmu_tgt = sdx5_inst_get(priv, TARGET_SD_CMU, cmu_idx);
cmu_cfg_tgt = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, cmu_idx);
if (cmu_idx == 1 || cmu_idx == 4 || cmu_idx == 7 ||
cmu_idx == 10 || cmu_idx == 13) {
spd10g = 0;
}
sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(1),
SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST,
cmu_cfg_tgt,
SD_CMU_CFG_SD_CMU_CFG(cmu_idx));
sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(0),
SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST,
cmu_cfg_tgt,
SD_CMU_CFG_SD_CMU_CFG(cmu_idx));
sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(1),
SD_CMU_CFG_SD_CMU_CFG_CMU_RST,
cmu_cfg_tgt,
SD_CMU_CFG_SD_CMU_CFG(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT_SET(0x1) |
SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT_SET(0x1) |
SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT_SET(0x1) |
SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT_SET(0x1) |
SD_CMU_CMU_45_R_EN_RATECHG_CTRL_SET(0x0),
SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT |
SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT |
SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT |
SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT |
SD_CMU_CMU_45_R_EN_RATECHG_CTRL,
cmu_tgt,
SD_CMU_CMU_45(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_SET(0),
SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0,
cmu_tgt,
SD_CMU_CMU_47(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_1B_CFG_RESERVE_7_0_SET(0),
SD_CMU_CMU_1B_CFG_RESERVE_7_0,
cmu_tgt,
SD_CMU_CMU_1B(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_0D_CFG_JC_BYP_SET(0x1),
SD_CMU_CMU_0D_CFG_JC_BYP,
cmu_tgt,
SD_CMU_CMU_0D(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_1F_CFG_VTUNE_SEL_SET(1),
SD_CMU_CMU_1F_CFG_VTUNE_SEL,
cmu_tgt,
SD_CMU_CMU_1F(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0_SET(3),
SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0,
cmu_tgt,
SD_CMU_CMU_00(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_SET(3),
SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0,
cmu_tgt,
SD_CMU_CMU_05(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_30_R_PLL_DLOL_EN_SET(1),
SD_CMU_CMU_30_R_PLL_DLOL_EN,
cmu_tgt,
SD_CMU_CMU_30(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_09_CFG_SW_10G_SET(spd10g),
SD_CMU_CMU_09_CFG_SW_10G,
cmu_tgt,
SD_CMU_CMU_09(cmu_idx));
sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(0),
SD_CMU_CFG_SD_CMU_CFG_CMU_RST,
cmu_cfg_tgt,
SD_CMU_CFG_SD_CMU_CFG(cmu_idx));
msleep(20);
sdx5_inst_rmw(SD_CMU_CMU_44_R_PLL_RSTN_SET(0),
SD_CMU_CMU_44_R_PLL_RSTN,
cmu_tgt,
SD_CMU_CMU_44(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_44_R_PLL_RSTN_SET(1),
SD_CMU_CMU_44_R_PLL_RSTN,
cmu_tgt,
SD_CMU_CMU_44(cmu_idx));
msleep(20);
value = readl(sdx5_addr(regs, SD_CMU_CMU_E0(cmu_idx)));
value = SD_CMU_CMU_E0_PLL_LOL_UDL_GET(value);
if (value) {
dev_err(dev, "CMU PLL Loss of Lock: 0x%x\n", value);
return -EINVAL;
}
sdx5_inst_rmw(SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD_SET(0),
SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD,
cmu_tgt,
SD_CMU_CMU_0D(cmu_idx));
return 0;
}
static int sparx5_cmu_cfg(struct sparx5_serdes_private *priv, u32 cmu_idx)
{
void __iomem *cmu_tgt, *cmu_cfg_tgt;
u32 spd10g = 1;
if (cmu_idx == 1 || cmu_idx == 4 || cmu_idx == 7 ||
cmu_idx == 10 || cmu_idx == 13) {
spd10g = 0;
}
cmu_tgt = sdx5_inst_get(priv, TARGET_SD_CMU, cmu_idx);
cmu_cfg_tgt = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, cmu_idx);
return sparx5_cmu_apply_cfg(priv, cmu_idx, cmu_tgt, cmu_cfg_tgt, spd10g);
}
/* Map of 6G/10G serdes mode and index to CMU index. */
static const int
sparx5_serdes_cmu_map[SPX5_SD10G28_CMU_MAX][SPX5_SERDES_6G10G_CNT] = {
[SPX5_SD10G28_CMU_MAIN] = { 2, 2, 2, 2, 2,
2, 2, 2, 5, 5,
5, 5, 5, 5, 5,
5, 8, 11, 11, 11,
11, 11, 11, 11, 11 },
[SPX5_SD10G28_CMU_AUX1] = { 0, 0, 3, 3, 3,
3, 3, 3, 3, 3,
6, 6, 6, 6, 6,
6, 6, 9, 9, 12,
12, 12, 12, 12, 12 },
[SPX5_SD10G28_CMU_AUX2] = { 1, 1, 1, 1, 4,
4, 4, 4, 4, 4,
4, 4, 7, 7, 7,
7, 7, 10, 10, 10,
10, 13, 13, 13, 13 },
[SPX5_SD10G28_CMU_NONE] = { 1, 1, 1, 1, 4,
4, 4, 4, 4, 4,
4, 4, 7, 7, 7,
7, 7, 10, 10, 10,
10, 13, 13, 13, 13 },
};
/* Get the index of the CMU which provides the clock for the specified serdes
* mode and index.
*/
static int sparx5_serdes_cmu_get(enum sparx5_10g28cmu_mode mode, int sd_index)
{
return sparx5_serdes_cmu_map[mode][sd_index];
}
static void sparx5_serdes_cmu_power_off(struct sparx5_serdes_private *priv)
{
void __iomem *cmu_inst, *cmu_cfg_inst;
int i;
/* Power down each CMU */
for (i = 0; i < SPX5_CMU_MAX; i++) {
cmu_inst = sdx5_inst_get(priv, TARGET_SD_CMU, i);
cmu_cfg_inst = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, i);
sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(0),
SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, cmu_cfg_inst,
SD_CMU_CFG_SD_CMU_CFG(0));
sdx5_inst_rmw(SD_CMU_CMU_05_CFG_REFCK_TERM_EN_SET(0),
SD_CMU_CMU_05_CFG_REFCK_TERM_EN, cmu_inst,
SD_CMU_CMU_05(0));
sdx5_inst_rmw(SD_CMU_CMU_09_CFG_EN_TX_CK_DN_SET(0),
SD_CMU_CMU_09_CFG_EN_TX_CK_DN, cmu_inst,
SD_CMU_CMU_09(0));
sdx5_inst_rmw(SD_CMU_CMU_06_CFG_VCO_PD_SET(1),
SD_CMU_CMU_06_CFG_VCO_PD, cmu_inst,
SD_CMU_CMU_06(0));
sdx5_inst_rmw(SD_CMU_CMU_09_CFG_EN_TX_CK_UP_SET(0),
SD_CMU_CMU_09_CFG_EN_TX_CK_UP, cmu_inst,
SD_CMU_CMU_09(0));
sdx5_inst_rmw(SD_CMU_CMU_08_CFG_CK_TREE_PD_SET(1),
SD_CMU_CMU_08_CFG_CK_TREE_PD, cmu_inst,
SD_CMU_CMU_08(0));
sdx5_inst_rmw(SD_CMU_CMU_0D_CFG_REFCK_PD_SET(1) |
SD_CMU_CMU_0D_CFG_PD_DIV64_SET(1) |
SD_CMU_CMU_0D_CFG_PD_DIV66_SET(1),
SD_CMU_CMU_0D_CFG_REFCK_PD |
SD_CMU_CMU_0D_CFG_PD_DIV64 |
SD_CMU_CMU_0D_CFG_PD_DIV66, cmu_inst,
SD_CMU_CMU_0D(0));
sdx5_inst_rmw(SD_CMU_CMU_06_CFG_CTRL_LOGIC_PD_SET(1),
SD_CMU_CMU_06_CFG_CTRL_LOGIC_PD, cmu_inst,
SD_CMU_CMU_06(0));
}
}
static void sparx5_sd25g28_reset(void __iomem *regs[], static void sparx5_sd25g28_reset(void __iomem *regs[],
struct sparx5_sd25g28_params *params, struct sparx5_sd25g28_params *params,
u32 sd_index) u32 sd_index)
...@@ -1422,7 +1643,17 @@ static int sparx5_sd10g28_apply_params(struct sparx5_serdes_macro *macro, ...@@ -1422,7 +1643,17 @@ static int sparx5_sd10g28_apply_params(struct sparx5_serdes_macro *macro,
u32 lane_index = macro->sidx; u32 lane_index = macro->sidx;
u32 sd_index = macro->stpidx; u32 sd_index = macro->stpidx;
void __iomem *sd_inst; void __iomem *sd_inst;
u32 value; u32 value, cmu_idx;
int err;
/* Do not configure serdes if CMU is not to be configured too */
if (params->skip_cmu_cfg)
return 0;
cmu_idx = sparx5_serdes_cmu_get(params->cmu_sel, lane_index);
err = sparx5_cmu_cfg(priv, cmu_idx);
if (err)
return err;
if (params->is_6g) if (params->is_6g)
sd_inst = sdx5_inst_get(priv, TARGET_SD6G_LANE, sd_index); sd_inst = sdx5_inst_get(priv, TARGET_SD6G_LANE, sd_index);
...@@ -1884,6 +2115,7 @@ static int sparx5_sd10g28_config(struct sparx5_serdes_macro *macro, bool reset) ...@@ -1884,6 +2115,7 @@ static int sparx5_sd10g28_config(struct sparx5_serdes_macro *macro, bool reset)
.rxinvert = 1, .rxinvert = 1,
.txswing = 240, .txswing = 240,
.reg_rst = reset, .reg_rst = reset,
.skip_cmu_cfg = reset,
}; };
int err; int err;
...@@ -1899,7 +2131,7 @@ static int sparx5_sd10g28_config(struct sparx5_serdes_macro *macro, bool reset) ...@@ -1899,7 +2131,7 @@ static int sparx5_sd10g28_config(struct sparx5_serdes_macro *macro, bool reset)
static int sparx5_serdes_power_save(struct sparx5_serdes_macro *macro, u32 pwdn) static int sparx5_serdes_power_save(struct sparx5_serdes_macro *macro, u32 pwdn)
{ {
struct sparx5_serdes_private *priv = macro->priv; struct sparx5_serdes_private *priv = macro->priv;
void __iomem *sd_inst; void __iomem *sd_inst, *sd_lane_inst;
if (macro->serdestype == SPX5_SDT_6G) if (macro->serdestype == SPX5_SDT_6G)
sd_inst = sdx5_inst_get(priv, TARGET_SD6G_LANE, macro->stpidx); sd_inst = sdx5_inst_get(priv, TARGET_SD6G_LANE, macro->stpidx);
...@@ -1909,12 +2141,36 @@ static int sparx5_serdes_power_save(struct sparx5_serdes_macro *macro, u32 pwdn) ...@@ -1909,12 +2141,36 @@ static int sparx5_serdes_power_save(struct sparx5_serdes_macro *macro, u32 pwdn)
sd_inst = sdx5_inst_get(priv, TARGET_SD25G_LANE, macro->stpidx); sd_inst = sdx5_inst_get(priv, TARGET_SD25G_LANE, macro->stpidx);
if (macro->serdestype == SPX5_SDT_25G) { if (macro->serdestype == SPX5_SDT_25G) {
sd_lane_inst = sdx5_inst_get(priv, TARGET_SD_LANE_25G,
macro->stpidx);
/* Take serdes out of reset */
sdx5_inst_rmw(SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST_SET(0),
SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST, sd_lane_inst,
SD_LANE_25G_SD_LANE_CFG(0));
/* Configure optimal settings for quiet mode */
sdx5_inst_rmw(SD_LANE_25G_QUIET_MODE_6G_QUIET_MODE_SET(SPX5_SERDES_QUIET_MODE_VAL),
SD_LANE_25G_QUIET_MODE_6G_QUIET_MODE,
sd_lane_inst, SD_LANE_25G_QUIET_MODE_6G(0));
sdx5_inst_rmw(SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER_SET(pwdn), sdx5_inst_rmw(SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER_SET(pwdn),
SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER, SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER,
sd_inst, sd_inst,
SD25G_LANE_LANE_04(0)); SD25G_LANE_LANE_04(0));
} else { } else {
/* 6G and 10G */ /* 6G and 10G */
sd_lane_inst = sdx5_inst_get(priv, TARGET_SD_LANE, macro->sidx);
/* Take serdes out of reset */
sdx5_inst_rmw(SD_LANE_SD_LANE_CFG_EXT_CFG_RST_SET(0),
SD_LANE_SD_LANE_CFG_EXT_CFG_RST, sd_lane_inst,
SD_LANE_SD_LANE_CFG(0));
/* Configure optimal settings for quiet mode */
sdx5_inst_rmw(SD_LANE_QUIET_MODE_6G_QUIET_MODE_SET(SPX5_SERDES_QUIET_MODE_VAL),
SD_LANE_QUIET_MODE_6G_QUIET_MODE, sd_lane_inst,
SD_LANE_QUIET_MODE_6G(0));
sdx5_inst_rmw(SD10G_LANE_LANE_06_CFG_PD_DRIVER_SET(pwdn), sdx5_inst_rmw(SD10G_LANE_LANE_06_CFG_PD_DRIVER_SET(pwdn),
SD10G_LANE_LANE_06_CFG_PD_DRIVER, SD10G_LANE_LANE_06_CFG_PD_DRIVER,
sd_inst, sd_inst,
...@@ -1939,159 +2195,6 @@ static int sparx5_serdes_clock_config(struct sparx5_serdes_macro *macro) ...@@ -1939,159 +2195,6 @@ static int sparx5_serdes_clock_config(struct sparx5_serdes_macro *macro)
return 0; return 0;
} }
static int sparx5_cmu_apply_cfg(struct sparx5_serdes_private *priv,
u32 cmu_idx,
void __iomem *cmu_tgt,
void __iomem *cmu_cfg_tgt,
u32 spd10g)
{
void __iomem **regs = priv->regs;
struct device *dev = priv->dev;
int value;
cmu_tgt = sdx5_inst_get(priv, TARGET_SD_CMU, cmu_idx);
cmu_cfg_tgt = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, cmu_idx);
if (cmu_idx == 1 || cmu_idx == 4 || cmu_idx == 7 ||
cmu_idx == 10 || cmu_idx == 13) {
spd10g = 0;
}
sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(1),
SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST,
cmu_cfg_tgt,
SD_CMU_CFG_SD_CMU_CFG(cmu_idx));
sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(0),
SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST,
cmu_cfg_tgt,
SD_CMU_CFG_SD_CMU_CFG(cmu_idx));
sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(1),
SD_CMU_CFG_SD_CMU_CFG_CMU_RST,
cmu_cfg_tgt,
SD_CMU_CFG_SD_CMU_CFG(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT_SET(0x1) |
SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT_SET(0x1) |
SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT_SET(0x1) |
SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT_SET(0x1) |
SD_CMU_CMU_45_R_EN_RATECHG_CTRL_SET(0x0),
SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT |
SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT |
SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT |
SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT |
SD_CMU_CMU_45_R_EN_RATECHG_CTRL,
cmu_tgt,
SD_CMU_CMU_45(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_SET(0),
SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0,
cmu_tgt,
SD_CMU_CMU_47(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_1B_CFG_RESERVE_7_0_SET(0),
SD_CMU_CMU_1B_CFG_RESERVE_7_0,
cmu_tgt,
SD_CMU_CMU_1B(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_0D_CFG_JC_BYP_SET(0x1),
SD_CMU_CMU_0D_CFG_JC_BYP,
cmu_tgt,
SD_CMU_CMU_0D(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_1F_CFG_VTUNE_SEL_SET(1),
SD_CMU_CMU_1F_CFG_VTUNE_SEL,
cmu_tgt,
SD_CMU_CMU_1F(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0_SET(3),
SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0,
cmu_tgt,
SD_CMU_CMU_00(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_SET(3),
SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0,
cmu_tgt,
SD_CMU_CMU_05(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_30_R_PLL_DLOL_EN_SET(1),
SD_CMU_CMU_30_R_PLL_DLOL_EN,
cmu_tgt,
SD_CMU_CMU_30(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_09_CFG_SW_10G_SET(spd10g),
SD_CMU_CMU_09_CFG_SW_10G,
cmu_tgt,
SD_CMU_CMU_09(cmu_idx));
sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(0),
SD_CMU_CFG_SD_CMU_CFG_CMU_RST,
cmu_cfg_tgt,
SD_CMU_CFG_SD_CMU_CFG(cmu_idx));
msleep(20);
sdx5_inst_rmw(SD_CMU_CMU_44_R_PLL_RSTN_SET(0),
SD_CMU_CMU_44_R_PLL_RSTN,
cmu_tgt,
SD_CMU_CMU_44(cmu_idx));
sdx5_inst_rmw(SD_CMU_CMU_44_R_PLL_RSTN_SET(1),
SD_CMU_CMU_44_R_PLL_RSTN,
cmu_tgt,
SD_CMU_CMU_44(cmu_idx));
msleep(20);
value = readl(sdx5_addr(regs, SD_CMU_CMU_E0(cmu_idx)));
value = SD_CMU_CMU_E0_PLL_LOL_UDL_GET(value);
if (value) {
dev_err(dev, "CMU PLL Loss of Lock: 0x%x\n", value);
return -EINVAL;
}
sdx5_inst_rmw(SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD_SET(0),
SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD,
cmu_tgt,
SD_CMU_CMU_0D(cmu_idx));
return 0;
}
static int sparx5_cmu_cfg(struct sparx5_serdes_private *priv, u32 cmu_idx)
{
void __iomem *cmu_tgt, *cmu_cfg_tgt;
u32 spd10g = 1;
if (cmu_idx == 1 || cmu_idx == 4 || cmu_idx == 7 ||
cmu_idx == 10 || cmu_idx == 13) {
spd10g = 0;
}
cmu_tgt = sdx5_inst_get(priv, TARGET_SD_CMU, cmu_idx);
cmu_cfg_tgt = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, cmu_idx);
return sparx5_cmu_apply_cfg(priv, cmu_idx, cmu_tgt, cmu_cfg_tgt, spd10g);
}
static int sparx5_serdes_cmu_enable(struct sparx5_serdes_private *priv)
{
int idx, err = 0;
if (!priv->cmu_enabled) {
for (idx = 0; idx < SPX5_CMU_MAX; idx++) {
err = sparx5_cmu_cfg(priv, idx);
if (err) {
dev_err(priv->dev, "CMU %u, error: %d\n", idx, err);
goto leave;
}
}
priv->cmu_enabled = true;
}
leave:
return err;
}
static int sparx5_serdes_get_serdesmode(phy_interface_t portmode, int speed) static int sparx5_serdes_get_serdesmode(phy_interface_t portmode, int speed)
{ {
switch (portmode) { switch (portmode) {
...@@ -2120,10 +2223,6 @@ static int sparx5_serdes_config(struct sparx5_serdes_macro *macro) ...@@ -2120,10 +2223,6 @@ static int sparx5_serdes_config(struct sparx5_serdes_macro *macro)
int serdesmode; int serdesmode;
int err; int err;
err = sparx5_serdes_cmu_enable(macro->priv);
if (err)
return err;
serdesmode = sparx5_serdes_get_serdesmode(macro->portmode, macro->speed); serdesmode = sparx5_serdes_get_serdesmode(macro->portmode, macro->speed);
if (serdesmode < 0) { if (serdesmode < 0) {
dev_err(dev, "SerDes %u, interface not supported: %s\n", dev_err(dev, "SerDes %u, interface not supported: %s\n",
...@@ -2215,9 +2314,6 @@ static int sparx5_serdes_reset(struct phy *phy) ...@@ -2215,9 +2314,6 @@ static int sparx5_serdes_reset(struct phy *phy)
struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); struct sparx5_serdes_macro *macro = phy_get_drvdata(phy);
int err; int err;
err = sparx5_serdes_cmu_enable(macro->priv);
if (err)
return err;
if (macro->serdestype == SPX5_SDT_25G) if (macro->serdestype == SPX5_SDT_25G)
err = sparx5_sd25g28_config(macro, true); err = sparx5_sd25g28_config(macro, true);
else else
...@@ -2308,6 +2404,9 @@ static int sparx5_phy_create(struct sparx5_serdes_private *priv, ...@@ -2308,6 +2404,9 @@ static int sparx5_phy_create(struct sparx5_serdes_private *priv,
phy_set_drvdata(*phy, macro); phy_set_drvdata(*phy, macro);
/* Power off serdes by default */
sparx5_serdes_power_off(*phy);
return 0; return 0;
} }
...@@ -2491,6 +2590,9 @@ static int sparx5_serdes_probe(struct platform_device *pdev) ...@@ -2491,6 +2590,9 @@ static int sparx5_serdes_probe(struct platform_device *pdev)
return err; return err;
} }
/* Power down all CMUs by default */
sparx5_serdes_cmu_power_off(priv);
provider = devm_of_phy_provider_register(priv->dev, sparx5_serdes_xlate); provider = devm_of_phy_provider_register(priv->dev, sparx5_serdes_xlate);
return PTR_ERR_OR_ZERO(provider); return PTR_ERR_OR_ZERO(provider);
......
...@@ -30,7 +30,6 @@ struct sparx5_serdes_private { ...@@ -30,7 +30,6 @@ struct sparx5_serdes_private {
struct device *dev; struct device *dev;
void __iomem *regs[NUM_TARGETS]; void __iomem *regs[NUM_TARGETS];
struct phy *phys[SPX5_SERDES_MAX]; struct phy *phys[SPX5_SERDES_MAX];
bool cmu_enabled;
unsigned long coreclock; unsigned long coreclock;
}; };
......
...@@ -2149,6 +2149,92 @@ enum sparx5_serdes_target { ...@@ -2149,6 +2149,92 @@ enum sparx5_serdes_target {
#define SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_GET(x)\ #define SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_GET(x)\
FIELD_GET(SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0, x) FIELD_GET(SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0, x)
/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_06 */
#define SD_CMU_CMU_06(t) \
__REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 4, 0, 1, 4)
#define SD_CMU_CMU_06_CFG_DISLOS BIT(0)
#define SD_CMU_CMU_06_CFG_DISLOS_SET(x)\
FIELD_PREP(SD_CMU_CMU_06_CFG_DISLOS, x)
#define SD_CMU_CMU_06_CFG_DISLOS_GET(x)\
FIELD_GET(SD_CMU_CMU_06_CFG_DISLOS, x)
#define SD_CMU_CMU_06_CFG_DISLOL BIT(1)
#define SD_CMU_CMU_06_CFG_DISLOL_SET(x)\
FIELD_PREP(SD_CMU_CMU_06_CFG_DISLOL, x)
#define SD_CMU_CMU_06_CFG_DISLOL_GET(x)\
FIELD_GET(SD_CMU_CMU_06_CFG_DISLOL, x)
#define SD_CMU_CMU_06_CFG_DCLOL BIT(2)
#define SD_CMU_CMU_06_CFG_DCLOL_SET(x)\
FIELD_PREP(SD_CMU_CMU_06_CFG_DCLOL, x)
#define SD_CMU_CMU_06_CFG_DCLOL_GET(x)\
FIELD_GET(SD_CMU_CMU_06_CFG_DCLOL, x)
#define SD_CMU_CMU_06_CFG_FORCE_RX_FILT BIT(3)
#define SD_CMU_CMU_06_CFG_FORCE_RX_FILT_SET(x)\
FIELD_PREP(SD_CMU_CMU_06_CFG_FORCE_RX_FILT, x)
#define SD_CMU_CMU_06_CFG_FORCE_RX_FILT_GET(x)\
FIELD_GET(SD_CMU_CMU_06_CFG_FORCE_RX_FILT, x)
#define SD_CMU_CMU_06_CFG_CTRL_LOGIC_PD BIT(4)
#define SD_CMU_CMU_06_CFG_CTRL_LOGIC_PD_SET(x)\
FIELD_PREP(SD_CMU_CMU_06_CFG_CTRL_LOGIC_PD, x)
#define SD_CMU_CMU_06_CFG_CTRL_LOGIC_PD_GET(x)\
FIELD_GET(SD_CMU_CMU_06_CFG_CTRL_LOGIC_PD, x)
#define SD_CMU_CMU_06_CFG_VCO_PD BIT(5)
#define SD_CMU_CMU_06_CFG_VCO_PD_SET(x)\
FIELD_PREP(SD_CMU_CMU_06_CFG_VCO_PD, x)
#define SD_CMU_CMU_06_CFG_VCO_PD_GET(x)\
FIELD_GET(SD_CMU_CMU_06_CFG_VCO_PD, x)
#define SD_CMU_CMU_06_CFG_VCO_CAL_RESETN BIT(6)
#define SD_CMU_CMU_06_CFG_VCO_CAL_RESETN_SET(x)\
FIELD_PREP(SD_CMU_CMU_06_CFG_VCO_CAL_RESETN, x)
#define SD_CMU_CMU_06_CFG_VCO_CAL_RESETN_GET(x)\
FIELD_GET(SD_CMU_CMU_06_CFG_VCO_CAL_RESETN, x)
#define SD_CMU_CMU_06_CFG_VCO_CAL_BYP BIT(7)
#define SD_CMU_CMU_06_CFG_VCO_CAL_BYP_SET(x)\
FIELD_PREP(SD_CMU_CMU_06_CFG_VCO_CAL_BYP, x)
#define SD_CMU_CMU_06_CFG_VCO_CAL_BYP_GET(x)\
FIELD_GET(SD_CMU_CMU_06_CFG_VCO_CAL_BYP, x)
/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_08 */
#define SD_CMU_CMU_08(t) \
__REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 12, 0, 1, 4)
#define SD_CMU_CMU_08_CFG_VFILT2PAD BIT(0)
#define SD_CMU_CMU_08_CFG_VFILT2PAD_SET(x)\
FIELD_PREP(SD_CMU_CMU_08_CFG_VFILT2PAD, x)
#define SD_CMU_CMU_08_CFG_VFILT2PAD_GET(x)\
FIELD_GET(SD_CMU_CMU_08_CFG_VFILT2PAD, x)
#define SD_CMU_CMU_08_CFG_EN_DUMMY BIT(1)
#define SD_CMU_CMU_08_CFG_EN_DUMMY_SET(x)\
FIELD_PREP(SD_CMU_CMU_08_CFG_EN_DUMMY, x)
#define SD_CMU_CMU_08_CFG_EN_DUMMY_GET(x)\
FIELD_GET(SD_CMU_CMU_08_CFG_EN_DUMMY, x)
#define SD_CMU_CMU_08_CFG_CK_TREE_PD BIT(2)
#define SD_CMU_CMU_08_CFG_CK_TREE_PD_SET(x)\
FIELD_PREP(SD_CMU_CMU_08_CFG_CK_TREE_PD, x)
#define SD_CMU_CMU_08_CFG_CK_TREE_PD_GET(x)\
FIELD_GET(SD_CMU_CMU_08_CFG_CK_TREE_PD, x)
#define SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN BIT(3)
#define SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN_SET(x)\
FIELD_PREP(SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN, x)
#define SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN_GET(x)\
FIELD_GET(SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN, x)
#define SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN_EN BIT(4)
#define SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN_EN_SET(x)\
FIELD_PREP(SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN_EN, x)
#define SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN_EN_GET(x)\
FIELD_GET(SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN_EN, x)
/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_09 */ /* SD10G_CMU_TARGET:CMU_GRP_1:CMU_09 */
#define SD_CMU_CMU_09(t) __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 16, 0, 1, 4) #define SD_CMU_CMU_09(t) __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 16, 0, 1, 4)
...@@ -2443,6 +2529,16 @@ enum sparx5_serdes_target { ...@@ -2443,6 +2529,16 @@ enum sparx5_serdes_target {
#define SD_LANE_SD_LANE_STAT_DBG_OBS_GET(x)\ #define SD_LANE_SD_LANE_STAT_DBG_OBS_GET(x)\
FIELD_GET(SD_LANE_SD_LANE_STAT_DBG_OBS, x) FIELD_GET(SD_LANE_SD_LANE_STAT_DBG_OBS, x)
/* SD_LANE_TARGET:SD_PWR_CFG:QUIET_MODE_6G */
#define SD_LANE_QUIET_MODE_6G(t) \
__REG(TARGET_SD_LANE, t, 25, 24, 0, 1, 8, 4, 0, 1, 4)
#define SD_LANE_QUIET_MODE_6G_QUIET_MODE GENMASK(24, 0)
#define SD_LANE_QUIET_MODE_6G_QUIET_MODE_SET(x)\
FIELD_PREP(SD_LANE_QUIET_MODE_6G_QUIET_MODE, x)
#define SD_LANE_QUIET_MODE_6G_QUIET_MODE_GET(x)\
FIELD_GET(SD_LANE_QUIET_MODE_6G_QUIET_MODE, x)
/* SD_LANE_TARGET:CFG_STAT_FX100:MISC */ /* SD_LANE_TARGET:CFG_STAT_FX100:MISC */
#define SD_LANE_MISC(t) __REG(TARGET_SD_LANE, t, 25, 56, 0, 1, 56, 0, 0, 1, 4) #define SD_LANE_MISC(t) __REG(TARGET_SD_LANE, t, 25, 56, 0, 1, 56, 0, 0, 1, 4)
...@@ -2692,4 +2788,14 @@ enum sparx5_serdes_target { ...@@ -2692,4 +2788,14 @@ enum sparx5_serdes_target {
#define SD_LANE_25G_SD_LANE_STAT_DBG_OBS_GET(x)\ #define SD_LANE_25G_SD_LANE_STAT_DBG_OBS_GET(x)\
FIELD_GET(SD_LANE_25G_SD_LANE_STAT_DBG_OBS, x) FIELD_GET(SD_LANE_25G_SD_LANE_STAT_DBG_OBS, x)
/* SD25G_CFG_TARGET:SD_PWR_CFG:QUIET_MODE_6G */
#define SD_LANE_25G_QUIET_MODE_6G(t) \
__REG(TARGET_SD_LANE_25G, t, 8, 28, 0, 1, 8, 4, 0, 1, 4)
#define SD_LANE_25G_QUIET_MODE_6G_QUIET_MODE GENMASK(24, 0)
#define SD_LANE_25G_QUIET_MODE_6G_QUIET_MODE_SET(x)\
FIELD_PREP(SD_LANE_25G_QUIET_MODE_6G_QUIET_MODE, x)
#define SD_LANE_25G_QUIET_MODE_6G_QUIET_MODE_GET(x)\
FIELD_GET(SD_LANE_25G_QUIET_MODE_6G_QUIET_MODE, x)
#endif /* _SPARX5_SERDES_REGS_H_ */ #endif /* _SPARX5_SERDES_REGS_H_ */
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/debugfs.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
static struct class *phy_class; static struct class *phy_class;
static struct dentry *phy_debugfs_root;
static DEFINE_MUTEX(phy_provider_mutex); static DEFINE_MUTEX(phy_provider_mutex);
static LIST_HEAD(phy_provider_list); static LIST_HEAD(phy_provider_list);
static LIST_HEAD(phys); static LIST_HEAD(phys);
...@@ -996,6 +998,8 @@ struct phy *phy_create(struct device *dev, struct device_node *node, ...@@ -996,6 +998,8 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
pm_runtime_no_callbacks(&phy->dev); pm_runtime_no_callbacks(&phy->dev);
} }
phy->debugfs = debugfs_create_dir(dev_name(&phy->dev), phy_debugfs_root);
return phy; return phy;
put_dev: put_dev:
...@@ -1226,6 +1230,7 @@ static void phy_release(struct device *dev) ...@@ -1226,6 +1230,7 @@ static void phy_release(struct device *dev)
phy = to_phy(dev); phy = to_phy(dev);
dev_vdbg(dev, "releasing '%s'\n", dev_name(dev)); dev_vdbg(dev, "releasing '%s'\n", dev_name(dev));
debugfs_remove_recursive(phy->debugfs);
regulator_put(phy->pwr); regulator_put(phy->pwr);
ida_simple_remove(&phy_ida, phy->id); ida_simple_remove(&phy_ida, phy->id);
kfree(phy); kfree(phy);
...@@ -1242,6 +1247,15 @@ static int __init phy_core_init(void) ...@@ -1242,6 +1247,15 @@ static int __init phy_core_init(void)
phy_class->dev_release = phy_release; phy_class->dev_release = phy_release;
phy_debugfs_root = debugfs_create_dir("phy", NULL);
return 0; return 0;
} }
device_initcall(phy_core_init); device_initcall(phy_core_init);
static void __exit phy_core_exit(void)
{
debugfs_remove_recursive(phy_debugfs_root);
class_destroy(phy_class);
}
module_exit(phy_core_exit);
...@@ -59,8 +59,11 @@ if PHY_QCOM_QMP ...@@ -59,8 +59,11 @@ if PHY_QCOM_QMP
config PHY_QCOM_QMP_COMBO config PHY_QCOM_QMP_COMBO
tristate "Qualcomm QMP Combo PHY Driver" tristate "Qualcomm QMP Combo PHY Driver"
default PHY_QCOM_QMP default PHY_QCOM_QMP
depends on TYPEC || TYPEC=n
depends on DRM || DRM=n
select GENERIC_PHY select GENERIC_PHY
select MFD_SYSCON select MFD_SYSCON
select DRM_PANEL_BRIDGE if DRM
help help
Enable this to support the QMP Combo PHY transceiver that is used Enable this to support the QMP Combo PHY transceiver that is used
with USB3 and DisplayPort controllers on Qualcomm chips. with USB3 and DisplayPort controllers on Qualcomm chips.
...@@ -185,3 +188,12 @@ config PHY_QCOM_IPQ806X_USB ...@@ -185,3 +188,12 @@ config PHY_QCOM_IPQ806X_USB
This option enables support for the Synopsis PHYs present inside the This option enables support for the Synopsis PHYs present inside the
Qualcomm USB3.0 DWC3 controller on ipq806x SoC. This driver supports Qualcomm USB3.0 DWC3 controller on ipq806x SoC. This driver supports
both HS and SS PHY controllers. both HS and SS PHY controllers.
config PHY_QCOM_SGMII_ETH
tristate "Qualcomm DWMAC SGMII SerDes/PHY driver"
depends on OF && (ARCH_QCOM || COMPILE_TEST)
depends on HAS_IOMEM
select GENERIC_PHY
help
Enable this to support the internal SerDes/SGMII PHY on various
Qualcomm chipsets.
...@@ -20,4 +20,5 @@ obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o ...@@ -20,4 +20,5 @@ obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
obj-$(CONFIG_PHY_QCOM_USB_HS_28NM) += phy-qcom-usb-hs-28nm.o obj-$(CONFIG_PHY_QCOM_USB_HS_28NM) += phy-qcom-usb-hs-28nm.o
obj-$(CONFIG_PHY_QCOM_USB_SS) += phy-qcom-usb-ss.o obj-$(CONFIG_PHY_QCOM_USB_SS) += phy-qcom-usb-ss.o
obj-$(CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2)+= phy-qcom-snps-femto-v2.o obj-$(CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2)+= phy-qcom-snps-femto-v2.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_USB) += phy-qcom-ipq806x-usb.o obj-$(CONFIG_PHY_QCOM_IPQ806X_USB) += phy-qcom-ipq806x-usb.o
obj-$(CONFIG_PHY_QCOM_SGMII_ETH) += phy-qcom-sgmii-eth.o
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb/typec.h>
#include <linux/usb/typec_mux.h>
#include <drm/drm_bridge.h>
#include <dt-bindings/phy/phy-qcom-qmp.h> #include <dt-bindings/phy/phy-qcom-qmp.h>
...@@ -63,6 +67,10 @@ ...@@ -63,6 +67,10 @@
/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */ /* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
#define CLAMP_EN BIT(0) /* enables i/o clamp_n */ #define CLAMP_EN BIT(0) /* enables i/o clamp_n */
/* QPHY_V3_DP_COM_TYPEC_CTRL register bits */
#define SW_PORTSELECT_VAL BIT(0)
#define SW_PORTSELECT_MUX BIT(1)
#define PHY_INIT_COMPLETE_TIMEOUT 10000 #define PHY_INIT_COMPLETE_TIMEOUT 10000
struct qmp_phy_init_tbl { struct qmp_phy_init_tbl {
...@@ -1315,14 +1323,21 @@ struct qmp_combo { ...@@ -1315,14 +1323,21 @@ struct qmp_combo {
struct phy *usb_phy; struct phy *usb_phy;
enum phy_mode mode; enum phy_mode mode;
unsigned int usb_init_count;
struct phy *dp_phy; struct phy *dp_phy;
unsigned int dp_aux_cfg; unsigned int dp_aux_cfg;
struct phy_configure_opts_dp dp_opts; struct phy_configure_opts_dp dp_opts;
unsigned int dp_init_count;
struct clk_fixed_rate pipe_clk_fixed; struct clk_fixed_rate pipe_clk_fixed;
struct clk_hw dp_link_hw; struct clk_hw dp_link_hw;
struct clk_hw dp_pixel_hw; struct clk_hw dp_pixel_hw;
struct drm_bridge bridge;
struct typec_switch_dev *sw;
enum typec_orientation orientation;
}; };
static void qmp_v3_dp_aux_init(struct qmp_combo *qmp); static void qmp_v3_dp_aux_init(struct qmp_combo *qmp);
...@@ -1954,30 +1969,24 @@ static void qmp_v3_configure_dp_tx(struct qmp_combo *qmp) ...@@ -1954,30 +1969,24 @@ static void qmp_v3_configure_dp_tx(struct qmp_combo *qmp)
static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp) static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp)
{ {
bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
u32 val; u32 val;
bool reverse = false;
val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN; DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN;
/* if (dp_opts->lanes == 4 || reverse)
* TODO: Assume orientation is CC1 for now and two lanes, need to val |= DP_PHY_PD_CTL_LANE_0_1_PWRDN;
* use type-c connector to understand orientation and lanes. if (dp_opts->lanes == 4 || !reverse)
* val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
* Otherwise val changes to be like below if this code understood
* the orientation of the type-c cable.
*
* if (lane_cnt == 4 || orientation == ORIENTATION_CC2)
* val |= DP_PHY_PD_CTL_LANE_0_1_PWRDN;
* if (lane_cnt == 4 || orientation == ORIENTATION_CC1)
* val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
* if (orientation == ORIENTATION_CC2)
* writel(0x4c, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_MODE);
*/
val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
writel(0x5c, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE); if (reverse)
writel(0x4c, qmp->pcs + QSERDES_DP_PHY_MODE);
else
writel(0x5c, qmp->pcs + QSERDES_DP_PHY_MODE);
return reverse; return reverse;
} }
...@@ -2142,6 +2151,7 @@ static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp) ...@@ -2142,6 +2151,7 @@ static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp)
static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp, static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp,
unsigned int com_resetm_ctrl_reg, unsigned int com_resetm_ctrl_reg,
unsigned int com_c_ready_status_reg, unsigned int com_c_ready_status_reg,
unsigned int com_cmn_status_reg,
unsigned int dp_phy_status_reg) unsigned int dp_phy_status_reg)
{ {
const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
...@@ -2198,14 +2208,14 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp, ...@@ -2198,14 +2208,14 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp,
10000)) 10000))
return -ETIMEDOUT; return -ETIMEDOUT;
if (readl_poll_timeout(qmp->dp_serdes + QSERDES_V4_COM_CMN_STATUS, if (readl_poll_timeout(qmp->dp_serdes + com_cmn_status_reg,
status, status,
((status & BIT(0)) > 0), ((status & BIT(0)) > 0),
500, 500,
10000)) 10000))
return -ETIMEDOUT; return -ETIMEDOUT;
if (readl_poll_timeout(qmp->dp_serdes + QSERDES_V4_COM_CMN_STATUS, if (readl_poll_timeout(qmp->dp_serdes + com_cmn_status_reg,
status, status,
((status & BIT(1)) > 0), ((status & BIT(1)) > 0),
500, 500,
...@@ -2233,14 +2243,15 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp, ...@@ -2233,14 +2243,15 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp,
static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp)
{ {
bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
u32 bias0_en, drvr0_en, bias1_en, drvr1_en; u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
bool reverse = false;
u32 status; u32 status;
int ret; int ret;
ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V4_COM_RESETSM_CNTRL, ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V4_COM_RESETSM_CNTRL,
QSERDES_V4_COM_C_READY_STATUS, QSERDES_V4_COM_C_READY_STATUS,
QSERDES_V4_COM_CMN_STATUS,
QSERDES_V4_DP_PHY_STATUS); QSERDES_V4_DP_PHY_STATUS);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -2297,14 +2308,15 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) ...@@ -2297,14 +2308,15 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp)
static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp) static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp)
{ {
bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
u32 bias0_en, drvr0_en, bias1_en, drvr1_en; u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
bool reverse = false;
u32 status; u32 status;
int ret; int ret;
ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V4_COM_RESETSM_CNTRL, ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V4_COM_RESETSM_CNTRL,
QSERDES_V4_COM_C_READY_STATUS, QSERDES_V4_COM_C_READY_STATUS,
QSERDES_V4_COM_CMN_STATUS,
QSERDES_V4_DP_PHY_STATUS); QSERDES_V4_DP_PHY_STATUS);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -2356,14 +2368,15 @@ static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp) ...@@ -2356,14 +2368,15 @@ static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp)
static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp) static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp)
{ {
bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
u32 bias0_en, drvr0_en, bias1_en, drvr1_en; u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
bool reverse = false;
u32 status; u32 status;
int ret; int ret;
ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V6_COM_RESETSM_CNTRL, ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V6_COM_RESETSM_CNTRL,
QSERDES_V6_COM_C_READY_STATUS, QSERDES_V6_COM_C_READY_STATUS,
QSERDES_V6_COM_CMN_STATUS,
QSERDES_V6_DP_PHY_STATUS); QSERDES_V6_DP_PHY_STATUS);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -2437,12 +2450,16 @@ static int qmp_combo_dp_configure(struct phy *phy, union phy_configure_opts *opt ...@@ -2437,12 +2450,16 @@ static int qmp_combo_dp_configure(struct phy *phy, union phy_configure_opts *opt
struct qmp_combo *qmp = phy_get_drvdata(phy); struct qmp_combo *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg; const struct qmp_phy_cfg *cfg = qmp->cfg;
mutex_lock(&qmp->phy_mutex);
memcpy(&qmp->dp_opts, dp_opts, sizeof(*dp_opts)); memcpy(&qmp->dp_opts, dp_opts, sizeof(*dp_opts));
if (qmp->dp_opts.set_voltages) { if (qmp->dp_opts.set_voltages) {
cfg->configure_dp_tx(qmp); cfg->configure_dp_tx(qmp);
qmp->dp_opts.set_voltages = 0; qmp->dp_opts.set_voltages = 0;
} }
mutex_unlock(&qmp->phy_mutex);
return 0; return 0;
} }
...@@ -2450,24 +2467,27 @@ static int qmp_combo_dp_calibrate(struct phy *phy) ...@@ -2450,24 +2467,27 @@ static int qmp_combo_dp_calibrate(struct phy *phy)
{ {
struct qmp_combo *qmp = phy_get_drvdata(phy); struct qmp_combo *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg; const struct qmp_phy_cfg *cfg = qmp->cfg;
int ret = 0;
mutex_lock(&qmp->phy_mutex);
if (cfg->calibrate_dp_phy) if (cfg->calibrate_dp_phy)
return cfg->calibrate_dp_phy(qmp); ret = cfg->calibrate_dp_phy(qmp);
return 0; mutex_unlock(&qmp->phy_mutex);
return ret;
} }
static int qmp_combo_com_init(struct qmp_combo *qmp) static int qmp_combo_com_init(struct qmp_combo *qmp, bool force)
{ {
const struct qmp_phy_cfg *cfg = qmp->cfg; const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *com = qmp->com; void __iomem *com = qmp->com;
int ret; int ret;
u32 val;
mutex_lock(&qmp->phy_mutex); if (!force && qmp->init_count++)
if (qmp->init_count++) {
mutex_unlock(&qmp->phy_mutex);
return 0; return 0;
}
ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
if (ret) { if (ret) {
...@@ -2498,10 +2518,12 @@ static int qmp_combo_com_init(struct qmp_combo *qmp) ...@@ -2498,10 +2518,12 @@ static int qmp_combo_com_init(struct qmp_combo *qmp)
SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
/* Default type-c orientation, i.e CC1 */ /* Use software based port select and switch on typec orientation */
qphy_setbits(com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02); val = SW_PORTSELECT_MUX;
if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
qphy_setbits(com, QPHY_V3_DP_COM_PHY_MODE_CTRL, USB3_MODE | DP_MODE); val |= SW_PORTSELECT_VAL;
writel(val, com + QPHY_V3_DP_COM_TYPEC_CTRL);
writel(USB3_MODE | DP_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL);
/* bring both QMP USB and QMP DP PHYs PCS block out of reset */ /* bring both QMP USB and QMP DP PHYs PCS block out of reset */
qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
...@@ -2514,8 +2536,6 @@ static int qmp_combo_com_init(struct qmp_combo *qmp) ...@@ -2514,8 +2536,6 @@ static int qmp_combo_com_init(struct qmp_combo *qmp)
qphy_setbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], qphy_setbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
SW_PWRDN); SW_PWRDN);
mutex_unlock(&qmp->phy_mutex);
return 0; return 0;
err_assert_reset: err_assert_reset:
...@@ -2524,20 +2544,16 @@ static int qmp_combo_com_init(struct qmp_combo *qmp) ...@@ -2524,20 +2544,16 @@ static int qmp_combo_com_init(struct qmp_combo *qmp)
regulator_bulk_disable(cfg->num_vregs, qmp->vregs); regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
err_decrement_count: err_decrement_count:
qmp->init_count--; qmp->init_count--;
mutex_unlock(&qmp->phy_mutex);
return ret; return ret;
} }
static int qmp_combo_com_exit(struct qmp_combo *qmp) static int qmp_combo_com_exit(struct qmp_combo *qmp, bool force)
{ {
const struct qmp_phy_cfg *cfg = qmp->cfg; const struct qmp_phy_cfg *cfg = qmp->cfg;
mutex_lock(&qmp->phy_mutex); if (!force && --qmp->init_count)
if (--qmp->init_count) {
mutex_unlock(&qmp->phy_mutex);
return 0; return 0;
}
reset_control_bulk_assert(cfg->num_resets, qmp->resets); reset_control_bulk_assert(cfg->num_resets, qmp->resets);
...@@ -2545,8 +2561,6 @@ static int qmp_combo_com_exit(struct qmp_combo *qmp) ...@@ -2545,8 +2561,6 @@ static int qmp_combo_com_exit(struct qmp_combo *qmp)
regulator_bulk_disable(cfg->num_vregs, qmp->vregs); regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
mutex_unlock(&qmp->phy_mutex);
return 0; return 0;
} }
...@@ -2556,20 +2570,32 @@ static int qmp_combo_dp_init(struct phy *phy) ...@@ -2556,20 +2570,32 @@ static int qmp_combo_dp_init(struct phy *phy)
const struct qmp_phy_cfg *cfg = qmp->cfg; const struct qmp_phy_cfg *cfg = qmp->cfg;
int ret; int ret;
ret = qmp_combo_com_init(qmp); mutex_lock(&qmp->phy_mutex);
ret = qmp_combo_com_init(qmp, false);
if (ret) if (ret)
return ret; goto out_unlock;
cfg->dp_aux_init(qmp); cfg->dp_aux_init(qmp);
return 0; qmp->dp_init_count++;
out_unlock:
mutex_unlock(&qmp->phy_mutex);
return ret;
} }
static int qmp_combo_dp_exit(struct phy *phy) static int qmp_combo_dp_exit(struct phy *phy)
{ {
struct qmp_combo *qmp = phy_get_drvdata(phy); struct qmp_combo *qmp = phy_get_drvdata(phy);
qmp_combo_com_exit(qmp); mutex_lock(&qmp->phy_mutex);
qmp_combo_com_exit(qmp, false);
qmp->dp_init_count--;
mutex_unlock(&qmp->phy_mutex);
return 0; return 0;
} }
...@@ -2581,6 +2607,8 @@ static int qmp_combo_dp_power_on(struct phy *phy) ...@@ -2581,6 +2607,8 @@ static int qmp_combo_dp_power_on(struct phy *phy)
void __iomem *tx = qmp->dp_tx; void __iomem *tx = qmp->dp_tx;
void __iomem *tx2 = qmp->dp_tx2; void __iomem *tx2 = qmp->dp_tx2;
mutex_lock(&qmp->phy_mutex);
qmp_combo_dp_serdes_init(qmp); qmp_combo_dp_serdes_init(qmp);
qmp_combo_configure_lane(tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1); qmp_combo_configure_lane(tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1);
...@@ -2592,6 +2620,8 @@ static int qmp_combo_dp_power_on(struct phy *phy) ...@@ -2592,6 +2620,8 @@ static int qmp_combo_dp_power_on(struct phy *phy)
/* Configure link rate, swing, etc. */ /* Configure link rate, swing, etc. */
cfg->configure_dp_phy(qmp); cfg->configure_dp_phy(qmp);
mutex_unlock(&qmp->phy_mutex);
return 0; return 0;
} }
...@@ -2599,9 +2629,13 @@ static int qmp_combo_dp_power_off(struct phy *phy) ...@@ -2599,9 +2629,13 @@ static int qmp_combo_dp_power_off(struct phy *phy)
{ {
struct qmp_combo *qmp = phy_get_drvdata(phy); struct qmp_combo *qmp = phy_get_drvdata(phy);
mutex_lock(&qmp->phy_mutex);
/* Assert DP PHY power down */ /* Assert DP PHY power down */
writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
mutex_unlock(&qmp->phy_mutex);
return 0; return 0;
} }
...@@ -2687,14 +2721,21 @@ static int qmp_combo_usb_init(struct phy *phy) ...@@ -2687,14 +2721,21 @@ static int qmp_combo_usb_init(struct phy *phy)
struct qmp_combo *qmp = phy_get_drvdata(phy); struct qmp_combo *qmp = phy_get_drvdata(phy);
int ret; int ret;
ret = qmp_combo_com_init(qmp); mutex_lock(&qmp->phy_mutex);
ret = qmp_combo_com_init(qmp, false);
if (ret) if (ret)
return ret; goto out_unlock;
ret = qmp_combo_usb_power_on(phy); ret = qmp_combo_usb_power_on(phy);
if (ret) if (ret) {
qmp_combo_com_exit(qmp); qmp_combo_com_exit(qmp, false);
goto out_unlock;
}
qmp->usb_init_count++;
out_unlock:
mutex_unlock(&qmp->phy_mutex);
return ret; return ret;
} }
...@@ -2703,11 +2744,20 @@ static int qmp_combo_usb_exit(struct phy *phy) ...@@ -2703,11 +2744,20 @@ static int qmp_combo_usb_exit(struct phy *phy)
struct qmp_combo *qmp = phy_get_drvdata(phy); struct qmp_combo *qmp = phy_get_drvdata(phy);
int ret; int ret;
mutex_lock(&qmp->phy_mutex);
ret = qmp_combo_usb_power_off(phy); ret = qmp_combo_usb_power_off(phy);
if (ret) if (ret)
return ret; goto out_unlock;
ret = qmp_combo_com_exit(qmp, false);
if (ret)
goto out_unlock;
qmp->usb_init_count--;
return qmp_combo_com_exit(qmp); out_unlock:
mutex_unlock(&qmp->phy_mutex);
return ret;
} }
static int qmp_combo_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode) static int qmp_combo_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode)
...@@ -3173,6 +3223,103 @@ static int qmp_combo_register_clocks(struct qmp_combo *qmp, struct device_node * ...@@ -3173,6 +3223,103 @@ static int qmp_combo_register_clocks(struct qmp_combo *qmp, struct device_node *
return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, dp_np); return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, dp_np);
} }
#if IS_ENABLED(CONFIG_TYPEC)
static int qmp_combo_typec_switch_set(struct typec_switch_dev *sw,
enum typec_orientation orientation)
{
struct qmp_combo *qmp = typec_switch_get_drvdata(sw);
const struct qmp_phy_cfg *cfg = qmp->cfg;
if (orientation == qmp->orientation || orientation == TYPEC_ORIENTATION_NONE)
return 0;
mutex_lock(&qmp->phy_mutex);
qmp->orientation = orientation;
if (qmp->init_count) {
if (qmp->usb_init_count)
qmp_combo_usb_power_off(qmp->usb_phy);
qmp_combo_com_exit(qmp, true);
qmp_combo_com_init(qmp, true);
if (qmp->usb_init_count)
qmp_combo_usb_power_on(qmp->usb_phy);
if (qmp->dp_init_count)
cfg->dp_aux_init(qmp);
}
mutex_unlock(&qmp->phy_mutex);
return 0;
}
static void qmp_combo_typec_unregister(void *data)
{
struct qmp_combo *qmp = data;
typec_switch_unregister(qmp->sw);
}
static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
{
struct typec_switch_desc sw_desc = {};
struct device *dev = qmp->dev;
sw_desc.drvdata = qmp;
sw_desc.fwnode = dev->fwnode;
sw_desc.set = qmp_combo_typec_switch_set;
qmp->sw = typec_switch_register(dev, &sw_desc);
if (IS_ERR(qmp->sw)) {
dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw);
return PTR_ERR(qmp->sw);
}
return devm_add_action_or_reset(dev, qmp_combo_typec_unregister, qmp);
}
#else
static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
{
return 0;
}
#endif
#if IS_ENABLED(CONFIG_DRM)
static int qmp_combo_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct qmp_combo *qmp = container_of(bridge, struct qmp_combo, bridge);
struct drm_bridge *next_bridge;
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
next_bridge = devm_drm_of_get_bridge(qmp->dev, qmp->dev->of_node, 0, 0);
if (IS_ERR(next_bridge)) {
dev_err(qmp->dev, "failed to acquire drm_bridge: %pe\n", next_bridge);
return PTR_ERR(next_bridge);
}
return drm_bridge_attach(bridge->encoder, next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
}
static const struct drm_bridge_funcs qmp_combo_bridge_funcs = {
.attach = qmp_combo_bridge_attach,
};
static int qmp_combo_dp_register_bridge(struct qmp_combo *qmp)
{
qmp->bridge.funcs = &qmp_combo_bridge_funcs;
qmp->bridge.of_node = qmp->dev->of_node;
return devm_drm_bridge_add(qmp->dev, &qmp->bridge);
}
#else
static int qmp_combo_dp_register_bridge(struct qmp_combo *qmp)
{
return 0;
}
#endif
static int qmp_combo_parse_dt_lecacy_dp(struct qmp_combo *qmp, struct device_node *np) static int qmp_combo_parse_dt_lecacy_dp(struct qmp_combo *qmp, struct device_node *np)
{ {
struct device *dev = qmp->dev; struct device *dev = qmp->dev;
...@@ -3353,6 +3500,8 @@ static int qmp_combo_probe(struct platform_device *pdev) ...@@ -3353,6 +3500,8 @@ static int qmp_combo_probe(struct platform_device *pdev)
qmp->dev = dev; qmp->dev = dev;
qmp->orientation = TYPEC_ORIENTATION_NORMAL;
qmp->cfg = of_device_get_match_data(dev); qmp->cfg = of_device_get_match_data(dev);
if (!qmp->cfg) if (!qmp->cfg)
return -EINVAL; return -EINVAL;
...@@ -3371,6 +3520,14 @@ static int qmp_combo_probe(struct platform_device *pdev) ...@@ -3371,6 +3520,14 @@ static int qmp_combo_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
ret = qmp_combo_typec_switch_register(qmp);
if (ret)
return ret;
ret = qmp_combo_dp_register_bridge(qmp);
if (ret)
return ret;
/* Check for legacy binding with child nodes. */ /* Check for legacy binding with child nodes. */
usb_np = of_get_child_by_name(dev->of_node, "usb3-phy"); usb_np = of_get_child_by_name(dev->of_node, "usb3-phy");
if (usb_np) { if (usb_np) {
......
...@@ -139,6 +139,88 @@ static const unsigned int qmp_v5_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { ...@@ -139,6 +139,88 @@ static const unsigned int qmp_v5_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V5_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V5_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR,
}; };
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),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),
QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06),
/* PLL and Loop filter settings */
QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x68),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0xab),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0xaa),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x02),
QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x09),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0xa0),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xaa),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x29),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a),
/* SSC settings */
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x7d),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x05),
};
static const struct qmp_phy_init_tbl ipq9574_usb3_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45),
QMP_PHY_INIT_CFG(QSERDES_TX_RCV_DETECT_LVL_2, 0x12),
QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06),
};
static const struct qmp_phy_init_tbl ipq9574_usb3_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x06),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x6c),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4c),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xb8),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x03),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x16),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_ENABLES, 0x0c),
};
static const struct qmp_phy_init_tbl ipq9574_usb3_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0e),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x85),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x17),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0f),
};
static const struct qmp_phy_init_tbl ipq8074_usb3_serdes_tbl[] = { static const struct qmp_phy_init_tbl ipq8074_usb3_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x1a), QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x1a),
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
...@@ -1408,12 +1490,36 @@ static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_pcs_tbl[] = { ...@@ -1408,12 +1490,36 @@ static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V5_PCS_REFGEN_REQ_CONFIG1, 0x21), QMP_PHY_INIT_CFG(QPHY_V5_PCS_REFGEN_REQ_CONFIG1, 0x21),
}; };
static const struct qmp_phy_init_tbl sa8775p_usb3_uniphy_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG1, 0xc4),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG2, 0x89),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG3, 0x20),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG6, 0x13),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_RX_SIGDET_LVL, 0xaa),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCS_TX_RX_CONFIG, 0x0c),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_POWER_STATE_CONFIG1, 0x6f),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_CDR_RESET_TIME, 0x0a),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_ALIGN_DETECT_CONFIG1, 0x88),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_ALIGN_DETECT_CONFIG2, 0x13),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_EQ_CONFIG1, 0x4b),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_EQ_CONFIG5, 0x10),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_REFGEN_REQ_CONFIG1, 0x21),
};
struct qmp_usb_offsets { struct qmp_usb_offsets {
u16 serdes; u16 serdes;
u16 pcs; u16 pcs;
u16 pcs_misc;
u16 pcs_usb; u16 pcs_usb;
u16 tx; u16 tx;
u16 rx; u16 rx;
/* for PHYs with >= 2 lanes */
u16 tx2;
u16 rx2;
}; };
/* struct qmp_phy_cfg - per-PHY initialization config */ /* struct qmp_phy_cfg - per-PHY initialization config */
...@@ -1558,6 +1664,24 @@ static const char * const qmp_phy_vreg_l[] = { ...@@ -1558,6 +1664,24 @@ static const char * const qmp_phy_vreg_l[] = {
"vdda-phy", "vdda-pll", "vdda-phy", "vdda-pll",
}; };
static const struct qmp_usb_offsets qmp_usb_offsets_ipq9574 = {
.serdes = 0,
.pcs = 0x800,
.pcs_usb = 0x800,
.tx = 0x200,
.rx = 0x400,
};
static const struct qmp_usb_offsets qmp_usb_offsets_v3 = {
.serdes = 0,
.pcs = 0xc00,
.pcs_misc = 0xa00,
.tx = 0x200,
.rx = 0x400,
.tx2 = 0x600,
.rx2 = 0x800,
};
static const struct qmp_usb_offsets qmp_usb_offsets_v5 = { static const struct qmp_usb_offsets qmp_usb_offsets_v5 = {
.serdes = 0, .serdes = 0,
.pcs = 0x0200, .pcs = 0x0200,
...@@ -1586,6 +1710,28 @@ static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = { ...@@ -1586,6 +1710,28 @@ static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = {
.regs = qmp_v3_usb3phy_regs_layout, .regs = qmp_v3_usb3phy_regs_layout,
}; };
static const struct qmp_phy_cfg ipq9574_usb3phy_cfg = {
.lanes = 1,
.offsets = &qmp_usb_offsets_ipq9574,
.serdes_tbl = ipq9574_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(ipq9574_usb3_serdes_tbl),
.tx_tbl = ipq9574_usb3_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(ipq9574_usb3_tx_tbl),
.rx_tbl = ipq9574_usb3_rx_tbl,
.rx_tbl_num = ARRAY_SIZE(ipq9574_usb3_rx_tbl),
.pcs_tbl = ipq9574_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(ipq9574_usb3_pcs_tbl),
.clk_list = msm8996_phy_clk_l,
.num_clks = ARRAY_SIZE(msm8996_phy_clk_l),
.reset_list = qcm2290_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(qcm2290_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout,
};
static const struct qmp_phy_cfg msm8996_usb3phy_cfg = { static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
.lanes = 1, .lanes = 1,
...@@ -1629,6 +1775,28 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { ...@@ -1629,6 +1775,28 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
.has_phy_dp_com_ctrl = true, .has_phy_dp_com_ctrl = true,
}; };
static const struct qmp_phy_cfg sa8775p_usb3_uniphy_cfg = {
.lanes = 1,
.offsets = &qmp_usb_offsets_v5,
.serdes_tbl = sc8280xp_usb3_uniphy_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_serdes_tbl),
.tx_tbl = sc8280xp_usb3_uniphy_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_tx_tbl),
.rx_tbl = sc8280xp_usb3_uniphy_rx_tbl,
.rx_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_rx_tbl),
.pcs_tbl = sa8775p_usb3_uniphy_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(sa8775p_usb3_uniphy_pcs_tbl),
.clk_list = qmp_v4_phy_clk_l,
.num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l),
.reset_list = qcm2290_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(qcm2290_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = qmp_v5_usb3phy_regs_layout,
};
static const struct qmp_phy_cfg sc7180_usb3phy_cfg = { static const struct qmp_phy_cfg sc7180_usb3phy_cfg = {
.lanes = 2, .lanes = 2,
...@@ -1922,6 +2090,8 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = { ...@@ -1922,6 +2090,8 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = {
static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
.lanes = 2, .lanes = 2,
.offsets = &qmp_usb_offsets_v3,
.serdes_tbl = qcm2290_usb3_serdes_tbl, .serdes_tbl = qcm2290_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
.tx_tbl = qcm2290_usb3_tx_tbl, .tx_tbl = qcm2290_usb3_tx_tbl,
...@@ -2493,10 +2663,16 @@ static int qmp_usb_parse_dt(struct qmp_usb *qmp) ...@@ -2493,10 +2663,16 @@ static int qmp_usb_parse_dt(struct qmp_usb *qmp)
qmp->serdes = base + offs->serdes; qmp->serdes = base + offs->serdes;
qmp->pcs = base + offs->pcs; qmp->pcs = base + offs->pcs;
qmp->pcs_misc = base + offs->pcs_misc;
qmp->pcs_usb = base + offs->pcs_usb; qmp->pcs_usb = base + offs->pcs_usb;
qmp->tx = base + offs->tx; qmp->tx = base + offs->tx;
qmp->rx = base + offs->rx; qmp->rx = base + offs->rx;
if (cfg->lanes >= 2) {
qmp->tx2 = base + offs->tx2;
qmp->rx2 = base + offs->rx2;
}
qmp->pipe_clk = devm_clk_get(dev, "pipe"); qmp->pipe_clk = devm_clk_get(dev, "pipe");
if (IS_ERR(qmp->pipe_clk)) { if (IS_ERR(qmp->pipe_clk)) {
return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk), return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
...@@ -2588,6 +2764,9 @@ static const struct of_device_id qmp_usb_of_match_table[] = { ...@@ -2588,6 +2764,9 @@ static const struct of_device_id qmp_usb_of_match_table[] = {
}, { }, {
.compatible = "qcom,ipq8074-qmp-usb3-phy", .compatible = "qcom,ipq8074-qmp-usb3-phy",
.data = &ipq8074_usb3phy_cfg, .data = &ipq8074_usb3phy_cfg,
}, {
.compatible = "qcom,ipq9574-qmp-usb3-phy",
.data = &ipq9574_usb3phy_cfg,
}, { }, {
.compatible = "qcom,msm8996-qmp-usb3-phy", .compatible = "qcom,msm8996-qmp-usb3-phy",
.data = &msm8996_usb3phy_cfg, .data = &msm8996_usb3phy_cfg,
...@@ -2597,6 +2776,9 @@ static const struct of_device_id qmp_usb_of_match_table[] = { ...@@ -2597,6 +2776,9 @@ static const struct of_device_id qmp_usb_of_match_table[] = {
}, { }, {
.compatible = "qcom,qcm2290-qmp-usb3-phy", .compatible = "qcom,qcm2290-qmp-usb3-phy",
.data = &qcm2290_usb3phy_cfg, .data = &qcm2290_usb3phy_cfg,
}, {
.compatible = "qcom,sa8775p-qmp-usb3-uni-phy",
.data = &sa8775p_usb3_uniphy_cfg,
}, { }, {
.compatible = "qcom,sc7180-qmp-usb3-phy", .compatible = "qcom,sc7180-qmp-usb3-phy",
.data = &sc7180_usb3phy_cfg, .data = &sc7180_usb3phy_cfg,
......
...@@ -911,6 +911,9 @@ static const struct of_device_id qusb2_phy_of_match_table[] = { ...@@ -911,6 +911,9 @@ static const struct of_device_id qusb2_phy_of_match_table[] = {
}, { }, {
.compatible = "qcom,ipq8074-qusb2-phy", .compatible = "qcom,ipq8074-qusb2-phy",
.data = &msm8996_phy_cfg, .data = &msm8996_phy_cfg,
}, {
.compatible = "qcom,ipq9574-qusb2-phy",
.data = &ipq6018_phy_cfg,
}, { }, {
.compatible = "qcom,msm8953-qusb2-phy", .compatible = "qcom,msm8953-qusb2-phy",
.data = &msm8996_phy_cfg, .data = &msm8996_phy_cfg,
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2023, Linaro Limited
*/
#include <linux/clk.h>
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define QSERDES_QMP_PLL 0x0
#define QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0 (QSERDES_QMP_PLL + 0x1ac)
#define QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0 (QSERDES_QMP_PLL + 0x1b0)
#define QSERDES_COM_BIN_VCOCAL_HSCLK_SEL (QSERDES_QMP_PLL + 0x1bc)
#define QSERDES_COM_CORE_CLK_EN (QSERDES_QMP_PLL + 0x174)
#define QSERDES_COM_CORECLK_DIV_MODE0 (QSERDES_QMP_PLL + 0x168)
#define QSERDES_COM_CP_CTRL_MODE0 (QSERDES_QMP_PLL + 0x74)
#define QSERDES_COM_DEC_START_MODE0 (QSERDES_QMP_PLL + 0xbc)
#define QSERDES_COM_DIV_FRAC_START1_MODE0 (QSERDES_QMP_PLL + 0xcc)
#define QSERDES_COM_DIV_FRAC_START2_MODE0 (QSERDES_QMP_PLL + 0xd0)
#define QSERDES_COM_DIV_FRAC_START3_MODE0 (QSERDES_QMP_PLL + 0xd4)
#define QSERDES_COM_HSCLK_HS_SWITCH_SEL (QSERDES_QMP_PLL + 0x15c)
#define QSERDES_COM_HSCLK_SEL (QSERDES_QMP_PLL + 0x158)
#define QSERDES_COM_LOCK_CMP1_MODE0 (QSERDES_QMP_PLL + 0xac)
#define QSERDES_COM_LOCK_CMP2_MODE0 (QSERDES_QMP_PLL + 0xb0)
#define QSERDES_COM_PLL_CCTRL_MODE0 (QSERDES_QMP_PLL + 0x84)
#define QSERDES_COM_PLL_IVCO (QSERDES_QMP_PLL + 0x58)
#define QSERDES_COM_PLL_RCTRL_MODE0 (QSERDES_QMP_PLL + 0x7c)
#define QSERDES_COM_SYSCLK_EN_SEL (QSERDES_QMP_PLL + 0x94)
#define QSERDES_COM_VCO_TUNE1_MODE0 (QSERDES_QMP_PLL + 0x110)
#define QSERDES_COM_VCO_TUNE2_MODE0 (QSERDES_QMP_PLL + 0x114)
#define QSERDES_COM_VCO_TUNE_INITVAL2 (QSERDES_QMP_PLL + 0x124)
#define QSERDES_COM_C_READY_STATUS (QSERDES_QMP_PLL + 0x178)
#define QSERDES_COM_CMN_STATUS (QSERDES_QMP_PLL + 0x140)
#define QSERDES_RX 0x600
#define QSERDES_RX_UCDR_FO_GAIN (QSERDES_RX + 0x8)
#define QSERDES_RX_UCDR_SO_GAIN (QSERDES_RX + 0x14)
#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN (QSERDES_RX + 0x30)
#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE (QSERDES_RX + 0x34)
#define QSERDES_RX_UCDR_FASTLOCK_COUNT_LOW (QSERDES_RX + 0x3c)
#define QSERDES_RX_UCDR_FASTLOCK_COUNT_HIGH (QSERDES_RX + 0x40)
#define QSERDES_RX_UCDR_PI_CONTROLS (QSERDES_RX + 0x44)
#define QSERDES_RX_UCDR_PI_CTRL2 (QSERDES_RX + 0x48)
#define QSERDES_RX_RX_TERM_BW (QSERDES_RX + 0x80)
#define QSERDES_RX_VGA_CAL_CNTRL2 (QSERDES_RX + 0xd8)
#define QSERDES_RX_GM_CAL (QSERDES_RX + 0xdc)
#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1 (QSERDES_RX + 0xe8)
#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 (QSERDES_RX + 0xec)
#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 (QSERDES_RX + 0xf0)
#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 (QSERDES_RX + 0xf4)
#define QSERDES_RX_RX_IDAC_TSETTLE_LOW (QSERDES_RX + 0xf8)
#define QSERDES_RX_RX_IDAC_TSETTLE_HIGH (QSERDES_RX + 0xfc)
#define QSERDES_RX_RX_IDAC_MEASURE_TIME (QSERDES_RX + 0x100)
#define QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 (QSERDES_RX + 0x110)
#define QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2 (QSERDES_RX + 0x114)
#define QSERDES_RX_SIGDET_CNTRL (QSERDES_RX + 0x11c)
#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL (QSERDES_RX + 0x124)
#define QSERDES_RX_RX_BAND (QSERDES_RX + 0x128)
#define QSERDES_RX_RX_MODE_00_LOW (QSERDES_RX + 0x15c)
#define QSERDES_RX_RX_MODE_00_HIGH (QSERDES_RX + 0x160)
#define QSERDES_RX_RX_MODE_00_HIGH2 (QSERDES_RX + 0x164)
#define QSERDES_RX_RX_MODE_00_HIGH3 (QSERDES_RX + 0x168)
#define QSERDES_RX_RX_MODE_00_HIGH4 (QSERDES_RX + 0x16c)
#define QSERDES_RX_RX_MODE_01_LOW (QSERDES_RX + 0x170)
#define QSERDES_RX_RX_MODE_01_HIGH (QSERDES_RX + 0x174)
#define QSERDES_RX_RX_MODE_01_HIGH2 (QSERDES_RX + 0x178)
#define QSERDES_RX_RX_MODE_01_HIGH3 (QSERDES_RX + 0x17c)
#define QSERDES_RX_RX_MODE_01_HIGH4 (QSERDES_RX + 0x180)
#define QSERDES_RX_RX_MODE_10_LOW (QSERDES_RX + 0x184)
#define QSERDES_RX_RX_MODE_10_HIGH (QSERDES_RX + 0x188)
#define QSERDES_RX_RX_MODE_10_HIGH2 (QSERDES_RX + 0x18c)
#define QSERDES_RX_RX_MODE_10_HIGH3 (QSERDES_RX + 0x190)
#define QSERDES_RX_RX_MODE_10_HIGH4 (QSERDES_RX + 0x194)
#define QSERDES_RX_DCC_CTRL1 (QSERDES_RX + 0x1a8)
#define QSERDES_TX 0x400
#define QSERDES_TX_TX_BAND (QSERDES_TX + 0x24)
#define QSERDES_TX_SLEW_CNTL (QSERDES_TX + 0x28)
#define QSERDES_TX_RES_CODE_LANE_OFFSET_TX (QSERDES_TX + 0x3c)
#define QSERDES_TX_RES_CODE_LANE_OFFSET_RX (QSERDES_TX + 0x40)
#define QSERDES_TX_LANE_MODE_1 (QSERDES_TX + 0x84)
#define QSERDES_TX_LANE_MODE_3 (QSERDES_TX + 0x8c)
#define QSERDES_TX_RCV_DETECT_LVL_2 (QSERDES_TX + 0xa4)
#define QSERDES_TX_TRAN_DRVR_EMP_EN (QSERDES_TX + 0xc0)
#define QSERDES_PCS 0xC00
#define QSERDES_PCS_PHY_START (QSERDES_PCS + 0x0)
#define QSERDES_PCS_POWER_DOWN_CONTROL (QSERDES_PCS + 0x4)
#define QSERDES_PCS_SW_RESET (QSERDES_PCS + 0x8)
#define QSERDES_PCS_LINE_RESET_TIME (QSERDES_PCS + 0xc)
#define QSERDES_PCS_TX_LARGE_AMP_DRV_LVL (QSERDES_PCS + 0x20)
#define QSERDES_PCS_TX_SMALL_AMP_DRV_LVL (QSERDES_PCS + 0x28)
#define QSERDES_PCS_TX_MID_TERM_CTRL1 (QSERDES_PCS + 0xd8)
#define QSERDES_PCS_TX_MID_TERM_CTRL2 (QSERDES_PCS + 0xdc)
#define QSERDES_PCS_SGMII_MISC_CTRL8 (QSERDES_PCS + 0x118)
#define QSERDES_PCS_PCS_READY_STATUS (QSERDES_PCS + 0x94)
#define QSERDES_COM_C_READY BIT(0)
#define QSERDES_PCS_READY BIT(0)
#define QSERDES_PCS_SGMIIPHY_READY BIT(7)
#define QSERDES_COM_C_PLL_LOCKED BIT(1)
struct qcom_dwmac_sgmii_phy_data {
struct regmap *regmap;
struct clk *refclk;
int speed;
};
static void qcom_dwmac_sgmii_phy_init_1g(struct regmap *regmap)
{
regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x01);
regmap_write(regmap, QSERDES_PCS_POWER_DOWN_CONTROL, 0x01);
regmap_write(regmap, QSERDES_COM_PLL_IVCO, 0x0F);
regmap_write(regmap, QSERDES_COM_CP_CTRL_MODE0, 0x06);
regmap_write(regmap, QSERDES_COM_PLL_RCTRL_MODE0, 0x16);
regmap_write(regmap, QSERDES_COM_PLL_CCTRL_MODE0, 0x36);
regmap_write(regmap, QSERDES_COM_SYSCLK_EN_SEL, 0x1A);
regmap_write(regmap, QSERDES_COM_LOCK_CMP1_MODE0, 0x0A);
regmap_write(regmap, QSERDES_COM_LOCK_CMP2_MODE0, 0x1A);
regmap_write(regmap, QSERDES_COM_DEC_START_MODE0, 0x82);
regmap_write(regmap, QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55);
regmap_write(regmap, QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55);
regmap_write(regmap, QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03);
regmap_write(regmap, QSERDES_COM_VCO_TUNE1_MODE0, 0x24);
regmap_write(regmap, QSERDES_COM_VCO_TUNE2_MODE0, 0x02);
regmap_write(regmap, QSERDES_COM_VCO_TUNE_INITVAL2, 0x00);
regmap_write(regmap, QSERDES_COM_HSCLK_SEL, 0x04);
regmap_write(regmap, QSERDES_COM_HSCLK_HS_SWITCH_SEL, 0x00);
regmap_write(regmap, QSERDES_COM_CORECLK_DIV_MODE0, 0x0A);
regmap_write(regmap, QSERDES_COM_CORE_CLK_EN, 0x00);
regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xB9);
regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1E);
regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_HSCLK_SEL, 0x11);
regmap_write(regmap, QSERDES_TX_TX_BAND, 0x05);
regmap_write(regmap, QSERDES_TX_SLEW_CNTL, 0x0A);
regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_TX, 0x09);
regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_RX, 0x09);
regmap_write(regmap, QSERDES_TX_LANE_MODE_1, 0x05);
regmap_write(regmap, QSERDES_TX_LANE_MODE_3, 0x00);
regmap_write(regmap, QSERDES_TX_RCV_DETECT_LVL_2, 0x12);
regmap_write(regmap, QSERDES_TX_TRAN_DRVR_EMP_EN, 0x0C);
regmap_write(regmap, QSERDES_RX_UCDR_FO_GAIN, 0x0A);
regmap_write(regmap, QSERDES_RX_UCDR_SO_GAIN, 0x06);
regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A);
regmap_write(regmap, QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F);
regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00);
regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01);
regmap_write(regmap, QSERDES_RX_UCDR_PI_CONTROLS, 0x81);
regmap_write(regmap, QSERDES_RX_UCDR_PI_CTRL2, 0x80);
regmap_write(regmap, QSERDES_RX_RX_TERM_BW, 0x04);
regmap_write(regmap, QSERDES_RX_VGA_CAL_CNTRL2, 0x08);
regmap_write(regmap, QSERDES_RX_GM_CAL, 0x0F);
regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04);
regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00);
regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A);
regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A);
regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_LOW, 0x80);
regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_HIGH, 0x01);
regmap_write(regmap, QSERDES_RX_RX_IDAC_MEASURE_TIME, 0x20);
regmap_write(regmap, QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17);
regmap_write(regmap, QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00);
regmap_write(regmap, QSERDES_RX_SIGDET_CNTRL, 0x0F);
regmap_write(regmap, QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E);
regmap_write(regmap, QSERDES_RX_RX_BAND, 0x05);
regmap_write(regmap, QSERDES_RX_RX_MODE_00_LOW, 0xE0);
regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH2, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH3, 0x09);
regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH4, 0xB1);
regmap_write(regmap, QSERDES_RX_RX_MODE_01_LOW, 0xE0);
regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH2, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH3, 0x09);
regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH4, 0xB1);
regmap_write(regmap, QSERDES_RX_RX_MODE_10_LOW, 0xE0);
regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH2, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH3, 0x3B);
regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH4, 0xB7);
regmap_write(regmap, QSERDES_RX_DCC_CTRL1, 0x0C);
regmap_write(regmap, QSERDES_PCS_LINE_RESET_TIME, 0x0C);
regmap_write(regmap, QSERDES_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F);
regmap_write(regmap, QSERDES_PCS_TX_SMALL_AMP_DRV_LVL, 0x03);
regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL1, 0x83);
regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL2, 0x08);
regmap_write(regmap, QSERDES_PCS_SGMII_MISC_CTRL8, 0x0C);
regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x00);
regmap_write(regmap, QSERDES_PCS_PHY_START, 0x01);
}
static void qcom_dwmac_sgmii_phy_init_2p5g(struct regmap *regmap)
{
regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x01);
regmap_write(regmap, QSERDES_PCS_POWER_DOWN_CONTROL, 0x01);
regmap_write(regmap, QSERDES_COM_PLL_IVCO, 0x0F);
regmap_write(regmap, QSERDES_COM_CP_CTRL_MODE0, 0x06);
regmap_write(regmap, QSERDES_COM_PLL_RCTRL_MODE0, 0x16);
regmap_write(regmap, QSERDES_COM_PLL_CCTRL_MODE0, 0x36);
regmap_write(regmap, QSERDES_COM_SYSCLK_EN_SEL, 0x1A);
regmap_write(regmap, QSERDES_COM_LOCK_CMP1_MODE0, 0x1A);
regmap_write(regmap, QSERDES_COM_LOCK_CMP2_MODE0, 0x41);
regmap_write(regmap, QSERDES_COM_DEC_START_MODE0, 0x7A);
regmap_write(regmap, QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00);
regmap_write(regmap, QSERDES_COM_DIV_FRAC_START2_MODE0, 0x20);
regmap_write(regmap, QSERDES_COM_DIV_FRAC_START3_MODE0, 0x01);
regmap_write(regmap, QSERDES_COM_VCO_TUNE1_MODE0, 0xA1);
regmap_write(regmap, QSERDES_COM_VCO_TUNE2_MODE0, 0x02);
regmap_write(regmap, QSERDES_COM_VCO_TUNE_INITVAL2, 0x00);
regmap_write(regmap, QSERDES_COM_HSCLK_SEL, 0x03);
regmap_write(regmap, QSERDES_COM_HSCLK_HS_SWITCH_SEL, 0x00);
regmap_write(regmap, QSERDES_COM_CORECLK_DIV_MODE0, 0x05);
regmap_write(regmap, QSERDES_COM_CORE_CLK_EN, 0x00);
regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xCD);
regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1C);
regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_HSCLK_SEL, 0x11);
regmap_write(regmap, QSERDES_TX_TX_BAND, 0x04);
regmap_write(regmap, QSERDES_TX_SLEW_CNTL, 0x0A);
regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_TX, 0x09);
regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_RX, 0x02);
regmap_write(regmap, QSERDES_TX_LANE_MODE_1, 0x05);
regmap_write(regmap, QSERDES_TX_LANE_MODE_3, 0x00);
regmap_write(regmap, QSERDES_TX_RCV_DETECT_LVL_2, 0x12);
regmap_write(regmap, QSERDES_TX_TRAN_DRVR_EMP_EN, 0x0C);
regmap_write(regmap, QSERDES_RX_UCDR_FO_GAIN, 0x0A);
regmap_write(regmap, QSERDES_RX_UCDR_SO_GAIN, 0x06);
regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A);
regmap_write(regmap, QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F);
regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00);
regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01);
regmap_write(regmap, QSERDES_RX_UCDR_PI_CONTROLS, 0x81);
regmap_write(regmap, QSERDES_RX_UCDR_PI_CTRL2, 0x80);
regmap_write(regmap, QSERDES_RX_RX_TERM_BW, 0x00);
regmap_write(regmap, QSERDES_RX_VGA_CAL_CNTRL2, 0x08);
regmap_write(regmap, QSERDES_RX_GM_CAL, 0x0F);
regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04);
regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00);
regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A);
regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A);
regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_LOW, 0x80);
regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_HIGH, 0x01);
regmap_write(regmap, QSERDES_RX_RX_IDAC_MEASURE_TIME, 0x20);
regmap_write(regmap, QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17);
regmap_write(regmap, QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00);
regmap_write(regmap, QSERDES_RX_SIGDET_CNTRL, 0x0F);
regmap_write(regmap, QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E);
regmap_write(regmap, QSERDES_RX_RX_BAND, 0x18);
regmap_write(regmap, QSERDES_RX_RX_MODE_00_LOW, 0x18);
regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH2, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH3, 0x0C);
regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH4, 0xB8);
regmap_write(regmap, QSERDES_RX_RX_MODE_01_LOW, 0xE0);
regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH2, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH3, 0x09);
regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH4, 0xB1);
regmap_write(regmap, QSERDES_RX_RX_MODE_10_LOW, 0xE0);
regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH2, 0xC8);
regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH3, 0x3B);
regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH4, 0xB7);
regmap_write(regmap, QSERDES_RX_DCC_CTRL1, 0x0C);
regmap_write(regmap, QSERDES_PCS_LINE_RESET_TIME, 0x0C);
regmap_write(regmap, QSERDES_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F);
regmap_write(regmap, QSERDES_PCS_TX_SMALL_AMP_DRV_LVL, 0x03);
regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL1, 0x83);
regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL2, 0x08);
regmap_write(regmap, QSERDES_PCS_SGMII_MISC_CTRL8, 0x8C);
regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x00);
regmap_write(regmap, QSERDES_PCS_PHY_START, 0x01);
}
static inline int
qcom_dwmac_sgmii_phy_poll_status(struct regmap *regmap, unsigned int reg,
unsigned int bit)
{
unsigned int val;
return regmap_read_poll_timeout(regmap, reg, val,
val & bit, 1500, 750000);
}
static int qcom_dwmac_sgmii_phy_calibrate(struct phy *phy)
{
struct qcom_dwmac_sgmii_phy_data *data = phy_get_drvdata(phy);
struct device *dev = phy->dev.parent;
switch (data->speed) {
case SPEED_10:
case SPEED_100:
case SPEED_1000:
qcom_dwmac_sgmii_phy_init_1g(data->regmap);
break;
case SPEED_2500:
qcom_dwmac_sgmii_phy_init_2p5g(data->regmap);
break;
}
if (qcom_dwmac_sgmii_phy_poll_status(data->regmap,
QSERDES_COM_C_READY_STATUS,
QSERDES_COM_C_READY)) {
dev_err(dev, "QSERDES_COM_C_READY_STATUS timed-out");
return -ETIMEDOUT;
}
if (qcom_dwmac_sgmii_phy_poll_status(data->regmap,
QSERDES_PCS_PCS_READY_STATUS,
QSERDES_PCS_READY)) {
dev_err(dev, "PCS_READY timed-out");
return -ETIMEDOUT;
}
if (qcom_dwmac_sgmii_phy_poll_status(data->regmap,
QSERDES_PCS_PCS_READY_STATUS,
QSERDES_PCS_SGMIIPHY_READY)) {
dev_err(dev, "SGMIIPHY_READY timed-out");
return -ETIMEDOUT;
}
if (qcom_dwmac_sgmii_phy_poll_status(data->regmap,
QSERDES_COM_CMN_STATUS,
QSERDES_COM_C_PLL_LOCKED)) {
dev_err(dev, "PLL Lock Status timed-out");
return -ETIMEDOUT;
}
return 0;
}
static int qcom_dwmac_sgmii_phy_power_on(struct phy *phy)
{
struct qcom_dwmac_sgmii_phy_data *data = phy_get_drvdata(phy);
return clk_prepare_enable(data->refclk);
}
static int qcom_dwmac_sgmii_phy_power_off(struct phy *phy)
{
struct qcom_dwmac_sgmii_phy_data *data = phy_get_drvdata(phy);
regmap_write(data->regmap, QSERDES_PCS_TX_MID_TERM_CTRL2, 0x08);
regmap_write(data->regmap, QSERDES_PCS_SW_RESET, 0x01);
udelay(100);
regmap_write(data->regmap, QSERDES_PCS_SW_RESET, 0x00);
regmap_write(data->regmap, QSERDES_PCS_PHY_START, 0x01);
clk_disable_unprepare(data->refclk);
return 0;
}
static int qcom_dwmac_sgmii_phy_set_speed(struct phy *phy, int speed)
{
struct qcom_dwmac_sgmii_phy_data *data = phy_get_drvdata(phy);
if (speed != data->speed)
data->speed = speed;
return qcom_dwmac_sgmii_phy_calibrate(phy);
}
static const struct phy_ops qcom_dwmac_sgmii_phy_ops = {
.power_on = qcom_dwmac_sgmii_phy_power_on,
.power_off = qcom_dwmac_sgmii_phy_power_off,
.set_speed = qcom_dwmac_sgmii_phy_set_speed,
.calibrate = qcom_dwmac_sgmii_phy_calibrate,
.owner = THIS_MODULE,
};
static const struct regmap_config qcom_dwmac_sgmii_phy_regmap_cfg = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.use_relaxed_mmio = true,
.disable_locking = true,
};
static int qcom_dwmac_sgmii_phy_probe(struct platform_device *pdev)
{
struct qcom_dwmac_sgmii_phy_data *data;
struct device *dev = &pdev->dev;
struct phy_provider *provider;
void __iomem *base;
struct phy *phy;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->speed = SPEED_10;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
data->regmap = devm_regmap_init_mmio(dev, base,
&qcom_dwmac_sgmii_phy_regmap_cfg);
if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap);
phy = devm_phy_create(dev, NULL, &qcom_dwmac_sgmii_phy_ops);
if (IS_ERR(phy))
return PTR_ERR(phy);
data->refclk = devm_clk_get(dev, "sgmi_ref");
if (IS_ERR(data->refclk))
return PTR_ERR(data->refclk);
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(provider))
return PTR_ERR(provider);
phy_set_drvdata(phy, data);
return 0;
}
static const struct of_device_id qcom_dwmac_sgmii_phy_of_match[] = {
{ .compatible = "qcom,sa8775p-dwmac-sgmii-phy" },
{ },
};
MODULE_DEVICE_TABLE(of, qcom_dwmac_sgmii_phy_of_match);
static struct platform_driver qcom_dwmac_sgmii_phy_driver = {
.probe = qcom_dwmac_sgmii_phy_probe,
.driver = {
.name = "qcom-dwmac-sgmii-phy",
.of_match_table = qcom_dwmac_sgmii_phy_of_match,
}
};
module_platform_driver(qcom_dwmac_sgmii_phy_driver);
MODULE_DESCRIPTION("Qualcomm DWMAC SGMII PHY driver");
MODULE_LICENSE("GPL");
...@@ -59,7 +59,7 @@ config PHY_EXYNOS4210_USB2 ...@@ -59,7 +59,7 @@ config PHY_EXYNOS4210_USB2
config PHY_EXYNOS4X12_USB2 config PHY_EXYNOS4X12_USB2
bool bool
depends on PHY_SAMSUNG_USB2 depends on PHY_SAMSUNG_USB2
default SOC_EXYNOS3250 || SOC_EXYNOS4412 default SOC_EXYNOS3250 || SOC_EXYNOS4212 || SOC_EXYNOS4412
config PHY_EXYNOS5250_USB2 config PHY_EXYNOS5250_USB2
bool bool
......
...@@ -568,6 +568,7 @@ static void tegra_xusb_port_unregister(struct tegra_xusb_port *port) ...@@ -568,6 +568,7 @@ static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
usb_role_switch_unregister(port->usb_role_sw); usb_role_switch_unregister(port->usb_role_sw);
cancel_work_sync(&port->usb_phy_work); cancel_work_sync(&port->usb_phy_work);
usb_remove_phy(&port->usb_phy); usb_remove_phy(&port->usb_phy);
port->usb_phy.dev->driver = NULL;
} }
if (port->ops->remove) if (port->ops->remove)
...@@ -675,6 +676,9 @@ static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port) ...@@ -675,6 +676,9 @@ static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port)
port->dev.driver = devm_kzalloc(&port->dev, port->dev.driver = devm_kzalloc(&port->dev,
sizeof(struct device_driver), sizeof(struct device_driver),
GFP_KERNEL); GFP_KERNEL);
if (!port->dev.driver)
return -ENOMEM;
port->dev.driver->owner = THIS_MODULE; port->dev.driver->owner = THIS_MODULE;
port->usb_role_sw = usb_role_switch_register(&port->dev, port->usb_role_sw = usb_role_switch_register(&port->dev,
......
...@@ -23,7 +23,9 @@ ...@@ -23,7 +23,9 @@
#define AM33XX_GMII_SEL_MODE_RGMII 2 #define AM33XX_GMII_SEL_MODE_RGMII 2
/* J72xx SoC specific definitions for the CONTROL port */ /* J72xx SoC specific definitions for the CONTROL port */
#define J72XX_GMII_SEL_MODE_SGMII 3
#define J72XX_GMII_SEL_MODE_QSGMII 4 #define J72XX_GMII_SEL_MODE_QSGMII 4
#define J72XX_GMII_SEL_MODE_USXGMII 5
#define J72XX_GMII_SEL_MODE_QSGMII_SUB 6 #define J72XX_GMII_SEL_MODE_QSGMII_SUB 6
#define PHY_GMII_PORT(n) BIT((n) - 1) #define PHY_GMII_PORT(n) BIT((n) - 1)
...@@ -106,6 +108,20 @@ static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode) ...@@ -106,6 +108,20 @@ static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode)
gmii_sel_mode = J72XX_GMII_SEL_MODE_QSGMII_SUB; gmii_sel_mode = J72XX_GMII_SEL_MODE_QSGMII_SUB;
break; break;
case PHY_INTERFACE_MODE_SGMII:
if (!(soc_data->extra_modes & BIT(PHY_INTERFACE_MODE_SGMII)))
goto unsupported;
else
gmii_sel_mode = J72XX_GMII_SEL_MODE_SGMII;
break;
case PHY_INTERFACE_MODE_USXGMII:
if (!(soc_data->extra_modes & BIT(PHY_INTERFACE_MODE_USXGMII)))
goto unsupported;
else
gmii_sel_mode = J72XX_GMII_SEL_MODE_USXGMII;
break;
default: default:
goto unsupported; goto unsupported;
} }
...@@ -213,7 +229,7 @@ static const ...@@ -213,7 +229,7 @@ static const
struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = { struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = {
.use_of_data = true, .use_of_data = true,
.regfields = phy_gmii_sel_fields_am654, .regfields = phy_gmii_sel_fields_am654,
.extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII), .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII),
.num_ports = 4, .num_ports = 4,
.num_qsgmii_main_ports = 1, .num_qsgmii_main_ports = 1,
}; };
...@@ -222,7 +238,17 @@ static const ...@@ -222,7 +238,17 @@ static const
struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j721e = { struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j721e = {
.use_of_data = true, .use_of_data = true,
.regfields = phy_gmii_sel_fields_am654, .regfields = phy_gmii_sel_fields_am654,
.extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII), .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII),
.num_ports = 8,
.num_qsgmii_main_ports = 2,
};
static const
struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j784s4 = {
.use_of_data = true,
.regfields = phy_gmii_sel_fields_am654,
.extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) |
BIT(PHY_INTERFACE_MODE_USXGMII),
.num_ports = 8, .num_ports = 8,
.num_qsgmii_main_ports = 2, .num_qsgmii_main_ports = 2,
}; };
...@@ -256,6 +282,10 @@ static const struct of_device_id phy_gmii_sel_id_table[] = { ...@@ -256,6 +282,10 @@ static const struct of_device_id phy_gmii_sel_id_table[] = {
.compatible = "ti,j721e-cpsw9g-phy-gmii-sel", .compatible = "ti,j721e-cpsw9g-phy-gmii-sel",
.data = &phy_gmii_sel_cpsw9g_soc_j721e, .data = &phy_gmii_sel_cpsw9g_soc_j721e,
}, },
{
.compatible = "ti,j784s4-cpsw9g-phy-gmii-sel",
.data = &phy_gmii_sel_cpsw9g_soc_j784s4,
},
{} {}
}; };
MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table); MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table);
......
...@@ -148,6 +148,7 @@ struct phy_attrs { ...@@ -148,6 +148,7 @@ struct phy_attrs {
* @power_count: used to protect when the PHY is used by multiple consumers * @power_count: used to protect when the PHY is used by multiple consumers
* @attrs: used to specify PHY specific attributes * @attrs: used to specify PHY specific attributes
* @pwr: power regulator associated with the phy * @pwr: power regulator associated with the phy
* @debugfs: debugfs directory
*/ */
struct phy { struct phy {
struct device dev; struct device dev;
...@@ -158,6 +159,7 @@ struct phy { ...@@ -158,6 +159,7 @@ struct phy {
int power_count; int power_count;
struct phy_attrs attrs; struct phy_attrs attrs;
struct regulator *pwr; struct regulator *pwr;
struct dentry *debugfs;
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment