[{"id":3678805,"web_url":"http://patchwork.ozlabs.org/comment/3678805/","msgid":"<61e06e0d-0968-491d-90df-86a69f3c5978@collabora.com>","list_archive_url":null,"date":"2026-04-17T15:44:49","subject":"Re: [PATCH 1/3] phy: mediatek: new XS-PHY driver","submitter":{"id":78980,"url":"http://patchwork.ozlabs.org/api/people/78980/","name":"Arnaud Ferraris","email":"arnaud.ferraris@collabora.com"},"content":"Hi David,\n\nLe 01/04/2026 à 23:53, David Lechner a écrit :\n> Add a new driver for the Mediatek XS-PHY. This is found on some newer\n> Mediatek SoCs.\n> \n> Upstream devicetree bindings already exist. MAINTAINERS is already\n> covered by drivers/phy/phy-mtk-*.\n> \n> Signed-off-by: David Lechner <dlechner@baylibre.com>\n> ---\n>   drivers/phy/Kconfig         |  11 +\n>   drivers/phy/Makefile        |   1 +\n>   drivers/phy/phy-mtk-xsphy.c | 600 ++++++++++++++++++++++++++++++++++++++++++++\n>   3 files changed, 612 insertions(+)\n> \n> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig\n> index 09810b62b51..fc4daa00661 100644\n> --- a/drivers/phy/Kconfig\n> +++ b/drivers/phy/Kconfig\n> @@ -292,6 +292,17 @@ config PHY_MTK_UFS\n>   \t  initialization, power on and power off flow of\n>   \t  specified M-PHYs.\n>   \n> +config PHY_MTK_XSPHY\n> +\tbool \"MediaTek XS-PHY Driver\"\n> +\tdepends on PHY\n> +\tdepends on ARCH_MEDIATEK\n> +\tselect REGMAP\n> +\tselect SYSCON\n> +\thelp\n> +\t  Enable this to support the SuperSpeedPlus XS-PHY transceiver for\n> +\t  USB3.1 GEN2 controllers on MediaTek chips. The driver supports\n> +\t  multiple USB2.0, USB3.1 GEN2 ports.\n> +\n>   config PHY_NPCM_USB\n>   \tbool \"Nuvoton NPCM USB PHY support\"\n>   \tdepends on PHY\n> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile\n> index 83102349669..684e9a99af8 100644\n> --- a/drivers/phy/Makefile\n> +++ b/drivers/phy/Makefile\n> @@ -38,6 +38,7 @@ obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o\n>   obj-$(CONFIG_PHY_EXYNOS_USBDRD) += phy-exynos-usbdrd.o\n>   obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o\n>   obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o\n> +obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o\n>   obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o\n>   obj-$(CONFIG_$(PHASE_)PHY_IMX8MQ_USB) += phy-imx8mq-usb.o\n>   obj-$(CONFIG_PHY_IMX8M_PCIE) += phy-imx8m-pcie.o\n> diff --git a/drivers/phy/phy-mtk-xsphy.c b/drivers/phy/phy-mtk-xsphy.c\n> new file mode 100644\n> index 00000000000..d3418ffb101\n> --- /dev/null\n> +++ b/drivers/phy/phy-mtk-xsphy.c\n> @@ -0,0 +1,600 @@\n> +// SPDX-License-Identifier: GPL-2.0-only\n> +/*\n> + * MediaTek USB3.1 gen2 xsphy Driver\n> + *\n> + * Copyright (c) 2026 MediaTek Inc.\n> + * Copyright (c) 2026 BayLibre, SAS\n> + *\n> + * Based on Linux mtk-xsphy driver:\n> + * Copyright (c) 2018 MediaTek Inc.\n> + * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>\n> + *\n> + * And U-Boot mtk-tphy driver:\n> + * Copyright (c) 2015 - 2019 MediaTek Inc.\n> + * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>\n> + *\t   Ryder Lee <ryder.lee@mediatek.com>\n> + */\n> +\n> +#include <clk.h>\n> +#include <dm.h>\n> +#include <generic-phy.h>\n> +#include <malloc.h>\n> +#include <mapmem.h>\n> +#include <regmap.h>\n> +#include <syscon.h>\n> +\n> +#include <asm/io.h>\n> +#include <dm/device_compat.h>\n> +#include <dm/devres.h>\n> +#include <linux/bitfield.h>\n> +#include <linux/bitops.h>\n> +#include <linux/delay.h>\n> +#include <linux/iopoll.h>\n> +\n> +#include <dt-bindings/phy/phy.h>\n> +\n> +/* u2 phy banks */\n> +#define SSUSB_SIFSLV_MISC\t\t0x000\n> +#define SSUSB_SIFSLV_U2FREQ\t\t0x100\n> +#define SSUSB_SIFSLV_U2PHY_COM\t\t0x300\n> +\n> +/* u3 phy shared banks */\n> +#define SSPXTP_SIFSLV_DIG_GLB\t\t0x000\n> +#define SSPXTP_SIFSLV_PHYA_GLB\t\t0x100\n> +\n> +/* u3 phy banks */\n> +#define SSPXTP_SIFSLV_DIG_LN_TOP\t0x000\n> +#define SSPXTP_SIFSLV_DIG_LN_TX0\t0x100\n> +#define SSPXTP_SIFSLV_DIG_LN_RX0\t0x200\n> +#define SSPXTP_SIFSLV_DIG_LN_DAIF\t0x300\n> +#define SSPXTP_SIFSLV_PHYA_LN\t\t0x400\n> +\n> +#define XSP_U2FREQ_FMCR0\t((SSUSB_SIFSLV_U2FREQ) + 0x00)\n> +#define P2F_RG_FREQDET_EN\t\tBIT(24)\n> +#define P2F_RG_CYCLECNT\t\t\tGENMASK(23, 0)\n> +\n> +#define XSP_U2FREQ_MMONR0\t((SSUSB_SIFSLV_U2FREQ) + 0x0c)\n> +\n> +#define XSP_U2FREQ_FMMONR1\t((SSUSB_SIFSLV_U2FREQ) + 0x10)\n> +#define P2F_RG_FRCK_EN\t\t\tBIT(8)\n> +#define P2F_USB_FM_VALID\t\tBIT(0)\n> +\n> +#define XSP_USBPHYACR0\t\t((SSUSB_SIFSLV_U2PHY_COM) + 0x00)\n> +#define P2A0_RG_INTR_EN\t\t\tBIT(5)\n> +\n> +#define XSP_USBPHYACR1\t\t((SSUSB_SIFSLV_U2PHY_COM) + 0x04)\n> +#define P2A1_RG_INTR_CAL\t\tGENMASK(23, 19)\n> +#define P2A1_RG_VRT_SEL\t\t\tGENMASK(14, 12)\n> +#define P2A1_RG_TERM_SEL\t\tGENMASK(10, 8)\n> +\n> +#define XSP_USBPHYACR5\t\t((SSUSB_SIFSLV_U2PHY_COM) + 0x014)\n> +#define P2A5_RG_HSTX_SRCAL_EN\t\tBIT(15)\n> +#define P2A5_RG_HSTX_SRCTRL\t\tGENMASK(14, 12)\n> +\n> +#define XSP_USBPHYACR6\t\t((SSUSB_SIFSLV_U2PHY_COM) + 0x018)\n> +#define P2A6_RG_BC11_SW_EN\t\tBIT(23)\n> +#define P2A6_RG_OTG_VBUSCMP_EN\t\tBIT(20)\n> +\n> +#define XSP_U2PHYDTM1\t\t((SSUSB_SIFSLV_U2PHY_COM) + 0x06C)\n> +#define P2D_FORCE_IDDIG\t\t\tBIT(9)\n> +#define P2D_RG_VBUSVALID\t\tBIT(5)\n> +#define P2D_RG_SESSEND\t\t\tBIT(4)\n> +#define P2D_RG_AVALID\t\t\tBIT(2)\n> +#define P2D_RG_IDDIG\t\t\tBIT(1)\n> +\n> +#define SSPXTP_PHYA_GLB_00\t((SSPXTP_SIFSLV_PHYA_GLB) + 0x00)\n> +#define RG_XTP_GLB_BIAS_INTR_CTRL\tGENMASK(21, 16)\n> +\n> +#define SSPXTP_PHYA_LN_04\t((SSPXTP_SIFSLV_PHYA_LN) + 0x04)\n> +#define RG_XTP_LN0_TX_IMPSEL\t\tGENMASK(4, 0)\n> +\n> +#define SSPXTP_PHYA_LN_14\t((SSPXTP_SIFSLV_PHYA_LN) + 0x014)\n> +#define RG_XTP_LN0_RX_IMPSEL\t\tGENMASK(4, 0)\n> +\n> +#define XSP_REF_CLK_MHZ\t\t26\n> +#define XSP_SLEW_RATE_COEF\t17\n> +#define XSP_SR_COEF_DIVISOR\t1000\n> +#define XSP_FM_DET_CYCLE_CNT\t1024\n> +\n> +/* PHY switch between pcie/usb3/sgmii */\n> +#define USB_PHY_SWITCH_CTRL\t0x0\n> +#define RG_PHY_SW_TYPE\t\tGENMASK(3, 0)\n> +#define RG_PHY_SW_PCIE\t\t0x0\n> +#define RG_PHY_SW_USB3\t\t0x1\n> +#define RG_PHY_SW_SGMII\t\t0x2\n> +\n> +struct mtk_xsphy_instance {\n> +\tvoid __iomem *port_base;\n> +\tstruct device_node *np;\n> +\tstruct clk ref_clk;\t/* reference clock of analog phy */\n> +\tu32 index;\n> +\tu32 type;\n> +\tstruct regmap *type_sw;\n> +\tu32 type_sw_reg;\n> +\tu32 type_sw_index;\n> +\t/* only for HQA test */\n> +\tu32 efuse_intr;\n> +\tu32 efuse_tx_imp;\n> +\tu32 efuse_rx_imp;\n> +\t/* u2 eye diagram */\n> +\tu32 eye_src;\n> +\tu32 eye_vrt;\n> +\tu32 eye_term;\n> +};\n> +\n> +struct mtk_xsphy {\n> +\tstruct udevice *dev;\n> +\tvoid __iomem *sif_base;\n> +\tstruct mtk_xsphy_instance **phys;\n> +\tu32 nphys;\n> +\tu32 src_ref_clk_mhz; /* reference clock for slew rate calibrate */\n> +\tu32 src_coef; /* coefficient for slew rate calibrate */\n> +};\n> +\n> +static void mtk_xsphy_u2_slew_rate_calibrate(struct mtk_xsphy *xsphy,\n> +\t\t\t\t\t     struct mtk_xsphy_instance *instance)\n> +{\n> +\tvoid __iomem *pbase = instance->port_base;\n> +\tu32 calib_val;\n> +\tu32 fm_out;\n> +\tu32 tmp;\n> +\n> +\t/* use force value */\n> +\tif (instance->eye_src)\n> +\t\treturn;\n> +\n> +\t/* enable USB ring oscillator */\n> +\tsetbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCAL_EN);\n> +\t/* wait for clock to become stable */\n> +\tudelay(1);\n> +\n> +\t/* enable free run clock */\n> +\tsetbits_le32(pbase + XSP_U2FREQ_FMMONR1, P2F_RG_FRCK_EN);\n> +\n> +\t/* set cycle count as 1024 */\n> +\tclrsetbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_CYCLECNT,\n> +\t\t\tFIELD_PREP(P2F_RG_CYCLECNT, XSP_FM_DET_CYCLE_CNT));\n> +\n> +\t/* enable frequency meter */\n> +\tsetbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_FREQDET_EN);\n> +\n> +\t/* ignore return value */\n> +\treadl_poll_sleep_timeout(pbase + XSP_U2FREQ_FMMONR1, tmp,\n> +\t\t\t\t (tmp & P2F_USB_FM_VALID), 10, 200);\n> +\n> +\tfm_out = readl(pbase + XSP_U2FREQ_MMONR0);\n> +\n> +\t/* disable frequency meter */\n> +\tclrbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_FREQDET_EN);\n> +\n> +\t/* disable free run clock */\n> +\tclrbits_le32(pbase + XSP_U2FREQ_FMMONR1, P2F_RG_FRCK_EN);\n> +\n> +\tif (fm_out) {\n> +\t\t/* (1024 / FM_OUT) x reference clock frequency x coefficient */\n> +\t\ttmp = xsphy->src_ref_clk_mhz * xsphy->src_coef;\n> +\t\ttmp = (tmp * XSP_FM_DET_CYCLE_CNT) / fm_out;\n> +\t\tcalib_val = DIV_ROUND_CLOSEST(tmp, XSP_SR_COEF_DIVISOR);\n> +\t} else {\n> +\t\t/* if FM detection fail, set default value */\n> +\t\tcalib_val = 3;\n> +\t}\n> +\tdev_dbg(xsphy->dev, \"phy.%u, fm_out:%u, calib:%u (clk:%u, coef:%u)\\n\",\n> +\t\tinstance->index, fm_out, calib_val, xsphy->src_ref_clk_mhz,\n> +\t\txsphy->src_coef);\n> +\n> +\t/* set HS slew rate */\n> +\tclrsetbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL,\n> +\t\t\tFIELD_PREP(P2A5_RG_HSTX_SRCTRL, calib_val));\n> +\n> +\t/* disable USB ring oscillator */\n> +\tclrbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCAL_EN);\n> +}\n> +\n> +static void mtk_xsphy_u2_instance_init(struct mtk_xsphy *xsphy,\n> +\t\t\t\t       struct mtk_xsphy_instance *instance)\n> +{\n> +\tvoid __iomem *pbase = instance->port_base;\n> +\n> +\t/* DP/DM BC1.1 path Disable */\n> +\tclrbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_BC11_SW_EN);\n> +\n> +\tsetbits_le32(pbase + XSP_USBPHYACR0, P2A0_RG_INTR_EN);\n> +}\n> +\n> +static void mtk_xsphy_u2_instance_power_on(struct mtk_xsphy *xsphy,\n> +\t\t\t\t\t   struct mtk_xsphy_instance *instance)\n> +{\n> +\tvoid __iomem *pbase = instance->port_base;\n> +\n> +\tsetbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_OTG_VBUSCMP_EN);\n> +\n> +\tclrsetbits_le32(pbase + XSP_U2PHYDTM1,\n> +\t\t\tP2D_RG_VBUSVALID | P2D_RG_AVALID | P2D_RG_SESSEND,\n> +\t\t\tP2D_RG_VBUSVALID | P2D_RG_AVALID);\n> +\n> +\tdev_dbg(xsphy->dev, \"%s(%u)\\n\", __func__, instance->index);\n> +}\n> +\n> +static void mtk_xsphy_u2_instance_power_off(struct mtk_xsphy *xsphy,\n> +\t\t\t\t\t    struct mtk_xsphy_instance *instance)\n> +{\n> +\tvoid __iomem *pbase = instance->port_base;\n> +\n> +\tclrbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_OTG_VBUSCMP_EN);\n> +\n> +\tclrsetbits_le32(pbase + XSP_U2PHYDTM1,\n> +\t\t\tP2D_RG_VBUSVALID | P2D_RG_AVALID | P2D_RG_SESSEND,\n> +\t\t\tP2D_RG_SESSEND);\n> +\n> +\tdev_dbg(xsphy->dev, \"%s(%u)\\n\", __func__, instance->index);\n> +}\n> +\n> +static void mtk_xsphy_u2_instance_set_mode(struct mtk_xsphy *xsphy,\n> +\t\t\t\t\t   struct mtk_xsphy_instance *instance,\n> +\t\t\t\t\t   enum phy_mode mode)\n> +{\n> +\tu32 tmp;\n> +\n> +\ttmp = readl(instance->port_base + XSP_U2PHYDTM1);\n> +\n> +\tswitch (mode) {\n> +\tcase PHY_MODE_USB_DEVICE:\n> +\t\ttmp |= P2D_FORCE_IDDIG | P2D_RG_IDDIG;\n> +\t\tbreak;\n> +\tcase PHY_MODE_USB_HOST:\n> +\t\ttmp |= P2D_FORCE_IDDIG;\n> +\t\ttmp &= ~P2D_RG_IDDIG;\n> +\t\tbreak;\n> +\tcase PHY_MODE_USB_OTG:\n> +\t\ttmp &= ~(P2D_FORCE_IDDIG | P2D_RG_IDDIG);\n> +\t\tbreak;\n> +\tdefault:\n> +\t\treturn;\n> +\t}\n> +\n> +\twritel(tmp, instance->port_base + XSP_U2PHYDTM1);\n> +}\n> +\n> +static void mtk_xsphy_parse_property(struct mtk_xsphy *xsphy,\n> +\t\t\t\t     struct mtk_xsphy_instance *instance)\n> +{\n> +\tofnode node = np_to_ofnode(instance->np);\n> +\n> +\tswitch (instance->type) {\n> +\tcase PHY_TYPE_USB2:\n> +\t\tofnode_read_u32(node, \"mediatek,efuse-intr\", &instance->efuse_intr);\n> +\t\tofnode_read_u32(node, \"mediatek,eye-src\", &instance->eye_src);\n> +\t\tofnode_read_u32(node, \"mediatek,eye-vrt\", &instance->eye_vrt);\n> +\t\tofnode_read_u32(node, \"mediatek,eye-term\", &instance->eye_term);\n> +\n> +\t\tdev_dbg(xsphy->dev, \"intr:%u, src:%u, vrt:%u, term:%u\\n\",\n> +\t\t\tinstance->efuse_intr, instance->eye_src,\n> +\t\t\tinstance->eye_vrt, instance->eye_term);\n> +\t\treturn;\n> +\tcase PHY_TYPE_USB3:\n> +\t\tofnode_read_u32(node, \"mediatek,efuse-intr\", &instance->efuse_intr);\n> +\t\tofnode_read_u32(node, \"mediatek,efuse-tx-imp\", &instance->efuse_tx_imp);\n> +\t\tofnode_read_u32(node, \"mediatek,efuse-rx-imp\", &instance->efuse_rx_imp);\n> +\n> +\t\tdev_dbg(xsphy->dev, \"intr:%u, tx-imp:%u, rx-imp:%u\\n\",\n> +\t\t\tinstance->efuse_intr, instance->efuse_tx_imp,\n> +\t\t\tinstance->efuse_rx_imp);\n> +\t\treturn;\n> +\tcase PHY_TYPE_PCIE:\n> +\tcase PHY_TYPE_SGMII:\n> +\t\t/* nothing to do */\n> +\t\treturn;\n> +\tdefault:\n> +\t\tdev_err(xsphy->dev, \"incompatible PHY type\\n\");\n> +\t\treturn;\n> +\t}\n> +}\n> +\n> +static void mtk_xsphy_u2_props_set(struct mtk_xsphy *xsphy,\n> +\t\t\t\t   struct mtk_xsphy_instance *instance)\n> +{\n> +\tvoid __iomem *pbase = instance->port_base;\n> +\n> +\tif (instance->efuse_intr)\n> +\t\tclrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_INTR_CAL,\n> +\t\t\t\tFIELD_PREP(P2A1_RG_INTR_CAL, instance->efuse_intr));\n> +\n> +\tif (instance->eye_src)\n> +\t\tclrsetbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL,\n> +\t\t\t\tFIELD_PREP(P2A5_RG_HSTX_SRCTRL, instance->eye_src));\n> +\n> +\tif (instance->eye_vrt)\n> +\t\tclrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_VRT_SEL,\n> +\t\t\t\tFIELD_PREP(P2A1_RG_VRT_SEL, instance->eye_vrt));\n> +\n> +\tif (instance->eye_term)\n> +\t\tclrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_TERM_SEL,\n> +\t\t\t\tFIELD_PREP(P2A1_RG_TERM_SEL, instance->eye_term));\n> +}\n> +\n> +static void mtk_xsphy_u3_props_set(struct mtk_xsphy *xsphy,\n> +\t\t\t\t   struct mtk_xsphy_instance *instance)\n> +{\n> +\tvoid __iomem *pbase = instance->port_base;\n> +\n> +\tif (instance->efuse_intr)\n> +\t\tclrsetbits_le32(xsphy->sif_base + SSPXTP_PHYA_GLB_00,\n> +\t\t\t\tRG_XTP_GLB_BIAS_INTR_CTRL,\n> +\t\t\t\tFIELD_PREP(RG_XTP_GLB_BIAS_INTR_CTRL, instance->efuse_intr));\n> +\n> +\tif (instance->efuse_tx_imp)\n> +\t\tclrsetbits_le32(pbase + SSPXTP_PHYA_LN_04, RG_XTP_LN0_TX_IMPSEL,\n> +\t\t\t\tFIELD_PREP(RG_XTP_LN0_TX_IMPSEL, instance->efuse_tx_imp));\n> +\n> +\tif (instance->efuse_rx_imp)\n> +\t\tclrsetbits_le32(pbase + SSPXTP_PHYA_LN_14, RG_XTP_LN0_RX_IMPSEL,\n> +\t\t\t\tFIELD_PREP(RG_XTP_LN0_RX_IMPSEL, instance->efuse_rx_imp));\n> +}\n> +\n> +/* type switch for usb3/pcie/sgmii */\n> +static int mtk_xsphy_type_syscon_get(struct udevice *dev,\n> +\t\t\t\t     struct mtk_xsphy_instance *instance,\n> +\t\t\t\t     ofnode dn)\n> +{\n> +\tstruct ofnode_phandle_args args;\n> +\tint ret;\n> +\n> +\tif (!ofnode_read_bool(dn, \"mediatek,syscon-type\"))\n> +\t\treturn 0;\n> +\n> +\tret = ofnode_parse_phandle_with_args(dn, \"mediatek,syscon-type\",\n> +\t\t\t\t\t     NULL, 2, 0, &args);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tinstance->type_sw_reg = args.args[0];\n> +\tinstance->type_sw_index = args.args[1] & 0x3; /* <=3 */\n> +\tinstance->type_sw = syscon_node_to_regmap(args.node);\n> +\tif (IS_ERR(instance->type_sw))\n> +\t\treturn PTR_ERR(instance->type_sw);\n> +\n> +\tdev_dbg(dev, \"phy-%s.%d: type_sw - reg %#x, index %d\\n\",\n> +\t\tdev->name, instance->index, instance->type_sw_reg,\n> +\t\tinstance->type_sw_index);\n> +\n> +\treturn 0;\n> +}\n> +\n> +static int mtk_xsphy_type_set(struct mtk_xsphy_instance *instance)\n> +{\n> +\tint type;\n> +\tu32 offset;\n> +\n> +\tif (!instance->type_sw)\n> +\t\treturn 0;\n> +\n> +\tswitch (instance->type) {\n> +\tcase PHY_TYPE_USB3:\n> +\t\ttype = RG_PHY_SW_USB3;\n> +\t\tbreak;\n> +\tcase PHY_TYPE_PCIE:\n> +\t\ttype = RG_PHY_SW_PCIE;\n> +\t\tbreak;\n> +\tcase PHY_TYPE_SGMII:\n> +\t\ttype = RG_PHY_SW_SGMII;\n> +\t\tbreak;\n> +\tcase PHY_TYPE_USB2:\n> +\tdefault:\n> +\t\treturn 0;\n> +\t}\n> +\n> +\toffset = instance->type_sw_index * BITS_PER_BYTE;\n> +\tregmap_update_bits(instance->type_sw, instance->type_sw_reg,\n> +\t\t\t   RG_PHY_SW_TYPE << offset, type << offset);\n> +\n> +\treturn 0;\n> +}\n> +\n> +static int mtk_xsphy_init(struct phy *phy)\n> +{\n> +\tstruct mtk_xsphy *xsphy = dev_get_priv(phy->dev);\n> +\tstruct mtk_xsphy_instance *instance = xsphy->phys[phy->id];\n> +\tint ret;\n> +\n> +\tret = clk_enable(&instance->ref_clk);\n> +\tif (ret) {\n> +\t\tdev_err(xsphy->dev, \"failed to enable ref_clk\\n\");\n> +\t\treturn ret;\n> +\t}\n> +\n> +\tswitch (instance->type) {\n> +\tcase PHY_TYPE_USB2:\n> +\t\tmtk_xsphy_u2_instance_init(xsphy, instance);\n> +\t\tmtk_xsphy_u2_props_set(xsphy, instance);\n> +\t\tbreak;\n> +\tcase PHY_TYPE_USB3:\n> +\t\tmtk_xsphy_u3_props_set(xsphy, instance);\n> +\t\tbreak;\n> +\tcase PHY_TYPE_PCIE:\n> +\tcase PHY_TYPE_SGMII:\n> +\t\t/* nothing to do, only used to set type */\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tdev_err(xsphy->dev, \"incompatible PHY type\\n\");\n> +\t\tclk_disable(&instance->ref_clk);\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +static int mtk_xsphy_power_on(struct phy *phy)\n> +{\n> +\tstruct mtk_xsphy *xsphy = dev_get_priv(phy->dev);\n> +\tstruct mtk_xsphy_instance *instance = xsphy->phys[phy->id];\n> +\n> +\tif (instance->type == PHY_TYPE_USB2) {\n> +\t\tmtk_xsphy_u2_instance_power_on(xsphy, instance);\n> +\t\tmtk_xsphy_u2_slew_rate_calibrate(xsphy, instance);\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +static int mtk_xsphy_power_off(struct phy *phy)\n> +{\n> +\tstruct mtk_xsphy *xsphy = dev_get_priv(phy->dev);\n> +\tstruct mtk_xsphy_instance *instance = xsphy->phys[phy->id];\n> +\n> +\tif (instance->type == PHY_TYPE_USB2)\n> +\t\tmtk_xsphy_u2_instance_power_off(xsphy, instance);\n> +\n> +\treturn 0;\n> +}\n> +\n> +static int mtk_xsphy_exit(struct phy *phy)\n> +{\n> +\tstruct mtk_xsphy *xsphy = dev_get_priv(phy->dev);\n> +\tstruct mtk_xsphy_instance *instance = xsphy->phys[phy->id];\n> +\n> +\tclk_disable(&instance->ref_clk);\n> +\n> +\treturn 0;\n> +}\n> +\n> +static int mtk_xsphy_set_mode(struct phy *phy, enum phy_mode mode, int submode)\n> +{\n> +\tstruct mtk_xsphy *xsphy = dev_get_priv(phy->dev);\n> +\tstruct mtk_xsphy_instance *instance = xsphy->phys[phy->id];\n> +\n> +\tif (instance->type == PHY_TYPE_USB2)\n> +\t\tmtk_xsphy_u2_instance_set_mode(xsphy, instance, mode);\n> +\n> +\treturn 0;\n> +}\n> +\n> +static int mtk_xsphy_xlate(struct phy *phy, struct ofnode_phandle_args *args)\n> +{\n> +\tstruct mtk_xsphy *xsphy = dev_get_priv(phy->dev);\n> +\tstruct mtk_xsphy_instance *instance = NULL;\n> +\tconst struct device_node *phy_np = ofnode_to_np(args->node);\n> +\tu32 index;\n> +\n> +\tif (!phy_np) {\n> +\t\tdev_err(phy->dev, \"null pointer phy node\\n\");\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tif (args->args_count != 2) {\n> +\t\tdev_err(phy->dev, \"invalid number of cells in 'phy' property\\n\");\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tfor (index = 0; index < xsphy->nphys; index++)\n> +\t\tif (phy_np == xsphy->phys[index]->np) {\n> +\t\t\tinstance = xsphy->phys[index];\n> +\t\t\tbreak;\n> +\t\t}\n> +\n> +\tif (!instance) {\n> +\t\tdev_err(phy->dev, \"failed to find appropriate phy\\n\");\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tphy->id = index;\n> +\tinstance->type = args->args[1];\n> +\tif (!(instance->type == PHY_TYPE_USB2 ||\n> +\t      instance->type == PHY_TYPE_USB3 ||\n> +\t      instance->type == PHY_TYPE_PCIE ||\n> +\t      instance->type == PHY_TYPE_SGMII)) {\n> +\t\tdev_err(phy->dev, \"unsupported PHY type\\n\");\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tmtk_xsphy_parse_property(xsphy, instance);\n> +\tmtk_xsphy_type_set(instance);\n> +\n> +\treturn 0;\n> +}\n> +\n> +static const struct phy_ops mtk_xsphy_ops = {\n> +\t.init\t\t= mtk_xsphy_init,\n> +\t.exit\t\t= mtk_xsphy_exit,\n> +\t.power_on\t= mtk_xsphy_power_on,\n> +\t.power_off\t= mtk_xsphy_power_off,\n> +\t.set_mode\t= mtk_xsphy_set_mode,\n> +\t.of_xlate\t= mtk_xsphy_xlate,\n> +};\n> +\n> +static int mtk_xsphy_probe(struct udevice *dev)\n> +{\n> +\tstruct mtk_xsphy *xsphy = dev_get_priv(dev);\n> +\tfdt_addr_t sif_addr;\n> +\tofnode subnode;\n> +\tint index = 0;\n> +\n> +\txsphy->nphys = dev_get_child_count(dev);\n> +\n> +\txsphy->phys = devm_kcalloc(dev, xsphy->nphys, sizeof(*xsphy->phys),\n> +\t\t\t\t   GFP_KERNEL);\n> +\tif (!xsphy->phys)\n> +\t\treturn -ENOMEM;\n> +\n> +\txsphy->dev = dev;\n> +\n> +\tsif_addr = ofnode_get_addr(dev_ofnode(dev));\n> +\t/* optional, may not exist if no u3 phys */\n> +\tif (sif_addr != FDT_ADDR_T_NONE)\n> +\t\txsphy->sif_base = map_sysmem(sif_addr, 0);\n> +\n> +\txsphy->src_ref_clk_mhz = XSP_REF_CLK_MHZ;\n> +\txsphy->src_coef = XSP_SLEW_RATE_COEF;\n> +\t/* update parameters of slew rate calibrate if exist */\n> +\tofnode_read_u32(dev_ofnode(dev), \"mediatek,src-ref-clk-mhz\",\n> +\t\t\t&xsphy->src_ref_clk_mhz);\n> +\tofnode_read_u32(dev_ofnode(dev), \"mediatek,src-coef\", &xsphy->src_coef);\n> +\n> +\tdev_for_each_subnode(subnode, dev) {\n> +\t\tstruct mtk_xsphy_instance *inst;\n> +\t\tfdt_addr_t addr;\n> +\t\tint ret;\n> +\n> +\t\tinst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL);\n> +\t\tif (!inst)\n> +\t\t\treturn -ENOMEM;\n> +\n> +\t\txsphy->phys[index] = inst;\n> +\n> +\t\taddr = ofnode_get_addr(subnode);\n> +\t\tif (addr == FDT_ADDR_T_NONE)\n> +\t\t\treturn -EADDRNOTAVAIL;\n> +\n> +\t\tinst->port_base = map_sysmem(addr, 0);\n> +\t\tinst->index = index;\n> +\t\tinst->np = ofnode_to_np(subnode);\n> +\n> +\t\tret = clk_get_by_name_nodev(subnode, \"ref\", &inst->ref_clk);\n> +\t\tif (ret) {\n> +\t\t\tdev_err(dev, \"failed to get ref_clk(id-%d)\\n\", index);\n> +\t\t\treturn ret;\n> +\t\t}\n> +\n> +\t\tret = mtk_xsphy_type_syscon_get(dev, inst, subnode);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\n> +\t\tindex++;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +static const struct udevice_id mtk_xsphy_id_table[] = {\n> +\t{ .compatible = \"mediatek,xsphy\" },\n> +\t{ }\n> +};\n> +\n> +U_BOOT_DRIVER(mtk_xsphy) = {\n> +\t.name\t\t= \"mtk-xsphy\",\n> +\t.id\t\t= UCLASS_PHY,\n> +\t.of_match\t= mtk_xsphy_id_table,\n> +\t.ops\t\t= &mtk_xsphy_ops,\n> +\t.probe\t\t= mtk_xsphy_probe,\n> +\t.priv_auto\t= sizeof(struct mtk_xsphy),\n> +};\n> \n\nI came up with a (very) similar driver for this phy, too bad for the \nduplicated work. Anyway, successfully tested on Genio Pro and even a bit \nbetter than my own version, so feel free to add\n\nReviewed-by: Arnaud Ferraris <arnaud.ferraris@collabora.com>\n\nRegards,\nArnaud","headers":{"Return-Path":"<u-boot-bounces@lists.denx.de>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=collabora.com header.i=@collabora.com\n header.a=rsa-sha256 header.s=mail header.b=ecUxBd/u;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=85.214.62.61; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org)","phobos.denx.de;\n dmarc=pass (p=none dis=none) header.from=collabora.com","phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de","phobos.denx.de;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=collabora.com header.i=@collabora.com\n header.b=\"ecUxBd/u\";\n\tdkim-atps=neutral","phobos.denx.de;\n dmarc=pass (p=none dis=none) header.from=collabora.com","phobos.denx.de;\n spf=pass smtp.mailfrom=arnaud.ferraris@collabora.com"],"Received":["from phobos.denx.de (phobos.denx.de [85.214.62.61])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fxzj90xj8z1yD3\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 18 Apr 2026 01:45:01 +1000 (AEST)","from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id D90B284258;\n\tFri, 17 Apr 2026 17:44:55 +0200 (CEST)","by phobos.denx.de (Postfix, from userid 109)\n id E40D384286; Fri, 17 Apr 2026 17:44:53 +0200 (CEST)","from bali.collaboradmins.com (bali.collaboradmins.com\n [IPv6:2a01:4f8:201:9162::2])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id 3FF6384246\n for <u-boot@lists.denx.de>; Fri, 17 Apr 2026 17:44:51 +0200 (CEST)","from [100.64.1.83] (unknown [100.64.1.83])\n (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)\n key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest\n SHA256)\n (No client certificate requested) (Authenticated sender: aferraris)\n by bali.collaboradmins.com (Postfix) with ESMTPSA id 3F47117E1317;\n Fri, 17 Apr 2026 17:44:50 +0200 (CEST)"],"X-Spam-Checker-Version":"SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de","X-Spam-Level":"","X-Spam-Status":"No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED,\n SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com;\n s=mail; t=1776440690;\n bh=VIqQ4w8hO5+TeBIodSY3jMWkZ0QZFwa+5IaoQtdCTk8=;\n h=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n b=ecUxBd/u7822kCt3oak2hItGYzALDXFvmvALediM9igyXXWu2MUT58dL06rbMGU28\n 5WonLEM3kNpm1xlsf5KJFX1g0tWdIHUqGVTN+to31fUNzj2ftdoHvBH2tePm15iNHY\n xut8DUDhknXviyDQmhT1PobXlR2/ofDlssNpTXizuLXRl0iRjX5hyk8fsLJa1d+0CK\n OvwmU8j3L2mytJNkO5CD6aqtfUAL6LVElAj+ZAlZA4cC4N50zh2DFh94ULDO9c0Bgf\n CTDymyz27JjlP20AJDr4GaRsDFsiuRDb0OWcjPAJbHTML1gZmmFLwyxnRmJcqqplb5\n tQWRz9BLGCqZA==","Message-ID":"<61e06e0d-0968-491d-90df-86a69f3c5978@collabora.com>","Date":"Fri, 17 Apr 2026 17:44:49 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH 1/3] phy: mediatek: new XS-PHY driver","To":"David Lechner <dlechner@baylibre.com>, Tom Rini <trini@konsulko.com>,\n Ryder Lee <ryder.lee@mediatek.com>, Weijie Gao <weijie.gao@mediatek.com>,\n Chunfeng Yun <chunfeng.yun@mediatek.com>,\n Igor Belwon <igor.belwon@mentallysanemainliners.org>,\n GSS_MTK_Uboot_upstream <GSS_MTK_Uboot_upstream@mediatek.com>,\n Macpaul Lin <macpaul.lin@mediatek.com>","Cc":"Julien Stephan <jstephan@baylibre.com>, u-boot@lists.denx.de","References":"<20260401-mtk-mt8189-usb-v1-0-a4bf951aa8ad@baylibre.com>\n <20260401-mtk-mt8189-usb-v1-1-a4bf951aa8ad@baylibre.com>","From":"Arnaud Ferraris <arnaud.ferraris@collabora.com>","Content-Language":"en-US, fr","Autocrypt":"addr=arnaud.ferraris@collabora.com; keydata=\n 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\n L9jD4jU=","In-Reply-To":"<20260401-mtk-mt8189-usb-v1-1-a4bf951aa8ad@baylibre.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"u-boot@lists.denx.de","X-Mailman-Version":"2.1.39","Precedence":"list","List-Id":"U-Boot discussion <u-boot.lists.denx.de>","List-Unsubscribe":"<https://lists.denx.de/options/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>","List-Archive":"<https://lists.denx.de/pipermail/u-boot/>","List-Post":"<mailto:u-boot@lists.denx.de>","List-Help":"<mailto:u-boot-request@lists.denx.de?subject=help>","List-Subscribe":"<https://lists.denx.de/listinfo/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=subscribe>","Errors-To":"u-boot-bounces@lists.denx.de","Sender":"\"U-Boot\" <u-boot-bounces@lists.denx.de>","X-Virus-Scanned":"clamav-milter 0.103.8 at phobos.denx.de","X-Virus-Status":"Clean"}}]