Commit c33ffdb7 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull phy updates from Vinod Koul:
 "New Support
   - Samsung Exynos gs101 drd combo phy
   - Qualcomm SC8180x USB uniphy, IPQ9574 QMP PCIe phy
   - Airoha EN7581 PCIe phy
   - Freescale i.MX8Q HSIO SerDes phy
   - Starfive jh7110 dphy tx

  Updates:
   - Resume support for j721e-wiz driver
   - Updates to Exynos usbdrd driver
   - Support for optional power domains in g12a usb2-phy driver
   - Debugfs support and updates to zynqmp driver"

* tag 'phy-for-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (56 commits)
  phy: airoha: Add dtime and Rx AEQ IO registers
  dt-bindings: phy: airoha: Add dtime and Rx AEQ IO registers
  dt-bindings: phy: rockchip-emmc-phy: Convert to dtschema
  dt-bindings: phy: qcom,qmp-usb: fix spelling error
  phy: exynos5-usbdrd: support Exynos USBDRD 3.1 combo phy (HS & SS)
  phy: exynos5-usbdrd: convert Vbus supplies to regulator_bulk
  phy: exynos5-usbdrd: convert (phy) register access clock to clk_bulk
  phy: exynos5-usbdrd: convert core clocks to clk_bulk
  phy: exynos5-usbdrd: support isolating HS and SS ports independently
  dt-bindings: phy: samsung,usb3-drd-phy: add gs101 compatible
  phy: core: Fix documentation of of_phy_get
  phy: starfive: Correct the dphy configure process
  phy: zynqmp: Add debugfs support
  phy: zynqmp: Take the phy mutex in xlate
  phy: zynqmp: Only wait for PLL lock "primary" instances
  phy: zynqmp: Store instance instead of type
  phy: zynqmp: Enable reference clock correctly
  phy: cadence-torrent: Check return value on register read
  phy: Fix the cacography in phy-exynos5250-usb2.c
  phy: phy-rockchip-samsung-hdptx: Select CONFIG_MFD_SYSCON
  ...
parents ad7b0b7b 2a011c3c
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/airoha,en7581-pcie-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Airoha EN7581 PCI-Express PHY
maintainers:
- Lorenzo Bianconi <lorenzo@kernel.org>
description:
The PCIe PHY supports physical layer functionality for PCIe Gen2/Gen3 port.
properties:
compatible:
const: airoha,en7581-pcie-phy
reg:
items:
- description: PCIE analog base address
- description: PCIE lane0 base address
- description: PCIE lane1 base address
- description: PCIE lane0 detection time base address
- description: PCIE lane1 detection time base address
- description: PCIE Rx AEQ base address
reg-names:
items:
- const: csr-2l
- const: pma0
- const: pma1
- const: p0-xr-dtime
- const: p1-xr-dtime
- const: rx-aeq
"#phy-cells":
const: 0
required:
- compatible
- reg
- reg-names
- "#phy-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/phy/phy.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
phy@11e80000 {
compatible = "airoha,en7581-pcie-phy";
#phy-cells = <0>;
reg = <0x0 0x1fa5a000 0x0 0xfff>,
<0x0 0x1fa5b000 0x0 0xfff>,
<0x0 0x1fa5c000 0x0 0xfff>,
<0x0 0x1fc10044 0x0 0x4>,
<0x0 0x1fc30044 0x0 0x4>,
<0x0 0x1fc15030 0x0 0x104>;
reg-names = "csr-2l", "pma0", "pma1",
"p0-xr-dtime", "p1-xr-dtime",
"rx-aeq";
};
};
......@@ -41,6 +41,9 @@ properties:
Phandle to a regulator that provides power to the PHY. This
regulator will be managed during the PHY power on/off sequence.
power-domains:
maxItems: 1
required:
- compatible
- reg
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/fsl,imx8qm-hsio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8QM SoC series High Speed IO(HSIO) SERDES PHY
maintainers:
- Richard Zhu <hongxing.zhu@nxp.com>
properties:
compatible:
enum:
- fsl,imx8qm-hsio
- fsl,imx8qxp-hsio
reg:
items:
- description: Base address and length of the PHY block
- description: HSIO control and status registers(CSR) of the PHY
- description: HSIO CSR of the controller bound to the PHY
- description: HSIO CSR for MISC
reg-names:
items:
- const: reg
- const: phy
- const: ctrl
- const: misc
"#phy-cells":
const: 3
description:
The first defines lane index.
The second defines the type of the PHY refer to the include phy.h.
The third defines the controller index, indicated which controller
is bound to the lane.
clocks:
minItems: 5
maxItems: 14
clock-names:
minItems: 5
maxItems: 14
fsl,hsio-cfg:
description: |
Specifies the use case of the HSIO module in the hardware design.
Regarding the design of i.MX8QM HSIO subsystem, HSIO module can be
confiured as following three use cases.
+---------------------------------------+
| | i.MX8QM |
|------------------|--------------------|
| | Lane0| Lane1| Lane2|
|------------------|------|------|------|
| pciea-x2-sata | PCIEA| PCIEA| SATA |
|------------------|------|------|------|
| pciea-x2-pcieb | PCIEA| PCIEA| PCIEB|
|------------------|------|------|------|
| pciea-pcieb-sata | PCIEA| PCIEB| SATA |
+---------------------------------------+
$ref: /schemas/types.yaml#/definitions/string
enum: [ pciea-x2-sata, pciea-x2-pcieb, pciea-pcieb-sata]
default: pciea-pcieb-sata
fsl,refclk-pad-mode:
description:
Specifies the mode of the refclk pad used. INPUT(PHY refclock is
provided externally via the refclk pad) or OUTPUT(PHY refclock is
derived from SoC internal source and provided on the refclk pad).
This property not exists means unused(PHY refclock is derived from
SoC internal source).
$ref: /schemas/types.yaml#/definitions/string
enum: [ input, output, unused ]
default: unused
power-domains:
minItems: 1
maxItems: 2
required:
- compatible
- reg
- reg-names
- "#phy-cells"
- clocks
- clock-names
- fsl,hsio-cfg
allOf:
- if:
properties:
compatible:
contains:
enum:
- fsl,imx8qxp-hsio
then:
properties:
clock-names:
items:
- const: pclk0
- const: apb_pclk0
- const: phy0_crr
- const: ctl0_crr
- const: misc_crr
power-domains:
maxItems: 1
- if:
properties:
compatible:
contains:
enum:
- fsl,imx8qm-hsio
then:
properties:
clock-names:
items:
- const: pclk0
- const: pclk1
- const: apb_pclk0
- const: apb_pclk1
- const: pclk2
- const: epcs_tx
- const: epcs_rx
- const: apb_pclk2
- const: phy0_crr
- const: phy1_crr
- const: ctl0_crr
- const: ctl1_crr
- const: ctl2_crr
- const: misc_crr
power-domains:
minItems: 2
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8-clock.h>
#include <dt-bindings/clock/imx8-lpcg.h>
#include <dt-bindings/firmware/imx/rsrc.h>
#include <dt-bindings/phy/phy-imx8-pcie.h>
phy@5f1a0000 {
compatible = "fsl,imx8qxp-hsio";
reg = <0x5f1a0000 0x10000>,
<0x5f120000 0x10000>,
<0x5f140000 0x10000>,
<0x5f160000 0x10000>;
reg-names = "reg", "phy", "ctrl", "misc";
clocks = <&phyx1_lpcg IMX_LPCG_CLK_0>,
<&phyx1_lpcg IMX_LPCG_CLK_4>,
<&phyx1_crr1_lpcg IMX_LPCG_CLK_4>,
<&pcieb_crr3_lpcg IMX_LPCG_CLK_4>,
<&misc_crr5_lpcg IMX_LPCG_CLK_4>;
clock-names = "pclk0", "apb_pclk0", "phy0_crr", "ctl0_crr", "misc_crr";
power-domains = <&pd IMX_SC_R_SERDES_1>;
#phy-cells = <3>;
fsl,hsio-cfg = "pciea-pcieb-sata";
fsl,refclk-pad-mode = "input";
};
...
......@@ -41,6 +41,12 @@ properties:
Phandle to the system controller node
$ref: /schemas/types.yaml#/definitions/phandle
swap-dx-lanes:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: |
Specifies the ports which will swap the differential-pair (D+/D-),
default is not-swapped.
# Required child nodes:
patternProperties:
......
......@@ -19,6 +19,8 @@ properties:
- qcom,ipq6018-qmp-pcie-phy
- qcom,ipq8074-qmp-gen3-pcie-phy
- qcom,ipq8074-qmp-pcie-phy
- qcom,ipq9574-qmp-gen3x1-pcie-phy
- qcom,ipq9574-qmp-gen3x2-pcie-phy
reg:
items:
......
......@@ -91,8 +91,7 @@ properties:
"#clock-cells": true
clock-output-names:
minItems: 1
maxItems: 2
maxItems: 1
"#phy-cells":
const: 0
......@@ -222,14 +221,10 @@ allOf:
- qcom,sm8650-qmp-gen4x2-pcie-phy
then:
properties:
clock-output-names:
minItems: 2
"#clock-cells":
const: 1
else:
properties:
clock-output-names:
maxItems: 1
"#clock-cells":
const: 0
......
......@@ -20,8 +20,9 @@ properties:
- qcom,ipq8074-qmp-usb3-phy
- qcom,ipq9574-qmp-usb3-phy
- qcom,msm8996-qmp-usb3-phy
- com,qdu1000-qmp-usb3-uni-phy
- qcom,qdu1000-qmp-usb3-uni-phy
- qcom,sa8775p-qmp-usb3-uni-phy
- qcom,sc8180x-qmp-usb3-uni-phy
- qcom,sc8280xp-qmp-usb3-uni-phy
- qcom,sdm845-qmp-usb3-uni-phy
- qcom,sdx55-qmp-usb3-uni-phy
......@@ -112,6 +113,7 @@ allOf:
enum:
- qcom,qdu1000-qmp-usb3-uni-phy
- qcom,sa8775p-qmp-usb3-uni-phy
- qcom,sc8180x-qmp-usb3-uni-phy
- qcom,sc8280xp-qmp-usb3-uni-phy
- qcom,sm8150-qmp-usb3-uni-phy
- qcom,sm8250-qmp-usb3-uni-phy
......@@ -152,6 +154,7 @@ allOf:
contains:
enum:
- qcom,sa8775p-qmp-usb3-uni-phy
- qcom,sc8180x-qmp-usb3-uni-phy
- qcom,sc8280xp-qmp-usb3-uni-phy
- qcom,x1e80100-qmp-usb3-uni-phy
then:
......
......@@ -15,6 +15,7 @@ if:
contains:
enum:
- qcom,usb-hs-phy-apq8064
- qcom,usb-hs-phy-msm8660
- qcom,usb-hs-phy-msm8960
then:
properties:
......@@ -41,6 +42,7 @@ properties:
- enum:
- qcom,usb-hs-phy-apq8064
- qcom,usb-hs-phy-msm8226
- qcom,usb-hs-phy-msm8660
- qcom,usb-hs-phy-msm8916
- qcom,usb-hs-phy-msm8960
- qcom,usb-hs-phy-msm8974
......
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/rockchip,rk3399-emmc-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Rockchip EMMC PHY
maintainers:
- Heiko Stuebner <heiko@sntech.de>
properties:
compatible:
const: rockchip,rk3399-emmc-phy
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
const: emmcclk
drive-impedance-ohm:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Specifies the drive impedance in Ohm.
enum: [33, 40, 50, 66, 100]
default: 50
rockchip,enable-strobe-pulldown:
type: boolean
description: |
Enable internal pull-down for the strobe
line. If not set, pull-down is not used.
rockchip,output-tapdelay-select:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Specifies the phyctrl_otapdlysec register.
default: 0x4
maximum: 0xf
"#phy-cells":
const: 0
required:
- compatible
- reg
- "#phy-cells"
additionalProperties: false
examples:
- |
phy@f780 {
compatible = "rockchip,rk3399-emmc-phy";
reg = <0xf780 0x20>;
clocks = <&sdhci>;
clock-names = "emmcclk";
drive-impedance-ohm = <50>;
#phy-cells = <0>;
};
Rockchip EMMC PHY
-----------------------
Required properties:
- compatible: rockchip,rk3399-emmc-phy
- #phy-cells: must be 0
- reg: PHY register address offset and length in "general
register files"
Optional properties:
- clock-names: Should contain "emmcclk". Although this is listed as optional
(because most boards can get basic functionality without having
access to it), it is strongly suggested.
See ../clock/clock-bindings.txt for details.
- clocks: Should have a phandle to the card clock exported by the SDHCI driver.
- drive-impedance-ohm: Specifies the drive impedance in Ohm.
Possible values are 33, 40, 50, 66 and 100.
If not set, the default value of 50 will be applied.
- rockchip,enable-strobe-pulldown: Enable internal pull-down for the strobe
line. If not set, pull-down is not used.
- rockchip,output-tapdelay-select: Specifies the phyctrl_otapdlysec register.
If not set, the register defaults to 0x4.
Maximum value 0xf.
Example:
grf: syscon@ff770000 {
compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
#address-cells = <1>;
#size-cells = <1>;
...
emmcphy: phy@f780 {
compatible = "rockchip,rk3399-emmc-phy";
reg = <0xf780 0x20>;
clocks = <&sdhci>;
clock-names = "emmcclk";
drive-impedance-ohm = <50>;
#phy-cells = <0>;
};
};
......@@ -25,6 +25,7 @@ description: |
properties:
compatible:
enum:
- google,gs101-usb31drd-phy
- samsung,exynos5250-usbdrd-phy
- samsung,exynos5420-usbdrd-phy
- samsung,exynos5433-usbdrd-phy
......@@ -57,7 +58,15 @@ properties:
the OF graph bindings specified.
reg:
maxItems: 1
minItems: 1
maxItems: 3
reg-names:
minItems: 1
items:
- const: phy
- const: pcs
- const: pma
samsung,pmu-syscon:
$ref: /schemas/types.yaml#/definitions/phandle
......@@ -72,6 +81,19 @@ properties:
description:
VBUS Boost 5V power source.
pll-supply:
description: Power supply for the USB PLL.
dvdd-usb20-supply:
description: DVDD power supply for the USB 2.0 phy.
vddh-usb20-supply:
description: VDDh power supply for the USB 2.0 phy.
vdd33-usb20-supply:
description: 3.3V power supply for the USB 2.0 phy.
vdda-usbdp-supply:
description: VDDa power supply for the USB DP phy.
vddh-usbdp-supply:
description: VDDh power supply for the USB DP phy.
required:
- compatible
- clocks
......@@ -81,6 +103,40 @@ required:
- samsung,pmu-syscon
allOf:
- if:
properties:
compatible:
contains:
const: google,gs101-usb31drd-phy
then:
properties:
clocks:
items:
- description: Gate of main PHY clock
- description: Gate of PHY reference clock
- description: Gate of control interface AXI clock
- description: Gate of control interface APB clock
- description: Gate of SCL APB clock
clock-names:
items:
- const: phy
- const: ref
- const: ctrl_aclk
- const: ctrl_pclk
- const: scl_pclk
reg:
minItems: 3
reg-names:
minItems: 3
required:
- reg-names
- pll-supply
- dvdd-usb20-supply
- vddh-usb20-supply
- vdd33-usb20-supply
- vdda-usbdp-supply
- vddh-usbdp-supply
- if:
properties:
compatible:
......@@ -100,7 +156,20 @@ allOf:
- const: phy_utmi
- const: phy_pipe
- const: itp
else:
reg:
maxItems: 1
reg-names:
maxItems: 1
- if:
properties:
compatible:
contains:
enum:
- samsung,exynos5250-usbdrd-phy
- samsung,exynos5420-usbdrd-phy
- samsung,exynos850-usbdrd-phy
then:
properties:
clocks:
minItems: 2
......@@ -109,6 +178,10 @@ allOf:
items:
- const: phy
- const: ref
reg:
maxItems: 1
reg-names:
maxItems: 1
additionalProperties: false
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/starfive,jh7110-dphy-tx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Starfive SoC MIPI D-PHY Tx Controller
maintainers:
- Keith Zhao <keith.zhao@starfivetech.com>
- Shengyang Chen <shengyang.chen@starfivetech.com>
description:
The Starfive SoC uses the MIPI DSI D-PHY based on M31 IP to transfer
DSI data.
properties:
compatible:
const: starfive,jh7110-dphy-tx
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: txesc
resets:
items:
- description: MIPITX_DPHY_SYS reset
reset-names:
items:
- const: sys
power-domains:
maxItems: 1
"#phy-cells":
const: 0
required:
- compatible
- reg
- clocks
- clock-names
- resets
- reset-names
- power-domains
- "#phy-cells"
additionalProperties: false
examples:
- |
phy@295e0000 {
compatible = "starfive,jh7110-dphy-tx";
reg = <0x295e0000 0x10000>;
clocks = <&voutcrg 14>;
clock-names = "txesc";
resets = <&syscrg 10>;
reset-names = "sys";
power-domains = <&aon_syscon 0>;
#phy-cells = <0>;
};
......@@ -176,9 +176,10 @@ allOf:
Documentation/devicetree/bindings/phy/rockchip-pcie-phy.txt
patternProperties:
"phy@[0-9a-f]+$":
description:
Documentation/devicetree/bindings/phy/rockchip-emmc-phy.txt
"^phy@[0-9a-f]+$":
type: object
$ref: /schemas/phy/rockchip,rk3399-emmc-phy.yaml#
unevaluatedProperties: false
- if:
properties:
......@@ -292,6 +293,15 @@ examples:
#phy-cells = <0>;
};
phy@f780 {
compatible = "rockchip,rk3399-emmc-phy";
reg = <0xf780 0x20>;
clocks = <&sdhci>;
clock-names = "emmcclk";
drive-impedance-ohm = <50>;
#phy-cells = <0>;
};
u2phy0: usb2phy@e450 {
compatible = "rockchip,rk3399-usb2phy";
reg = <0xe450 0x10>;
......
......@@ -702,6 +702,14 @@ S: Maintained
F: Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml
F: drivers/net/ethernet/mediatek/airoha_eth.c
AIROHA PCIE PHY DRIVER
M: Lorenzo Bianconi <lorenzo@kernel.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/phy/airoha,en7581-pcie-phy.yaml
F: drivers/phy/phy-airoha-pcie-regs.h
F: drivers/phy/phy-airoha-pcie.c
AIROHA SPI SNFI DRIVER
M: Lorenzo Bianconi <lorenzo@kernel.org>
M: Ray Liu <ray.liu@airoha.com>
......@@ -21682,6 +21690,13 @@ S: Supported
F: Documentation/devicetree/bindings/phy/starfive,jh7110-dphy-rx.yaml
F: drivers/phy/starfive/phy-jh7110-dphy-rx.c
STARFIVE JH7110 DPHY TX DRIVER
M: Keith Zhao <keith.zhao@starfivetech.com>
M: Shengyang Chen <shengyang.chen@starfivetech.com>
S: Supported
F: Documentation/devicetree/bindings/phy/starfive,jh7110-dphy-tx.yaml
F: drivers/phy/starfive/phy-jh7110-dphy-tx.c
STARFIVE JH7110 MMC/SD/SDIO DRIVER
M: William Qiu <william.qiu@starfivetech.com>
S: Supported
......
......@@ -72,6 +72,16 @@ config PHY_CAN_TRANSCEIVER
functional modes using gpios and sets the attribute max link
rate, for CAN drivers.
config PHY_AIROHA_PCIE
tristate "Airoha PCIe-PHY Driver"
depends on ARCH_AIROHA || COMPILE_TEST
depends on OF
select GENERIC_PHY
help
Say Y here to add support for Airoha PCIe PHY driver.
This driver create the basic PHY instance and provides initialize
callback for PCIe GEN3 port.
source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/amlogic/Kconfig"
source "drivers/phy/broadcom/Kconfig"
......
......@@ -10,6 +10,7 @@ obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o
obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o
obj-y += allwinner/ \
amlogic/ \
broadcom/ \
......
......@@ -162,4 +162,5 @@ static struct platform_driver bcm_ns_usb2_driver = {
};
module_platform_driver(bcm_ns_usb2_driver);
MODULE_DESCRIPTION("Broadcom Northstar USB 2.0 PHY Driver");
MODULE_LICENSE("GPL v2");
......@@ -240,5 +240,6 @@ static struct mdio_driver bcm_ns_usb3_mdio_driver = {
mdio_module_driver(bcm_ns_usb3_mdio_driver);
MODULE_DESCRIPTION("Broadcom Northstar USB 3.0 PHY Driver");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(of, bcm_ns_usb3_id_table);
......@@ -360,6 +360,7 @@ struct cdns_torrent_phy {
enum cdns_torrent_ref_clk ref_clk1_rate;
struct cdns_torrent_inst phys[MAX_NUM_LANES];
int nsubnodes;
int already_configured;
const struct cdns_torrent_data *init_data;
struct regmap *regmap_common_cdb;
struct regmap *regmap_phy_pcs_common_cdb;
......@@ -1156,6 +1157,9 @@ static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy,
ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_POWER_STATE_ACK,
read_val, (read_val & mask) == value, 0,
POLL_TIMEOUT_US);
if (ret)
return ret;
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, 0x00000000);
ndelay(100);
......@@ -1594,6 +1598,9 @@ static int cdns_torrent_dp_configure(struct phy *phy,
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
int ret;
if (cdns_phy->already_configured)
return 0;
ret = cdns_torrent_dp_verify_config(inst, &opts->dp);
if (ret) {
dev_err(&phy->dev, "invalid params for phy configure\n");
......@@ -1629,6 +1636,12 @@ static int cdns_torrent_phy_on(struct phy *phy)
u32 read_val;
int ret;
if (cdns_phy->already_configured) {
/* Give 5ms to 10ms delay for the PIPE clock to be stable */
usleep_range(5000, 10000);
return 0;
}
if (cdns_phy->nsubnodes == 1) {
/* Take the PHY lane group out of reset */
reset_control_deassert(inst->lnk_rst);
......@@ -2307,6 +2320,9 @@ static int cdns_torrent_phy_init(struct phy *phy)
u32 num_regs;
int i, j;
if (cdns_phy->already_configured)
return 0;
if (cdns_phy->nsubnodes > 1) {
if (phy_type == TYPE_DP)
return cdns_torrent_dp_multilink_init(cdns_phy, inst, phy);
......@@ -2444,19 +2460,6 @@ 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,
};
static
int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy)
{
......@@ -2678,7 +2681,7 @@ static int cdns_torrent_clk_register(struct cdns_torrent_phy *cdns_phy)
return 0;
}
static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy)
static int cdns_torrent_of_get_reset(struct cdns_torrent_phy *cdns_phy)
{
struct device *dev = cdns_phy->dev;
......@@ -2699,20 +2702,29 @@ static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy)
return 0;
}
static int cdns_torrent_of_get_clk(struct cdns_torrent_phy *cdns_phy)
{
/* refclk: Input reference clock for PLL0 */
cdns_phy->clk = devm_clk_get(cdns_phy->dev, "refclk");
if (IS_ERR(cdns_phy->clk))
return dev_err_probe(cdns_phy->dev, PTR_ERR(cdns_phy->clk),
"phy ref clock not found\n");
/* refclk1: Input reference clock for PLL1 */
cdns_phy->clk1 = devm_clk_get_optional(cdns_phy->dev, "pll1_refclk");
if (IS_ERR(cdns_phy->clk1))
return dev_err_probe(cdns_phy->dev, PTR_ERR(cdns_phy->clk1),
"phy PLL1 ref clock not found\n");
return 0;
}
static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy)
{
struct device *dev = cdns_phy->dev;
unsigned long ref_clk1_rate;
unsigned long ref_clk_rate;
int ret;
/* refclk: Input reference clock for PLL0 */
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: %d\n", ret);
......@@ -2745,14 +2757,6 @@ static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy)
goto disable_clk;
}
/* refclk1: Input reference clock for PLL1 */
cdns_phy->clk1 = devm_clk_get_optional(dev, "pll1_refclk");
if (IS_ERR(cdns_phy->clk1)) {
dev_err(dev, "phy PLL1 ref clock not found\n");
ret = PTR_ERR(cdns_phy->clk1);
goto disable_clk;
}
if (cdns_phy->clk1) {
ret = clk_prepare_enable(cdns_phy->clk1);
if (ret) {
......@@ -2807,7 +2811,6 @@ 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;
......@@ -2846,13 +2849,17 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
if (ret)
return ret;
regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &already_configured);
ret = cdns_torrent_of_get_reset(cdns_phy);
if (ret)
goto clk_cleanup;
if (!already_configured) {
ret = cdns_torrent_reset(cdns_phy);
if (ret)
goto clk_cleanup;
ret = cdns_torrent_of_get_clk(cdns_phy);
if (ret)
goto clk_cleanup;
regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &cdns_phy->already_configured);
if (!cdns_phy->already_configured) {
ret = cdns_torrent_clk(cdns_phy);
if (ret)
goto clk_cleanup;
......@@ -2932,10 +2939,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
of_property_read_u32(child, "cdns,ssc-mode",
&cdns_phy->phys[node].ssc_mode);
if (!already_configured)
gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops);
else
gphy = devm_phy_create(dev, child, &noop_ops);
gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops);
if (IS_ERR(gphy)) {
ret = PTR_ERR(gphy);
goto put_child;
......@@ -3018,7 +3022,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
goto put_lnk_rst;
}
if (cdns_phy->nsubnodes > 1 && !already_configured) {
if (cdns_phy->nsubnodes > 1 && !cdns_phy->already_configured) {
ret = cdns_torrent_phy_configure_multilink(cdns_phy);
if (ret)
goto put_lnk_rst;
......@@ -3074,6 +3078,82 @@ static void cdns_torrent_phy_remove(struct platform_device *pdev)
cdns_torrent_clk_cleanup(cdns_phy);
}
/* SGMII and QSGMII link configuration */
static struct cdns_reg_pairs sgmii_qsgmii_link_cmn_regs[] = {
{0x0002, PHY_PLL_CFG}
};
static struct cdns_reg_pairs sgmii_qsgmii_xcvr_diag_ln_regs[] = {
{0x0003, XCVR_DIAG_HSCLK_DIV},
{0x0113, XCVR_DIAG_PLLDRC_CTRL}
};
static struct cdns_torrent_vals sgmii_qsgmii_link_cmn_vals = {
.reg_pairs = sgmii_qsgmii_link_cmn_regs,
.num_regs = ARRAY_SIZE(sgmii_qsgmii_link_cmn_regs),
};
static struct cdns_torrent_vals sgmii_qsgmii_xcvr_diag_ln_vals = {
.reg_pairs = sgmii_qsgmii_xcvr_diag_ln_regs,
.num_regs = ARRAY_SIZE(sgmii_qsgmii_xcvr_diag_ln_regs),
};
static int cdns_torrent_phy_suspend_noirq(struct device *dev)
{
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(dev);
int i;
reset_control_assert(cdns_phy->phy_rst);
reset_control_assert(cdns_phy->apb_rst);
for (i = 0; i < cdns_phy->nsubnodes; i++)
reset_control_assert(cdns_phy->phys[i].lnk_rst);
if (cdns_phy->already_configured)
cdns_phy->already_configured = 0;
else {
clk_disable_unprepare(cdns_phy->clk1);
clk_disable_unprepare(cdns_phy->clk);
}
return 0;
}
static int cdns_torrent_phy_resume_noirq(struct device *dev)
{
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(dev);
int node = cdns_phy->nsubnodes;
int ret, i;
ret = cdns_torrent_clk(cdns_phy);
if (ret)
return ret;
/* Enable APB */
reset_control_deassert(cdns_phy->apb_rst);
if (cdns_phy->nsubnodes > 1) {
ret = cdns_torrent_phy_configure_multilink(cdns_phy);
if (ret)
goto put_lnk_rst;
}
return 0;
put_lnk_rst:
for (i = 0; i < node; i++)
reset_control_assert(cdns_phy->phys[i].lnk_rst);
reset_control_assert(cdns_phy->apb_rst);
clk_disable_unprepare(cdns_phy->clk1);
clk_disable_unprepare(cdns_phy->clk);
return ret;
}
static DEFINE_NOIRQ_DEV_PM_OPS(cdns_torrent_phy_pm_ops,
cdns_torrent_phy_suspend_noirq,
cdns_torrent_phy_resume_noirq);
/* USB and DP link configuration */
static struct cdns_reg_pairs usb_dp_link_cmn_regs[] = {
{0x0002, PHY_PLL_CFG},
......@@ -4043,7 +4123,8 @@ static struct cdns_reg_pairs sgmii_100_no_ssc_tx_ln_regs[] = {
{0x04A2, TX_PSC_A2},
{0x04A2, TX_PSC_A3},
{0x0000, TX_TXCC_CPOST_MULT_00},
{0x00B3, DRV_DIAG_TX_DRV}
{0x00B3, DRV_DIAG_TX_DRV},
{0x0002, XCVR_DIAG_PSC_OVRD}
};
static struct cdns_reg_pairs ti_sgmii_100_no_ssc_tx_ln_regs[] = {
......@@ -4052,7 +4133,8 @@ static struct cdns_reg_pairs ti_sgmii_100_no_ssc_tx_ln_regs[] = {
{0x04A2, TX_PSC_A3},
{0x0000, TX_TXCC_CPOST_MULT_00},
{0x00B3, DRV_DIAG_TX_DRV},
{0x4000, XCVR_DIAG_RXCLK_CTRL},
{0x0002, XCVR_DIAG_PSC_OVRD},
{0x4000, XCVR_DIAG_RXCLK_CTRL}
};
static struct cdns_reg_pairs sgmii_100_no_ssc_rx_ln_regs[] = {
......@@ -4219,7 +4301,8 @@ static struct cdns_reg_pairs qsgmii_100_no_ssc_tx_ln_regs[] = {
{0x04A2, TX_PSC_A3},
{0x0000, TX_TXCC_CPOST_MULT_00},
{0x0011, TX_TXCC_MGNFS_MULT_100},
{0x0003, DRV_DIAG_TX_DRV}
{0x0003, DRV_DIAG_TX_DRV},
{0x0002, XCVR_DIAG_PSC_OVRD}
};
static struct cdns_reg_pairs ti_qsgmii_100_no_ssc_tx_ln_regs[] = {
......@@ -4229,7 +4312,8 @@ static struct cdns_reg_pairs ti_qsgmii_100_no_ssc_tx_ln_regs[] = {
{0x0000, TX_TXCC_CPOST_MULT_00},
{0x0011, TX_TXCC_MGNFS_MULT_100},
{0x0003, DRV_DIAG_TX_DRV},
{0x4000, XCVR_DIAG_RXCLK_CTRL},
{0x0002, XCVR_DIAG_PSC_OVRD},
{0x4000, XCVR_DIAG_RXCLK_CTRL}
};
static struct cdns_reg_pairs qsgmii_100_no_ssc_rx_ln_regs[] = {
......@@ -4541,11 +4625,13 @@ static struct cdns_torrent_vals_entry link_cmn_vals_entries[] = {
{CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_NONE), &sl_sgmii_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_PCIE), &pcie_sgmii_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_QSGMII), &sgmii_qsgmii_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USB), &usb_sgmii_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USXGMII), &usxgmii_sgmii_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_NONE), &sl_sgmii_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_PCIE), &pcie_sgmii_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_SGMII), &sgmii_qsgmii_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USB), &usb_sgmii_link_cmn_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USXGMII), &usxgmii_sgmii_link_cmn_vals},
......@@ -4575,11 +4661,13 @@ static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = {
{CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_NONE), &sl_sgmii_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_PCIE), &sgmii_pcie_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_QSGMII), &sgmii_qsgmii_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USB), &sgmii_usb_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USXGMII), &sgmii_usxgmii_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_NONE), &sl_sgmii_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_PCIE), &sgmii_pcie_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_SGMII), &sgmii_qsgmii_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USB), &sgmii_usb_xcvr_diag_ln_vals},
{CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USXGMII), &sgmii_usxgmii_xcvr_diag_ln_vals},
......@@ -4635,6 +4723,8 @@ static struct cdns_torrent_vals_entry cmn_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_int_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sl_sgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals},
......@@ -4645,6 +4735,8 @@ static struct cdns_torrent_vals_entry cmn_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_int_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &sl_qsgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals},
......@@ -4713,6 +4805,8 @@ static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals},
......@@ -4723,6 +4817,8 @@ static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals},
......@@ -4791,6 +4887,8 @@ static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals},
......@@ -4801,6 +4899,8 @@ static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
......@@ -4905,6 +5005,8 @@ static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
......@@ -4915,6 +5017,8 @@ static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
......@@ -5017,6 +5121,8 @@ static struct cdns_torrent_vals_entry ti_j7200_cmn_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_int_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sl_sgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals},
......@@ -5027,6 +5133,8 @@ static struct cdns_torrent_vals_entry ti_j7200_cmn_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_int_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &sl_qsgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals},
......@@ -5095,6 +5203,8 @@ static struct cdns_torrent_vals_entry ti_j7200_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals},
......@@ -5105,6 +5215,8 @@ static struct cdns_torrent_vals_entry ti_j7200_tx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals},
......@@ -5173,6 +5285,8 @@ static struct cdns_torrent_vals_entry ti_j7200_rx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals},
......@@ -5183,6 +5297,8 @@ static struct cdns_torrent_vals_entry ti_j7200_rx_ln_vals_entries[] = {
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
{CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals},
......@@ -5275,6 +5391,7 @@ static struct platform_driver cdns_torrent_phy_driver = {
.driver = {
.name = "cdns-torrent-phy",
.of_match_table = cdns_torrent_phy_of_match,
.pm = pm_sleep_ptr(&cdns_torrent_phy_pm_ops),
}
};
module_platform_driver(cdns_torrent_phy_driver);
......
......@@ -35,12 +35,19 @@ config PHY_FSL_IMX8M_PCIE
Enable this to add support for the PCIE PHY as found on
i.MX8M family of SOCs.
config PHY_FSL_IMX8QM_HSIO
tristate "Freescale i.MX8QM HSIO PHY"
depends on OF && HAS_IOMEM
select GENERIC_PHY
help
Enable this to add support for the HSIO PHY as found on
i.MX8QM family of SOCs.
config PHY_FSL_SAMSUNG_HDMI_PHY
tristate "Samsung HDMI PHY support"
depends on OF && HAS_IOMEM && COMMON_CLK
help
Enable this to add support for the Samsung HDMI PHY in i.MX8MP.
endif
config PHY_FSL_LYNX_28G
......
......@@ -3,5 +3,6 @@ obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o
obj-$(CONFIG_PHY_MIXEL_LVDS_PHY) += phy-fsl-imx8qm-lvds-phy.o
obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o
obj-$(CONFIG_PHY_FSL_IMX8M_PCIE) += phy-fsl-imx8m-pcie.o
obj-$(CONFIG_PHY_FSL_IMX8QM_HSIO) += phy-fsl-imx8qm-hsio.o
obj-$(CONFIG_PHY_FSL_LYNX_28G) += phy-fsl-lynx-28g.o
obj-$(CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY) += phy-fsl-samsung-hdmi.o
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2024 NXP
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pci_regs.h>
#include <linux/phy/phy.h>
#include <linux/phy/pcie.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <dt-bindings/phy/phy.h>
#include <dt-bindings/phy/phy-imx8-pcie.h>
#define MAX_NUM_LANE 3
#define LANE_NUM_CLKS 5
/* Parameters for the waiting for PCIe PHY PLL to lock */
#define PHY_INIT_WAIT_USLEEP_MAX 10
#define PHY_INIT_WAIT_TIMEOUT (1000 * PHY_INIT_WAIT_USLEEP_MAX)
/* i.MX8Q HSIO registers */
#define HSIO_CTRL0 0x0
#define HSIO_APB_RSTN_0 BIT(0)
#define HSIO_APB_RSTN_1 BIT(1)
#define HSIO_PIPE_RSTN_0_MASK GENMASK(25, 24)
#define HSIO_PIPE_RSTN_1_MASK GENMASK(27, 26)
#define HSIO_MODE_MASK GENMASK(20, 17)
#define HSIO_MODE_PCIE 0x0
#define HSIO_MODE_SATA 0x4
#define HSIO_DEVICE_TYPE_MASK GENMASK(27, 24)
#define HSIO_EPCS_TXDEEMP BIT(5)
#define HSIO_EPCS_TXDEEMP_SEL BIT(6)
#define HSIO_EPCS_PHYRESET_N BIT(7)
#define HSIO_RESET_N BIT(12)
#define HSIO_IOB_RXENA BIT(0)
#define HSIO_IOB_TXENA BIT(1)
#define HSIO_IOB_A_0_TXOE BIT(2)
#define HSIO_IOB_A_0_M1M0_2 BIT(4)
#define HSIO_IOB_A_0_M1M0_MASK GENMASK(4, 3)
#define HSIO_PHYX1_EPCS_SEL BIT(12)
#define HSIO_PCIE_AB_SELECT BIT(13)
#define HSIO_PHY_STS0 0x4
#define HSIO_LANE0_TX_PLL_LOCK BIT(4)
#define HSIO_LANE1_TX_PLL_LOCK BIT(12)
#define HSIO_CTRL2 0x8
#define HSIO_LTSSM_ENABLE BIT(4)
#define HSIO_BUTTON_RST_N BIT(21)
#define HSIO_PERST_N BIT(22)
#define HSIO_POWER_UP_RST_N BIT(23)
#define HSIO_PCIE_STS0 0xc
#define HSIO_PM_REQ_CORE_RST BIT(19)
#define HSIO_REG48_PMA_STATUS 0x30
#define HSIO_REG48_PMA_RDY BIT(7)
struct imx_hsio_drvdata {
int lane_num;
};
struct imx_hsio_lane {
u32 ctrl_index;
u32 ctrl_off;
u32 idx;
u32 phy_off;
u32 phy_type;
const char * const *clk_names;
struct clk_bulk_data clks[LANE_NUM_CLKS];
struct imx_hsio_priv *priv;
struct phy *phy;
enum phy_mode phy_mode;
};
struct imx_hsio_priv {
void __iomem *base;
struct device *dev;
struct mutex lock;
const char *hsio_cfg;
const char *refclk_pad;
u32 open_cnt;
struct regmap *phy;
struct regmap *ctrl;
struct regmap *misc;
const struct imx_hsio_drvdata *drvdata;
struct imx_hsio_lane lane[MAX_NUM_LANE];
};
static const char * const lan0_pcie_clks[] = {"apb_pclk0", "pclk0", "ctl0_crr",
"phy0_crr", "misc_crr"};
static const char * const lan1_pciea_clks[] = {"apb_pclk1", "pclk1", "ctl0_crr",
"phy0_crr", "misc_crr"};
static const char * const lan1_pcieb_clks[] = {"apb_pclk1", "pclk1", "ctl1_crr",
"phy0_crr", "misc_crr"};
static const char * const lan2_pcieb_clks[] = {"apb_pclk2", "pclk2", "ctl1_crr",
"phy1_crr", "misc_crr"};
static const char * const lan2_sata_clks[] = {"pclk2", "epcs_tx", "epcs_rx",
"phy1_crr", "misc_crr"};
static const struct regmap_config regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
static int imx_hsio_init(struct phy *phy)
{
int ret, i;
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
struct device *dev = priv->dev;
/* Assign clocks refer to different modes */
switch (lane->phy_type) {
case PHY_TYPE_PCIE:
lane->phy_mode = PHY_MODE_PCIE;
if (lane->ctrl_index == 0) { /* PCIEA */
lane->ctrl_off = 0;
lane->phy_off = 0;
for (i = 0; i < LANE_NUM_CLKS; i++) {
if (lane->idx == 0)
lane->clks[i].id = lan0_pcie_clks[i];
else
lane->clks[i].id = lan1_pciea_clks[i];
}
} else { /* PCIEB */
if (lane->idx == 0) { /* i.MX8QXP */
lane->ctrl_off = 0;
lane->phy_off = 0;
} else {
/*
* On i.MX8QM, only second or third lane can be
* bound to PCIEB.
*/
lane->ctrl_off = SZ_64K;
if (lane->idx == 1)
lane->phy_off = 0;
else /* the third lane is bound to PCIEB */
lane->phy_off = SZ_64K;
}
for (i = 0; i < LANE_NUM_CLKS; i++) {
if (lane->idx == 1)
lane->clks[i].id = lan1_pcieb_clks[i];
else if (lane->idx == 2)
lane->clks[i].id = lan2_pcieb_clks[i];
else /* i.MX8QXP only has PCIEB, idx is 0 */
lane->clks[i].id = lan0_pcie_clks[i];
}
}
break;
case PHY_TYPE_SATA:
/* On i.MX8QM, only the third lane can be bound to SATA */
lane->phy_mode = PHY_MODE_SATA;
lane->ctrl_off = SZ_128K;
lane->phy_off = SZ_64K;
for (i = 0; i < LANE_NUM_CLKS; i++)
lane->clks[i].id = lan2_sata_clks[i];
break;
default:
return -EINVAL;
}
/* Fetch clocks and enable them */
ret = devm_clk_bulk_get(dev, LANE_NUM_CLKS, lane->clks);
if (ret)
return ret;
ret = clk_bulk_prepare_enable(LANE_NUM_CLKS, lane->clks);
if (ret)
return ret;
/* allow the clocks to stabilize */
usleep_range(200, 500);
return 0;
}
static int imx_hsio_exit(struct phy *phy)
{
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
clk_bulk_disable_unprepare(LANE_NUM_CLKS, lane->clks);
return 0;
}
static void imx_hsio_pcie_phy_resets(struct phy *phy)
{
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
regmap_clear_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2,
HSIO_BUTTON_RST_N);
regmap_clear_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2,
HSIO_PERST_N);
regmap_clear_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2,
HSIO_POWER_UP_RST_N);
regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2,
HSIO_BUTTON_RST_N);
regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2,
HSIO_PERST_N);
regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2,
HSIO_POWER_UP_RST_N);
if (lane->idx == 1) {
regmap_set_bits(priv->phy, lane->phy_off + HSIO_CTRL0,
HSIO_APB_RSTN_1);
regmap_set_bits(priv->phy, lane->phy_off + HSIO_CTRL0,
HSIO_PIPE_RSTN_1_MASK);
} else {
regmap_set_bits(priv->phy, lane->phy_off + HSIO_CTRL0,
HSIO_APB_RSTN_0);
regmap_set_bits(priv->phy, lane->phy_off + HSIO_CTRL0,
HSIO_PIPE_RSTN_0_MASK);
}
}
static void imx_hsio_sata_phy_resets(struct phy *phy)
{
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
/* clear PHY RST, then set it */
regmap_clear_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0,
HSIO_EPCS_PHYRESET_N);
regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0,
HSIO_EPCS_PHYRESET_N);
/* CTRL RST: SET -> delay 1 us -> CLEAR -> SET */
regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0, HSIO_RESET_N);
udelay(1);
regmap_clear_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0,
HSIO_RESET_N);
regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0, HSIO_RESET_N);
}
static void imx_hsio_configure_clk_pad(struct phy *phy)
{
bool pll = false;
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
if (strncmp(priv->refclk_pad, "output", 6) == 0) {
pll = true;
regmap_update_bits(priv->misc, HSIO_CTRL0,
HSIO_IOB_A_0_TXOE | HSIO_IOB_A_0_M1M0_MASK,
HSIO_IOB_A_0_TXOE | HSIO_IOB_A_0_M1M0_2);
} else {
regmap_update_bits(priv->misc, HSIO_CTRL0,
HSIO_IOB_A_0_TXOE | HSIO_IOB_A_0_M1M0_MASK,
0);
}
regmap_update_bits(priv->misc, HSIO_CTRL0, HSIO_IOB_RXENA,
pll ? 0 : HSIO_IOB_RXENA);
regmap_update_bits(priv->misc, HSIO_CTRL0, HSIO_IOB_TXENA,
pll ? HSIO_IOB_TXENA : 0);
}
static void imx_hsio_pre_set(struct phy *phy)
{
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
if (strncmp(priv->hsio_cfg, "pciea-x2-pcieb", 14) == 0) {
regmap_set_bits(priv->misc, HSIO_CTRL0, HSIO_PCIE_AB_SELECT);
} else if (strncmp(priv->hsio_cfg, "pciea-x2-sata", 13) == 0) {
regmap_set_bits(priv->misc, HSIO_CTRL0, HSIO_PHYX1_EPCS_SEL);
} else if (strncmp(priv->hsio_cfg, "pciea-pcieb-sata", 16) == 0) {
regmap_set_bits(priv->misc, HSIO_CTRL0, HSIO_PCIE_AB_SELECT);
regmap_set_bits(priv->misc, HSIO_CTRL0, HSIO_PHYX1_EPCS_SEL);
}
imx_hsio_configure_clk_pad(phy);
}
static int imx_hsio_pcie_power_on(struct phy *phy)
{
int ret;
u32 val, addr, cond;
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
imx_hsio_pcie_phy_resets(phy);
/* Toggle apb_pclk to make sure PM_REQ_CORE_RST is cleared. */
clk_disable_unprepare(lane->clks[0].clk);
mdelay(1);
ret = clk_prepare_enable(lane->clks[0].clk);
if (ret) {
dev_err(priv->dev, "unable to enable phy apb_pclk\n");
return ret;
}
addr = lane->ctrl_off + HSIO_PCIE_STS0;
cond = HSIO_PM_REQ_CORE_RST;
ret = regmap_read_poll_timeout(priv->ctrl, addr, val,
(val & cond) == 0,
PHY_INIT_WAIT_USLEEP_MAX,
PHY_INIT_WAIT_TIMEOUT);
if (ret)
dev_err(priv->dev, "HSIO_PM_REQ_CORE_RST is set\n");
return ret;
}
static int imx_hsio_sata_power_on(struct phy *phy)
{
int ret;
u32 val, cond;
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
regmap_set_bits(priv->phy, lane->phy_off + HSIO_CTRL0, HSIO_APB_RSTN_0);
regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0,
HSIO_EPCS_TXDEEMP);
regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0,
HSIO_EPCS_TXDEEMP_SEL);
imx_hsio_sata_phy_resets(phy);
cond = HSIO_REG48_PMA_RDY;
ret = read_poll_timeout(readb, val, ((val & cond) == cond),
PHY_INIT_WAIT_USLEEP_MAX,
PHY_INIT_WAIT_TIMEOUT, false,
priv->base + HSIO_REG48_PMA_STATUS);
if (ret)
dev_err(priv->dev, "PHY calibration is timeout\n");
else
dev_dbg(priv->dev, "PHY calibration is done\n");
return ret;
}
static int imx_hsio_power_on(struct phy *phy)
{
int ret;
u32 val, cond;
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
scoped_guard(mutex, &priv->lock) {
if (!priv->open_cnt)
imx_hsio_pre_set(phy);
priv->open_cnt++;
}
if (lane->phy_mode == PHY_MODE_PCIE)
ret = imx_hsio_pcie_power_on(phy);
else /* SATA */
ret = imx_hsio_sata_power_on(phy);
if (ret)
return ret;
/* Polling to check the PHY is ready or not. */
if (lane->idx == 1)
cond = HSIO_LANE1_TX_PLL_LOCK;
else
/*
* Except the phy_off, the bit-offset of lane2 is same to lane0.
* Merge the lane0 and lane2 bit-operations together.
*/
cond = HSIO_LANE0_TX_PLL_LOCK;
ret = regmap_read_poll_timeout(priv->phy, lane->phy_off + HSIO_PHY_STS0,
val, ((val & cond) == cond),
PHY_INIT_WAIT_USLEEP_MAX,
PHY_INIT_WAIT_TIMEOUT);
if (ret) {
dev_err(priv->dev, "IMX8Q PHY%d PLL lock timeout\n", lane->idx);
return ret;
}
dev_dbg(priv->dev, "IMX8Q PHY%d PLL is locked\n", lane->idx);
return ret;
}
static int imx_hsio_power_off(struct phy *phy)
{
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
scoped_guard(mutex, &priv->lock) {
priv->open_cnt--;
if (priv->open_cnt == 0) {
regmap_clear_bits(priv->misc, HSIO_CTRL0,
HSIO_PCIE_AB_SELECT);
regmap_clear_bits(priv->misc, HSIO_CTRL0,
HSIO_PHYX1_EPCS_SEL);
if (lane->phy_mode == PHY_MODE_PCIE) {
regmap_clear_bits(priv->ctrl,
lane->ctrl_off + HSIO_CTRL2,
HSIO_BUTTON_RST_N);
regmap_clear_bits(priv->ctrl,
lane->ctrl_off + HSIO_CTRL2,
HSIO_PERST_N);
regmap_clear_bits(priv->ctrl,
lane->ctrl_off + HSIO_CTRL2,
HSIO_POWER_UP_RST_N);
} else {
regmap_clear_bits(priv->ctrl,
lane->ctrl_off + HSIO_CTRL0,
HSIO_EPCS_TXDEEMP);
regmap_clear_bits(priv->ctrl,
lane->ctrl_off + HSIO_CTRL0,
HSIO_EPCS_TXDEEMP_SEL);
regmap_clear_bits(priv->ctrl,
lane->ctrl_off + HSIO_CTRL0,
HSIO_RESET_N);
}
if (lane->idx == 1) {
regmap_clear_bits(priv->phy,
lane->phy_off + HSIO_CTRL0,
HSIO_APB_RSTN_1);
regmap_clear_bits(priv->phy,
lane->phy_off + HSIO_CTRL0,
HSIO_PIPE_RSTN_1_MASK);
} else {
/*
* Except the phy_off, the bit-offset of lane2 is same
* to lane0. Merge the lane0 and lane2 bit-operations
* together.
*/
regmap_clear_bits(priv->phy,
lane->phy_off + HSIO_CTRL0,
HSIO_APB_RSTN_0);
regmap_clear_bits(priv->phy,
lane->phy_off + HSIO_CTRL0,
HSIO_PIPE_RSTN_0_MASK);
}
}
}
return 0;
}
static int imx_hsio_set_mode(struct phy *phy, enum phy_mode mode,
int submode)
{
u32 val;
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
if (lane->phy_mode != mode)
return -EINVAL;
val = (mode == PHY_MODE_PCIE) ? HSIO_MODE_PCIE : HSIO_MODE_SATA;
val = FIELD_PREP(HSIO_MODE_MASK, val);
regmap_update_bits(priv->phy, lane->phy_off + HSIO_CTRL0,
HSIO_MODE_MASK, val);
switch (submode) {
case PHY_MODE_PCIE_RC:
val = FIELD_PREP(HSIO_DEVICE_TYPE_MASK, PCI_EXP_TYPE_ROOT_PORT);
break;
case PHY_MODE_PCIE_EP:
val = FIELD_PREP(HSIO_DEVICE_TYPE_MASK, PCI_EXP_TYPE_ENDPOINT);
break;
default: /* Support only PCIe EP and RC now. */
return 0;
}
if (submode)
regmap_update_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0,
HSIO_DEVICE_TYPE_MASK, val);
return 0;
}
static int imx_hsio_set_speed(struct phy *phy, int speed)
{
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
regmap_update_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2,
HSIO_LTSSM_ENABLE,
speed ? HSIO_LTSSM_ENABLE : 0);
return 0;
}
static const struct phy_ops imx_hsio_ops = {
.init = imx_hsio_init,
.exit = imx_hsio_exit,
.power_on = imx_hsio_power_on,
.power_off = imx_hsio_power_off,
.set_mode = imx_hsio_set_mode,
.set_speed = imx_hsio_set_speed,
.owner = THIS_MODULE,
};
static const struct imx_hsio_drvdata imx8qxp_hsio_drvdata = {
.lane_num = 0x1,
};
static const struct imx_hsio_drvdata imx8qm_hsio_drvdata = {
.lane_num = 0x3,
};
static const struct of_device_id imx_hsio_of_match[] = {
{.compatible = "fsl,imx8qm-hsio", .data = &imx8qm_hsio_drvdata},
{.compatible = "fsl,imx8qxp-hsio", .data = &imx8qxp_hsio_drvdata},
{ },
};
MODULE_DEVICE_TABLE(of, imx_hsio_of_match);
static struct phy *imx_hsio_xlate(struct device *dev,
const struct of_phandle_args *args)
{
struct imx_hsio_priv *priv = dev_get_drvdata(dev);
int idx = args->args[0];
int phy_type = args->args[1];
int ctrl_index = args->args[2];
if (idx < 0 || idx >= priv->drvdata->lane_num)
return ERR_PTR(-EINVAL);
priv->lane[idx].idx = idx;
priv->lane[idx].phy_type = phy_type;
priv->lane[idx].ctrl_index = ctrl_index;
return priv->lane[idx].phy;
}
static int imx_hsio_probe(struct platform_device *pdev)
{
int i;
void __iomem *off;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct imx_hsio_priv *priv;
struct phy_provider *provider;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = &pdev->dev;
priv->drvdata = of_device_get_match_data(dev);
/* Get HSIO configuration mode */
if (of_property_read_string(np, "fsl,hsio-cfg", &priv->hsio_cfg))
priv->hsio_cfg = "pciea-pcieb-sata";
/* Get PHY refclk pad mode */
if (of_property_read_string(np, "fsl,refclk-pad-mode",
&priv->refclk_pad))
priv->refclk_pad = NULL;
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
off = devm_platform_ioremap_resource_byname(pdev, "phy");
priv->phy = devm_regmap_init_mmio(dev, off, &regmap_config);
if (IS_ERR(priv->phy))
return dev_err_probe(dev, PTR_ERR(priv->phy),
"unable to find phy csr registers\n");
off = devm_platform_ioremap_resource_byname(pdev, "ctrl");
priv->ctrl = devm_regmap_init_mmio(dev, off, &regmap_config);
if (IS_ERR(priv->ctrl))
return dev_err_probe(dev, PTR_ERR(priv->ctrl),
"unable to find ctrl csr registers\n");
off = devm_platform_ioremap_resource_byname(pdev, "misc");
priv->misc = devm_regmap_init_mmio(dev, off, &regmap_config);
if (IS_ERR(priv->misc))
return dev_err_probe(dev, PTR_ERR(priv->misc),
"unable to find misc csr registers\n");
for (i = 0; i < priv->drvdata->lane_num; i++) {
struct imx_hsio_lane *lane = &priv->lane[i];
struct phy *phy;
phy = devm_phy_create(&pdev->dev, NULL, &imx_hsio_ops);
if (IS_ERR(phy))
return PTR_ERR(phy);
lane->priv = priv;
lane->phy = phy;
lane->idx = i;
phy_set_drvdata(phy, lane);
}
dev_set_drvdata(dev, priv);
dev_set_drvdata(&pdev->dev, priv);
provider = devm_of_phy_provider_register(&pdev->dev, imx_hsio_xlate);
return PTR_ERR_OR_ZERO(provider);
}
static struct platform_driver imx_hsio_driver = {
.probe = imx_hsio_probe,
.driver = {
.name = "imx8qm-hsio-phy",
.of_match_table = imx_hsio_of_match,
}
};
module_platform_driver(imx_hsio_driver);
MODULE_DESCRIPTION("FSL IMX8QM HSIO SERDES PHY driver");
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2024 AIROHA Inc
* Author: Lorenzo Bianconi <lorenzo@kernel.org>
*/
#ifndef _PHY_AIROHA_PCIE_H
#define _PHY_AIROHA_PCIE_H
/* CSR_2L */
#define REG_CSR_2L_CMN 0x0000
#define CSR_2L_PXP_CMN_LANE_EN BIT(0)
#define CSR_2L_PXP_CMN_TRIM_MASK GENMASK(28, 24)
#define REG_CSR_2L_JCPLL_IB_EXT 0x0004
#define REG_CSR_2L_JCPLL_LPF_SHCK_EN BIT(8)
#define CSR_2L_PXP_JCPLL_CHP_IBIAS GENMASK(21, 16)
#define CSR_2L_PXP_JCPLL_CHP_IOFST GENMASK(29, 24)
#define REG_CSR_2L_JCPLL_LPF_BR 0x0008
#define CSR_2L_PXP_JCPLL_LPF_BR GENMASK(4, 0)
#define CSR_2L_PXP_JCPLL_LPF_BC GENMASK(12, 8)
#define CSR_2L_PXP_JCPLL_LPF_BP GENMASK(20, 16)
#define CSR_2L_PXP_JCPLL_LPF_BWR GENMASK(28, 24)
#define REG_CSR_2L_JCPLL_LPF_BWC 0x000c
#define CSR_2L_PXP_JCPLL_LPF_BWC GENMASK(4, 0)
#define CSR_2L_PXP_JCPLL_KBAND_CODE GENMASK(23, 16)
#define CSR_2L_PXP_JCPLL_KBAND_DIV GENMASK(26, 24)
#define REG_CSR_2L_JCPLL_KBAND_KFC 0x0010
#define CSR_2L_PXP_JCPLL_KBAND_KFC GENMASK(1, 0)
#define CSR_2L_PXP_JCPLL_KBAND_KF GENMASK(9, 8)
#define CSR_2L_PXP_JCPLL_KBAND_KS GENMASK(17, 16)
#define CSR_2L_PXP_JCPLL_POSTDIV_EN BIT(24)
#define REG_CSR_2L_JCPLL_MMD_PREDIV_MODE 0x0014
#define CSR_2L_PXP_JCPLL_MMD_PREDIV_MODE GENMASK(1, 0)
#define CSR_2L_PXP_JCPLL_POSTDIV_D2 BIT(16)
#define CSR_2L_PXP_JCPLL_POSTDIV_D5 BIT(24)
#define CSR_2L_PXP_JCPLL_MONCK 0x0018
#define CSR_2L_PXP_JCPLL_REFIN_DIV GENMASK(25, 24)
#define REG_CSR_2L_JCPLL_RST_DLY 0x001c
#define CSR_2L_PXP_JCPLL_RST_DLY GENMASK(2, 0)
#define CSR_2L_PXP_JCPLL_RST BIT(8)
#define CSR_2L_PXP_JCPLL_SDM_DI_EN BIT(16)
#define CSR_2L_PXP_JCPLL_SDM_DI_LS GENMASK(25, 24)
#define REG_CSR_2L_JCPLL_SDM_IFM 0x0020
#define CSR_2L_PXP_JCPLL_SDM_IFM BIT(0)
#define REG_CSR_2L_JCPLL_SDM_HREN 0x0024
#define CSR_2L_PXP_JCPLL_SDM_HREN BIT(0)
#define CSR_2L_PXP_JCPLL_TCL_AMP_EN BIT(8)
#define CSR_2L_PXP_JCPLL_TCL_AMP_GAIN GENMASK(18, 16)
#define CSR_2L_PXP_JCPLL_TCL_AMP_VREF GENMASK(28, 24)
#define REG_CSR_2L_JCPLL_TCL_CMP 0x0028
#define CSR_2L_PXP_JCPLL_TCL_LPF_EN BIT(16)
#define CSR_2L_PXP_JCPLL_TCL_LPF_BW GENMASK(26, 24)
#define REG_CSR_2L_JCPLL_VCODIV 0x002c
#define CSR_2L_PXP_JCPLL_VCO_CFIX GENMASK(9, 8)
#define CSR_2L_PXP_JCPLL_VCO_HALFLSB_EN BIT(16)
#define CSR_2L_PXP_JCPLL_VCO_SCAPWR GENMASK(26, 24)
#define REG_CSR_2L_JCPLL_VCO_TCLVAR 0x0030
#define CSR_2L_PXP_JCPLL_VCO_TCLVAR GENMASK(2, 0)
#define REG_CSR_2L_JCPLL_SSC 0x0038
#define CSR_2L_PXP_JCPLL_SSC_EN BIT(0)
#define CSR_2L_PXP_JCPLL_SSC_PHASE_INI BIT(8)
#define CSR_2L_PXP_JCPLL_SSC_TRI_EN BIT(16)
#define REG_CSR_2L_JCPLL_SSC_DELTA1 0x003c
#define CSR_2L_PXP_JCPLL_SSC_DELTA1 GENMASK(15, 0)
#define CSR_2L_PXP_JCPLL_SSC_DELTA GENMASK(31, 16)
#define REG_CSR_2L_JCPLL_SSC_PERIOD 0x0040
#define CSR_2L_PXP_JCPLL_SSC_PERIOD GENMASK(15, 0)
#define REG_CSR_2L_JCPLL_TCL_VTP_EN 0x004c
#define CSR_2L_PXP_JCPLL_SPARE_LOW GENMASK(31, 24)
#define REG_CSR_2L_JCPLL_TCL_KBAND_VREF 0x0050
#define CSR_2L_PXP_JCPLL_TCL_KBAND_VREF GENMASK(4, 0)
#define CSR_2L_PXP_JCPLL_VCO_KBAND_MEAS_EN BIT(24)
#define REG_CSR_2L_750M_SYS_CK 0x0054
#define CSR_2L_PXP_TXPLL_LPF_SHCK_EN BIT(16)
#define CSR_2L_PXP_TXPLL_CHP_IBIAS GENMASK(29, 24)
#define REG_CSR_2L_TXPLL_CHP_IOFST 0x0058
#define CSR_2L_PXP_TXPLL_CHP_IOFST GENMASK(5, 0)
#define CSR_2L_PXP_TXPLL_LPF_BR GENMASK(12, 8)
#define CSR_2L_PXP_TXPLL_LPF_BC GENMASK(20, 16)
#define CSR_2L_PXP_TXPLL_LPF_BP GENMASK(28, 24)
#define REG_CSR_2L_TXPLL_LPF_BWR 0x005c
#define CSR_2L_PXP_TXPLL_LPF_BWR GENMASK(4, 0)
#define CSR_2L_PXP_TXPLL_LPF_BWC GENMASK(12, 8)
#define CSR_2L_PXP_TXPLL_KBAND_CODE GENMASK(31, 24)
#define REG_CSR_2L_TXPLL_KBAND_DIV 0x0060
#define CSR_2L_PXP_TXPLL_KBAND_DIV GENMASK(2, 0)
#define CSR_2L_PXP_TXPLL_KBAND_KFC GENMASK(9, 8)
#define CSR_2L_PXP_TXPLL_KBAND_KF GENMASK(17, 16)
#define CSR_2L_PXP_txpll_KBAND_KS GENMASK(25, 24)
#define REG_CSR_2L_TXPLL_POSTDIV 0x0064
#define CSR_2L_PXP_TXPLL_POSTDIV_EN BIT(0)
#define CSR_2L_PXP_TXPLL_MMD_PREDIV_MODE GENMASK(9, 8)
#define CSR_2L_PXP_TXPLL_PHY_CK1_EN BIT(24)
#define REG_CSR_2L_TXPLL_PHY_CK2 0x0068
#define CSR_2L_PXP_TXPLL_REFIN_INTERNAL BIT(24)
#define REG_CSR_2L_TXPLL_REFIN_DIV 0x006c
#define CSR_2L_PXP_TXPLL_REFIN_DIV GENMASK(1, 0)
#define CSR_2L_PXP_TXPLL_RST_DLY GENMASK(10, 8)
#define CSR_2L_PXP_TXPLL_PLL_RSTB BIT(16)
#define REG_CSR_2L_TXPLL_SDM_DI_LS 0x0070
#define CSR_2L_PXP_TXPLL_SDM_DI_LS GENMASK(1, 0)
#define CSR_2L_PXP_TXPLL_SDM_IFM BIT(8)
#define CSR_2L_PXP_TXPLL_SDM_ORD GENMASK(25, 24)
#define REG_CSR_2L_TXPLL_SDM_OUT 0x0074
#define CSR_2L_PXP_TXPLL_TCL_AMP_EN BIT(16)
#define CSR_2L_PXP_TXPLL_TCL_AMP_GAIN GENMASK(26, 24)
#define REG_CSR_2L_TXPLL_TCL_AMP_VREF 0x0078
#define CSR_2L_PXP_TXPLL_TCL_AMP_VREF GENMASK(4, 0)
#define CSR_2L_PXP_TXPLL_TCL_LPF_EN BIT(24)
#define REG_CSR_2L_TXPLL_TCL_LPF_BW 0x007c
#define CSR_2L_PXP_TXPLL_TCL_LPF_BW GENMASK(2, 0)
#define CSR_2L_PXP_TXPLL_VCO_CFIX GENMASK(17, 16)
#define CSR_2L_PXP_TXPLL_VCO_HALFLSB_EN BIT(24)
#define REG_CSR_2L_TXPLL_VCO_SCAPWR 0x0080
#define CSR_2L_PXP_TXPLL_VCO_SCAPWR GENMASK(2, 0)
#define REG_CSR_2L_TXPLL_SSC 0x0084
#define CSR_2L_PXP_TXPLL_SSC_EN BIT(0)
#define CSR_2L_PXP_TXPLL_SSC_PHASE_INI BIT(8)
#define REG_CSR_2L_TXPLL_SSC_DELTA1 0x0088
#define CSR_2L_PXP_TXPLL_SSC_DELTA1 GENMASK(15, 0)
#define CSR_2L_PXP_TXPLL_SSC_DELTA GENMASK(31, 16)
#define REG_CSR_2L_TXPLL_SSC_PERIOD 0x008c
#define CSR_2L_PXP_txpll_SSC_PERIOD GENMASK(15, 0)
#define REG_CSR_2L_TXPLL_VTP 0x0090
#define CSR_2L_PXP_TXPLL_VTP_EN BIT(0)
#define REG_CSR_2L_TXPLL_TCL_VTP 0x0098
#define CSR_2L_PXP_TXPLL_SPARE_L GENMASK(31, 24)
#define REG_CSR_2L_TXPLL_TCL_KBAND_VREF 0x009c
#define CSR_2L_PXP_TXPLL_TCL_KBAND_VREF GENMASK(4, 0)
#define CSR_2L_PXP_TXPLL_VCO_KBAND_MEAS_EN BIT(24)
#define REG_CSR_2L_TXPLL_POSTDIV_D256 0x00a0
#define CSR_2L_PXP_CLKTX0_AMP GENMASK(10, 8)
#define CSR_2L_PXP_CLKTX0_OFFSET GENMASK(17, 16)
#define CSR_2L_PXP_CLKTX0_SR GENMASK(25, 24)
#define REG_CSR_2L_CLKTX0_FORCE_OUT1 0x00a4
#define CSR_2L_PXP_CLKTX0_HZ BIT(8)
#define CSR_2L_PXP_CLKTX0_IMP_SEL GENMASK(20, 16)
#define CSR_2L_PXP_CLKTX1_AMP GENMASK(26, 24)
#define REG_CSR_2L_CLKTX1_OFFSET 0x00a8
#define CSR_2L_PXP_CLKTX1_OFFSET GENMASK(1, 0)
#define CSR_2L_PXP_CLKTX1_SR GENMASK(9, 8)
#define CSR_2L_PXP_CLKTX1_HZ BIT(24)
#define REG_CSR_2L_CLKTX1_IMP_SEL 0x00ac
#define CSR_2L_PXP_CLKTX1_IMP_SEL GENMASK(4, 0)
#define REG_CSR_2L_PLL_CMN_RESERVE0 0x00b0
#define CSR_2L_PXP_PLL_RESERVE_MASK GENMASK(15, 0)
#define REG_CSR_2L_TX0_CKLDO 0x00cc
#define CSR_2L_PXP_TX0_CKLDO_EN BIT(0)
#define CSR_2L_PXP_TX0_DMEDGEGEN_EN BIT(24)
#define REG_CSR_2L_TX1_CKLDO 0x00e8
#define CSR_2L_PXP_TX1_CKLDO_EN BIT(0)
#define CSR_2L_PXP_TX1_DMEDGEGEN_EN BIT(24)
#define REG_CSR_2L_TX1_MULTLANE 0x00ec
#define CSR_2L_PXP_TX1_MULTLANE_EN BIT(0)
#define REG_CSR_2L_RX0_REV0 0x00fc
#define CSR_2L_PXP_VOS_PNINV GENMASK(3, 2)
#define CSR_2L_PXP_FE_GAIN_NORMAL_MODE GENMASK(6, 4)
#define CSR_2L_PXP_FE_GAIN_TRAIN_MODE GENMASK(10, 8)
#define REG_CSR_2L_RX0_PHYCK_DIV 0x0100
#define CSR_2L_PXP_RX0_PHYCK_SEL GENMASK(9, 8)
#define CSR_2L_PXP_RX0_PHYCK_RSTB BIT(16)
#define CSR_2L_PXP_RX0_TDC_CK_SEL BIT(24)
#define REG_CSR_2L_CDR0_PD_PICAL_CKD8_INV 0x0104
#define CSR_2L_PXP_CDR0_PD_EDGE_DISABLE BIT(8)
#define REG_CSR_2L_CDR0_LPF_RATIO 0x0110
#define CSR_2L_PXP_CDR0_LPF_TOP_LIM GENMASK(26, 8)
#define REG_CSR_2L_CDR0_PR_INJ_MODE 0x011c
#define CSR_2L_PXP_CDR0_INJ_FORCE_OFF BIT(24)
#define REG_CSR_2L_CDR0_PR_BETA_DAC 0x0120
#define CSR_2L_PXP_CDR0_PR_BETA_SEL GENMASK(19, 16)
#define CSR_2L_PXP_CDR0_PR_KBAND_DIV GENMASK(26, 24)
#define REG_CSR_2L_CDR0_PR_VREG_IBAND 0x0124
#define CSR_2L_PXP_CDR0_PR_VREG_IBAND GENMASK(2, 0)
#define CSR_2L_PXP_CDR0_PR_VREG_CKBUF GENMASK(10, 8)
#define REG_CSR_2L_CDR0_PR_CKREF_DIV 0x0128
#define CSR_2L_PXP_CDR0_PR_CKREF_DIV GENMASK(1, 0)
#define REG_CSR_2L_CDR0_PR_MONCK 0x012c
#define CSR_2L_PXP_CDR0_PR_MONCK_ENABLE BIT(0)
#define CSR_2L_PXP_CDR0_PR_RESERVE0 GENMASK(19, 16)
#define REG_CSR_2L_CDR0_PR_COR_HBW 0x0130
#define CSR_2L_PXP_CDR0_PR_LDO_FORCE_ON BIT(8)
#define CSR_2L_PXP_CDR0_PR_CKREF_DIV1 GENMASK(17, 16)
#define REG_CSR_2L_CDR0_PR_MONPI 0x0134
#define CSR_2L_PXP_CDR0_PR_XFICK_EN BIT(8)
#define REG_CSR_2L_RX0_SIGDET_DCTEST 0x0140
#define CSR_2L_PXP_RX0_SIGDET_LPF_CTRL GENMASK(9, 8)
#define CSR_2L_PXP_RX0_SIGDET_PEAK GENMASK(25, 24)
#define REG_CSR_2L_RX0_SIGDET_VTH_SEL 0x0144
#define CSR_2L_PXP_RX0_SIGDET_VTH_SEL GENMASK(4, 0)
#define CSR_2L_PXP_RX0_FE_VB_EQ1_EN BIT(24)
#define REG_CSR_2L_PXP_RX0_FE_VB_EQ2 0x0148
#define CSR_2L_PXP_RX0_FE_VB_EQ2_EN BIT(0)
#define CSR_2L_PXP_RX0_FE_VB_EQ3_EN BIT(8)
#define CSR_2L_PXP_RX0_FE_VCM_GEN_PWDB BIT(16)
#define REG_CSR_2L_PXP_RX0_OSCAL_CTLE1IOS 0x0158
#define CSR_2L_PXP_RX0_PR_OSCAL_VGA1IOS GENMASK(29, 24)
#define REG_CSR_2L_PXP_RX0_OSCA_VGA1VOS 0x015c
#define CSR_2L_PXP_RX0_PR_OSCAL_VGA1VOS GENMASK(5, 0)
#define CSR_2L_PXP_RX0_PR_OSCAL_VGA2IOS GENMASK(13, 8)
#define REG_CSR_2L_RX1_REV0 0x01b4
#define REG_CSR_2L_RX1_PHYCK_DIV 0x01b8
#define CSR_2L_PXP_RX1_PHYCK_SEL GENMASK(9, 8)
#define CSR_2L_PXP_RX1_PHYCK_RSTB BIT(16)
#define CSR_2L_PXP_RX1_TDC_CK_SEL BIT(24)
#define REG_CSR_2L_CDR1_PD_PICAL_CKD8_INV 0x01bc
#define CSR_2L_PXP_CDR1_PD_EDGE_DISABLE BIT(8)
#define REG_CSR_2L_CDR1_PR_BETA_DAC 0x01d8
#define CSR_2L_PXP_CDR1_PR_BETA_SEL GENMASK(19, 16)
#define CSR_2L_PXP_CDR1_PR_KBAND_DIV GENMASK(26, 24)
#define REG_CSR_2L_CDR1_PR_MONCK 0x01e4
#define CSR_2L_PXP_CDR1_PR_MONCK_ENABLE BIT(0)
#define CSR_2L_PXP_CDR1_PR_RESERVE0 GENMASK(19, 16)
#define REG_CSR_2L_CDR1_LPF_RATIO 0x01c8
#define CSR_2L_PXP_CDR1_LPF_TOP_LIM GENMASK(26, 8)
#define REG_CSR_2L_CDR1_PR_INJ_MODE 0x01d4
#define CSR_2L_PXP_CDR1_INJ_FORCE_OFF BIT(24)
#define REG_CSR_2L_CDR1_PR_VREG_IBAND_VAL 0x01dc
#define CSR_2L_PXP_CDR1_PR_VREG_IBAND GENMASK(2, 0)
#define CSR_2L_PXP_CDR1_PR_VREG_CKBUF GENMASK(10, 8)
#define REG_CSR_2L_CDR1_PR_CKREF_DIV 0x01e0
#define CSR_2L_PXP_CDR1_PR_CKREF_DIV GENMASK(1, 0)
#define REG_CSR_2L_CDR1_PR_COR_HBW 0x01e8
#define CSR_2L_PXP_CDR1_PR_LDO_FORCE_ON BIT(8)
#define CSR_2L_PXP_CDR1_PR_CKREF_DIV1 GENMASK(17, 16)
#define REG_CSR_2L_CDR1_PR_MONPI 0x01ec
#define CSR_2L_PXP_CDR1_PR_XFICK_EN BIT(8)
#define REG_CSR_2L_RX1_DAC_RANGE_EYE 0x01f4
#define CSR_2L_PXP_RX1_SIGDET_LPF_CTRL GENMASK(25, 24)
#define REG_CSR_2L_RX1_SIGDET_NOVTH 0x01f8
#define CSR_2L_PXP_RX1_SIGDET_PEAK GENMASK(9, 8)
#define CSR_2L_PXP_RX1_SIGDET_VTH_SEL GENMASK(20, 16)
#define REG_CSR_2L_RX1_FE_VB_EQ1 0x0200
#define CSR_2L_PXP_RX1_FE_VB_EQ1_EN BIT(0)
#define CSR_2L_PXP_RX1_FE_VB_EQ2_EN BIT(8)
#define CSR_2L_PXP_RX1_FE_VB_EQ3_EN BIT(16)
#define CSR_2L_PXP_RX1_FE_VCM_GEN_PWDB BIT(24)
#define REG_CSR_2L_RX1_OSCAL_VGA1IOS 0x0214
#define CSR_2L_PXP_RX1_PR_OSCAL_VGA1IOS GENMASK(5, 0)
#define CSR_2L_PXP_RX1_PR_OSCAL_VGA1VOS GENMASK(13, 8)
#define CSR_2L_PXP_RX1_PR_OSCAL_VGA2IOS GENMASK(21, 16)
/* PMA */
#define REG_PCIE_PMA_SS_LCPLL_PWCTL_SETTING_1 0x0004
#define PCIE_LCPLL_MAN_PWDB BIT(0)
#define REG_PCIE_PMA_SEQUENCE_DISB_CTRL1 0x010c
#define PCIE_DISB_RX_SDCAL_EN BIT(0)
#define REG_PCIE_PMA_CTRL_SEQUENCE_FORCE_CTRL1 0x0114
#define PCIE_FORCE_RX_SDCAL_EN BIT(0)
#define REG_PCIE_PMA_SS_RX_FREQ_DET1 0x014c
#define PCIE_PLL_FT_LOCK_CYCLECNT GENMASK(15, 0)
#define PCIE_PLL_FT_UNLOCK_CYCLECNT GENMASK(31, 16)
#define REG_PCIE_PMA_SS_RX_FREQ_DET2 0x0150
#define PCIE_LOCK_TARGET_BEG GENMASK(15, 0)
#define PCIE_LOCK_TARGET_END GENMASK(31, 16)
#define REG_PCIE_PMA_SS_RX_FREQ_DET3 0x0154
#define PCIE_UNLOCK_TARGET_BEG GENMASK(15, 0)
#define PCIE_UNLOCK_TARGET_END GENMASK(31, 16)
#define REG_PCIE_PMA_SS_RX_FREQ_DET4 0x0158
#define PCIE_FREQLOCK_DET_EN GENMASK(2, 0)
#define PCIE_LOCK_LOCKTH GENMASK(11, 8)
#define PCIE_UNLOCK_LOCKTH GENMASK(15, 12)
#define REG_PCIE_PMA_SS_RX_CAL1 0x0160
#define REG_PCIE_PMA_SS_RX_CAL2 0x0164
#define PCIE_CAL_OUT_OS GENMASK(11, 8)
#define REG_PCIE_PMA_SS_RX_SIGDET0 0x0168
#define PCIE_SIGDET_WIN_NONVLD_TIMES GENMASK(28, 24)
#define REG_PCIE_PMA_TX_RESET 0x0260
#define PCIE_TX_TOP_RST BIT(0)
#define PCIE_TX_CAL_RST BIT(8)
#define REG_PCIE_PMA_RX_FORCE_MODE0 0x0294
#define PCIE_FORCE_DA_XPON_RX_FE_GAIN_CTRL GENMASK(1, 0)
#define REG_PCIE_PMA_SS_DA_XPON_PWDB0 0x034c
#define PCIE_DA_XPON_CDR_PR_PWDB BIT(8)
#define REG_PCIE_PMA_SW_RESET 0x0460
#define PCIE_SW_RX_FIFO_RST BIT(0)
#define PCIE_SW_RX_RST BIT(1)
#define PCIE_SW_TX_RST BIT(2)
#define PCIE_SW_PMA_RST BIT(3)
#define PCIE_SW_ALLPCS_RST BIT(4)
#define PCIE_SW_REF_RST BIT(5)
#define PCIE_SW_TX_FIFO_RST BIT(6)
#define PCIE_SW_XFI_TXPCS_RST BIT(7)
#define PCIE_SW_XFI_RXPCS_RST BIT(8)
#define PCIE_SW_XFI_RXPCS_BIST_RST BIT(9)
#define PCIE_SW_HSG_TXPCS_RST BIT(10)
#define PCIE_SW_HSG_RXPCS_RST BIT(11)
#define PCIE_PMA_SW_RST (PCIE_SW_RX_FIFO_RST | \
PCIE_SW_RX_RST | \
PCIE_SW_TX_RST | \
PCIE_SW_PMA_RST | \
PCIE_SW_ALLPCS_RST | \
PCIE_SW_REF_RST | \
PCIE_SW_TX_FIFO_RST | \
PCIE_SW_XFI_TXPCS_RST | \
PCIE_SW_XFI_RXPCS_RST | \
PCIE_SW_XFI_RXPCS_BIST_RST | \
PCIE_SW_HSG_TXPCS_RST | \
PCIE_SW_HSG_RXPCS_RST)
#define REG_PCIE_PMA_RO_RX_FREQDET 0x0530
#define PCIE_RO_FBCK_LOCK BIT(0)
#define PCIE_RO_FL_OUT GENMASK(31, 16)
#define REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC 0x0794
#define PCIE_FORCE_DA_PXP_CDR_PR_IDAC GENMASK(10, 0)
#define PCIE_FORCE_SEL_DA_PXP_CDR_PR_IDAC BIT(16)
#define PCIE_FORCE_SEL_DA_PXP_TXPLL_SDM_PCW BIT(24)
#define REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_SDM_PCW 0x0798
#define PCIE_FORCE_DA_PXP_TXPLL_SDM_PCW GENMASK(30, 0)
#define REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_VOS 0x079c
#define PCIE_FORCE_SEL_DA_PXP_JCPLL_SDM_PCW BIT(16)
#define REG_PCIE_PMA_FORCE_DA_PXP_JCPLL_SDM_PCW 0x0800
#define PCIE_FORCE_DA_PXP_JCPLL_SDM_PCW GENMASK(30, 0)
#define REG_PCIE_PMA_FORCE_DA_PXP_CDR_PD_PWDB 0x081c
#define PCIE_FORCE_DA_PXP_CDR_PD_PWDB BIT(0)
#define PCIE_FORCE_SEL_DA_PXP_CDR_PD_PWDB BIT(8)
#define REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C 0x0820
#define PCIE_FORCE_DA_PXP_CDR_PR_LPF_C_EN BIT(0)
#define PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_C_EN BIT(8)
#define PCIE_FORCE_DA_PXP_CDR_PR_LPF_R_EN BIT(16)
#define PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_R_EN BIT(24)
#define REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB 0x0824
#define PCIE_FORCE_DA_PXP_CDR_PR_PWDB BIT(16)
#define PCIE_FORCE_SEL_DA_PXP_CDR_PR_PWDB BIT(24)
#define REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT 0x0828
#define PCIE_FORCE_DA_PXP_JCPLL_CKOUT_EN BIT(0)
#define PCIE_FORCE_SEL_DA_PXP_JCPLL_CKOUT_EN BIT(8)
#define PCIE_FORCE_DA_PXP_JCPLL_EN BIT(16)
#define PCIE_FORCE_SEL_DA_PXP_JCPLL_EN BIT(24)
#define REG_PCIE_PMA_FORCE_DA_PXP_RX_SCAN_RST 0x0084c
#define PCIE_FORCE_DA_PXP_RX_SIGDET_PWDB BIT(16)
#define PCIE_FORCE_SEL_DA_PXP_RX_SIGDET_PWDB BIT(24)
#define REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT 0x0854
#define PCIE_FORCE_DA_PXP_TXPLL_CKOUT_EN BIT(0)
#define PCIE_FORCE_SEL_DA_PXP_TXPLL_CKOUT_EN BIT(8)
#define PCIE_FORCE_DA_PXP_TXPLL_EN BIT(16)
#define PCIE_FORCE_SEL_DA_PXP_TXPLL_EN BIT(24)
#define REG_PCIE_PMA_SCAN_MODE 0x0884
#define PCIE_FORCE_DA_PXP_JCPLL_KBAND_LOAD_EN BIT(0)
#define PCIE_FORCE_SEL_DA_PXP_JCPLL_KBAND_LOAD_EN BIT(8)
#define REG_PCIE_PMA_DIG_RESERVE_13 0x08bc
#define PCIE_FLL_IDAC_PCIEG1 GENMASK(10, 0)
#define PCIE_FLL_IDAC_PCIEG2 GENMASK(26, 16)
#define REG_PCIE_PMA_DIG_RESERVE_14 0x08c0
#define PCIE_FLL_IDAC_PCIEG3 GENMASK(10, 0)
#define PCIE_FLL_LOAD_EN BIT(16)
#define REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_GAIN_CTRL 0x088c
#define PCIE_FORCE_DA_PXP_RX_FE_GAIN_CTRL GENMASK(1, 0)
#define PCIE_FORCE_SEL_DA_PXP_RX_FE_GAIN_CTRL BIT(8)
#define REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_PWDB 0x0894
#define PCIE_FORCE_DA_PXP_RX_FE_PWDB BIT(0)
#define PCIE_FORCE_SEL_DA_PXP_RX_FE_PWDB BIT(8)
#define REG_PCIE_PMA_DIG_RESERVE_12 0x08b8
#define PCIE_FORCE_PMA_RX_SPEED GENMASK(7, 4)
#define PCIE_FORCE_SEL_PMA_RX_SPEED BIT(7)
#define REG_PCIE_PMA_DIG_RESERVE_17 0x08e0
#define REG_PCIE_PMA_DIG_RESERVE_18 0x08e4
#define PCIE_PXP_RX_VTH_SEL_PCIE_G1 GENMASK(4, 0)
#define PCIE_PXP_RX_VTH_SEL_PCIE_G2 GENMASK(12, 8)
#define PCIE_PXP_RX_VTH_SEL_PCIE_G3 GENMASK(20, 16)
#define REG_PCIE_PMA_DIG_RESERVE_19 0x08e8
#define PCIE_PCP_RX_REV0_PCIE_GEN1 GENMASK(31, 16)
#define REG_PCIE_PMA_DIG_RESERVE_20 0x08ec
#define PCIE_PCP_RX_REV0_PCIE_GEN2 GENMASK(15, 0)
#define PCIE_PCP_RX_REV0_PCIE_GEN3 GENMASK(31, 16)
#define REG_PCIE_PMA_DIG_RESERVE_21 0x08f0
#define REG_PCIE_PMA_DIG_RESERVE_22 0x08f4
#define REG_PCIE_PMA_DIG_RESERVE_27 0x0908
#define REG_PCIE_PMA_DIG_RESERVE_30 0x0914
/* DTIME */
#define REG_PCIE_PEXTP_DIG_GLB44 0x00
#define PCIE_XTP_RXDET_VCM_OFF_STB_T_SEL GENMASK(7, 0)
#define PCIE_XTP_RXDET_EN_STB_T_SEL GENMASK(15, 8)
#define PCIE_XTP_RXDET_FINISH_STB_T_SEL GENMASK(23, 16)
#define PCIE_XTP_TXPD_TX_DATA_EN_DLY GENMASK(27, 24)
#define PCIE_XTP_TXPD_RXDET_DONE_CDT BIT(28)
#define PCIE_XTP_RXDET_LATCH_STB_T_SEL GENMASK(31, 29)
/* RX AEQ */
#define REG_PCIE_PEXTP_DIG_LN_RX30_P0 0x0000
#define PCIE_XTP_LN_RX_PDOWN_L1P2_EXIT_WAIT GENMASK(7, 0)
#define PCIE_XTP_LN_RX_PDOWN_T2RLB_DIG_EN BIT(8)
#define PCIE_XTP_LN_RX_PDOWN_E0_AEQEN_WAIT GENMASK(31, 16)
#define REG_PCIE_PEXTP_DIG_LN_RX30_P1 0x0100
#endif /* _PHY_AIROHA_PCIE_H */
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2024 AIROHA Inc
* Author: Lorenzo Bianconi <lorenzo@kernel.org>
*/
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "phy-airoha-pcie-regs.h"
#define LEQ_LEN_CTRL_MAX_VAL 7
#define FREQ_LOCK_MAX_ATTEMPT 10
enum airoha_pcie_port_gen {
PCIE_PORT_GEN1 = 1,
PCIE_PORT_GEN2,
PCIE_PORT_GEN3,
};
/**
* struct airoha_pcie_phy - PCIe phy driver main structure
* @dev: pointer to device
* @phy: pointer to generic phy
* @csr_2l: Analogic lane IO mapped register base address
* @pma0: IO mapped register base address of PMA0-PCIe
* @pma1: IO mapped register base address of PMA1-PCIe
* @p0_xr_dtime: IO mapped register base address of port0 Tx-Rx detection time
* @p1_xr_dtime: IO mapped register base address of port1 Tx-Rx detection time
* @rx_aeq: IO mapped register base address of Rx AEQ training
*/
struct airoha_pcie_phy {
struct device *dev;
struct phy *phy;
void __iomem *csr_2l;
void __iomem *pma0;
void __iomem *pma1;
void __iomem *p0_xr_dtime;
void __iomem *p1_xr_dtime;
void __iomem *rx_aeq;
};
static void airoha_phy_clear_bits(void __iomem *reg, u32 mask)
{
u32 val = readl(reg) & ~mask;
writel(val, reg);
}
static void airoha_phy_set_bits(void __iomem *reg, u32 mask)
{
u32 val = readl(reg) | mask;
writel(val, reg);
}
static void airoha_phy_update_bits(void __iomem *reg, u32 mask, u32 val)
{
u32 tmp = readl(reg);
tmp &= ~mask;
tmp |= val & mask;
writel(tmp, reg);
}
#define airoha_phy_update_field(reg, mask, val) \
do { \
BUILD_BUG_ON_MSG(!__builtin_constant_p((mask)), \
"mask is not constant"); \
airoha_phy_update_bits((reg), (mask), \
FIELD_PREP((mask), (val))); \
} while (0)
#define airoha_phy_csr_2l_clear_bits(pcie_phy, reg, mask) \
airoha_phy_clear_bits((pcie_phy)->csr_2l + (reg), (mask))
#define airoha_phy_csr_2l_set_bits(pcie_phy, reg, mask) \
airoha_phy_set_bits((pcie_phy)->csr_2l + (reg), (mask))
#define airoha_phy_csr_2l_update_field(pcie_phy, reg, mask, val) \
airoha_phy_update_field((pcie_phy)->csr_2l + (reg), (mask), (val))
#define airoha_phy_pma0_clear_bits(pcie_phy, reg, mask) \
airoha_phy_clear_bits((pcie_phy)->pma0 + (reg), (mask))
#define airoha_phy_pma1_clear_bits(pcie_phy, reg, mask) \
airoha_phy_clear_bits((pcie_phy)->pma1 + (reg), (mask))
#define airoha_phy_pma0_set_bits(pcie_phy, reg, mask) \
airoha_phy_set_bits((pcie_phy)->pma0 + (reg), (mask))
#define airoha_phy_pma1_set_bits(pcie_phy, reg, mask) \
airoha_phy_set_bits((pcie_phy)->pma1 + (reg), (mask))
#define airoha_phy_pma0_update_field(pcie_phy, reg, mask, val) \
airoha_phy_update_field((pcie_phy)->pma0 + (reg), (mask), (val))
#define airoha_phy_pma1_update_field(pcie_phy, reg, mask, val) \
airoha_phy_update_field((pcie_phy)->pma1 + (reg), (mask), (val))
static void
airoha_phy_init_lane0_rx_fw_pre_calib(struct airoha_pcie_phy *pcie_phy,
enum airoha_pcie_port_gen gen)
{
u32 fl_out_target = gen == PCIE_PORT_GEN3 ? 41600 : 41941;
u32 lock_cyclecnt = gen == PCIE_PORT_GEN3 ? 26000 : 32767;
u32 pr_idac, val, cdr_pr_idac_tmp = 0;
int i;
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_SS_LCPLL_PWCTL_SETTING_1,
PCIE_LCPLL_MAN_PWDB);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET2,
PCIE_LOCK_TARGET_BEG,
fl_out_target - 100);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET2,
PCIE_LOCK_TARGET_END,
fl_out_target + 100);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET1,
PCIE_PLL_FT_LOCK_CYCLECNT, lock_cyclecnt);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_LOCK_LOCKTH, 0x3);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET3,
PCIE_UNLOCK_TARGET_BEG,
fl_out_target - 100);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET3,
PCIE_UNLOCK_TARGET_END,
fl_out_target + 100);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET1,
PCIE_PLL_FT_UNLOCK_CYCLECNT,
lock_cyclecnt);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_UNLOCK_LOCKTH, 0x3);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR0_PR_INJ_MODE,
CSR_2L_PXP_CDR0_INJ_FORCE_OFF);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_R_EN);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_DA_PXP_CDR_PR_LPF_R_EN);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_C_EN);
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_DA_PXP_CDR_PR_LPF_C_EN);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_IDAC);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_PWDB);
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB,
PCIE_FORCE_DA_PXP_CDR_PR_PWDB);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB,
PCIE_FORCE_DA_PXP_CDR_PR_PWDB);
for (i = 0; i < LEQ_LEN_CTRL_MAX_VAL; i++) {
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_DA_PXP_CDR_PR_IDAC, i << 8);
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN);
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN, 0x3);
usleep_range(10000, 15000);
val = FIELD_GET(PCIE_RO_FL_OUT,
readl(pcie_phy->pma0 +
REG_PCIE_PMA_RO_RX_FREQDET));
if (val > fl_out_target)
cdr_pr_idac_tmp = i << 8;
}
for (i = LEQ_LEN_CTRL_MAX_VAL; i >= 0; i--) {
pr_idac = cdr_pr_idac_tmp | (0x1 << i);
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_DA_PXP_CDR_PR_IDAC, pr_idac);
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN);
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN, 0x3);
usleep_range(10000, 15000);
val = FIELD_GET(PCIE_RO_FL_OUT,
readl(pcie_phy->pma0 +
REG_PCIE_PMA_RO_RX_FREQDET));
if (val < fl_out_target)
pr_idac &= ~(0x1 << i);
cdr_pr_idac_tmp = pr_idac;
}
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_DA_PXP_CDR_PR_IDAC,
cdr_pr_idac_tmp);
for (i = 0; i < FREQ_LOCK_MAX_ATTEMPT; i++) {
u32 val;
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN);
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN, 0x3);
usleep_range(10000, 15000);
val = readl(pcie_phy->pma0 + REG_PCIE_PMA_RO_RX_FREQDET);
if (val & PCIE_RO_FBCK_LOCK)
break;
}
/* turn off force mode and update band values */
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR0_PR_INJ_MODE,
CSR_2L_PXP_CDR0_INJ_FORCE_OFF);
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_R_EN);
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_C_EN);
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_PWDB);
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_IDAC);
if (gen == PCIE_PORT_GEN3) {
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_DIG_RESERVE_14,
PCIE_FLL_IDAC_PCIEG3,
cdr_pr_idac_tmp);
} else {
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_DIG_RESERVE_13,
PCIE_FLL_IDAC_PCIEG1,
cdr_pr_idac_tmp);
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_DIG_RESERVE_13,
PCIE_FLL_IDAC_PCIEG2,
cdr_pr_idac_tmp);
}
}
static void
airoha_phy_init_lane1_rx_fw_pre_calib(struct airoha_pcie_phy *pcie_phy,
enum airoha_pcie_port_gen gen)
{
u32 fl_out_target = gen == PCIE_PORT_GEN3 ? 41600 : 41941;
u32 lock_cyclecnt = gen == PCIE_PORT_GEN3 ? 26000 : 32767;
u32 pr_idac, val, cdr_pr_idac_tmp = 0;
int i;
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_SS_LCPLL_PWCTL_SETTING_1,
PCIE_LCPLL_MAN_PWDB);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET2,
PCIE_LOCK_TARGET_BEG,
fl_out_target - 100);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET2,
PCIE_LOCK_TARGET_END,
fl_out_target + 100);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET1,
PCIE_PLL_FT_LOCK_CYCLECNT, lock_cyclecnt);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_LOCK_LOCKTH, 0x3);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET3,
PCIE_UNLOCK_TARGET_BEG,
fl_out_target - 100);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET3,
PCIE_UNLOCK_TARGET_END,
fl_out_target + 100);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET1,
PCIE_PLL_FT_UNLOCK_CYCLECNT,
lock_cyclecnt);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_UNLOCK_LOCKTH, 0x3);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR1_PR_INJ_MODE,
CSR_2L_PXP_CDR1_INJ_FORCE_OFF);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_R_EN);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_DA_PXP_CDR_PR_LPF_R_EN);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_C_EN);
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_DA_PXP_CDR_PR_LPF_C_EN);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_IDAC);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_PWDB);
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB,
PCIE_FORCE_DA_PXP_CDR_PR_PWDB);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB,
PCIE_FORCE_DA_PXP_CDR_PR_PWDB);
for (i = 0; i < LEQ_LEN_CTRL_MAX_VAL; i++) {
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_DA_PXP_CDR_PR_IDAC, i << 8);
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN);
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN, 0x3);
usleep_range(10000, 15000);
val = FIELD_GET(PCIE_RO_FL_OUT,
readl(pcie_phy->pma1 +
REG_PCIE_PMA_RO_RX_FREQDET));
if (val > fl_out_target)
cdr_pr_idac_tmp = i << 8;
}
for (i = LEQ_LEN_CTRL_MAX_VAL; i >= 0; i--) {
pr_idac = cdr_pr_idac_tmp | (0x1 << i);
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_DA_PXP_CDR_PR_IDAC, pr_idac);
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN);
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN, 0x3);
usleep_range(10000, 15000);
val = FIELD_GET(PCIE_RO_FL_OUT,
readl(pcie_phy->pma1 +
REG_PCIE_PMA_RO_RX_FREQDET));
if (val < fl_out_target)
pr_idac &= ~(0x1 << i);
cdr_pr_idac_tmp = pr_idac;
}
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_DA_PXP_CDR_PR_IDAC,
cdr_pr_idac_tmp);
for (i = 0; i < FREQ_LOCK_MAX_ATTEMPT; i++) {
u32 val;
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN);
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_SS_RX_FREQ_DET4,
PCIE_FREQLOCK_DET_EN, 0x3);
usleep_range(10000, 15000);
val = readl(pcie_phy->pma1 + REG_PCIE_PMA_RO_RX_FREQDET);
if (val & PCIE_RO_FBCK_LOCK)
break;
}
/* turn off force mode and update band values */
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR1_PR_INJ_MODE,
CSR_2L_PXP_CDR1_INJ_FORCE_OFF);
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_R_EN);
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_C_EN);
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_PWDB);
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_SEL_DA_PXP_CDR_PR_IDAC);
if (gen == PCIE_PORT_GEN3) {
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_DIG_RESERVE_14,
PCIE_FLL_IDAC_PCIEG3,
cdr_pr_idac_tmp);
} else {
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_DIG_RESERVE_13,
PCIE_FLL_IDAC_PCIEG1,
cdr_pr_idac_tmp);
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_DIG_RESERVE_13,
PCIE_FLL_IDAC_PCIEG2,
cdr_pr_idac_tmp);
}
}
static void airoha_pcie_phy_init_default(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CMN,
CSR_2L_PXP_CMN_TRIM_MASK, 0x10);
writel(0xcccbcccb, pcie_phy->pma0 + REG_PCIE_PMA_DIG_RESERVE_21);
writel(0xcccb, pcie_phy->pma0 + REG_PCIE_PMA_DIG_RESERVE_22);
writel(0xcccbcccb, pcie_phy->pma1 + REG_PCIE_PMA_DIG_RESERVE_21);
writel(0xcccb, pcie_phy->pma1 + REG_PCIE_PMA_DIG_RESERVE_22);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CMN,
CSR_2L_PXP_CMN_LANE_EN);
}
static void airoha_pcie_phy_init_clk_out(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_TXPLL_POSTDIV_D256,
CSR_2L_PXP_CLKTX0_AMP, 0x5);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_CLKTX0_FORCE_OUT1,
CSR_2L_PXP_CLKTX1_AMP, 0x5);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_TXPLL_POSTDIV_D256,
CSR_2L_PXP_CLKTX0_OFFSET, 0x2);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CLKTX1_OFFSET,
CSR_2L_PXP_CLKTX1_OFFSET, 0x2);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CLKTX0_FORCE_OUT1,
CSR_2L_PXP_CLKTX0_HZ);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CLKTX1_OFFSET,
CSR_2L_PXP_CLKTX1_HZ);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_CLKTX0_FORCE_OUT1,
CSR_2L_PXP_CLKTX0_IMP_SEL, 0x12);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CLKTX1_IMP_SEL,
CSR_2L_PXP_CLKTX1_IMP_SEL, 0x12);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_POSTDIV_D256,
CSR_2L_PXP_CLKTX0_SR);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CLKTX1_OFFSET,
CSR_2L_PXP_CLKTX1_SR);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_PLL_CMN_RESERVE0,
CSR_2L_PXP_PLL_RESERVE_MASK, 0xdd);
}
static void airoha_pcie_phy_init_csr_2l(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_SW_RESET,
PCIE_SW_XFI_RXPCS_RST | PCIE_SW_REF_RST |
PCIE_SW_RX_RST);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_SW_RESET,
PCIE_SW_XFI_RXPCS_RST | PCIE_SW_REF_RST |
PCIE_SW_RX_RST);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_TX_RESET,
PCIE_TX_TOP_RST | REG_PCIE_PMA_TX_RESET);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_TX_RESET,
PCIE_TX_TOP_RST | REG_PCIE_PMA_TX_RESET);
}
static void airoha_pcie_phy_init_rx(struct airoha_pcie_phy *pcie_phy)
{
writel(0x2a00090b, pcie_phy->pma0 + REG_PCIE_PMA_DIG_RESERVE_17);
writel(0x2a00090b, pcie_phy->pma1 + REG_PCIE_PMA_DIG_RESERVE_17);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR0_PR_MONPI,
CSR_2L_PXP_CDR0_PR_XFICK_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR1_PR_MONPI,
CSR_2L_PXP_CDR1_PR_XFICK_EN);
airoha_phy_csr_2l_clear_bits(pcie_phy,
REG_CSR_2L_CDR0_PD_PICAL_CKD8_INV,
CSR_2L_PXP_CDR0_PD_EDGE_DISABLE);
airoha_phy_csr_2l_clear_bits(pcie_phy,
REG_CSR_2L_CDR1_PD_PICAL_CKD8_INV,
CSR_2L_PXP_CDR1_PD_EDGE_DISABLE);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_PHYCK_DIV,
CSR_2L_PXP_RX0_PHYCK_SEL, 0x1);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_PHYCK_DIV,
CSR_2L_PXP_RX1_PHYCK_SEL, 0x1);
}
static void airoha_pcie_phy_init_jcpll(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_JCPLL_EN);
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_DA_PXP_JCPLL_EN);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_JCPLL_EN);
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_DA_PXP_JCPLL_EN);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_TCL_VTP_EN,
CSR_2L_PXP_JCPLL_SPARE_LOW, 0x20);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_RST_DLY,
CSR_2L_PXP_JCPLL_RST);
writel(0x0, pcie_phy->csr_2l + REG_CSR_2L_JCPLL_SSC_DELTA1);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC_PERIOD,
CSR_2L_PXP_JCPLL_SSC_PERIOD);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC,
CSR_2L_PXP_JCPLL_SSC_PHASE_INI);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC,
CSR_2L_PXP_JCPLL_SSC_TRI_EN);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BR,
CSR_2L_PXP_JCPLL_LPF_BR, 0xa);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BR,
CSR_2L_PXP_JCPLL_LPF_BP, 0xc);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BR,
CSR_2L_PXP_JCPLL_LPF_BC, 0x1f);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BWC,
CSR_2L_PXP_JCPLL_LPF_BWC, 0x1e);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BR,
CSR_2L_PXP_JCPLL_LPF_BWR, 0xa);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_JCPLL_MMD_PREDIV_MODE,
CSR_2L_PXP_JCPLL_MMD_PREDIV_MODE,
0x1);
airoha_phy_csr_2l_clear_bits(pcie_phy, CSR_2L_PXP_JCPLL_MONCK,
CSR_2L_PXP_JCPLL_REFIN_DIV);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_VOS,
PCIE_FORCE_SEL_DA_PXP_JCPLL_SDM_PCW);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_VOS,
PCIE_FORCE_SEL_DA_PXP_JCPLL_SDM_PCW);
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_JCPLL_SDM_PCW,
PCIE_FORCE_DA_PXP_JCPLL_SDM_PCW,
0x50000000);
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_JCPLL_SDM_PCW,
PCIE_FORCE_DA_PXP_JCPLL_SDM_PCW,
0x50000000);
airoha_phy_csr_2l_set_bits(pcie_phy,
REG_CSR_2L_JCPLL_MMD_PREDIV_MODE,
CSR_2L_PXP_JCPLL_POSTDIV_D5);
airoha_phy_csr_2l_set_bits(pcie_phy,
REG_CSR_2L_JCPLL_MMD_PREDIV_MODE,
CSR_2L_PXP_JCPLL_POSTDIV_D2);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_RST_DLY,
CSR_2L_PXP_JCPLL_RST_DLY, 0x4);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_RST_DLY,
CSR_2L_PXP_JCPLL_SDM_DI_LS);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_TCL_KBAND_VREF,
CSR_2L_PXP_JCPLL_VCO_KBAND_MEAS_EN);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_IB_EXT,
CSR_2L_PXP_JCPLL_CHP_IOFST);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_IB_EXT,
CSR_2L_PXP_JCPLL_CHP_IBIAS, 0xc);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_JCPLL_MMD_PREDIV_MODE,
CSR_2L_PXP_JCPLL_MMD_PREDIV_MODE,
0x1);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_VCODIV,
CSR_2L_PXP_JCPLL_VCO_HALFLSB_EN);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_VCODIV,
CSR_2L_PXP_JCPLL_VCO_CFIX, 0x1);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_VCODIV,
CSR_2L_PXP_JCPLL_VCO_SCAPWR, 0x4);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_IB_EXT,
REG_CSR_2L_JCPLL_LPF_SHCK_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_KBAND_KFC,
CSR_2L_PXP_JCPLL_POSTDIV_EN);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_KBAND_KFC,
CSR_2L_PXP_JCPLL_KBAND_KFC);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_KBAND_KFC,
CSR_2L_PXP_JCPLL_KBAND_KF, 0x3);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_KBAND_KFC,
CSR_2L_PXP_JCPLL_KBAND_KS);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BWC,
CSR_2L_PXP_JCPLL_KBAND_DIV, 0x1);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_SCAN_MODE,
PCIE_FORCE_SEL_DA_PXP_JCPLL_KBAND_LOAD_EN);
airoha_phy_pma0_clear_bits(pcie_phy, REG_PCIE_PMA_SCAN_MODE,
PCIE_FORCE_DA_PXP_JCPLL_KBAND_LOAD_EN);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BWC,
CSR_2L_PXP_JCPLL_KBAND_CODE, 0xe4);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SDM_HREN,
CSR_2L_PXP_JCPLL_TCL_AMP_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_TCL_CMP,
CSR_2L_PXP_JCPLL_TCL_LPF_EN);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_JCPLL_TCL_KBAND_VREF,
CSR_2L_PXP_JCPLL_TCL_KBAND_VREF, 0xf);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_SDM_HREN,
CSR_2L_PXP_JCPLL_TCL_AMP_GAIN, 0x1);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_SDM_HREN,
CSR_2L_PXP_JCPLL_TCL_AMP_VREF, 0x5);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_TCL_CMP,
CSR_2L_PXP_JCPLL_TCL_LPF_BW, 0x1);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_VCO_TCLVAR,
CSR_2L_PXP_JCPLL_VCO_TCLVAR, 0x3);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_JCPLL_CKOUT_EN);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_DA_PXP_JCPLL_CKOUT_EN);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_JCPLL_CKOUT_EN);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_DA_PXP_JCPLL_CKOUT_EN);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_JCPLL_EN);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_DA_PXP_JCPLL_EN);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_JCPLL_EN);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT,
PCIE_FORCE_DA_PXP_JCPLL_EN);
}
static void airoha_pcie_phy_txpll(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_TXPLL_EN);
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_DA_PXP_TXPLL_EN);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_TXPLL_EN);
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_DA_PXP_TXPLL_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_REFIN_DIV,
CSR_2L_PXP_TXPLL_PLL_RSTB);
writel(0x0, pcie_phy->csr_2l + REG_CSR_2L_TXPLL_SSC_DELTA1);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SSC_PERIOD,
CSR_2L_PXP_txpll_SSC_PERIOD);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_CHP_IOFST,
CSR_2L_PXP_TXPLL_CHP_IOFST, 0x1);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_750M_SYS_CK,
CSR_2L_PXP_TXPLL_CHP_IBIAS, 0x2d);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_REFIN_DIV,
CSR_2L_PXP_TXPLL_REFIN_DIV);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_TCL_LPF_BW,
CSR_2L_PXP_TXPLL_VCO_CFIX, 0x3);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_SEL_DA_PXP_TXPLL_SDM_PCW);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_SEL_DA_PXP_TXPLL_SDM_PCW);
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_SDM_PCW,
PCIE_FORCE_DA_PXP_TXPLL_SDM_PCW,
0xc800000);
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_SDM_PCW,
PCIE_FORCE_DA_PXP_TXPLL_SDM_PCW,
0xc800000);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SDM_DI_LS,
CSR_2L_PXP_TXPLL_SDM_IFM);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SSC,
CSR_2L_PXP_TXPLL_SSC_PHASE_INI);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_REFIN_DIV,
CSR_2L_PXP_TXPLL_RST_DLY, 0x4);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SDM_DI_LS,
CSR_2L_PXP_TXPLL_SDM_DI_LS);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_SDM_DI_LS,
CSR_2L_PXP_TXPLL_SDM_ORD, 0x3);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_TCL_KBAND_VREF,
CSR_2L_PXP_TXPLL_VCO_KBAND_MEAS_EN);
writel(0x0, pcie_phy->csr_2l + REG_CSR_2L_TXPLL_SSC_DELTA1);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_CHP_IOFST,
CSR_2L_PXP_TXPLL_LPF_BP, 0x1);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_CHP_IOFST,
CSR_2L_PXP_TXPLL_LPF_BC, 0x18);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_CHP_IOFST,
CSR_2L_PXP_TXPLL_LPF_BR, 0x5);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_CHP_IOFST,
CSR_2L_PXP_TXPLL_CHP_IOFST, 0x1);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_750M_SYS_CK,
CSR_2L_PXP_TXPLL_CHP_IBIAS, 0x2d);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_TCL_VTP,
CSR_2L_PXP_TXPLL_SPARE_L, 0x1);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_LPF_BWR,
CSR_2L_PXP_TXPLL_LPF_BWC);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_POSTDIV,
CSR_2L_PXP_TXPLL_MMD_PREDIV_MODE);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_REFIN_DIV,
CSR_2L_PXP_TXPLL_REFIN_DIV);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_TCL_LPF_BW,
CSR_2L_PXP_TXPLL_VCO_HALFLSB_EN);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_VCO_SCAPWR,
CSR_2L_PXP_TXPLL_VCO_SCAPWR, 0x7);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_TCL_LPF_BW,
CSR_2L_PXP_TXPLL_VCO_CFIX, 0x3);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_SEL_DA_PXP_TXPLL_SDM_PCW);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC,
PCIE_FORCE_SEL_DA_PXP_TXPLL_SDM_PCW);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SSC,
CSR_2L_PXP_TXPLL_SSC_PHASE_INI);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_LPF_BWR,
CSR_2L_PXP_TXPLL_LPF_BWR);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_PHY_CK2,
CSR_2L_PXP_TXPLL_REFIN_INTERNAL);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_TCL_KBAND_VREF,
CSR_2L_PXP_TXPLL_VCO_KBAND_MEAS_EN);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_VTP,
CSR_2L_PXP_TXPLL_VTP_EN);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_POSTDIV,
CSR_2L_PXP_TXPLL_PHY_CK1_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_PHY_CK2,
CSR_2L_PXP_TXPLL_REFIN_INTERNAL);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SSC,
CSR_2L_PXP_TXPLL_SSC_EN);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_750M_SYS_CK,
CSR_2L_PXP_TXPLL_LPF_SHCK_EN);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_POSTDIV,
CSR_2L_PXP_TXPLL_POSTDIV_EN);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_KBAND_DIV,
CSR_2L_PXP_TXPLL_KBAND_KFC);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_KBAND_DIV,
CSR_2L_PXP_TXPLL_KBAND_KF, 0x3);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_KBAND_DIV,
CSR_2L_PXP_txpll_KBAND_KS, 0x1);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_KBAND_DIV,
CSR_2L_PXP_TXPLL_KBAND_DIV, 0x4);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_LPF_BWR,
CSR_2L_PXP_TXPLL_KBAND_CODE, 0xe4);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_SDM_OUT,
CSR_2L_PXP_TXPLL_TCL_AMP_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_TCL_AMP_VREF,
CSR_2L_PXP_TXPLL_TCL_LPF_EN);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_TXPLL_TCL_KBAND_VREF,
CSR_2L_PXP_TXPLL_TCL_KBAND_VREF, 0xf);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_SDM_OUT,
CSR_2L_PXP_TXPLL_TCL_AMP_GAIN, 0x3);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_TXPLL_TCL_AMP_VREF,
CSR_2L_PXP_TXPLL_TCL_AMP_VREF, 0xb);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_TCL_LPF_BW,
CSR_2L_PXP_TXPLL_TCL_LPF_BW, 0x3);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_TXPLL_CKOUT_EN);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_DA_PXP_TXPLL_CKOUT_EN);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_TXPLL_CKOUT_EN);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_DA_PXP_TXPLL_CKOUT_EN);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_TXPLL_EN);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_DA_PXP_TXPLL_EN);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_SEL_DA_PXP_TXPLL_EN);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT,
PCIE_FORCE_DA_PXP_TXPLL_EN);
}
static void airoha_pcie_phy_init_ssc_jcpll(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_SSC_DELTA1,
CSR_2L_PXP_JCPLL_SSC_DELTA1, 0x106);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_SSC_DELTA1,
CSR_2L_PXP_JCPLL_SSC_DELTA, 0x106);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_SSC_PERIOD,
CSR_2L_PXP_JCPLL_SSC_PERIOD, 0x31b);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC,
CSR_2L_PXP_JCPLL_SSC_PHASE_INI);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC,
CSR_2L_PXP_JCPLL_SSC_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SDM_IFM,
CSR_2L_PXP_JCPLL_SDM_IFM);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SDM_HREN,
REG_CSR_2L_JCPLL_SDM_HREN);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_RST_DLY,
CSR_2L_PXP_JCPLL_SDM_DI_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC,
CSR_2L_PXP_JCPLL_SSC_TRI_EN);
}
static void
airoha_pcie_phy_set_rxlan0_signal_detect(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR0_PR_COR_HBW,
CSR_2L_PXP_CDR0_PR_LDO_FORCE_ON);
usleep_range(100, 200);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_19,
PCIE_PCP_RX_REV0_PCIE_GEN1, 0x18b0);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_20,
PCIE_PCP_RX_REV0_PCIE_GEN2, 0x18b0);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_20,
PCIE_PCP_RX_REV0_PCIE_GEN3, 0x1030);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_SIGDET_DCTEST,
CSR_2L_PXP_RX0_SIGDET_PEAK, 0x2);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_SIGDET_VTH_SEL,
CSR_2L_PXP_RX0_SIGDET_VTH_SEL, 0x5);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_REV0,
CSR_2L_PXP_VOS_PNINV, 0x2);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_SIGDET_DCTEST,
CSR_2L_PXP_RX0_SIGDET_LPF_CTRL, 0x1);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_CAL2,
PCIE_CAL_OUT_OS, 0x0);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_PXP_RX0_FE_VB_EQ2,
CSR_2L_PXP_RX0_FE_VCM_GEN_PWDB);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_GAIN_CTRL,
PCIE_FORCE_SEL_DA_PXP_RX_FE_PWDB);
airoha_phy_pma0_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_GAIN_CTRL,
PCIE_FORCE_DA_PXP_RX_FE_GAIN_CTRL, 0x3);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_RX_FORCE_MODE0,
PCIE_FORCE_DA_XPON_RX_FE_GAIN_CTRL, 0x1);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_SIGDET0,
PCIE_SIGDET_WIN_NONVLD_TIMES, 0x3);
airoha_phy_pma0_clear_bits(pcie_phy, REG_PCIE_PMA_SEQUENCE_DISB_CTRL1,
PCIE_DISB_RX_SDCAL_EN);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_CTRL_SEQUENCE_FORCE_CTRL1,
PCIE_FORCE_RX_SDCAL_EN);
usleep_range(150, 200);
airoha_phy_pma0_clear_bits(pcie_phy,
REG_PCIE_PMA_CTRL_SEQUENCE_FORCE_CTRL1,
PCIE_FORCE_RX_SDCAL_EN);
}
static void
airoha_pcie_phy_set_rxlan1_signal_detect(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR1_PR_COR_HBW,
CSR_2L_PXP_CDR1_PR_LDO_FORCE_ON);
usleep_range(100, 200);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_19,
PCIE_PCP_RX_REV0_PCIE_GEN1, 0x18b0);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_20,
PCIE_PCP_RX_REV0_PCIE_GEN2, 0x18b0);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_20,
PCIE_PCP_RX_REV0_PCIE_GEN3, 0x1030);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_SIGDET_NOVTH,
CSR_2L_PXP_RX1_SIGDET_PEAK, 0x2);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_SIGDET_NOVTH,
CSR_2L_PXP_RX1_SIGDET_VTH_SEL, 0x5);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_REV0,
CSR_2L_PXP_VOS_PNINV, 0x2);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_DAC_RANGE_EYE,
CSR_2L_PXP_RX1_SIGDET_LPF_CTRL, 0x1);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_CAL2,
PCIE_CAL_OUT_OS, 0x0);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_RX1_FE_VB_EQ1,
CSR_2L_PXP_RX1_FE_VCM_GEN_PWDB);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_GAIN_CTRL,
PCIE_FORCE_SEL_DA_PXP_RX_FE_PWDB);
airoha_phy_pma1_update_field(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_GAIN_CTRL,
PCIE_FORCE_DA_PXP_RX_FE_GAIN_CTRL, 0x3);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_RX_FORCE_MODE0,
PCIE_FORCE_DA_XPON_RX_FE_GAIN_CTRL, 0x1);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_SIGDET0,
PCIE_SIGDET_WIN_NONVLD_TIMES, 0x3);
airoha_phy_pma1_clear_bits(pcie_phy, REG_PCIE_PMA_SEQUENCE_DISB_CTRL1,
PCIE_DISB_RX_SDCAL_EN);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_CTRL_SEQUENCE_FORCE_CTRL1,
PCIE_FORCE_RX_SDCAL_EN);
usleep_range(150, 200);
airoha_phy_pma1_clear_bits(pcie_phy,
REG_PCIE_PMA_CTRL_SEQUENCE_FORCE_CTRL1,
PCIE_FORCE_RX_SDCAL_EN);
}
static void airoha_pcie_phy_set_rxflow(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_RX_SCAN_RST,
PCIE_FORCE_DA_PXP_RX_SIGDET_PWDB |
PCIE_FORCE_SEL_DA_PXP_RX_SIGDET_PWDB);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_RX_SCAN_RST,
PCIE_FORCE_DA_PXP_RX_SIGDET_PWDB |
PCIE_FORCE_SEL_DA_PXP_RX_SIGDET_PWDB);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PD_PWDB,
PCIE_FORCE_DA_PXP_CDR_PD_PWDB |
PCIE_FORCE_SEL_DA_PXP_CDR_PD_PWDB);
airoha_phy_pma0_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_PWDB,
PCIE_FORCE_DA_PXP_RX_FE_PWDB |
PCIE_FORCE_SEL_DA_PXP_RX_FE_PWDB);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_CDR_PD_PWDB,
PCIE_FORCE_DA_PXP_CDR_PD_PWDB |
PCIE_FORCE_SEL_DA_PXP_CDR_PD_PWDB);
airoha_phy_pma1_set_bits(pcie_phy,
REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_PWDB,
PCIE_FORCE_DA_PXP_RX_FE_PWDB |
PCIE_FORCE_SEL_DA_PXP_RX_FE_PWDB);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_RX0_PHYCK_DIV,
CSR_2L_PXP_RX0_PHYCK_RSTB |
CSR_2L_PXP_RX0_TDC_CK_SEL);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_RX1_PHYCK_DIV,
CSR_2L_PXP_RX1_PHYCK_RSTB |
CSR_2L_PXP_RX1_TDC_CK_SEL);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_SW_RESET,
PCIE_SW_RX_FIFO_RST | PCIE_SW_TX_RST |
PCIE_SW_PMA_RST | PCIE_SW_ALLPCS_RST |
PCIE_SW_TX_FIFO_RST);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_SW_RESET,
PCIE_SW_RX_FIFO_RST | PCIE_SW_TX_RST |
PCIE_SW_PMA_RST | PCIE_SW_ALLPCS_RST |
PCIE_SW_TX_FIFO_RST);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_PXP_RX0_FE_VB_EQ2,
CSR_2L_PXP_RX0_FE_VB_EQ2_EN |
CSR_2L_PXP_RX0_FE_VB_EQ3_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_RX0_SIGDET_VTH_SEL,
CSR_2L_PXP_RX0_FE_VB_EQ1_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_RX1_FE_VB_EQ1,
CSR_2L_PXP_RX1_FE_VB_EQ1_EN |
CSR_2L_PXP_RX1_FE_VB_EQ2_EN |
CSR_2L_PXP_RX1_FE_VB_EQ3_EN);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_REV0,
CSR_2L_PXP_FE_GAIN_NORMAL_MODE, 0x4);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_REV0,
CSR_2L_PXP_FE_GAIN_TRAIN_MODE, 0x4);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_REV0,
CSR_2L_PXP_FE_GAIN_NORMAL_MODE, 0x4);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_REV0,
CSR_2L_PXP_FE_GAIN_TRAIN_MODE, 0x4);
}
static void airoha_pcie_phy_set_pr(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_PR_VREG_IBAND,
CSR_2L_PXP_CDR0_PR_VREG_IBAND, 0x5);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_PR_VREG_IBAND,
CSR_2L_PXP_CDR0_PR_VREG_CKBUF, 0x5);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR0_PR_CKREF_DIV,
CSR_2L_PXP_CDR0_PR_CKREF_DIV);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR0_PR_COR_HBW,
CSR_2L_PXP_CDR0_PR_CKREF_DIV1);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_CDR1_PR_VREG_IBAND_VAL,
CSR_2L_PXP_CDR1_PR_VREG_IBAND, 0x5);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_CDR1_PR_VREG_IBAND_VAL,
CSR_2L_PXP_CDR1_PR_VREG_CKBUF, 0x5);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR1_PR_CKREF_DIV,
CSR_2L_PXP_CDR1_PR_CKREF_DIV);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR1_PR_COR_HBW,
CSR_2L_PXP_CDR1_PR_CKREF_DIV1);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_LPF_RATIO,
CSR_2L_PXP_CDR0_LPF_TOP_LIM, 0x20000);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR1_LPF_RATIO,
CSR_2L_PXP_CDR1_LPF_TOP_LIM, 0x20000);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_PR_BETA_DAC,
CSR_2L_PXP_CDR0_PR_BETA_SEL, 0x2);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR1_PR_BETA_DAC,
CSR_2L_PXP_CDR1_PR_BETA_SEL, 0x2);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_PR_BETA_DAC,
CSR_2L_PXP_CDR0_PR_KBAND_DIV, 0x4);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR1_PR_BETA_DAC,
CSR_2L_PXP_CDR1_PR_KBAND_DIV, 0x4);
}
static void airoha_pcie_phy_set_txflow(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TX0_CKLDO,
CSR_2L_PXP_TX0_CKLDO_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TX1_CKLDO,
CSR_2L_PXP_TX1_CKLDO_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TX0_CKLDO,
CSR_2L_PXP_TX0_DMEDGEGEN_EN);
airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TX1_CKLDO,
CSR_2L_PXP_TX1_DMEDGEGEN_EN);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TX1_MULTLANE,
CSR_2L_PXP_TX1_MULTLANE_EN);
}
static void airoha_pcie_phy_set_rx_mode(struct airoha_pcie_phy *pcie_phy)
{
writel(0x804000, pcie_phy->pma0 + REG_PCIE_PMA_DIG_RESERVE_27);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18,
PCIE_PXP_RX_VTH_SEL_PCIE_G1, 0x5);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18,
PCIE_PXP_RX_VTH_SEL_PCIE_G2, 0x5);
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18,
PCIE_PXP_RX_VTH_SEL_PCIE_G3, 0x5);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_30,
0x77700);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR0_PR_MONCK,
CSR_2L_PXP_CDR0_PR_MONCK_ENABLE);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_PR_MONCK,
CSR_2L_PXP_CDR0_PR_RESERVE0, 0x2);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_PXP_RX0_OSCAL_CTLE1IOS,
CSR_2L_PXP_RX0_PR_OSCAL_VGA1IOS, 0x19);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_PXP_RX0_OSCA_VGA1VOS,
CSR_2L_PXP_RX0_PR_OSCAL_VGA1VOS, 0x19);
airoha_phy_csr_2l_update_field(pcie_phy,
REG_CSR_2L_PXP_RX0_OSCA_VGA1VOS,
CSR_2L_PXP_RX0_PR_OSCAL_VGA2IOS, 0x14);
writel(0x804000, pcie_phy->pma1 + REG_PCIE_PMA_DIG_RESERVE_27);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18,
PCIE_PXP_RX_VTH_SEL_PCIE_G1, 0x5);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18,
PCIE_PXP_RX_VTH_SEL_PCIE_G2, 0x5);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18,
PCIE_PXP_RX_VTH_SEL_PCIE_G3, 0x5);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_30,
0x77700);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR1_PR_MONCK,
CSR_2L_PXP_CDR1_PR_MONCK_ENABLE);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR1_PR_MONCK,
CSR_2L_PXP_CDR1_PR_RESERVE0, 0x2);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_OSCAL_VGA1IOS,
CSR_2L_PXP_RX1_PR_OSCAL_VGA1IOS, 0x19);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_OSCAL_VGA1IOS,
CSR_2L_PXP_RX1_PR_OSCAL_VGA1VOS, 0x19);
airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_OSCAL_VGA1IOS,
CSR_2L_PXP_RX1_PR_OSCAL_VGA2IOS, 0x14);
}
static void airoha_pcie_phy_load_kflow(struct airoha_pcie_phy *pcie_phy)
{
airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_12,
PCIE_FORCE_PMA_RX_SPEED, 0xa);
airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_12,
PCIE_FORCE_PMA_RX_SPEED, 0xa);
airoha_phy_init_lane0_rx_fw_pre_calib(pcie_phy, PCIE_PORT_GEN3);
airoha_phy_init_lane1_rx_fw_pre_calib(pcie_phy, PCIE_PORT_GEN3);
airoha_phy_pma0_clear_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_12,
PCIE_FORCE_PMA_RX_SPEED);
airoha_phy_pma1_clear_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_12,
PCIE_FORCE_PMA_RX_SPEED);
usleep_range(100, 200);
airoha_phy_init_lane0_rx_fw_pre_calib(pcie_phy, PCIE_PORT_GEN2);
airoha_phy_init_lane1_rx_fw_pre_calib(pcie_phy, PCIE_PORT_GEN2);
}
/**
* airoha_pcie_phy_init() - Initialize the phy
* @phy: the phy to be initialized
*
* Initialize the phy registers.
* The hardware settings will be reset during suspend, it should be
* reinitialized when the consumer calls phy_init() again on resume.
*/
static int airoha_pcie_phy_init(struct phy *phy)
{
struct airoha_pcie_phy *pcie_phy = phy_get_drvdata(phy);
u32 val;
/* Setup Tx-Rx detection time */
val = FIELD_PREP(PCIE_XTP_RXDET_VCM_OFF_STB_T_SEL, 0x33) |
FIELD_PREP(PCIE_XTP_RXDET_EN_STB_T_SEL, 0x1) |
FIELD_PREP(PCIE_XTP_RXDET_FINISH_STB_T_SEL, 0x2) |
FIELD_PREP(PCIE_XTP_TXPD_TX_DATA_EN_DLY, 0x3) |
FIELD_PREP(PCIE_XTP_RXDET_LATCH_STB_T_SEL, 0x1);
writel(val, pcie_phy->p0_xr_dtime + REG_PCIE_PEXTP_DIG_GLB44);
writel(val, pcie_phy->p1_xr_dtime + REG_PCIE_PEXTP_DIG_GLB44);
/* Setup Rx AEQ training time */
val = FIELD_PREP(PCIE_XTP_LN_RX_PDOWN_L1P2_EXIT_WAIT, 0x32) |
FIELD_PREP(PCIE_XTP_LN_RX_PDOWN_E0_AEQEN_WAIT, 0x5050);
writel(val, pcie_phy->rx_aeq + REG_PCIE_PEXTP_DIG_LN_RX30_P0);
writel(val, pcie_phy->rx_aeq + REG_PCIE_PEXTP_DIG_LN_RX30_P1);
/* enable load FLL-K flow */
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_14,
PCIE_FLL_LOAD_EN);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_14,
PCIE_FLL_LOAD_EN);
airoha_pcie_phy_init_default(pcie_phy);
airoha_pcie_phy_init_clk_out(pcie_phy);
airoha_pcie_phy_init_csr_2l(pcie_phy);
usleep_range(100, 200);
airoha_pcie_phy_init_rx(pcie_phy);
/* phase 1, no ssc for K TXPLL */
airoha_pcie_phy_init_jcpll(pcie_phy);
usleep_range(500, 600);
/* TX PLL settings */
airoha_pcie_phy_txpll(pcie_phy);
usleep_range(200, 300);
/* SSC JCPLL setting */
airoha_pcie_phy_init_ssc_jcpll(pcie_phy);
usleep_range(100, 200);
/* Rx lan0 signal detect */
airoha_pcie_phy_set_rxlan0_signal_detect(pcie_phy);
/* Rx lan1 signal detect */
airoha_pcie_phy_set_rxlan1_signal_detect(pcie_phy);
/* RX FLOW */
airoha_pcie_phy_set_rxflow(pcie_phy);
usleep_range(100, 200);
airoha_pcie_phy_set_pr(pcie_phy);
/* TX FLOW */
airoha_pcie_phy_set_txflow(pcie_phy);
usleep_range(100, 200);
/* RX mode setting */
airoha_pcie_phy_set_rx_mode(pcie_phy);
/* Load K-Flow */
airoha_pcie_phy_load_kflow(pcie_phy);
airoha_phy_pma0_clear_bits(pcie_phy, REG_PCIE_PMA_SS_DA_XPON_PWDB0,
PCIE_DA_XPON_CDR_PR_PWDB);
airoha_phy_pma1_clear_bits(pcie_phy, REG_PCIE_PMA_SS_DA_XPON_PWDB0,
PCIE_DA_XPON_CDR_PR_PWDB);
usleep_range(100, 200);
airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_SS_DA_XPON_PWDB0,
PCIE_DA_XPON_CDR_PR_PWDB);
airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_SS_DA_XPON_PWDB0,
PCIE_DA_XPON_CDR_PR_PWDB);
usleep_range(100, 200);
return 0;
}
static int airoha_pcie_phy_exit(struct phy *phy)
{
struct airoha_pcie_phy *pcie_phy = phy_get_drvdata(phy);
airoha_phy_pma0_clear_bits(pcie_phy, REG_PCIE_PMA_SW_RESET,
PCIE_PMA_SW_RST);
airoha_phy_pma1_clear_bits(pcie_phy, REG_PCIE_PMA_SW_RESET,
PCIE_PMA_SW_RST);
airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC,
CSR_2L_PXP_JCPLL_SSC_PHASE_INI |
CSR_2L_PXP_JCPLL_SSC_TRI_EN |
CSR_2L_PXP_JCPLL_SSC_EN);
return 0;
}
static const struct phy_ops airoha_pcie_phy_ops = {
.init = airoha_pcie_phy_init,
.exit = airoha_pcie_phy_exit,
.owner = THIS_MODULE,
};
static int airoha_pcie_phy_probe(struct platform_device *pdev)
{
struct airoha_pcie_phy *pcie_phy;
struct device *dev = &pdev->dev;
struct phy_provider *provider;
pcie_phy = devm_kzalloc(dev, sizeof(*pcie_phy), GFP_KERNEL);
if (!pcie_phy)
return -ENOMEM;
pcie_phy->csr_2l = devm_platform_ioremap_resource_byname(pdev, "csr-2l");
if (IS_ERR(pcie_phy->csr_2l))
return dev_err_probe(dev, PTR_ERR(pcie_phy->csr_2l),
"Failed to map phy-csr-2l base\n");
pcie_phy->pma0 = devm_platform_ioremap_resource_byname(pdev, "pma0");
if (IS_ERR(pcie_phy->pma0))
return dev_err_probe(dev, PTR_ERR(pcie_phy->pma0),
"Failed to map phy-pma0 base\n");
pcie_phy->pma1 = devm_platform_ioremap_resource_byname(pdev, "pma1");
if (IS_ERR(pcie_phy->pma1))
return dev_err_probe(dev, PTR_ERR(pcie_phy->pma1),
"Failed to map phy-pma1 base\n");
pcie_phy->phy = devm_phy_create(dev, dev->of_node, &airoha_pcie_phy_ops);
if (IS_ERR(pcie_phy->phy))
return dev_err_probe(dev, PTR_ERR(pcie_phy->phy),
"Failed to create PCIe phy\n");
pcie_phy->p0_xr_dtime =
devm_platform_ioremap_resource_byname(pdev, "p0-xr-dtime");
if (IS_ERR(pcie_phy->p0_xr_dtime))
return dev_err_probe(dev, PTR_ERR(pcie_phy->p0_xr_dtime),
"Failed to map P0 Tx-Rx dtime base\n");
pcie_phy->p1_xr_dtime =
devm_platform_ioremap_resource_byname(pdev, "p1-xr-dtime");
if (IS_ERR(pcie_phy->p1_xr_dtime))
return dev_err_probe(dev, PTR_ERR(pcie_phy->p1_xr_dtime),
"Failed to map P1 Tx-Rx dtime base\n");
pcie_phy->rx_aeq = devm_platform_ioremap_resource_byname(pdev, "rx-aeq");
if (IS_ERR(pcie_phy->rx_aeq))
return dev_err_probe(dev, PTR_ERR(pcie_phy->rx_aeq),
"Failed to map Rx AEQ base\n");
pcie_phy->dev = dev;
phy_set_drvdata(pcie_phy->phy, pcie_phy);
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(provider))
return dev_err_probe(dev, PTR_ERR(provider),
"PCIe phy probe failed\n");
return 0;
}
static const struct of_device_id airoha_pcie_phy_of_match[] = {
{ .compatible = "airoha,en7581-pcie-phy" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, airoha_pcie_phy_of_match);
static struct platform_driver airoha_pcie_phy_driver = {
.probe = airoha_pcie_phy_probe,
.driver = {
.name = "airoha-pcie-phy",
.of_match_table = airoha_pcie_phy_of_match,
},
};
module_platform_driver(airoha_pcie_phy_driver);
MODULE_DESCRIPTION("Airoha PCIe PHY driver");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
MODULE_LICENSE("GPL");
......@@ -664,7 +664,7 @@ static struct phy *_of_phy_get(struct device_node *np, int index)
*
* Returns the phy driver, after getting a refcount to it; or
* -ENODEV if there is no such phy. The caller is responsible for
* calling phy_put() to release that count.
* calling of_phy_put() to release that count.
*/
struct phy *of_phy_get(struct device_node *np, const char *con_id)
{
......
......@@ -489,6 +489,243 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_gen3_pcs_misc_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
};
static const struct qmp_phy_init_tbl ipq9574_gen3x1_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CLKBUFLR_EN, 0x18),
QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CTRL_BY_PSM, 0x01),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_SELECT, 0x31),
QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_IVCO, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_PLL_BG_TRIM, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_PLL_CMN_CONFIG, 0x06),
QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP_EN, 0x42),
QMP_PHY_INIT_CFG(QSERDES_PLL_RESETSM_CNTRL, 0x20),
QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_MAP, 0x04),
QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_TIMER1, 0xff),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_TIMER2, 0x3f),
QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x30),
QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x21),
QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE0, 0x68),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START3_MODE0, 0x02),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START2_MODE0, 0xaa),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START1_MODE0, 0xab),
QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE0, 0x14),
QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE0, 0xd4),
QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE0, 0x09),
QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE0, 0x16),
QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE0, 0x28),
QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN1_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE0, 0xa0),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE0, 0x02),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE0, 0x24),
QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05),
QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x20),
QMP_PHY_INIT_CFG(QSERDES_PLL_CORECLK_DIV, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_SELECT, 0x32),
QMP_PHY_INIT_CFG(QSERDES_PLL_SYS_CLK_CTRL, 0x02),
QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_BUF_ENABLE, 0x07),
QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_EN_SEL, 0x08),
QMP_PHY_INIT_CFG(QSERDES_PLL_BG_TIMER, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE1, 0x53),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START3_MODE1, 0x05),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START2_MODE1, 0x55),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START1_MODE1, 0x55),
QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE1, 0x29),
QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE1, 0xaa),
QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE1, 0x09),
QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE1, 0x16),
QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE1, 0x28),
QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN1_MODE1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE1, 0xa0),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE1, 0x03),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE1, 0xb4),
QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05),
QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x00),
QMP_PHY_INIT_CFG(QSERDES_PLL_CORECLK_DIV_MODE1, 0x08),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER1, 0x7d),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER2, 0x01),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_ADJ_PER1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_ADJ_PER2, 0x00),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE1_MODE0, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE2_MODE0, 0x05),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE1_MODE1, 0x08),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE2_MODE1, 0x04),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_EP_DIV_MODE0, 0x19),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_EP_DIV_MODE1, 0x28),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_ENABLE1, 0x90),
QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x89),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_ENABLE1, 0x10),
};
static const struct qmp_phy_init_tbl ipq9574_gen3x2_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CLKBUFLR_EN, 0x18),
QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CTRL_BY_PSM, 0x01),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_SELECT, 0x31),
QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_IVCO, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_PLL_BG_TRIM, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_PLL_CMN_CONFIG, 0x06),
QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP_EN, 0x42),
QMP_PHY_INIT_CFG(QSERDES_PLL_RESETSM_CNTRL, 0x20),
QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_MAP, 0x04),
QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_TIMER1, 0xff),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_TIMER2, 0x3f),
QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x30),
QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x21),
QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE0, 0x68),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START3_MODE0, 0x02),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START2_MODE0, 0xaa),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START1_MODE0, 0xab),
QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE0, 0x14),
QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE0, 0xd4),
QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE0, 0x09),
QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE0, 0x16),
QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE0, 0x28),
QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN1_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE0, 0xa0),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE0, 0x02),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE0, 0x24),
QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05),
QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x00),
QMP_PHY_INIT_CFG(QSERDES_PLL_CORECLK_DIV, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_SELECT, 0x32),
QMP_PHY_INIT_CFG(QSERDES_PLL_SYS_CLK_CTRL, 0x02),
QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_BUF_ENABLE, 0x07),
QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_EN_SEL, 0x08),
QMP_PHY_INIT_CFG(QSERDES_PLL_BG_TIMER, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE1, 0x53),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START3_MODE1, 0x05),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START2_MODE1, 0x55),
QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START1_MODE1, 0x55),
QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE1, 0x29),
QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE1, 0xaa),
QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE1, 0x09),
QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE1, 0x16),
QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE1, 0x28),
QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN1_MODE1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE1, 0xa0),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE1, 0x03),
QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE1, 0xb4),
QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05),
QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x00),
QMP_PHY_INIT_CFG(QSERDES_PLL_CORECLK_DIV_MODE1, 0x08),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER1, 0x7d),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER2, 0x01),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_ADJ_PER1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_ADJ_PER2, 0x00),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE1_MODE0, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE2_MODE0, 0x05),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE1_MODE1, 0x08),
QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE2_MODE1, 0x04),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_EP_DIV_MODE0, 0x19),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_EP_DIV_MODE1, 0x28),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_ENABLE1, 0x90),
QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x89),
QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_ENABLE1, 0x10),
};
static const struct qmp_phy_init_tbl ipq9574_pcie_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x03),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_ENABLES, 0x1c),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x14),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x61),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1e),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FO_GAIN, 0x0c),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x70),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL1, 0x73),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x80),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_LOW, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH2, 0xc8),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH3, 0x09),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH4, 0xb1),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0xc8),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x09),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0xb1),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0xf0),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0x2f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0xd3),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x40),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0),
};
static const struct qmp_phy_init_tbl ipq9574_gen3x1_pcie_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_H, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_DCC_CAL_CONFIG, 0x01),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x0d),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_G12S1_TXDEEMPH_M3P5DB, 0x10),
};
static const struct qmp_phy_init_tbl ipq9574_gen3x1_pcie_pcs_misc_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_POWER_STATE_CONFIG2, 0x0d),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_H, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_EQ_CONFIG1, 0x14),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_EQ_CONFIG1, 0x10),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_EQ_CONFIG2, 0x0b),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_PRESET_P10_PRE, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_PRESET_P10_POST, 0x58),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_POWER_STATE_CONFIG4, 0x07),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_CONFIG2, 0x52),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_INT_AUX_CLK_CONFIG1, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_MODE2_CONFIG2, 0x50),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_MODE2_CONFIG4, 0x1a),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5, 0x06),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_MODE2_CONFIG6, 0x03),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
};
static const struct qmp_phy_init_tbl ipq9574_gen3x2_pcie_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x0d),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_G12S1_TXDEEMPH_M3P5DB, 0x10),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_H, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_DCC_CAL_CONFIG, 0x01),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa),
};
static const struct qmp_phy_init_tbl ipq9574_gen3x2_pcie_pcs_misc_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG2, 0x1d),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H, 0x00),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_H, 0x00),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_EQ_CONFIG1, 0x14),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_EQ_CONFIG1, 0x10),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_EQ_CONFIG2, 0x0b),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_PRESET_P10_PRE, 0x00),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_PRESET_P10_POST, 0x58),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG4, 0x07),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG1, 0x00),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG2, 0x52),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG4, 0x19),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_INT_AUX_CLK_CONFIG1, 0x00),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG2, 0x49),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG4, 0x2a),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5, 0x02),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG6, 0x03),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
};
static const struct qmp_phy_init_tbl sdm845_qmp_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
......@@ -2535,6 +2772,16 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v5 = {
.rx2 = 0x1800,
};
static const struct qmp_pcie_offsets qmp_pcie_offsets_ipq9574 = {
.serdes = 0,
.pcs = 0x1000,
.pcs_misc = 0x1400,
.tx = 0x0200,
.rx = 0x0400,
.tx2 = 0x0600,
.rx2 = 0x0800,
};
static const struct qmp_pcie_offsets qmp_pcie_offsets_v5_20 = {
.serdes = 0x1000,
.pcs = 0x1200,
......@@ -2647,6 +2894,62 @@ static const struct qmp_phy_cfg ipq6018_pciephy_cfg = {
.phy_status = PHYSTATUS,
};
static const struct qmp_phy_cfg ipq9574_gen3x1_pciephy_cfg = {
.lanes = 1,
.offsets = &qmp_pcie_offsets_v4x1,
.tbls = {
.serdes = ipq9574_gen3x1_pcie_serdes_tbl,
.serdes_num = ARRAY_SIZE(ipq9574_gen3x1_pcie_serdes_tbl),
.tx = ipq8074_pcie_gen3_tx_tbl,
.tx_num = ARRAY_SIZE(ipq8074_pcie_gen3_tx_tbl),
.rx = ipq9574_pcie_rx_tbl,
.rx_num = ARRAY_SIZE(ipq9574_pcie_rx_tbl),
.pcs = ipq9574_gen3x1_pcie_pcs_tbl,
.pcs_num = ARRAY_SIZE(ipq9574_gen3x1_pcie_pcs_tbl),
.pcs_misc = ipq9574_gen3x1_pcie_pcs_misc_tbl,
.pcs_misc_num = ARRAY_SIZE(ipq9574_gen3x1_pcie_pcs_misc_tbl),
},
.reset_list = ipq8074_pciephy_reset_l,
.num_resets = ARRAY_SIZE(ipq8074_pciephy_reset_l),
.vreg_list = NULL,
.num_vregs = 0,
.regs = pciephy_v4_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
.pipe_clock_rate = 250000000,
};
static const struct qmp_phy_cfg ipq9574_gen3x2_pciephy_cfg = {
.lanes = 2,
.offsets = &qmp_pcie_offsets_ipq9574,
.tbls = {
.serdes = ipq9574_gen3x2_pcie_serdes_tbl,
.serdes_num = ARRAY_SIZE(ipq9574_gen3x2_pcie_serdes_tbl),
.tx = ipq8074_pcie_gen3_tx_tbl,
.tx_num = ARRAY_SIZE(ipq8074_pcie_gen3_tx_tbl),
.rx = ipq9574_pcie_rx_tbl,
.rx_num = ARRAY_SIZE(ipq9574_pcie_rx_tbl),
.pcs = ipq9574_gen3x2_pcie_pcs_tbl,
.pcs_num = ARRAY_SIZE(ipq9574_gen3x2_pcie_pcs_tbl),
.pcs_misc = ipq9574_gen3x2_pcie_pcs_misc_tbl,
.pcs_misc_num = ARRAY_SIZE(ipq9574_gen3x2_pcie_pcs_misc_tbl),
},
.reset_list = ipq8074_pciephy_reset_l,
.num_resets = ARRAY_SIZE(ipq8074_pciephy_reset_l),
.vreg_list = NULL,
.num_vregs = 0,
.regs = pciephy_v5_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
.pipe_clock_rate = 250000000,
};
static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = {
.lanes = 1,
......@@ -3730,14 +4033,11 @@ static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np)
{
struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed;
struct clk_init_data init = { };
int ret;
char name[64];
ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name);
if (ret) {
dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np);
return ret;
}
snprintf(name, sizeof(name), "%s::phy_aux_clk", dev_name(qmp->dev));
init.name = name;
init.ops = &clk_fixed_rate_ops;
fixed->fixed_rate = qmp->cfg->aux_clock_rate;
......@@ -4030,6 +4330,12 @@ static const struct of_device_id qmp_pcie_of_match_table[] = {
}, {
.compatible = "qcom,ipq8074-qmp-pcie-phy",
.data = &ipq8074_pciephy_cfg,
}, {
.compatible = "qcom,ipq9574-qmp-gen3x1-pcie-phy",
.data = &ipq9574_gen3x1_pciephy_cfg,
}, {
.compatible = "qcom,ipq9574-qmp-gen3x2-pcie-phy",
.data = &ipq9574_gen3x2_pciephy_cfg,
}, {
.compatible = "qcom,msm8998-qmp-pcie-phy",
.data = &msm8998_pciephy_cfg,
......
......@@ -11,8 +11,22 @@
#define QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG2 0x0c
#define QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG4 0x14
#define QPHY_V5_PCS_PCIE_ENDPOINT_REFCLK_DRIVE 0x20
#define QPHY_V5_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L 0x44
#define QPHY_V5_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H 0x48
#define QPHY_V5_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L 0x4c
#define QPHY_V5_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_H 0x50
#define QPHY_V5_PCS_PCIE_INT_AUX_CLK_CONFIG1 0x54
#define QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG1 0x5c
#define QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG2 0x60
#define QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG4 0x68
#define QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG2 0x7c
#define QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG4 0x84
#define QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5 0x88
#define QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG6 0x8c
#define QPHY_V5_PCS_PCIE_OSC_DTCT_ACTIONS 0x94
#define QPHY_V5_PCS_PCIE_EQ_CONFIG1 0xa4
#define QPHY_V5_PCS_PCIE_EQ_CONFIG2 0xa8
#define QPHY_V5_PCS_PCIE_PRESET_P10_PRE 0xc0
#define QPHY_V5_PCS_PCIE_PRESET_P10_POST 0xe4
#endif
......@@ -8,6 +8,9 @@
/* QMP V2 PHY for PCIE gen3 ports - QSERDES PLL registers */
#define QSERDES_PLL_BG_TIMER 0x00c
#define QSERDES_PLL_SSC_EN_CENTER 0x010
#define QSERDES_PLL_SSC_ADJ_PER1 0x014
#define QSERDES_PLL_SSC_ADJ_PER2 0x018
#define QSERDES_PLL_SSC_PER1 0x01c
#define QSERDES_PLL_SSC_PER2 0x020
#define QSERDES_PLL_SSC_STEP_SIZE1_MODE0 0x024
......
......@@ -2252,6 +2252,9 @@ static const struct of_device_id qmp_usb_of_match_table[] = {
}, {
.compatible = "qcom,sa8775p-qmp-usb3-uni-phy",
.data = &sa8775p_usb3_uniphy_cfg,
}, {
.compatible = "qcom,sc8180x-qmp-usb3-uni-phy",
.data = &sm8150_usb3_uniphy_cfg,
}, {
.compatible = "qcom,sc8280xp-qmp-usb3-uni-phy",
.data = &sc8280xp_usb3_uniphy_cfg,
......
......@@ -86,7 +86,9 @@ config PHY_ROCKCHIP_PCIE
config PHY_ROCKCHIP_SAMSUNG_HDPTX
tristate "Rockchip Samsung HDMI/eDP Combo PHY driver"
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
depends on HAS_IOMEM
select GENERIC_PHY
select MFD_SYSCON
select RATIONAL
help
Enable this to support the Rockchip HDMI/eDP Combo PHY
......
......@@ -8,6 +8,7 @@
* Author: Vivek Gautam <gautam.vivek@samsung.com>
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
......@@ -30,18 +31,16 @@
#define EXYNOS5_FSEL_19MHZ2 0x3
#define EXYNOS5_FSEL_20MHZ 0x4
#define EXYNOS5_FSEL_24MHZ 0x5
#define EXYNOS5_FSEL_26MHZ 0x82
#define EXYNOS5_FSEL_26MHZ 0x6
#define EXYNOS5_FSEL_50MHZ 0x7
/* Exynos5: USB 3.0 DRD PHY registers */
#define EXYNOS5_DRD_LINKSYSTEM 0x04
#define LINKSYSTEM_XHCI_VERSION_CONTROL BIT(27)
#define LINKSYSTEM_FLADJ_MASK (0x3f << 1)
#define LINKSYSTEM_FLADJ(_x) ((_x) << 1)
#define LINKSYSTEM_XHCI_VERSION_CONTROL BIT(27)
#define EXYNOS5_DRD_PHYUTMI 0x08
#define PHYUTMI_OTGDISABLE BIT(6)
#define PHYUTMI_FORCESUSPEND BIT(1)
#define PHYUTMI_FORCESLEEP BIT(0)
......@@ -49,40 +48,31 @@
#define EXYNOS5_DRD_PHYPIPE 0x0c
#define EXYNOS5_DRD_PHYCLKRST 0x10
#define PHYCLKRST_EN_UTMISUSPEND BIT(31)
#define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23)
#define PHYCLKRST_SSC_REFCLKSEL(_x) ((_x) << 23)
#define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21)
#define PHYCLKRST_SSC_RANGE(_x) ((_x) << 21)
#define PHYCLKRST_SSC_EN BIT(20)
#define PHYCLKRST_REF_SSP_EN BIT(19)
#define PHYCLKRST_REF_CLKDIV2 BIT(18)
#define PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11)
#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF (0x19 << 11)
#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF (0x32 << 11)
#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF (0x68 << 11)
#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF (0x7d << 11)
#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF (0x02 << 11)
#define PHYCLKRST_FSEL_UTMI_MASK (0x7 << 5)
#define PHYCLKRST_FSEL_PIPE_MASK (0x7 << 8)
#define PHYCLKRST_FSEL_UTMI_MASK (0x7 << 5)
#define PHYCLKRST_FSEL(_x) ((_x) << 5)
#define PHYCLKRST_FSEL_PAD_100MHZ (0x27 << 5)
#define PHYCLKRST_FSEL_PAD_24MHZ (0x2a << 5)
#define PHYCLKRST_FSEL_PAD_20MHZ (0x31 << 5)
#define PHYCLKRST_FSEL_PAD_19_2MHZ (0x38 << 5)
#define PHYCLKRST_RETENABLEN BIT(4)
#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2)
#define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2)
#define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2)
#define PHYCLKRST_PORTRESET BIT(1)
#define PHYCLKRST_COMMONONN BIT(0)
......@@ -100,30 +90,27 @@
#define PHYREG1_CR_ACK BIT(0)
#define EXYNOS5_DRD_PHYPARAM0 0x1c
#define PHYPARAM0_REF_USE_PAD BIT(31)
#define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26)
#define PHYPARAM0_REF_LOSLEVEL (0x9 << 26)
#define EXYNOS5_DRD_PHYPARAM1 0x20
#define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0)
#define PHYPARAM1_PCS_TXDEEMPH (0x1c)
#define EXYNOS5_DRD_PHYTERM 0x24
#define EXYNOS5_DRD_PHYTEST 0x28
#define PHYTEST_POWERDOWN_SSP BIT(3)
#define PHYTEST_POWERDOWN_HSP BIT(2)
#define EXYNOS5_DRD_PHYADP 0x2c
#define EXYNOS5_DRD_PHYUTMICLKSEL 0x30
#define PHYUTMICLKSEL_UTMI_CLKSEL BIT(2)
#define EXYNOS5_DRD_PHYRESUME 0x34
#define EXYNOS5_DRD_LINKPORT 0x44
/* USB 3.0 DRD PHY SS Function Control Reg; accessed by CR_PORT */
......@@ -147,35 +134,215 @@
/* Exynos850: USB DRD PHY registers */
#define EXYNOS850_DRD_LINKCTRL 0x04
#define LINKCTRL_BUS_FILTER_BYPASS(_x) ((_x) << 4)
#define LINKCTRL_FORCE_RXELECIDLE BIT(18)
#define LINKCTRL_FORCE_PHYSTATUS BIT(17)
#define LINKCTRL_FORCE_PIPE_EN BIT(16)
#define LINKCTRL_FORCE_QACT BIT(8)
#define LINKCTRL_BUS_FILTER_BYPASS(_x) ((_x) << 4)
#define EXYNOS850_DRD_LINKPORT 0x08
#define LINKPORT_HOST_NUM_U3 GENMASK(19, 16)
#define LINKPORT_HOST_NUM_U2 GENMASK(15, 12)
#define EXYNOS850_DRD_CLKRST 0x20
#define CLKRST_LINK_SW_RST BIT(0)
#define CLKRST_PORT_RST BIT(1)
/*
* On versions without SS ports (like E850), bit 3 is for the 2.0 phy (HS),
* while on versions with (like gs101), bits 2 and 3 are for the 3.0 phy (SS)
* and bits 12 & 13 for the 2.0 phy.
*/
#define CLKRST_PHY20_SW_POR BIT(13)
#define CLKRST_PHY20_SW_POR_SEL BIT(12)
#define CLKRST_LINK_PCLK_SEL BIT(7)
#define CLKRST_PHY_SW_RST BIT(3)
#define CLKRST_PHY_RESET_SEL BIT(2)
#define CLKRST_PORT_RST BIT(1)
#define CLKRST_LINK_SW_RST BIT(0)
#define EXYNOS850_DRD_SSPPLLCTL 0x30
#define SSPPLLCTL_FSEL GENMASK(2, 0)
#define EXYNOS850_DRD_UTMI 0x50
#define UTMI_FORCE_SLEEP BIT(0)
#define UTMI_FORCE_SUSPEND BIT(1)
#define UTMI_DM_PULLDOWN BIT(2)
#define UTMI_DP_PULLDOWN BIT(3)
#define UTMI_FORCE_BVALID BIT(4)
#define UTMI_FORCE_VBUSVALID BIT(5)
#define UTMI_FORCE_BVALID BIT(4)
#define UTMI_DP_PULLDOWN BIT(3)
#define UTMI_DM_PULLDOWN BIT(2)
#define UTMI_FORCE_SUSPEND BIT(1)
#define UTMI_FORCE_SLEEP BIT(0)
#define EXYNOS850_DRD_HSP 0x54
#define HSP_COMMONONN BIT(8)
#define HSP_EN_UTMISUSPEND BIT(9)
#define HSP_VBUSVLDEXT BIT(12)
#define HSP_VBUSVLDEXTSEL BIT(13)
#define HSP_FSV_OUT_EN BIT(24)
#define HSP_VBUSVLDEXTSEL BIT(13)
#define HSP_VBUSVLDEXT BIT(12)
#define HSP_EN_UTMISUSPEND BIT(9)
#define HSP_COMMONONN BIT(8)
#define EXYNOS850_DRD_HSPPARACON 0x58
#define HSPPARACON_TXVREF GENMASK(31, 28)
#define HSPPARACON_TXRISE GENMASK(25, 24)
#define HSPPARACON_TXRES GENMASK(22, 21)
#define HSPPARACON_TXPREEMPPULSE BIT(20)
#define HSPPARACON_TXPREEMPAMP GENMASK(19, 18)
#define HSPPARACON_TXHSXV GENMASK(17, 16)
#define HSPPARACON_TXFSLS GENMASK(15, 12)
#define HSPPARACON_SQRX GENMASK(10, 8)
#define HSPPARACON_OTG GENMASK(6, 4)
#define HSPPARACON_COMPDIS GENMASK(2, 0)
#define EXYNOS850_DRD_HSP_TEST 0x5c
#define HSP_TEST_SIDDQ BIT(24)
/* Exynos9 - GS101 */
#define EXYNOS850_DRD_SECPMACTL 0x48
#define SECPMACTL_PMA_ROPLL_REF_CLK_SEL GENMASK(13, 12)
#define SECPMACTL_PMA_LCPLL_REF_CLK_SEL GENMASK(11, 10)
#define SECPMACTL_PMA_REF_FREQ_SEL GENMASK(9, 8)
#define SECPMACTL_PMA_LOW_PWR BIT(4)
#define SECPMACTL_PMA_TRSV_SW_RST BIT(3)
#define SECPMACTL_PMA_CMN_SW_RST BIT(2)
#define SECPMACTL_PMA_INIT_SW_RST BIT(1)
#define SECPMACTL_PMA_APB_SW_RST BIT(0)
/* PMA registers */
#define EXYNOS9_PMA_USBDP_CMN_REG0008 0x0020
#define CMN_REG0008_OVRD_AUX_EN BIT(3)
#define CMN_REG0008_AUX_EN BIT(2)
#define EXYNOS9_PMA_USBDP_CMN_REG00B8 0x02e0
#define CMN_REG00B8_LANE_MUX_SEL_DP GENMASK(3, 0)
#define EXYNOS9_PMA_USBDP_CMN_REG01C0 0x0700
#define CMN_REG01C0_ANA_LCPLL_LOCK_DONE BIT(7)
#define CMN_REG01C0_ANA_LCPLL_AFC_DONE BIT(6)
/* these have similar register layout, for lanes 0 and 2 */
#define EXYNOS9_PMA_USBDP_TRSV_REG03C3 0x0f0c
#define EXYNOS9_PMA_USBDP_TRSV_REG07C3 0x1f0c
#define TRSV_REG03C3_LN0_MON_RX_CDR_AFC_DONE BIT(3)
#define TRSV_REG03C3_LN0_MON_RX_CDR_CAL_DONE BIT(2)
#define TRSV_REG03C3_LN0_MON_RX_CDR_FLD_PLL_MODE_DONE BIT(1)
#define TRSV_REG03C3_LN0_MON_RX_CDR_LOCK_DONE BIT(0)
/* TRSV_REG0413 and TRSV_REG0813 have similar register layout */
#define EXYNOS9_PMA_USBDP_TRSV_REG0413 0x104c
#define TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN BIT(7)
#define TRSV_REG0413_OVRD_LN1_TX_RXD_EN BIT(5)
#define EXYNOS9_PMA_USBDP_TRSV_REG0813 0x204c
#define TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN BIT(7)
#define TRSV_REG0813_OVRD_LN3_TX_RXD_EN BIT(5)
/* PCS registers */
#define EXYNOS9_PCS_NS_VEC_PS1_N1 0x010c
#define EXYNOS9_PCS_NS_VEC_PS2_N0 0x0110
#define EXYNOS9_PCS_NS_VEC_PS3_N0 0x0118
#define NS_VEC_NS_REQ GENMASK(31, 24)
#define NS_VEC_ENABLE_TIMER BIT(22)
#define NS_VEC_SEL_TIMEOUT GENMASK(21, 20)
#define NS_VEC_INV_MASK GENMASK(19, 16)
#define NS_VEC_COND_MASK GENMASK(11, 8)
#define NS_VEC_EXP_COND GENMASK(3, 0)
#define EXYNOS9_PCS_OUT_VEC_2 0x014c
#define EXYNOS9_PCS_OUT_VEC_3 0x0150
#define PCS_OUT_VEC_B9_DYNAMIC BIT(19)
#define PCS_OUT_VEC_B9_SEL_OUT BIT(18)
#define PCS_OUT_VEC_B8_DYNAMIC BIT(17)
#define PCS_OUT_VEC_B8_SEL_OUT BIT(16)
#define PCS_OUT_VEC_B7_DYNAMIC BIT(15)
#define PCS_OUT_VEC_B7_SEL_OUT BIT(14)
#define PCS_OUT_VEC_B6_DYNAMIC BIT(13)
#define PCS_OUT_VEC_B6_SEL_OUT BIT(12)
#define PCS_OUT_VEC_B5_DYNAMIC BIT(11)
#define PCS_OUT_VEC_B5_SEL_OUT BIT(10)
#define PCS_OUT_VEC_B4_DYNAMIC BIT(9)
#define PCS_OUT_VEC_B4_SEL_OUT BIT(8)
#define PCS_OUT_VEC_B3_DYNAMIC BIT(7)
#define PCS_OUT_VEC_B3_SEL_OUT BIT(6)
#define PCS_OUT_VEC_B2_DYNAMIC BIT(5)
#define PCS_OUT_VEC_B2_SEL_OUT BIT(4)
#define PCS_OUT_VEC_B1_DYNAMIC BIT(3)
#define PCS_OUT_VEC_B1_SEL_OUT BIT(2)
#define PCS_OUT_VEC_B0_DYNAMIC BIT(1)
#define PCS_OUT_VEC_B0_SEL_OUT BIT(0)
#define EXYNOS9_PCS_TIMEOUT_0 0x0170
#define EXYNOS9_PCS_TIMEOUT_3 0x017c
#define EXYNOS9_PCS_EBUF_PARAM 0x0304
#define EBUF_PARAM_SKP_REMOVE_TH_EMPTY_MODE GENMASK(29, 24)
#define EXYNOS9_PCS_BACK_END_MODE_VEC 0x030c
#define BACK_END_MODE_VEC_FORCE_EBUF_EMPTY_MODE BIT(1)
#define BACK_END_MODE_VEC_DISABLE_DATA_MASK BIT(0)
#define EXYNOS9_PCS_RX_CONTROL 0x03f0
#define RX_CONTROL_EN_BLOCK_ALIGNER_TYPE_B BIT(22)
#define EXYNOS9_PCS_RX_CONTROL_DEBUG 0x03f4
#define RX_CONTROL_DEBUG_EN_TS_CHECK BIT(5)
#define RX_CONTROL_DEBUG_NUM_COM_FOUND GENMASK(3, 0)
#define EXYNOS9_PCS_LOCAL_COEF 0x040c
#define LOCAL_COEF_PMA_CENTER_COEF GENMASK(21, 16)
#define LOCAL_COEF_LF GENMASK(13, 8)
#define LOCAL_COEF_FS GENMASK(5, 0)
#define EXYNOS9_PCS_HS_TX_COEF_MAP_0 0x0410
#define HS_TX_COEF_MAP_0_SSTX_DEEMP GENMASK(17, 12)
#define HS_TX_COEF_MAP_0_SSTX_LEVEL GENMASK(11, 6)
#define HS_TX_COEF_MAP_0_SSTX_PRE_SHOOT GENMASK(5, 0)
#define KHZ 1000
#define MHZ (KHZ * KHZ)
#define PHY_TUNING_ENTRY_PHY(o, m, v) { \
.off = (o), \
.mask = (m), \
.val = (v), \
.region = PTR_PHY \
}
#define PHY_TUNING_ENTRY_PCS(o, m, v) { \
.off = (o), \
.mask = (m), \
.val = (v), \
.region = PTR_PCS \
}
#define PHY_TUNING_ENTRY_PMA(o, m, v) { \
.off = (o), \
.mask = (m), \
.val = (v), \
.region = PTR_PMA, \
}
#define PHY_TUNING_ENTRY_LAST { .region = PTR_INVALID }
#define for_each_phy_tune(tune) \
for (; (tune)->region != PTR_INVALID; ++(tune))
struct exynos5_usbdrd_phy_tuning {
u32 off;
u32 mask;
u32 val;
char region;
#define PTR_INVALID 0
#define PTR_PHY 1
#define PTR_PCS 2
#define PTR_PMA 3
};
enum exynos5_usbdrd_phy_tuning_state {
PTS_UTMI_POSTINIT,
PTS_PIPE3_PREINIT,
PTS_PIPE3_INIT,
PTS_PIPE3_POSTINIT,
PTS_PIPE3_POSTLOCK,
PTS_MAX,
};
enum exynos5_usbdrd_phy_id {
EXYNOS5_DRDPHY_UTMI,
EXYNOS5_DRDPHY_PIPE3,
......@@ -187,44 +354,48 @@ struct exynos5_usbdrd_phy;
struct exynos5_usbdrd_phy_config {
u32 id;
void (*phy_isol)(struct phy_usb_instance *inst, u32 on);
void (*phy_isol)(struct phy_usb_instance *inst, bool isolate);
void (*phy_init)(struct exynos5_usbdrd_phy *phy_drd);
unsigned int (*set_refclk)(struct phy_usb_instance *inst);
};
struct exynos5_usbdrd_phy_drvdata {
const struct exynos5_usbdrd_phy_config *phy_cfg;
const struct exynos5_usbdrd_phy_tuning **phy_tunes;
const struct phy_ops *phy_ops;
const char * const *clk_names;
int n_clks;
const char * const *core_clk_names;
int n_core_clks;
const char * const *regulator_names;
int n_regulators;
u32 pmu_offset_usbdrd0_phy;
u32 pmu_offset_usbdrd0_phy_ss;
u32 pmu_offset_usbdrd1_phy;
bool has_common_clk_gate;
};
/**
* struct exynos5_usbdrd_phy - driver data for USB 3.0 PHY
* @dev: pointer to device instance of this platform device
* @reg_phy: usb phy controller register memory base
* @clk: phy clock for register access
* @pipeclk: clock for pipe3 phy
* @utmiclk: clock for utmi+ phy
* @itpclk: clock for ITP generation
* @reg_pcs: usb phy physical coding sublayer register memory base
* @reg_pma: usb phy physical media attachment register memory base
* @clks: clocks for register access
* @core_clks: core clocks for phy (ref, pipe3, utmi+, ITP, etc. as required)
* @drv_data: pointer to SoC level driver data structure
* @phys: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
* instances each with its 'phy' and 'phy_cfg'.
* @extrefclk: frequency select settings when using 'separate
* reference clocks' for SS and HS operations
* @ref_clk: reference clock to PHY block from which PHY's
* operational clocks are derived
* @vbus: VBUS regulator for phy
* @vbus_boost: Boost regulator for VBUS present on few Exynos boards
* @regulators: regulators for phy
*/
struct exynos5_usbdrd_phy {
struct device *dev;
void __iomem *reg_phy;
struct clk *clk;
struct clk *pipeclk;
struct clk *utmiclk;
struct clk *itpclk;
void __iomem *reg_pcs;
void __iomem *reg_pma;
struct clk_bulk_data *clks;
struct clk_bulk_data *core_clks;
const struct exynos5_usbdrd_phy_drvdata *drv_data;
struct phy_usb_instance {
struct phy *phy;
......@@ -234,9 +405,7 @@ struct exynos5_usbdrd_phy {
const struct exynos5_usbdrd_phy_config *phy_cfg;
} phys[EXYNOS5_DRDPHYS_NUM];
u32 extrefclk;
struct clk *ref_clk;
struct regulator *vbus;
struct regulator *vbus_boost;
struct regulator_bulk_data *regulators;
};
static inline
......@@ -287,14 +456,14 @@ static unsigned int exynos5_rate_to_clk(unsigned long rate, u32 *reg)
}
static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst,
unsigned int on)
bool isolate)
{
unsigned int val;
if (!inst->reg_pmu)
return;
val = on ? 0 : EXYNOS4_PHY_ENABLE;
val = isolate ? 0 : EXYNOS4_PHY_ENABLE;
regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
EXYNOS4_PHY_ENABLE, val);
......@@ -371,6 +540,45 @@ exynos5_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst)
return reg;
}
static void
exynos5_usbdrd_apply_phy_tunes(struct exynos5_usbdrd_phy *phy_drd,
enum exynos5_usbdrd_phy_tuning_state state)
{
const struct exynos5_usbdrd_phy_tuning *tune;
tune = phy_drd->drv_data->phy_tunes[state];
if (!tune)
return;
for_each_phy_tune(tune) {
void __iomem *reg_base;
u32 reg = 0;
switch (tune->region) {
case PTR_PHY:
reg_base = phy_drd->reg_phy;
break;
case PTR_PCS:
reg_base = phy_drd->reg_pcs;
break;
case PTR_PMA:
reg_base = phy_drd->reg_pma;
break;
default:
dev_warn_once(phy_drd->dev,
"unknown phy region %d\n", tune->region);
continue;
}
if (~tune->mask) {
reg = readl(reg_base + tune->off);
reg &= ~tune->mask;
}
reg |= tune->val;
writel(reg, reg_base + tune->off);
}
}
static void exynos5_usbdrd_pipe3_init(struct exynos5_usbdrd_phy *phy_drd)
{
u32 reg;
......@@ -386,6 +594,129 @@ static void exynos5_usbdrd_pipe3_init(struct exynos5_usbdrd_phy *phy_drd)
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
}
static void
exynos5_usbdrd_usbdp_g2_v4_ctrl_pma_ready(struct exynos5_usbdrd_phy *phy_drd)
{
void __iomem *regs_base = phy_drd->reg_phy;
u32 reg;
/* link pipe_clock selection to pclk of PMA */
reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
reg |= CLKRST_LINK_PCLK_SEL;
writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL);
reg &= ~SECPMACTL_PMA_REF_FREQ_SEL;
reg |= FIELD_PREP_CONST(SECPMACTL_PMA_REF_FREQ_SEL, 1);
/* SFR reset */
reg |= (SECPMACTL_PMA_LOW_PWR | SECPMACTL_PMA_APB_SW_RST);
reg &= ~(SECPMACTL_PMA_ROPLL_REF_CLK_SEL |
SECPMACTL_PMA_LCPLL_REF_CLK_SEL);
/* PMA power off */
reg |= (SECPMACTL_PMA_TRSV_SW_RST | SECPMACTL_PMA_CMN_SW_RST |
SECPMACTL_PMA_INIT_SW_RST);
writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL);
udelay(1);
reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL);
reg &= ~SECPMACTL_PMA_LOW_PWR;
writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL);
udelay(1);
/* release override */
reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL);
reg &= ~LINKCTRL_FORCE_PIPE_EN;
writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
udelay(1);
/* APB enable */
reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL);
reg &= ~SECPMACTL_PMA_APB_SW_RST;
writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL);
}
static void
exynos5_usbdrd_usbdp_g2_v4_pma_lane_mux_sel(struct exynos5_usbdrd_phy *phy_drd)
{
void __iomem *regs_base = phy_drd->reg_pma;
u32 reg;
/* lane configuration: USB on all lanes */
reg = readl(regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8);
reg &= ~CMN_REG00B8_LANE_MUX_SEL_DP;
writel(reg, regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8);
/*
* FIXME: below code supports one connector orientation only. It needs
* updating once we can receive connector events.
*/
/* override of TX receiver detector and comparator: lane 1 */
reg = readl(regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0413);
reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN;
reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_EN;
writel(reg, regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0413);
/* lane 3 */
reg = readl(regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0813);
reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN;
reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_EN;
writel(reg, regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0813);
}
static int
exynos5_usbdrd_usbdp_g2_v4_pma_check_pll_lock(struct exynos5_usbdrd_phy *phy_drd)
{
static const unsigned int timeout_us = 40000;
static const unsigned int sleep_us = 40;
static const u32 locked = (CMN_REG01C0_ANA_LCPLL_LOCK_DONE |
CMN_REG01C0_ANA_LCPLL_AFC_DONE);
u32 reg;
int err;
err = readl_poll_timeout(
phy_drd->reg_pma + EXYNOS9_PMA_USBDP_CMN_REG01C0,
reg, (reg & locked) == locked, sleep_us, timeout_us);
if (err)
dev_err(phy_drd->dev,
"timed out waiting for PLL lock: %#.8x\n", reg);
return err;
}
static void
exynos5_usbdrd_usbdp_g2_v4_pma_check_cdr_lock(struct exynos5_usbdrd_phy *phy_drd)
{
static const unsigned int timeout_us = 40000;
static const unsigned int sleep_us = 40;
static const u32 locked =
(TRSV_REG03C3_LN0_MON_RX_CDR_AFC_DONE
| TRSV_REG03C3_LN0_MON_RX_CDR_CAL_DONE
| TRSV_REG03C3_LN0_MON_RX_CDR_FLD_PLL_MODE_DONE
| TRSV_REG03C3_LN0_MON_RX_CDR_LOCK_DONE);
u32 reg;
int err;
err = readl_poll_timeout(
phy_drd->reg_pma + EXYNOS9_PMA_USBDP_TRSV_REG03C3,
reg, (reg & locked) == locked, sleep_us, timeout_us);
if (!err)
return;
dev_err(phy_drd->dev,
"timed out waiting for CDR lock (l0): %#.8x, retrying\n", reg);
/* based on cable orientation, this might be on the other phy port */
err = readl_poll_timeout(
phy_drd->reg_pma + EXYNOS9_PMA_USBDP_TRSV_REG07C3,
reg, (reg & locked) == locked, sleep_us, timeout_us);
if (err)
dev_err(phy_drd->dev,
"timed out waiting for CDR lock (l2): %#.8x\n", reg);
}
static void exynos5_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
{
u32 reg;
......@@ -417,7 +748,7 @@ static int exynos5_usbdrd_phy_init(struct phy *phy)
struct phy_usb_instance *inst = phy_get_drvdata(phy);
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
ret = clk_prepare_enable(phy_drd->clk);
ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
if (ret)
return ret;
......@@ -462,12 +793,12 @@ static int exynos5_usbdrd_phy_init(struct phy *phy)
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
udelay(10);
fsleep(10);
reg &= ~PHYCLKRST_PORTRESET;
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
clk_disable_unprepare(phy_drd->clk);
clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
return 0;
}
......@@ -479,7 +810,7 @@ static int exynos5_usbdrd_phy_exit(struct phy *phy)
struct phy_usb_instance *inst = phy_get_drvdata(phy);
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
ret = clk_prepare_enable(phy_drd->clk);
ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
if (ret)
return ret;
......@@ -501,7 +832,7 @@ static int exynos5_usbdrd_phy_exit(struct phy *phy)
PHYTEST_POWERDOWN_HSP;
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
clk_disable_unprepare(phy_drd->clk);
clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
return 0;
}
......@@ -514,47 +845,27 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy)
dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n");
clk_prepare_enable(phy_drd->ref_clk);
if (!phy_drd->drv_data->has_common_clk_gate) {
clk_prepare_enable(phy_drd->pipeclk);
clk_prepare_enable(phy_drd->utmiclk);
clk_prepare_enable(phy_drd->itpclk);
}
ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_core_clks,
phy_drd->core_clks);
if (ret)
return ret;
/* Enable VBUS supply */
if (phy_drd->vbus_boost) {
ret = regulator_enable(phy_drd->vbus_boost);
if (ret) {
dev_err(phy_drd->dev,
"Failed to enable VBUS boost supply\n");
goto fail_vbus;
}
}
if (phy_drd->vbus) {
ret = regulator_enable(phy_drd->vbus);
if (ret) {
dev_err(phy_drd->dev, "Failed to enable VBUS supply\n");
goto fail_vbus_boost;
}
ret = regulator_bulk_enable(phy_drd->drv_data->n_regulators,
phy_drd->regulators);
if (ret) {
dev_err(phy_drd->dev, "Failed to enable PHY regulator(s)\n");
goto fail_vbus;
}
/* Power-on PHY*/
inst->phy_cfg->phy_isol(inst, 0);
/* Power-on PHY */
inst->phy_cfg->phy_isol(inst, false);
return 0;
fail_vbus_boost:
if (phy_drd->vbus_boost)
regulator_disable(phy_drd->vbus_boost);
fail_vbus:
clk_disable_unprepare(phy_drd->ref_clk);
if (!phy_drd->drv_data->has_common_clk_gate) {
clk_disable_unprepare(phy_drd->itpclk);
clk_disable_unprepare(phy_drd->utmiclk);
clk_disable_unprepare(phy_drd->pipeclk);
}
clk_bulk_disable_unprepare(phy_drd->drv_data->n_core_clks,
phy_drd->core_clks);
return ret;
}
......@@ -567,20 +878,14 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy)
dev_dbg(phy_drd->dev, "Request to power_off usbdrd_phy phy\n");
/* Power-off the PHY */
inst->phy_cfg->phy_isol(inst, 1);
inst->phy_cfg->phy_isol(inst, true);
/* Disable VBUS supply */
if (phy_drd->vbus)
regulator_disable(phy_drd->vbus);
if (phy_drd->vbus_boost)
regulator_disable(phy_drd->vbus_boost);
clk_disable_unprepare(phy_drd->ref_clk);
if (!phy_drd->drv_data->has_common_clk_gate) {
clk_disable_unprepare(phy_drd->itpclk);
clk_disable_unprepare(phy_drd->pipeclk);
clk_disable_unprepare(phy_drd->utmiclk);
}
regulator_bulk_disable(phy_drd->drv_data->n_regulators,
phy_drd->regulators);
clk_bulk_disable_unprepare(phy_drd->drv_data->n_core_clks,
phy_drd->core_clks);
return 0;
}
......@@ -744,10 +1049,29 @@ static const struct phy_ops exynos5_usbdrd_phy_ops = {
.owner = THIS_MODULE,
};
static void
exynos5_usbdrd_usb_v3p1_pipe_override(struct exynos5_usbdrd_phy *phy_drd)
{
void __iomem *regs_base = phy_drd->reg_phy;
u32 reg;
/* force pipe3 signal for link */
reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL);
reg &= ~LINKCTRL_FORCE_PHYSTATUS;
reg |= LINKCTRL_FORCE_PIPE_EN | LINKCTRL_FORCE_RXELECIDLE;
writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
/* PMA disable */
reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL);
reg |= SECPMACTL_PMA_LOW_PWR;
writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL);
}
static void exynos850_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
{
void __iomem *regs_base = phy_drd->reg_phy;
u32 reg;
u32 ss_ports;
/*
* Disable HWACG (hardware auto clock gating control). This will force
......@@ -758,8 +1082,16 @@ static void exynos850_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
reg |= LINKCTRL_FORCE_QACT;
writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
reg = readl(regs_base + EXYNOS850_DRD_LINKPORT);
ss_ports = FIELD_GET(LINKPORT_HOST_NUM_U3, reg);
/* Start PHY Reset (POR=high) */
reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
if (ss_ports) {
reg |= CLKRST_PHY20_SW_POR;
reg |= CLKRST_PHY20_SW_POR_SEL;
reg |= CLKRST_PHY_RESET_SEL;
}
reg |= CLKRST_PHY_SW_RST;
writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
......@@ -787,22 +1119,58 @@ static void exynos850_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
reg |= HSP_VBUSVLDEXT | HSP_VBUSVLDEXTSEL;
writel(reg, regs_base + EXYNOS850_DRD_HSP);
reg = readl(regs_base + EXYNOS850_DRD_SSPPLLCTL);
reg &= ~SSPPLLCTL_FSEL;
switch (phy_drd->extrefclk) {
case EXYNOS5_FSEL_50MHZ:
reg |= FIELD_PREP_CONST(SSPPLLCTL_FSEL, 7);
break;
case EXYNOS5_FSEL_26MHZ:
reg |= FIELD_PREP_CONST(SSPPLLCTL_FSEL, 6);
break;
case EXYNOS5_FSEL_24MHZ:
reg |= FIELD_PREP_CONST(SSPPLLCTL_FSEL, 2);
break;
case EXYNOS5_FSEL_20MHZ:
reg |= FIELD_PREP_CONST(SSPPLLCTL_FSEL, 1);
break;
case EXYNOS5_FSEL_19MHZ2:
reg |= FIELD_PREP_CONST(SSPPLLCTL_FSEL, 0);
break;
default:
dev_warn(phy_drd->dev, "unsupported ref clk: %#.2x\n",
phy_drd->extrefclk);
break;
}
writel(reg, regs_base + EXYNOS850_DRD_SSPPLLCTL);
if (phy_drd->drv_data->phy_tunes)
exynos5_usbdrd_apply_phy_tunes(phy_drd,
PTS_UTMI_POSTINIT);
/* Power up PHY analog blocks */
reg = readl(regs_base + EXYNOS850_DRD_HSP_TEST);
reg &= ~HSP_TEST_SIDDQ;
writel(reg, regs_base + EXYNOS850_DRD_HSP_TEST);
/* Finish PHY reset (POR=low) */
udelay(10); /* required before doing POR=low */
fsleep(10); /* required before doing POR=low */
reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
if (ss_ports) {
reg |= CLKRST_PHY20_SW_POR_SEL;
reg &= ~CLKRST_PHY20_SW_POR;
}
reg &= ~(CLKRST_PHY_SW_RST | CLKRST_PORT_RST);
writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
udelay(75); /* required after POR=low for guaranteed PHY clock */
fsleep(75); /* required after POR=low for guaranteed PHY clock */
/* Disable single ended signal out */
reg = readl(regs_base + EXYNOS850_DRD_HSP);
reg &= ~HSP_FSV_OUT_EN;
writel(reg, regs_base + EXYNOS850_DRD_HSP);
if (ss_ports)
exynos5_usbdrd_usb_v3p1_pipe_override(phy_drd);
}
static int exynos850_usbdrd_phy_init(struct phy *phy)
......@@ -811,14 +1179,14 @@ static int exynos850_usbdrd_phy_init(struct phy *phy)
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
int ret;
ret = clk_prepare_enable(phy_drd->clk);
ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
if (ret)
return ret;
/* UTMI or PIPE3 specific init */
inst->phy_cfg->phy_init(phy_drd);
clk_disable_unprepare(phy_drd->clk);
clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
return 0;
}
......@@ -831,7 +1199,7 @@ static int exynos850_usbdrd_phy_exit(struct phy *phy)
u32 reg;
int ret;
ret = clk_prepare_enable(phy_drd->clk);
ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
if (ret)
return ret;
......@@ -850,11 +1218,11 @@ static int exynos850_usbdrd_phy_exit(struct phy *phy)
reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
reg |= CLKRST_LINK_SW_RST;
writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
udelay(10); /* required before doing POR=low */
fsleep(10); /* required before doing POR=low */
reg &= ~CLKRST_LINK_SW_RST;
writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
clk_disable_unprepare(phy_drd->clk);
clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
return 0;
}
......@@ -867,53 +1235,138 @@ static const struct phy_ops exynos850_usbdrd_phy_ops = {
.owner = THIS_MODULE,
};
static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
static void exynos5_usbdrd_gs101_pipe3_init(struct exynos5_usbdrd_phy *phy_drd)
{
unsigned long ref_rate;
void __iomem *regs_pma = phy_drd->reg_pma;
void __iomem *regs_phy = phy_drd->reg_phy;
u32 reg;
exynos5_usbdrd_usbdp_g2_v4_ctrl_pma_ready(phy_drd);
/* force aux off */
reg = readl(regs_pma + EXYNOS9_PMA_USBDP_CMN_REG0008);
reg &= ~CMN_REG0008_AUX_EN;
reg |= CMN_REG0008_OVRD_AUX_EN;
writel(reg, regs_pma + EXYNOS9_PMA_USBDP_CMN_REG0008);
exynos5_usbdrd_apply_phy_tunes(phy_drd, PTS_PIPE3_PREINIT);
exynos5_usbdrd_apply_phy_tunes(phy_drd, PTS_PIPE3_INIT);
exynos5_usbdrd_apply_phy_tunes(phy_drd, PTS_PIPE3_POSTINIT);
exynos5_usbdrd_usbdp_g2_v4_pma_lane_mux_sel(phy_drd);
/* reset release from port */
reg = readl(regs_phy + EXYNOS850_DRD_SECPMACTL);
reg &= ~(SECPMACTL_PMA_TRSV_SW_RST | SECPMACTL_PMA_CMN_SW_RST |
SECPMACTL_PMA_INIT_SW_RST);
writel(reg, regs_phy + EXYNOS850_DRD_SECPMACTL);
if (!exynos5_usbdrd_usbdp_g2_v4_pma_check_pll_lock(phy_drd))
exynos5_usbdrd_usbdp_g2_v4_pma_check_cdr_lock(phy_drd);
}
static int exynos5_usbdrd_gs101_phy_init(struct phy *phy)
{
struct phy_usb_instance *inst = phy_get_drvdata(phy);
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
int ret;
phy_drd->clk = devm_clk_get(phy_drd->dev, "phy");
if (IS_ERR(phy_drd->clk)) {
dev_err(phy_drd->dev, "Failed to get phy clock\n");
return PTR_ERR(phy_drd->clk);
if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) {
/* Power-on PHY ... */
ret = regulator_bulk_enable(phy_drd->drv_data->n_regulators,
phy_drd->regulators);
if (ret) {
dev_err(phy_drd->dev,
"Failed to enable PHY regulator(s)\n");
return ret;
}
}
/*
* ... and ungate power via PMU. Without this here, we get an SError
* trying to access PMA registers
*/
exynos5_usbdrd_phy_isol(inst, false);
phy_drd->ref_clk = devm_clk_get(phy_drd->dev, "ref");
if (IS_ERR(phy_drd->ref_clk)) {
dev_err(phy_drd->dev, "Failed to get phy reference clock\n");
return PTR_ERR(phy_drd->ref_clk);
}
ref_rate = clk_get_rate(phy_drd->ref_clk);
return exynos850_usbdrd_phy_init(phy);
}
ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
if (ret) {
dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n",
ref_rate);
static int exynos5_usbdrd_gs101_phy_exit(struct phy *phy)
{
struct phy_usb_instance *inst = phy_get_drvdata(phy);
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
int ret;
if (inst->phy_cfg->id != EXYNOS5_DRDPHY_UTMI)
return 0;
ret = exynos850_usbdrd_phy_exit(phy);
if (ret)
return ret;
}
if (!phy_drd->drv_data->has_common_clk_gate) {
phy_drd->pipeclk = devm_clk_get(phy_drd->dev, "phy_pipe");
if (IS_ERR(phy_drd->pipeclk)) {
dev_info(phy_drd->dev,
"PIPE3 phy operational clock not specified\n");
phy_drd->pipeclk = NULL;
}
exynos5_usbdrd_phy_isol(inst, true);
return regulator_bulk_disable(phy_drd->drv_data->n_regulators,
phy_drd->regulators);
}
phy_drd->utmiclk = devm_clk_get(phy_drd->dev, "phy_utmi");
if (IS_ERR(phy_drd->utmiclk)) {
dev_info(phy_drd->dev,
"UTMI phy operational clock not specified\n");
phy_drd->utmiclk = NULL;
}
static const struct phy_ops gs101_usbdrd_phy_ops = {
.init = exynos5_usbdrd_gs101_phy_init,
.exit = exynos5_usbdrd_gs101_phy_exit,
.owner = THIS_MODULE,
};
static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
{
int ret;
struct clk *ref_clk;
unsigned long ref_rate;
phy_drd->clks = devm_kcalloc(phy_drd->dev, phy_drd->drv_data->n_clks,
sizeof(*phy_drd->clks), GFP_KERNEL);
if (!phy_drd->clks)
return -ENOMEM;
for (int i = 0; i < phy_drd->drv_data->n_clks; ++i)
phy_drd->clks[i].id = phy_drd->drv_data->clk_names[i];
ret = devm_clk_bulk_get(phy_drd->dev, phy_drd->drv_data->n_clks,
phy_drd->clks);
if (ret)
return dev_err_probe(phy_drd->dev, ret,
"failed to get phy clock(s)\n");
phy_drd->core_clks = devm_kcalloc(phy_drd->dev,
phy_drd->drv_data->n_core_clks,
sizeof(*phy_drd->core_clks),
GFP_KERNEL);
if (!phy_drd->core_clks)
return -ENOMEM;
phy_drd->itpclk = devm_clk_get(phy_drd->dev, "itp");
if (IS_ERR(phy_drd->itpclk)) {
dev_info(phy_drd->dev,
"ITP clock from main OSC not specified\n");
phy_drd->itpclk = NULL;
for (int i = 0; i < phy_drd->drv_data->n_core_clks; ++i)
phy_drd->core_clks[i].id = phy_drd->drv_data->core_clk_names[i];
ret = devm_clk_bulk_get(phy_drd->dev, phy_drd->drv_data->n_core_clks,
phy_drd->core_clks);
if (ret)
return dev_err_probe(phy_drd->dev, ret,
"failed to get phy core clock(s)\n");
ref_clk = NULL;
for (int i = 0; i < phy_drd->drv_data->n_core_clks; ++i) {
if (!strcmp(phy_drd->core_clks[i].id, "ref")) {
ref_clk = phy_drd->core_clks[i].clk;
break;
}
}
if (!ref_clk)
return dev_err_probe(phy_drd->dev, -ENODEV,
"failed to find phy reference clock\n");
ref_rate = clk_get_rate(ref_clk);
ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
if (ret)
return dev_err_probe(phy_drd->dev, ret,
"clock rate (%ld) not supported\n",
ref_rate);
return 0;
}
......@@ -941,19 +1394,45 @@ static const struct exynos5_usbdrd_phy_config phy_cfg_exynos850[] = {
},
};
static const char * const exynos5_clk_names[] = {
"phy",
};
static const char * const exynos5_core_clk_names[] = {
"ref",
};
static const char * const exynos5433_core_clk_names[] = {
"ref", "phy_pipe", "phy_utmi", "itp",
};
static const char * const exynos5_regulator_names[] = {
"vbus", "vbus-boost",
};
static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5,
.phy_ops = &exynos5_usbdrd_phy_ops,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL,
.has_common_clk_gate = true,
.clk_names = exynos5_clk_names,
.n_clks = ARRAY_SIZE(exynos5_clk_names),
.core_clk_names = exynos5_core_clk_names,
.n_core_clks = ARRAY_SIZE(exynos5_core_clk_names),
.regulator_names = exynos5_regulator_names,
.n_regulators = ARRAY_SIZE(exynos5_regulator_names),
};
static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5,
.phy_ops = &exynos5_usbdrd_phy_ops,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.has_common_clk_gate = true,
.clk_names = exynos5_clk_names,
.n_clks = ARRAY_SIZE(exynos5_clk_names),
.core_clk_names = exynos5_core_clk_names,
.n_core_clks = ARRAY_SIZE(exynos5_core_clk_names),
.regulator_names = exynos5_regulator_names,
.n_regulators = ARRAY_SIZE(exynos5_regulator_names),
};
static const struct exynos5_usbdrd_phy_drvdata exynos5433_usbdrd_phy = {
......@@ -961,25 +1440,218 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5433_usbdrd_phy = {
.phy_ops = &exynos5_usbdrd_phy_ops,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.pmu_offset_usbdrd1_phy = EXYNOS5433_USBHOST30_PHY_CONTROL,
.has_common_clk_gate = false,
.clk_names = exynos5_clk_names,
.n_clks = ARRAY_SIZE(exynos5_clk_names),
.core_clk_names = exynos5433_core_clk_names,
.n_core_clks = ARRAY_SIZE(exynos5433_core_clk_names),
.regulator_names = exynos5_regulator_names,
.n_regulators = ARRAY_SIZE(exynos5_regulator_names),
};
static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5,
.phy_ops = &exynos5_usbdrd_phy_ops,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.has_common_clk_gate = false,
.clk_names = exynos5_clk_names,
.n_clks = ARRAY_SIZE(exynos5_clk_names),
.core_clk_names = exynos5433_core_clk_names,
.n_core_clks = ARRAY_SIZE(exynos5433_core_clk_names),
.regulator_names = exynos5_regulator_names,
.n_regulators = ARRAY_SIZE(exynos5_regulator_names),
};
static const struct exynos5_usbdrd_phy_drvdata exynos850_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos850,
.phy_ops = &exynos850_usbdrd_phy_ops,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.has_common_clk_gate = true,
.clk_names = exynos5_clk_names,
.n_clks = ARRAY_SIZE(exynos5_clk_names),
.core_clk_names = exynos5_core_clk_names,
.n_core_clks = ARRAY_SIZE(exynos5_core_clk_names),
.regulator_names = exynos5_regulator_names,
.n_regulators = ARRAY_SIZE(exynos5_regulator_names),
};
static const struct exynos5_usbdrd_phy_config phy_cfg_gs101[] = {
{
.id = EXYNOS5_DRDPHY_UTMI,
.phy_isol = exynos5_usbdrd_phy_isol,
.phy_init = exynos850_usbdrd_utmi_init,
},
{
.id = EXYNOS5_DRDPHY_PIPE3,
.phy_isol = exynos5_usbdrd_phy_isol,
.phy_init = exynos5_usbdrd_gs101_pipe3_init,
},
};
static const struct exynos5_usbdrd_phy_tuning gs101_tunes_utmi_postinit[] = {
PHY_TUNING_ENTRY_PHY(EXYNOS850_DRD_HSPPARACON,
(HSPPARACON_TXVREF | HSPPARACON_TXRES |
HSPPARACON_TXPREEMPAMP | HSPPARACON_SQRX |
HSPPARACON_COMPDIS),
(FIELD_PREP_CONST(HSPPARACON_TXVREF, 6) |
FIELD_PREP_CONST(HSPPARACON_TXRES, 1) |
FIELD_PREP_CONST(HSPPARACON_TXPREEMPAMP, 3) |
FIELD_PREP_CONST(HSPPARACON_SQRX, 5) |
FIELD_PREP_CONST(HSPPARACON_COMPDIS, 7))),
PHY_TUNING_ENTRY_LAST
};
static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_preinit[] = {
/* preinit */
/* CDR data mode exit GEN1 ON / GEN2 OFF */
PHY_TUNING_ENTRY_PMA(0x0c8c, -1, 0xff),
PHY_TUNING_ENTRY_PMA(0x1c8c, -1, 0xff),
PHY_TUNING_ENTRY_PMA(0x0c9c, -1, 0x7d),
PHY_TUNING_ENTRY_PMA(0x1c9c, -1, 0x7d),
/* improve EDS distribution */
PHY_TUNING_ENTRY_PMA(0x0e7c, -1, 0x06),
PHY_TUNING_ENTRY_PMA(0x09e0, -1, 0x00),
PHY_TUNING_ENTRY_PMA(0x09e4, -1, 0x36),
PHY_TUNING_ENTRY_PMA(0x1e7c, -1, 0x06),
PHY_TUNING_ENTRY_PMA(0x1e90, -1, 0x00),
PHY_TUNING_ENTRY_PMA(0x1e94, -1, 0x36),
/* improve LVCC */
PHY_TUNING_ENTRY_PMA(0x08f0, -1, 0x30),
PHY_TUNING_ENTRY_PMA(0x18f0, -1, 0x30),
/* LFPS RX VIH shmoo hole */
PHY_TUNING_ENTRY_PMA(0x0a08, -1, 0x0c),
PHY_TUNING_ENTRY_PMA(0x1a08, -1, 0x0c),
/* remove unrelated option for v4 phy */
PHY_TUNING_ENTRY_PMA(0x0a0c, -1, 0x05),
PHY_TUNING_ENTRY_PMA(0x1a0c, -1, 0x05),
/* improve Gen2 LVCC */
PHY_TUNING_ENTRY_PMA(0x00f8, -1, 0x1c),
PHY_TUNING_ENTRY_PMA(0x00fc, -1, 0x54),
/* Change Vth of RCV_DET because of TD 7.40 Polling Retry Test */
PHY_TUNING_ENTRY_PMA(0x104c, -1, 0x07),
PHY_TUNING_ENTRY_PMA(0x204c, -1, 0x07),
/* reduce Ux Exit time, assuming 26MHz clock */
/* Gen1 */
PHY_TUNING_ENTRY_PMA(0x0ca8, -1, 0x00),
PHY_TUNING_ENTRY_PMA(0x0cac, -1, 0x04),
PHY_TUNING_ENTRY_PMA(0x1ca8, -1, 0x00),
PHY_TUNING_ENTRY_PMA(0x1cac, -1, 0x04),
/* Gen2 */
PHY_TUNING_ENTRY_PMA(0x0cb8, -1, 0x00),
PHY_TUNING_ENTRY_PMA(0x0cbc, -1, 0x04),
PHY_TUNING_ENTRY_PMA(0x1cb8, -1, 0x00),
PHY_TUNING_ENTRY_PMA(0x1cbc, -1, 0x04),
/* RX impedance setting */
PHY_TUNING_ENTRY_PMA(0x0bb0, 0x03, 0x01),
PHY_TUNING_ENTRY_PMA(0x0bb4, 0xf0, 0xa0),
PHY_TUNING_ENTRY_PMA(0x1bb0, 0x03, 0x01),
PHY_TUNING_ENTRY_PMA(0x1bb4, 0xf0, 0xa0),
PHY_TUNING_ENTRY_LAST
};
static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_init[] = {
/* init */
/* abnormal common pattern mask */
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_BACK_END_MODE_VEC,
BACK_END_MODE_VEC_DISABLE_DATA_MASK, 0),
/* de-serializer enabled when U2 */
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_OUT_VEC_2, PCS_OUT_VEC_B4_DYNAMIC,
PCS_OUT_VEC_B4_SEL_OUT),
/* TX Keeper Disable, Squelch on when U3 */
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_OUT_VEC_3, PCS_OUT_VEC_B7_DYNAMIC,
PCS_OUT_VEC_B7_SEL_OUT | PCS_OUT_VEC_B2_SEL_OUT),
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_NS_VEC_PS1_N1, -1,
(FIELD_PREP_CONST(NS_VEC_NS_REQ, 5) |
NS_VEC_ENABLE_TIMER |
FIELD_PREP_CONST(NS_VEC_SEL_TIMEOUT, 3))),
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_NS_VEC_PS2_N0, -1,
(FIELD_PREP_CONST(NS_VEC_NS_REQ, 1) |
NS_VEC_ENABLE_TIMER |
FIELD_PREP_CONST(NS_VEC_SEL_TIMEOUT, 3) |
FIELD_PREP_CONST(NS_VEC_COND_MASK, 2) |
FIELD_PREP_CONST(NS_VEC_EXP_COND, 2))),
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_NS_VEC_PS3_N0, -1,
(FIELD_PREP_CONST(NS_VEC_NS_REQ, 1) |
NS_VEC_ENABLE_TIMER |
FIELD_PREP_CONST(NS_VEC_SEL_TIMEOUT, 3) |
FIELD_PREP_CONST(NS_VEC_COND_MASK, 7) |
FIELD_PREP_CONST(NS_VEC_EXP_COND, 7))),
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_TIMEOUT_0, -1, 112),
/* Block Aligner Type B */
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_RX_CONTROL, 0,
RX_CONTROL_EN_BLOCK_ALIGNER_TYPE_B),
/* Block align at TS1/TS2 for Gen2 stability (Gen2 only) */
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_RX_CONTROL_DEBUG,
RX_CONTROL_DEBUG_NUM_COM_FOUND,
(RX_CONTROL_DEBUG_EN_TS_CHECK |
/*
* increase pcs ts1 adding packet-cnt 1 --> 4
* lnx_rx_valid_rstn_delay_rise_sp/ssp :
* 19.6us(0x200) -> 15.3us(0x4)
*/
FIELD_PREP_CONST(RX_CONTROL_DEBUG_NUM_COM_FOUND, 4))),
/* Gen1 Tx DRIVER pre-shoot, de-emphasis, level ctrl */
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_HS_TX_COEF_MAP_0,
(HS_TX_COEF_MAP_0_SSTX_DEEMP | HS_TX_COEF_MAP_0_SSTX_LEVEL |
HS_TX_COEF_MAP_0_SSTX_PRE_SHOOT),
(FIELD_PREP_CONST(HS_TX_COEF_MAP_0_SSTX_DEEMP, 8) |
FIELD_PREP_CONST(HS_TX_COEF_MAP_0_SSTX_LEVEL, 0xb) |
FIELD_PREP_CONST(HS_TX_COEF_MAP_0_SSTX_PRE_SHOOT, 0))),
/* Gen2 Tx DRIVER level ctrl */
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_LOCAL_COEF,
LOCAL_COEF_PMA_CENTER_COEF,
FIELD_PREP_CONST(LOCAL_COEF_PMA_CENTER_COEF, 0xb)),
/* Gen2 U1 exit LFPS duration : 900ns ~ 1.2us */
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_TIMEOUT_3, -1, 4096),
/* set skp_remove_th 0x2 -> 0x7 for avoiding retry problem. */
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_EBUF_PARAM,
EBUF_PARAM_SKP_REMOVE_TH_EMPTY_MODE,
FIELD_PREP_CONST(EBUF_PARAM_SKP_REMOVE_TH_EMPTY_MODE, 0x7)),
PHY_TUNING_ENTRY_LAST
};
static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_postlock[] = {
/* Squelch off when U3 */
PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_OUT_VEC_3, PCS_OUT_VEC_B2_SEL_OUT, 0),
PHY_TUNING_ENTRY_LAST
};
static const struct exynos5_usbdrd_phy_tuning *gs101_tunes[PTS_MAX] = {
[PTS_UTMI_POSTINIT] = gs101_tunes_utmi_postinit,
[PTS_PIPE3_PREINIT] = gs101_tunes_pipe3_preinit,
[PTS_PIPE3_INIT] = gs101_tunes_pipe3_init,
[PTS_PIPE3_POSTLOCK] = gs101_tunes_pipe3_postlock,
};
static const char * const gs101_clk_names[] = {
"phy", "ctrl_aclk", "ctrl_pclk", "scl_pclk",
};
static const char * const gs101_regulator_names[] = {
"pll",
"dvdd-usb20", "vddh-usb20", "vdd33-usb20",
"vdda-usbdp", "vddh-usbdp",
};
static const struct exynos5_usbdrd_phy_drvdata gs101_usbd31rd_phy = {
.phy_cfg = phy_cfg_gs101,
.phy_tunes = gs101_tunes,
.phy_ops = &gs101_usbdrd_phy_ops,
.pmu_offset_usbdrd0_phy = GS101_PHY_CTRL_USB20,
.pmu_offset_usbdrd0_phy_ss = GS101_PHY_CTRL_USBDP,
.clk_names = gs101_clk_names,
.n_clks = ARRAY_SIZE(gs101_clk_names),
.core_clk_names = exynos5_core_clk_names,
.n_core_clks = ARRAY_SIZE(exynos5_core_clk_names),
.regulator_names = gs101_regulator_names,
.n_regulators = ARRAY_SIZE(gs101_regulator_names),
};
static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
{
.compatible = "google,gs101-usb31drd-phy",
.data = &gs101_usbd31rd_phy
}, {
.compatible = "samsung,exynos5250-usbdrd-phy",
.data = &exynos5250_usbdrd_phy
}, {
......@@ -1018,21 +1690,38 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
dev_set_drvdata(dev, phy_drd);
phy_drd->dev = dev;
phy_drd->reg_phy = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(phy_drd->reg_phy))
return PTR_ERR(phy_drd->reg_phy);
drv_data = of_device_get_match_data(dev);
if (!drv_data)
return -EINVAL;
phy_drd->drv_data = drv_data;
if (of_property_present(dev->of_node, "reg-names")) {
void __iomem *reg;
reg = devm_platform_ioremap_resource_byname(pdev, "phy");
if (IS_ERR(reg))
return PTR_ERR(reg);
phy_drd->reg_phy = reg;
reg = devm_platform_ioremap_resource_byname(pdev, "pcs");
if (IS_ERR(reg))
return PTR_ERR(reg);
phy_drd->reg_pcs = reg;
reg = devm_platform_ioremap_resource_byname(pdev, "pma");
if (IS_ERR(reg))
return PTR_ERR(reg);
phy_drd->reg_pma = reg;
} else {
/* DTB with just a single region */
phy_drd->reg_phy = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(phy_drd->reg_phy))
return PTR_ERR(phy_drd->reg_phy);
}
ret = exynos5_usbdrd_phy_clk_handle(phy_drd);
if (ret) {
dev_err(dev, "Failed to initialize clocks\n");
if (ret)
return ret;
}
reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
"samsung,pmu-syscon");
......@@ -1050,36 +1739,20 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
if (channel < 0)
dev_dbg(dev, "Not a multi-controller usbdrd phy\n");
switch (channel) {
case 1:
pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd1_phy;
break;
case 0:
default:
pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd0_phy;
break;
}
/* Get Vbus regulators */
phy_drd->vbus = devm_regulator_get(dev, "vbus");
if (IS_ERR(phy_drd->vbus)) {
ret = PTR_ERR(phy_drd->vbus);
if (ret == -EPROBE_DEFER)
return ret;
dev_warn(dev, "Failed to get VBUS supply regulator\n");
phy_drd->vbus = NULL;
}
phy_drd->vbus_boost = devm_regulator_get(dev, "vbus-boost");
if (IS_ERR(phy_drd->vbus_boost)) {
ret = PTR_ERR(phy_drd->vbus_boost);
if (ret == -EPROBE_DEFER)
return ret;
dev_warn(dev, "Failed to get VBUS boost supply regulator\n");
phy_drd->vbus_boost = NULL;
}
/* Get regulators */
phy_drd->regulators = devm_kcalloc(dev,
drv_data->n_regulators,
sizeof(*phy_drd->regulators),
GFP_KERNEL);
if (!phy_drd->regulators)
return ENOMEM;
regulator_bulk_set_supply_names(phy_drd->regulators,
drv_data->regulator_names,
drv_data->n_regulators);
ret = devm_regulator_bulk_get(dev, drv_data->n_regulators,
phy_drd->regulators);
if (ret)
return dev_err_probe(dev, ret, "failed to get regulators\n");
dev_vdbg(dev, "Creating usbdrd_phy phy\n");
......@@ -1094,6 +1767,18 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
phy_drd->phys[i].phy = phy;
phy_drd->phys[i].index = i;
phy_drd->phys[i].reg_pmu = reg_pmu;
switch (channel) {
case 1:
pmu_offset = drv_data->pmu_offset_usbdrd1_phy;
break;
case 0:
default:
pmu_offset = drv_data->pmu_offset_usbdrd0_phy;
if (i == EXYNOS5_DRDPHY_PIPE3 && drv_data
->pmu_offset_usbdrd0_phy_ss)
pmu_offset = drv_data->pmu_offset_usbdrd0_phy_ss;
break;
}
phy_drd->phys[i].pmu_offset = pmu_offset;
phy_drd->phys[i].phy_cfg = &drv_data->phy_cfg[i];
phy_set_drvdata(phy, &phy_drd->phys[i]);
......
......@@ -121,7 +121,7 @@
#define EXYNOS_5420_USB_ISOL_HOST_OFFSET 0x70C
#define EXYNOS_5250_USB_ISOL_ENABLE BIT(0)
/* Mode swtich register */
/* Mode switch register */
#define EXYNOS_5250_MODE_SWITCH_OFFSET 0x230
#define EXYNOS_5250_MODE_SWITCH_MASK 1
#define EXYNOS_5250_MODE_SWITCH_DEVICE 0
......
......@@ -228,11 +228,6 @@ struct miphy28lp_dev {
int nphys;
};
struct miphy_initval {
u16 reg;
u16 val;
};
enum miphy_sata_gen { SATA_GEN1, SATA_GEN2, SATA_GEN3 };
static char *PHY_TYPE_name[] = { "sata-up", "pcie-up", "", "usb3-up" };
......
......@@ -15,6 +15,16 @@ config PHY_STARFIVE_JH7110_DPHY_RX
system. If M is selected, the module will be called
phy-jh7110-dphy-rx.ko.
config PHY_STARFIVE_JH7110_DPHY_TX
tristate "StarFive JH7110 D-PHY TX Support"
depends on HAS_IOMEM
select GENERIC_PHY
select GENERIC_PHY_MIPI_DPHY
help
Choose this option if you have a StarFive D-PHY TX in your
system. If M is selected, the module will be called
phy-jh7110-dphy-tx.ko.
config PHY_STARFIVE_JH7110_PCIE
tristate "Starfive JH7110 PCIE 2.0/USB 3.0 PHY support"
depends on HAS_IOMEM
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PHY_STARFIVE_JH7110_DPHY_RX) += phy-jh7110-dphy-rx.o
obj-$(CONFIG_PHY_STARFIVE_JH7110_DPHY_TX) += phy-jh7110-dphy-tx.o
obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o
obj-$(CONFIG_PHY_STARFIVE_JH7110_USB) += phy-jh7110-usb.o
......@@ -46,11 +46,6 @@
#define STF_MAP_LANES_NUM 6
struct regval {
u32 addr;
u32 val;
};
struct stf_dphy_info {
/**
* @maps:
......
// SPDX-License-Identifier: GPL-2.0+
/*
* DPHY TX driver for the StarFive JH7110 SoC
*
* Copyright (C) 2023 StarFive Technology Co., Ltd.
* Author: Keith Zhao <keith.zhao@starfivetech.com>
* Author: Shengyang Chen <shengyang.chen@starfivetech.com>
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/phy/phy-mipi-dphy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#define STF_DPHY_APBIFSAIF_SYSCFG(x) (x)
#define STF_DPHY_AON_POWER_READY_N_ACTIVE 0
#define STF_DPHY_AON_POWER_READY_N BIT(0)
#define STF_DPHY_CFG_L0_SWAP_SEL GENMASK(14, 12)
#define STF_DPHY_CFG_L1_SWAP_SEL GENMASK(17, 15)
#define STF_DPHY_CFG_L2_SWAP_SEL GENMASK(20, 18)
#define STF_DPHY_CFG_L3_SWAP_SEL GENMASK(23, 21)
#define STF_DPHY_CFG_L4_SWAP_SEL GENMASK(26, 24)
#define STF_DPHY_RGS_CDTX_PLL_UNLOCK BIT(18)
#define STF_DPHY_RG_CDTX_L0N_HSTX_RES GENMASK(23, 19)
#define STF_DPHY_RG_CDTX_L0P_HSTX_RES GENMASK(28, 24)
#define STF_DPHY_RG_CDTX_L1P_HSTX_RES GENMASK(9, 5)
#define STF_DPHY_RG_CDTX_L2N_HSTX_RES GENMASK(14, 10)
#define STF_DPHY_RG_CDTX_L2P_HSTX_RES GENMASK(19, 15)
#define STF_DPHY_RG_CDTX_L3N_HSTX_RES GENMASK(24, 20)
#define STF_DPHY_RG_CDTX_L3P_HSTX_RES GENMASK(29, 25)
#define STF_DPHY_RG_CDTX_L4N_HSTX_RES GENMASK(4, 0)
#define STF_DPHY_RG_CDTX_L4P_HSTX_RES GENMASK(9, 5)
#define STF_DPHY_RG_CDTX_PLL_FBK_FRA GENMASK(23, 0)
#define STF_DPHY_RG_CDTX_PLL_FBK_INT GENMASK(8, 0)
#define STF_DPHY_RG_CDTX_PLL_FM_EN BIT(9)
#define STF_DPHY_RG_CDTX_PLL_LDO_STB_X2_EN BIT(10)
#define STF_DPHY_RG_CDTX_PLL_PRE_DIV GENMASK(12, 11)
#define STF_DPHY_RG_CDTX_PLL_SSC_EN BIT(18)
#define STF_DPHY_RG_CLANE_HS_CLK_POST_TIME GENMASK(7, 0)
#define STF_DPHY_RG_CLANE_HS_CLK_PRE_TIME GENMASK(15, 8)
#define STF_DPHY_RG_CLANE_HS_PRE_TIME GENMASK(23, 16)
#define STF_DPHY_RG_CLANE_HS_TRAIL_TIME GENMASK(31, 24)
#define STF_DPHY_RG_CLANE_HS_ZERO_TIME GENMASK(7, 0)
#define STF_DPHY_RG_DLANE_HS_PRE_TIME GENMASK(15, 8)
#define STF_DPHY_RG_DLANE_HS_TRAIL_TIME GENMASK(23, 16)
#define STF_DPHY_RG_DLANE_HS_ZERO_TIME GENMASK(31, 24)
#define STF_DPHY_RG_EXTD_CYCLE_SEL GENMASK(2, 0)
#define STF_DPHY_SCFG_C_HS_PRE_ZERO_TIME GENMASK(31, 0)
#define STF_DPHY_SCFG_DSI_TXREADY_ESC_SEL GENMASK(2, 1)
#define STF_DPHY_SCFG_PPI_C_READY_SEL GENMASK(4, 3)
#define STF_DPHY_REFCLK_IN_SEL GENMASK(28, 26)
#define STF_DPHY_RESETB BIT(29)
#define STF_DPHY_REFCLK_12M 1
#define STF_DPHY_BITRATE_ALIGN 10000000
#define STF_MAP_LANES_NUM 5
#define STF_DPHY_LSHIFT_16(x) (FIELD_PREP(GENMASK(23, 16), (x)))
#define STF_DPHY_LSHIFT_8(x) (FIELD_PREP(GENMASK(15, 8), (x)))
#define STF_DPHY_HW_DELAY_US 200
#define STF_DPHY_HW_TIMEOUT_US 5000
struct stf_dphy_config {
unsigned long bitrate;
u32 pll_fbk_int;
u32 pll_fbk_fra_val;
u32 extd_cycle_sel;
u32 dlane_hs_pre_time;
u32 dlane_hs_zero_time;
u32 dlane_hs_trail_time;
u32 clane_hs_pre_time;
u32 clane_hs_zero_time;
u32 clane_hs_trail_time;
u32 clane_hs_clk_pre_time;
u32 clane_hs_clk_post_time;
};
static const struct stf_dphy_config reg_configs[] = {
{160000000, 0x6a, 0xaa, 0x3, 0xa, 0x17, 0x11, 0x5, 0x2b, 0xd, 0x7, 0x3d},
{170000000, 0x71, 0x55, 0x3, 0xb, 0x18, 0x11, 0x5, 0x2e, 0xd, 0x7, 0x3d},
{180000000, 0x78, 0x0, 0x3, 0xb, 0x19, 0x12, 0x6, 0x30, 0xe, 0x7, 0x3e},
{190000000, 0x7e, 0xaa, 0x3, 0xc, 0x1a, 0x12, 0x6, 0x33, 0xe, 0x7, 0x3e},
{200000000, 0x85, 0x55, 0x3, 0xc, 0x1b, 0x13, 0x7, 0x35, 0xf, 0x7, 0x3f},
{320000000, 0x6a, 0xaa, 0x2, 0x8, 0x14, 0xf, 0x5, 0x2b, 0xd, 0x3, 0x23},
{330000000, 0x6e, 0x0, 0x2, 0x8, 0x15, 0xf, 0x5, 0x2d, 0xd, 0x3, 0x23},
{340000000, 0x71, 0x55, 0x2, 0x9, 0x15, 0xf, 0x5, 0x2e, 0xd, 0x3, 0x23},
{350000000, 0x74, 0xaa, 0x2, 0x9, 0x15, 0x10, 0x6, 0x2f, 0xe, 0x3, 0x24},
{360000000, 0x78, 0x0, 0x2, 0x9, 0x16, 0x10, 0x6, 0x30, 0xe, 0x3, 0x24},
{370000000, 0x7b, 0x55, 0x2, 0x9, 0x17, 0x10, 0x6, 0x32, 0xe, 0x3, 0x24},
{380000000, 0x7e, 0xaa, 0x2, 0xa, 0x17, 0x10, 0x6, 0x33, 0xe, 0x3, 0x24},
{390000000, 0x82, 0x0, 0x2, 0xa, 0x17, 0x11, 0x6, 0x35, 0xf, 0x3, 0x25},
{400000000, 0x85, 0x55, 0x2, 0xa, 0x18, 0x11, 0x7, 0x35, 0xf, 0x3, 0x25},
{410000000, 0x88, 0xaa, 0x2, 0xa, 0x19, 0x11, 0x7, 0x37, 0xf, 0x3, 0x25},
{420000000, 0x8c, 0x0, 0x2, 0xa, 0x19, 0x12, 0x7, 0x38, 0x10, 0x3, 0x26},
{430000000, 0x8f, 0x55, 0x2, 0xb, 0x19, 0x12, 0x7, 0x39, 0x10, 0x3, 0x26},
{440000000, 0x92, 0xaa, 0x2, 0xb, 0x1a, 0x12, 0x7, 0x3b, 0x10, 0x3, 0x26},
{450000000, 0x96, 0x0, 0x2, 0xb, 0x1b, 0x12, 0x8, 0x3c, 0x10, 0x3, 0x26},
{460000000, 0x99, 0x55, 0x2, 0xb, 0x1b, 0x13, 0x8, 0x3d, 0x11, 0x3, 0x27},
{470000000, 0x9c, 0xaa, 0x2, 0xc, 0x1b, 0x13, 0x8, 0x3e, 0x11, 0x3, 0x27},
{480000000, 0xa0, 0x27, 0x2, 0xc, 0x1c, 0x13, 0x8, 0x40, 0x11, 0x3, 0x27},
{490000000, 0xa3, 0x55, 0x2, 0xc, 0x1d, 0x14, 0x8, 0x42, 0x12, 0x3, 0x28},
{500000000, 0xa6, 0xaa, 0x2, 0xc, 0x1d, 0x14, 0x9, 0x42, 0x12, 0x3, 0x28},
{510000000, 0xaa, 0x0, 0x2, 0xc, 0x1e, 0x14, 0x9, 0x44, 0x12, 0x3, 0x28},
{520000000, 0xad, 0x55, 0x2, 0xd, 0x1e, 0x15, 0x9, 0x45, 0x13, 0x3, 0x29},
{530000000, 0xb0, 0xaa, 0x2, 0xd, 0x1e, 0x15, 0x9, 0x47, 0x13, 0x3, 0x29},
{540000000, 0xb4, 0x0, 0x2, 0xd, 0x1f, 0x15, 0x9, 0x48, 0x13, 0x3, 0x29},
{550000000, 0xb7, 0x55, 0x2, 0xd, 0x20, 0x16, 0x9, 0x4a, 0x14, 0x3, 0x2a},
{560000000, 0xba, 0xaa, 0x2, 0xe, 0x20, 0x16, 0xa, 0x4a, 0x14, 0x3, 0x2a},
{570000000, 0xbe, 0x0, 0x2, 0xe, 0x20, 0x16, 0xa, 0x4c, 0x14, 0x3, 0x2a},
{580000000, 0xc1, 0x55, 0x2, 0xe, 0x21, 0x16, 0xa, 0x4d, 0x14, 0x3, 0x2a},
{590000000, 0xc4, 0xaa, 0x2, 0xe, 0x22, 0x17, 0xa, 0x4f, 0x15, 0x3, 0x2b},
{600000000, 0xc8, 0x0, 0x2, 0xe, 0x23, 0x17, 0xa, 0x50, 0x15, 0x3, 0x2b},
{610000000, 0xcb, 0x55, 0x2, 0xf, 0x22, 0x17, 0xb, 0x50, 0x15, 0x3, 0x2b},
{620000000, 0xce, 0xaa, 0x2, 0xf, 0x23, 0x18, 0xb, 0x52, 0x16, 0x3, 0x2c},
{630000000, 0x69, 0x0, 0x1, 0x7, 0x12, 0xd, 0x5, 0x2a, 0xc, 0x1, 0x15},
{640000000, 0x6a, 0xaa, 0x1, 0x7, 0x13, 0xe, 0x5, 0x2b, 0xd, 0x1, 0x16},
{650000000, 0x6c, 0x55, 0x1, 0x7, 0x13, 0xe, 0x5, 0x2c, 0xd, 0x1, 0x16},
{660000000, 0x6e, 0x0, 0x1, 0x7, 0x13, 0xe, 0x5, 0x2d, 0xd, 0x1, 0x16},
{670000000, 0x6f, 0xaa, 0x1, 0x8, 0x13, 0xe, 0x5, 0x2d, 0xd, 0x1, 0x16},
{680000000, 0x71, 0x55, 0x1, 0x8, 0x13, 0xe, 0x5, 0x2e, 0xd, 0x1, 0x16},
{690000000, 0x73, 0x0, 0x1, 0x8, 0x14, 0xe, 0x6, 0x2e, 0xd, 0x1, 0x16},
{700000000, 0x74, 0xaa, 0x1, 0x8, 0x14, 0xf, 0x6, 0x2f, 0xe, 0x1, 0x16},
{710000000, 0x76, 0x55, 0x1, 0x8, 0x14, 0xf, 0x6, 0x2f, 0xe, 0x1, 0x17},
{720000000, 0x78, 0x0, 0x1, 0x8, 0x15, 0xf, 0x6, 0x30, 0xe, 0x1, 0x17},
{730000000, 0x79, 0xaa, 0x1, 0x8, 0x15, 0xf, 0x6, 0x31, 0xe, 0x1, 0x17},
{740000000, 0x7b, 0x55, 0x1, 0x8, 0x15, 0xf, 0x6, 0x32, 0xe, 0x1, 0x17},
{750000000, 0x7d, 0x0, 0x1, 0x8, 0x16, 0xf, 0x6, 0x32, 0xe, 0x1, 0x17},
{760000000, 0x7e, 0xaa, 0x1, 0x9, 0x15, 0xf, 0x6, 0x33, 0xe, 0x1, 0x17},
{770000000, 0x80, 0x55, 0x1, 0x9, 0x15, 0x10, 0x6, 0x34, 0xf, 0x1, 0x18},
{780000000, 0x82, 0x0, 0x1, 0x9, 0x16, 0x10, 0x6, 0x35, 0xf, 0x1, 0x18,},
{790000000, 0x83, 0xaa, 0x1, 0x9, 0x16, 0x10, 0x7, 0x34, 0xf, 0x1, 0x18},
{800000000, 0x85, 0x55, 0x1, 0x9, 0x17, 0x10, 0x7, 0x35, 0xf, 0x1, 0x18},
{810000000, 0x87, 0x0, 0x1, 0x9, 0x17, 0x10, 0x7, 0x36, 0xf, 0x1, 0x18},
{820000000, 0x88, 0xaa, 0x1, 0x9, 0x17, 0x10, 0x7, 0x37, 0xf, 0x1, 0x18},
{830000000, 0x8a, 0x55, 0x1, 0x9, 0x18, 0x10, 0x7, 0x37, 0xf, 0x1, 0x18},
{840000000, 0x8c, 0x0, 0x1, 0x9, 0x18, 0x11, 0x7, 0x38, 0x10, 0x1, 0x19},
{850000000, 0x8d, 0xaa, 0x1, 0xa, 0x17, 0x11, 0x7, 0x39, 0x10, 0x1, 0x19},
{860000000, 0x8f, 0x55, 0x1, 0xa, 0x18, 0x11, 0x7, 0x39, 0x10, 0x1, 0x19},
{870000000, 0x91, 0x0, 0x1, 0xa, 0x18, 0x11, 0x7, 0x3a, 0x10, 0x1, 0x19},
{880000000, 0x92, 0xaa, 0x1, 0xa, 0x18, 0x11, 0x7, 0x3b, 0x10, 0x1, 0x19},
{890000000, 0x94, 0x55, 0x1, 0xa, 0x19, 0x11, 0x7, 0x3c, 0x10, 0x1, 0x19},
{900000000, 0x96, 0x0, 0x1, 0xa, 0x19, 0x12, 0x8, 0x3c, 0x10, 0x1, 0x19},
{910000000, 0x97, 0xaa, 0x1, 0xa, 0x19, 0x12, 0x8, 0x3c, 0x11, 0x1, 0x1a},
{920000000, 0x99, 0x55, 0x1, 0xa, 0x1a, 0x12, 0x8, 0x3d, 0x11, 0x1, 0x1a},
{930000000, 0x9b, 0x0, 0x1, 0xa, 0x1a, 0x12, 0x8, 0x3e, 0x11, 0x1, 0x1a},
{940000000, 0x9c, 0xaa, 0x1, 0xb, 0x1a, 0x12, 0x8, 0x3e, 0x11, 0x1, 0x1a},
{950000000, 0x9e, 0x55, 0x1, 0xb, 0x1a, 0x12, 0x8, 0x3f, 0x11, 0x1, 0x1a},
{960000000, 0xa0, 0x0, 0x1, 0xb, 0x1a, 0x12, 0x8, 0x40, 0x11, 0x1, 0x1a},
{970000000, 0xa1, 0xaa, 0x1, 0xb, 0x1b, 0x13, 0x8, 0x41, 0x12, 0x1, 0x1b},
{980000000, 0xa3, 0x55, 0x1, 0xb, 0x1b, 0x13, 0x8, 0x42, 0x12, 0x1, 0x1b},
{990000000, 0xa5, 0x0, 0x1, 0xb, 0x1b, 0x13, 0x8, 0x42, 0x12, 0x1, 0x1b},
{1000000000, 0xa6, 0xaa, 0x1, 0xb, 0x1c, 0x13, 0x9, 0x42, 0x12, 0x1, 0x1b},
};
struct stf_dphy_info {
/**
* @maps:
*
* Physical lanes and logic lanes mapping table.
*
* The default order is:
* [data lane 0, data lane 1, data lane 2, date lane 3, clk lane]
*/
u8 maps[STF_MAP_LANES_NUM];
};
struct stf_dphy {
struct device *dev;
void __iomem *topsys;
struct clk *txesc_clk;
struct reset_control *sys_rst;
struct phy_configure_opts_mipi_dphy config;
struct phy *phy;
const struct stf_dphy_info *info;
};
static u32 stf_dphy_get_config_index(u32 bitrate)
{
u32 i;
for (i = 0; i < ARRAY_SIZE(reg_configs); i++) {
if (reg_configs[i].bitrate == bitrate)
return i;
}
return 0;
}
static void stf_dphy_hw_reset(struct stf_dphy *dphy, int assert)
{
int rc;
u32 status = 0;
writel(FIELD_PREP(STF_DPHY_RESETB, assert),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(100));
if (assert) {
rc = readl_poll_timeout_atomic(dphy->topsys +
STF_DPHY_APBIFSAIF_SYSCFG(8),
status,
!(FIELD_GET(STF_DPHY_RGS_CDTX_PLL_UNLOCK, status)),
STF_DPHY_HW_DELAY_US, STF_DPHY_HW_TIMEOUT_US);
if (rc)
dev_err(dphy->dev, "MIPI dphy-tx # PLL Locked\n");
}
}
static int stf_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
{
struct stf_dphy *dphy = phy_get_drvdata(phy);
const struct stf_dphy_info *info = dphy->info;
const struct stf_dphy_config *p = reg_configs;
unsigned long alignment = STF_DPHY_BITRATE_ALIGN;
u32 bitrate = opts->mipi_dphy.hs_clk_rate;
u32 tmp;
u32 i;
if (bitrate % alignment)
bitrate += alignment - (bitrate % alignment);
i = stf_dphy_get_config_index(bitrate);
tmp = readl(dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(100));
tmp &= ~STF_DPHY_REFCLK_IN_SEL;
tmp |= FIELD_PREP(STF_DPHY_REFCLK_IN_SEL, STF_DPHY_REFCLK_12M);
writel(tmp, dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(100));
writel(FIELD_PREP(STF_DPHY_RG_CDTX_L0N_HSTX_RES, 0x10) |
FIELD_PREP(STF_DPHY_RG_CDTX_L0P_HSTX_RES, 0x10),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(8));
writel(FIELD_PREP(STF_DPHY_RG_CDTX_L0N_HSTX_RES, 0x10) |
FIELD_PREP(STF_DPHY_RG_CDTX_L2N_HSTX_RES, 0x10) |
FIELD_PREP(STF_DPHY_RG_CDTX_L3N_HSTX_RES, 0x10) |
FIELD_PREP(STF_DPHY_RG_CDTX_L1P_HSTX_RES, 0x10) |
FIELD_PREP(STF_DPHY_RG_CDTX_L2P_HSTX_RES, 0x10) |
FIELD_PREP(STF_DPHY_RG_CDTX_L3P_HSTX_RES, 0x10),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(12));
writel(FIELD_PREP(STF_DPHY_RG_CDTX_L4N_HSTX_RES, 0x10) |
FIELD_PREP(STF_DPHY_RG_CDTX_L4P_HSTX_RES, 0x10),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(16));
/* Lane setting */
writel(FIELD_PREP(STF_DPHY_AON_POWER_READY_N,
STF_DPHY_AON_POWER_READY_N_ACTIVE) |
FIELD_PREP(STF_DPHY_CFG_L0_SWAP_SEL, info->maps[0]) |
FIELD_PREP(STF_DPHY_CFG_L1_SWAP_SEL, info->maps[1]) |
FIELD_PREP(STF_DPHY_CFG_L2_SWAP_SEL, info->maps[2]) |
FIELD_PREP(STF_DPHY_CFG_L3_SWAP_SEL, info->maps[3]) |
FIELD_PREP(STF_DPHY_CFG_L4_SWAP_SEL, info->maps[4]),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(0));
/* PLL setting */
writel(FIELD_PREP(STF_DPHY_RG_CDTX_PLL_SSC_EN, 0x0),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(28));
writel(FIELD_PREP(STF_DPHY_RG_CDTX_PLL_LDO_STB_X2_EN, 0x1) |
FIELD_PREP(STF_DPHY_RG_CDTX_PLL_FM_EN, 0x1) |
FIELD_PREP(STF_DPHY_RG_CDTX_PLL_PRE_DIV, 0x0) |
FIELD_PREP(STF_DPHY_RG_CDTX_PLL_FBK_INT, p[i].pll_fbk_int),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(24));
writel(FIELD_PREP(STF_DPHY_RG_CDTX_PLL_FBK_FRA,
STF_DPHY_LSHIFT_16(p[i].pll_fbk_fra_val) |
STF_DPHY_LSHIFT_8(p[i].pll_fbk_fra_val) |
p[i].pll_fbk_fra_val),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(20));
writel(FIELD_PREP(STF_DPHY_RG_EXTD_CYCLE_SEL, p[i].extd_cycle_sel),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(40));
writel(FIELD_PREP(STF_DPHY_RG_DLANE_HS_PRE_TIME, p[i].dlane_hs_pre_time) |
FIELD_PREP(STF_DPHY_RG_DLANE_HS_ZERO_TIME, p[i].dlane_hs_zero_time) |
FIELD_PREP(STF_DPHY_RG_DLANE_HS_TRAIL_TIME, p[i].dlane_hs_trail_time) |
FIELD_PREP(STF_DPHY_RG_CLANE_HS_ZERO_TIME, p[i].clane_hs_zero_time),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(36));
writel(FIELD_PREP(STF_DPHY_RG_CLANE_HS_PRE_TIME, p[i].clane_hs_pre_time) |
FIELD_PREP(STF_DPHY_RG_CLANE_HS_TRAIL_TIME, p[i].clane_hs_trail_time) |
FIELD_PREP(STF_DPHY_RG_CLANE_HS_CLK_PRE_TIME, p[i].clane_hs_clk_pre_time) |
FIELD_PREP(STF_DPHY_RG_CLANE_HS_CLK_POST_TIME, p[i].clane_hs_clk_post_time),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(32));
return 0;
}
static int stf_dphy_init(struct phy *phy)
{
struct stf_dphy *dphy = phy_get_drvdata(phy);
int ret;
stf_dphy_hw_reset(dphy, 1);
writel(FIELD_PREP(STF_DPHY_SCFG_PPI_C_READY_SEL, 0) |
FIELD_PREP(STF_DPHY_SCFG_DSI_TXREADY_ESC_SEL, 0),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(48));
writel(FIELD_PREP(STF_DPHY_SCFG_C_HS_PRE_ZERO_TIME, 0x30),
dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(44));
ret = clk_prepare_enable(dphy->txesc_clk);
if (ret) {
dev_err(dphy->dev, "Failed to prepare/enable txesc_clk\n");
return ret;
}
ret = reset_control_deassert(dphy->sys_rst);
if (ret) {
dev_err(dphy->dev, "Failed to deassert sys_rst\n");
return ret;
}
return 0;
}
static int stf_dphy_exit(struct phy *phy)
{
struct stf_dphy *dphy = phy_get_drvdata(phy);
int ret;
ret = reset_control_assert(dphy->sys_rst);
if (ret) {
dev_err(dphy->dev, "Failed to assert sys_rst\n");
return ret;
}
clk_disable_unprepare(dphy->txesc_clk);
stf_dphy_hw_reset(dphy, 0);
return 0;
}
static int stf_dphy_power_on(struct phy *phy)
{
struct stf_dphy *dphy = phy_get_drvdata(phy);
return pm_runtime_resume_and_get(dphy->dev);
}
static int stf_dphy_validate(struct phy *phy, enum phy_mode mode, int submode,
union phy_configure_opts *opts)
{
if (mode != PHY_MODE_MIPI_DPHY)
return -EINVAL;
return 0;
}
static int stf_dphy_power_off(struct phy *phy)
{
struct stf_dphy *dphy = phy_get_drvdata(phy);
return pm_runtime_put_sync(dphy->dev);
}
static const struct phy_ops stf_dphy_ops = {
.power_on = stf_dphy_power_on,
.power_off = stf_dphy_power_off,
.init = stf_dphy_init,
.exit = stf_dphy_exit,
.configure = stf_dphy_configure,
.validate = stf_dphy_validate,
.owner = THIS_MODULE,
};
static int stf_dphy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
struct stf_dphy *dphy;
dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
if (!dphy)
return -ENOMEM;
dphy->info = of_device_get_match_data(&pdev->dev);
dphy->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, dphy);
dphy->topsys = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dphy->topsys))
return PTR_ERR(dphy->topsys);
pm_runtime_enable(&pdev->dev);
dphy->txesc_clk = devm_clk_get(&pdev->dev, "txesc");
if (IS_ERR(dphy->txesc_clk))
return dev_err_probe(&pdev->dev, PTR_ERR(dphy->txesc_clk),
"Failed to get txesc clock\n");
dphy->sys_rst = devm_reset_control_get_exclusive(&pdev->dev, "sys");
if (IS_ERR(dphy->sys_rst))
return dev_err_probe(&pdev->dev, PTR_ERR(dphy->sys_rst),
"Failed to get sys reset\n");
dphy->phy = devm_phy_create(&pdev->dev, NULL, &stf_dphy_ops);
if (IS_ERR(dphy->phy))
return dev_err_probe(&pdev->dev, PTR_ERR(dphy->phy),
"Failed to create phy\n");
phy_set_drvdata(dphy->phy, dphy);
phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider))
return dev_err_probe(&pdev->dev, PTR_ERR(phy_provider),
"Failed to register phy\n");
return 0;
}
static const struct stf_dphy_info starfive_dphy_info = {
.maps = {0, 1, 2, 3, 4},
};
static const struct of_device_id stf_dphy_dt_ids[] = {
{
.compatible = "starfive,jh7110-dphy-tx",
.data = &starfive_dphy_info,
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, stf_dphy_dt_ids);
static struct platform_driver stf_dphy_driver = {
.driver = {
.name = "starfive-dphy-tx",
.of_match_table = stf_dphy_dt_ids,
},
.probe = stf_dphy_probe,
};
module_platform_driver(stf_dphy_driver);
MODULE_AUTHOR("Keith Zhao <keith.zhao@starfivetech.com>");
MODULE_AUTHOR("Shengyang Chen <shengyang.chen@starfivetech.com>");
MODULE_DESCRIPTION("StarFive JH7110 DPHY TX driver");
MODULE_LICENSE("GPL");
......@@ -30,7 +30,6 @@
#define LANE_R058 0x258
#define LANE_R06c 0x26c
#define LANE_R070 0x270
#define LANE_R070 0x270
#define LANE_R19C 0x39c
#define COMLANE_R004 0xa04
......
......@@ -1076,27 +1076,12 @@ static int wiz_clock_register(struct wiz *wiz)
return ret;
}
static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
static void wiz_clock_init(struct wiz *wiz)
{
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;
unsigned long rate;
struct clk *clk;
int ret;
int i;
clk = devm_clk_get(dev, "core_ref_clk");
if (IS_ERR(clk)) {
dev_err(dev, "core_ref_clk clock not found\n");
ret = PTR_ERR(clk);
return ret;
}
wiz->input_clks[WIZ_CORE_REFCLK] = clk;
rate = clk_get_rate(clk);
if (rate >= 100000000)
rate = clk_get_rate(wiz->input_clks[WIZ_CORE_REFCLK]);
if (rate >= REF_CLK_100MHZ)
regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x1);
else
regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x3);
......@@ -1120,35 +1105,55 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
break;
}
if (wiz->data->pma_cmn_refclk1_int_mode) {
clk = devm_clk_get(dev, "core_ref1_clk");
if (IS_ERR(clk)) {
dev_err(dev, "core_ref1_clk clock not found\n");
ret = PTR_ERR(clk);
return ret;
}
wiz->input_clks[WIZ_CORE_REFCLK1] = clk;
rate = clk_get_rate(clk);
if (rate >= 100000000)
if (wiz->input_clks[WIZ_CORE_REFCLK1]) {
rate = clk_get_rate(wiz->input_clks[WIZ_CORE_REFCLK1]);
if (rate >= REF_CLK_100MHZ)
regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x1);
else
regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x3);
}
clk = devm_clk_get(dev, "ext_ref_clk");
if (IS_ERR(clk)) {
dev_err(dev, "ext_ref_clk clock not found\n");
ret = PTR_ERR(clk);
return ret;
}
wiz->input_clks[WIZ_EXT_REFCLK] = clk;
rate = clk_get_rate(clk);
if (rate >= 100000000)
rate = clk_get_rate(wiz->input_clks[WIZ_EXT_REFCLK]);
if (rate >= REF_CLK_100MHZ)
regmap_field_write(wiz->pma_cmn_refclk_mode, 0x0);
else
regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2);
}
static int wiz_clock_probe(struct wiz *wiz, struct device_node *node)
{
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;
struct clk *clk;
int ret;
int i;
clk = devm_clk_get(dev, "core_ref_clk");
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk),
"core_ref_clk clock not found\n");
wiz->input_clks[WIZ_CORE_REFCLK] = clk;
if (wiz->data->pma_cmn_refclk1_int_mode) {
clk = devm_clk_get(dev, "core_ref1_clk");
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk),
"core_ref1_clk clock not found\n");
wiz->input_clks[WIZ_CORE_REFCLK1] = clk;
}
clk = devm_clk_get(dev, "ext_ref_clk");
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk),
"ext_ref_clk clock not found\n");
wiz->input_clks[WIZ_EXT_REFCLK] = clk;
wiz_clock_init(wiz);
switch (wiz->type) {
case AM64_WIZ_10G:
......@@ -1157,8 +1162,9 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
case J721S2_WIZ_10G:
ret = wiz_clock_register(wiz);
if (ret)
dev_err(dev, "Failed to register wiz clocks\n");
return ret;
return dev_err_probe(dev, ret, "Failed to register wiz clocks\n");
return 0;
default:
break;
}
......@@ -1167,16 +1173,15 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
node_name = clk_mux_sel[i].node_name;
clk_node = of_get_child_by_name(node, node_name);
if (!clk_node) {
dev_err(dev, "Unable to get %s node\n", node_name);
ret = -EINVAL;
ret = dev_err_probe(dev, -EINVAL, "Unable to get %s node\n", node_name);
goto err;
}
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);
dev_err_probe(dev, ret, "Failed to register %s clock\n",
node_name);
of_node_put(clk_node);
goto err;
}
......@@ -1188,16 +1193,15 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
node_name = clk_div_sel[i].node_name;
clk_node = of_get_child_by_name(node, node_name);
if (!clk_node) {
dev_err(dev, "Unable to get %s node\n", node_name);
ret = -EINVAL;
ret = dev_err_probe(dev, -EINVAL, "Unable to get %s node\n", node_name);
goto err;
}
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",
node_name);
dev_err_probe(dev, ret, "Failed to register %s clock\n",
node_name);
of_node_put(clk_node);
goto err;
}
......@@ -1593,7 +1597,7 @@ static int wiz_probe(struct platform_device *pdev)
goto err_get_sync;
}
ret = wiz_clock_init(wiz, node);
ret = wiz_clock_probe(wiz, node);
if (ret < 0) {
dev_warn(dev, "Failed to initialize clocks\n");
goto err_get_sync;
......@@ -1655,12 +1659,41 @@ static void wiz_remove(struct platform_device *pdev)
pm_runtime_disable(dev);
}
static int wiz_resume_noirq(struct device *dev)
{
struct device_node *node = dev->of_node;
struct wiz *wiz = dev_get_drvdata(dev);
int ret;
/* Enable supplemental Control override if available */
if (wiz->sup_legacy_clk_override)
regmap_field_write(wiz->sup_legacy_clk_override, 1);
wiz_clock_init(wiz);
ret = wiz_init(wiz);
if (ret) {
dev_err(dev, "WIZ initialization failed\n");
goto err_wiz_init;
}
return 0;
err_wiz_init:
wiz_clock_cleanup(wiz, node);
return ret;
}
static DEFINE_NOIRQ_DEV_PM_OPS(wiz_pm_ops, NULL, wiz_resume_noirq);
static struct platform_driver wiz_driver = {
.probe = wiz_probe,
.remove_new = wiz_remove,
.driver = {
.name = "wiz",
.of_match_table = wiz_id_table,
.pm = pm_sleep_ptr(&wiz_pm_ops),
},
};
module_platform_driver(wiz_driver);
......
......@@ -13,6 +13,7 @@
*/
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
......@@ -80,7 +81,8 @@
/* Reference clock selection parameters */
#define L0_Ln_REF_CLK_SEL(n) (0x2860 + (n) * 4)
#define L0_REF_CLK_SEL_MASK 0x8f
#define L0_REF_CLK_LCL_SEL BIT(7)
#define L0_REF_CLK_SEL_MASK 0x9f
/* Calibration digital logic parameters */
#define L3_TM_CALIB_DIG19 0xec4c
......@@ -122,6 +124,15 @@
#define ICM_PROTOCOL_DP 0x4
#define ICM_PROTOCOL_SGMII 0x5
static const char *const xpsgtr_icm_str[] = {
[ICM_PROTOCOL_PD] = "none",
[ICM_PROTOCOL_PCIE] = "PCIe",
[ICM_PROTOCOL_SATA] = "SATA",
[ICM_PROTOCOL_USB] = "USB",
[ICM_PROTOCOL_DP] = "DisplayPort",
[ICM_PROTOCOL_SGMII] = "SGMII",
};
/* Test Mode common reset control parameters */
#define TM_CMN_RST 0x10018
#define TM_CMN_RST_EN 0x1
......@@ -146,22 +157,6 @@
/* Total number of controllers */
#define CONTROLLERS_PER_LANE 5
/* Protocol Type parameters */
#define XPSGTR_TYPE_USB0 0 /* USB controller 0 */
#define XPSGTR_TYPE_USB1 1 /* USB controller 1 */
#define XPSGTR_TYPE_SATA_0 2 /* SATA controller lane 0 */
#define XPSGTR_TYPE_SATA_1 3 /* SATA controller lane 1 */
#define XPSGTR_TYPE_PCIE_0 4 /* PCIe controller lane 0 */
#define XPSGTR_TYPE_PCIE_1 5 /* PCIe controller lane 1 */
#define XPSGTR_TYPE_PCIE_2 6 /* PCIe controller lane 2 */
#define XPSGTR_TYPE_PCIE_3 7 /* PCIe controller lane 3 */
#define XPSGTR_TYPE_DP_0 8 /* Display Port controller lane 0 */
#define XPSGTR_TYPE_DP_1 9 /* Display Port controller lane 1 */
#define XPSGTR_TYPE_SGMII0 10 /* Ethernet SGMII controller 0 */
#define XPSGTR_TYPE_SGMII1 11 /* Ethernet SGMII controller 1 */
#define XPSGTR_TYPE_SGMII2 12 /* Ethernet SGMII controller 2 */
#define XPSGTR_TYPE_SGMII3 13 /* Ethernet SGMII controller 3 */
/* Timeout values */
#define TIMEOUT_US 1000
......@@ -184,7 +179,8 @@ struct xpsgtr_ssc {
/**
* struct xpsgtr_phy - representation of a lane
* @phy: pointer to the kernel PHY device
* @type: controller which uses this lane
* @instance: instance of the protocol type (such as the lane within a
* protocol, or the USB/Ethernet controller)
* @lane: lane number
* @protocol: protocol in which the lane operates
* @skip_phy_init: skip phy_init() if true
......@@ -193,7 +189,7 @@ struct xpsgtr_ssc {
*/
struct xpsgtr_phy {
struct phy *phy;
u8 type;
u8 instance;
u8 lane;
u8 protocol;
bool skip_phy_init;
......@@ -308,10 +304,30 @@ static int xpsgtr_wait_pll_lock(struct phy *phy)
struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
unsigned int timeout = TIMEOUT_US;
u8 protocol = gtr_phy->protocol;
int ret;
dev_dbg(gtr_dev->dev, "Waiting for PLL lock\n");
/*
* For DP and PCIe, only the instance 0 PLL is used. Switch to that phy
* so we wait on the right PLL.
*/
if ((protocol == ICM_PROTOCOL_DP || protocol == ICM_PROTOCOL_PCIE) &&
gtr_phy->instance) {
int i;
for (i = 0; i < NUM_LANES; i++) {
gtr_phy = &gtr_dev->phys[i];
if (gtr_phy->protocol == protocol && !gtr_phy->instance)
goto got_phy;
}
return -EBUSY;
}
got_phy:
while (1) {
u32 reg = xpsgtr_read_phy(gtr_phy, L0_PLL_STATUS_READ_1);
......@@ -330,8 +346,8 @@ static int xpsgtr_wait_pll_lock(struct phy *phy)
if (ret == -ETIMEDOUT)
dev_err(gtr_dev->dev,
"lane %u (type %u, protocol %u): PLL lock timeout\n",
gtr_phy->lane, gtr_phy->type, gtr_phy->protocol);
"lane %u (protocol %u, instance %u): PLL lock timeout\n",
gtr_phy->lane, gtr_phy->protocol, gtr_phy->instance);
return ret;
}
......@@ -349,11 +365,12 @@ static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy)
PLL_FREQ_MASK, ssc->pll_ref_clk);
/* Enable lane clock sharing, if required */
if (gtr_phy->refclk != gtr_phy->lane) {
/* Lane3 Ref Clock Selection Register */
if (gtr_phy->refclk == gtr_phy->lane)
xpsgtr_clr_set(gtr_phy->dev, L0_Ln_REF_CLK_SEL(gtr_phy->lane),
L0_REF_CLK_SEL_MASK, L0_REF_CLK_LCL_SEL);
else
xpsgtr_clr_set(gtr_phy->dev, L0_Ln_REF_CLK_SEL(gtr_phy->lane),
L0_REF_CLK_SEL_MASK, 1 << gtr_phy->refclk);
}
/* SSC step size [7:0] */
xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_0_LSB,
......@@ -573,7 +590,7 @@ static int xpsgtr_phy_init(struct phy *phy)
mutex_lock(&gtr_dev->gtr_mutex);
/* Configure and enable the clock when peripheral phy_init call */
if (clk_prepare_enable(gtr_dev->clk[gtr_phy->lane]))
if (clk_prepare_enable(gtr_dev->clk[gtr_phy->refclk]))
goto out;
/* Skip initialization if not required. */
......@@ -625,7 +642,7 @@ static int xpsgtr_phy_exit(struct phy *phy)
gtr_phy->skip_phy_init = false;
/* Ensure that disable clock only, which configure for lane */
clk_disable_unprepare(gtr_dev->clk[gtr_phy->lane]);
clk_disable_unprepare(gtr_dev->clk[gtr_phy->refclk]);
return 0;
}
......@@ -638,16 +655,7 @@ static int xpsgtr_phy_power_on(struct phy *phy)
/* Skip initialization if not required. */
if (!xpsgtr_phy_init_required(gtr_phy))
return ret;
/*
* Wait for the PLL to lock. For DP, only wait on DP0 to avoid
* cumulating waits for both lanes. The user is expected to initialize
* lane 0 last.
*/
if (gtr_phy->protocol != ICM_PROTOCOL_DP ||
gtr_phy->type == XPSGTR_TYPE_DP_0)
ret = xpsgtr_wait_pll_lock(phy);
return ret;
return xpsgtr_wait_pll_lock(phy);
}
static int xpsgtr_phy_configure(struct phy *phy, union phy_configure_opts *opts)
......@@ -674,73 +682,33 @@ static const struct phy_ops xpsgtr_phyops = {
* OF Xlate Support
*/
/* Set the lane type and protocol based on the PHY type and instance number. */
/* Set the lane protocol and instance based on the PHY type and instance number. */
static int xpsgtr_set_lane_type(struct xpsgtr_phy *gtr_phy, u8 phy_type,
unsigned int phy_instance)
{
unsigned int num_phy_types;
const int *phy_types;
switch (phy_type) {
case PHY_TYPE_SATA: {
static const int types[] = {
XPSGTR_TYPE_SATA_0,
XPSGTR_TYPE_SATA_1,
};
phy_types = types;
num_phy_types = ARRAY_SIZE(types);
case PHY_TYPE_SATA:
num_phy_types = 2;
gtr_phy->protocol = ICM_PROTOCOL_SATA;
break;
}
case PHY_TYPE_USB3: {
static const int types[] = {
XPSGTR_TYPE_USB0,
XPSGTR_TYPE_USB1,
};
phy_types = types;
num_phy_types = ARRAY_SIZE(types);
case PHY_TYPE_USB3:
num_phy_types = 2;
gtr_phy->protocol = ICM_PROTOCOL_USB;
break;
}
case PHY_TYPE_DP: {
static const int types[] = {
XPSGTR_TYPE_DP_0,
XPSGTR_TYPE_DP_1,
};
phy_types = types;
num_phy_types = ARRAY_SIZE(types);
case PHY_TYPE_DP:
num_phy_types = 2;
gtr_phy->protocol = ICM_PROTOCOL_DP;
break;
}
case PHY_TYPE_PCIE: {
static const int types[] = {
XPSGTR_TYPE_PCIE_0,
XPSGTR_TYPE_PCIE_1,
XPSGTR_TYPE_PCIE_2,
XPSGTR_TYPE_PCIE_3,
};
phy_types = types;
num_phy_types = ARRAY_SIZE(types);
case PHY_TYPE_PCIE:
num_phy_types = 4;
gtr_phy->protocol = ICM_PROTOCOL_PCIE;
break;
}
case PHY_TYPE_SGMII: {
static const int types[] = {
XPSGTR_TYPE_SGMII0,
XPSGTR_TYPE_SGMII1,
XPSGTR_TYPE_SGMII2,
XPSGTR_TYPE_SGMII3,
};
phy_types = types;
num_phy_types = ARRAY_SIZE(types);
case PHY_TYPE_SGMII:
num_phy_types = 4;
gtr_phy->protocol = ICM_PROTOCOL_SGMII;
break;
}
default:
return -EINVAL;
}
......@@ -748,22 +716,25 @@ static int xpsgtr_set_lane_type(struct xpsgtr_phy *gtr_phy, u8 phy_type,
if (phy_instance >= num_phy_types)
return -EINVAL;
gtr_phy->type = phy_types[phy_instance];
gtr_phy->instance = phy_instance;
return 0;
}
/*
* Valid combinations of controllers and lanes (Interconnect Matrix).
* Valid combinations of controllers and lanes (Interconnect Matrix). Each
* "instance" represents one controller for a lane. For PCIe and DP, the
* "instance" is the logical lane in the link. For SATA, USB, and SGMII,
* the instance is the index of the controller.
*
* This information is only used to validate the devicetree reference, and is
* not used when programming the hardware.
*/
static const unsigned int icm_matrix[NUM_LANES][CONTROLLERS_PER_LANE] = {
{ XPSGTR_TYPE_PCIE_0, XPSGTR_TYPE_SATA_0, XPSGTR_TYPE_USB0,
XPSGTR_TYPE_DP_1, XPSGTR_TYPE_SGMII0 },
{ XPSGTR_TYPE_PCIE_1, XPSGTR_TYPE_SATA_1, XPSGTR_TYPE_USB0,
XPSGTR_TYPE_DP_0, XPSGTR_TYPE_SGMII1 },
{ XPSGTR_TYPE_PCIE_2, XPSGTR_TYPE_SATA_0, XPSGTR_TYPE_USB0,
XPSGTR_TYPE_DP_1, XPSGTR_TYPE_SGMII2 },
{ XPSGTR_TYPE_PCIE_3, XPSGTR_TYPE_SATA_1, XPSGTR_TYPE_USB1,
XPSGTR_TYPE_DP_0, XPSGTR_TYPE_SGMII3 }
/* PCIe, SATA, USB, DP, SGMII */
{ 0, 0, 0, 1, 0 }, /* Lane 0 */
{ 1, 1, 0, 0, 1 }, /* Lane 1 */
{ 2, 0, 0, 1, 2 }, /* Lane 2 */
{ 3, 1, 1, 0, 3 }, /* Lane 3 */
};
/* Translate OF phandle and args to PHY instance. */
......@@ -798,6 +769,7 @@ static struct phy *xpsgtr_xlate(struct device *dev,
phy_type = args->args[1];
phy_instance = args->args[2];
guard(mutex)(&gtr_phy->phy->mutex);
ret = xpsgtr_set_lane_type(gtr_phy, phy_type, phy_instance);
if (ret < 0) {
dev_err(gtr_dev->dev, "Invalid PHY type and/or instance\n");
......@@ -818,13 +790,41 @@ static struct phy *xpsgtr_xlate(struct device *dev,
* is allowed to operate on the lane.
*/
for (i = 0; i < CONTROLLERS_PER_LANE; i++) {
if (icm_matrix[phy_lane][i] == gtr_phy->type)
if (icm_matrix[phy_lane][i] == gtr_phy->instance)
return gtr_phy->phy;
}
return ERR_PTR(-EINVAL);
}
/*
* DebugFS
*/
static int xpsgtr_status_read(struct seq_file *seq, void *data)
{
struct device *dev = seq->private;
struct xpsgtr_phy *gtr_phy = dev_get_drvdata(dev);
struct clk *clk;
u32 pll_status;
mutex_lock(&gtr_phy->phy->mutex);
pll_status = xpsgtr_read_phy(gtr_phy, L0_PLL_STATUS_READ_1);
clk = gtr_phy->dev->clk[gtr_phy->refclk];
seq_printf(seq, "Lane: %u\n", gtr_phy->lane);
seq_printf(seq, "Protocol: %s\n",
xpsgtr_icm_str[gtr_phy->protocol]);
seq_printf(seq, "Instance: %u\n", gtr_phy->instance);
seq_printf(seq, "Reference clock: %u (%pC)\n", gtr_phy->refclk, clk);
seq_printf(seq, "Reference rate: %lu\n", clk_get_rate(clk));
seq_printf(seq, "PLL locked: %s\n",
pll_status & PLL_STATUS_LOCKED ? "yes" : "no");
mutex_unlock(&gtr_phy->phy->mutex);
return 0;
}
/*
* Power Management
*/
......@@ -974,6 +974,8 @@ static int xpsgtr_probe(struct platform_device *pdev)
gtr_phy->phy = phy;
phy_set_drvdata(phy, gtr_phy);
debugfs_create_devm_seqfile(&phy->dev, "status", phy->debugfs,
xpsgtr_status_read);
}
/* Register the PHY provider. */
......
......@@ -660,5 +660,7 @@
/* For Tensor GS101 */
#define GS101_SYSIP_DAT0 (0x810)
#define GS101_SYSTEM_CONFIGURATION (0x3A00)
#define GS101_PHY_CTRL_USB20 (0x3EB0)
#define GS101_PHY_CTRL_USBDP (0x3EB4)
#endif /* __LINUX_SOC_EXYNOS_REGS_PMU_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment