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:
commit
7afb9d76bc
@ -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:
|
||||
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
||||
...
|
@ -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
|
||||
|
@ -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
|
||||
|
128
Documentation/devicetree/bindings/phy/fsl,mxs-usbphy.yaml
Normal file
128
Documentation/devicetree/bindings/phy/fsl,mxs-usbphy.yaml
Normal 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>;
|
||||
};
|
||||
|
||||
...
|
@ -15,7 +15,7 @@ description: |
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "combophy(@.*|-[0-9a-f])*$"
|
||||
pattern: "combophy(@.*|-([0-9]|[1-9][0-9]+))?$"
|
||||
|
||||
compatible:
|
||||
items:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>;
|
||||
};
|
@ -43,6 +43,9 @@ properties:
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
vdda-phy-supply: true
|
||||
vdda-pll-supply: true
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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>;
|
||||
};
|
@ -78,9 +78,9 @@ allOf:
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 3
|
||||
minItems: 3
|
||||
clock-names:
|
||||
maxItems: 3
|
||||
minItems: 3
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
|
@ -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:
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
451
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c
Normal file
451
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c
Normal 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");
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user