From nobody Sat Jul 25 15:53:15 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1816C42901C; Thu, 16 Jul 2026 15:13:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784214823; cv=none; b=LGiTYZY3Q7k3jVErc24/wAzOow1zZrPZjc4Yciqk0SiqXUXOyiI2/lUvwddJs+xUQdITVHHPK2Qvg7V2ShpmrhfmYi14fhaeobQjvJ45XbP8VVGPe5L4WzMtiFqzr26ZYFeT3M7Go22viS2mDxwZ6MtGKWWFifyTMpMu3mZ9mWE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784214823; c=relaxed/simple; bh=1TfHjfCjyABk53A8MaRhQkosWW62gMUxDynVzVFzhyE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Nq1vaYTGf712HzbQvLMWxRhVTRH7fticvpSxsspwKC1fYVPVhricFsz+yMIVB8SR4opi5seDCSZk9LhoWohPBsTPTXgxZ1MWQXN0RE9nsSudynmIff3RBs5mYEittki7FhWhfJkMZZRLIzDgw7l6N3k6kMtxhX1V/Kaqgoh2+Fc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=llxscuaw; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="llxscuaw" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1784214817; bh=1TfHjfCjyABk53A8MaRhQkosWW62gMUxDynVzVFzhyE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=llxscuaw1rmARpqLMcpCOo4I/OPeGwUx1/z0v9vAj6q8gd/8c8AXeP/PoFV3mh5QB 31+s7AImDTpu5gXKvRTzdv9fxWGDC09hNB7pl6NoaHJNNoLrz1ieAorOCPClbSdgEr AM9dbMoyEGV2LRcwnpUY72uzZsOVkBecffiWcp/kUZKDuxOhqTFqAHWNNkUf38p238 22Kv8tz1TGSUv5quA1rpNnxqMRxLmBHVejHTgBuHcBPu3inYa2s8kjt+4zkkhkkDCP A7rfFq6EA+ZITpvDjHdT4IGN3dmt/QV6ScssCE/wEtcNDIKfkdpxK55o/DetvlkRCA 93fUejgYRvu5w== Received: from IcarusMOD.eternityproject.eu (unknown [100.64.1.21]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: kholk11) by bali.collaboradmins.com (Postfix) with ESMTPSA id BB46017E0018; Thu, 16 Jul 2026 17:13:36 +0200 (CEST) From: AngeloGioacchino Del Regno To: chunfeng.yun@mediatek.com Cc: vkoul@kernel.org, neil.armstrong@linaro.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-phy@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, kernel@collabora.com Subject: [PATCH 1/2] dt-bindings: phy: Document MT8196 MediaTek PCI-Express Gen4 S-PHY Date: Thu, 16 Jul 2026 17:13:32 +0200 Message-ID: <20260716151333.77254-2-angelogioacchino.delregno@collabora.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260716151333.77254-1-angelogioacchino.delregno@collabora.com> References: <20260716151333.77254-1-angelogioacchino.delregno@collabora.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This adds bindings for the PCI-Express Gen4 S-PHY found in newer MediaTek SoCs, such as MT8196 and its variants. In the current "revision 3", depending on the specific port, this S-PHY supports up to two lanes of PCI-Express Gen 4 and both EP and RC modes. It is not clear whether revisions/versions earlier than 3 have ever been shipped in any other MediaTek SoC. Signed-off-by: AngeloGioacchino Del Regno --- .../phy/mediatek,mt8196-pcie-sphy.yaml | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/mediatek,mt8196-p= cie-sphy.yaml diff --git a/Documentation/devicetree/bindings/phy/mediatek,mt8196-pcie-sph= y.yaml b/Documentation/devicetree/bindings/phy/mediatek,mt8196-pcie-sphy.ya= ml new file mode 100644 index 000000000000..2b61882c402c --- /dev/null +++ b/Documentation/devicetree/bindings/phy/mediatek,mt8196-pcie-sphy.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/mediatek,mt8196-pcie-sphy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek PCI-Express Gen4 S-PHY + +maintainers: + - AngeloGioacchino Del Regno + +description: + The MediaTek PCI-Express Gen4 S-PHY is capable of data serialization + and de-serialization with 8, 10, 128 or 130 bits (16GT/s) encoding + and decoding, has analog buffers, elastic buffers and mechanisms for + receiver detection. + This PHY supports link rates of 2.5, 5.0, 6.0 and 16.0 GT/s per-lane + in both Root Complex (RC) and End Point (EP) modes, depending on the + chosen port. + The Digital PHY (PHYD) part adheres to the Intel PIPE (PHY Interface + for the PCIe) specification. + +properties: + compatible: + const: mediatek,mt8196-pcie-sphy + + reg: + minItems: 2 + + reg-names: + items: + - const: sif + - const: ckm + + "#phy-cells": + const: 0 + + nvmem-cells: + items: + - description: Internal resistor selection of TX Bias Current + - description: XTP Bias V2V voltage calibration + - description: S-PLL CKTX Impedance Selection (P-MOSFET side) + - description: S-PLL CKTX Impedance Selection (N-MOSFET side) + - description: S-PLL CKTX Intermediate Transition Impedance + - description: RX Front-End Return Loss Continuous Time Linear EQ + - description: RX Front-End Return Loss Variable Gain Amplifier + - description: RX Front-End Return Loss Decision Feedback EQ + - description: RX Impedance Selection + - description: TX Impedance Selection (P-MOSFET side) + - description: TX Impedance Selection (N-MOSFET side) + - description: TX Lane 0 Switch Resistance (RSWn) + - description: TX Lane 1 Switch Resistance (RSWn) + - description: eFuse calibration table version + + nvmem-cell-names: + items: + - const: int-r + - const: xtp-vtrim + - const: cktx-pmos + - const: cktx-nmos + - const: cktx-r-mid + - const: rxfe-lanes-rl-ctle + - const: rxfe-lanes-rl-vga + - const: rxfe-lanes-rl-dfe + - const: rx-lanes-imp + - const: tx-lanes-pmos + - const: tx-lanes-nmos + - const: tx-ln0-rswn + - const: tx-ln1-rswn + - const: cal-version + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - reg-names + - "#phy-cells" + +additionalProperties: false + +examples: + - | + phy@16900000 { + compatible =3D "mediatek,mt8196-pcie-sphy"; + reg =3D <0x16900000 0x10000>, <0x16920000 0x10000>; + reg-names =3D "sif", "ckm"; + power-domains =3D <&spm 10>; + #phy-cells =3D <0>; + }; --=20 2.54.0 From nobody Sat Jul 25 15:53:15 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3E61441F7D4; Thu, 16 Jul 2026 15:13:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784214827; cv=none; b=bGiuvu/06foQJe8E4BOiehYFqIAigWSKoVkqJQgV4wZ8ekycGmHv1F0NYE6VqfFbOWQF/7/0LzP56w89r/2/GKnxQWivs4IcOqAWhto3WpJyTR0SaeXfEsunLg82s0reWBWrDeTA/6tfR1pT9UMrXpvgHJOSgijRshloZuATDI4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784214827; c=relaxed/simple; bh=h6qVIW/55ZaaxNVC3nOm50V/lNeGr3xdAgd4vM3aWgY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=i3w+X5MCT7stoqlXzJ7BZWmMESmEcXPXY2SXWlmS1Ew4HsagFX0oTISL+dOVRFIV9wpoD7tuQkRYqCv5u6iLPFLXb25ErXWLMYioZJ/WLN2Hf903VT9C2eN1c129oax2gfRy1xKcbZFI+wH4E0EQX2nwla4I/wX7Rp7yDKa/lNU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=XqeUxI+K; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="XqeUxI+K" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1784214818; bh=h6qVIW/55ZaaxNVC3nOm50V/lNeGr3xdAgd4vM3aWgY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XqeUxI+K4HYfliHW350szspLhgewvSpMqtqkq51FN2/aJHaLJ5RFU74U5fidTZ3QL CLhsgVW6Z2INGGXaTaJvf+iCumGnBEWuYanec/KHV0lNdZCdQ/H7kdNSPUBrbLJU8B LsEPgNA6518ZsXeBDBcDK8Wh3t8kQMve3yvwPuNf8xpbf+STjsWNz0K6ROebVWWWn7 SrSPAsgO3ryBzr/z0V9klpM56KczuY0rblt+1VTvuJtOzas15h7zJHUbwuMw7sdpP/ 8Vhcv3z5eEZ1wBn4DIomMdR5e4T3oZLjNtWT+ziiSzWaR/Q0nZGSsPGeG59m5YrhiI 1vlNv0uxc7Lxg== Received: from IcarusMOD.eternityproject.eu (unknown [100.64.1.21]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: kholk11) by bali.collaboradmins.com (Postfix) with ESMTPSA id 7623817E0076; Thu, 16 Jul 2026 17:13:37 +0200 (CEST) From: AngeloGioacchino Del Regno To: chunfeng.yun@mediatek.com Cc: vkoul@kernel.org, neil.armstrong@linaro.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-phy@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, kernel@collabora.com Subject: [PATCH 2/2] phy: mediatek: Add support for PCI-Express Gen4 S-PHY Date: Thu, 16 Jul 2026 17:13:33 +0200 Message-ID: <20260716151333.77254-3-angelogioacchino.delregno@collabora.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260716151333.77254-1-angelogioacchino.delregno@collabora.com> References: <20260716151333.77254-1-angelogioacchino.delregno@collabora.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for the PCI-Express Gen4 S-PHY found in the latest MediaTek SoCs, including MT8196, MT8894 and similar. Signed-off-by: AngeloGioacchino Del Regno --- drivers/phy/mediatek/Kconfig | 9 + drivers/phy/mediatek/Makefile | 1 + drivers/phy/mediatek/phy-mtk-pcie-sphy.c | 560 +++++++++++++++++++++++ 3 files changed, 570 insertions(+) create mode 100644 drivers/phy/mediatek/phy-mtk-pcie-sphy.c diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig index ba6461350951..77236f3084c8 100644 --- a/drivers/phy/mediatek/Kconfig +++ b/drivers/phy/mediatek/Kconfig @@ -13,6 +13,15 @@ config PHY_MTK_PCIE callback for PCIe GEN3 port, it supports software efuse initialization. =20 +config PHY_MTK_PCIE_SPHY + tristate "MediaTek PCIe S-PHY Driver" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on OF + select GENERIC_PHY + help + Say 'Y' here to add support for MediaTek PCIe S-PHY driver for + PCI-Express Gen4 controllers as found in MT6991, MT8196 and others. + config PHY_MTK_XFI_TPHY tristate "MediaTek 10GE SerDes XFI T-PHY driver" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile index ed0da708759b..7e984c7cfea3 100644 --- a/drivers/phy/mediatek/Makefile +++ b/drivers/phy/mediatek/Makefile @@ -5,6 +5,7 @@ =20 obj-$(CONFIG_PHY_MTK_DP) +=3D phy-mtk-dp.o obj-$(CONFIG_PHY_MTK_PCIE) +=3D phy-mtk-pcie.o +obj-$(CONFIG_PHY_MTK_PCIE_SPHY) +=3D phy-mtk-pcie-sphy.o obj-$(CONFIG_PHY_MTK_TPHY) +=3D phy-mtk-tphy.o obj-$(CONFIG_PHY_MTK_UFS) +=3D phy-mtk-ufs.o obj-$(CONFIG_PHY_MTK_XSPHY) +=3D phy-mtk-xsphy.o diff --git a/drivers/phy/mediatek/phy-mtk-pcie-sphy.c b/drivers/phy/mediate= k/phy-mtk-pcie-sphy.c new file mode 100644 index 000000000000..c794505060a8 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-pcie-sphy.c @@ -0,0 +1,560 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 MediaTek Inc. + * Copyright (c) 2026 Collabora Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "phy-mtk-io.h" + +/* PHY System Interface (SIF) registers */ +#define PEXTP_DIG_GLB_TOP 0x20 +# define RG_XTP_BYPASS_PIPE_RST_RC BIT(17) +#define PEXTP_DIG_GLB_CKBG0 0x30 +# define RG_XTP_CKBG_XTAL_STABLE_TIME_SEL GENMASK(25, 16) +#define PEXTP_DIG_GLB_TPLL_CTL0 0x38 +# define RG_XTP_TPLL_SET_STABLE_TIME_SEL GENMASK(7, 2) +# define RG_XTP_TPLL_PWE_ON_STABLE_TIME_SEL GENMASK(9, 8) +#define PEXTP_DIG_GLB_CLKREQ_CTL 0x50 +# define RG_XTP_CKM_EN_L1S0 BIT(13) +# define RG_XTP_CKM_EN_L1S1 BIT(14) +#define PEXTP_DIG_GLB_TPLL_CTL2 0xf4 +# define RG_XTP_TPLL_ISO_EN_STABLE_TIME_SEL GENMASK(13, 12) + +/* PHY System Interface Digital registers */ +#define PEXTP_DIG_LN_TRX_PIPE_IF_17 0x30e8 +# define RG_XTP_LN_RX_LF_CTLE_CSEL_GEN4 GENMASK(14, 12) +#define PEXTP_DIG_LN_RX_F0 0x50f0 +# define RG_XTP_LN_RX_GEN1_CTLE1_CSEL GENMASK(3, 0) +# define RG_XTP_LN_RX_GEN2_CTLE1_CSEL GENMASK(7, 4) +# define RG_XTP_LN_RX_GEN3_CTLE1_CSEL GENMASK(11, 8) +# define RG_XTP_LN_RX_GEN4_CTLE1_CSEL GENMASK(15, 12) +#define PEXTP_DIG_LN_RX2_AEQ_EDGE_0 0x6004 +# define RG_XTP_LN_RX_AEQ_EGEQ_RATIO_GEN3 GENMASK(21, 16) +# define RG_XTP_LN_RX_AEQ_EGEQ_RATIO_GEN4 GENMASK(29, 24) +# define AEQ_EGEQ_RATIO_GEN3_TO_22 0x16 +# define AEQ_EGEQ_RATIO_GEN4_TO_22 0x16 + +/* PHY System Interface Analog registers */ +#define PEXTP_ANA_GLB_TPLL1_RSVD 0x902c +# define RG_XTP_GLB_TPLL1_P_PATH_GAIN GENMASK(2, 0) +#define PEXTP_ANA_GLB_BIAS_0 0x9060 +# define RG_XTP_GLB_BIAS_INTR_CTRL GENMASK(5, 0) +#define PEXTP_ANA_GLB_BIAS_1 0x90c0 +# define RG_XTP_GLB_BIAS_V2V_VTRIM GENMASK(9, 6) +#define PEXTP_ANA_LN_TRX_0C 0xa00c +# define RG_XTP_LN_TX_RSWN_IMPSEL GENMASK(20, 16) +#define PEXTP_ANA_LN_TRX_34 0xa034 +# define RG_XTP_LN_RX_FE BIT(15) +#define PEXTP_ANA_LN_TRX_6C 0xa06c +# define RG_XTP_LN_RX_AEQ_CTLE_ERR_TYPE GENMASK(14, 13) +# define AEQ_CTLE_SEARCH_ERR_TYPE_H1P5 0 +# define AEQ_CTLE_SEARCH_ERR_TYPE_H1P5_H2P5 1 +# define AEQ_CTLE_SEARCH_ERR_TYPE_P1P5_H2P5_H3P5 2 +#define PEXTP_ANA_LN_TRX_A0 0xa0a0 +# define RG_XTP_LN_TX_IMPSEL_PMOS GENMASK(4, 0) +# define RG_XTP_LN_TX_IMPSEL_NMOS GENMASK(11, 7) +# define RG_XTP_LN_RX_IMPSEL GENMASK(15, 12) +#define PEXTP_ANA_LN_TRX_A8 0xa0a8 +# define RG_XTP_LN_RX_LEQ_RL_CTLE_CAL GENMASK(6, 2) +# define RG_XTP_LN_RX_LEQ_RL_VGA_CAL GENMASK(11, 7) +# define RG_XTP_LN_RX_LEQ_RL_DFE_CAL GENMASK(23, 19) +#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_4 0xb004 +#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_8 0xb008 +#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_C 0xb00c +#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_10 0xb010 +#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_14 0xb014 +#define PEXTP_DIG_LN_TX_LC_TABLE_RSWN_18 0xb018 +# define RG_XTP_LN_TX_LC_PRESET_MGx_Px_CM1 GENMASK(5, 0) +# define RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0 GENMASK(13, 8) +# define RG_XTP_LN_TX_LC_PRESET_MGx_Px_CP1 GENMASK(21, 16) +#define PEXTP_REG_LANE(x) ((x) * 0x100) + +/* PHY Clock Management (CKM) registers */ +#define XTP_CKM_FORCE_6 0x38 +# define RG_CKM_BIAS_WAIT_PRD_US GENMASK(21, 16) +#define XTP_CKM_REG_SPLL_FBKDIV_5 0xd4 +# define RG_CKM_CKTX_IMPSEL_PMOS GENMASK(19, 16) +# define RG_CKM_CKTX_IMPSEL_NMOS GENMASK(23, 20) +# define RG_CKM_CKTX_IMPSEL_SW GENMASK(27, 24) + +/* Calibration data from eFuses */ +#define MTK_PCIE_SPHY_CALIBRATION_MAX_DATA_LANES 2 +#define MTK_PCIE_SPHY_CALIBRATION_LAST_QUIRK_VER 4 + +/** + * struct mtk_pcie_sphy_imp_sel - Impedance Selection parameters + * @pmos: Impedance selection for P-Channel MOSFET + * @nmos: Impedance selection for N-Channel MOSFET + */ +struct mtk_pcie_sphy_imp_sel { + u8 pmos : 4; + u8 nmos : 4; +}; + +/** + * struct mtk_pcie_sphy_efuse - eFuse calibration data for S-PHY + * @int_r_ctrl: Internal resistor selection of TX Bias Current + * @xtp_vtrim: XTP Bias V2V voltage calibration + * @cktx_impsel: SPLL CKTX Impedance Selection (P and N MOSFET) + * @cktx_r_mid: SPLL CKTX Intermediate Transition Impedance (Rmid) + * @rx_leq_rl_ctle: RX Front-End Return Loss Continuous Time Linear Equali= zation value + * @rx_leq_rl_vga: RX Front-End Return Loss Variable Gain Amplifier value + * @rx_leq_rl_dfe: RX Front-End Return Loss Decision Feedback Equalizatio= n value + * @rx_impsel: RX Impedance Selection + * @tx_impsel: TX Impedance Selection (P and N MOSFET) + * @tx_rswn_impsel: TX RSWn (Switch Resistance) impedance selection + * @supported: eFuse calibration data is supported + */ +struct mtk_pcie_sphy_efuse { + u8 int_r_ctrl; + u8 xtp_vtrim; + struct mtk_pcie_sphy_imp_sel cktx_impsel; + u8 cktx_r_mid; + u8 rx_leq_rl_ctle; + u8 rx_leq_rl_vga; + u8 rx_leq_rl_dfe; + u8 rx_impsel; + struct mtk_pcie_sphy_imp_sel tx_impsel; + u8 tx_rswn_impsel[MTK_PCIE_SPHY_CALIBRATION_MAX_DATA_LANES]; + bool supported; +}; + +/** + * struct mtk_pcie_sphy - PCI-Express S-PHY driver main structure + * @dev: Pointer to device structure + * @phy: Pointer to generic phy structure + * @sif_base: IO mapped register base address of system interface + * @ckm_base: IO mapped register base address of clock management inter= face + * @num_lanes: Number of lanes + * @calibration: eFuse calibration data for S-PHY + */ +struct mtk_pcie_sphy { + struct device *dev; + struct phy *phy; + void __iomem *sif_base; + void __iomem *ckm_base; + u8 num_lanes; + struct mtk_pcie_sphy_efuse calibration; +}; + +static void mtk_pcie_sphy_apply_calibration(struct mtk_pcie_sphy *pcie_sph= y) +{ + struct mtk_pcie_sphy_efuse *cal =3D &pcie_sphy->calibration; + int i; + + mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_ANA_GLB_BIAS_0, + RG_XTP_GLB_BIAS_INTR_CTRL, cal->int_r_ctrl); + + mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_ANA_GLB_BIAS_1, + RG_XTP_GLB_BIAS_V2V_VTRIM, cal->xtp_vtrim); + + mtk_phy_update_field(pcie_sphy->ckm_base + XTP_CKM_REG_SPLL_FBKDIV_5, + RG_CKM_CKTX_IMPSEL_PMOS, cal->cktx_impsel.pmos); + + mtk_phy_update_field(pcie_sphy->ckm_base + XTP_CKM_REG_SPLL_FBKDIV_5, + RG_CKM_CKTX_IMPSEL_NMOS, cal->cktx_impsel.nmos); + + mtk_phy_update_field(pcie_sphy->ckm_base + XTP_CKM_REG_SPLL_FBKDIV_5, + RG_CKM_CKTX_IMPSEL_SW, cal->cktx_r_mid); + + for (i =3D 0; i < pcie_sphy->num_lanes; i++) { + void __iomem *sif_lane_base =3D pcie_sphy->sif_base + PEXTP_REG_LANE(i); + + mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_0C, + RG_XTP_LN_TX_RSWN_IMPSEL, cal->tx_rswn_impsel[i]); + + mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A8, + RG_XTP_LN_RX_LEQ_RL_CTLE_CAL, cal->rx_leq_rl_ctle); + + mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A8, + RG_XTP_LN_RX_LEQ_RL_VGA_CAL, cal->rx_leq_rl_vga); + + mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A8, + RG_XTP_LN_RX_LEQ_RL_DFE_CAL, cal->rx_leq_rl_dfe); + + mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A0, + RG_XTP_LN_RX_IMPSEL, cal->rx_impsel); + + mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A0, + RG_XTP_LN_TX_IMPSEL_PMOS, cal->tx_impsel.pmos); + + mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A0, + RG_XTP_LN_TX_IMPSEL_NMOS, cal->tx_impsel.nmos); + } +} + +/** + * mtk_pcie_sphy_init() - Initialize the PCI-Express S-PHY + * @phy: the phy to be initialized + * + * The hardware settings will be reset during suspend, it should be + * reinitialized when the consumer calls phy_init() again on resume. + */ +static int mtk_pcie_sphy_init(struct phy *phy) +{ + struct mtk_pcie_sphy *pcie_sphy =3D phy_get_drvdata(phy); + struct mtk_pcie_sphy_imp_sel tx_impsel; + int i; + + /* Set CKM Bias wait time to 4 microseconds */ + mtk_phy_update_field(pcie_sphy->ckm_base + XTP_CKM_FORCE_6, + RG_CKM_BIAS_WAIT_PRD_US, 4); + + /* TPLL needs 63 ref_ck ticks to stabilize when setting frequency */ + mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_DIG_GLB_TPLL_CTL0, + RG_XTP_TPLL_SET_STABLE_TIME_SEL, 63); + + /* TPLL needs 3 ref_ck ticks to stabilize when powering on... */ + mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_DIG_GLB_TPLL_CTL0, + RG_XTP_TPLL_PWE_ON_STABLE_TIME_SEL, 3); + + /* ...and the same goes for setting isolation */ + mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_DIG_GLB_TPLL_CTL2, + RG_XTP_TPLL_ISO_EN_STABLE_TIME_SEL, 3); + + /* XTAL doesn't need any stabilization time */ + mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_DIG_GLB_CKBG0, + RG_XTP_CKBG_XTAL_STABLE_TIME_SEL, 0); + + /* Keep pextp_ckm enabled when in L1SS_L1S1 state */ + mtk_phy_clear_bits(pcie_sphy->sif_base + PEXTP_DIG_GLB_CLKREQ_CTL, RG_XTP= _CKM_EN_L1S1); + + /* Set PIPE to reset TPLL */ + mtk_phy_clear_bits(pcie_sphy->sif_base + PEXTP_DIG_GLB_TOP, RG_XTP_BYPASS= _PIPE_RST_RC); + + /* Set TPLL P-Path gain compensation to 1 */ + mtk_phy_update_field(pcie_sphy->sif_base + PEXTP_ANA_GLB_TPLL1_RSVD, + RG_XTP_GLB_TPLL1_P_PATH_GAIN, 1); + + for (i =3D 0; i < pcie_sphy->num_lanes; i++) { + void __iomem *sif_lane_base =3D pcie_sphy->sif_base + PEXTP_REG_LANE(i); + + /* Set RX Lane AEQ CTRL-E Search Error type to h1.5 + h2.5 */ + mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_6C, + RG_XTP_LN_RX_AEQ_CTLE_ERR_TYPE, + AEQ_CTLE_SEARCH_ERR_TYPE_H1P5_H2P5); + + mtk_phy_set_bits(sif_lane_base + PEXTP_ANA_LN_TRX_34, RG_XTP_LN_RX_FE); + + /* TRX: Select CTLE1 for RX Lane AutoEQ CTRL-E Setting on Gen4 */ + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TRX_PIPE_IF_17, + RG_XTP_LN_RX_LF_CTLE_CSEL_GEN4, 1); + + /* Set RX Lane AutoEQ CTRL-E for PCI-Express Gen1 to Gen 4 */ + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX_F0, + RG_XTP_LN_RX_GEN1_CTLE1_CSEL, 13); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX_F0, + RG_XTP_LN_RX_GEN2_CTLE1_CSEL, 13); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX_F0, + RG_XTP_LN_RX_GEN3_CTLE1_CSEL, 13); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX_F0, + RG_XTP_LN_RX_GEN4_CTLE1_CSEL, 0); + + /* Set RX Lane AutoEQ's Edge EQ Ratio to 22 * 0.0625 =3D 1.375 */ + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX2_AEQ_EDGE_0, + RG_XTP_LN_RX_AEQ_EGEQ_RATIO_GEN3, 22); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_RX2_AEQ_EDGE_0, + RG_XTP_LN_RX_AEQ_EGEQ_RATIO_GEN4, 22); + + /* Setup Digital lane TX Link Characteristics Table */ + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_4, + RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 10); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_4, + RG_XTP_LN_TX_LC_PRESET_MGx_Px_CP1, 2); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_8, + RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 11); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_8, + RG_XTP_LN_TX_LC_PRESET_MGx_Px_CP1, 1); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_C, + RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 12); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_10, + RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 13); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_10, + RG_XTP_LN_TX_LC_PRESET_MGx_Px_CM1, 1); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_14, + RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 11); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_14, + RG_XTP_LN_TX_LC_PRESET_MGx_Px_CM1, 1); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_18, + RG_XTP_LN_TX_LC_PRESET_MGx_Px_C0, 10); + + mtk_phy_update_field(sif_lane_base + PEXTP_DIG_LN_TX_LC_TABLE_RSWN_18, + RG_XTP_LN_TX_LC_PRESET_MGx_Px_CM1, 2); + } + + if (pcie_sphy->calibration.supported) { + mtk_pcie_sphy_apply_calibration(pcie_sphy); + + tx_impsel.pmos =3D pcie_sphy->calibration.tx_impsel.pmos; + tx_impsel.nmos =3D pcie_sphy->calibration.tx_impsel.nmos; + } else { + /* Set P=3D10, N=3D9 to prevent EMI if no calibration present */ + tx_impsel.pmos =3D 10; + tx_impsel.nmos =3D 9; + } + + /* Select TX Impedance on N and P MOSFETs */ + for (i =3D 0; i < pcie_sphy->num_lanes; i++) { + void __iomem *sif_lane_base =3D pcie_sphy->sif_base + PEXTP_REG_LANE(i); + + mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A0, + RG_XTP_LN_TX_IMPSEL_PMOS, tx_impsel.pmos); + + mtk_phy_update_field(sif_lane_base + PEXTP_ANA_LN_TRX_A0, + RG_XTP_LN_TX_IMPSEL_NMOS, tx_impsel.nmos); + } + + return 0; +} + +static const struct phy_ops mtk_pcie_sphy_ops =3D { + .init =3D mtk_pcie_sphy_init, + .owner =3D THIS_MODULE, +}; + +static int mtk_pcie_sphy_get_one_cal_para(struct device *dev, const char *= name, u8 max_val) +{ + u16 buf; + u8 tmp; + int ret; + + /* + * All of the calibrations are always max 8 bits long, but some may + * be split between two different 8-bits cells: handle this corner + * case by retrying reading as u16. + */ + ret =3D nvmem_cell_read_u8(dev, name, &tmp); + if (ret =3D=3D 0) + buf =3D tmp; + else + ret =3D nvmem_cell_read_u16(dev, name, &buf); + + if (ret) { + dev_err(dev, "Cannot get calibration data for %s: %d\n", name, ret); + return ret; + }; + + if (buf =3D=3D 0) { + dev_warn(dev, "No calibration for %s. Using defaults\n", name); + return -ENOENT; + } + + if (buf > max_val) { + dev_err(dev, "Bad value %u retrieved for %s. Returning.\n", buf, name); + return -ERANGE; + }; + + return buf; +} + +static int mtk_pcie_sphy_get_calibration_data(struct mtk_pcie_sphy *pcie_s= phy) +{ + struct mtk_pcie_sphy_efuse *cal =3D &pcie_sphy->calibration; + struct device *dev =3D pcie_sphy->dev; + u8 version; + int ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "int-r", + FIELD_MAX(RG_XTP_GLB_BIAS_INTR_CTRL)); + if (ret < 0) + goto end; + cal->int_r_ctrl =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "xtp-vtrim", + FIELD_MAX(RG_XTP_GLB_BIAS_V2V_VTRIM)); + if (ret < 0) + goto end; + cal->xtp_vtrim =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "cktx-pmos", + FIELD_MAX(RG_CKM_CKTX_IMPSEL_PMOS)); + if (ret < 0) + goto end; + cal->cktx_impsel.pmos =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "cktx-nmos", + FIELD_MAX(RG_CKM_CKTX_IMPSEL_NMOS)); + if (ret < 0) + goto end; + cal->cktx_impsel.nmos =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "cktx-r-mid", + FIELD_MAX(RG_CKM_CKTX_IMPSEL_SW)); + if (ret < 0) + goto end; + cal->cktx_r_mid =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "rxfe-lanes-rl-ctle", + FIELD_MAX(RG_XTP_LN_RX_LEQ_RL_CTLE_CAL)); + if (ret < 0) + goto end; + cal->rx_leq_rl_ctle =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "rxfe-lanes-rl-vga", + FIELD_MAX(RG_XTP_LN_RX_LEQ_RL_VGA_CAL)); + if (ret < 0) + goto end; + cal->rx_leq_rl_vga =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "rxfe-lanes-rl-dfe", + FIELD_MAX(RG_XTP_LN_RX_LEQ_RL_DFE_CAL)); + if (ret < 0) + goto end; + cal->rx_leq_rl_dfe =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "rx-lanes-imp", + FIELD_MAX(RG_XTP_LN_RX_IMPSEL)); + if (ret < 0) + goto end; + cal->rx_impsel =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "tx-lanes-pmos", + FIELD_MAX(RG_XTP_LN_TX_IMPSEL_PMOS)); + if (ret < 0) + goto end; + cal->tx_impsel.pmos =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "tx-lanes-nmos", + FIELD_MAX(RG_XTP_LN_TX_IMPSEL_NMOS)); + if (ret < 0) + goto end; + cal->tx_impsel.nmos =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "tx-ln0-rswn", + FIELD_MAX(RG_XTP_LN_TX_RSWN_IMPSEL)); + if (ret < 0) + goto end; + cal->tx_rswn_impsel[0] =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "tx-ln1-rswn", + FIELD_MAX(RG_XTP_LN_TX_RSWN_IMPSEL)); + if (ret < 0) + goto end; + cal->tx_rswn_impsel[1] =3D ret; + + ret =3D mtk_pcie_sphy_get_one_cal_para(dev, "cal-version", 15); + if (ret < 0) + goto end; + version =3D ret; + + /* Quirk for eFuse calibration table versions 0 to 4 */ + if ((version <=3D MTK_PCIE_SPHY_CALIBRATION_LAST_QUIRK_VER) && + cal->rx_leq_rl_ctle =3D=3D 10) { + cal->rx_leq_rl_vga =3D cal->rx_leq_rl_ctle; + cal->rx_leq_rl_dfe =3D cal->rx_leq_rl_ctle; + } + +end: + if (ret < 0) { + /* + * If any of the calibration values is missing, or if there is + * no calibration at all in the eFuses, this is not a problem, + * as the PHY doesn't require one to actually work. + */ + if (ret =3D=3D -ENOENT) { + cal->supported =3D false; + return 0; + } + return ret; + }; + cal->supported =3D true; + + return 0; +} + +static int mtk_pcie_sphy_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct phy_provider *provider; + struct mtk_pcie_sphy *pcie_sphy; + u32 num_lanes; + int ret; + + pcie_sphy =3D devm_kzalloc(dev, sizeof(*pcie_sphy), GFP_KERNEL); + if (!pcie_sphy) + return -ENOMEM; + + pcie_sphy->sif_base =3D devm_platform_ioremap_resource_byname(pdev, "sif"= ); + if (IS_ERR(pcie_sphy->sif_base)) + return dev_err_probe(dev, PTR_ERR(pcie_sphy->sif_base), + "Failed to map phy-sif base\n"); + + pcie_sphy->ckm_base =3D devm_platform_ioremap_resource_byname(pdev, "ckm"= ); + if (IS_ERR(pcie_sphy->ckm_base)) + return dev_err_probe(dev, PTR_ERR(pcie_sphy->ckm_base), + "Failed to map phy-ckm base\n"); + + pcie_sphy->phy =3D devm_phy_create(dev, dev->of_node, &mtk_pcie_sphy_ops); + if (IS_ERR(pcie_sphy->phy)) + return dev_err_probe(dev, PTR_ERR(pcie_sphy->phy), + "Failed to create PCIe phy\n"); + + ret =3D of_property_read_u32(dev->of_node, "num-lanes", &num_lanes); + if (ret) + num_lanes =3D 1; + else if (num_lanes > 4) + return dev_err_probe(dev, -EINVAL, "Invalid number of lanes.\n"); + + pcie_sphy->num_lanes =3D num_lanes; + pcie_sphy->dev =3D dev; + + if (pcie_sphy->num_lanes <=3D MTK_PCIE_SPHY_CALIBRATION_MAX_DATA_LANES) { + ret =3D mtk_pcie_sphy_get_calibration_data(pcie_sphy); + if (ret) + return ret; + } + + phy_set_drvdata(pcie_sphy->phy, pcie_sphy); + + provider =3D devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) + return dev_err_probe(dev, PTR_ERR(provider), + "Could not register PCI-Express S-PHY\n"); + + ret =3D devm_pm_runtime_enable(dev); + if (ret) + return ret; + + return 0; +} + +static const struct of_device_id mtk_pcie_sphy_of_match[] =3D { + { .compatible =3D "mediatek,mt8196-pcie-sphy" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mtk_pcie_sphy_of_match); + +static struct platform_driver mtk_pcie_sphy_driver =3D { + .probe =3D mtk_pcie_sphy_probe, + .driver =3D { + .name =3D "mtk-pcie-sphy", + .of_match_table =3D mtk_pcie_sphy_of_match, + }, +}; +module_platform_driver(mtk_pcie_sphy_driver); + +MODULE_DESCRIPTION("MediaTek PCIe SPHY driver"); +MODULE_AUTHOR("AngeloGioacchino Del Regno "); +MODULE_LICENSE("GPL"); --=20 2.54.0