From 080b4f099558212703a772d3ca74c0521cf5a7e8 Mon Sep 17 00:00:00 2001 From: Padmarao Begari Date: Wed, 26 Nov 2025 16:06:41 +0100 Subject: ufs: Disable UTP command timeout in slow mode When the UFS controller is operating in slow (PWM) mode, the driver is disabled the timeout for UTP send commands. In high-speed mode, the timeout remains enabled to detect stalled or failed transfers. This change ensures reliable operation in slow mode, where command completion may take longer and timeouts are not required. Signed-off-by: Padmarao Begari Signed-off-by: Michal Simek Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/e6deb9086afab9d2bdd53db8ecbc7db93af5204d.1764169598.git.michal.simek@amd.com Signed-off-by: Neil Armstrong --- drivers/ufs/ufs-uclass.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c index 3c8e4299259..7a80a9d5664 100644 --- a/drivers/ufs/ufs-uclass.c +++ b/drivers/ufs/ufs-uclass.c @@ -917,11 +917,13 @@ static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) enabled_intr_status = intr_status & hba->intr_mask; ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS); - if (get_timer(start) > QUERY_REQ_TIMEOUT) { - dev_err(hba->dev, - "Timedout waiting for UTP response\n"); - - return -ETIMEDOUT; + if (hba->max_pwr_info.info.pwr_rx != SLOWAUTO_MODE && + hba->max_pwr_info.info.pwr_tx != SLOWAUTO_MODE) { + if (get_timer(start) > QUERY_REQ_TIMEOUT) { + dev_err(hba->dev, + "Timedout waiting for UTP response\n"); + return -ETIMEDOUT; + } } if (enabled_intr_status & UFSHCD_ERROR_MASK) { -- cgit v1.2.3 From 25f142543196e5b5f0f9c916f15671dcd26eb2f7 Mon Sep 17 00:00:00 2001 From: Igor Belwon Date: Sat, 11 Oct 2025 21:10:04 +0200 Subject: phy: Add MediaTek UFS PHY Driver This UFS M-PHY driver can be used on recent MediaTek SoCs as the primary PHY for the UFS controller. Signed-off-by: Igor Belwon Link: https://patch.msgid.link/20251011-mtk-ufs-uboot-v1-1-a05f991ee150@mentallysanemainliners.org Signed-off-by: Neil Armstrong --- drivers/phy/Kconfig | 10 +++ drivers/phy/Makefile | 1 + drivers/phy/phy-mtk-ufs.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 drivers/phy/phy-mtk-ufs.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 87729b479bd..09810b62b51 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -282,6 +282,16 @@ config PHY_MTK_TPHY multi-ports is first version, otherwise is second veriosn, so you can easily distinguish them by banks layout. +config PHY_MTK_UFS + tristate "MediaTek UFS M-PHY driver" + depends on ARCH_MEDIATEK + depends on PHY + help + Support for UFS M-PHY on MediaTek chipsets. + Enable this to provide vendor-specific probing, + initialization, power on and power off flow of + specified M-PHYs. + config PHY_NPCM_USB bool "Nuvoton NPCM USB PHY support" depends on PHY diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 5a6df0ecfeb..83102349669 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_MT76X8_USB_PHY) += mt76x8-usb-phy.o obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o obj-$(CONFIG_PHY_EXYNOS_USBDRD) += phy-exynos-usbdrd.o obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o +obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o obj-$(CONFIG_$(PHASE_)PHY_IMX8MQ_USB) += phy-imx8mq-usb.o obj-$(CONFIG_PHY_IMX8M_PCIE) += phy-imx8m-pcie.o diff --git a/drivers/phy/phy-mtk-ufs.c b/drivers/phy/phy-mtk-ufs.c new file mode 100644 index 00000000000..1eda3df858d --- /dev/null +++ b/drivers/phy/phy-mtk-ufs.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 MediaTek Inc. + * Author: Stanley Chu + * + * Copyright (c) 2025, Igor Belwon + */ + +#include "dm/ofnode.h" +#include "dm/read.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* mphy register and offsets */ +#define MP_GLB_DIG_8C 0x008C +#define FRC_PLL_ISO_EN BIT(8) +#define PLL_ISO_EN BIT(9) +#define FRC_FRC_PWR_ON BIT(10) +#define PLL_PWR_ON BIT(11) + +#define MP_LN_DIG_RX_9C 0xA09C +#define FSM_DIFZ_FRC BIT(18) + +#define MP_LN_DIG_RX_AC 0xA0AC +#define FRC_RX_SQ_EN BIT(0) +#define RX_SQ_EN BIT(1) + +#define MP_LN_RX_44 0xB044 +#define FRC_CDR_PWR_ON BIT(17) +#define CDR_PWR_ON BIT(18) +#define FRC_CDR_ISO_EN BIT(19) +#define CDR_ISO_EN BIT(20) + +#define UFSPHY_CLKS_CNT 2 + +struct mtk_ufs_phy { + struct udevice *dev; + void __iomem *mmio; + + struct clk *unipro_clk; + struct clk *mp_clk; +}; + +static void ufs_mtk_phy_set_active(struct mtk_ufs_phy *phy) +{ + /* release DA_MP_PLL_PWR_ON */ + setbits_le32(phy->mmio + MP_GLB_DIG_8C, PLL_PWR_ON); + clrbits_le32(phy->mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON); + + /* release DA_MP_PLL_ISO_EN */ + clrbits_le32(phy->mmio + MP_GLB_DIG_8C, PLL_ISO_EN); + clrbits_le32(phy->mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN); + + /* release DA_MP_CDR_PWR_ON */ + setbits_le32(phy->mmio + MP_LN_RX_44, CDR_PWR_ON); + clrbits_le32(phy->mmio + MP_LN_RX_44, FRC_CDR_PWR_ON); + + /* release DA_MP_CDR_ISO_EN */ + clrbits_le32(phy->mmio + MP_LN_RX_44, CDR_ISO_EN); + clrbits_le32(phy->mmio + MP_LN_RX_44, FRC_CDR_ISO_EN); + + /* release DA_MP_RX0_SQ_EN */ + setbits_le32(phy->mmio + MP_LN_DIG_RX_AC, RX_SQ_EN); + clrbits_le32(phy->mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); + + /* delay 1us to wait DIFZ stable */ + udelay(1); + + /* release DIFZ */ + clrbits_le32(phy->mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); +} + +static int mtk_phy_power_on(struct phy *phy) +{ + struct mtk_ufs_phy *ufs_phy = dev_get_priv(phy->dev); + int ret; + + ret = clk_enable(ufs_phy->mp_clk); + if (ret < 0) { + dev_err(phy->dev, "failed to enable mp_clk\n"); + return ret; + } + + ret = clk_enable(ufs_phy->unipro_clk); + if (ret < 0) { + dev_err(phy->dev, "failed to enable unipro_clk %d\n", ret); + clk_disable(ufs_phy->unipro_clk); + return ret; + } + + ufs_mtk_phy_set_active(ufs_phy); + + return 0; +} + +static int mtk_phy_power_off(struct phy *phy) +{ + struct mtk_ufs_phy *ufs_phy = dev_get_priv(phy->dev); + + /* Set PHY to Deep Hibernate mode */ + setbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); + + /* force DA_MP_RX0_SQ_EN */ + setbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); + clrbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_AC, RX_SQ_EN); + + /* force DA_MP_CDR_ISO_EN */ + setbits_le32(ufs_phy->mmio + MP_LN_RX_44, FRC_CDR_ISO_EN); + setbits_le32(ufs_phy->mmio + MP_LN_RX_44, CDR_ISO_EN); + + /* force DA_MP_CDR_PWR_ON */ + setbits_le32(ufs_phy->mmio + MP_LN_RX_44, FRC_CDR_PWR_ON); + clrbits_le32(ufs_phy->mmio + MP_LN_RX_44, CDR_PWR_ON); + + /* force DA_MP_PLL_ISO_EN */ + setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN); + setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, PLL_ISO_EN); + + /* force DA_MP_PLL_PWR_ON */ + setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON); + clrbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, PLL_PWR_ON); + + return 0; +} + +static const struct phy_ops mtk_ufs_phy_ops = { + .power_on = mtk_phy_power_on, + .power_off = mtk_phy_power_off, +}; + +static int mtk_ufs_phy_probe(struct udevice *dev) +{ + struct mtk_ufs_phy *phy = dev_get_priv(dev); + fdt_addr_t addr; + int ret; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -ENOMEM; + + phy->dev = dev; + phy->mmio = map_sysmem(addr, 0); + + phy->mp_clk = devm_clk_get(dev, "mp"); + if (IS_ERR(phy->mp_clk)) { + ret = PTR_ERR(phy->mp_clk); + dev_err(dev, "Failed to get mp clock (ret=%d)\n", ret); + return ret; + } + + phy->unipro_clk = devm_clk_get(dev, "unipro"); + if (IS_ERR(phy->unipro_clk)) { + ret = PTR_ERR(phy->unipro_clk); + dev_err(dev, "Failed to get unipro clock (ret=%d)\n", ret); + return ret; + } + + return 0; +} + +static const struct udevice_id mtk_ufs_phy_id_table[] = { + {.compatible = "mediatek,mt8183-ufsphy"}, + {}, +}; + +U_BOOT_DRIVER(mtk_ufs_phy) = { + .name = "mtk-ufs_phy", + .id = UCLASS_PHY, + .of_match = mtk_ufs_phy_id_table, + .ops = &mtk_ufs_phy_ops, + .probe = mtk_ufs_phy_probe, + .priv_auto = sizeof(struct mtk_ufs_phy), +}; -- cgit v1.2.3 From 47905f28468e3524cb5f775f52928cdcc568815a Mon Sep 17 00:00:00 2001 From: Julien Stephan Date: Tue, 3 Feb 2026 10:21:26 +0100 Subject: drivers: ufs: remove unused ufs_post_bind() declaration Commit 067c1b033282 ("ufs: Call ufs_scsi_bind() from uclass .post_bind") inlined ufs_scsi_bind() into ufs_post_bind() as trivial device_bind_driver() call. ufs_scsi_bind() is no longer referenced anywhere in the codebase, so drop its declaration from include/ufs.h. Drivers used to include to include prototype of ufs_scsi_bind() function, so we can now safely remove such includes. Fixes: 067c1b033282 ("ufs: Call ufs_scsi_bind() from uclass .post_bind") Signed-off-by: Julien Stephan Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20260203-cleanup-ufs-header-v1-1-4c10424485f0@baylibre.com Signed-off-by: Neil Armstrong --- drivers/ufs/cdns-platform.c | 1 - drivers/ufs/ufs-amd-versal2.c | 1 - drivers/ufs/ufs-pci.c | 1 - drivers/ufs/ufs-qcom.c | 1 - drivers/ufs/ufs-renesas-rcar-gen5.c | 1 - drivers/ufs/ufs-renesas.c | 1 - drivers/ufs/ufs-rockchip.c | 1 - drivers/ufs/ufshcd-dwc.c | 1 - include/ufs.h | 9 --------- 9 files changed, 17 deletions(-) diff --git a/drivers/ufs/cdns-platform.c b/drivers/ufs/cdns-platform.c index 87d9c5bad79..40883a187b0 100644 --- a/drivers/ufs/cdns-platform.c +++ b/drivers/ufs/cdns-platform.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c index dd62c9819ba..6c949b2ca76 100644 --- a/drivers/ufs/ufs-amd-versal2.c +++ b/drivers/ufs/ufs-amd-versal2.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/ufs/ufs-pci.c b/drivers/ufs/ufs-pci.c index 5b9c72a695d..e1e010d027c 100644 --- a/drivers/ufs/ufs-pci.c +++ b/drivers/ufs/ufs-pci.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include "ufs.h" diff --git a/drivers/ufs/ufs-qcom.c b/drivers/ufs/ufs-qcom.c index ee43958d5d8..dc40ee62daf 100644 --- a/drivers/ufs/ufs-qcom.c +++ b/drivers/ufs/ufs-qcom.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/ufs/ufs-renesas-rcar-gen5.c b/drivers/ufs/ufs-renesas-rcar-gen5.c index cc53e91449c..a21ae3f390e 100644 --- a/drivers/ufs/ufs-renesas-rcar-gen5.c +++ b/drivers/ufs/ufs-renesas-rcar-gen5.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/ufs/ufs-renesas.c b/drivers/ufs/ufs-renesas.c index 5652309911e..a206e3c6d58 100644 --- a/drivers/ufs/ufs-renesas.c +++ b/drivers/ufs/ufs-renesas.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/ufs/ufs-rockchip.c b/drivers/ufs/ufs-rockchip.c index 0384244387d..643a6ffb9bc 100644 --- a/drivers/ufs/ufs-rockchip.c +++ b/drivers/ufs/ufs-rockchip.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "ufs.h" #include "unipro.h" diff --git a/drivers/ufs/ufshcd-dwc.c b/drivers/ufs/ufshcd-dwc.c index 3f62e59a060..98422d742a0 100644 --- a/drivers/ufs/ufshcd-dwc.c +++ b/drivers/ufs/ufshcd-dwc.c @@ -7,7 +7,6 @@ */ #include #include -#include #include #include #include diff --git a/include/ufs.h b/include/ufs.h index 702b8359dbd..f6e27d90e43 100644 --- a/include/ufs.h +++ b/include/ufs.h @@ -20,13 +20,4 @@ int ufs_probe(void); */ int ufs_probe_dev(int index); -/* - * ufs_scsi_bind() - Create a new scsi device as a child of the UFS device and - * bind it to the ufs_scsi driver - * @ufs_dev: UFS device - * @scsi_devp: Pointer to scsi device - * - * Return: 0 if Ok, -ve on error - */ -int ufs_scsi_bind(struct udevice *ufs_dev, struct udevice **scsi_devp); #endif -- cgit v1.2.3