From nobody Sat Jul 25 02:36:11 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 7170342B30A; Mon, 20 Jul 2026 13:54:18 +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=1784555660; cv=none; b=GQNuAHaiTvdfQgvY7TXaCR3wOSJOjxr1xzpkxA+JgaEqH/Y+WPaBJy916udv0Sj+eVN/+oaK0G4RmSU4L9sFWlrZME0xrkb3dqgsFT83q5557qwXRVFGhXAAgzUbZdbSGI3g6qrCV1Jx44tLGZBicrcDbqqg7SWuisfwUTNUhfA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784555660; c=relaxed/simple; bh=p+IHXAGkZYBnXP0KK3KUxT6ZWI3a3RuaN/BGaUcuR3w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RgCatVshZp/FeRigQjKz6PtQ/5F3OZBSYJ59UCxpRJ9g530hEVP54rJUB9Mhv+RW2egLssS2lHvZB6QEAD/+Y8tkausY4dHNw0EiP0bh3rqtPevUatpXXN9S1YReT0Jb4bic4wNqNJgEzsoL06Zzfe3BqJ3p6vBFoInmSxG3CW8= 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=BNqXhUel; 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="BNqXhUel" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1784555656; bh=p+IHXAGkZYBnXP0KK3KUxT6ZWI3a3RuaN/BGaUcuR3w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BNqXhUeltySqygbcC0Y+CCd9z/CmMt1k4Jw9EKJOs89GG0N4AGsmBMJQ4N0C2bpa1 9liq+pkIpRG7vTYb6eMYG93GG0pHFtRa6WsOfuiqZuwhO9SlSNyaDUqGsbJCplryd7 hHzG6SpGfqlkjScoSPQBQe5HlfbsJo0I7lqcxhlEL0blXFzsJWk2Ir6ZVwrGXVaDV7 VwjWmEvXosLiFhmudXGtYPQMfMPIVdzaHQiSDtVR/nZpMKBvAjlVli3qR0brPbkCs2 e34PocyTGIR2dsdjDPMpSq1cCy7xgZv4V7nsqBJKjOuAxif+XSN6Fx9h6zAKQ2pF3Q 7D6igRoJ8BNbA== 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 5042317E0974; Mon, 20 Jul 2026 15:54:16 +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 v2 1/2] dt-bindings: phy: Document MT8196 MediaTek PCI-Express Gen4 S-PHY Date: Mon, 20 Jul 2026 15:53:43 +0200 Message-ID: <20260720135344.84183-2-angelogioacchino.delregno@collabora.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260720135344.84183-1-angelogioacchino.delregno@collabora.com> References: <20260720135344.84183-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 | 93 +++++++++++++++++++ 1 file changed, 93 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..c24871f7e0e5 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/mediatek,mt8196-pcie-sphy.yaml @@ -0,0 +1,93 @@ +# 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: + items: + - description: System Interface (SIF) registers + - description: Clock Management (CKM) registers + + 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.55.0 From nobody Sat Jul 25 02:36:11 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 404E042587C; Mon, 20 Jul 2026 13:54:19 +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=1784555661; cv=none; b=bN2G16eg3PFvuv8iG0v24mcJxgEgtXjqsG1gsSUxWKJyfBYhirE6N7D7aR1M5VzXD3o/c38cUia/ujkZhUeEaNQgb54SW+UEb7EYmuiHvM5WzsNE4jVNmnBKLsoF7iDQ531dRKle8+wpOPNhUCDBrlPiyX34m3jJTNAdlf+07ZM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784555661; c=relaxed/simple; bh=JA6GGkkEk+2Nz+Gb3Hmsaz7EZ3GQp7eT91o3aSK8e7E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BjPVyCeJlyoaw/xeZluB0Mab50H5mEh0nNET8STh+DBfbQ7qO1XFeAenPMf2hnGd/INtT5/Mtjz0tdnWey2WTFonYEzhhtty+Hnub3Yk9K3bN1oy3VRrPAbb16jbn5x3JLb5DFTaWtgDq3+wZJGLXik3u0O4ID0HUaIfZLOmpQ4= 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=VRpugf2O; 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="VRpugf2O" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1784555657; bh=JA6GGkkEk+2Nz+Gb3Hmsaz7EZ3GQp7eT91o3aSK8e7E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VRpugf2O/EIjfv1kexIIG3cBGaMlI0do7QFLtaqvYpcqLbF9Qxd/Ec3lDia9sLS1S /5metYy0vWd1mdafx5MjQHI9jITKEnpoZNFx/1hWHti6qswhxqorcXpwvFkLUd5BuJ 5pAWU6cKi1VDx/JQUSktdM6snBVgXarX/3mvCNrdhdcO15aNTMuBbfTGxiJvuYROGZ X6R3vJ7cRnTOQkVmCYFgT8H1Bx7PIToUnhUCfDiV6rUI2xcigeThHrWMgq4xXjnFov IlyMNWYOjqvAy/vGrnVszqZSFEgd2oyyGAHWaFYPcGqzBAJ4zAWlzV+lXe14KzX7Aq R+ZjcIwvgzl5g== 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 0619717E0977; Mon, 20 Jul 2026 15:54:16 +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 v2 2/2] phy: mediatek: Add support for PCI-Express Gen4 S-PHY Date: Mon, 20 Jul 2026 15:53:44 +0200 Message-ID: <20260720135344.84183-3-angelogioacchino.delregno@collabora.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260720135344.84183-1-angelogioacchino.delregno@collabora.com> References: <20260720135344.84183-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 | 561 +++++++++++++++++++++++ 3 files changed, 571 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..6c1362b70fab --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-pcie-sphy.c @@ -0,0 +1,561 @@ +// 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 + +#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; + u8 nmos; +}; + +/** + * 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) + return dev_err_probe(dev, ret, + "Cannot get calibration data for %s\n", name); + + if (buf =3D=3D 0) { + dev_info(dev, "No calibration for %s. Using defaults\n", name); + return -ENOENT; + } + + if (buf > max_val) + return dev_err_probe(dev, -ERANGE, + "Bad value %u retrieved for %s.\n", buf, name); + + 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; + + if (pcie_sphy->num_lanes =3D=3D 2) { + 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); + + ret =3D devm_pm_runtime_enable(dev); + if (ret) + return ret; + + 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"); + + 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.55.0