phy-for-5.13
- Updates: - Yaml conversion for mvebu-utmi binding, bcm-ns-usb2 and bcm-ns-usb3 bindings - Mediatek dsi and hdmi phy updates - TI j721e-wiz updates for AM64 - Cadence-torrent phy updates for SGMII/QSGMII - New support: - usb3-dp phy for Qualcomm SM8250 - UTMI phy for Armada CP110 - USB phy for Qualcomm SC7280 - Binding and driver for Sparx5 ethernet serdes -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmBtqI0ACgkQfBQHDyUj g0f09hAAn1C0rmyPFjycPTWwnbom52AFMvG95jZJvUK8QDxBDOuhnv0qcZa7pdgt ulSMLK2AhEExyqtUFf6TSZDZJXHioriGJh54D3qqBGtFHnc/60eTQfVHbp6H8ulr G/NmyXeB4nUdco8Lw38Fs6RQufSwQTWLLaPHPCEGTFZr3g0gh7RfaHyHF8CpOGNI Dd+IiPs+TMfB3MKaY3im45WP4e1sYQiPkMs8XQpu04Fvz2CELUxk1qK7GDviISIt tkU5G87Syu5oCNaKm1sus817yIbLTIU0pPYq6c/JDpPL3l9vavbsZ3HrOkMD7XOQ tpDcOkepU3srDkv8GIClfdJdzu8lOhmYbE4ktvlBtKLSf6XFC17whamHu9eYcrqH 6x9PFDRm7hloAjxLuiEQInsNndW7mF0BUwCfEW7iOZ+Mzh06HqkHSSLF0gpFoYFj YUC0fKubqP/IHV32G1iQ+61ftjcAx7WOcZn2VJXHxiomjPJrRr5plIlTkOT8pcIW R7nDcxN8f0LRpuXx+pFjqWpTK/lvG0cO3DxNpaeTF7kfy5hYyvOtw6MconDR7qJa f1PQGhO49IYBjSwDdxgu6MtevhOt62NVRXuNs5mjqPEzLVrjvHshAOdo2Xwd8mjz 47wWR9LUAXc1/S+H+gHpn1Chl7p+8HbgE1VdbrJ7limuF6E6fFQ= =T8Jv -----END PGP SIGNATURE----- Merge tag 'phy-for-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy into char-misc-next Vinod writes: phy-for-5.13 - Updates: - Yaml conversion for mvebu-utmi binding, bcm-ns-usb2 and bcm-ns-usb3 bindings - Mediatek dsi and hdmi phy updates - TI j721e-wiz updates for AM64 - Cadence-torrent phy updates for SGMII/QSGMII - New support: - usb3-dp phy for Qualcomm SM8250 - UTMI phy for Armada CP110 - USB phy for Qualcomm SC7280 - Binding and driver for Sparx5 ethernet serdes * tag 'phy-for-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (75 commits) phy: fix resource_size.cocci warnings phy: Sparx5 Eth SerDes: Use direct register operations phy: hisilicon: Use the correct HiSilicon copyright phy: marvell: phy-mvebu-cp11i-utmi needs USB_COMMON phy: qcom-qmp: add support for sm8250-usb3-dp phy phy: qcom-qmp: rename common registers phy: qcom-qmp: move DP functions to callbacks dt-bindings: phy: qcom,qmp-usb3-dp: Add support for SM8250 dt-bindings: phy: qcom,qmp-usb3-dp-phy: move usb3 compatibles back to qcom,qmp-phy.yaml phy: ti: j721e-wiz: Configure 'p_standard_mode' only for DP/QSGMII dt-bindings: phy: fix dt_binding_check warning in mediatek, ufs-phy.yaml phy: zynqmp: Handle the clock enable/disable properly dt-bindings: phy: bcm-ns-usb3-phy: convert to yaml dt-bindings: phy: bcm-ns-usb2-phy: convert to yaml phy: microchip: PHY_SPARX5_SERDES should depend on ARCH_SPARX5 phy: cadence-torrent: Add delay for PIPE clock to be stable phy: cadence-torrent: Explicitly request exclusive reset control phy: cadence-torrent: Do not configure SERDES if it's already configured phy: cadence-torrent: Group reset APIs and clock APIs phy: ti: j721e-wiz: Do not configure wiz if its already configured ...
This commit is contained in:
commit
fbb0ad4229
@ -1,21 +0,0 @@
|
||||
Driver for Broadcom Northstar USB 2.0 PHY
|
||||
|
||||
Required properties:
|
||||
- compatible: brcm,ns-usb2-phy
|
||||
- reg: iomem address range of DMU (Device Management Unit)
|
||||
- reg-names: "dmu", the only needed & supported reg right now
|
||||
- clocks: USB PHY reference clock
|
||||
- clock-names: "phy-ref-clk", the only needed & supported clock right now
|
||||
|
||||
To initialize USB 2.0 PHY driver needs to setup PLL correctly. To do this it
|
||||
requires passing phandle to the USB PHY reference clock.
|
||||
|
||||
Example:
|
||||
usb2-phy {
|
||||
compatible = "brcm,ns-usb2-phy";
|
||||
reg = <0x1800c000 0x1000>;
|
||||
reg-names = "dmu";
|
||||
#phy-cells = <0>;
|
||||
clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>;
|
||||
clock-names = "phy-ref-clk";
|
||||
};
|
59
Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml
Normal file
59
Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml
Normal file
@ -0,0 +1,59 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/bcm-ns-usb2-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom Northstar USB 2.0 PHY
|
||||
|
||||
description: >
|
||||
To initialize USB 2.0 PHY driver needs to setup PLL correctly.
|
||||
To do this it requires passing phandle to the USB PHY reference clock.
|
||||
|
||||
maintainers:
|
||||
- Rafał Miłecki <rafal@milecki.pl>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,ns-usb2-phy
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: iomem address range of DMU (Device Management Unit)
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: dmu
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: USB PHY reference clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: phy-ref-clk
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/bcm-nsp.h>
|
||||
phy@1800c000 {
|
||||
compatible = "brcm,ns-usb2-phy";
|
||||
reg = <0x1800c000 0x1000>;
|
||||
reg-names = "dmu";
|
||||
clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>;
|
||||
clock-names = "phy-ref-clk";
|
||||
#phy-cells = <0>;
|
||||
};
|
@ -1,34 +0,0 @@
|
||||
Driver for Broadcom Northstar USB 3.0 PHY
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: one of: "brcm,ns-ax-usb3-phy", "brcm,ns-bx-usb3-phy".
|
||||
- reg: address of MDIO bus device
|
||||
- usb3-dmp-syscon: phandle to syscon with DMP (Device Management Plugin)
|
||||
registers
|
||||
- #phy-cells: must be 0
|
||||
|
||||
Initialization of USB 3.0 PHY depends on Northstar version. There are currently
|
||||
three known series: Ax, Bx and Cx.
|
||||
Known A0: BCM4707 rev 0
|
||||
Known B0: BCM4707 rev 4, BCM53573 rev 2
|
||||
Known B1: BCM4707 rev 6
|
||||
Known C0: BCM47094 rev 0
|
||||
|
||||
Example:
|
||||
mdio: mdio@0 {
|
||||
reg = <0x0>;
|
||||
#size-cells = <1>;
|
||||
#address-cells = <0>;
|
||||
|
||||
usb3-phy@10 {
|
||||
compatible = "brcm,ns-ax-usb3-phy";
|
||||
reg = <0x10>;
|
||||
usb3-dmp-syscon = <&usb3_dmp>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
usb3_dmp: syscon@18105000 {
|
||||
reg = <0x18105000 0x1000>;
|
||||
};
|
62
Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.yaml
Normal file
62
Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.yaml
Normal file
@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/bcm-ns-usb3-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom Northstar USB 3.0 PHY
|
||||
|
||||
description: |
|
||||
Initialization of USB 3.0 PHY depends on Northstar version. There are currently
|
||||
three known series: Ax, Bx and Cx.
|
||||
Known A0: BCM4707 rev 0
|
||||
Known B0: BCM4707 rev 4, BCM53573 rev 2
|
||||
Known B1: BCM4707 rev 6
|
||||
Known C0: BCM47094 rev 0
|
||||
|
||||
maintainers:
|
||||
- Rafał Miłecki <rafal@milecki.pl>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- brcm,ns-ax-usb3-phy
|
||||
- brcm,ns-bx-usb3-phy
|
||||
|
||||
reg:
|
||||
description: address of MDIO bus device
|
||||
maxItems: 1
|
||||
|
||||
usb3-dmp-syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to the DMP (Device Management Plugin) syscon
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- usb3-dmp-syscon
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
usb3-phy@10 {
|
||||
compatible = "brcm,ns-ax-usb3-phy";
|
||||
reg = <0x10>;
|
||||
usb3-dmp-syscon = <&usb3_dmp>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
usb3_dmp: syscon@18105000 {
|
||||
reg = <0x18105000 0x1000>;
|
||||
};
|
@ -42,6 +42,9 @@ properties:
|
||||
- const: usb_mdio
|
||||
- const: bdc_ec
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
@ -0,0 +1,57 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/phy/marvell,armada-3700-utmi-phy.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Marvell Armada UTMI/UTMI+ PHY
|
||||
|
||||
maintainers:
|
||||
- Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
|
||||
description:
|
||||
On Armada 3700, there are two USB controllers, one is compatible with
|
||||
the USB2 and USB3 specifications and supports OTG. The other one is USB2
|
||||
compliant and only supports host mode. Both of these controllers come with
|
||||
a slightly different UTMI PHY.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- marvell,a3700-utmi-host-phy
|
||||
- marvell,a3700-utmi-otg-phy
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
marvell,usb-misc-reg:
|
||||
description:
|
||||
Phandle on the "USB miscellaneous registers" shared region
|
||||
covering registers related to both the host controller and
|
||||
the PHY.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
- marvell,usb-misc-reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
usb2_utmi_host_phy: phy@5f000 {
|
||||
compatible = "marvell,armada-3700-utmi-host-phy";
|
||||
reg = <0x5f000 0x800>;
|
||||
marvell,usb-misc-reg = <&usb2_syscon>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
usb2_syscon: system-controller@5f800 {
|
||||
compatible = "marvell,armada-3700-usb2-host-misc", "syscon";
|
||||
reg = <0x5f800 0x800>;
|
||||
};
|
@ -0,0 +1,109 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/phy/marvell,armada-cp110-utmi-phy.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Marvell Armada CP110/CP115 UTMI PHY
|
||||
|
||||
maintainers:
|
||||
- Konstantin Porotchkin <kostap@marvell.com>
|
||||
|
||||
description:
|
||||
On Armada 7k/8k and CN913x, there are two host and one device USB controllers.
|
||||
Each of two exiting UTMI PHYs could be connected to either USB host or USB device
|
||||
controller.
|
||||
The USB device controller can only be connected to a single UTMI PHY port
|
||||
0.H----- USB HOST0
|
||||
UTMI PHY0 --------/
|
||||
0.D-----0
|
||||
\------ USB DEVICE
|
||||
1.D-----1
|
||||
UTMI PHY1 --------\
|
||||
1.H----- USB HOST1
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: marvell,cp110-utmi-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
marvell,system-controller:
|
||||
description:
|
||||
Phandle to the system controller node
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
#Required child nodes:
|
||||
|
||||
patternProperties:
|
||||
"^usb-phy@[0|1]$":
|
||||
type: object
|
||||
description:
|
||||
Each UTMI PHY port must be represented as a sub-node.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: phy port index.
|
||||
maxItems: 1
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- marvell,system-controller
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
cp0_utmi: utmi@580000 {
|
||||
compatible = "marvell,cp110-utmi-phy";
|
||||
reg = <0x580000 0x2000>;
|
||||
marvell,system-controller = <&cp0_syscon0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cp0_utmi0: usb-phy@0 {
|
||||
reg = <0>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
cp0_utmi1: usb-phy@1 {
|
||||
reg = <1>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
cp0_usb3_0 {
|
||||
usb-phy = <&cp0_usb3_0_phy0>;
|
||||
phys = <&cp0_utmi0>;
|
||||
phy-names = "utmi";
|
||||
/* UTMI0 is connected to USB host controller (default mode) */
|
||||
dr_mode = "host";
|
||||
};
|
||||
|
||||
cp0_usb3_1 {
|
||||
usb-phy = <&cp0_usb3_0_phy1>;
|
||||
phys = <&cp0_utmi1>;
|
||||
phy-names = "utmi";
|
||||
/* UTMI1 is connected to USB device controller */
|
||||
dr_mode = "peripheral";
|
||||
};
|
@ -19,11 +19,14 @@ properties:
|
||||
pattern: "^dsi-phy@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt2701-mipi-tx
|
||||
- mediatek,mt7623-mipi-tx
|
||||
- mediatek,mt8173-mipi-tx
|
||||
- mediatek,mt8183-mipi-tx
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt7623-mipi-tx
|
||||
- const: mediatek,mt2701-mipi-tx
|
||||
- const: mediatek,mt2701-mipi-tx
|
||||
- const: mediatek,mt8173-mipi-tx
|
||||
- const: mediatek,mt8183-mipi-tx
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -21,10 +21,13 @@ properties:
|
||||
pattern: "^hdmi-phy@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt2701-hdmi-phy
|
||||
- mediatek,mt7623-hdmi-phy
|
||||
- mediatek,mt8173-hdmi-phy
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt7623-hdmi-phy
|
||||
- const: mediatek,mt2701-hdmi-phy
|
||||
- const: mediatek,mt2701-hdmi-phy
|
||||
- const: mediatek,mt8173-hdmi-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -79,6 +79,7 @@ properties:
|
||||
- mediatek,mt2712-tphy
|
||||
- mediatek,mt7629-tphy
|
||||
- mediatek,mt8183-tphy
|
||||
- mediatek,mt8195-tphy
|
||||
- const: mediatek,generic-tphy-v2
|
||||
- const: mediatek,mt2701-u3phy
|
||||
deprecated: true
|
||||
@ -117,7 +118,7 @@ properties:
|
||||
|
||||
# Required child node:
|
||||
patternProperties:
|
||||
"^usb-phy@[0-9a-f]+$":
|
||||
"^(usb|pcie|sata)-phy@[0-9a-f]+$":
|
||||
type: object
|
||||
description:
|
||||
A sub-node is required for each port the controller provides.
|
||||
|
@ -22,7 +22,12 @@ properties:
|
||||
pattern: "^ufs-phy@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
const: mediatek,mt8183-ufsphy
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8195-ufsphy
|
||||
- const: mediatek,mt8183-ufsphy
|
||||
- const: mediatek,mt8183-ufsphy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -0,0 +1,100 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/microchip,sparx5-serdes.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip Sparx5 Serdes controller
|
||||
|
||||
maintainers:
|
||||
- Steen Hegelund <steen.hegelund@microchip.com>
|
||||
|
||||
description: |
|
||||
The Sparx5 SERDES interfaces share the same basic functionality, but
|
||||
support different operating modes and line rates.
|
||||
|
||||
The following list lists the SERDES features:
|
||||
|
||||
* RX Adaptive Decision Feedback Equalizer (DFE)
|
||||
* Programmable continuous time linear equalizer (CTLE)
|
||||
* Rx variable gain control
|
||||
* Rx built-in fault detector (loss-of-lock/loss-of-signal)
|
||||
* Adjustable tx de-emphasis (FFE)
|
||||
* Tx output amplitude control
|
||||
* Supports rx eye monitor
|
||||
* Multiple loopback modes
|
||||
* Prbs generator and checker
|
||||
* Polarity inversion control
|
||||
|
||||
SERDES6G:
|
||||
|
||||
The SERDES6G is a high-speed SERDES interface, which can operate at
|
||||
the following data rates:
|
||||
|
||||
* 100 Mbps (100BASE-FX)
|
||||
* 1.25 Gbps (SGMII/1000BASE-X/1000BASE-KX)
|
||||
* 3.125 Gbps (2.5GBASE-X/2.5GBASE-KX)
|
||||
* 5.15625 Gbps (5GBASE-KR/5G-USXGMII)
|
||||
|
||||
SERDES10G
|
||||
|
||||
The SERDES10G is a high-speed SERDES interface, which can operate at
|
||||
the following data rates:
|
||||
|
||||
* 100 Mbps (100BASE-FX)
|
||||
* 1.25 Gbps (SGMII/1000BASE-X/1000BASE-KX)
|
||||
* 3.125 Gbps (2.5GBASE-X/2.5GBASE-KX)
|
||||
* 5 Gbps (QSGMII/USGMII)
|
||||
* 5.15625 Gbps (5GBASE-KR/5G-USXGMII)
|
||||
* 10 Gbps (10G-USGMII)
|
||||
* 10.3125 Gbps (10GBASE-R/10GBASE-KR/USXGMII)
|
||||
|
||||
SERDES25G
|
||||
|
||||
The SERDES25G is a high-speed SERDES interface, which can operate at
|
||||
the following data rates:
|
||||
|
||||
* 1.25 Gbps (SGMII/1000BASE-X/1000BASE-KX)
|
||||
* 3.125 Gbps (2.5GBASE-X/2.5GBASE-KX)
|
||||
* 5 Gbps (QSGMII/USGMII)
|
||||
* 5.15625 Gbps (5GBASE-KR/5G-USXGMII)
|
||||
* 10 Gbps (10G-USGMII)
|
||||
* 10.3125 Gbps (10GBASE-R/10GBASE-KR/USXGMII)
|
||||
* 25.78125 Gbps (25GBASE-KR/25GBASE-CR/25GBASE-SR/25GBASE-LR/25GBASE-ER)
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^serdes@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
const: microchip,sparx5-serdes
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
|
||||
'#phy-cells':
|
||||
const: 1
|
||||
description: |
|
||||
- The main serdes input port
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#phy-cells'
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
serdes: serdes@10808000 {
|
||||
compatible = "microchip,sparx5-serdes";
|
||||
#phy-cells = <1>;
|
||||
clocks = <&sys_clk>;
|
||||
reg = <0x10808000 0x5d0000>;
|
||||
};
|
||||
|
||||
...
|
@ -26,6 +26,9 @@ properties:
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
resets:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
@ -49,12 +52,24 @@ properties:
|
||||
const: serdes
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: cmn_refclk_dig_div
|
||||
- const: cmn_refclk1_dig_div
|
||||
- const: pll0_refclk
|
||||
- const: pll1_refclk
|
||||
|
||||
assigned-clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
assigned-clock-parents:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
cdns,autoconf:
|
||||
type: boolean
|
||||
|
@ -28,13 +28,27 @@ properties:
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description:
|
||||
PHY reference clock. Must contain an entry in clock-names.
|
||||
PHY reference clock for 1 item. Must contain an entry in clock-names.
|
||||
Optional Parent to enable output reference clock.
|
||||
|
||||
clock-names:
|
||||
const: refclk
|
||||
minItems: 1
|
||||
items:
|
||||
- const: refclk
|
||||
- const: phy_en_refclk
|
||||
|
||||
assigned-clocks:
|
||||
maxItems: 3
|
||||
|
||||
assigned-clock-parents:
|
||||
maxItems: 3
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
@ -170,7 +184,7 @@ examples:
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
#include <dt-bindings/phy/phy-cadence-torrent.h>
|
||||
#include <dt-bindings/phy/phy-cadence.h>
|
||||
|
||||
bus {
|
||||
#address-cells = <2>;
|
||||
|
@ -1,38 +0,0 @@
|
||||
MVEBU A3700 UTMI PHY
|
||||
--------------------
|
||||
|
||||
USB2 UTMI+ PHY controllers can be found on the following Marvell MVEBU SoCs:
|
||||
* Armada 3700
|
||||
|
||||
On Armada 3700, there are two USB controllers, one is compatible with the USB2
|
||||
and USB3 specifications and supports OTG. The other one is USB2 compliant and
|
||||
only supports host mode. Both of these controllers come with a slightly
|
||||
different UTMI PHY.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be one of:
|
||||
* "marvell,a3700-utmi-host-phy" for the PHY connected to
|
||||
the USB2 host-only controller.
|
||||
* "marvell,a3700-utmi-otg-phy" for the PHY connected to
|
||||
the USB3 and USB2 OTG capable controller.
|
||||
- reg: PHY IP register range.
|
||||
- marvell,usb-misc-reg: handle on the "USB miscellaneous registers" shared
|
||||
region covering registers related to both the host
|
||||
controller and the PHY.
|
||||
- #phy-cells: Standard property (Documentation: phy-bindings.txt) Should be 0.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
usb2_utmi_host_phy: phy@5f000 {
|
||||
compatible = "marvell,armada-3700-utmi-host-phy";
|
||||
reg = <0x5f000 0x800>;
|
||||
marvell,usb-misc-reg = <&usb2_syscon>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
usb2_syscon: system-controller@5f800 {
|
||||
compatible = "marvell,armada-3700-usb2-host-misc", "syscon";
|
||||
reg = <0x5f800 0x800>;
|
||||
};
|
@ -51,6 +51,10 @@ properties:
|
||||
vdda1v8-supply:
|
||||
description: regulator providing 1V8 power supply to the PLL block
|
||||
|
||||
'#clock-cells':
|
||||
description: number of clock cells for ck_usbo_48m consumer
|
||||
const: 0
|
||||
|
||||
#Required child nodes:
|
||||
|
||||
patternProperties:
|
||||
@ -120,6 +124,7 @@ examples:
|
||||
vdda1v8-supply = <®18>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#clock-cells = <0>;
|
||||
|
||||
usbphyc_port0: usb-phy@0 {
|
||||
reg = <0>;
|
||||
|
@ -25,11 +25,13 @@ properties:
|
||||
- qcom,msm8998-qmp-pcie-phy
|
||||
- qcom,msm8998-qmp-ufs-phy
|
||||
- qcom,msm8998-qmp-usb3-phy
|
||||
- qcom,sc7180-qmp-usb3-phy
|
||||
- qcom,sc8180x-qmp-ufs-phy
|
||||
- qcom,sc8180x-qmp-usb3-phy
|
||||
- qcom,sdm845-qhp-pcie-phy
|
||||
- qcom,sdm845-qmp-pcie-phy
|
||||
- qcom,sdm845-qmp-ufs-phy
|
||||
- qcom,sdm845-qmp-usb3-phy
|
||||
- qcom,sdm845-qmp-usb3-uni-phy
|
||||
- qcom,sm8150-qmp-ufs-phy
|
||||
- qcom,sm8150-qmp-usb3-phy
|
||||
|
@ -14,9 +14,8 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sc7180-qmp-usb3-dp-phy
|
||||
- qcom,sc7180-qmp-usb3-phy
|
||||
- qcom,sdm845-qmp-usb3-dp-phy
|
||||
- qcom,sdm845-qmp-usb3-phy
|
||||
- qcom,sm8250-qmp-usb3-dp-phy
|
||||
reg:
|
||||
items:
|
||||
- description: Address and length of PHY's USB serdes block.
|
||||
|
@ -16,6 +16,7 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,usb-snps-hs-7nm-phy
|
||||
- qcom,sc7280-usb-hs-phy
|
||||
- qcom,sm8150-usb-hs-phy
|
||||
- qcom,sm8250-usb-hs-phy
|
||||
- qcom,sm8350-usb-hs-phy
|
||||
|
@ -15,6 +15,7 @@ properties:
|
||||
enum:
|
||||
- ti,j721e-wiz-16g
|
||||
- ti,j721e-wiz-10g
|
||||
- ti,am64-wiz-10g
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
@ -42,6 +43,9 @@ properties:
|
||||
"#reset-cells":
|
||||
const: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
ranges: true
|
||||
|
||||
assigned-clocks:
|
||||
|
@ -71,6 +71,7 @@ source "drivers/phy/ingenic/Kconfig"
|
||||
source "drivers/phy/lantiq/Kconfig"
|
||||
source "drivers/phy/marvell/Kconfig"
|
||||
source "drivers/phy/mediatek/Kconfig"
|
||||
source "drivers/phy/microchip/Kconfig"
|
||||
source "drivers/phy/motorola/Kconfig"
|
||||
source "drivers/phy/mscc/Kconfig"
|
||||
source "drivers/phy/qualcomm/Kconfig"
|
||||
|
@ -20,6 +20,7 @@ obj-y += allwinner/ \
|
||||
lantiq/ \
|
||||
marvell/ \
|
||||
mediatek/ \
|
||||
microchip/ \
|
||||
motorola/ \
|
||||
mscc/ \
|
||||
qualcomm/ \
|
||||
|
@ -94,7 +94,7 @@ config PHY_BRCM_USB
|
||||
depends on ARCH_BCM4908 || ARCH_BRCMSTB || COMPILE_TEST
|
||||
depends on OF
|
||||
select GENERIC_PHY
|
||||
select SOC_BRCMSTB
|
||||
select SOC_BRCMSTB if ARCH_BRCMSTB
|
||||
default ARCH_BCM4908
|
||||
default ARCH_BRCMSTB
|
||||
help
|
||||
|
@ -7,6 +7,7 @@ config PHY_CADENCE_TORRENT
|
||||
tristate "Cadence Torrent PHY driver"
|
||||
depends on OF
|
||||
depends on HAS_IOMEM
|
||||
depends on COMMON_CLK
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Support for Cadence Torrent PHY.
|
||||
@ -24,6 +25,7 @@ config PHY_CADENCE_DPHY
|
||||
config PHY_CADENCE_SIERRA
|
||||
tristate "Cadence Sierra PHY Driver"
|
||||
depends on OF && HAS_IOMEM && RESET_CONTROLLER
|
||||
depends on COMMON_CLK
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the Cadence Sierra PHY driver
|
||||
|
@ -7,6 +7,7 @@
|
||||
*
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
@ -20,10 +21,12 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
#include <dt-bindings/phy/phy-cadence.h>
|
||||
|
||||
/* PHY register offsets */
|
||||
#define SIERRA_COMMON_CDB_OFFSET 0x0
|
||||
#define SIERRA_MACRO_ID_REG 0x0
|
||||
#define SIERRA_CMN_PLLLC_GEN_PREG 0x42
|
||||
#define SIERRA_CMN_PLLLC_MODE_PREG 0x48
|
||||
#define SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG 0x49
|
||||
#define SIERRA_CMN_PLLLC_LF_COEFF_MODE0_PREG 0x4A
|
||||
@ -31,6 +34,9 @@
|
||||
#define SIERRA_CMN_PLLLC_BWCAL_MODE1_PREG 0x4F
|
||||
#define SIERRA_CMN_PLLLC_BWCAL_MODE0_PREG 0x50
|
||||
#define SIERRA_CMN_PLLLC_SS_TIME_STEPSIZE_MODE_PREG 0x62
|
||||
#define SIERRA_CMN_REFRCV_PREG 0x98
|
||||
#define SIERRA_CMN_REFRCV1_PREG 0xB8
|
||||
#define SIERRA_CMN_PLLLC1_GEN_PREG 0xC2
|
||||
|
||||
#define SIERRA_LANE_CDB_OFFSET(ln, block_offset, reg_offset) \
|
||||
((0x4000 << (block_offset)) + \
|
||||
@ -144,6 +150,19 @@
|
||||
#define SIERRA_MAX_LANES 16
|
||||
#define PLL_LOCK_TIME 100000
|
||||
|
||||
#define CDNS_SIERRA_OUTPUT_CLOCKS 2
|
||||
#define CDNS_SIERRA_INPUT_CLOCKS 5
|
||||
enum cdns_sierra_clock_input {
|
||||
PHY_CLK,
|
||||
CMN_REFCLK_DIG_DIV,
|
||||
CMN_REFCLK1_DIG_DIV,
|
||||
PLL0_REFCLK,
|
||||
PLL1_REFCLK,
|
||||
};
|
||||
|
||||
#define SIERRA_NUM_CMN_PLLC 2
|
||||
#define SIERRA_NUM_CMN_PLLC_PARENTS 2
|
||||
|
||||
static const struct reg_field macro_id_type =
|
||||
REG_FIELD(SIERRA_MACRO_ID_REG, 0, 15);
|
||||
static const struct reg_field phy_pll_cfg_1 =
|
||||
@ -151,6 +170,53 @@ static const struct reg_field phy_pll_cfg_1 =
|
||||
static const struct reg_field pllctrl_lock =
|
||||
REG_FIELD(SIERRA_PLLCTRL_STATUS_PREG, 0, 0);
|
||||
|
||||
static const char * const clk_names[] = {
|
||||
[CDNS_SIERRA_PLL_CMNLC] = "pll_cmnlc",
|
||||
[CDNS_SIERRA_PLL_CMNLC1] = "pll_cmnlc1",
|
||||
};
|
||||
|
||||
enum cdns_sierra_cmn_plllc {
|
||||
CMN_PLLLC,
|
||||
CMN_PLLLC1,
|
||||
};
|
||||
|
||||
struct cdns_sierra_pll_mux_reg_fields {
|
||||
struct reg_field pfdclk_sel_preg;
|
||||
struct reg_field plllc1en_field;
|
||||
struct reg_field termen_field;
|
||||
};
|
||||
|
||||
static const struct cdns_sierra_pll_mux_reg_fields cmn_plllc_pfdclk1_sel_preg[] = {
|
||||
[CMN_PLLLC] = {
|
||||
.pfdclk_sel_preg = REG_FIELD(SIERRA_CMN_PLLLC_GEN_PREG, 1, 1),
|
||||
.plllc1en_field = REG_FIELD(SIERRA_CMN_REFRCV1_PREG, 8, 8),
|
||||
.termen_field = REG_FIELD(SIERRA_CMN_REFRCV1_PREG, 0, 0),
|
||||
},
|
||||
[CMN_PLLLC1] = {
|
||||
.pfdclk_sel_preg = REG_FIELD(SIERRA_CMN_PLLLC1_GEN_PREG, 1, 1),
|
||||
.plllc1en_field = REG_FIELD(SIERRA_CMN_REFRCV_PREG, 8, 8),
|
||||
.termen_field = REG_FIELD(SIERRA_CMN_REFRCV_PREG, 0, 0),
|
||||
},
|
||||
};
|
||||
|
||||
struct cdns_sierra_pll_mux {
|
||||
struct clk_hw hw;
|
||||
struct regmap_field *pfdclk_sel_preg;
|
||||
struct regmap_field *plllc1en_field;
|
||||
struct regmap_field *termen_field;
|
||||
struct clk_init_data clk_data;
|
||||
};
|
||||
|
||||
#define to_cdns_sierra_pll_mux(_hw) \
|
||||
container_of(_hw, struct cdns_sierra_pll_mux, hw)
|
||||
|
||||
static const int pll_mux_parent_index[][SIERRA_NUM_CMN_PLLC_PARENTS] = {
|
||||
[CMN_PLLLC] = { PLL0_REFCLK, PLL1_REFCLK },
|
||||
[CMN_PLLLC1] = { PLL1_REFCLK, PLL0_REFCLK },
|
||||
};
|
||||
|
||||
static u32 cdns_sierra_pll_mux_table[] = { 0, 1 };
|
||||
|
||||
struct cdns_sierra_inst {
|
||||
struct phy *phy;
|
||||
u32 phy_type;
|
||||
@ -197,12 +263,15 @@ struct cdns_sierra_phy {
|
||||
struct regmap_field *macro_id_type;
|
||||
struct regmap_field *phy_pll_cfg_1;
|
||||
struct regmap_field *pllctrl_lock[SIERRA_MAX_LANES];
|
||||
struct clk *clk;
|
||||
struct clk *cmn_refclk_dig_div;
|
||||
struct clk *cmn_refclk1_dig_div;
|
||||
struct regmap_field *cmn_refrcv_refclk_plllc1en_preg[SIERRA_NUM_CMN_PLLC];
|
||||
struct regmap_field *cmn_refrcv_refclk_termen_preg[SIERRA_NUM_CMN_PLLC];
|
||||
struct regmap_field *cmn_plllc_pfdclk1_sel_preg[SIERRA_NUM_CMN_PLLC];
|
||||
struct clk *input_clks[CDNS_SIERRA_INPUT_CLOCKS];
|
||||
int nsubnodes;
|
||||
u32 num_lanes;
|
||||
bool autoconf;
|
||||
struct clk_onecell_data clk_data;
|
||||
struct clk *output_clks[CDNS_SIERRA_OUTPUT_CLOCKS];
|
||||
};
|
||||
|
||||
static int cdns_regmap_write(void *context, unsigned int reg, unsigned int val)
|
||||
@ -281,8 +350,8 @@ static int cdns_sierra_phy_init(struct phy *gphy)
|
||||
if (phy->autoconf)
|
||||
return 0;
|
||||
|
||||
clk_set_rate(phy->cmn_refclk_dig_div, 25000000);
|
||||
clk_set_rate(phy->cmn_refclk1_dig_div, 25000000);
|
||||
clk_set_rate(phy->input_clks[CMN_REFCLK_DIG_DIV], 25000000);
|
||||
clk_set_rate(phy->input_clks[CMN_REFCLK1_DIG_DIV], 25000000);
|
||||
if (ins->phy_type == PHY_TYPE_PCIE) {
|
||||
num_cmn_regs = phy->init_data->pcie_cmn_regs;
|
||||
num_ln_regs = phy->init_data->pcie_ln_regs;
|
||||
@ -319,6 +388,12 @@ static int cdns_sierra_phy_on(struct phy *gphy)
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = reset_control_deassert(sp->phy_rst);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to take the PHY out of reset\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Take the PHY lane group out of reset */
|
||||
ret = reset_control_deassert(ins->lnk_rst);
|
||||
if (ret) {
|
||||
@ -358,6 +433,153 @@ static const struct phy_ops ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static u8 cdns_sierra_pll_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct cdns_sierra_pll_mux *mux = to_cdns_sierra_pll_mux(hw);
|
||||
struct regmap_field *field = mux->pfdclk_sel_preg;
|
||||
unsigned int val;
|
||||
|
||||
regmap_field_read(field, &val);
|
||||
return clk_mux_val_to_index(hw, cdns_sierra_pll_mux_table, 0, val);
|
||||
}
|
||||
|
||||
static int cdns_sierra_pll_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct cdns_sierra_pll_mux *mux = to_cdns_sierra_pll_mux(hw);
|
||||
struct regmap_field *plllc1en_field = mux->plllc1en_field;
|
||||
struct regmap_field *termen_field = mux->termen_field;
|
||||
struct regmap_field *field = mux->pfdclk_sel_preg;
|
||||
int val, ret;
|
||||
|
||||
ret = regmap_field_write(plllc1en_field, 0);
|
||||
ret |= regmap_field_write(termen_field, 0);
|
||||
if (index == 1) {
|
||||
ret |= regmap_field_write(plllc1en_field, 1);
|
||||
ret |= regmap_field_write(termen_field, 1);
|
||||
}
|
||||
|
||||
val = cdns_sierra_pll_mux_table[index];
|
||||
ret |= regmap_field_write(field, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct clk_ops cdns_sierra_pll_mux_ops = {
|
||||
.set_parent = cdns_sierra_pll_mux_set_parent,
|
||||
.get_parent = cdns_sierra_pll_mux_get_parent,
|
||||
};
|
||||
|
||||
static int cdns_sierra_pll_mux_register(struct cdns_sierra_phy *sp,
|
||||
struct regmap_field *pfdclk1_sel_field,
|
||||
struct regmap_field *plllc1en_field,
|
||||
struct regmap_field *termen_field,
|
||||
int clk_index)
|
||||
{
|
||||
struct cdns_sierra_pll_mux *mux;
|
||||
struct device *dev = sp->dev;
|
||||
struct clk_init_data *init;
|
||||
const char **parent_names;
|
||||
unsigned int num_parents;
|
||||
char clk_name[100];
|
||||
struct clk *clk;
|
||||
int i;
|
||||
|
||||
mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux)
|
||||
return -ENOMEM;
|
||||
|
||||
num_parents = SIERRA_NUM_CMN_PLLC_PARENTS;
|
||||
parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents), GFP_KERNEL);
|
||||
if (!parent_names)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_parents; i++) {
|
||||
clk = sp->input_clks[pll_mux_parent_index[clk_index][i]];
|
||||
if (IS_ERR_OR_NULL(clk)) {
|
||||
dev_err(dev, "No parent clock for derived_refclk\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
parent_names[i] = __clk_get_name(clk);
|
||||
}
|
||||
|
||||
snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), clk_names[clk_index]);
|
||||
|
||||
init = &mux->clk_data;
|
||||
|
||||
init->ops = &cdns_sierra_pll_mux_ops;
|
||||
init->flags = CLK_SET_RATE_NO_REPARENT;
|
||||
init->parent_names = parent_names;
|
||||
init->num_parents = num_parents;
|
||||
init->name = clk_name;
|
||||
|
||||
mux->pfdclk_sel_preg = pfdclk1_sel_field;
|
||||
mux->plllc1en_field = plllc1en_field;
|
||||
mux->termen_field = termen_field;
|
||||
mux->hw.init = init;
|
||||
|
||||
clk = devm_clk_register(dev, &mux->hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
sp->output_clks[clk_index] = clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_sierra_phy_register_pll_mux(struct cdns_sierra_phy *sp)
|
||||
{
|
||||
struct regmap_field *pfdclk1_sel_field;
|
||||
struct regmap_field *plllc1en_field;
|
||||
struct regmap_field *termen_field;
|
||||
struct device *dev = sp->dev;
|
||||
int ret = 0, i, clk_index;
|
||||
|
||||
clk_index = CDNS_SIERRA_PLL_CMNLC;
|
||||
for (i = 0; i < SIERRA_NUM_CMN_PLLC; i++, clk_index++) {
|
||||
pfdclk1_sel_field = sp->cmn_plllc_pfdclk1_sel_preg[i];
|
||||
plllc1en_field = sp->cmn_refrcv_refclk_plllc1en_preg[i];
|
||||
termen_field = sp->cmn_refrcv_refclk_termen_preg[i];
|
||||
|
||||
ret = cdns_sierra_pll_mux_register(sp, pfdclk1_sel_field, plllc1en_field,
|
||||
termen_field, clk_index);
|
||||
if (ret) {
|
||||
dev_err(dev, "Fail to register cmn plllc mux\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cdns_sierra_clk_unregister(struct cdns_sierra_phy *sp)
|
||||
{
|
||||
struct device *dev = sp->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
|
||||
of_clk_del_provider(node);
|
||||
}
|
||||
|
||||
static int cdns_sierra_clk_register(struct cdns_sierra_phy *sp)
|
||||
{
|
||||
struct device *dev = sp->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
int ret;
|
||||
|
||||
ret = cdns_sierra_phy_register_pll_mux(sp);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to pll mux clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
sp->clk_data.clks = sp->output_clks;
|
||||
sp->clk_data.clk_num = CDNS_SIERRA_OUTPUT_CLOCKS;
|
||||
ret = of_clk_add_provider(node, of_clk_src_onecell_get, &sp->clk_data);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to add clock provider: %s\n", node->name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cdns_sierra_get_optional(struct cdns_sierra_inst *inst,
|
||||
struct device_node *child)
|
||||
{
|
||||
@ -396,6 +618,7 @@ static int cdns_regfield_init(struct cdns_sierra_phy *sp)
|
||||
{
|
||||
struct device *dev = sp->dev;
|
||||
struct regmap_field *field;
|
||||
struct reg_field reg_field;
|
||||
struct regmap *regmap;
|
||||
int i;
|
||||
|
||||
@ -407,6 +630,32 @@ static int cdns_regfield_init(struct cdns_sierra_phy *sp)
|
||||
}
|
||||
sp->macro_id_type = field;
|
||||
|
||||
for (i = 0; i < SIERRA_NUM_CMN_PLLC; i++) {
|
||||
reg_field = cmn_plllc_pfdclk1_sel_preg[i].pfdclk_sel_preg;
|
||||
field = devm_regmap_field_alloc(dev, regmap, reg_field);
|
||||
if (IS_ERR(field)) {
|
||||
dev_err(dev, "PLLLC%d_PFDCLK1_SEL failed\n", i);
|
||||
return PTR_ERR(field);
|
||||
}
|
||||
sp->cmn_plllc_pfdclk1_sel_preg[i] = field;
|
||||
|
||||
reg_field = cmn_plllc_pfdclk1_sel_preg[i].plllc1en_field;
|
||||
field = devm_regmap_field_alloc(dev, regmap, reg_field);
|
||||
if (IS_ERR(field)) {
|
||||
dev_err(dev, "REFRCV%d_REFCLK_PLLLC1EN failed\n", i);
|
||||
return PTR_ERR(field);
|
||||
}
|
||||
sp->cmn_refrcv_refclk_plllc1en_preg[i] = field;
|
||||
|
||||
reg_field = cmn_plllc_pfdclk1_sel_preg[i].termen_field;
|
||||
field = devm_regmap_field_alloc(dev, regmap, reg_field);
|
||||
if (IS_ERR(field)) {
|
||||
dev_err(dev, "REFRCV%d_REFCLK_TERMEN failed\n", i);
|
||||
return PTR_ERR(field);
|
||||
}
|
||||
sp->cmn_refrcv_refclk_termen_preg[i] = field;
|
||||
}
|
||||
|
||||
regmap = sp->regmap_phy_config_ctrl;
|
||||
field = devm_regmap_field_alloc(dev, regmap, phy_pll_cfg_1);
|
||||
if (IS_ERR(field)) {
|
||||
@ -471,6 +720,110 @@ static int cdns_regmap_init_blocks(struct cdns_sierra_phy *sp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp,
|
||||
struct device *dev)
|
||||
{
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
clk = devm_clk_get_optional(dev, "phy_clk");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "failed to get clock phy_clk\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
sp->input_clks[PHY_CLK] = clk;
|
||||
|
||||
clk = devm_clk_get_optional(dev, "cmn_refclk_dig_div");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "cmn_refclk_dig_div clock not found\n");
|
||||
ret = PTR_ERR(clk);
|
||||
return ret;
|
||||
}
|
||||
sp->input_clks[CMN_REFCLK_DIG_DIV] = clk;
|
||||
|
||||
clk = devm_clk_get_optional(dev, "cmn_refclk1_dig_div");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "cmn_refclk1_dig_div clock not found\n");
|
||||
ret = PTR_ERR(clk);
|
||||
return ret;
|
||||
}
|
||||
sp->input_clks[CMN_REFCLK1_DIG_DIV] = clk;
|
||||
|
||||
clk = devm_clk_get_optional(dev, "pll0_refclk");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "pll0_refclk clock not found\n");
|
||||
ret = PTR_ERR(clk);
|
||||
return ret;
|
||||
}
|
||||
sp->input_clks[PLL0_REFCLK] = clk;
|
||||
|
||||
clk = devm_clk_get_optional(dev, "pll1_refclk");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "pll1_refclk clock not found\n");
|
||||
ret = PTR_ERR(clk);
|
||||
return ret;
|
||||
}
|
||||
sp->input_clks[PLL1_REFCLK] = clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_sierra_phy_enable_clocks(struct cdns_sierra_phy *sp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(sp->input_clks[PHY_CLK]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]);
|
||||
if (ret)
|
||||
goto err_pll_cmnlc;
|
||||
|
||||
ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]);
|
||||
if (ret)
|
||||
goto err_pll_cmnlc1;
|
||||
|
||||
return 0;
|
||||
|
||||
err_pll_cmnlc1:
|
||||
clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]);
|
||||
|
||||
err_pll_cmnlc:
|
||||
clk_disable_unprepare(sp->input_clks[PHY_CLK]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cdns_sierra_phy_disable_clocks(struct cdns_sierra_phy *sp)
|
||||
{
|
||||
clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]);
|
||||
clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]);
|
||||
clk_disable_unprepare(sp->input_clks[PHY_CLK]);
|
||||
}
|
||||
|
||||
static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp,
|
||||
struct device *dev)
|
||||
{
|
||||
struct reset_control *rst;
|
||||
|
||||
rst = devm_reset_control_get_exclusive(dev, "sierra_reset");
|
||||
if (IS_ERR(rst)) {
|
||||
dev_err(dev, "failed to get reset\n");
|
||||
return PTR_ERR(rst);
|
||||
}
|
||||
sp->phy_rst = rst;
|
||||
|
||||
rst = devm_reset_control_get_optional_exclusive(dev, "sierra_apb");
|
||||
if (IS_ERR(rst)) {
|
||||
dev_err(dev, "failed to get apb reset\n");
|
||||
return PTR_ERR(rst);
|
||||
}
|
||||
sp->apb_rst = rst;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_sierra_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cdns_sierra_phy *sp;
|
||||
@ -481,7 +834,6 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
|
||||
unsigned int id_value;
|
||||
int i, ret, node = 0;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
struct device_node *dn = dev->of_node, *child;
|
||||
|
||||
if (of_get_child_count(dn) == 0)
|
||||
@ -518,44 +870,22 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, sp);
|
||||
|
||||
sp->clk = devm_clk_get_optional(dev, "phy_clk");
|
||||
if (IS_ERR(sp->clk)) {
|
||||
dev_err(dev, "failed to get clock phy_clk\n");
|
||||
return PTR_ERR(sp->clk);
|
||||
}
|
||||
|
||||
sp->phy_rst = devm_reset_control_get(dev, "sierra_reset");
|
||||
if (IS_ERR(sp->phy_rst)) {
|
||||
dev_err(dev, "failed to get reset\n");
|
||||
return PTR_ERR(sp->phy_rst);
|
||||
}
|
||||
|
||||
sp->apb_rst = devm_reset_control_get_optional(dev, "sierra_apb");
|
||||
if (IS_ERR(sp->apb_rst)) {
|
||||
dev_err(dev, "failed to get apb reset\n");
|
||||
return PTR_ERR(sp->apb_rst);
|
||||
}
|
||||
|
||||
clk = devm_clk_get_optional(dev, "cmn_refclk_dig_div");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "cmn_refclk_dig_div clock not found\n");
|
||||
ret = PTR_ERR(clk);
|
||||
return ret;
|
||||
}
|
||||
sp->cmn_refclk_dig_div = clk;
|
||||
|
||||
clk = devm_clk_get_optional(dev, "cmn_refclk1_dig_div");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "cmn_refclk1_dig_div clock not found\n");
|
||||
ret = PTR_ERR(clk);
|
||||
return ret;
|
||||
}
|
||||
sp->cmn_refclk1_dig_div = clk;
|
||||
|
||||
ret = clk_prepare_enable(sp->clk);
|
||||
ret = cdns_sierra_phy_get_clocks(sp, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cdns_sierra_clk_register(sp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cdns_sierra_phy_get_resets(sp, dev);
|
||||
if (ret)
|
||||
goto unregister_clk;
|
||||
|
||||
ret = cdns_sierra_phy_enable_clocks(sp);
|
||||
if (ret)
|
||||
goto unregister_clk;
|
||||
|
||||
/* Enable APB */
|
||||
reset_control_deassert(sp->apb_rst);
|
||||
|
||||
@ -571,6 +901,10 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
|
||||
for_each_available_child_of_node(dn, child) {
|
||||
struct phy *gphy;
|
||||
|
||||
if (!(of_node_name_eq(child, "phy") ||
|
||||
of_node_name_eq(child, "link")))
|
||||
continue;
|
||||
|
||||
sp->phys[node].lnk_rst =
|
||||
of_reset_control_array_get_exclusive(child);
|
||||
|
||||
@ -616,7 +950,6 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
reset_control_deassert(sp->phy_rst);
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
|
||||
put_child:
|
||||
@ -626,8 +959,10 @@ put_child2:
|
||||
reset_control_put(sp->phys[i].lnk_rst);
|
||||
of_node_put(child);
|
||||
clk_disable:
|
||||
clk_disable_unprepare(sp->clk);
|
||||
cdns_sierra_phy_disable_clocks(sp);
|
||||
reset_control_assert(sp->apb_rst);
|
||||
unregister_clk:
|
||||
cdns_sierra_clk_unregister(sp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -640,6 +975,7 @@ static int cdns_sierra_phy_remove(struct platform_device *pdev)
|
||||
reset_control_assert(phy->apb_rst);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
cdns_sierra_phy_disable_clocks(phy);
|
||||
/*
|
||||
* The device level resets will be put automatically.
|
||||
* Need to put the subnode resets here though.
|
||||
@ -648,6 +984,9 @@ static int cdns_sierra_phy_remove(struct platform_device *pdev)
|
||||
reset_control_assert(phy->phys[i].lnk_rst);
|
||||
reset_control_put(phy->phys[i].lnk_rst);
|
||||
}
|
||||
|
||||
cdns_sierra_clk_unregister(phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,9 @@
|
||||
*/
|
||||
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
#include <dt-bindings/phy/phy-cadence.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
@ -84,6 +86,8 @@
|
||||
#define CMN_PLLSM1_PLLLOCK_TMR 0x0034U
|
||||
#define CMN_CDIAG_CDB_PWRI_OVRD 0x0041U
|
||||
#define CMN_CDIAG_XCVRC_PWRI_OVRD 0x0047U
|
||||
#define CMN_CDIAG_REFCLK_OVRD 0x004CU
|
||||
#define CMN_CDIAG_REFCLK_DRV0_CTRL 0x0050U
|
||||
#define CMN_BGCAL_INIT_TMR 0x0064U
|
||||
#define CMN_BGCAL_ITER_TMR 0x0065U
|
||||
#define CMN_IBCAL_INIT_TMR 0x0074U
|
||||
@ -122,6 +126,8 @@
|
||||
#define CMN_PLL1_FRACDIVH_M0 0x00D2U
|
||||
#define CMN_PLL1_HIGH_THR_M0 0x00D3U
|
||||
#define CMN_PLL1_DSM_DIAG_M0 0x00D4U
|
||||
#define CMN_PLL1_DSM_FBH_OVRD_M0 0x00D5U
|
||||
#define CMN_PLL1_DSM_FBL_OVRD_M0 0x00D6U
|
||||
#define CMN_PLL1_SS_CTRL1_M0 0x00D8U
|
||||
#define CMN_PLL1_SS_CTRL2_M0 0x00D9U
|
||||
#define CMN_PLL1_SS_CTRL3_M0 0x00DAU
|
||||
@ -163,10 +169,12 @@
|
||||
#define TX_TXCC_CPOST_MULT_00 0x004CU
|
||||
#define TX_TXCC_CPOST_MULT_01 0x004DU
|
||||
#define TX_TXCC_MGNFS_MULT_000 0x0050U
|
||||
#define TX_TXCC_MGNFS_MULT_100 0x0054U
|
||||
#define DRV_DIAG_TX_DRV 0x00C6U
|
||||
#define XCVR_DIAG_PLLDRC_CTRL 0x00E5U
|
||||
#define XCVR_DIAG_HSCLK_SEL 0x00E6U
|
||||
#define XCVR_DIAG_HSCLK_DIV 0x00E7U
|
||||
#define XCVR_DIAG_RXCLK_CTRL 0x00E9U
|
||||
#define XCVR_DIAG_BIDI_CTRL 0x00EAU
|
||||
#define XCVR_DIAG_PSC_OVRD 0x00EBU
|
||||
#define TX_PSC_A0 0x0100U
|
||||
@ -206,6 +214,7 @@
|
||||
#define RX_DIAG_ACYA 0x01FFU
|
||||
|
||||
/* PHY PCS common registers */
|
||||
#define PHY_PIPE_CMN_CTRL1 0x0000U
|
||||
#define PHY_PLL_CFG 0x000EU
|
||||
#define PHY_PIPE_USB3_GEN2_PRE_CFG0 0x0020U
|
||||
#define PHY_PIPE_USB3_GEN2_POST_CFG0 0x0022U
|
||||
@ -216,6 +225,10 @@
|
||||
#define PHY_PMA_CMN_CTRL2 0x0001U
|
||||
#define PHY_PMA_PLL_RAW_CTRL 0x0003U
|
||||
|
||||
static const char * const clk_names[] = {
|
||||
[CDNS_TORRENT_REFCLK_DRIVER] = "refclk-driver",
|
||||
};
|
||||
|
||||
static const struct reg_field phy_pll_cfg =
|
||||
REG_FIELD(PHY_PLL_CFG, 0, 1);
|
||||
|
||||
@ -231,6 +244,26 @@ static const struct reg_field phy_pma_pll_raw_ctrl =
|
||||
static const struct reg_field phy_reset_ctrl =
|
||||
REG_FIELD(PHY_RESET, 8, 8);
|
||||
|
||||
static const struct reg_field phy_pipe_cmn_ctrl1_0 = REG_FIELD(PHY_PIPE_CMN_CTRL1, 0, 0);
|
||||
|
||||
#define REFCLK_OUT_NUM_CMN_CONFIG 5
|
||||
|
||||
enum cdns_torrent_refclk_out_cmn {
|
||||
CMN_CDIAG_REFCLK_OVRD_4,
|
||||
CMN_CDIAG_REFCLK_DRV0_CTRL_1,
|
||||
CMN_CDIAG_REFCLK_DRV0_CTRL_4,
|
||||
CMN_CDIAG_REFCLK_DRV0_CTRL_5,
|
||||
CMN_CDIAG_REFCLK_DRV0_CTRL_6,
|
||||
};
|
||||
|
||||
static const struct reg_field refclk_out_cmn_cfg[] = {
|
||||
[CMN_CDIAG_REFCLK_OVRD_4] = REG_FIELD(CMN_CDIAG_REFCLK_OVRD, 4, 4),
|
||||
[CMN_CDIAG_REFCLK_DRV0_CTRL_1] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 1, 1),
|
||||
[CMN_CDIAG_REFCLK_DRV0_CTRL_4] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 4, 4),
|
||||
[CMN_CDIAG_REFCLK_DRV0_CTRL_5] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 5, 5),
|
||||
[CMN_CDIAG_REFCLK_DRV0_CTRL_6] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 6, 6),
|
||||
};
|
||||
|
||||
enum cdns_torrent_phy_type {
|
||||
TYPE_NONE,
|
||||
TYPE_DP,
|
||||
@ -279,6 +312,8 @@ struct cdns_torrent_phy {
|
||||
struct regmap_field *phy_pma_cmn_ctrl_2;
|
||||
struct regmap_field *phy_pma_pll_raw_ctrl;
|
||||
struct regmap_field *phy_reset_ctrl;
|
||||
struct clk *clks[CDNS_TORRENT_REFCLK_DRIVER + 1];
|
||||
struct clk_onecell_data clk_data;
|
||||
};
|
||||
|
||||
enum phy_powerstate {
|
||||
@ -288,6 +323,16 @@ enum phy_powerstate {
|
||||
POWERSTATE_A3 = 3,
|
||||
};
|
||||
|
||||
struct cdns_torrent_derived_refclk {
|
||||
struct clk_hw hw;
|
||||
struct regmap_field *phy_pipe_cmn_ctrl1_0;
|
||||
struct regmap_field *cmn_fields[REFCLK_OUT_NUM_CMN_CONFIG];
|
||||
struct clk_init_data clk_data;
|
||||
};
|
||||
|
||||
#define to_cdns_torrent_derived_refclk(_hw) \
|
||||
container_of(_hw, struct cdns_torrent_derived_refclk, hw)
|
||||
|
||||
static int cdns_torrent_phy_init(struct phy *phy);
|
||||
static int cdns_torrent_dp_init(struct phy *phy);
|
||||
static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy,
|
||||
@ -326,6 +371,19 @@ static const struct phy_ops cdns_torrent_phy_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int cdns_torrent_noop_phy_on(struct phy *phy)
|
||||
{
|
||||
/* Give 5ms to 10ms delay for the PIPE clock to be stable */
|
||||
usleep_range(5000, 10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops noop_ops = {
|
||||
.power_on = cdns_torrent_noop_phy_on,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
struct cdns_reg_pairs {
|
||||
u32 val;
|
||||
u32 off;
|
||||
@ -1604,6 +1662,108 @@ static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cdns_torrent_derived_refclk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw);
|
||||
|
||||
regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_6], 0);
|
||||
regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_4], 1);
|
||||
regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_5], 1);
|
||||
regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_1], 0);
|
||||
regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_OVRD_4], 1);
|
||||
regmap_field_write(derived_refclk->phy_pipe_cmn_ctrl1_0, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cdns_torrent_derived_refclk_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw);
|
||||
|
||||
regmap_field_write(derived_refclk->phy_pipe_cmn_ctrl1_0, 0);
|
||||
}
|
||||
|
||||
static int cdns_torrent_derived_refclk_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw);
|
||||
int val;
|
||||
|
||||
regmap_field_read(derived_refclk->phy_pipe_cmn_ctrl1_0, &val);
|
||||
|
||||
return !!val;
|
||||
}
|
||||
|
||||
static const struct clk_ops cdns_torrent_derived_refclk_ops = {
|
||||
.enable = cdns_torrent_derived_refclk_enable,
|
||||
.disable = cdns_torrent_derived_refclk_disable,
|
||||
.is_enabled = cdns_torrent_derived_refclk_is_enabled,
|
||||
};
|
||||
|
||||
static int cdns_torrent_derived_refclk_register(struct cdns_torrent_phy *cdns_phy)
|
||||
{
|
||||
struct cdns_torrent_derived_refclk *derived_refclk;
|
||||
struct device *dev = cdns_phy->dev;
|
||||
struct regmap_field *field;
|
||||
struct clk_init_data *init;
|
||||
const char *parent_name;
|
||||
struct regmap *regmap;
|
||||
char clk_name[100];
|
||||
struct clk *clk;
|
||||
int i;
|
||||
|
||||
derived_refclk = devm_kzalloc(dev, sizeof(*derived_refclk), GFP_KERNEL);
|
||||
if (!derived_refclk)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev),
|
||||
clk_names[CDNS_TORRENT_REFCLK_DRIVER]);
|
||||
|
||||
clk = devm_clk_get_optional(dev, "phy_en_refclk");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "No parent clock for derived_refclk\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
init = &derived_refclk->clk_data;
|
||||
|
||||
if (clk) {
|
||||
parent_name = __clk_get_name(clk);
|
||||
init->parent_names = &parent_name;
|
||||
init->num_parents = 1;
|
||||
}
|
||||
init->ops = &cdns_torrent_derived_refclk_ops;
|
||||
init->flags = 0;
|
||||
init->name = clk_name;
|
||||
|
||||
regmap = cdns_phy->regmap_phy_pcs_common_cdb;
|
||||
field = devm_regmap_field_alloc(dev, regmap, phy_pipe_cmn_ctrl1_0);
|
||||
if (IS_ERR(field)) {
|
||||
dev_err(dev, "phy_pipe_cmn_ctrl1_0 reg field init failed\n");
|
||||
return PTR_ERR(field);
|
||||
}
|
||||
derived_refclk->phy_pipe_cmn_ctrl1_0 = field;
|
||||
|
||||
regmap = cdns_phy->regmap_common_cdb;
|
||||
for (i = 0; i < REFCLK_OUT_NUM_CMN_CONFIG; i++) {
|
||||
field = devm_regmap_field_alloc(dev, regmap, refclk_out_cmn_cfg[i]);
|
||||
if (IS_ERR(field)) {
|
||||
dev_err(dev, "CMN reg field init failed\n");
|
||||
return PTR_ERR(field);
|
||||
}
|
||||
derived_refclk->cmn_fields[i] = field;
|
||||
}
|
||||
|
||||
derived_refclk->hw.init = init;
|
||||
|
||||
clk = devm_clk_register(dev, &derived_refclk->hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
cdns_phy->clks[CDNS_TORRENT_REFCLK_DRIVER] = clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_torrent_phy_on(struct phy *phy)
|
||||
{
|
||||
struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
|
||||
@ -2071,6 +2231,85 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cdns_torrent_clk_cleanup(struct cdns_torrent_phy *cdns_phy)
|
||||
{
|
||||
struct device *dev = cdns_phy->dev;
|
||||
|
||||
of_clk_del_provider(dev->of_node);
|
||||
}
|
||||
|
||||
static int cdns_torrent_clk_register(struct cdns_torrent_phy *cdns_phy)
|
||||
{
|
||||
struct device *dev = cdns_phy->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
int ret;
|
||||
|
||||
ret = cdns_torrent_derived_refclk_register(cdns_phy);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register derived refclk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cdns_phy->clk_data.clks = cdns_phy->clks;
|
||||
cdns_phy->clk_data.clk_num = CDNS_TORRENT_REFCLK_DRIVER + 1;
|
||||
|
||||
ret = of_clk_add_provider(node, of_clk_src_onecell_get, &cdns_phy->clk_data);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to add clock provider: %s\n", node->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy)
|
||||
{
|
||||
struct device *dev = cdns_phy->dev;
|
||||
|
||||
cdns_phy->phy_rst = devm_reset_control_get_exclusive_by_index(dev, 0);
|
||||
if (IS_ERR(cdns_phy->phy_rst)) {
|
||||
dev_err(dev, "%s: failed to get reset\n",
|
||||
dev->of_node->full_name);
|
||||
return PTR_ERR(cdns_phy->phy_rst);
|
||||
}
|
||||
|
||||
cdns_phy->apb_rst = devm_reset_control_get_optional_exclusive(dev, "torrent_apb");
|
||||
if (IS_ERR(cdns_phy->apb_rst)) {
|
||||
dev_err(dev, "%s: failed to get apb reset\n",
|
||||
dev->of_node->full_name);
|
||||
return PTR_ERR(cdns_phy->apb_rst);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy)
|
||||
{
|
||||
struct device *dev = cdns_phy->dev;
|
||||
int ret;
|
||||
|
||||
cdns_phy->clk = devm_clk_get(dev, "refclk");
|
||||
if (IS_ERR(cdns_phy->clk)) {
|
||||
dev_err(dev, "phy ref clock not found\n");
|
||||
return PTR_ERR(cdns_phy->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(cdns_phy->clk);
|
||||
if (ret) {
|
||||
dev_err(cdns_phy->dev, "Failed to prepare ref clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cdns_phy->ref_clk_rate = clk_get_rate(cdns_phy->clk);
|
||||
if (!(cdns_phy->ref_clk_rate)) {
|
||||
dev_err(cdns_phy->dev, "Failed to get ref clock rate\n");
|
||||
clk_disable_unprepare(cdns_phy->clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_torrent_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cdns_torrent_phy *cdns_phy;
|
||||
@ -2080,6 +2319,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
|
||||
struct device_node *child;
|
||||
int ret, subnodes, node = 0, i;
|
||||
u32 total_num_lanes = 0;
|
||||
int already_configured;
|
||||
u8 init_dp_regmap = 0;
|
||||
u32 phy_type;
|
||||
|
||||
@ -2096,26 +2336,6 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
|
||||
cdns_phy->dev = dev;
|
||||
cdns_phy->init_data = data;
|
||||
|
||||
cdns_phy->phy_rst = devm_reset_control_get_exclusive_by_index(dev, 0);
|
||||
if (IS_ERR(cdns_phy->phy_rst)) {
|
||||
dev_err(dev, "%s: failed to get reset\n",
|
||||
dev->of_node->full_name);
|
||||
return PTR_ERR(cdns_phy->phy_rst);
|
||||
}
|
||||
|
||||
cdns_phy->apb_rst = devm_reset_control_get_optional(dev, "torrent_apb");
|
||||
if (IS_ERR(cdns_phy->apb_rst)) {
|
||||
dev_err(dev, "%s: failed to get apb reset\n",
|
||||
dev->of_node->full_name);
|
||||
return PTR_ERR(cdns_phy->apb_rst);
|
||||
}
|
||||
|
||||
cdns_phy->clk = devm_clk_get(dev, "refclk");
|
||||
if (IS_ERR(cdns_phy->clk)) {
|
||||
dev_err(dev, "phy ref clock not found\n");
|
||||
return PTR_ERR(cdns_phy->clk);
|
||||
}
|
||||
|
||||
cdns_phy->sd_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(cdns_phy->sd_base))
|
||||
return PTR_ERR(cdns_phy->sd_base);
|
||||
@ -2134,21 +2354,24 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(cdns_phy->clk);
|
||||
if (ret) {
|
||||
dev_err(cdns_phy->dev, "Failed to prepare ref clock\n");
|
||||
ret = cdns_torrent_clk_register(cdns_phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
cdns_phy->ref_clk_rate = clk_get_rate(cdns_phy->clk);
|
||||
if (!(cdns_phy->ref_clk_rate)) {
|
||||
dev_err(cdns_phy->dev, "Failed to get ref clock rate\n");
|
||||
clk_disable_unprepare(cdns_phy->clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &already_configured);
|
||||
|
||||
/* Enable APB */
|
||||
reset_control_deassert(cdns_phy->apb_rst);
|
||||
if (!already_configured) {
|
||||
ret = cdns_torrent_reset(cdns_phy);
|
||||
if (ret)
|
||||
goto clk_cleanup;
|
||||
|
||||
ret = cdns_torrent_clk(cdns_phy);
|
||||
if (ret)
|
||||
goto clk_cleanup;
|
||||
|
||||
/* Enable APB */
|
||||
reset_control_deassert(cdns_phy->apb_rst);
|
||||
}
|
||||
|
||||
for_each_available_child_of_node(dev->of_node, child) {
|
||||
struct phy *gphy;
|
||||
@ -2218,7 +2441,10 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
|
||||
of_property_read_u32(child, "cdns,ssc-mode",
|
||||
&cdns_phy->phys[node].ssc_mode);
|
||||
|
||||
gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops);
|
||||
if (!already_configured)
|
||||
gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops);
|
||||
else
|
||||
gphy = devm_phy_create(dev, child, &noop_ops);
|
||||
if (IS_ERR(gphy)) {
|
||||
ret = PTR_ERR(gphy);
|
||||
goto put_child;
|
||||
@ -2302,7 +2528,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
|
||||
goto put_lnk_rst;
|
||||
}
|
||||
|
||||
if (cdns_phy->nsubnodes > 1) {
|
||||
if (cdns_phy->nsubnodes > 1 && !already_configured) {
|
||||
ret = cdns_torrent_phy_configure_multilink(cdns_phy);
|
||||
if (ret)
|
||||
goto put_lnk_rst;
|
||||
@ -2324,6 +2550,8 @@ put_lnk_rst:
|
||||
of_node_put(child);
|
||||
reset_control_assert(cdns_phy->apb_rst);
|
||||
clk_disable_unprepare(cdns_phy->clk);
|
||||
clk_cleanup:
|
||||
cdns_torrent_clk_cleanup(cdns_phy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2340,6 +2568,7 @@ static int cdns_torrent_phy_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
clk_disable_unprepare(cdns_phy->clk);
|
||||
cdns_torrent_clk_cleanup(cdns_phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2455,8 +2684,6 @@ static struct cdns_reg_pairs usb_100_int_ssc_cmn_regs[] = {
|
||||
{0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START},
|
||||
{0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START},
|
||||
{0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START},
|
||||
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
|
||||
{0x0003, CMN_PLL1_VCOCAL_TCTRL},
|
||||
{0x00C7, CMN_PLL0_LOCK_REFCNT_START},
|
||||
{0x00C7, CMN_PLL1_LOCK_REFCNT_START},
|
||||
{0x00C7, CMN_PLL0_LOCK_PLLCNT_START},
|
||||
@ -2464,7 +2691,9 @@ static struct cdns_reg_pairs usb_100_int_ssc_cmn_regs[] = {
|
||||
{0x0005, CMN_PLL0_LOCK_PLLCNT_THR},
|
||||
{0x0005, CMN_PLL1_LOCK_PLLCNT_THR},
|
||||
{0x8200, CMN_CDIAG_CDB_PWRI_OVRD},
|
||||
{0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD}
|
||||
{0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD},
|
||||
{0x007F, CMN_TXPUCAL_TUNE},
|
||||
{0x007F, CMN_TXPDCAL_TUNE}
|
||||
};
|
||||
|
||||
static struct cdns_torrent_vals usb_100_int_ssc_cmn_vals = {
|
||||
@ -2507,13 +2736,28 @@ static struct cdns_torrent_vals usb_phy_pcs_cmn_vals = {
|
||||
};
|
||||
|
||||
/* USB 100 MHz Ref clk, no SSC */
|
||||
static struct cdns_reg_pairs usb_100_no_ssc_cmn_regs[] = {
|
||||
static struct cdns_reg_pairs sl_usb_100_no_ssc_cmn_regs[] = {
|
||||
{0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0},
|
||||
{0x001E, CMN_PLL1_DSM_FBH_OVRD_M0},
|
||||
{0x000C, CMN_PLL1_DSM_FBL_OVRD_M0},
|
||||
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
|
||||
{0x0003, CMN_PLL1_VCOCAL_TCTRL},
|
||||
{0x8200, CMN_CDIAG_CDB_PWRI_OVRD},
|
||||
{0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD}
|
||||
};
|
||||
|
||||
static struct cdns_torrent_vals sl_usb_100_no_ssc_cmn_vals = {
|
||||
.reg_pairs = sl_usb_100_no_ssc_cmn_regs,
|
||||
.num_regs = ARRAY_SIZE(sl_usb_100_no_ssc_cmn_regs),
|
||||
};
|
||||
|
||||
static struct cdns_reg_pairs usb_100_no_ssc_cmn_regs[] = {
|
||||
{0x8200, CMN_CDIAG_CDB_PWRI_OVRD},
|
||||
{0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD},
|
||||
{0x007F, CMN_TXPUCAL_TUNE},
|
||||
{0x007F, CMN_TXPDCAL_TUNE}
|
||||
};
|
||||
|
||||
static struct cdns_reg_pairs usb_100_no_ssc_tx_ln_regs[] = {
|
||||
{0x02FF, TX_PSC_A0},
|
||||
{0x06AF, TX_PSC_A1},
|
||||
@ -2645,12 +2889,22 @@ static struct cdns_torrent_vals sgmii_pcie_xcvr_diag_ln_vals = {
|
||||
};
|
||||
|
||||
/* SGMII 100 MHz Ref clk, no SSC */
|
||||
static struct cdns_reg_pairs sgmii_100_no_ssc_cmn_regs[] = {
|
||||
static struct cdns_reg_pairs sl_sgmii_100_no_ssc_cmn_regs[] = {
|
||||
{0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0},
|
||||
{0x001E, CMN_PLL1_DSM_FBH_OVRD_M0},
|
||||
{0x000C, CMN_PLL1_DSM_FBL_OVRD_M0},
|
||||
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
|
||||
{0x0003, CMN_PLL1_VCOCAL_TCTRL},
|
||||
{0x3700, CMN_DIAG_BIAS_OVRD1},
|
||||
{0x0008, CMN_TXPUCAL_TUNE},
|
||||
{0x0008, CMN_TXPDCAL_TUNE}
|
||||
{0x0003, CMN_PLL1_VCOCAL_TCTRL}
|
||||
};
|
||||
|
||||
static struct cdns_torrent_vals sl_sgmii_100_no_ssc_cmn_vals = {
|
||||
.reg_pairs = sl_sgmii_100_no_ssc_cmn_regs,
|
||||
.num_regs = ARRAY_SIZE(sl_sgmii_100_no_ssc_cmn_regs),
|
||||
};
|
||||
|
||||
static struct cdns_reg_pairs sgmii_100_no_ssc_cmn_regs[] = {
|
||||
{0x007F, CMN_TXPUCAL_TUNE},
|
||||
{0x007F, CMN_TXPDCAL_TUNE}
|
||||
};
|
||||
|
||||
static struct cdns_reg_pairs sgmii_100_no_ssc_tx_ln_regs[] = {
|
||||
@ -2661,6 +2915,15 @@ static struct cdns_reg_pairs sgmii_100_no_ssc_tx_ln_regs[] = {
|
||||
{0x00B3, DRV_DIAG_TX_DRV}
|
||||
};
|
||||
|
||||
static struct cdns_reg_pairs ti_sgmii_100_no_ssc_tx_ln_regs[] = {
|
||||
{0x00F3, TX_PSC_A0},
|
||||
{0x04A2, TX_PSC_A2},
|
||||
{0x04A2, TX_PSC_A3},
|
||||
{0x0000, TX_TXCC_CPOST_MULT_00},
|
||||
{0x00B3, DRV_DIAG_TX_DRV},
|
||||
{0x4000, XCVR_DIAG_RXCLK_CTRL},
|
||||
};
|
||||
|
||||
static struct cdns_reg_pairs sgmii_100_no_ssc_rx_ln_regs[] = {
|
||||
{0x091D, RX_PSC_A0},
|
||||
{0x0900, RX_PSC_A2},
|
||||
@ -2689,6 +2952,11 @@ static struct cdns_torrent_vals sgmii_100_no_ssc_tx_ln_vals = {
|
||||
.num_regs = ARRAY_SIZE(sgmii_100_no_ssc_tx_ln_regs),
|
||||
};
|
||||
|
||||
static struct cdns_torrent_vals ti_sgmii_100_no_ssc_tx_ln_vals = {
|
||||
.reg_pairs = ti_sgmii_100_no_ssc_tx_ln_regs,
|
||||
.num_regs = ARRAY_SIZE(ti_sgmii_100_no_ssc_tx_ln_regs),
|
||||
};
|
||||
|
||||
static struct cdns_torrent_vals sgmii_100_no_ssc_rx_ln_vals = {
|
||||
.reg_pairs = sgmii_100_no_ssc_rx_ln_regs,
|
||||
.num_regs = ARRAY_SIZE(sgmii_100_no_ssc_rx_ln_regs),
|
||||
@ -2736,17 +3004,14 @@ static struct cdns_reg_pairs sgmii_100_int_ssc_cmn_regs[] = {
|
||||
{0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START},
|
||||
{0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START},
|
||||
{0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START},
|
||||
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
|
||||
{0x0003, CMN_PLL1_VCOCAL_TCTRL},
|
||||
{0x00C7, CMN_PLL0_LOCK_REFCNT_START},
|
||||
{0x00C7, CMN_PLL1_LOCK_REFCNT_START},
|
||||
{0x00C7, CMN_PLL0_LOCK_PLLCNT_START},
|
||||
{0x00C7, CMN_PLL1_LOCK_PLLCNT_START},
|
||||
{0x0005, CMN_PLL0_LOCK_PLLCNT_THR},
|
||||
{0x0005, CMN_PLL1_LOCK_PLLCNT_THR},
|
||||
{0x3700, CMN_DIAG_BIAS_OVRD1},
|
||||
{0x0008, CMN_TXPUCAL_TUNE},
|
||||
{0x0008, CMN_TXPDCAL_TUNE}
|
||||
{0x007F, CMN_TXPUCAL_TUNE},
|
||||
{0x007F, CMN_TXPDCAL_TUNE}
|
||||
};
|
||||
|
||||
static struct cdns_torrent_vals sgmii_100_int_ssc_cmn_vals = {
|
||||
@ -2755,19 +3020,43 @@ static struct cdns_torrent_vals sgmii_100_int_ssc_cmn_vals = {
|
||||
};
|
||||
|
||||
/* QSGMII 100 MHz Ref clk, no SSC */
|
||||
static struct cdns_reg_pairs qsgmii_100_no_ssc_cmn_regs[] = {
|
||||
static struct cdns_reg_pairs sl_qsgmii_100_no_ssc_cmn_regs[] = {
|
||||
{0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0},
|
||||
{0x001E, CMN_PLL1_DSM_FBH_OVRD_M0},
|
||||
{0x000C, CMN_PLL1_DSM_FBL_OVRD_M0},
|
||||
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
|
||||
{0x0003, CMN_PLL1_VCOCAL_TCTRL}
|
||||
};
|
||||
|
||||
static struct cdns_torrent_vals sl_qsgmii_100_no_ssc_cmn_vals = {
|
||||
.reg_pairs = sl_qsgmii_100_no_ssc_cmn_regs,
|
||||
.num_regs = ARRAY_SIZE(sl_qsgmii_100_no_ssc_cmn_regs),
|
||||
};
|
||||
|
||||
static struct cdns_reg_pairs qsgmii_100_no_ssc_cmn_regs[] = {
|
||||
{0x007F, CMN_TXPUCAL_TUNE},
|
||||
{0x007F, CMN_TXPDCAL_TUNE}
|
||||
};
|
||||
|
||||
static struct cdns_reg_pairs qsgmii_100_no_ssc_tx_ln_regs[] = {
|
||||
{0x00F3, TX_PSC_A0},
|
||||
{0x04A2, TX_PSC_A2},
|
||||
{0x04A2, TX_PSC_A3},
|
||||
{0x0000, TX_TXCC_CPOST_MULT_00},
|
||||
{0x0011, TX_TXCC_MGNFS_MULT_100},
|
||||
{0x0003, DRV_DIAG_TX_DRV}
|
||||
};
|
||||
|
||||
static struct cdns_reg_pairs ti_qsgmii_100_no_ssc_tx_ln_regs[] = {
|
||||
{0x00F3, TX_PSC_A0},
|
||||
{0x04A2, TX_PSC_A2},
|
||||
{0x04A2, TX_PSC_A3},
|
||||
{0x0000, TX_TXCC_CPOST_MULT_00},
|
||||
{0x0011, TX_TXCC_MGNFS_MULT_100},
|
||||
{0x0003, DRV_DIAG_TX_DRV},
|
||||
{0x4000, XCVR_DIAG_RXCLK_CTRL},
|
||||
};
|
||||
|
||||
static struct cdns_reg_pairs qsgmii_100_no_ssc_rx_ln_regs[] = {
|
||||
{0x091D, RX_PSC_A0},
|
||||
{0x0900, RX_PSC_A2},
|
||||
@ -2796,6 +3085,11 @@ static struct cdns_torrent_vals qsgmii_100_no_ssc_tx_ln_vals = {
|
||||
.num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_tx_ln_regs),
|
||||
};
|
||||
|
||||
static struct cdns_torrent_vals ti_qsgmii_100_no_ssc_tx_ln_vals = {
|
||||
.reg_pairs = ti_qsgmii_100_no_ssc_tx_ln_regs,
|
||||
.num_regs = ARRAY_SIZE(ti_qsgmii_100_no_ssc_tx_ln_regs),
|
||||
};
|
||||
|
||||
static struct cdns_torrent_vals qsgmii_100_no_ssc_rx_ln_vals = {
|
||||
.reg_pairs = qsgmii_100_no_ssc_rx_ln_regs,
|
||||
.num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_rx_ln_regs),
|
||||
@ -2843,14 +3137,14 @@ static struct cdns_reg_pairs qsgmii_100_int_ssc_cmn_regs[] = {
|
||||
{0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START},
|
||||
{0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START},
|
||||
{0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START},
|
||||
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
|
||||
{0x0003, CMN_PLL1_VCOCAL_TCTRL},
|
||||
{0x00C7, CMN_PLL0_LOCK_REFCNT_START},
|
||||
{0x00C7, CMN_PLL1_LOCK_REFCNT_START},
|
||||
{0x00C7, CMN_PLL0_LOCK_PLLCNT_START},
|
||||
{0x00C7, CMN_PLL1_LOCK_PLLCNT_START},
|
||||
{0x0005, CMN_PLL0_LOCK_PLLCNT_THR},
|
||||
{0x0005, CMN_PLL1_LOCK_PLLCNT_THR}
|
||||
{0x0005, CMN_PLL1_LOCK_PLLCNT_THR},
|
||||
{0x007F, CMN_TXPUCAL_TUNE},
|
||||
{0x007F, CMN_TXPDCAL_TUNE}
|
||||
};
|
||||
|
||||
static struct cdns_torrent_vals qsgmii_100_int_ssc_cmn_vals = {
|
||||
@ -2922,8 +3216,6 @@ static struct cdns_reg_pairs pcie_100_int_ssc_cmn_regs[] = {
|
||||
{0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START},
|
||||
{0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START},
|
||||
{0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START},
|
||||
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
|
||||
{0x0003, CMN_PLL1_VCOCAL_TCTRL},
|
||||
{0x00C7, CMN_PLL0_LOCK_REFCNT_START},
|
||||
{0x00C7, CMN_PLL1_LOCK_REFCNT_START},
|
||||
{0x00C7, CMN_PLL0_LOCK_PLLCNT_START},
|
||||
@ -2979,8 +3271,6 @@ static struct cdns_reg_pairs sl_pcie_100_int_ssc_cmn_regs[] = {
|
||||
{0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START},
|
||||
{0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START},
|
||||
{0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START},
|
||||
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
|
||||
{0x0003, CMN_PLL1_VCOCAL_TCTRL},
|
||||
{0x00C7, CMN_PLL0_LOCK_REFCNT_START},
|
||||
{0x00C7, CMN_PLL1_LOCK_REFCNT_START},
|
||||
{0x00C7, CMN_PLL0_LOCK_PLLCNT_START},
|
||||
@ -2996,8 +3286,9 @@ static struct cdns_torrent_vals sl_pcie_100_int_ssc_cmn_vals = {
|
||||
|
||||
/* PCIe, 100 MHz Ref clk, no SSC & external SSC */
|
||||
static struct cdns_reg_pairs pcie_100_ext_no_ssc_cmn_regs[] = {
|
||||
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
|
||||
{0x0003, CMN_PLL1_VCOCAL_TCTRL}
|
||||
{0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0},
|
||||
{0x001E, CMN_PLL1_DSM_FBH_OVRD_M0},
|
||||
{0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}
|
||||
};
|
||||
|
||||
static struct cdns_reg_pairs pcie_100_ext_no_ssc_rx_ln_regs[] = {
|
||||
@ -3198,8 +3489,8 @@ static const struct cdns_torrent_data cdns_map_torrent = {
|
||||
.cmn_vals = {
|
||||
[TYPE_PCIE] = {
|
||||
[TYPE_NONE] = {
|
||||
[NO_SSC] = &pcie_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = NULL,
|
||||
[EXTERNAL_SSC] = NULL,
|
||||
[INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_SGMII] = {
|
||||
@ -3220,7 +3511,7 @@ static const struct cdns_torrent_data cdns_map_torrent = {
|
||||
},
|
||||
[TYPE_SGMII] = {
|
||||
[TYPE_NONE] = {
|
||||
[NO_SSC] = &sgmii_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_PCIE] = {
|
||||
[NO_SSC] = &sgmii_100_no_ssc_cmn_vals,
|
||||
@ -3235,7 +3526,7 @@ static const struct cdns_torrent_data cdns_map_torrent = {
|
||||
},
|
||||
[TYPE_QSGMII] = {
|
||||
[TYPE_NONE] = {
|
||||
[NO_SSC] = &qsgmii_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_PCIE] = {
|
||||
[NO_SSC] = &qsgmii_100_no_ssc_cmn_vals,
|
||||
@ -3250,8 +3541,8 @@ static const struct cdns_torrent_data cdns_map_torrent = {
|
||||
},
|
||||
[TYPE_USB] = {
|
||||
[TYPE_NONE] = {
|
||||
[NO_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_PCIE] = {
|
||||
@ -3260,13 +3551,13 @@ static const struct cdns_torrent_data cdns_map_torrent = {
|
||||
[INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_SGMII] = {
|
||||
[NO_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_QSGMII] = {
|
||||
[NO_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals,
|
||||
},
|
||||
},
|
||||
@ -3607,8 +3898,8 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
|
||||
.cmn_vals = {
|
||||
[TYPE_PCIE] = {
|
||||
[TYPE_NONE] = {
|
||||
[NO_SSC] = &pcie_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = NULL,
|
||||
[EXTERNAL_SSC] = NULL,
|
||||
[INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_SGMII] = {
|
||||
@ -3629,7 +3920,7 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
|
||||
},
|
||||
[TYPE_SGMII] = {
|
||||
[TYPE_NONE] = {
|
||||
[NO_SSC] = &sgmii_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_PCIE] = {
|
||||
[NO_SSC] = &sgmii_100_no_ssc_cmn_vals,
|
||||
@ -3644,7 +3935,7 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
|
||||
},
|
||||
[TYPE_QSGMII] = {
|
||||
[TYPE_NONE] = {
|
||||
[NO_SSC] = &qsgmii_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_PCIE] = {
|
||||
[NO_SSC] = &qsgmii_100_no_ssc_cmn_vals,
|
||||
@ -3659,8 +3950,8 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
|
||||
},
|
||||
[TYPE_USB] = {
|
||||
[TYPE_NONE] = {
|
||||
[NO_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_PCIE] = {
|
||||
@ -3669,13 +3960,13 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
|
||||
[INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_SGMII] = {
|
||||
[NO_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals,
|
||||
},
|
||||
[TYPE_QSGMII] = {
|
||||
[NO_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals,
|
||||
[NO_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals,
|
||||
[INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals,
|
||||
},
|
||||
},
|
||||
@ -3705,32 +3996,32 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
|
||||
},
|
||||
[TYPE_SGMII] = {
|
||||
[TYPE_NONE] = {
|
||||
[NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals,
|
||||
[NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals,
|
||||
},
|
||||
[TYPE_PCIE] = {
|
||||
[NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals,
|
||||
[EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals,
|
||||
[INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals,
|
||||
[NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals,
|
||||
[EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals,
|
||||
[INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals,
|
||||
},
|
||||
[TYPE_USB] = {
|
||||
[NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals,
|
||||
[EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals,
|
||||
[INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals,
|
||||
[NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals,
|
||||
[EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals,
|
||||
[INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals,
|
||||
},
|
||||
},
|
||||
[TYPE_QSGMII] = {
|
||||
[TYPE_NONE] = {
|
||||
[NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals,
|
||||
[NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals,
|
||||
},
|
||||
[TYPE_PCIE] = {
|
||||
[NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals,
|
||||
[EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals,
|
||||
[INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals,
|
||||
[NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals,
|
||||
[EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals,
|
||||
[INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals,
|
||||
},
|
||||
[TYPE_USB] = {
|
||||
[NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals,
|
||||
[EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals,
|
||||
[INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals,
|
||||
[NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals,
|
||||
[EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals,
|
||||
[INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals,
|
||||
},
|
||||
},
|
||||
[TYPE_USB] = {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2015 Linaro Ltd.
|
||||
* Copyright (c) 2015 Hisilicon Limited.
|
||||
* Copyright (c) 2015 HiSilicon Limited.
|
||||
*/
|
||||
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2014 Linaro Ltd.
|
||||
* Copyright (c) 2014 Hisilicon Limited.
|
||||
* Copyright (c) 2014 HiSilicon Limited.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@ -352,8 +352,8 @@ static int ingenic_usb_phy_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
priv->phy = devm_phy_create(dev, NULL, &ingenic_usb_phy_ops);
|
||||
if (IS_ERR(priv))
|
||||
return PTR_ERR(priv);
|
||||
if (IS_ERR(priv->phy))
|
||||
return PTR_ERR(priv->phy);
|
||||
|
||||
phy_set_drvdata(priv->phy, priv);
|
||||
|
||||
|
@ -462,7 +462,7 @@ static int intel_cbphy_fwnode_parse(struct intel_combo_phy *cbphy)
|
||||
|
||||
/*
|
||||
* syscfg and hsiocfg variables stores the handle of the registers set
|
||||
* in which ComboPhy subsytem specific registers are subset. Using
|
||||
* in which ComboPhy subsystem specific registers are subset. Using
|
||||
* Register map framework to access the registers set.
|
||||
*/
|
||||
ret = fwnode_property_get_reference_args(fwnode, "intel,syscfg", NULL,
|
||||
|
@ -3,8 +3,8 @@
|
||||
# Phy drivers for Marvell platforms
|
||||
#
|
||||
config ARMADA375_USBCLUSTER_PHY
|
||||
def_bool y
|
||||
depends on MACH_ARMADA_375 || COMPILE_TEST
|
||||
bool "Armada 375 USB cluster PHY support" if COMPILE_TEST
|
||||
default y if MACH_ARMADA_375
|
||||
depends on OF && HAS_IOMEM
|
||||
select GENERIC_PHY
|
||||
|
||||
@ -67,6 +67,14 @@ config PHY_MVEBU_CP110_COMPHY
|
||||
lanes can be used by various controllers (Ethernet, sata, usb,
|
||||
PCIe...).
|
||||
|
||||
config PHY_MVEBU_CP110_UTMI
|
||||
tristate "Marvell CP110 UTMI driver"
|
||||
depends on ARCH_MVEBU || COMPILE_TEST
|
||||
depends on OF && USB_COMMON
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support Marvell CP110 UTMI PHY driver.
|
||||
|
||||
config PHY_MVEBU_SATA
|
||||
def_bool y
|
||||
depends on ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD
|
||||
|
@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_MVEBU_A3700_COMPHY) += phy-mvebu-a3700-comphy.o
|
||||
obj-$(CONFIG_PHY_MVEBU_A3700_UTMI) += phy-mvebu-a3700-utmi.o
|
||||
obj-$(CONFIG_PHY_MVEBU_A38X_COMPHY) += phy-armada38x-comphy.o
|
||||
obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY) += phy-mvebu-cp110-comphy.o
|
||||
obj-$(CONFIG_PHY_MVEBU_CP110_UTMI) += phy-mvebu-cp110-utmi.o
|
||||
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
|
||||
obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o
|
||||
obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o
|
||||
|
384
drivers/phy/marvell/phy-mvebu-cp110-utmi.c
Normal file
384
drivers/phy/marvell/phy-mvebu-cp110-utmi.c
Normal file
@ -0,0 +1,384 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2021 Marvell
|
||||
*
|
||||
* Authors:
|
||||
* Konstantin Porotchkin <kostap@marvell.com>
|
||||
*
|
||||
* Marvell CP110 UTMI PHY driver
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/usb/of.h>
|
||||
#include <linux/usb/otg.h>
|
||||
|
||||
#define UTMI_PHY_PORTS 2
|
||||
|
||||
/* CP110 UTMI register macro definetions */
|
||||
#define SYSCON_USB_CFG_REG 0x420
|
||||
#define USB_CFG_DEVICE_EN_MASK BIT(0)
|
||||
#define USB_CFG_DEVICE_MUX_OFFSET 1
|
||||
#define USB_CFG_DEVICE_MUX_MASK BIT(1)
|
||||
#define USB_CFG_PLL_MASK BIT(25)
|
||||
|
||||
#define SYSCON_UTMI_CFG_REG(id) (0x440 + (id) * 4)
|
||||
#define UTMI_PHY_CFG_PU_MASK BIT(5)
|
||||
|
||||
#define UTMI_PLL_CTRL_REG 0x0
|
||||
#define PLL_REFDIV_OFFSET 0
|
||||
#define PLL_REFDIV_MASK GENMASK(6, 0)
|
||||
#define PLL_REFDIV_VAL 0x5
|
||||
#define PLL_FBDIV_OFFSET 16
|
||||
#define PLL_FBDIV_MASK GENMASK(24, 16)
|
||||
#define PLL_FBDIV_VAL 0x60
|
||||
#define PLL_SEL_LPFR_MASK GENMASK(29, 28)
|
||||
#define PLL_RDY BIT(31)
|
||||
#define UTMI_CAL_CTRL_REG 0x8
|
||||
#define IMPCAL_VTH_OFFSET 8
|
||||
#define IMPCAL_VTH_MASK GENMASK(10, 8)
|
||||
#define IMPCAL_VTH_VAL 0x7
|
||||
#define IMPCAL_DONE BIT(23)
|
||||
#define PLLCAL_DONE BIT(31)
|
||||
#define UTMI_TX_CH_CTRL_REG 0xC
|
||||
#define DRV_EN_LS_OFFSET 12
|
||||
#define DRV_EN_LS_MASK GENMASK(15, 12)
|
||||
#define IMP_SEL_LS_OFFSET 16
|
||||
#define IMP_SEL_LS_MASK GENMASK(19, 16)
|
||||
#define TX_AMP_OFFSET 20
|
||||
#define TX_AMP_MASK GENMASK(22, 20)
|
||||
#define TX_AMP_VAL 0x4
|
||||
#define UTMI_RX_CH_CTRL0_REG 0x14
|
||||
#define SQ_DET_EN BIT(15)
|
||||
#define SQ_ANA_DTC_SEL BIT(28)
|
||||
#define UTMI_RX_CH_CTRL1_REG 0x18
|
||||
#define SQ_AMP_CAL_OFFSET 0
|
||||
#define SQ_AMP_CAL_MASK GENMASK(2, 0)
|
||||
#define SQ_AMP_CAL_VAL 1
|
||||
#define SQ_AMP_CAL_EN BIT(3)
|
||||
#define UTMI_CTRL_STATUS0_REG 0x24
|
||||
#define SUSPENDM BIT(22)
|
||||
#define TEST_SEL BIT(25)
|
||||
#define UTMI_CHGDTC_CTRL_REG 0x38
|
||||
#define VDAT_OFFSET 8
|
||||
#define VDAT_MASK GENMASK(9, 8)
|
||||
#define VDAT_VAL 1
|
||||
#define VSRC_OFFSET 10
|
||||
#define VSRC_MASK GENMASK(11, 10)
|
||||
#define VSRC_VAL 1
|
||||
|
||||
#define PLL_LOCK_DELAY_US 10000
|
||||
#define PLL_LOCK_TIMEOUT_US 1000000
|
||||
|
||||
#define PORT_REGS(p) ((p)->priv->regs + (p)->id * 0x1000)
|
||||
|
||||
/**
|
||||
* struct mvebu_cp110_utmi - PHY driver data
|
||||
*
|
||||
* @regs: PHY registers
|
||||
* @syscom: Regmap with system controller registers
|
||||
* @dev: device driver handle
|
||||
* @caps: PHY capabilities
|
||||
*/
|
||||
struct mvebu_cp110_utmi {
|
||||
void __iomem *regs;
|
||||
struct regmap *syscon;
|
||||
struct device *dev;
|
||||
const struct phy_ops *ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mvebu_cp110_utmi_port - PHY port data
|
||||
*
|
||||
* @priv: PHY driver data
|
||||
* @id: PHY port ID
|
||||
* @dr_mode: PHY connection: USB_DR_MODE_HOST or USB_DR_MODE_PERIPHERAL
|
||||
*/
|
||||
struct mvebu_cp110_utmi_port {
|
||||
struct mvebu_cp110_utmi *priv;
|
||||
u32 id;
|
||||
enum usb_dr_mode dr_mode;
|
||||
};
|
||||
|
||||
static void mvebu_cp110_utmi_port_setup(struct mvebu_cp110_utmi_port *port)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Setup PLL.
|
||||
* The reference clock is the frequency of quartz resonator
|
||||
* connected to pins REFCLK_XIN and REFCLK_XOUT of the SoC.
|
||||
* Register init values are matching the 40MHz default clock.
|
||||
* The crystal used for all platform boards is now 25MHz.
|
||||
* See the functional specification for details.
|
||||
*/
|
||||
reg = readl(PORT_REGS(port) + UTMI_PLL_CTRL_REG);
|
||||
reg &= ~(PLL_REFDIV_MASK | PLL_FBDIV_MASK | PLL_SEL_LPFR_MASK);
|
||||
reg |= (PLL_REFDIV_VAL << PLL_REFDIV_OFFSET) |
|
||||
(PLL_FBDIV_VAL << PLL_FBDIV_OFFSET);
|
||||
writel(reg, PORT_REGS(port) + UTMI_PLL_CTRL_REG);
|
||||
|
||||
/* Impedance Calibration Threshold Setting */
|
||||
reg = readl(PORT_REGS(port) + UTMI_CAL_CTRL_REG);
|
||||
reg &= ~IMPCAL_VTH_MASK;
|
||||
reg |= IMPCAL_VTH_VAL << IMPCAL_VTH_OFFSET;
|
||||
writel(reg, PORT_REGS(port) + UTMI_CAL_CTRL_REG);
|
||||
|
||||
/* Set LS TX driver strength coarse control */
|
||||
reg = readl(PORT_REGS(port) + UTMI_TX_CH_CTRL_REG);
|
||||
reg &= ~TX_AMP_MASK;
|
||||
reg |= TX_AMP_VAL << TX_AMP_OFFSET;
|
||||
writel(reg, PORT_REGS(port) + UTMI_TX_CH_CTRL_REG);
|
||||
|
||||
/* Disable SQ and enable analog squelch detect */
|
||||
reg = readl(PORT_REGS(port) + UTMI_RX_CH_CTRL0_REG);
|
||||
reg &= ~SQ_DET_EN;
|
||||
reg |= SQ_ANA_DTC_SEL;
|
||||
writel(reg, PORT_REGS(port) + UTMI_RX_CH_CTRL0_REG);
|
||||
|
||||
/*
|
||||
* Set External squelch calibration number and
|
||||
* enable the External squelch calibration
|
||||
*/
|
||||
reg = readl(PORT_REGS(port) + UTMI_RX_CH_CTRL1_REG);
|
||||
reg &= ~SQ_AMP_CAL_MASK;
|
||||
reg |= (SQ_AMP_CAL_VAL << SQ_AMP_CAL_OFFSET) | SQ_AMP_CAL_EN;
|
||||
writel(reg, PORT_REGS(port) + UTMI_RX_CH_CTRL1_REG);
|
||||
|
||||
/*
|
||||
* Set Control VDAT Reference Voltage - 0.325V and
|
||||
* Control VSRC Reference Voltage - 0.6V
|
||||
*/
|
||||
reg = readl(PORT_REGS(port) + UTMI_CHGDTC_CTRL_REG);
|
||||
reg &= ~(VDAT_MASK | VSRC_MASK);
|
||||
reg |= (VDAT_VAL << VDAT_OFFSET) | (VSRC_VAL << VSRC_OFFSET);
|
||||
writel(reg, PORT_REGS(port) + UTMI_CHGDTC_CTRL_REG);
|
||||
}
|
||||
|
||||
static int mvebu_cp110_utmi_phy_power_off(struct phy *phy)
|
||||
{
|
||||
struct mvebu_cp110_utmi_port *port = phy_get_drvdata(phy);
|
||||
struct mvebu_cp110_utmi *utmi = port->priv;
|
||||
int i;
|
||||
|
||||
/* Power down UTMI PHY port */
|
||||
regmap_clear_bits(utmi->syscon, SYSCON_UTMI_CFG_REG(port->id),
|
||||
UTMI_PHY_CFG_PU_MASK);
|
||||
|
||||
for (i = 0; i < UTMI_PHY_PORTS; i++) {
|
||||
int test = regmap_test_bits(utmi->syscon,
|
||||
SYSCON_UTMI_CFG_REG(i),
|
||||
UTMI_PHY_CFG_PU_MASK);
|
||||
/* skip PLL shutdown if there are active UTMI PHY ports */
|
||||
if (test != 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PLL Power down if all UTMI PHYs are down */
|
||||
regmap_clear_bits(utmi->syscon, SYSCON_USB_CFG_REG, USB_CFG_PLL_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_cp110_utmi_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct mvebu_cp110_utmi_port *port = phy_get_drvdata(phy);
|
||||
struct mvebu_cp110_utmi *utmi = port->priv;
|
||||
struct device *dev = &phy->dev;
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
||||
/* It is necessary to power off UTMI before configuration */
|
||||
ret = mvebu_cp110_utmi_phy_power_off(phy);
|
||||
if (ret) {
|
||||
dev_err(dev, "UTMI power OFF before power ON failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* If UTMI port is connected to USB Device controller,
|
||||
* configure the USB MUX prior to UTMI PHY initialization.
|
||||
* The single USB device controller can be connected
|
||||
* to UTMI0 or to UTMI1 PHY port, but not to both.
|
||||
*/
|
||||
if (port->dr_mode == USB_DR_MODE_PERIPHERAL) {
|
||||
regmap_update_bits(utmi->syscon, SYSCON_USB_CFG_REG,
|
||||
USB_CFG_DEVICE_EN_MASK | USB_CFG_DEVICE_MUX_MASK,
|
||||
USB_CFG_DEVICE_EN_MASK |
|
||||
(port->id << USB_CFG_DEVICE_MUX_OFFSET));
|
||||
}
|
||||
|
||||
/* Set Test suspendm mode and enable Test UTMI select */
|
||||
reg = readl(PORT_REGS(port) + UTMI_CTRL_STATUS0_REG);
|
||||
reg |= SUSPENDM | TEST_SEL;
|
||||
writel(reg, PORT_REGS(port) + UTMI_CTRL_STATUS0_REG);
|
||||
|
||||
/* Wait for UTMI power down */
|
||||
mdelay(1);
|
||||
|
||||
/* PHY port setup first */
|
||||
mvebu_cp110_utmi_port_setup(port);
|
||||
|
||||
/* Power UP UTMI PHY */
|
||||
regmap_set_bits(utmi->syscon, SYSCON_UTMI_CFG_REG(port->id),
|
||||
UTMI_PHY_CFG_PU_MASK);
|
||||
|
||||
/* Disable Test UTMI select */
|
||||
reg = readl(PORT_REGS(port) + UTMI_CTRL_STATUS0_REG);
|
||||
reg &= ~TEST_SEL;
|
||||
writel(reg, PORT_REGS(port) + UTMI_CTRL_STATUS0_REG);
|
||||
|
||||
/* Wait for impedance calibration */
|
||||
ret = readl_poll_timeout(PORT_REGS(port) + UTMI_CAL_CTRL_REG, reg,
|
||||
reg & IMPCAL_DONE,
|
||||
PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to end UTMI impedance calibration\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for PLL calibration */
|
||||
ret = readl_poll_timeout(PORT_REGS(port) + UTMI_CAL_CTRL_REG, reg,
|
||||
reg & PLLCAL_DONE,
|
||||
PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to end UTMI PLL calibration\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for PLL ready */
|
||||
ret = readl_poll_timeout(PORT_REGS(port) + UTMI_PLL_CTRL_REG, reg,
|
||||
reg & PLL_RDY,
|
||||
PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(dev, "PLL is not ready\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* PLL Power up */
|
||||
regmap_set_bits(utmi->syscon, SYSCON_USB_CFG_REG, USB_CFG_PLL_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops mvebu_cp110_utmi_phy_ops = {
|
||||
.power_on = mvebu_cp110_utmi_phy_power_on,
|
||||
.power_off = mvebu_cp110_utmi_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id mvebu_cp110_utmi_of_match[] = {
|
||||
{ .compatible = "marvell,cp110-utmi-phy" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mvebu_cp110_utmi_of_match);
|
||||
|
||||
static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mvebu_cp110_utmi *utmi;
|
||||
struct phy_provider *provider;
|
||||
struct device_node *child;
|
||||
u32 usb_devices = 0;
|
||||
|
||||
utmi = devm_kzalloc(dev, sizeof(*utmi), GFP_KERNEL);
|
||||
if (!utmi)
|
||||
return -ENOMEM;
|
||||
|
||||
utmi->dev = dev;
|
||||
|
||||
/* Get system controller region */
|
||||
utmi->syscon = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"marvell,system-controller");
|
||||
if (IS_ERR(utmi->syscon)) {
|
||||
dev_err(dev, "Missing UTMI system controller\n");
|
||||
return PTR_ERR(utmi->syscon);
|
||||
}
|
||||
|
||||
/* Get UTMI memory region */
|
||||
utmi->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(utmi->regs))
|
||||
return PTR_ERR(utmi->regs);
|
||||
|
||||
for_each_available_child_of_node(dev->of_node, child) {
|
||||
struct mvebu_cp110_utmi_port *port;
|
||||
struct phy *phy;
|
||||
int ret;
|
||||
u32 port_id;
|
||||
|
||||
ret = of_property_read_u32(child, "reg", &port_id);
|
||||
if ((ret < 0) || (port_id >= UTMI_PHY_PORTS)) {
|
||||
dev_err(dev,
|
||||
"invalid 'reg' property on child %pOF\n",
|
||||
child);
|
||||
continue;
|
||||
}
|
||||
|
||||
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
|
||||
if (!port) {
|
||||
of_node_put(child);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
port->dr_mode = of_usb_get_dr_mode_by_phy(child, -1);
|
||||
if ((port->dr_mode != USB_DR_MODE_HOST) &&
|
||||
(port->dr_mode != USB_DR_MODE_PERIPHERAL)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Missing dual role setting of the port%d, will use HOST mode\n",
|
||||
port_id);
|
||||
port->dr_mode = USB_DR_MODE_HOST;
|
||||
}
|
||||
|
||||
if (port->dr_mode == USB_DR_MODE_PERIPHERAL) {
|
||||
usb_devices++;
|
||||
if (usb_devices > 1) {
|
||||
dev_err(dev,
|
||||
"Single USB device allowed! Port%d will use HOST mode\n",
|
||||
port_id);
|
||||
port->dr_mode = USB_DR_MODE_HOST;
|
||||
}
|
||||
}
|
||||
|
||||
/* Retrieve PHY capabilities */
|
||||
utmi->ops = &mvebu_cp110_utmi_phy_ops;
|
||||
|
||||
/* Instantiate the PHY */
|
||||
phy = devm_phy_create(dev, child, utmi->ops);
|
||||
if (IS_ERR(phy)) {
|
||||
dev_err(dev, "Failed to create the UTMI PHY\n");
|
||||
of_node_put(child);
|
||||
return PTR_ERR(phy);
|
||||
}
|
||||
|
||||
port->priv = utmi;
|
||||
port->id = port_id;
|
||||
phy_set_drvdata(phy, port);
|
||||
|
||||
/* Ensure the PHY is powered off */
|
||||
mvebu_cp110_utmi_phy_power_off(phy);
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, utmi);
|
||||
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
|
||||
return PTR_ERR_OR_ZERO(provider);
|
||||
}
|
||||
|
||||
static struct platform_driver mvebu_cp110_utmi_driver = {
|
||||
.probe = mvebu_cp110_utmi_phy_probe,
|
||||
.driver = {
|
||||
.name = "mvebu-cp110-utmi-phy",
|
||||
.of_match_table = mvebu_cp110_utmi_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(mvebu_cp110_utmi_driver);
|
||||
|
||||
MODULE_AUTHOR("Konstatin Porotchkin <kostap@marvell.com>");
|
||||
MODULE_DESCRIPTION("Marvell Armada CP110 UTMI PHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
13
drivers/phy/microchip/Kconfig
Normal file
13
drivers/phy/microchip/Kconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Phy drivers for Microchip devices
|
||||
#
|
||||
|
||||
config PHY_SPARX5_SERDES
|
||||
tristate "Microchip Sparx5 SerDes PHY driver"
|
||||
select GENERIC_PHY
|
||||
depends on ARCH_SPARX5 || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Enable this for support of the 10G/25G SerDes on Microchip Sparx5.
|
6
drivers/phy/microchip/Makefile
Normal file
6
drivers/phy/microchip/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Makefile for the Microchip phy drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_PHY_SPARX5_SERDES) := sparx5_serdes.o
|
2513
drivers/phy/microchip/sparx5_serdes.c
Normal file
2513
drivers/phy/microchip/sparx5_serdes.c
Normal file
File diff suppressed because it is too large
Load Diff
136
drivers/phy/microchip/sparx5_serdes.h
Normal file
136
drivers/phy/microchip/sparx5_serdes.h
Normal file
@ -0,0 +1,136 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+
|
||||
* Microchip Sparx5 SerDes driver
|
||||
*
|
||||
* Copyright (c) 2020 Microchip Technology Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SPARX5_SERDES_H_
|
||||
#define _SPARX5_SERDES_H_
|
||||
|
||||
#include "sparx5_serdes_regs.h"
|
||||
|
||||
#define SPX5_SERDES_MAX 33
|
||||
|
||||
enum sparx5_serdes_type {
|
||||
SPX5_SDT_6G = 6,
|
||||
SPX5_SDT_10G = 10,
|
||||
SPX5_SDT_25G = 25,
|
||||
};
|
||||
|
||||
enum sparx5_serdes_mode {
|
||||
SPX5_SD_MODE_NONE,
|
||||
SPX5_SD_MODE_2G5,
|
||||
SPX5_SD_MODE_QSGMII,
|
||||
SPX5_SD_MODE_100FX,
|
||||
SPX5_SD_MODE_1000BASEX,
|
||||
SPX5_SD_MODE_SFI,
|
||||
};
|
||||
|
||||
struct sparx5_serdes_private {
|
||||
struct device *dev;
|
||||
void __iomem *regs[NUM_TARGETS];
|
||||
struct phy *phys[SPX5_SERDES_MAX];
|
||||
bool cmu_enabled;
|
||||
unsigned long coreclock;
|
||||
};
|
||||
|
||||
struct sparx5_serdes_macro {
|
||||
struct sparx5_serdes_private *priv;
|
||||
u32 sidx;
|
||||
u32 stpidx;
|
||||
enum sparx5_serdes_type serdestype;
|
||||
enum sparx5_serdes_mode serdesmode;
|
||||
phy_interface_t portmode;
|
||||
int speed;
|
||||
enum phy_media media;
|
||||
};
|
||||
|
||||
/* Read, Write and modify registers content.
|
||||
* The register definition macros start at the id
|
||||
*/
|
||||
static inline void __iomem *sdx5_addr(void __iomem *base[],
|
||||
int id, int tinst, int tcnt,
|
||||
int gbase, int ginst,
|
||||
int gcnt, int gwidth,
|
||||
int raddr, int rinst,
|
||||
int rcnt, int rwidth)
|
||||
{
|
||||
WARN_ON((tinst) >= tcnt);
|
||||
WARN_ON((ginst) >= gcnt);
|
||||
WARN_ON((rinst) >= rcnt);
|
||||
return base[id + (tinst)] +
|
||||
gbase + ((ginst) * gwidth) +
|
||||
raddr + ((rinst) * rwidth);
|
||||
}
|
||||
|
||||
static inline void __iomem *sdx5_inst_baseaddr(void __iomem *base,
|
||||
int gbase, int ginst,
|
||||
int gcnt, int gwidth,
|
||||
int raddr, int rinst,
|
||||
int rcnt, int rwidth)
|
||||
{
|
||||
WARN_ON((ginst) >= gcnt);
|
||||
WARN_ON((rinst) >= rcnt);
|
||||
return base +
|
||||
gbase + ((ginst) * gwidth) +
|
||||
raddr + ((rinst) * rwidth);
|
||||
}
|
||||
|
||||
static inline void sdx5_rmw(u32 val, u32 mask, struct sparx5_serdes_private *priv,
|
||||
int id, int tinst, int tcnt,
|
||||
int gbase, int ginst, int gcnt, int gwidth,
|
||||
int raddr, int rinst, int rcnt, int rwidth)
|
||||
{
|
||||
u32 nval;
|
||||
void __iomem *addr =
|
||||
sdx5_addr(priv->regs, id, tinst, tcnt,
|
||||
gbase, ginst, gcnt, gwidth,
|
||||
raddr, rinst, rcnt, rwidth);
|
||||
nval = readl(addr);
|
||||
nval = (nval & ~mask) | (val & mask);
|
||||
writel(nval, addr);
|
||||
}
|
||||
|
||||
static inline void sdx5_inst_rmw(u32 val, u32 mask, void __iomem *iomem,
|
||||
int id, int tinst, int tcnt,
|
||||
int gbase, int ginst, int gcnt, int gwidth,
|
||||
int raddr, int rinst, int rcnt, int rwidth)
|
||||
{
|
||||
u32 nval;
|
||||
void __iomem *addr =
|
||||
sdx5_inst_baseaddr(iomem,
|
||||
gbase, ginst, gcnt, gwidth,
|
||||
raddr, rinst, rcnt, rwidth);
|
||||
nval = readl(addr);
|
||||
nval = (nval & ~mask) | (val & mask);
|
||||
writel(nval, addr);
|
||||
}
|
||||
|
||||
static inline void sdx5_rmw_addr(u32 val, u32 mask, void __iomem *addr)
|
||||
{
|
||||
u32 nval;
|
||||
|
||||
nval = readl(addr);
|
||||
nval = (nval & ~mask) | (val & mask);
|
||||
writel(nval, addr);
|
||||
}
|
||||
|
||||
static inline void __iomem *sdx5_inst_get(struct sparx5_serdes_private *priv,
|
||||
int id, int tinst)
|
||||
{
|
||||
return priv->regs[id + tinst];
|
||||
}
|
||||
|
||||
static inline void __iomem *sdx5_inst_addr(void __iomem *iomem,
|
||||
int id, int tinst, int tcnt,
|
||||
int gbase,
|
||||
int ginst, int gcnt, int gwidth,
|
||||
int raddr,
|
||||
int rinst, int rcnt, int rwidth)
|
||||
{
|
||||
return sdx5_inst_baseaddr(iomem, gbase, ginst, gcnt, gwidth,
|
||||
raddr, rinst, rcnt, rwidth);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _SPARX5_SERDES_REGS_H_ */
|
2695
drivers/phy/microchip/sparx5_serdes_regs.h
Normal file
2695
drivers/phy/microchip/sparx5_serdes_regs.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -373,6 +373,36 @@ int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_set_mode_ext);
|
||||
|
||||
int phy_set_media(struct phy *phy, enum phy_media media)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!phy || !phy->ops->set_media)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&phy->mutex);
|
||||
ret = phy->ops->set_media(phy, media);
|
||||
mutex_unlock(&phy->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_set_media);
|
||||
|
||||
int phy_set_speed(struct phy *phy, int speed)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!phy || !phy->ops->set_speed)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&phy->mutex);
|
||||
ret = phy->ops->set_speed(phy, speed);
|
||||
mutex_unlock(&phy->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_set_speed);
|
||||
|
||||
int phy_reset(struct phy *phy)
|
||||
{
|
||||
int ret;
|
||||
|
@ -276,8 +276,8 @@ static int qcom_ipq806x_usb_hs_phy_init(struct phy *phy)
|
||||
val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP |
|
||||
HSUSB_CTRL_RETENABLEN | HSUSB_CTRL_COMMONONN |
|
||||
HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP |
|
||||
HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_UTMI_OTG_VBUS_VALID |
|
||||
HSUSB_CTRL_UTMI_CLK_EN | HSUSB_CTRL_CLAMP_EN | 0x70;
|
||||
HSUSB_CTRL_UTMI_OTG_VBUS_VALID | HSUSB_CTRL_UTMI_CLK_EN |
|
||||
HSUSB_CTRL_CLAMP_EN | 0x70;
|
||||
|
||||
/* use core clock if external reference is not present */
|
||||
if (!phy_dwc3->xo_clk)
|
||||
|
@ -1840,6 +1840,86 @@ static const struct qmp_phy_init_tbl sm8250_usb3_uniphy_pcs_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SVS_MODE_CLK_SEL, 0x05),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x3b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYS_CLK_CTRL, 0x02),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_ENABLE1, 0x0c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_BUF_ENABLE, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x30),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_IVCO, 0x0f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_CONFIG, 0x02),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE0, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BG_TIMER, 0x0a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE0, 0x0a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_CTRL, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN, 0x17),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORE_CLK_EN, 0x1f),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_rbr[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x05),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x69),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x80),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x07),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x6f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x08),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x04),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_hbr[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x03),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x69),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x80),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x07),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x0f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x0e),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x08),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_hbr2[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x8c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x0a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x1c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x08),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_hbr3[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x69),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x80),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x07),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x2f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x2a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x08),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl qmp_v4_dp_tx_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_VMODE_CTRL1, 0x40),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_PRE_STALL_LDO_BOOST_EN, 0x30),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_INTERFACE_SELECT, 0x3b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_CLKBUF_ENABLE, 0x0f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_RESET_TSYNC_EN, 0x03),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_TRAN_DRVR_EMP_EN, 0x0f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_INTERFACE_MODE, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX, 0x11),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX, 0x11),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_BAND, 0x4),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_POL_INV, 0x0a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_DRV_LVL, 0x2a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_EMP_POST1_LVL, 0x20),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl sm8250_qmp_pcie_serdes_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34),
|
||||
@ -2268,6 +2348,8 @@ static const struct qmp_phy_init_tbl sm8350_usb3_uniphy_pcs_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21),
|
||||
};
|
||||
|
||||
struct qmp_phy;
|
||||
|
||||
/* struct qmp_phy_cfg - per-PHY initialization config */
|
||||
struct qmp_phy_cfg {
|
||||
/* phy-type - PCIE/UFS/USB */
|
||||
@ -2307,6 +2389,12 @@ struct qmp_phy_cfg {
|
||||
const struct qmp_phy_init_tbl *serdes_tbl_hbr3;
|
||||
int serdes_tbl_hbr3_num;
|
||||
|
||||
/* DP PHY callbacks */
|
||||
int (*configure_dp_phy)(struct qmp_phy *qphy);
|
||||
void (*configure_dp_tx)(struct qmp_phy *qphy);
|
||||
int (*calibrate_dp_phy)(struct qmp_phy *qphy);
|
||||
void (*dp_aux_init)(struct qmp_phy *qphy);
|
||||
|
||||
/* clock ids to be requested */
|
||||
const char * const *clk_list;
|
||||
int num_clks;
|
||||
@ -2423,6 +2511,16 @@ struct qcom_qmp {
|
||||
struct reset_control *ufs_reset;
|
||||
};
|
||||
|
||||
static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy);
|
||||
static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy);
|
||||
static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy);
|
||||
static int qcom_qmp_v3_dp_phy_calibrate(struct qmp_phy *qphy);
|
||||
|
||||
static void qcom_qmp_v4_phy_dp_aux_init(struct qmp_phy *qphy);
|
||||
static void qcom_qmp_v4_phy_configure_dp_tx(struct qmp_phy *qphy);
|
||||
static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy);
|
||||
static int qcom_qmp_v4_dp_phy_calibrate(struct qmp_phy *qphy);
|
||||
|
||||
static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
|
||||
{
|
||||
u32 reg;
|
||||
@ -2871,6 +2969,11 @@ static const struct qmp_phy_cfg sc7180_dpphy_cfg = {
|
||||
|
||||
.has_phy_dp_com_ctrl = true,
|
||||
.is_dual_lane_phy = true,
|
||||
|
||||
.dp_aux_init = qcom_qmp_v3_phy_dp_aux_init,
|
||||
.configure_dp_tx = qcom_qmp_v3_phy_configure_dp_tx,
|
||||
.configure_dp_phy = qcom_qmp_v3_phy_configure_dp_phy,
|
||||
.calibrate_dp_phy = qcom_qmp_v3_dp_phy_calibrate,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_combo_cfg sc7180_usb3dpphy_cfg = {
|
||||
@ -3123,6 +3226,46 @@ static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = {
|
||||
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg sm8250_dpphy_cfg = {
|
||||
.type = PHY_TYPE_DP,
|
||||
.nlanes = 1,
|
||||
|
||||
.serdes_tbl = qmp_v4_dp_serdes_tbl,
|
||||
.serdes_tbl_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl),
|
||||
.tx_tbl = qmp_v4_dp_tx_tbl,
|
||||
.tx_tbl_num = ARRAY_SIZE(qmp_v4_dp_tx_tbl),
|
||||
|
||||
.serdes_tbl_rbr = qmp_v4_dp_serdes_tbl_rbr,
|
||||
.serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_rbr),
|
||||
.serdes_tbl_hbr = qmp_v4_dp_serdes_tbl_hbr,
|
||||
.serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr),
|
||||
.serdes_tbl_hbr2 = qmp_v4_dp_serdes_tbl_hbr2,
|
||||
.serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr2),
|
||||
.serdes_tbl_hbr3 = qmp_v4_dp_serdes_tbl_hbr3,
|
||||
.serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr3),
|
||||
|
||||
.clk_list = qmp_v4_phy_clk_l,
|
||||
.num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l),
|
||||
.reset_list = msm8996_usb3phy_reset_l,
|
||||
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
|
||||
.vreg_list = qmp_phy_vreg_l,
|
||||
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||
.regs = qmp_v4_usb3phy_regs_layout,
|
||||
|
||||
.has_phy_dp_com_ctrl = true,
|
||||
.is_dual_lane_phy = true,
|
||||
|
||||
.dp_aux_init = qcom_qmp_v4_phy_dp_aux_init,
|
||||
.configure_dp_tx = qcom_qmp_v4_phy_configure_dp_tx,
|
||||
.configure_dp_phy = qcom_qmp_v4_phy_configure_dp_phy,
|
||||
.calibrate_dp_phy = qcom_qmp_v4_dp_phy_calibrate,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_combo_cfg sm8250_usb3dpphy_cfg = {
|
||||
.usb_cfg = &sm8250_usb3phy_cfg,
|
||||
.dp_cfg = &sm8250_dpphy_cfg,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = {
|
||||
.type = PHY_TYPE_USB3,
|
||||
.nlanes = 1,
|
||||
@ -3332,24 +3475,24 @@ static int qcom_qmp_phy_serdes_init(struct qmp_phy *qphy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_qmp_phy_dp_aux_init(struct qmp_phy *qphy)
|
||||
static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy)
|
||||
{
|
||||
writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
|
||||
DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
|
||||
qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL);
|
||||
qphy->pcs + QSERDES_DP_PHY_PD_CTL);
|
||||
|
||||
/* Turn on BIAS current for PHY/PLL */
|
||||
writel(QSERDES_V3_COM_BIAS_EN | QSERDES_V3_COM_BIAS_EN_MUX |
|
||||
QSERDES_V3_COM_CLKBUF_L_EN | QSERDES_V3_COM_EN_SYSCLK_TX_SEL,
|
||||
qphy->serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN);
|
||||
|
||||
writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL);
|
||||
writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_DP_PHY_PD_CTL);
|
||||
|
||||
writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
|
||||
DP_PHY_PD_CTL_LANE_0_1_PWRDN |
|
||||
DP_PHY_PD_CTL_LANE_2_3_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN |
|
||||
DP_PHY_PD_CTL_DP_CLAMP_EN,
|
||||
qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL);
|
||||
qphy->pcs + QSERDES_DP_PHY_PD_CTL);
|
||||
|
||||
writel(QSERDES_V3_COM_BIAS_EN |
|
||||
QSERDES_V3_COM_BIAS_EN_MUX | QSERDES_V3_COM_CLKBUF_R_EN |
|
||||
@ -3357,16 +3500,16 @@ static void qcom_qmp_phy_dp_aux_init(struct qmp_phy *qphy)
|
||||
QSERDES_V3_COM_CLKBUF_RX_DRIVE_L,
|
||||
qphy->serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN);
|
||||
|
||||
writel(0x00, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG0);
|
||||
writel(0x13, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG1);
|
||||
writel(0x24, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG2);
|
||||
writel(0x00, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG3);
|
||||
writel(0x0a, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG4);
|
||||
writel(0x26, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG5);
|
||||
writel(0x0a, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG6);
|
||||
writel(0x03, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG7);
|
||||
writel(0xbb, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG8);
|
||||
writel(0x03, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG9);
|
||||
writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG0);
|
||||
writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1);
|
||||
writel(0x24, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2);
|
||||
writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG3);
|
||||
writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG4);
|
||||
writel(0x26, qphy->pcs + QSERDES_DP_PHY_AUX_CFG5);
|
||||
writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG6);
|
||||
writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG7);
|
||||
writel(0xbb, qphy->pcs + QSERDES_DP_PHY_AUX_CFG8);
|
||||
writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG9);
|
||||
qphy->dp_aux_cfg = 0;
|
||||
|
||||
writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK |
|
||||
@ -3375,6 +3518,20 @@ static void qcom_qmp_phy_dp_aux_init(struct qmp_phy *qphy)
|
||||
qphy->pcs + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK);
|
||||
}
|
||||
|
||||
static const u8 qmp_dp_v3_pre_emphasis_hbr3_hbr2[4][4] = {
|
||||
{ 0x00, 0x0c, 0x15, 0x1a },
|
||||
{ 0x02, 0x0e, 0x16, 0xff },
|
||||
{ 0x02, 0x11, 0xff, 0xff },
|
||||
{ 0x04, 0xff, 0xff, 0xff }
|
||||
};
|
||||
|
||||
static const u8 qmp_dp_v3_voltage_swing_hbr3_hbr2[4][4] = {
|
||||
{ 0x02, 0x12, 0x16, 0x1a },
|
||||
{ 0x09, 0x19, 0x1f, 0xff },
|
||||
{ 0x10, 0x1f, 0xff, 0xff },
|
||||
{ 0x1f, 0xff, 0xff, 0xff }
|
||||
};
|
||||
|
||||
static const u8 qmp_dp_v3_pre_emphasis_hbr_rbr[4][4] = {
|
||||
{ 0x00, 0x0c, 0x14, 0x19 },
|
||||
{ 0x00, 0x0b, 0x12, 0xff },
|
||||
@ -3389,11 +3546,11 @@ static const u8 qmp_dp_v3_voltage_swing_hbr_rbr[4][4] = {
|
||||
{ 0x1f, 0xff, 0xff, 0xff }
|
||||
};
|
||||
|
||||
static void qcom_qmp_phy_configure_dp_tx(struct qmp_phy *qphy)
|
||||
static int qcom_qmp_phy_configure_dp_swing(struct qmp_phy *qphy,
|
||||
unsigned int drv_lvl_reg, unsigned int emp_post_reg)
|
||||
{
|
||||
const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
|
||||
unsigned int v_level = 0, p_level = 0;
|
||||
u32 bias_en, drvr_en;
|
||||
u8 voltage_swing_cfg, pre_emphasis_cfg;
|
||||
int i;
|
||||
|
||||
@ -3402,6 +3559,40 @@ static void qcom_qmp_phy_configure_dp_tx(struct qmp_phy *qphy)
|
||||
p_level = max(p_level, dp_opts->pre[i]);
|
||||
}
|
||||
|
||||
if (dp_opts->link_rate <= 2700) {
|
||||
voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr_rbr[v_level][p_level];
|
||||
pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr_rbr[v_level][p_level];
|
||||
} else {
|
||||
voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr3_hbr2[v_level][p_level];
|
||||
pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr3_hbr2[v_level][p_level];
|
||||
}
|
||||
|
||||
/* TODO: Move check to config check */
|
||||
if (voltage_swing_cfg == 0xFF && pre_emphasis_cfg == 0xFF)
|
||||
return -EINVAL;
|
||||
|
||||
/* Enable MUX to use Cursor values from these registers */
|
||||
voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN;
|
||||
pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN;
|
||||
|
||||
writel(voltage_swing_cfg, qphy->tx + drv_lvl_reg);
|
||||
writel(pre_emphasis_cfg, qphy->tx + emp_post_reg);
|
||||
writel(voltage_swing_cfg, qphy->tx2 + drv_lvl_reg);
|
||||
writel(pre_emphasis_cfg, qphy->tx2 + emp_post_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy)
|
||||
{
|
||||
const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
|
||||
u32 bias_en, drvr_en;
|
||||
|
||||
if (qcom_qmp_phy_configure_dp_swing(qphy,
|
||||
QSERDES_V3_TX_TX_DRV_LVL,
|
||||
QSERDES_V3_TX_TX_EMP_POST1_LVL) < 0)
|
||||
return;
|
||||
|
||||
if (dp_opts->lanes == 1) {
|
||||
bias_en = 0x3e;
|
||||
drvr_en = 0x13;
|
||||
@ -3410,48 +3601,16 @@ static void qcom_qmp_phy_configure_dp_tx(struct qmp_phy *qphy)
|
||||
drvr_en = 0x10;
|
||||
}
|
||||
|
||||
voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr_rbr[v_level][p_level];
|
||||
pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr_rbr[v_level][p_level];
|
||||
|
||||
/* TODO: Move check to config check */
|
||||
if (voltage_swing_cfg == 0xFF && pre_emphasis_cfg == 0xFF)
|
||||
return;
|
||||
|
||||
/* Enable MUX to use Cursor values from these registers */
|
||||
voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN;
|
||||
pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN;
|
||||
|
||||
writel(voltage_swing_cfg, qphy->tx + QSERDES_V3_TX_TX_DRV_LVL);
|
||||
writel(pre_emphasis_cfg, qphy->tx + QSERDES_V3_TX_TX_EMP_POST1_LVL);
|
||||
writel(voltage_swing_cfg, qphy->tx2 + QSERDES_V3_TX_TX_DRV_LVL);
|
||||
writel(pre_emphasis_cfg, qphy->tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL);
|
||||
|
||||
writel(drvr_en, qphy->tx + QSERDES_V3_TX_HIGHZ_DRVR_EN);
|
||||
writel(bias_en, qphy->tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
|
||||
writel(drvr_en, qphy->tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN);
|
||||
writel(bias_en, qphy->tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN);
|
||||
}
|
||||
|
||||
static int qcom_qmp_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts)
|
||||
static bool qcom_qmp_phy_configure_dp_mode(struct qmp_phy *qphy)
|
||||
{
|
||||
const struct phy_configure_opts_dp *dp_opts = &opts->dp;
|
||||
struct qmp_phy *qphy = phy_get_drvdata(phy);
|
||||
|
||||
memcpy(&qphy->dp_opts, dp_opts, sizeof(*dp_opts));
|
||||
if (qphy->dp_opts.set_voltages) {
|
||||
qcom_qmp_phy_configure_dp_tx(qphy);
|
||||
qphy->dp_opts.set_voltages = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy)
|
||||
{
|
||||
const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks;
|
||||
const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
|
||||
u32 val, phy_vco_div, status;
|
||||
unsigned long pixel_freq;
|
||||
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;
|
||||
@ -3471,9 +3630,22 @@ static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy)
|
||||
* writel(0x4c, qphy->pcs + QSERDES_V3_DP_PHY_MODE);
|
||||
*/
|
||||
val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
|
||||
writel(val, qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL);
|
||||
writel(val, qphy->pcs + QSERDES_DP_PHY_PD_CTL);
|
||||
|
||||
writel(0x5c, qphy->pcs + QSERDES_DP_PHY_MODE);
|
||||
|
||||
return reverse;
|
||||
}
|
||||
|
||||
static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy)
|
||||
{
|
||||
const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks;
|
||||
const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
|
||||
u32 phy_vco_div, status;
|
||||
unsigned long pixel_freq;
|
||||
|
||||
qcom_qmp_phy_configure_dp_mode(qphy);
|
||||
|
||||
writel(0x5c, qphy->pcs + QSERDES_V3_DP_PHY_MODE);
|
||||
writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL);
|
||||
writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL);
|
||||
|
||||
@ -3503,11 +3675,11 @@ static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy)
|
||||
clk_set_rate(dp_clks->dp_link_hw.clk, dp_opts->link_rate * 100000);
|
||||
clk_set_rate(dp_clks->dp_pixel_hw.clk, pixel_freq);
|
||||
|
||||
writel(0x04, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG2);
|
||||
writel(0x01, qphy->pcs + QSERDES_V3_DP_PHY_CFG);
|
||||
writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_CFG);
|
||||
writel(0x01, qphy->pcs + QSERDES_V3_DP_PHY_CFG);
|
||||
writel(0x09, qphy->pcs + QSERDES_V3_DP_PHY_CFG);
|
||||
writel(0x04, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2);
|
||||
writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
writel(0x05, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
writel(0x09, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
|
||||
writel(0x20, qphy->serdes + QSERDES_V3_COM_RESETSM_CNTRL);
|
||||
|
||||
@ -3518,7 +3690,7 @@ static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy)
|
||||
10000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
writel(0x19, qphy->pcs + QSERDES_V3_DP_PHY_CFG);
|
||||
writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
|
||||
if (readl_poll_timeout(qphy->pcs + QSERDES_V3_DP_PHY_STATUS,
|
||||
status,
|
||||
@ -3527,9 +3699,9 @@ static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy)
|
||||
10000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
writel(0x18, qphy->pcs + QSERDES_V3_DP_PHY_CFG);
|
||||
writel(0x18, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
udelay(2000);
|
||||
writel(0x19, qphy->pcs + QSERDES_V3_DP_PHY_CFG);
|
||||
writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
|
||||
return readl_poll_timeout(qphy->pcs + QSERDES_V3_DP_PHY_STATUS,
|
||||
status,
|
||||
@ -3542,9 +3714,8 @@ static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy)
|
||||
* We need to calibrate the aux setting here as many times
|
||||
* as the caller tries
|
||||
*/
|
||||
static int qcom_qmp_dp_phy_calibrate(struct phy *phy)
|
||||
static int qcom_qmp_v3_dp_phy_calibrate(struct qmp_phy *qphy)
|
||||
{
|
||||
struct qmp_phy *qphy = phy_get_drvdata(phy);
|
||||
static const u8 cfg1_settings[] = { 0x13, 0x23, 0x1d };
|
||||
u8 val;
|
||||
|
||||
@ -3552,7 +3723,231 @@ static int qcom_qmp_dp_phy_calibrate(struct phy *phy)
|
||||
qphy->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
|
||||
val = cfg1_settings[qphy->dp_aux_cfg];
|
||||
|
||||
writel(val, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG1);
|
||||
writel(val, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_qmp_v4_phy_dp_aux_init(struct qmp_phy *qphy)
|
||||
{
|
||||
writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_PSR_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
|
||||
DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
|
||||
qphy->pcs + QSERDES_DP_PHY_PD_CTL);
|
||||
|
||||
/* Turn on BIAS current for PHY/PLL */
|
||||
writel(0x17, qphy->serdes + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN);
|
||||
|
||||
writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG0);
|
||||
writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1);
|
||||
writel(0xa4, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2);
|
||||
writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG3);
|
||||
writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG4);
|
||||
writel(0x26, qphy->pcs + QSERDES_DP_PHY_AUX_CFG5);
|
||||
writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG6);
|
||||
writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG7);
|
||||
writel(0xb7, qphy->pcs + QSERDES_DP_PHY_AUX_CFG8);
|
||||
writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG9);
|
||||
qphy->dp_aux_cfg = 0;
|
||||
|
||||
writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK |
|
||||
PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
|
||||
PHY_AUX_REQ_ERR_MASK,
|
||||
qphy->pcs + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK);
|
||||
}
|
||||
|
||||
static void qcom_qmp_v4_phy_configure_dp_tx(struct qmp_phy *qphy)
|
||||
{
|
||||
/* Program default values before writing proper values */
|
||||
writel(0x27, qphy->tx + QSERDES_V4_TX_TX_DRV_LVL);
|
||||
writel(0x27, qphy->tx2 + QSERDES_V4_TX_TX_DRV_LVL);
|
||||
|
||||
writel(0x20, qphy->tx + QSERDES_V4_TX_TX_EMP_POST1_LVL);
|
||||
writel(0x20, qphy->tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL);
|
||||
|
||||
qcom_qmp_phy_configure_dp_swing(qphy,
|
||||
QSERDES_V4_TX_TX_DRV_LVL,
|
||||
QSERDES_V4_TX_TX_EMP_POST1_LVL);
|
||||
}
|
||||
|
||||
static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy)
|
||||
{
|
||||
const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks;
|
||||
const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
|
||||
u32 phy_vco_div, status;
|
||||
unsigned long pixel_freq;
|
||||
u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
|
||||
bool reverse;
|
||||
|
||||
writel(0x0f, qphy->pcs + QSERDES_V4_DP_PHY_CFG_1);
|
||||
|
||||
reverse = qcom_qmp_phy_configure_dp_mode(qphy);
|
||||
|
||||
writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1);
|
||||
writel(0xa4, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2);
|
||||
|
||||
writel(0x05, qphy->pcs + QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL);
|
||||
writel(0x05, qphy->pcs + QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL);
|
||||
|
||||
switch (dp_opts->link_rate) {
|
||||
case 1620:
|
||||
phy_vco_div = 0x1;
|
||||
pixel_freq = 1620000000UL / 2;
|
||||
break;
|
||||
case 2700:
|
||||
phy_vco_div = 0x1;
|
||||
pixel_freq = 2700000000UL / 2;
|
||||
break;
|
||||
case 5400:
|
||||
phy_vco_div = 0x2;
|
||||
pixel_freq = 5400000000UL / 4;
|
||||
break;
|
||||
case 8100:
|
||||
phy_vco_div = 0x0;
|
||||
pixel_freq = 8100000000UL / 6;
|
||||
break;
|
||||
default:
|
||||
/* Other link rates aren't supported */
|
||||
return -EINVAL;
|
||||
}
|
||||
writel(phy_vco_div, qphy->pcs + QSERDES_V4_DP_PHY_VCO_DIV);
|
||||
|
||||
clk_set_rate(dp_clks->dp_link_hw.clk, dp_opts->link_rate * 100000);
|
||||
clk_set_rate(dp_clks->dp_pixel_hw.clk, pixel_freq);
|
||||
|
||||
writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
writel(0x05, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
writel(0x09, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
|
||||
writel(0x20, qphy->serdes + QSERDES_V4_COM_RESETSM_CNTRL);
|
||||
|
||||
if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_C_READY_STATUS,
|
||||
status,
|
||||
((status & BIT(0)) > 0),
|
||||
500,
|
||||
10000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_CMN_STATUS,
|
||||
status,
|
||||
((status & BIT(0)) > 0),
|
||||
500,
|
||||
10000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_CMN_STATUS,
|
||||
status,
|
||||
((status & BIT(1)) > 0),
|
||||
500,
|
||||
10000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
|
||||
if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS,
|
||||
status,
|
||||
((status & BIT(0)) > 0),
|
||||
500,
|
||||
10000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS,
|
||||
status,
|
||||
((status & BIT(1)) > 0),
|
||||
500,
|
||||
10000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/*
|
||||
* At least for 7nm DP PHY this has to be done after enabling link
|
||||
* clock.
|
||||
*/
|
||||
|
||||
if (dp_opts->lanes == 1) {
|
||||
bias0_en = reverse ? 0x3e : 0x15;
|
||||
bias1_en = reverse ? 0x15 : 0x3e;
|
||||
drvr0_en = reverse ? 0x13 : 0x10;
|
||||
drvr1_en = reverse ? 0x10 : 0x13;
|
||||
} else if (dp_opts->lanes == 2) {
|
||||
bias0_en = reverse ? 0x3f : 0x15;
|
||||
bias1_en = reverse ? 0x15 : 0x3f;
|
||||
drvr0_en = 0x10;
|
||||
drvr1_en = 0x10;
|
||||
} else {
|
||||
bias0_en = 0x3f;
|
||||
bias1_en = 0x3f;
|
||||
drvr0_en = 0x10;
|
||||
drvr1_en = 0x10;
|
||||
}
|
||||
|
||||
writel(drvr0_en, qphy->tx + QSERDES_V4_TX_HIGHZ_DRVR_EN);
|
||||
writel(bias0_en, qphy->tx + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN);
|
||||
writel(drvr1_en, qphy->tx2 + QSERDES_V4_TX_HIGHZ_DRVR_EN);
|
||||
writel(bias1_en, qphy->tx2 + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN);
|
||||
|
||||
writel(0x18, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
udelay(2000);
|
||||
writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG);
|
||||
|
||||
if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS,
|
||||
status,
|
||||
((status & BIT(1)) > 0),
|
||||
500,
|
||||
10000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
writel(0x0a, qphy->tx + QSERDES_V4_TX_TX_POL_INV);
|
||||
writel(0x0a, qphy->tx2 + QSERDES_V4_TX_TX_POL_INV);
|
||||
|
||||
writel(0x27, qphy->tx + QSERDES_V4_TX_TX_DRV_LVL);
|
||||
writel(0x27, qphy->tx2 + QSERDES_V4_TX_TX_DRV_LVL);
|
||||
|
||||
writel(0x20, qphy->tx + QSERDES_V4_TX_TX_EMP_POST1_LVL);
|
||||
writel(0x20, qphy->tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to calibrate the aux setting here as many times
|
||||
* as the caller tries
|
||||
*/
|
||||
static int qcom_qmp_v4_dp_phy_calibrate(struct qmp_phy *qphy)
|
||||
{
|
||||
static const u8 cfg1_settings[] = { 0x20, 0x13, 0x23, 0x1d };
|
||||
u8 val;
|
||||
|
||||
qphy->dp_aux_cfg++;
|
||||
qphy->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
|
||||
val = cfg1_settings[qphy->dp_aux_cfg];
|
||||
|
||||
writel(val, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_qmp_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts)
|
||||
{
|
||||
const struct phy_configure_opts_dp *dp_opts = &opts->dp;
|
||||
struct qmp_phy *qphy = phy_get_drvdata(phy);
|
||||
const struct qmp_phy_cfg *cfg = qphy->cfg;
|
||||
|
||||
memcpy(&qphy->dp_opts, dp_opts, sizeof(*dp_opts));
|
||||
if (qphy->dp_opts.set_voltages) {
|
||||
cfg->configure_dp_tx(qphy);
|
||||
qphy->dp_opts.set_voltages = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_qmp_dp_phy_calibrate(struct phy *phy)
|
||||
{
|
||||
struct qmp_phy *qphy = phy_get_drvdata(phy);
|
||||
const struct qmp_phy_cfg *cfg = qphy->cfg;
|
||||
|
||||
if (cfg->calibrate_dp_phy)
|
||||
return cfg->calibrate_dp_phy(qphy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3729,7 +4124,7 @@ static int qcom_qmp_phy_init(struct phy *phy)
|
||||
return ret;
|
||||
|
||||
if (cfg->type == PHY_TYPE_DP)
|
||||
qcom_qmp_phy_dp_aux_init(qphy);
|
||||
cfg->dp_aux_init(qphy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3783,7 +4178,7 @@ static int qcom_qmp_phy_power_on(struct phy *phy)
|
||||
|
||||
/* Configure special DP tx tunings */
|
||||
if (cfg->type == PHY_TYPE_DP)
|
||||
qcom_qmp_phy_configure_dp_tx(qphy);
|
||||
cfg->configure_dp_tx(qphy);
|
||||
|
||||
qcom_qmp_phy_configure_lane(rx, cfg->regs,
|
||||
cfg->rx_tbl, cfg->rx_tbl_num, 1);
|
||||
@ -3802,7 +4197,7 @@ static int qcom_qmp_phy_power_on(struct phy *phy)
|
||||
|
||||
/* Configure link rate, swing, etc. */
|
||||
if (cfg->type == PHY_TYPE_DP) {
|
||||
qcom_qmp_phy_configure_dp_phy(qphy);
|
||||
cfg->configure_dp_phy(qphy);
|
||||
} else {
|
||||
qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
|
||||
if (cfg->pcs_tbl_sec)
|
||||
@ -3874,7 +4269,7 @@ static int qcom_qmp_phy_power_off(struct phy *phy)
|
||||
|
||||
if (cfg->type == PHY_TYPE_DP) {
|
||||
/* Assert DP PHY power down */
|
||||
writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL);
|
||||
writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_DP_PHY_PD_CTL);
|
||||
} else {
|
||||
/* PHY reset */
|
||||
if (!cfg->no_pcs_sw_reset)
|
||||
@ -4577,6 +4972,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
|
||||
}, {
|
||||
.compatible = "qcom,sm8250-qmp-usb3-phy",
|
||||
.data = &sm8250_usb3phy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sm8250-qmp-usb3-dp-phy",
|
||||
/* It's a combo phy */
|
||||
}, {
|
||||
.compatible = "qcom,sm8250-qmp-usb3-uni-phy",
|
||||
.data = &sm8250_usb3_uniphy_cfg,
|
||||
@ -4611,6 +5009,10 @@ static const struct of_device_id qcom_qmp_combo_phy_of_match_table[] = {
|
||||
.compatible = "qcom,sc7180-qmp-usb3-dp-phy",
|
||||
.data = &sc7180_usb3dpphy_cfg,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,sm8250-qmp-usb3-dp-phy",
|
||||
.data = &sm8250_usb3dpphy_cfg,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -349,13 +349,13 @@
|
||||
#define QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG4 0x5c
|
||||
#define QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG5 0x60
|
||||
|
||||
/* Only for QMP V3 PHY - DP PHY registers */
|
||||
#define QSERDES_V3_DP_PHY_REVISION_ID0 0x000
|
||||
#define QSERDES_V3_DP_PHY_REVISION_ID1 0x004
|
||||
#define QSERDES_V3_DP_PHY_REVISION_ID2 0x008
|
||||
#define QSERDES_V3_DP_PHY_REVISION_ID3 0x00c
|
||||
#define QSERDES_V3_DP_PHY_CFG 0x010
|
||||
#define QSERDES_V3_DP_PHY_PD_CTL 0x018
|
||||
/* QMP PHY - DP PHY registers */
|
||||
#define QSERDES_DP_PHY_REVISION_ID0 0x000
|
||||
#define QSERDES_DP_PHY_REVISION_ID1 0x004
|
||||
#define QSERDES_DP_PHY_REVISION_ID2 0x008
|
||||
#define QSERDES_DP_PHY_REVISION_ID3 0x00c
|
||||
#define QSERDES_DP_PHY_CFG 0x010
|
||||
#define QSERDES_DP_PHY_PD_CTL 0x018
|
||||
# define DP_PHY_PD_CTL_PWRDN 0x001
|
||||
# define DP_PHY_PD_CTL_PSR_PWRDN 0x002
|
||||
# define DP_PHY_PD_CTL_AUX_PWRDN 0x004
|
||||
@ -363,18 +363,19 @@
|
||||
# define DP_PHY_PD_CTL_LANE_2_3_PWRDN 0x010
|
||||
# define DP_PHY_PD_CTL_PLL_PWRDN 0x020
|
||||
# define DP_PHY_PD_CTL_DP_CLAMP_EN 0x040
|
||||
#define QSERDES_V3_DP_PHY_MODE 0x01c
|
||||
#define QSERDES_V3_DP_PHY_AUX_CFG0 0x020
|
||||
#define QSERDES_V3_DP_PHY_AUX_CFG1 0x024
|
||||
#define QSERDES_V3_DP_PHY_AUX_CFG2 0x028
|
||||
#define QSERDES_V3_DP_PHY_AUX_CFG3 0x02c
|
||||
#define QSERDES_V3_DP_PHY_AUX_CFG4 0x030
|
||||
#define QSERDES_V3_DP_PHY_AUX_CFG5 0x034
|
||||
#define QSERDES_V3_DP_PHY_AUX_CFG6 0x038
|
||||
#define QSERDES_V3_DP_PHY_AUX_CFG7 0x03c
|
||||
#define QSERDES_V3_DP_PHY_AUX_CFG8 0x040
|
||||
#define QSERDES_V3_DP_PHY_AUX_CFG9 0x044
|
||||
#define QSERDES_DP_PHY_MODE 0x01c
|
||||
#define QSERDES_DP_PHY_AUX_CFG0 0x020
|
||||
#define QSERDES_DP_PHY_AUX_CFG1 0x024
|
||||
#define QSERDES_DP_PHY_AUX_CFG2 0x028
|
||||
#define QSERDES_DP_PHY_AUX_CFG3 0x02c
|
||||
#define QSERDES_DP_PHY_AUX_CFG4 0x030
|
||||
#define QSERDES_DP_PHY_AUX_CFG5 0x034
|
||||
#define QSERDES_DP_PHY_AUX_CFG6 0x038
|
||||
#define QSERDES_DP_PHY_AUX_CFG7 0x03c
|
||||
#define QSERDES_DP_PHY_AUX_CFG8 0x040
|
||||
#define QSERDES_DP_PHY_AUX_CFG9 0x044
|
||||
|
||||
/* Only for QMP V3 PHY - DP PHY registers */
|
||||
#define QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK 0x048
|
||||
# define PHY_AUX_STOP_ERR_MASK 0x01
|
||||
# define PHY_AUX_DEC_ERR_MASK 0x02
|
||||
@ -396,6 +397,7 @@
|
||||
#define QSERDES_V3_DP_PHY_STATUS 0x0c0
|
||||
|
||||
/* Only for QMP V4 PHY - QSERDES COM registers */
|
||||
#define QSERDES_V4_COM_BG_TIMER 0x00c
|
||||
#define QSERDES_V4_COM_SSC_EN_CENTER 0x010
|
||||
#define QSERDES_V4_COM_SSC_PER1 0x01c
|
||||
#define QSERDES_V4_COM_SSC_PER2 0x020
|
||||
@ -403,7 +405,9 @@
|
||||
#define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0 0x028
|
||||
#define QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1 0x030
|
||||
#define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1 0x034
|
||||
#define QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN 0x044
|
||||
#define QSERDES_V4_COM_CLK_ENABLE1 0x048
|
||||
#define QSERDES_V4_COM_SYS_CLK_CTRL 0x04c
|
||||
#define QSERDES_V4_COM_SYSCLK_BUF_ENABLE 0x050
|
||||
#define QSERDES_V4_COM_PLL_IVCO 0x058
|
||||
#define QSERDES_V4_COM_CMN_IPTRIM 0x060
|
||||
@ -414,6 +418,7 @@
|
||||
#define QSERDES_V4_COM_PLL_CCTRL_MODE0 0x084
|
||||
#define QSERDES_V4_COM_PLL_CCTRL_MODE1 0x088
|
||||
#define QSERDES_V4_COM_SYSCLK_EN_SEL 0x094
|
||||
#define QSERDES_V4_COM_RESETSM_CNTRL 0x09c
|
||||
#define QSERDES_V4_COM_LOCK_CMP_EN 0x0a4
|
||||
#define QSERDES_V4_COM_LOCK_CMP1_MODE0 0x0ac
|
||||
#define QSERDES_V4_COM_LOCK_CMP2_MODE0 0x0b0
|
||||
@ -427,16 +432,24 @@
|
||||
#define QSERDES_V4_COM_DIV_FRAC_START1_MODE1 0x0d8
|
||||
#define QSERDES_V4_COM_DIV_FRAC_START2_MODE1 0x0dc
|
||||
#define QSERDES_V4_COM_DIV_FRAC_START3_MODE1 0x0e0
|
||||
#define QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0 0x0ec
|
||||
#define QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0 0x0f0
|
||||
#define QSERDES_V4_COM_VCO_TUNE_CTRL 0x108
|
||||
#define QSERDES_V4_COM_VCO_TUNE_MAP 0x10c
|
||||
#define QSERDES_V4_COM_VCO_TUNE1_MODE0 0x110
|
||||
#define QSERDES_V4_COM_VCO_TUNE2_MODE0 0x114
|
||||
#define QSERDES_V4_COM_VCO_TUNE1_MODE1 0x118
|
||||
#define QSERDES_V4_COM_VCO_TUNE2_MODE1 0x11c
|
||||
#define QSERDES_V4_COM_VCO_TUNE_INITVAL2 0x124
|
||||
#define QSERDES_V4_COM_CMN_STATUS 0x140
|
||||
#define QSERDES_V4_COM_CLK_SELECT 0x154
|
||||
#define QSERDES_V4_COM_HSCLK_SEL 0x158
|
||||
#define QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL 0x15c
|
||||
#define QSERDES_V4_COM_CORECLK_DIV_MODE0 0x168
|
||||
#define QSERDES_V4_COM_CORECLK_DIV_MODE1 0x16c
|
||||
#define QSERDES_V4_COM_CORE_CLK_EN 0x174
|
||||
#define QSERDES_V4_COM_C_READY_STATUS 0x178
|
||||
#define QSERDES_V4_COM_CMN_CONFIG 0x17c
|
||||
#define QSERDES_V4_COM_SVS_MODE_CLK_SEL 0x184
|
||||
#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x1ac
|
||||
#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x1b0
|
||||
@ -445,19 +458,32 @@
|
||||
#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1 0x1b8
|
||||
|
||||
/* Only for QMP V4 PHY - TX registers */
|
||||
#define QSERDES_V4_TX_CLKBUF_ENABLE 0x08
|
||||
#define QSERDES_V4_TX_TX_EMP_POST1_LVL 0x0c
|
||||
#define QSERDES_V4_TX_TX_DRV_LVL 0x14
|
||||
#define QSERDES_V4_TX_RESET_TSYNC_EN 0x1c
|
||||
#define QSERDES_V4_TX_PRE_STALL_LDO_BOOST_EN 0x20
|
||||
#define QSERDES_V4_TX_TX_BAND 0x24
|
||||
#define QSERDES_V4_TX_INTERFACE_SELECT 0x2c
|
||||
#define QSERDES_V4_TX_RES_CODE_LANE_TX 0x34
|
||||
#define QSERDES_V4_TX_RES_CODE_LANE_RX 0x38
|
||||
#define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX 0x3c
|
||||
#define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX 0x40
|
||||
#define QSERDES_V4_TX_TRANSCEIVER_BIAS_EN 0x54
|
||||
#define QSERDES_V4_TX_HIGHZ_DRVR_EN 0x58
|
||||
#define QSERDES_V4_TX_TX_POL_INV 0x5c
|
||||
#define QSERDES_V4_TX_PARRATE_REC_DETECT_IDLE_EN 0x60
|
||||
#define QSERDES_V4_TX_LANE_MODE_1 0x84
|
||||
#define QSERDES_V4_TX_LANE_MODE_2 0x88
|
||||
#define QSERDES_V4_TX_RCV_DETECT_LVL_2 0x9c
|
||||
#define QSERDES_V4_TX_TRAN_DRVR_EMP_EN 0xb8
|
||||
#define QSERDES_V4_TX_TX_INTERFACE_MODE 0xbc
|
||||
#define QSERDES_V4_TX_PWM_GEAR_1_DIVIDER_BAND0_1 0xd8
|
||||
#define QSERDES_V4_TX_PWM_GEAR_2_DIVIDER_BAND0_1 0xdC
|
||||
#define QSERDES_V4_TX_PWM_GEAR_3_DIVIDER_BAND0_1 0xe0
|
||||
#define QSERDES_V4_TX_PWM_GEAR_4_DIVIDER_BAND0_1 0xe4
|
||||
#define QSERDES_V4_TX_TRAN_DRVR_EMP_EN 0xb8
|
||||
#define QSERDES_V4_TX_PI_QEC_CTRL 0x104
|
||||
#define QSERDES_V4_TX_VMODE_CTRL1 0xe8
|
||||
#define QSERDES_V4_TX_PI_QEC_CTRL 0x104
|
||||
|
||||
/* Only for QMP V4 PHY - RX registers */
|
||||
#define QSERDES_V4_RX_UCDR_FO_GAIN 0x008
|
||||
@ -514,6 +540,17 @@
|
||||
#define QSERDES_V4_RX_DCC_CTRL1 0x1bc
|
||||
#define QSERDES_V4_RX_VTH_CODE 0x1c4
|
||||
|
||||
/* Only for QMP V4 PHY - DP PHY registers */
|
||||
#define QSERDES_V4_DP_PHY_CFG_1 0x014
|
||||
#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK 0x054
|
||||
#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_CLEAR 0x058
|
||||
#define QSERDES_V4_DP_PHY_VCO_DIV 0x070
|
||||
#define QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL 0x078
|
||||
#define QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL 0x09c
|
||||
#define QSERDES_V4_DP_PHY_SPARE0 0x0c8
|
||||
#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_STATUS 0x0d8
|
||||
#define QSERDES_V4_DP_PHY_STATUS 0x0dc
|
||||
|
||||
/* Only for QMP V4 PHY - UFS PCS registers */
|
||||
#define QPHY_V4_PCS_UFS_PHY_START 0x000
|
||||
#define QPHY_V4_PCS_UFS_POWER_DOWN_CONTROL 0x004
|
||||
|
@ -56,6 +56,7 @@ static int qcom_usb_hs_phy_set_mode(struct phy *phy,
|
||||
fallthrough;
|
||||
case PHY_MODE_USB_DEVICE:
|
||||
val |= ULPI_INT_SESS_VALID;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@
|
||||
|
||||
#define RG_PE1_FRC_MSTCKDIV BIT(5)
|
||||
|
||||
#define XTAL_MASK GENMASK(7, 6)
|
||||
#define XTAL_MASK GENMASK(8, 6)
|
||||
|
||||
#define MAX_PHYS 2
|
||||
|
||||
@ -319,9 +319,9 @@ static int mt7621_pci_phy_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(phy->regmap);
|
||||
|
||||
phy->phy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
if (IS_ERR(phy->phy)) {
|
||||
dev_err(dev, "failed to create phy\n");
|
||||
return PTR_ERR(phy);
|
||||
return PTR_ERR(phy->phy);
|
||||
}
|
||||
|
||||
phy_set_drvdata(phy->phy, phy);
|
||||
|
@ -1180,6 +1180,7 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
|
||||
dev_err(dev, "failed to create phy: %pOFn\n",
|
||||
child_np);
|
||||
pm_runtime_disable(dev);
|
||||
of_node_put(child_np);
|
||||
return PTR_ERR(phy);
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ config PHY_STIH407_USB
|
||||
config PHY_STM32_USBPHYC
|
||||
tristate "STMicroelectronics STM32 USB HS PHY Controller driver"
|
||||
depends on ARCH_STM32 || COMPILE_TEST
|
||||
depends on COMMON_CLK
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the High-Speed USB transceivers that are part
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -70,6 +71,7 @@ struct stm32_usbphyc {
|
||||
struct regulator *vdda1v1;
|
||||
struct regulator *vdda1v8;
|
||||
atomic_t n_pll_cons;
|
||||
struct clk_hw clk48_hw;
|
||||
int switch_setup;
|
||||
};
|
||||
|
||||
@ -295,6 +297,61 @@ static const struct phy_ops stm32_usbphyc_phy_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int stm32_usbphyc_clk48_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, clk48_hw);
|
||||
|
||||
return stm32_usbphyc_pll_enable(usbphyc);
|
||||
}
|
||||
|
||||
static void stm32_usbphyc_clk48_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, clk48_hw);
|
||||
|
||||
stm32_usbphyc_pll_disable(usbphyc);
|
||||
}
|
||||
|
||||
static unsigned long stm32_usbphyc_clk48_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
{
|
||||
return 48000000;
|
||||
}
|
||||
|
||||
static const struct clk_ops usbphyc_clk48_ops = {
|
||||
.prepare = stm32_usbphyc_clk48_prepare,
|
||||
.unprepare = stm32_usbphyc_clk48_unprepare,
|
||||
.recalc_rate = stm32_usbphyc_clk48_recalc_rate,
|
||||
};
|
||||
|
||||
static void stm32_usbphyc_clk48_unregister(void *data)
|
||||
{
|
||||
struct stm32_usbphyc *usbphyc = data;
|
||||
|
||||
of_clk_del_provider(usbphyc->dev->of_node);
|
||||
clk_hw_unregister(&usbphyc->clk48_hw);
|
||||
}
|
||||
|
||||
static int stm32_usbphyc_clk48_register(struct stm32_usbphyc *usbphyc)
|
||||
{
|
||||
struct device_node *node = usbphyc->dev->of_node;
|
||||
struct clk_init_data init = { };
|
||||
int ret = 0;
|
||||
|
||||
init.name = "ck_usbo_48m";
|
||||
init.ops = &usbphyc_clk48_ops;
|
||||
|
||||
usbphyc->clk48_hw.init = &init;
|
||||
|
||||
ret = clk_hw_register(usbphyc->dev, &usbphyc->clk48_hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &usbphyc->clk48_hw);
|
||||
if (ret)
|
||||
clk_hw_unregister(&usbphyc->clk48_hw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc,
|
||||
u32 utmi_switch)
|
||||
{
|
||||
@ -473,6 +530,12 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
ret = stm32_usbphyc_clk48_register(usbphyc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register ck_usbo_48m clock: %d\n", ret);
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION);
|
||||
dev_info(dev, "registered rev:%lu.%lu\n",
|
||||
FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version));
|
||||
@ -497,6 +560,8 @@ static int stm32_usbphyc_remove(struct platform_device *pdev)
|
||||
if (usbphyc->phys[port]->active)
|
||||
stm32_usbphyc_phy_exit(usbphyc->phys[port]->phy);
|
||||
|
||||
stm32_usbphyc_clk48_unregister(usbphyc);
|
||||
|
||||
clk_disable_unprepare(usbphyc->clk);
|
||||
|
||||
return 0;
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
#include <dt-bindings/phy/phy-ti.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/gpio.h>
|
||||
@ -26,6 +27,11 @@
|
||||
#define WIZ_SERDES_RST 0x40c
|
||||
#define WIZ_SERDES_TYPEC 0x410
|
||||
#define WIZ_LANECTL(n) (0x480 + (0x40 * (n)))
|
||||
#define WIZ_LANEDIV(n) (0x484 + (0x40 * (n)))
|
||||
|
||||
#define WIZ_MAX_INPUT_CLOCKS 4
|
||||
/* To include mux clocks, divider clocks and gate clocks */
|
||||
#define WIZ_MAX_OUTPUT_CLOCKS 32
|
||||
|
||||
#define WIZ_MAX_LANES 4
|
||||
#define WIZ_MUX_NUM_CLOCKS 3
|
||||
@ -52,8 +58,16 @@ enum wiz_refclk_div_sel {
|
||||
CMN_REFCLK1_DIG_DIV,
|
||||
};
|
||||
|
||||
enum wiz_clock_input {
|
||||
WIZ_CORE_REFCLK,
|
||||
WIZ_EXT_REFCLK,
|
||||
WIZ_CORE_REFCLK1,
|
||||
WIZ_EXT_REFCLK1,
|
||||
};
|
||||
|
||||
static const struct reg_field por_en = REG_FIELD(WIZ_SERDES_CTRL, 31, 31);
|
||||
static const struct reg_field phy_reset_n = REG_FIELD(WIZ_SERDES_RST, 31, 31);
|
||||
static const struct reg_field phy_en_refclk = REG_FIELD(WIZ_SERDES_RST, 30, 30);
|
||||
static const struct reg_field pll1_refclk_mux_sel =
|
||||
REG_FIELD(WIZ_SERDES_RST, 29, 29);
|
||||
static const struct reg_field pll0_refclk_mux_sel =
|
||||
@ -70,6 +84,12 @@ static const struct reg_field pma_cmn_refclk_dig_div =
|
||||
REG_FIELD(WIZ_SERDES_TOP_CTRL, 26, 27);
|
||||
static const struct reg_field pma_cmn_refclk1_dig_div =
|
||||
REG_FIELD(WIZ_SERDES_TOP_CTRL, 24, 25);
|
||||
static const char * const output_clk_names[] = {
|
||||
[TI_WIZ_PLL0_REFCLK] = "pll0-refclk",
|
||||
[TI_WIZ_PLL1_REFCLK] = "pll1-refclk",
|
||||
[TI_WIZ_REFCLK_DIG] = "refclk-dig",
|
||||
[TI_WIZ_PHY_EN_REFCLK] = "phy-en-refclk",
|
||||
};
|
||||
|
||||
static const struct reg_field p_enable[WIZ_MAX_LANES] = {
|
||||
REG_FIELD(WIZ_LANECTL(0), 30, 31),
|
||||
@ -101,13 +121,34 @@ static const struct reg_field p_standard_mode[WIZ_MAX_LANES] = {
|
||||
REG_FIELD(WIZ_LANECTL(3), 24, 25),
|
||||
};
|
||||
|
||||
static const struct reg_field p0_fullrt_div[WIZ_MAX_LANES] = {
|
||||
REG_FIELD(WIZ_LANECTL(0), 22, 23),
|
||||
REG_FIELD(WIZ_LANECTL(1), 22, 23),
|
||||
REG_FIELD(WIZ_LANECTL(2), 22, 23),
|
||||
REG_FIELD(WIZ_LANECTL(3), 22, 23),
|
||||
};
|
||||
|
||||
static const struct reg_field p_mac_div_sel0[WIZ_MAX_LANES] = {
|
||||
REG_FIELD(WIZ_LANEDIV(0), 16, 22),
|
||||
REG_FIELD(WIZ_LANEDIV(1), 16, 22),
|
||||
REG_FIELD(WIZ_LANEDIV(2), 16, 22),
|
||||
REG_FIELD(WIZ_LANEDIV(3), 16, 22),
|
||||
};
|
||||
|
||||
static const struct reg_field p_mac_div_sel1[WIZ_MAX_LANES] = {
|
||||
REG_FIELD(WIZ_LANEDIV(0), 0, 8),
|
||||
REG_FIELD(WIZ_LANEDIV(1), 0, 8),
|
||||
REG_FIELD(WIZ_LANEDIV(2), 0, 8),
|
||||
REG_FIELD(WIZ_LANEDIV(3), 0, 8),
|
||||
};
|
||||
|
||||
static const struct reg_field typec_ln10_swap =
|
||||
REG_FIELD(WIZ_SERDES_TYPEC, 30, 30);
|
||||
|
||||
struct wiz_clk_mux {
|
||||
struct clk_hw hw;
|
||||
struct regmap_field *field;
|
||||
u32 *table;
|
||||
const u32 *table;
|
||||
struct clk_init_data clk_data;
|
||||
};
|
||||
|
||||
@ -123,18 +164,26 @@ struct wiz_clk_divider {
|
||||
#define to_wiz_clk_div(_hw) container_of(_hw, struct wiz_clk_divider, hw)
|
||||
|
||||
struct wiz_clk_mux_sel {
|
||||
struct regmap_field *field;
|
||||
u32 table[4];
|
||||
u32 table[WIZ_MAX_INPUT_CLOCKS];
|
||||
const char *node_name;
|
||||
u32 num_parents;
|
||||
u32 parents[WIZ_MAX_INPUT_CLOCKS];
|
||||
};
|
||||
|
||||
struct wiz_clk_div_sel {
|
||||
struct regmap_field *field;
|
||||
const struct clk_div_table *table;
|
||||
const struct clk_div_table *table;
|
||||
const char *node_name;
|
||||
};
|
||||
|
||||
static struct wiz_clk_mux_sel clk_mux_sel_16g[] = {
|
||||
struct wiz_phy_en_refclk {
|
||||
struct clk_hw hw;
|
||||
struct regmap_field *phy_en_refclk;
|
||||
struct clk_init_data clk_data;
|
||||
};
|
||||
|
||||
#define to_wiz_phy_en_refclk(_hw) container_of(_hw, struct wiz_phy_en_refclk, hw)
|
||||
|
||||
static const struct wiz_clk_mux_sel clk_mux_sel_16g[] = {
|
||||
{
|
||||
/*
|
||||
* Mux value to be configured for each of the input clocks
|
||||
@ -153,20 +202,26 @@ static struct wiz_clk_mux_sel clk_mux_sel_16g[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct wiz_clk_mux_sel clk_mux_sel_10g[] = {
|
||||
static const struct wiz_clk_mux_sel clk_mux_sel_10g[] = {
|
||||
{
|
||||
/*
|
||||
* Mux value to be configured for each of the input clocks
|
||||
* in the order populated in device tree
|
||||
*/
|
||||
.num_parents = 2,
|
||||
.parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK },
|
||||
.table = { 1, 0 },
|
||||
.node_name = "pll0-refclk",
|
||||
},
|
||||
{
|
||||
.num_parents = 2,
|
||||
.parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK },
|
||||
.table = { 1, 0 },
|
||||
.node_name = "pll1-refclk",
|
||||
},
|
||||
{
|
||||
.num_parents = 2,
|
||||
.parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK },
|
||||
.table = { 1, 0 },
|
||||
.node_name = "refclk-dig",
|
||||
},
|
||||
@ -179,7 +234,7 @@ static const struct clk_div_table clk_div_table[] = {
|
||||
{ .val = 3, .div = 8, },
|
||||
};
|
||||
|
||||
static struct wiz_clk_div_sel clk_div_sel[] = {
|
||||
static const struct wiz_clk_div_sel clk_div_sel[] = {
|
||||
{
|
||||
.table = clk_div_table,
|
||||
.node_name = "cmn-refclk-dig-div",
|
||||
@ -193,6 +248,7 @@ static struct wiz_clk_div_sel clk_div_sel[] = {
|
||||
enum wiz_type {
|
||||
J721E_WIZ_16G,
|
||||
J721E_WIZ_10G,
|
||||
AM64_WIZ_10G,
|
||||
};
|
||||
|
||||
#define WIZ_TYPEC_DIR_DEBOUNCE_MIN 100 /* ms */
|
||||
@ -201,19 +257,25 @@ enum wiz_type {
|
||||
struct wiz {
|
||||
struct regmap *regmap;
|
||||
enum wiz_type type;
|
||||
struct wiz_clk_mux_sel *clk_mux_sel;
|
||||
struct wiz_clk_div_sel *clk_div_sel;
|
||||
const struct wiz_clk_mux_sel *clk_mux_sel;
|
||||
const struct wiz_clk_div_sel *clk_div_sel;
|
||||
unsigned int clk_div_sel_num;
|
||||
struct regmap_field *por_en;
|
||||
struct regmap_field *phy_reset_n;
|
||||
struct regmap_field *phy_en_refclk;
|
||||
struct regmap_field *p_enable[WIZ_MAX_LANES];
|
||||
struct regmap_field *p_align[WIZ_MAX_LANES];
|
||||
struct regmap_field *p_raw_auto_start[WIZ_MAX_LANES];
|
||||
struct regmap_field *p_standard_mode[WIZ_MAX_LANES];
|
||||
struct regmap_field *p_mac_div_sel0[WIZ_MAX_LANES];
|
||||
struct regmap_field *p_mac_div_sel1[WIZ_MAX_LANES];
|
||||
struct regmap_field *p0_fullrt_div[WIZ_MAX_LANES];
|
||||
struct regmap_field *pma_cmn_refclk_int_mode;
|
||||
struct regmap_field *pma_cmn_refclk_mode;
|
||||
struct regmap_field *pma_cmn_refclk_dig_div;
|
||||
struct regmap_field *pma_cmn_refclk1_dig_div;
|
||||
struct regmap_field *mux_sel_field[WIZ_MUX_NUM_CLOCKS];
|
||||
struct regmap_field *div_sel_field[WIZ_DIV_NUM_CLOCKS_16G];
|
||||
struct regmap_field *typec_ln10_swap;
|
||||
|
||||
struct device *dev;
|
||||
@ -223,6 +285,9 @@ struct wiz {
|
||||
struct gpio_desc *gpio_typec_dir;
|
||||
int typec_dir_delay;
|
||||
u32 lane_phy_type[WIZ_MAX_LANES];
|
||||
struct clk *input_clks[WIZ_MAX_INPUT_CLOCKS];
|
||||
struct clk *output_clks[WIZ_MAX_OUTPUT_CLOCKS];
|
||||
struct clk_onecell_data clk_data;
|
||||
};
|
||||
|
||||
static int wiz_reset(struct wiz *wiz)
|
||||
@ -242,6 +307,27 @@ static int wiz_reset(struct wiz *wiz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wiz_p_mac_div_sel(struct wiz *wiz)
|
||||
{
|
||||
u32 num_lanes = wiz->num_lanes;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_lanes; i++) {
|
||||
if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) {
|
||||
ret = regmap_field_write(wiz->p_mac_div_sel0[i], 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_field_write(wiz->p_mac_div_sel1[i], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wiz_mode_select(struct wiz *wiz)
|
||||
{
|
||||
u32 num_lanes = wiz->num_lanes;
|
||||
@ -252,8 +338,10 @@ static int wiz_mode_select(struct wiz *wiz)
|
||||
for (i = 0; i < num_lanes; i++) {
|
||||
if (wiz->lane_phy_type[i] == PHY_TYPE_DP)
|
||||
mode = LANE_MODE_GEN1;
|
||||
else if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII)
|
||||
mode = LANE_MODE_GEN2;
|
||||
else
|
||||
mode = LANE_MODE_GEN4;
|
||||
continue;
|
||||
|
||||
ret = regmap_field_write(wiz->p_standard_mode[i], mode);
|
||||
if (ret)
|
||||
@ -299,6 +387,12 @@ static int wiz_init(struct wiz *wiz)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wiz_p_mac_div_sel(wiz);
|
||||
if (ret) {
|
||||
dev_err(dev, "Configuring P0 MAC DIV SEL failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wiz_init_raw_interface(wiz, true);
|
||||
if (ret) {
|
||||
dev_err(dev, "WIZ interface initialization failed\n");
|
||||
@ -310,8 +404,6 @@ static int wiz_init(struct wiz *wiz)
|
||||
|
||||
static int wiz_regfield_init(struct wiz *wiz)
|
||||
{
|
||||
struct wiz_clk_mux_sel *clk_mux_sel;
|
||||
struct wiz_clk_div_sel *clk_div_sel;
|
||||
struct regmap *regmap = wiz->regmap;
|
||||
int num_lanes = wiz->num_lanes;
|
||||
struct device *dev = wiz->dev;
|
||||
@ -344,54 +436,49 @@ static int wiz_regfield_init(struct wiz *wiz)
|
||||
return PTR_ERR(wiz->pma_cmn_refclk_mode);
|
||||
}
|
||||
|
||||
clk_div_sel = &wiz->clk_div_sel[CMN_REFCLK_DIG_DIV];
|
||||
clk_div_sel->field = devm_regmap_field_alloc(dev, regmap,
|
||||
pma_cmn_refclk_dig_div);
|
||||
if (IS_ERR(clk_div_sel->field)) {
|
||||
wiz->div_sel_field[CMN_REFCLK_DIG_DIV] =
|
||||
devm_regmap_field_alloc(dev, regmap, pma_cmn_refclk_dig_div);
|
||||
if (IS_ERR(wiz->div_sel_field[CMN_REFCLK_DIG_DIV])) {
|
||||
dev_err(dev, "PMA_CMN_REFCLK_DIG_DIV reg field init failed\n");
|
||||
return PTR_ERR(clk_div_sel->field);
|
||||
return PTR_ERR(wiz->div_sel_field[CMN_REFCLK_DIG_DIV]);
|
||||
}
|
||||
|
||||
if (wiz->type == J721E_WIZ_16G) {
|
||||
clk_div_sel = &wiz->clk_div_sel[CMN_REFCLK1_DIG_DIV];
|
||||
clk_div_sel->field =
|
||||
wiz->div_sel_field[CMN_REFCLK1_DIG_DIV] =
|
||||
devm_regmap_field_alloc(dev, regmap,
|
||||
pma_cmn_refclk1_dig_div);
|
||||
if (IS_ERR(clk_div_sel->field)) {
|
||||
if (IS_ERR(wiz->div_sel_field[CMN_REFCLK1_DIG_DIV])) {
|
||||
dev_err(dev, "PMA_CMN_REFCLK1_DIG_DIV reg field init failed\n");
|
||||
return PTR_ERR(clk_div_sel->field);
|
||||
return PTR_ERR(wiz->div_sel_field[CMN_REFCLK1_DIG_DIV]);
|
||||
}
|
||||
}
|
||||
|
||||
clk_mux_sel = &wiz->clk_mux_sel[PLL0_REFCLK];
|
||||
clk_mux_sel->field = devm_regmap_field_alloc(dev, regmap,
|
||||
pll0_refclk_mux_sel);
|
||||
if (IS_ERR(clk_mux_sel->field)) {
|
||||
wiz->mux_sel_field[PLL0_REFCLK] =
|
||||
devm_regmap_field_alloc(dev, regmap, pll0_refclk_mux_sel);
|
||||
if (IS_ERR(wiz->mux_sel_field[PLL0_REFCLK])) {
|
||||
dev_err(dev, "PLL0_REFCLK_SEL reg field init failed\n");
|
||||
return PTR_ERR(clk_mux_sel->field);
|
||||
return PTR_ERR(wiz->mux_sel_field[PLL0_REFCLK]);
|
||||
}
|
||||
|
||||
clk_mux_sel = &wiz->clk_mux_sel[PLL1_REFCLK];
|
||||
clk_mux_sel->field = devm_regmap_field_alloc(dev, regmap,
|
||||
pll1_refclk_mux_sel);
|
||||
if (IS_ERR(clk_mux_sel->field)) {
|
||||
wiz->mux_sel_field[PLL1_REFCLK] =
|
||||
devm_regmap_field_alloc(dev, regmap, pll1_refclk_mux_sel);
|
||||
if (IS_ERR(wiz->mux_sel_field[PLL1_REFCLK])) {
|
||||
dev_err(dev, "PLL1_REFCLK_SEL reg field init failed\n");
|
||||
return PTR_ERR(clk_mux_sel->field);
|
||||
return PTR_ERR(wiz->mux_sel_field[PLL1_REFCLK]);
|
||||
}
|
||||
|
||||
clk_mux_sel = &wiz->clk_mux_sel[REFCLK_DIG];
|
||||
if (wiz->type == J721E_WIZ_10G)
|
||||
clk_mux_sel->field =
|
||||
if (wiz->type == J721E_WIZ_10G || wiz->type == AM64_WIZ_10G)
|
||||
wiz->mux_sel_field[REFCLK_DIG] =
|
||||
devm_regmap_field_alloc(dev, regmap,
|
||||
refclk_dig_sel_10g);
|
||||
else
|
||||
clk_mux_sel->field =
|
||||
wiz->mux_sel_field[REFCLK_DIG] =
|
||||
devm_regmap_field_alloc(dev, regmap,
|
||||
refclk_dig_sel_16g);
|
||||
|
||||
if (IS_ERR(clk_mux_sel->field)) {
|
||||
if (IS_ERR(wiz->mux_sel_field[REFCLK_DIG])) {
|
||||
dev_err(dev, "REFCLK_DIG_SEL reg field init failed\n");
|
||||
return PTR_ERR(clk_mux_sel->field);
|
||||
return PTR_ERR(wiz->mux_sel_field[REFCLK_DIG]);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_lanes; i++) {
|
||||
@ -424,6 +511,28 @@ static int wiz_regfield_init(struct wiz *wiz)
|
||||
i);
|
||||
return PTR_ERR(wiz->p_standard_mode[i]);
|
||||
}
|
||||
|
||||
wiz->p0_fullrt_div[i] = devm_regmap_field_alloc(dev, regmap, p0_fullrt_div[i]);
|
||||
if (IS_ERR(wiz->p0_fullrt_div[i])) {
|
||||
dev_err(dev, "P%d_FULLRT_DIV reg field init failed\n", i);
|
||||
return PTR_ERR(wiz->p0_fullrt_div[i]);
|
||||
}
|
||||
|
||||
wiz->p_mac_div_sel0[i] =
|
||||
devm_regmap_field_alloc(dev, regmap, p_mac_div_sel0[i]);
|
||||
if (IS_ERR(wiz->p_mac_div_sel0[i])) {
|
||||
dev_err(dev, "P%d_MAC_DIV_SEL0 reg field init fail\n",
|
||||
i);
|
||||
return PTR_ERR(wiz->p_mac_div_sel0[i]);
|
||||
}
|
||||
|
||||
wiz->p_mac_div_sel1[i] =
|
||||
devm_regmap_field_alloc(dev, regmap, p_mac_div_sel1[i]);
|
||||
if (IS_ERR(wiz->p_mac_div_sel1[i])) {
|
||||
dev_err(dev, "P%d_MAC_DIV_SEL1 reg field init fail\n",
|
||||
i);
|
||||
return PTR_ERR(wiz->p_mac_div_sel1[i]);
|
||||
}
|
||||
}
|
||||
|
||||
wiz->typec_ln10_swap = devm_regmap_field_alloc(dev, regmap,
|
||||
@ -433,6 +542,76 @@ static int wiz_regfield_init(struct wiz *wiz)
|
||||
return PTR_ERR(wiz->typec_ln10_swap);
|
||||
}
|
||||
|
||||
wiz->phy_en_refclk = devm_regmap_field_alloc(dev, regmap, phy_en_refclk);
|
||||
if (IS_ERR(wiz->phy_en_refclk)) {
|
||||
dev_err(dev, "PHY_EN_REFCLK reg field init failed\n");
|
||||
return PTR_ERR(wiz->phy_en_refclk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wiz_phy_en_refclk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw);
|
||||
struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk;
|
||||
|
||||
regmap_field_write(phy_en_refclk, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wiz_phy_en_refclk_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw);
|
||||
struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk;
|
||||
|
||||
regmap_field_write(phy_en_refclk, 0);
|
||||
}
|
||||
|
||||
static int wiz_phy_en_refclk_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw);
|
||||
struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk;
|
||||
int val;
|
||||
|
||||
regmap_field_read(phy_en_refclk, &val);
|
||||
|
||||
return !!val;
|
||||
}
|
||||
|
||||
static const struct clk_ops wiz_phy_en_refclk_ops = {
|
||||
.enable = wiz_phy_en_refclk_enable,
|
||||
.disable = wiz_phy_en_refclk_disable,
|
||||
.is_enabled = wiz_phy_en_refclk_is_enabled,
|
||||
};
|
||||
|
||||
static int wiz_phy_en_refclk_register(struct wiz *wiz)
|
||||
{
|
||||
struct wiz_phy_en_refclk *wiz_phy_en_refclk;
|
||||
struct device *dev = wiz->dev;
|
||||
struct clk_init_data *init;
|
||||
struct clk *clk;
|
||||
|
||||
wiz_phy_en_refclk = devm_kzalloc(dev, sizeof(*wiz_phy_en_refclk), GFP_KERNEL);
|
||||
if (!wiz_phy_en_refclk)
|
||||
return -ENOMEM;
|
||||
|
||||
init = &wiz_phy_en_refclk->clk_data;
|
||||
|
||||
init->ops = &wiz_phy_en_refclk_ops;
|
||||
init->flags = 0;
|
||||
init->name = output_clk_names[TI_WIZ_PHY_EN_REFCLK];
|
||||
|
||||
wiz_phy_en_refclk->phy_en_refclk = wiz->phy_en_refclk;
|
||||
wiz_phy_en_refclk->hw.init = init;
|
||||
|
||||
clk = devm_clk_register(dev, &wiz_phy_en_refclk->hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
wiz->output_clks[TI_WIZ_PHY_EN_REFCLK] = clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -443,7 +622,7 @@ static u8 wiz_clk_mux_get_parent(struct clk_hw *hw)
|
||||
unsigned int val;
|
||||
|
||||
regmap_field_read(field, &val);
|
||||
return clk_mux_val_to_index(hw, mux->table, 0, val);
|
||||
return clk_mux_val_to_index(hw, (u32 *)mux->table, 0, val);
|
||||
}
|
||||
|
||||
static int wiz_clk_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
@ -461,8 +640,69 @@ static const struct clk_ops wiz_clk_mux_ops = {
|
||||
.get_parent = wiz_clk_mux_get_parent,
|
||||
};
|
||||
|
||||
static int wiz_mux_clk_register(struct wiz *wiz, struct device_node *node,
|
||||
struct regmap_field *field, u32 *table)
|
||||
static int wiz_mux_clk_register(struct wiz *wiz, struct regmap_field *field,
|
||||
const struct wiz_clk_mux_sel *mux_sel, int clk_index)
|
||||
{
|
||||
struct device *dev = wiz->dev;
|
||||
struct clk_init_data *init;
|
||||
const char **parent_names;
|
||||
unsigned int num_parents;
|
||||
struct wiz_clk_mux *mux;
|
||||
char clk_name[100];
|
||||
struct clk *clk;
|
||||
int ret = 0, i;
|
||||
|
||||
mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux)
|
||||
return -ENOMEM;
|
||||
|
||||
num_parents = mux_sel->num_parents;
|
||||
|
||||
parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
|
||||
if (!parent_names)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_parents; i++) {
|
||||
clk = wiz->input_clks[mux_sel->parents[i]];
|
||||
if (IS_ERR_OR_NULL(clk)) {
|
||||
dev_err(dev, "Failed to get parent clk for %s\n",
|
||||
output_clk_names[clk_index]);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
parent_names[i] = __clk_get_name(clk);
|
||||
}
|
||||
|
||||
snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), output_clk_names[clk_index]);
|
||||
|
||||
init = &mux->clk_data;
|
||||
|
||||
init->ops = &wiz_clk_mux_ops;
|
||||
init->flags = CLK_SET_RATE_NO_REPARENT;
|
||||
init->parent_names = parent_names;
|
||||
init->num_parents = num_parents;
|
||||
init->name = clk_name;
|
||||
|
||||
mux->field = field;
|
||||
mux->table = mux_sel->table;
|
||||
mux->hw.init = init;
|
||||
|
||||
clk = devm_clk_register(dev, &mux->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto err;
|
||||
}
|
||||
|
||||
wiz->output_clks[clk_index] = clk;
|
||||
|
||||
err:
|
||||
kfree(parent_names);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wiz_mux_of_clk_register(struct wiz *wiz, struct device_node *node,
|
||||
struct regmap_field *field, const u32 *table)
|
||||
{
|
||||
struct device *dev = wiz->dev;
|
||||
struct clk_init_data *init;
|
||||
@ -606,20 +846,70 @@ static int wiz_div_clk_register(struct wiz *wiz, struct device_node *node,
|
||||
|
||||
static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node)
|
||||
{
|
||||
struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel;
|
||||
const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel;
|
||||
struct device *dev = wiz->dev;
|
||||
struct device_node *clk_node;
|
||||
int i;
|
||||
|
||||
if (wiz->type == AM64_WIZ_10G) {
|
||||
of_clk_del_provider(dev->of_node);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) {
|
||||
clk_node = of_get_child_by_name(node, clk_mux_sel[i].node_name);
|
||||
of_clk_del_provider(clk_node);
|
||||
of_node_put(clk_node);
|
||||
}
|
||||
|
||||
for (i = 0; i < wiz->clk_div_sel_num; i++) {
|
||||
clk_node = of_get_child_by_name(node, clk_div_sel[i].node_name);
|
||||
of_clk_del_provider(clk_node);
|
||||
of_node_put(clk_node);
|
||||
}
|
||||
|
||||
of_clk_del_provider(wiz->dev->of_node);
|
||||
}
|
||||
|
||||
static int wiz_clock_register(struct wiz *wiz)
|
||||
{
|
||||
const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel;
|
||||
struct device *dev = wiz->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
int clk_index;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (wiz->type != AM64_WIZ_10G)
|
||||
return 0;
|
||||
|
||||
clk_index = TI_WIZ_PLL0_REFCLK;
|
||||
for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++, clk_index++) {
|
||||
ret = wiz_mux_clk_register(wiz, wiz->mux_sel_field[i], &clk_mux_sel[i], clk_index);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register clk: %s\n", output_clk_names[clk_index]);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = wiz_phy_en_refclk_register(wiz);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to add phy-en-refclk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
wiz->clk_data.clks = wiz->output_clks;
|
||||
wiz->clk_data.clk_num = WIZ_MAX_OUTPUT_CLOCKS;
|
||||
ret = of_clk_add_provider(node, of_clk_src_onecell_get, &wiz->clk_data);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to add clock provider: %s\n", node->name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
|
||||
{
|
||||
struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel;
|
||||
const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel;
|
||||
struct device *dev = wiz->dev;
|
||||
struct device_node *clk_node;
|
||||
const char *node_name;
|
||||
@ -634,6 +924,7 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
|
||||
ret = PTR_ERR(clk);
|
||||
return ret;
|
||||
}
|
||||
wiz->input_clks[WIZ_CORE_REFCLK] = clk;
|
||||
|
||||
rate = clk_get_rate(clk);
|
||||
if (rate >= 100000000)
|
||||
@ -647,6 +938,7 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
|
||||
ret = PTR_ERR(clk);
|
||||
return ret;
|
||||
}
|
||||
wiz->input_clks[WIZ_EXT_REFCLK] = clk;
|
||||
|
||||
rate = clk_get_rate(clk);
|
||||
if (rate >= 100000000)
|
||||
@ -654,6 +946,13 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
|
||||
else
|
||||
regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2);
|
||||
|
||||
if (wiz->type == AM64_WIZ_10G) {
|
||||
ret = wiz_clock_register(wiz);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to register wiz clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) {
|
||||
node_name = clk_mux_sel[i].node_name;
|
||||
clk_node = of_get_child_by_name(node, node_name);
|
||||
@ -663,8 +962,8 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = wiz_mux_clk_register(wiz, clk_node, clk_mux_sel[i].field,
|
||||
clk_mux_sel[i].table);
|
||||
ret = wiz_mux_of_clk_register(wiz, clk_node, wiz->mux_sel_field[i],
|
||||
clk_mux_sel[i].table);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register %s clock\n",
|
||||
node_name);
|
||||
@ -684,7 +983,7 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = wiz_div_clk_register(wiz, clk_node, clk_div_sel[i].field,
|
||||
ret = wiz_div_clk_register(wiz, clk_node, wiz->div_sel_field[i],
|
||||
clk_div_sel[i].table);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register %s clock\n",
|
||||
@ -719,6 +1018,17 @@ static int wiz_phy_reset_assert(struct reset_controller_dev *rcdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wiz_phy_fullrt_div(struct wiz *wiz, int lane)
|
||||
{
|
||||
if (wiz->type != AM64_WIZ_10G)
|
||||
return 0;
|
||||
|
||||
if (wiz->lane_phy_type[lane] == PHY_TYPE_PCIE)
|
||||
return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
@ -742,6 +1052,10 @@ static int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wiz_phy_fullrt_div(wiz, id - 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (wiz->lane_phy_type[id - 1] == PHY_TYPE_DP)
|
||||
ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE);
|
||||
else
|
||||
@ -769,6 +1083,9 @@ static const struct of_device_id wiz_id_table[] = {
|
||||
{
|
||||
.compatible = "ti,j721e-wiz-10g", .data = (void *)J721E_WIZ_10G
|
||||
},
|
||||
{
|
||||
.compatible = "ti,am64-wiz-10g", .data = (void *)AM64_WIZ_10G
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wiz_id_table);
|
||||
@ -787,11 +1104,17 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
|
||||
u32 reg, num_lanes = 1, phy_type = PHY_NONE;
|
||||
int ret, i;
|
||||
|
||||
if (!(of_node_name_eq(subnode, "phy") ||
|
||||
of_node_name_eq(subnode, "link")))
|
||||
continue;
|
||||
|
||||
ret = of_property_read_u32(subnode, "reg", ®);
|
||||
if (ret) {
|
||||
of_node_put(subnode);
|
||||
dev_err(dev,
|
||||
"%s: Reading \"reg\" from \"%s\" failed: %d\n",
|
||||
__func__, subnode->name, ret);
|
||||
of_node_put(subnode);
|
||||
return ret;
|
||||
}
|
||||
of_property_read_u32(subnode, "cdns,num-lanes", &num_lanes);
|
||||
@ -813,13 +1136,14 @@ static int wiz_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct platform_device *serdes_pdev;
|
||||
bool already_configured = false;
|
||||
struct device_node *child_node;
|
||||
struct regmap *regmap;
|
||||
struct resource res;
|
||||
void __iomem *base;
|
||||
struct wiz *wiz;
|
||||
int ret, val, i;
|
||||
u32 num_lanes;
|
||||
int ret;
|
||||
|
||||
wiz = devm_kzalloc(dev, sizeof(*wiz), GFP_KERNEL);
|
||||
if (!wiz)
|
||||
@ -900,14 +1224,14 @@ static int wiz_probe(struct platform_device *pdev)
|
||||
wiz->dev = dev;
|
||||
wiz->regmap = regmap;
|
||||
wiz->num_lanes = num_lanes;
|
||||
if (wiz->type == J721E_WIZ_10G)
|
||||
if (wiz->type == J721E_WIZ_10G || wiz->type == AM64_WIZ_10G)
|
||||
wiz->clk_mux_sel = clk_mux_sel_10g;
|
||||
else
|
||||
wiz->clk_mux_sel = clk_mux_sel_16g;
|
||||
|
||||
wiz->clk_div_sel = clk_div_sel;
|
||||
|
||||
if (wiz->type == J721E_WIZ_10G)
|
||||
if (wiz->type == J721E_WIZ_10G || wiz->type == AM64_WIZ_10G)
|
||||
wiz->clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G;
|
||||
else
|
||||
wiz->clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_16G;
|
||||
@ -947,27 +1271,34 @@ static int wiz_probe(struct platform_device *pdev)
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
for (i = 0; i < wiz->num_lanes; i++) {
|
||||
regmap_field_read(wiz->p_enable[i], &val);
|
||||
if (val & (P_ENABLE | P_ENABLE_FORCE)) {
|
||||
already_configured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!already_configured) {
|
||||
ret = wiz_init(wiz);
|
||||
if (ret) {
|
||||
dev_err(dev, "WIZ initialization failed\n");
|
||||
goto err_wiz_init;
|
||||
}
|
||||
}
|
||||
|
||||
serdes_pdev = of_platform_device_create(child_node, NULL, dev);
|
||||
if (!serdes_pdev) {
|
||||
dev_WARN(dev, "Unable to create SERDES platform device\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_pdev_create;
|
||||
}
|
||||
wiz->serdes_pdev = serdes_pdev;
|
||||
|
||||
ret = wiz_init(wiz);
|
||||
if (ret) {
|
||||
dev_err(dev, "WIZ initialization failed\n");
|
||||
goto err_wiz_init;
|
||||
}
|
||||
wiz->serdes_pdev = serdes_pdev;
|
||||
|
||||
of_node_put(child_node);
|
||||
return 0;
|
||||
|
||||
err_wiz_init:
|
||||
of_platform_device_destroy(&serdes_pdev->dev, NULL);
|
||||
|
||||
err_pdev_create:
|
||||
wiz_clock_cleanup(wiz, node);
|
||||
|
||||
err_get_sync:
|
||||
|
@ -7,15 +7,16 @@
|
||||
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/ulpi/driver.h>
|
||||
#include <linux/ulpi/regs.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/phy/ulpi_phy.h>
|
||||
|
||||
#define TUSB1210_VENDOR_SPECIFIC2 0x80
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT 0
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT 4
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT 6
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK GENMASK(3, 0)
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK GENMASK(5, 4)
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_DP_MASK BIT(6)
|
||||
|
||||
struct tusb1210 {
|
||||
struct ulpi *ulpi;
|
||||
@ -118,22 +119,22 @@ static int tusb1210_probe(struct ulpi *ulpi)
|
||||
* diagram optimization and DP/DM swap.
|
||||
*/
|
||||
|
||||
reg = ulpi_read(ulpi, TUSB1210_VENDOR_SPECIFIC2);
|
||||
|
||||
/* High speed output drive strength configuration */
|
||||
device_property_read_u8(&ulpi->dev, "ihstx", &val);
|
||||
reg = val << TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT;
|
||||
if (!device_property_read_u8(&ulpi->dev, "ihstx", &val))
|
||||
u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK);
|
||||
|
||||
/* High speed output impedance configuration */
|
||||
device_property_read_u8(&ulpi->dev, "zhsdrv", &val);
|
||||
reg |= val << TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT;
|
||||
if (!device_property_read_u8(&ulpi->dev, "zhsdrv", &val))
|
||||
u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK);
|
||||
|
||||
/* DP/DM swap control */
|
||||
device_property_read_u8(&ulpi->dev, "datapolarity", &val);
|
||||
reg |= val << TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT;
|
||||
if (!device_property_read_u8(&ulpi->dev, "datapolarity", &val))
|
||||
u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_DP_MASK);
|
||||
|
||||
if (reg) {
|
||||
ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg);
|
||||
tusb->vendor_specific2 = reg;
|
||||
}
|
||||
ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg);
|
||||
tusb->vendor_specific2 = reg;
|
||||
|
||||
tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
|
||||
if (IS_ERR(tusb->phy))
|
||||
|
@ -208,6 +208,7 @@ struct xpsgtr_phy {
|
||||
* @gtr_mutex: mutex for locking
|
||||
* @phys: PHY lanes
|
||||
* @refclk_sscs: spread spectrum settings for the reference clocks
|
||||
* @clk: reference clocks
|
||||
* @tx_term_fix: fix for GT issue
|
||||
* @saved_icm_cfg0: stored value of ICM CFG0 register
|
||||
* @saved_icm_cfg1: stored value of ICM CFG1 register
|
||||
@ -219,6 +220,7 @@ struct xpsgtr_dev {
|
||||
struct mutex gtr_mutex; /* mutex for locking */
|
||||
struct xpsgtr_phy phys[NUM_LANES];
|
||||
const struct xpsgtr_ssc *refclk_sscs[NUM_LANES];
|
||||
struct clk *clk[NUM_LANES];
|
||||
bool tx_term_fix;
|
||||
unsigned int saved_icm_cfg0;
|
||||
unsigned int saved_icm_cfg1;
|
||||
@ -818,11 +820,15 @@ static struct phy *xpsgtr_xlate(struct device *dev,
|
||||
static int __maybe_unused xpsgtr_suspend(struct device *dev)
|
||||
{
|
||||
struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
|
||||
unsigned int i;
|
||||
|
||||
/* Save the snapshot ICM_CFG registers. */
|
||||
gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
|
||||
gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++)
|
||||
clk_disable_unprepare(gtr_dev->clk[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -832,6 +838,13 @@ static int __maybe_unused xpsgtr_resume(struct device *dev)
|
||||
unsigned int icm_cfg0, icm_cfg1;
|
||||
unsigned int i;
|
||||
bool skip_phy_init;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) {
|
||||
err = clk_prepare_enable(gtr_dev->clk[i]);
|
||||
if (err)
|
||||
goto err_clk_put;
|
||||
}
|
||||
|
||||
icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
|
||||
icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
|
||||
@ -852,6 +865,12 @@ static int __maybe_unused xpsgtr_resume(struct device *dev)
|
||||
gtr_dev->phys[i].skip_phy_init = skip_phy_init;
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk_put:
|
||||
while (i--)
|
||||
clk_disable_unprepare(gtr_dev->clk[i]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops xpsgtr_pm_ops = {
|
||||
@ -865,6 +884,7 @@ static const struct dev_pm_ops xpsgtr_pm_ops = {
|
||||
static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
|
||||
{
|
||||
unsigned int refclk;
|
||||
int ret;
|
||||
|
||||
for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) {
|
||||
unsigned long rate;
|
||||
@ -874,14 +894,22 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
|
||||
|
||||
snprintf(name, sizeof(name), "ref%u", refclk);
|
||||
clk = devm_clk_get_optional(gtr_dev->dev, name);
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(gtr_dev->dev, PTR_ERR(clk),
|
||||
"Failed to get reference clock %u\n",
|
||||
refclk);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = dev_err_probe(gtr_dev->dev, PTR_ERR(clk),
|
||||
"Failed to get reference clock %u\n",
|
||||
refclk);
|
||||
goto err_clk_put;
|
||||
}
|
||||
|
||||
if (!clk)
|
||||
continue;
|
||||
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret)
|
||||
goto err_clk_put;
|
||||
|
||||
gtr_dev->clk[refclk] = clk;
|
||||
|
||||
/*
|
||||
* Get the spread spectrum (SSC) settings for the reference
|
||||
* clock rate.
|
||||
@ -899,11 +927,18 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
|
||||
dev_err(gtr_dev->dev,
|
||||
"Invalid rate %lu for reference clock %u\n",
|
||||
rate, refclk);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_clk_put;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk_put:
|
||||
while (refclk--)
|
||||
clk_disable_unprepare(gtr_dev->clk[refclk]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xpsgtr_probe(struct platform_device *pdev)
|
||||
@ -912,6 +947,7 @@ static int xpsgtr_probe(struct platform_device *pdev)
|
||||
struct xpsgtr_dev *gtr_dev;
|
||||
struct phy_provider *provider;
|
||||
unsigned int port;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
gtr_dev = devm_kzalloc(&pdev->dev, sizeof(*gtr_dev), GFP_KERNEL);
|
||||
@ -951,7 +987,8 @@ static int xpsgtr_probe(struct platform_device *pdev)
|
||||
phy = devm_phy_create(&pdev->dev, np, &xpsgtr_phyops);
|
||||
if (IS_ERR(phy)) {
|
||||
dev_err(&pdev->dev, "failed to create PHY\n");
|
||||
return PTR_ERR(phy);
|
||||
ret = PTR_ERR(phy);
|
||||
goto err_clk_put;
|
||||
}
|
||||
|
||||
gtr_phy->phy = phy;
|
||||
@ -962,9 +999,16 @@ static int xpsgtr_probe(struct platform_device *pdev)
|
||||
provider = devm_of_phy_provider_register(&pdev->dev, xpsgtr_xlate);
|
||||
if (IS_ERR(provider)) {
|
||||
dev_err(&pdev->dev, "registering provider failed\n");
|
||||
return PTR_ERR(provider);
|
||||
ret = PTR_ERR(provider);
|
||||
goto err_clk_put;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_clk_put:
|
||||
for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++)
|
||||
clk_disable_unprepare(gtr_dev->clk[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id xpsgtr_of_match[] = {
|
||||
|
@ -90,4 +90,9 @@
|
||||
#define J7200_SERDES0_LANE3_USB 0x2
|
||||
#define J7200_SERDES0_LANE3_IP4_UNUSED 0x3
|
||||
|
||||
/* AM64 */
|
||||
|
||||
#define AM64_SERDES0_LANE0_PCIE0 0x0
|
||||
#define AM64_SERDES0_LANE0_USB 0x1
|
||||
|
||||
#endif /* _DT_BINDINGS_MUX_TI_SERDES */
|
||||
|
@ -1,13 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* This header provides constants for Cadence Torrent SERDES.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_TORRENT_SERDES_H
|
||||
#define _DT_BINDINGS_TORRENT_SERDES_H
|
||||
|
||||
#define TORRENT_SERDES_NO_SSC 0
|
||||
#define TORRENT_SERDES_EXTERNAL_SSC 1
|
||||
#define TORRENT_SERDES_INTERNAL_SSC 2
|
||||
|
||||
#endif /* _DT_BINDINGS_TORRENT_SERDES_H */
|
20
include/dt-bindings/phy/phy-cadence.h
Normal file
20
include/dt-bindings/phy/phy-cadence.h
Normal file
@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* This header provides constants for Cadence SERDES.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_CADENCE_SERDES_H
|
||||
#define _DT_BINDINGS_CADENCE_SERDES_H
|
||||
|
||||
/* Torrent */
|
||||
#define TORRENT_SERDES_NO_SSC 0
|
||||
#define TORRENT_SERDES_EXTERNAL_SSC 1
|
||||
#define TORRENT_SERDES_INTERNAL_SSC 2
|
||||
|
||||
#define CDNS_TORRENT_REFCLK_DRIVER 0
|
||||
|
||||
/* Sierra */
|
||||
#define CDNS_SIERRA_PLL_CMNLC 0
|
||||
#define CDNS_SIERRA_PLL_CMNLC1 1
|
||||
|
||||
#endif /* _DT_BINDINGS_CADENCE_SERDES_H */
|
21
include/dt-bindings/phy/phy-ti.h
Normal file
21
include/dt-bindings/phy/phy-ti.h
Normal file
@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* This header provides constants for TI SERDES.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_TI_SERDES
|
||||
#define _DT_BINDINGS_TI_SERDES
|
||||
|
||||
/* Clock index for output clocks from WIZ */
|
||||
|
||||
/* MUX Clocks */
|
||||
#define TI_WIZ_PLL0_REFCLK 0
|
||||
#define TI_WIZ_PLL1_REFCLK 1
|
||||
#define TI_WIZ_REFCLK_DIG 2
|
||||
|
||||
/* Reserve index here for future additions */
|
||||
|
||||
/* MISC Clocks */
|
||||
#define TI_WIZ_PHY_EN_REFCLK 16
|
||||
|
||||
#endif /* _DT_BINDINGS_TI_SERDES */
|
@ -44,6 +44,12 @@ enum phy_mode {
|
||||
PHY_MODE_DP
|
||||
};
|
||||
|
||||
enum phy_media {
|
||||
PHY_MEDIA_DEFAULT,
|
||||
PHY_MEDIA_SR,
|
||||
PHY_MEDIA_DAC,
|
||||
};
|
||||
|
||||
/**
|
||||
* union phy_configure_opts - Opaque generic phy configuration
|
||||
*
|
||||
@ -64,6 +70,8 @@ union phy_configure_opts {
|
||||
* @power_on: powering on the phy
|
||||
* @power_off: powering off the phy
|
||||
* @set_mode: set the mode of the phy
|
||||
* @set_media: set the media type of the phy (optional)
|
||||
* @set_speed: set the speed of the phy (optional)
|
||||
* @reset: resetting the phy
|
||||
* @calibrate: calibrate the phy
|
||||
* @release: ops to be performed while the consumer relinquishes the PHY
|
||||
@ -75,6 +83,8 @@ struct phy_ops {
|
||||
int (*power_on)(struct phy *phy);
|
||||
int (*power_off)(struct phy *phy);
|
||||
int (*set_mode)(struct phy *phy, enum phy_mode mode, int submode);
|
||||
int (*set_media)(struct phy *phy, enum phy_media media);
|
||||
int (*set_speed)(struct phy *phy, int speed);
|
||||
|
||||
/**
|
||||
* @configure:
|
||||
@ -215,6 +225,8 @@ int phy_power_off(struct phy *phy);
|
||||
int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode);
|
||||
#define phy_set_mode(phy, mode) \
|
||||
phy_set_mode_ext(phy, mode, 0)
|
||||
int phy_set_media(struct phy *phy, enum phy_media media);
|
||||
int phy_set_speed(struct phy *phy, int speed);
|
||||
int phy_configure(struct phy *phy, union phy_configure_opts *opts);
|
||||
int phy_validate(struct phy *phy, enum phy_mode mode, int submode,
|
||||
union phy_configure_opts *opts);
|
||||
@ -344,6 +356,20 @@ static inline int phy_set_mode_ext(struct phy *phy, enum phy_mode mode,
|
||||
#define phy_set_mode(phy, mode) \
|
||||
phy_set_mode_ext(phy, mode, 0)
|
||||
|
||||
static inline int phy_set_media(struct phy *phy, enum phy_media media)
|
||||
{
|
||||
if (!phy)
|
||||
return 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int phy_set_speed(struct phy *phy, int speed)
|
||||
{
|
||||
if (!phy)
|
||||
return 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline enum phy_mode phy_get_mode(struct phy *phy)
|
||||
{
|
||||
return PHY_MODE_INVALID;
|
||||
|
Loading…
x
Reference in New Issue
Block a user