Re: [PATCH 2/2] phy: add driver for MediaTek XFI T-PHY

From: AngeloGioacchino Del Regno
Date: Mon Feb 05 2024 - 10:29:24 EST


Il 04/02/24 07:29, Chunfeng Yun (云春峰) ha scritto:
On Thu, 2024-02-01 at 21:53 +0000, Daniel Golle wrote:

External email : Please do not click links or open attachments until
you have verified the sender or the content.
Add driver for MediaTek's XFI T-PHY, 10 Gigabit/s Ethernet SerDes
PHY
which can be found in the MT7988 SoC.

The PHY can operates only in PHY_MODE_ETHERNET, the submode is one of
PHY_INTERFACE_MODE_* corresponding to the supported modes:

* USXGMII \
* 10GBase-R }- USXGMII PCS - XGDM \
* 5GBase-R / \
}- Ethernet MAC
* 2500Base-X \ /
* 1000Base-X }- LynxI PCS - GDM /
* Cisco SGMII (MAC side) /

In order to work-around a performance issue present on the first of
two XFI T-PHYs present in MT7988, special tuning is applied which can
be
selected by adding the 'mediatek,usxgmii-performance-errata' property
to
the device tree node.

There is no documentation for most registers used for the
analog/tuning part, however, most of the registers have been
partially
reverse-engineered from MediaTek's SDK implementation (an opaque
sequence of 32-bit register writes) and descriptions for all relevant
digital registers and bits such as resets and muxes have been
supplied
by MediaTek.

Signed-off-by: Daniel Golle <daniel@xxxxxxxxxxxxxx>
---
MAINTAINERS | 1 +
drivers/phy/mediatek/Kconfig | 12 +
drivers/phy/mediatek/Makefile | 1 +
drivers/phy/mediatek/phy-mtk-xfi-tphy.c | 392
++++++++++++++++++++++++
4 files changed, 406 insertions(+)
create mode 100644 drivers/phy/mediatek/phy-mtk-xfi-tphy.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 52769631bdb1a..52e4192470bd9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13715,6 +13715,7 @@ L:netdev@xxxxxxxxxxxxxxx
S:Maintained
F:drivers/net/phy/mediatek-ge-soc.c
F:drivers/net/phy/mediatek-ge.c
+F:drivers/phy/mediatek/phy-mtk-xfi-tphy.c
MEDIATEK I2C CONTROLLER DRIVER
M:Qii Wang <qii.wang@xxxxxxxxxxxx>
diff --git a/drivers/phy/mediatek/Kconfig
b/drivers/phy/mediatek/Kconfig
index 3125ecb5d119f..5161d130c7f8b 100644
--- a/drivers/phy/mediatek/Kconfig
+++ b/drivers/phy/mediatek/Kconfig
@@ -13,6 +13,18 @@ config PHY_MTK_PCIE
callback for PCIe GEN3 port, it supports software efuse
initialization.
+config PHY_MTK_XFI_TPHY
+tristate "MediaTek XFI T-PHY Driver"
+depends on ARCH_MEDIATEK || COMPILE_TEST
+depends on OF && OF_ADDRESS
+depends on HAS_IOMEM
+select GENERIC_PHY
+help
+ Say 'Y' here to add support for MediaTek XFI T-PHY driver.
+ The driver provides access to the Ethernet SerDes T-PHY supporting
+ 1GE and 2.5GE modes via the LynxI PCS, and 5GE and 10GE modes
+ via the USXGMII PCS found in MediaTek SoCs with 10G Ethernet.
+
config PHY_MTK_TPHY
tristate "MediaTek T-PHY Driver"
depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/phy/mediatek/Makefile
b/drivers/phy/mediatek/Makefile
index c9a50395533eb..fa7217178e7f4 100644
--- a/drivers/phy/mediatek/Makefile
+++ b/drivers/phy/mediatek/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_MTK_PCIE)+= phy-mtk-pcie.o
obj-$(CONFIG_PHY_MTK_TPHY)+= phy-mtk-tphy.o
obj-$(CONFIG_PHY_MTK_UFS)+= phy-mtk-ufs.o
obj-$(CONFIG_PHY_MTK_XSPHY)+= phy-mtk-xsphy.o
+obj-$(CONFIG_PHY_MTK_XFI_TPHY)+= phy-mtk-xfi-tphy.o
phy-mtk-hdmi-drv-y:= phy-mtk-hdmi.o
phy-mtk-hdmi-drv-y+= phy-mtk-hdmi-mt2701.o
diff --git a/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
new file mode 100644
index 0000000000000..d50e6320860e5
--- /dev/null
+++ b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* MediaTek 10GE SerDes PHY driver
+ *
+ * Copyright (c) 2024 Daniel Golle <daniel@xxxxxxxxxxxxxx>
+ * Bc-bocun Chen <bc-bocun.chen@xxxxxxxxxxxx>
+ * based on mtk_usxgmii.c found in MediaTek's SDK released under
GPL-2.0
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Henry Yen <henry.yen@xxxxxxxxxxxx>
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
+
+#define MTK_XFI_TPHY_NUM_CLOCKS2
+
+#define REG_DIG_GLB_700x0070
+#define XTP_PCS_RX_EQ_IN_PROGRESS(x)FIELD_PREP(GENMASK(25, 24),
(x))
+#define XTP_PCS_MODE_MASKGENMASK(17, 16)
+#define XTP_PCS_MODE(x)FIELD_PREP(GENMASK(17, 16), (x))
+#define XTP_PCS_RST_BBIT(15)
+#define XTP_FRC_PCS_RST_BBIT(14)
+#define XTP_PCS_PWD_SYNC_MASKGENMASK(13, 12)
+#define XTP_PCS_PWD_SYNC(x)FIELD_PREP(XTP_PCS_PWD_SYNC_MASK, (x))
+#define XTP_PCS_PWD_ASYNC_MASKGENMASK(11, 10)
+#define XTP_PCS_PWD_ASYNC(x)FIELD_PREP(XTP_PCS_PWD_ASYNC_MASK, (x))
+#define XTP_FRC_PCS_PWD_ASYNCBIT(8)
+#define XTP_PCS_UPDTBIT(4)
+#define XTP_PCS_IN_FR_RGBIT(0)
+
+#define REG_DIG_GLB_F40x00f4
+#define XFI_DPHY_PCS_SELBIT(0)
+#define XFI_DPHY_PCS_SEL_SGMIIFIELD_PREP(XFI_DPHY_PCS_SEL, 1)
+#define XFI_DPHY_PCS_SEL_USXGMIIFIELD_PREP(XFI_DPHY_PCS_SEL, 0)
+#define XFI_DPHY_AD_SGDT_FRC_ENBIT(5)
+
+#define REG_DIG_LN_TRX_400x3040
+#define XTP_LN_FRC_TX_DATA_ENBIT(29)
+#define XTP_LN_TX_DATA_ENBIT(28)
+
+#define REG_DIG_LN_TRX_B00x30b0
+#define XTP_LN_FRC_TX_MACCK_ENBIT(5)
+#define XTP_LN_TX_MACCK_ENBIT(4)
+
+#define REG_ANA_GLB_D00x90d0
+#define XTP_GLB_USXGMII_SEL_MASKGENMASK(3, 1)
+#define XTP_GLB_USXGMII_SEL(x)FIELD_PREP(GENMASK(3, 1), (x))
+#define XTP_GLB_USXGMII_ENBIT(0)
+
+struct mtk_xfi_tphy {
+void __iomem*base;
+struct device*dev;
+struct reset_control*reset;
+struct clk_bulk_dataclocks[MTK_XFI_TPHY_NUM_CLOCKS];
+boolda_war;
+};
+
+static void mtk_xfi_tphy_write(struct mtk_xfi_tphy *xfi_tphy, u16
reg,
+ u32 value)
+{
+iowrite32(value, xfi_tphy->base + reg);
+}
+
+static void mtk_xfi_tphy_rmw(struct mtk_xfi_tphy *xfi_tphy, u16 reg,
+ u32 clr, u32 set)
+{
+u32 val;
+
+val = ioread32(xfi_tphy->base + reg);
+val &= ~clr;
+val |= set;
+iowrite32(val, xfi_tphy->base + reg);
+}
+
+static void mtk_xfi_tphy_set(struct mtk_xfi_tphy *xfi_tphy, u16 reg,
+ u32 set)
+{
+mtk_xfi_tphy_rmw(xfi_tphy, reg, 0, set);
+}
+
+static void mtk_xfi_tphy_clear(struct mtk_xfi_tphy *xfi_tphy, u16
reg,
+ u32 clr)
+{
+mtk_xfi_tphy_rmw(xfi_tphy, reg, clr, 0);
+}

Helpers defined in phy-mtk-io.h can be used instead?

+
+static void mtk_xfi_tphy_setup(struct mtk_xfi_tphy *xfi_tphy,
+ phy_interface_t interface)
+{
+bool is_2p5g = (interface == PHY_INTERFACE_MODE_2500BASEX);
+bool is_1g = (interface == PHY_INTERFACE_MODE_1000BASEX ||
+ interface == PHY_INTERFACE_MODE_SGMII);
+bool is_10g = (interface == PHY_INTERFACE_MODE_10GBASER ||
+ interface == PHY_INTERFACE_MODE_USXGMII);
+bool is_5g = (interface == PHY_INTERFACE_MODE_5GBASER);
+bool is_xgmii = (is_10g || is_5g);
+
+dev_dbg(xfi_tphy->dev, "setting up for mode %s\n",
phy_modes(interface));
+
+/* Setup PLL setting */
+mtk_xfi_tphy_rmw(xfi_tphy, 0x9024, 0x100000, is_10g ? 0x0 :
0x100000);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x2020, 0x202000, is_5g ? 0x202000 :
0x0);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x2030, 0x500, is_1g ? 0x0 : 0x500);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x2034, 0xa00, is_1g ? 0x0 : 0xa00);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x2040, 0x340000, is_1g ? 0x200000 :
+ 0x140000);
+
+/* Setup RXFE BW setting */
+mtk_xfi_tphy_rmw(xfi_tphy, 0x50f0, 0xc10, is_1g ? 0x410 :
+ is_5g ? 0x800 : 0x400);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x50e0, 0x4000, is_5g ? 0x0 : 0x4000);
+
+/* Setup RX CDR setting */
+mtk_xfi_tphy_rmw(xfi_tphy, 0x506c, 0x30000, is_5g ? 0x0 : 0x30000);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x5070, 0x670000, is_5g ? 0x620000 :
0x50000);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x5074, 0x180000, is_5g ? 0x180000 :
0x0);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x5078, 0xf000400, is_5g ? 0x8000000 :
+ 0x7000400);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x507c, 0x5000500, is_5g ? 0x4000400 :
+ 0x1000100);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x5080, 0x1410, is_1g ? 0x400 :
+ is_5g ? 0x1010 : 0x0);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x5084, 0x30300, is_1g ? 0x30300 :
+ is_5g ? 0x30100 :
+ 0x100);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x5088, 0x60200, is_1g ? 0x20200 :
+ is_5g ? 0x40000 :
+ 0x20000);
+
+/* Setting RXFE adaptation range setting */
+mtk_xfi_tphy_rmw(xfi_tphy, 0x50e4, 0xc0000, is_5g ? 0x0 : 0xc0000);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x50e8, 0x40000, is_5g ? 0x0 : 0x40000);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x50ec, 0xa00, is_1g ? 0x200 : 0x800);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x50a8, 0xee0000, is_5g ? 0x800000 :
+ 0x6e0000);
+mtk_xfi_tphy_rmw(xfi_tphy, 0x6004, 0x190000, is_5g ? 0x0 :
0x190000);
+if (is_10g)
+mtk_xfi_tphy_write(xfi_tphy, 0x00f8, 0x01423342);
+else if (is_5g)
+mtk_xfi_tphy_write(xfi_tphy, 0x00f8, 0x00a132a1);
+else if (is_2p5g)
+mtk_xfi_tphy_write(xfi_tphy, 0x00f8, 0x009c329c);
+else
+mtk_xfi_tphy_write(xfi_tphy, 0x00f8, 0x00fa32fa);
Still have many magic number.


There's lack of documentation, that's why Daniel has all those magic numbers there.

If you can help unrolling some definitions that'd be really appreciated, as that
would result in a cleaner driver.

Cheers,
Angelo