2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-11-24 02:24:28 +08:00

phy-for-6.5-v2

- 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
 
 - Updates
   - 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
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmSlyssACgkQfBQHDyUj
 g0d6yg/9Ghx1aHTN3DgdXQ0DNSv79IlQXSMP3KXQJgRxmMbdJyVIv/FdnEYRnXFD
 Rhvfal/fbBiGh7VskrcuYjW8ijQ4cSyvcgu+2FeuPoRq/0x7S3XMlw/2Fex6H1wU
 wCS2V3RVuePEQRYeO3eVHQyVxWEa8Qk+2Ry0KG1s9DBIZgeMuU2f1FRED6p9Ayz8
 Q1dBA/mVpPnEFhhIaO66IpvTLZ2M8x+mk0wFLtDl7f5ImFz0A7lM+Dfr42rJ0rWi
 A1YbTSpEMTKVaoNKhAxrqdIEZzlQ/sPWiqeDwA+Ao9l1N8Dn0UWVJfXIuwBi/XzK
 9552nsWwQE4ikiEU4+mxq7pZqrlT5kt8axxdvIC9MH70yRTdrEH34IbOb2IaD+GM
 oKW++7ZVyeFmSmy5XezrgYbHzEdh2HBESUrbrLUg0qFOR+5lccDOI2KxOKx08Myw
 pLpjROADwwUpa2PJ3hTRhCGURPXRVPQuB2Du7s1ILH6Fckeq9rIbmYEVcKUt8dgu
 ZJXCRMG7nEKmT5G6XND7pHfFmt+oA4zdQxnUpBOgY64RIcllbpkv1smbJYlyqfKG
 1pvOSkzriacldQSVSuzUiQ3CFgVN1+NjBBSLHDd5UWilEKVCjP5+gNpLhg2oAiXu
 VK6j8MeHOmVgVH2V2kSnNU9oUBorddoMiTua7ci14NbwqVwwjUU=
 =ReXo
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2023-07-05 21:38:13 -07:00
commit 7afb9d76bc
46 changed files with 3005 additions and 560 deletions

View File

@ -115,8 +115,8 @@ allOf:
compatible:
contains:
enum:
- const: brcm,bcm4908-usb-phy
- const: brcm,brcmstb-usb-phy
- brcm,bcm4908-usb-phy
- brcm,brcmstb-usb-phy
then:
properties:
reg:

View File

@ -1,15 +0,0 @@
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>;
};

View File

@ -0,0 +1,36 @@
# 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>;
};
...

View File

@ -31,6 +31,12 @@ properties:
"#phy-cells":
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:
- compatible
- reg

View File

@ -35,6 +35,53 @@ properties:
description:
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:
- compatible
- reg

View File

@ -0,0 +1,128 @@
# 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>;
};
...

View File

@ -15,7 +15,7 @@ description: |
properties:
$nodename:
pattern: "combophy(@.*|-[0-9a-f])*$"
pattern: "combophy(@.*|-([0-9]|[1-9][0-9]+))?$"
compatible:
items:

View File

@ -32,15 +32,6 @@ properties:
clock-names:
const: phy_ref
assigned-clocks:
maxItems: 1
assigned-clock-parents:
maxItems: 1
assigned-clock-rates:
maxItems: 1
"#phy-cells":
const: 0

View File

@ -1,33 +0,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>;
};

View File

@ -43,6 +43,9 @@ properties:
"#phy-cells":
const: 0
power-domains:
maxItems: 1
vdda-phy-supply: true
vdda-pll-supply: true

View File

@ -203,6 +203,7 @@ allOf:
compatible:
contains:
enum:
- qcom,sc8180x-qmp-pcie-phy
- qcom,sm8250-qmp-gen3x2-pcie-phy
- qcom,sm8250-qmp-modem-pcie-phy
- qcom,sm8450-qmp-gen4x2-pcie-phy
@ -224,7 +225,6 @@ allOf:
compatible:
contains:
enum:
- qcom,sc8180x-qmp-pcie-phy
- qcom,sdm845-qmp-pcie-phy
- qcom,sdx55-qmp-pcie-phy
- qcom,sm8250-qmp-gen3x1-pcie-phy

View File

@ -160,6 +160,7 @@ allOf:
contains:
enum:
- qcom,msm8998-qmp-ufs-phy
- qcom,sc8180x-qmp-ufs-phy
- qcom,sdm845-qmp-ufs-phy
- qcom,sm6350-qmp-ufs-phy
- qcom,sm8150-qmp-ufs-phy
@ -178,23 +179,6 @@ allOf:
- description: TX lane 2
- description: RX lane 2
- if:
properties:
compatible:
contains:
enum:
- qcom,sc8180x-qmp-ufs-phy
then:
patternProperties:
"^phy@[0-9a-f]+$":
properties:
reg:
items:
- description: TX
- description: RX
- description: PCS
- description: PCS_MISC
- if:
properties:
compatible:

View File

@ -23,14 +23,12 @@ properties:
- qcom,ipq8074-qmp-usb3-phy
- qcom,msm8996-qmp-usb3-phy
- qcom,msm8998-qmp-usb3-phy
- qcom,qcm2290-qmp-usb3-phy
- qcom,sc7180-qmp-usb3-phy
- qcom,sc8180x-qmp-usb3-phy
- qcom,sdm845-qmp-usb3-phy
- qcom,sdm845-qmp-usb3-uni-phy
- qcom,sdx55-qmp-usb3-uni-phy
- qcom,sdx65-qmp-usb3-uni-phy
- qcom,sm6115-qmp-usb3-phy
- qcom,sm8150-qmp-usb3-phy
- qcom,sm8150-qmp-usb3-uni-phy
- qcom,sm8250-qmp-usb3-phy
@ -248,29 +246,6 @@ allOf:
- const: phy
- 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:
properties:
compatible:
@ -318,12 +293,10 @@ allOf:
enum:
- qcom,ipq6018-qmp-usb3-phy
- qcom,ipq8074-qmp-usb3-phy
- qcom,qcm2290-qmp-usb3-phy
- qcom,sc7180-qmp-usb3-phy
- qcom,sc8180x-qmp-usb3-phy
- qcom,sdx55-qmp-usb3-uni-phy
- qcom,sdx65-qmp-usb3-uni-phy
- qcom,sm6115-qmp-usb3-phy
- qcom,sm8150-qmp-usb3-uni-phy
- qcom,sm8250-qmp-usb3-phy
then:

View File

@ -18,13 +18,14 @@ properties:
oneOf:
- items:
- enum:
- qcom,ipq6018-qusb2-phy
- qcom,ipq8074-qusb2-phy
- qcom,ipq9574-qusb2-phy
- qcom,msm8953-qusb2-phy
- qcom,msm8996-qusb2-phy
- qcom,msm8998-qusb2-phy
- qcom,qcm2290-qusb2-phy
- qcom,sdm660-qusb2-phy
- qcom,ipq6018-qusb2-phy
- qcom,sm4250-qusb2-phy
- qcom,sm6115-qusb2-phy
- items:

View File

@ -0,0 +1,55 @@
# 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>;
};

View File

@ -78,9 +78,9 @@ allOf:
then:
properties:
clocks:
maxItems: 3
minItems: 3
clock-names:
maxItems: 3
minItems: 3
else:
properties:
clocks:

View File

@ -16,7 +16,11 @@ description:
properties:
compatible:
enum:
- qcom,ipq9574-qmp-usb3-phy
- qcom,qcm2290-qmp-usb3-phy
- qcom,sa8775p-qmp-usb3-uni-phy
- qcom,sc8280xp-qmp-usb3-uni-phy
- qcom,sm6115-qmp-usb3-phy
reg:
maxItems: 1
@ -25,11 +29,7 @@ properties:
maxItems: 4
clock-names:
items:
- const: aux
- const: ref
- const: com_aux
- const: pipe
maxItems: 4
power-domains:
maxItems: 1
@ -60,7 +60,6 @@ required:
- reg
- clocks
- clock-names
- power-domains
- resets
- reset-names
- vdda-phy-supply
@ -69,6 +68,60 @@ required:
- clock-output-names
- "#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
examples:

View File

@ -60,6 +60,26 @@ properties:
description:
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:
- compatible
- reg
@ -98,6 +118,37 @@ examples:
vdda-phy-supply = <&vreg_l9d>;
vdda-pll-supply = <&vreg_l4d>;
orientation-switch;
#clock-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>;
};
};
};
};

View File

@ -13,7 +13,9 @@ if:
properties:
compatible:
contains:
const: qcom,usb-hs-phy-apq8064
enum:
- qcom,usb-hs-phy-apq8064
- qcom,usb-hs-phy-msm8960
then:
properties:
resets:
@ -40,6 +42,7 @@ properties:
- qcom,usb-hs-phy-apq8064
- qcom,usb-hs-phy-msm8226
- qcom,usb-hs-phy-msm8916
- qcom,usb-hs-phy-msm8960
- qcom,usb-hs-phy-msm8974
- const: qcom,usb-hs-phy

View File

@ -20,6 +20,7 @@ properties:
- qcom,usb-snps-femto-v2-phy
- items:
- enum:
- qcom,sa8775p-usb-hs-phy
- qcom,sc8280xp-usb-hs-phy
- const: qcom,usb-snps-hs-5nm-phy
- items:

View File

@ -24,6 +24,7 @@ properties:
- qcom,msm8998-dwc3
- qcom,qcm2290-dwc3
- qcom,qcs404-dwc3
- qcom,sa8775p-dwc3
- qcom,sc7180-dwc3
- qcom,sc7280-dwc3
- qcom,sc8280xp-dwc3
@ -181,6 +182,7 @@ allOf:
- qcom,msm8953-dwc3
- qcom,msm8996-dwc3
- qcom,msm8998-dwc3
- qcom,sa8775p-dwc3
- qcom,sc7180-dwc3
- qcom,sc7280-dwc3
- qcom,sdm670-dwc3
@ -456,6 +458,25 @@ allOf:
- const: dm_hs_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
examples:

View File

@ -172,10 +172,16 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
int ret;
unsigned int value;
ret = reset_control_reset(priv->reset);
ret = clk_prepare_enable(priv->clk);
if (ret)
return ret;
ret = reset_control_reset(priv->reset);
if (ret) {
clk_disable_unprepare(priv->clk);
return ret;
}
udelay(RESET_COMPLETE_TIME);
/* usb2_otg_aca_en == 0 */
@ -277,8 +283,13 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
static int phy_meson_g12a_usb2_exit(struct phy *phy)
{
struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy);
int ret;
return reset_control_reset(priv->reset);
ret = reset_control_reset(priv->reset);
if (!ret)
clk_disable_unprepare(priv->clk);
return ret;
}
/* set_mode is not needed, mode setting is handled via the UTMI bus */

View File

@ -59,6 +59,8 @@
#define USB_CTLR_TP_DIAG1_wake_MASK BIT(1)
#define USB_CTRL_CTLR_CSHCR 0x50
#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 */
#define USB_PHY_PLL_CTL 0x00
@ -90,6 +92,8 @@
#define BDC_EC_AXIRDA_RTS_MASK GENMASK(31, 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,
uint8_t addr, uint16_t data)
@ -140,13 +144,17 @@ static void xhci_soft_reset(struct brcm_usb_init_params *params,
int on_off)
{
void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
void __iomem *xhci_gbl = params->regs[BRCM_REGS_XHCI_GBL];
/* Assert reset */
if (on_off)
if (on_off) {
USB_CTRL_UNSET(ctrl, USB_PM, XHC_SOFT_RESETB);
/* De-assert reset */
else
} else {
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)
@ -320,6 +328,9 @@ static void usb_init_common_7216(struct brcm_usb_init_params *params)
/* 1 millisecond - for USB clocks to settle down */
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_init_common(params);
}

View File

@ -35,6 +35,11 @@
#define USB_CTRL_SETUP_STRAP_IPP_SEL_MASK BIT(25) /* option */
#define USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK BIT(26) /* option */
#define USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK BIT(27) /* opt */
#define USB_CTRL_SETUP_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_PLL_CTL 0x04
#define USB_CTRL_PLL_CTL_PLL_SUSPEND_EN_MASK BIT(27)
@ -114,6 +119,8 @@ enum {
USB_CTRL_SETUP_SCB2_EN_SELECTOR,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_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_PLL_CTL_PLL_IDDQ_PWRDN_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] = {
USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_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,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_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] = {
USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_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_PLL_CTL_PLL_IDDQ_PWRDN_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] = {
0, /* USB_CTRL_SETUP_SCB2_EN_MASK */
USB_CTRL_SETUP_SS_EHCI64BIT_EN_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,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_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] = {
USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_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_PLL_CTL_PLL_IDDQ_PWRDN_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] = {
USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_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,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_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] = {
USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_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 */
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_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] = {
USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_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,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_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] = {
USB_CTRL_SETUP_SCB2_EN_MASK,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_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_PLL_CTL_PLL_IDDQ_PWRDN_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] = {
0, /* USB_CTRL_SETUP_SCB2_EN_MASK */
USB_CTRL_SETUP_SS_EHCI64BIT_EN_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,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_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] = {
0, /* USB_CTRL_SETUP_SCB2_EN_MASK */
0, /*USB_CTRL_SETUP_SS_EHCI64BIT_EN_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,
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK,
@ -872,6 +899,13 @@ static void usb_init_common(struct brcm_usb_init_params *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)) {
reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
reg &= ~USB_CTRL_MASK_FAMILY(params, USB_DEVICE_CTL1,

View File

@ -34,6 +34,14 @@ enum brcmusb_reg_sel {
brcm_usb_ctrl_unset(USB_CTRL_REG(base, reg), \
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_ops {

View File

@ -6,6 +6,7 @@
* Copyright (c) 2019-2020 NXP
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
@ -15,7 +16,9 @@
#include <linux/of.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 TB_ADDR_CMN_DIAG_HSCLK_SEL 0x01e0
#define TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR 0x0084
@ -87,8 +90,35 @@
#define TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40f2
#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 */
#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 {
u16 val;
@ -106,19 +136,27 @@ struct cdns_salvo_phy {
struct clk *clk;
void __iomem *base;
struct cdns_salvo_data *data;
enum usb2_disconn_threshold usb2_disconn;
};
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 (u16)readl(salvo_phy->base +
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 + offset +
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)
{
writel(val, salvo_phy->base +
writel(val, salvo_phy->base + offset +
reg * (1 << salvo_phy->data->reg_offset_shift));
}
@ -219,15 +257,27 @@ static int cdns_salvo_phy_init(struct phy *phy)
for (i = 0; i < data->init_sequence_length; 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 */
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;
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);
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);
clk_disable_unprepare(salvo_phy->clk);
@ -251,11 +301,29 @@ static int cdns_salvo_phy_power_off(struct phy *phy)
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 = {
.init = cdns_salvo_phy_init,
.power_on = cdns_salvo_phy_power_on,
.power_off = cdns_salvo_phy_power_off,
.owner = THIS_MODULE,
.set_mode = cdns_salvo_set_mode,
};
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 cdns_salvo_phy *salvo_phy;
struct cdns_salvo_data *data;
u32 val;
data = (struct cdns_salvo_data *)of_device_get_match_data(dev);
salvo_phy = devm_kzalloc(dev, sizeof(*salvo_phy), GFP_KERNEL);
@ -275,6 +344,16 @@ static int cdns_salvo_phy_probe(struct platform_device *pdev)
if (IS_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);
if (IS_ERR(salvo_phy->base))
return PTR_ERR(salvo_phy->base);

File diff suppressed because it is too large Load Diff

View File

@ -206,7 +206,6 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct imx8_pcie_phy *imx8_phy;
struct resource *res;
imx8_phy = devm_kzalloc(dev, sizeof(*imx8_phy), GFP_KERNEL);
if (!imx8_phy)
@ -259,8 +258,7 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
"Failed to get PCIE PHY PERST control\n");
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
imx8_phy->base = devm_ioremap_resource(dev, res);
imx8_phy->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(imx8_phy->base))
return PTR_ERR(imx8_phy->base);

View File

@ -27,17 +27,231 @@
#define PHY_CTRL2_TXENABLEN0 BIT(8)
#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_ALT_CLK_EN BIT(1)
#define PHY_CTRL6_ALT_CLK_SEL BIT(0)
#define PHY_TUNE_DEFAULT 0xffffffff
struct imx8mq_usb_phy {
struct phy *phy;
struct clk *clk;
void __iomem *base;
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)
{
struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
@ -99,6 +313,8 @@ static int imx8mp_usb_phy_init(struct phy *phy)
value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
writel(value, imx_phy->base + PHY_CTRL1);
imx8m_phy_tune(imx_phy);
return 0;
}
@ -182,6 +398,8 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
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);
return PTR_ERR_OR_ZERO(phy_provider);

View File

@ -54,7 +54,7 @@ config PHY_HISTB_COMBPHY
config PHY_HISI_INNO_USB2
tristate "HiSilicon INNO USB2 PHY support"
depends on (ARCH_HISI && ARM64) || COMPILE_TEST
depends on ARCH_HISI || COMPILE_TEST
select GENERIC_PHY
select MFD_SYSCON
help

View File

@ -9,7 +9,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/reset.h>
@ -20,12 +20,25 @@
#define PHY_CLK_STABLE_TIME 2 /* unit:ms */
#define UTMI_RST_COMPLETE_TIME 2 /* unit:ms */
#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_ADDR GENMASK(15, 8)
#define PHY_TEST_PORT GENMASK(18, 16)
#define PHY_TEST_WREN BIT(21)
#define PHY_TEST_CLK BIT(22) /* rising edge active */
#define PHY_TEST_RST BIT(23) /* low active */
#define PHY_TEST_ADDR_OFFSET 8
#define PHY0_TEST_ADDR GENMASK(15, 8)
#define PHY0_TEST_PORT_OFFSET 16
#define PHY0_TEST_PORT GENMASK(18, 16)
#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)
struct hisi_inno_phy_port {
@ -37,6 +50,7 @@ struct hisi_inno_phy_priv {
void __iomem *mmio;
struct clk *ref_clk;
struct reset_control *por_rst;
unsigned int type;
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,
{
void __iomem *reg = priv->mmio;
u32 val;
u32 value;
val = (data & PHY_TEST_DATA) |
((addr << 8) & PHY_TEST_ADDR) |
((port << 16) & PHY_TEST_PORT) |
PHY_TEST_WREN | PHY_TEST_RST;
if (priv->type == PHY_TYPE_0)
val = (data & PHY_TEST_DATA) |
((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);
val |= PHY_TEST_CLK;
writel(val, reg);
value = val;
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);
}
@ -135,6 +159,8 @@ static int hisi_inno_phy_probe(struct platform_device *pdev)
if (IS_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) {
struct reset_control *rst;
struct phy *phy;
@ -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[] = {
{ .compatible = "hisilicon,inno-usb2-phy", },
{ .compatible = "hisilicon,hi3798cv200-usb2-phy", },
{ .compatible = "hisilicon,inno-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);

View File

@ -7,6 +7,7 @@
#include <dt-bindings/phy/phy.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
@ -264,6 +265,8 @@
#define TPHY_CLKS_CNT 2
#define USER_BUF_LEN(count) min_t(size_t, 8, (count))
enum mtk_phy_version {
MTK_PHY_V1 = 1,
MTK_PHY_V2,
@ -336,6 +339,358 @@ struct mtk_tphy {
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,
struct mtk_phy_instance *instance)
{
@ -1140,6 +1495,7 @@ static struct phy *mtk_phy_xlate(struct device *dev,
phy_parse_property(tphy, instance);
phy_type_set(instance);
phy_debugfs_init(instance);
return instance->phy;
}

View File

@ -25,12 +25,17 @@
#define SPX5_SERDES_10G_START 13
#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 {
SPX5_SD10G28_CMU_MAIN = 0,
SPX5_SD10G28_CMU_AUX1 = 1,
SPX5_SD10G28_CMU_AUX2 = 3,
SPX5_SD10G28_CMU_NONE = 4,
SPX5_SD10G28_CMU_MAX,
};
enum sparx5_sd25g28_mode_preset_type {
@ -922,6 +927,222 @@ static void sparx5_sd10g28_get_params(struct sparx5_serdes_macro *macro,
*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[],
struct sparx5_sd25g28_params *params,
u32 sd_index)
@ -1422,7 +1643,17 @@ static int sparx5_sd10g28_apply_params(struct sparx5_serdes_macro *macro,
u32 lane_index = macro->sidx;
u32 sd_index = macro->stpidx;
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)
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)
.rxinvert = 1,
.txswing = 240,
.reg_rst = reset,
.skip_cmu_cfg = reset,
};
int err;
@ -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)
{
struct sparx5_serdes_private *priv = macro->priv;
void __iomem *sd_inst;
void __iomem *sd_inst, *sd_lane_inst;
if (macro->serdestype == SPX5_SDT_6G)
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)
sd_inst = sdx5_inst_get(priv, TARGET_SD25G_LANE, macro->stpidx);
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),
SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER,
sd_inst,
SD25G_LANE_LANE_04(0));
} else {
/* 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),
SD10G_LANE_LANE_06_CFG_PD_DRIVER,
sd_inst,
@ -1939,159 +2195,6 @@ static int sparx5_serdes_clock_config(struct sparx5_serdes_macro *macro)
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)
{
switch (portmode) {
@ -2120,10 +2223,6 @@ static int sparx5_serdes_config(struct sparx5_serdes_macro *macro)
int serdesmode;
int err;
err = sparx5_serdes_cmu_enable(macro->priv);
if (err)
return err;
serdesmode = sparx5_serdes_get_serdesmode(macro->portmode, macro->speed);
if (serdesmode < 0) {
dev_err(dev, "SerDes %u, interface not supported: %s\n",
@ -2215,9 +2314,6 @@ static int sparx5_serdes_reset(struct phy *phy)
struct sparx5_serdes_macro *macro = phy_get_drvdata(phy);
int err;
err = sparx5_serdes_cmu_enable(macro->priv);
if (err)
return err;
if (macro->serdestype == SPX5_SDT_25G)
err = sparx5_sd25g28_config(macro, true);
else
@ -2308,6 +2404,9 @@ static int sparx5_phy_create(struct sparx5_serdes_private *priv,
phy_set_drvdata(*phy, macro);
/* Power off serdes by default */
sparx5_serdes_power_off(*phy);
return 0;
}
@ -2491,6 +2590,9 @@ static int sparx5_serdes_probe(struct platform_device *pdev)
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);
return PTR_ERR_OR_ZERO(provider);

View File

@ -30,7 +30,6 @@ struct sparx5_serdes_private {
struct device *dev;
void __iomem *regs[NUM_TARGETS];
struct phy *phys[SPX5_SERDES_MAX];
bool cmu_enabled;
unsigned long coreclock;
};

View File

@ -2149,6 +2149,92 @@ enum sparx5_serdes_target {
#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)
/* 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 */
#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 {
#define SD_LANE_SD_LANE_STAT_DBG_OBS_GET(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 */
#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 {
#define SD_LANE_25G_SD_LANE_STAT_DBG_OBS_GET(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_ */

View File

@ -11,6 +11,7 @@
#include <linux/export.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/of.h>
@ -20,6 +21,7 @@
#include <linux/regulator/consumer.h>
static struct class *phy_class;
static struct dentry *phy_debugfs_root;
static DEFINE_MUTEX(phy_provider_mutex);
static LIST_HEAD(phy_provider_list);
static LIST_HEAD(phys);
@ -996,6 +998,8 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
pm_runtime_no_callbacks(&phy->dev);
}
phy->debugfs = debugfs_create_dir(dev_name(&phy->dev), phy_debugfs_root);
return phy;
put_dev:
@ -1226,6 +1230,7 @@ static void phy_release(struct device *dev)
phy = to_phy(dev);
dev_vdbg(dev, "releasing '%s'\n", dev_name(dev));
debugfs_remove_recursive(phy->debugfs);
regulator_put(phy->pwr);
ida_simple_remove(&phy_ida, phy->id);
kfree(phy);
@ -1242,6 +1247,15 @@ static int __init phy_core_init(void)
phy_class->dev_release = phy_release;
phy_debugfs_root = debugfs_create_dir("phy", NULL);
return 0;
}
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);

View File

@ -59,8 +59,11 @@ if PHY_QCOM_QMP
config PHY_QCOM_QMP_COMBO
tristate "Qualcomm QMP Combo PHY Driver"
default PHY_QCOM_QMP
depends on TYPEC || TYPEC=n
depends on DRM || DRM=n
select GENERIC_PHY
select MFD_SYSCON
select DRM_PANEL_BRIDGE if DRM
help
Enable this to support the QMP Combo PHY transceiver that is used
with USB3 and DisplayPort controllers on Qualcomm chips.
@ -185,3 +188,12 @@ config PHY_QCOM_IPQ806X_USB
This option enables support for the Synopsis PHYs present inside the
Qualcomm USB3.0 DWC3 controller on ipq806x SoC. This driver supports
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.

View File

@ -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_SS) += phy-qcom-usb-ss.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

View File

@ -19,6 +19,10 @@
#include <linux/regulator/consumer.h>
#include <linux/reset.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>
@ -63,6 +67,10 @@
/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
#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
struct qmp_phy_init_tbl {
@ -1315,14 +1323,21 @@ struct qmp_combo {
struct phy *usb_phy;
enum phy_mode mode;
unsigned int usb_init_count;
struct phy *dp_phy;
unsigned int dp_aux_cfg;
struct phy_configure_opts_dp dp_opts;
unsigned int dp_init_count;
struct clk_fixed_rate pipe_clk_fixed;
struct clk_hw dp_link_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);
@ -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)
{
bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
u32 val;
bool reverse = false;
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;
/*
* TODO: Assume orientation is CC1 for now and two lanes, need to
* use type-c connector to understand orientation and lanes.
*
* 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;
if (dp_opts->lanes == 4 || reverse)
val |= DP_PHY_PD_CTL_LANE_0_1_PWRDN;
if (dp_opts->lanes == 4 || !reverse)
val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
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;
}
@ -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,
unsigned int com_resetm_ctrl_reg,
unsigned int com_c_ready_status_reg,
unsigned int com_cmn_status_reg,
unsigned int dp_phy_status_reg)
{
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,
10000))
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 & BIT(0)) > 0),
500,
10000))
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 & BIT(1)) > 0),
500,
@ -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)
{
bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
bool reverse = false;
u32 status;
int ret;
ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V4_COM_RESETSM_CNTRL,
QSERDES_V4_COM_C_READY_STATUS,
QSERDES_V4_COM_CMN_STATUS,
QSERDES_V4_DP_PHY_STATUS);
if (ret < 0)
return ret;
@ -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)
{
bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
bool reverse = false;
u32 status;
int ret;
ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V4_COM_RESETSM_CNTRL,
QSERDES_V4_COM_C_READY_STATUS,
QSERDES_V4_COM_CMN_STATUS,
QSERDES_V4_DP_PHY_STATUS);
if (ret < 0)
return ret;
@ -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)
{
bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
bool reverse = false;
u32 status;
int ret;
ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V6_COM_RESETSM_CNTRL,
QSERDES_V6_COM_C_READY_STATUS,
QSERDES_V6_COM_CMN_STATUS,
QSERDES_V6_DP_PHY_STATUS);
if (ret < 0)
return ret;
@ -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);
const struct qmp_phy_cfg *cfg = qmp->cfg;
mutex_lock(&qmp->phy_mutex);
memcpy(&qmp->dp_opts, dp_opts, sizeof(*dp_opts));
if (qmp->dp_opts.set_voltages) {
cfg->configure_dp_tx(qmp);
qmp->dp_opts.set_voltages = 0;
}
mutex_unlock(&qmp->phy_mutex);
return 0;
}
@ -2450,24 +2467,27 @@ static int qmp_combo_dp_calibrate(struct phy *phy)
{
struct qmp_combo *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg;
int ret = 0;
mutex_lock(&qmp->phy_mutex);
if (cfg->calibrate_dp_phy)
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;
void __iomem *com = qmp->com;
int ret;
u32 val;
mutex_lock(&qmp->phy_mutex);
if (qmp->init_count++) {
mutex_unlock(&qmp->phy_mutex);
if (!force && qmp->init_count++)
return 0;
}
ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
if (ret) {
@ -2498,10 +2518,12 @@ static int qmp_combo_com_init(struct qmp_combo *qmp)
SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
/* Default type-c orientation, i.e CC1 */
qphy_setbits(com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02);
qphy_setbits(com, QPHY_V3_DP_COM_PHY_MODE_CTRL, USB3_MODE | DP_MODE);
/* Use software based port select and switch on typec orientation */
val = SW_PORTSELECT_MUX;
if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
val |= SW_PORTSELECT_VAL;
writel(val, 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 */
qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
@ -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],
SW_PWRDN);
mutex_unlock(&qmp->phy_mutex);
return 0;
err_assert_reset:
@ -2524,20 +2544,16 @@ err_disable_regulators:
regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
err_decrement_count:
qmp->init_count--;
mutex_unlock(&qmp->phy_mutex);
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;
mutex_lock(&qmp->phy_mutex);
if (--qmp->init_count) {
mutex_unlock(&qmp->phy_mutex);
if (!force && --qmp->init_count)
return 0;
}
reset_control_bulk_assert(cfg->num_resets, qmp->resets);
@ -2545,8 +2561,6 @@ static int qmp_combo_com_exit(struct qmp_combo *qmp)
regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
mutex_unlock(&qmp->phy_mutex);
return 0;
}
@ -2556,20 +2570,32 @@ static int qmp_combo_dp_init(struct phy *phy)
const struct qmp_phy_cfg *cfg = qmp->cfg;
int ret;
ret = qmp_combo_com_init(qmp);
mutex_lock(&qmp->phy_mutex);
ret = qmp_combo_com_init(qmp, false);
if (ret)
return ret;
goto out_unlock;
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)
{
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;
}
@ -2581,6 +2607,8 @@ static int qmp_combo_dp_power_on(struct phy *phy)
void __iomem *tx = qmp->dp_tx;
void __iomem *tx2 = qmp->dp_tx2;
mutex_lock(&qmp->phy_mutex);
qmp_combo_dp_serdes_init(qmp);
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)
/* Configure link rate, swing, etc. */
cfg->configure_dp_phy(qmp);
mutex_unlock(&qmp->phy_mutex);
return 0;
}
@ -2599,9 +2629,13 @@ static int qmp_combo_dp_power_off(struct phy *phy)
{
struct qmp_combo *qmp = phy_get_drvdata(phy);
mutex_lock(&qmp->phy_mutex);
/* Assert DP PHY power down */
writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
mutex_unlock(&qmp->phy_mutex);
return 0;
}
@ -2687,14 +2721,21 @@ static int qmp_combo_usb_init(struct phy *phy)
struct qmp_combo *qmp = phy_get_drvdata(phy);
int ret;
ret = qmp_combo_com_init(qmp);
mutex_lock(&qmp->phy_mutex);
ret = qmp_combo_com_init(qmp, false);
if (ret)
return ret;
goto out_unlock;
ret = qmp_combo_usb_power_on(phy);
if (ret)
qmp_combo_com_exit(qmp);
if (ret) {
qmp_combo_com_exit(qmp, false);
goto out_unlock;
}
qmp->usb_init_count++;
out_unlock:
mutex_unlock(&qmp->phy_mutex);
return ret;
}
@ -2703,11 +2744,20 @@ static int qmp_combo_usb_exit(struct phy *phy)
struct qmp_combo *qmp = phy_get_drvdata(phy);
int ret;
mutex_lock(&qmp->phy_mutex);
ret = qmp_combo_usb_power_off(phy);
if (ret)
return ret;
goto out_unlock;
return qmp_combo_com_exit(qmp);
ret = qmp_combo_com_exit(qmp, false);
if (ret)
goto out_unlock;
qmp->usb_init_count--;
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)
@ -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);
}
#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)
{
struct device *dev = qmp->dev;
@ -3353,6 +3500,8 @@ static int qmp_combo_probe(struct platform_device *pdev)
qmp->dev = dev;
qmp->orientation = TYPEC_ORIENTATION_NORMAL;
qmp->cfg = of_device_get_match_data(dev);
if (!qmp->cfg)
return -EINVAL;
@ -3371,6 +3520,14 @@ static int qmp_combo_probe(struct platform_device *pdev)
if (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. */
usb_np = of_get_child_by_name(dev->of_node, "usb3-phy");
if (usb_np) {

View File

@ -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,
};
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[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x1a),
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[] = {
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 {
u16 serdes;
u16 pcs;
u16 pcs_misc;
u16 pcs_usb;
u16 tx;
u16 rx;
/* for PHYs with >= 2 lanes */
u16 tx2;
u16 rx2;
};
/* struct qmp_phy_cfg - per-PHY initialization config */
@ -1558,6 +1664,24 @@ static const char * const qmp_phy_vreg_l[] = {
"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 = {
.serdes = 0,
.pcs = 0x0200,
@ -1586,6 +1710,28 @@ static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = {
.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 = {
.lanes = 1,
@ -1629,6 +1775,28 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
.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 = {
.lanes = 2,
@ -1922,6 +2090,8 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = {
static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
.lanes = 2,
.offsets = &qmp_usb_offsets_v3,
.serdes_tbl = qcm2290_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
.tx_tbl = qcm2290_usb3_tx_tbl,
@ -2493,10 +2663,16 @@ static int qmp_usb_parse_dt(struct qmp_usb *qmp)
qmp->serdes = base + offs->serdes;
qmp->pcs = base + offs->pcs;
qmp->pcs_misc = base + offs->pcs_misc;
qmp->pcs_usb = base + offs->pcs_usb;
qmp->tx = base + offs->tx;
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");
if (IS_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[] = {
}, {
.compatible = "qcom,ipq8074-qmp-usb3-phy",
.data = &ipq8074_usb3phy_cfg,
}, {
.compatible = "qcom,ipq9574-qmp-usb3-phy",
.data = &ipq9574_usb3phy_cfg,
}, {
.compatible = "qcom,msm8996-qmp-usb3-phy",
.data = &msm8996_usb3phy_cfg,
@ -2597,6 +2776,9 @@ static const struct of_device_id qmp_usb_of_match_table[] = {
}, {
.compatible = "qcom,qcm2290-qmp-usb3-phy",
.data = &qcm2290_usb3phy_cfg,
}, {
.compatible = "qcom,sa8775p-qmp-usb3-uni-phy",
.data = &sa8775p_usb3_uniphy_cfg,
}, {
.compatible = "qcom,sc7180-qmp-usb3-phy",
.data = &sc7180_usb3phy_cfg,

View File

@ -911,6 +911,9 @@ static const struct of_device_id qusb2_phy_of_match_table[] = {
}, {
.compatible = "qcom,ipq8074-qusb2-phy",
.data = &msm8996_phy_cfg,
}, {
.compatible = "qcom,ipq9574-qusb2-phy",
.data = &ipq6018_phy_cfg,
}, {
.compatible = "qcom,msm8953-qusb2-phy",
.data = &msm8996_phy_cfg,

View File

@ -0,0 +1,451 @@
// 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");

View File

@ -59,7 +59,7 @@ config PHY_EXYNOS4210_USB2
config PHY_EXYNOS4X12_USB2
bool
depends on PHY_SAMSUNG_USB2
default SOC_EXYNOS3250 || SOC_EXYNOS4412
default SOC_EXYNOS3250 || SOC_EXYNOS4212 || SOC_EXYNOS4412
config PHY_EXYNOS5250_USB2
bool

View File

@ -568,6 +568,7 @@ static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
usb_role_switch_unregister(port->usb_role_sw);
cancel_work_sync(&port->usb_phy_work);
usb_remove_phy(&port->usb_phy);
port->usb_phy.dev->driver = NULL;
}
if (port->ops->remove)
@ -675,6 +676,9 @@ static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port)
port->dev.driver = devm_kzalloc(&port->dev,
sizeof(struct device_driver),
GFP_KERNEL);
if (!port->dev.driver)
return -ENOMEM;
port->dev.driver->owner = THIS_MODULE;
port->usb_role_sw = usb_role_switch_register(&port->dev,

View File

@ -23,7 +23,9 @@
#define AM33XX_GMII_SEL_MODE_RGMII 2
/* 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_USXGMII 5
#define J72XX_GMII_SEL_MODE_QSGMII_SUB 6
#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)
gmii_sel_mode = J72XX_GMII_SEL_MODE_QSGMII_SUB;
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:
goto unsupported;
}
@ -213,7 +229,7 @@ static const
struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = {
.use_of_data = true,
.regfields = phy_gmii_sel_fields_am654,
.extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII),
.extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII),
.num_ports = 4,
.num_qsgmii_main_ports = 1,
};
@ -222,7 +238,17 @@ static const
struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j721e = {
.use_of_data = true,
.regfields = phy_gmii_sel_fields_am654,
.extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII),
.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_qsgmii_main_ports = 2,
};
@ -256,6 +282,10 @@ static const struct of_device_id phy_gmii_sel_id_table[] = {
.compatible = "ti,j721e-cpsw9g-phy-gmii-sel",
.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);

View File

@ -148,6 +148,7 @@ struct phy_attrs {
* @power_count: used to protect when the PHY is used by multiple consumers
* @attrs: used to specify PHY specific attributes
* @pwr: power regulator associated with the phy
* @debugfs: debugfs directory
*/
struct phy {
struct device dev;
@ -158,6 +159,7 @@ struct phy {
int power_count;
struct phy_attrs attrs;
struct regulator *pwr;
struct dentry *debugfs;
};
/**