From 0bb1d511e4f5deb4e8426ba2c8fc8f4859999341 Mon Sep 17 00:00:00 2001 From: Julien Stephan Date: Thu, 5 Mar 2026 09:49:02 +0100 Subject: [PATCH 1/5] drivers: ufs: handle return values of ufs_hba_ops callbacks The return values of ufshcd_ops_link_startup_notify(), ufshcd_ops_hce_enable_notify(), ufshcd_ops_init(), and ufshcd_device_reset() are currently ignored. Check and propagate these return values properly and emit appropriate error messages on error. While at it, remove the ufshcd_device_reset() wrapper, which just call ufshcd_device_reset(). Signed-off-by: Julien Stephan Reviewed-by: Macpaul Lin Link: https://patch.msgid.link/20260305-ufs-ufs_hba_ops-cleanup-v3-1-e153ffab98f5@baylibre.com Signed-off-by: Neil Armstrong --- drivers/ufs/ufs-uclass.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c index 3c8e4299259..c09f61aa420 100644 --- a/drivers/ufs/ufs-uclass.c +++ b/drivers/ufs/ufs-uclass.c @@ -127,11 +127,6 @@ static void ufshcd_print_pwr_info(struct ufs_hba *hba) hba->pwr_info.hs_rate); } -static void ufshcd_device_reset(struct ufs_hba *hba) -{ - ufshcd_vops_device_reset(hba); -} - /** * ufshcd_ready_for_uic_cmd - Check if controller is ready * to accept UIC commands @@ -512,7 +507,9 @@ static int ufshcd_link_startup(struct ufs_hba *hba) int retries = DME_LINKSTARTUP_RETRIES; do { - ufshcd_ops_link_startup_notify(hba, PRE_CHANGE); + ret = ufshcd_ops_link_startup_notify(hba, PRE_CHANGE); + if (ret) + goto out; ret = ufshcd_dme_link_startup(hba); @@ -598,12 +595,18 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba) static int ufshcd_hba_enable(struct ufs_hba *hba) { int retry; + int ret; if (!ufshcd_is_hba_active(hba)) /* change controller state to "reset state" */ ufshcd_hba_stop(hba); - ufshcd_ops_hce_enable_notify(hba, PRE_CHANGE); + ret = ufshcd_ops_hce_enable_notify(hba, PRE_CHANGE); + if (ret) { + dev_err(hba->dev, "Controller enable notify PRE_CHANGE failed: %i\n", + ret); + return ret; + } /* start controller initialization sequence */ ufshcd_hba_start(hba); @@ -635,7 +638,12 @@ static int ufshcd_hba_enable(struct ufs_hba *hba) /* enable UIC related interrupts */ ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); - ufshcd_ops_hce_enable_notify(hba, POST_CHANGE); + ret = ufshcd_ops_hce_enable_notify(hba, POST_CHANGE); + if (ret) { + dev_err(hba->dev, "Controller enable notify POST_CHANGE failed: %i\n", + ret); + return ret; + } return 0; } @@ -2182,7 +2190,11 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) /* Set descriptor lengths to specification defaults */ ufshcd_def_desc_sizes(hba); - ufshcd_ops_init(hba); + err = ufshcd_ops_init(hba); + if (err) { + dev_err(hba->dev, "Host controller init failed: %i\n", err); + return err; + } /* Read capabilities registers */ hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES); @@ -2226,7 +2238,11 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) mb(); /* flush previous writes */ /* Reset the attached device */ - ufshcd_device_reset(hba); + err = ufshcd_vops_device_reset(hba); + if (err) { + dev_err(hba->dev, "Failed to reset attached device: %i\n", err); + return err; + } err = ufshcd_hba_enable(hba); if (err) { From aa1b3f2583f14d2ecf7d5c455f1500790e3bcdf2 Mon Sep 17 00:00:00 2001 From: Julien Stephan Date: Thu, 5 Mar 2026 09:49:03 +0100 Subject: [PATCH 2/5] drivers: ufs: add helper for phy_initialization callback Introduce ufshcd_ops_phy_initialization() as a helper for invoking the phy_initialization callback from ufs_hba_ops. This mirrors the existing helper pattern used for other ufs_hba_ops callbacks and keeps the call sites consistent and easier to maintain. Signed-off-by: Julien Stephan Link: https://patch.msgid.link/20260305-ufs-ufs_hba_ops-cleanup-v3-2-e153ffab98f5@baylibre.com Signed-off-by: Neil Armstrong --- drivers/ufs/ufs-rockchip.c | 9 +++------ drivers/ufs/ufs.h | 8 ++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/ufs/ufs-rockchip.c b/drivers/ufs/ufs-rockchip.c index 0384244387d..8ce3c269cf7 100644 --- a/drivers/ufs/ufs-rockchip.c +++ b/drivers/ufs/ufs-rockchip.c @@ -30,12 +30,9 @@ static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba, ufshcd_dme_reset(hba); ufshcd_dme_enable(hba); - if (hba->ops->phy_initialization) { - err = hba->ops->phy_initialization(hba); - if (err) - dev_err(hba->dev, - "Phy init failed (%d)\n", err); - } + err = ufshcd_ops_phy_initialization(hba); + if (err) + dev_err(hba->dev, "Phy init failed (%d)\n", err); return err; } diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index bc839a43704..74125b1ab31 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -756,6 +756,14 @@ static inline int ufshcd_ops_link_startup_notify(struct ufs_hba *hba, return 0; } +static inline int ufshcd_ops_phy_initialization(struct ufs_hba *hba) +{ + if (hba->ops && hba->ops->phy_initialization) + return hba->ops->phy_initialization(hba); + + return 0; +} + static inline int ufshcd_vops_device_reset(struct ufs_hba *hba) { if (hba->ops && hba->ops->device_reset) From d908dd98de5c335a213d882746d033158db02cce Mon Sep 17 00:00:00 2001 From: Julien Stephan Date: Thu, 5 Mar 2026 09:49:04 +0100 Subject: [PATCH 3/5] drivers: ufs: fix typo in struct ufs_dev_cmd kernel-doc Fix "associated" typo in struct ufs_dev_cmd kernel-doc. Signed-off-by: Julien Stephan Reviewed-by: Macpaul Lin Link: https://patch.msgid.link/20260305-ufs-ufs_hba_ops-cleanup-v3-3-e153ffab98f5@baylibre.com Signed-off-by: Neil Armstrong --- drivers/ufs/ufs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 74125b1ab31..0f6c93fbce7 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -509,7 +509,7 @@ struct ufs_query { }; /** - * struct ufs_dev_cmd - all assosiated fields with device management commands + * struct ufs_dev_cmd - all associated fields with device management commands * @type: device management command type - Query, NOP OUT * @tag_wq: wait queue until free command slot is available */ From c664b4d5f30a704003b97823a5ad6361cb16fbe8 Mon Sep 17 00:00:00 2001 From: Alexey Charkov Date: Tue, 20 Jan 2026 22:09:02 +0400 Subject: [PATCH 4/5] spl: Make UFS available for SPL builds Add minimal infrastructure to build SPL images with support for UFS storage devices. This also pulls in SCSI support and charset functions, which are dependencies of the UFS code. With this, only a fixed offset is supported for loading the next image, which should be specified in CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR as the number of 4096-byte sectors into the UFS block device. Reviewed-by: Neil Armstrong Signed-off-by: Alexey Charkov Link: https://patch.msgid.link/20260120-rk3576-ufs-v5-1-0edb61b301b7@gmail.com Signed-off-by: Neil Armstrong --- MAINTAINERS | 1 + arch/arm/include/asm/spl.h | 1 + common/spl/Kconfig | 30 +++++++++++++++++++++++ common/spl/Makefile | 1 + common/spl/spl_ufs.c | 49 ++++++++++++++++++++++++++++++++++++++ drivers/Makefile | 1 + drivers/scsi/Makefile | 3 +++ lib/Makefile | 1 + 8 files changed, 87 insertions(+) create mode 100644 common/spl/spl_ufs.c diff --git a/MAINTAINERS b/MAINTAINERS index 00cb03fe592..e62ef15b5a9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1893,6 +1893,7 @@ M: Neil Armstrong M: Bhupesh Sharma M: Neha Malcom Francis S: Maintained +F: common/spl/spl_ufs.c F: drivers/ufs/ UPL diff --git a/arch/arm/include/asm/spl.h b/arch/arm/include/asm/spl.h index ee79a19c05c..dd462ea6ad8 100644 --- a/arch/arm/include/asm/spl.h +++ b/arch/arm/include/asm/spl.h @@ -30,6 +30,7 @@ enum { BOOT_DEVICE_XIP, BOOT_DEVICE_BOOTROM, BOOT_DEVICE_SMH, + BOOT_DEVICE_UFS, BOOT_DEVICE_NONE }; #endif diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 996c9b8db4f..dafc0cb91bd 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -1613,6 +1613,36 @@ config SPL_THERMAL automatic power-off when the temperature gets too high or low. Other devices may be discrete but connected on a suitable bus. +config SPL_UFS_SUPPORT + bool "Support loading from UFS" + depends on UFS + select SPL_LOAD_BLOCK + help + Enable support for UFS in SPL. This allows + use of UFS devices such as hard drives and flash drivers for + loading U-Boot. + +config SPL_UFS_RAW_U_BOOT_DEVNUM + int "SCSI device number of the UFS device to load U-Boot from" + depends on SPL_UFS_SUPPORT + default 0 + help + UFS devices are usually configured with multiple LUNs, which present + themselves as sequentially numbered SCSI devices. Usually one would + get a default LUN 0 taking up most of the space on the device, with + a number of smaller LUNs following it. This option controls which of + them the SPL will attempt to load U-Boot from. Note that this is the + SCSI device number, which might differ from the UFS LUN if you have + multiple SCSI devices attached and recognized by the SPL. + +config SPL_UFS_RAW_U_BOOT_SECTOR + hex "Address on the UFS to load U-Boot from" + depends on SPL_UFS_SUPPORT + default 0x800 if ARCH_ROCKCHIP + help + Address on the block device to load U-Boot from. + Units: UFS sectors (1 sector = 4096 bytes). + config SPL_WATCHDOG bool "Support watchdog drivers" imply SPL_WDT if !HW_WATCHDOG diff --git a/common/spl/Makefile b/common/spl/Makefile index 4c9482bd309..e18f3cf0948 100644 --- a/common/spl/Makefile +++ b/common/spl/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_$(PHASE_)DFU) += spl_dfu.o obj-$(CONFIG_$(PHASE_)SPI_LOAD) += spl_spi.o obj-$(CONFIG_$(PHASE_)RAM_SUPPORT) += spl_ram.o obj-$(CONFIG_$(PHASE_)USB_SDP_SUPPORT) += spl_sdp.o +obj-$(CONFIG_$(PHASE_)UFS_SUPPORT) += spl_ufs.o endif obj-$(CONFIG_$(PHASE_)UPL) += spl_upl.o diff --git a/common/spl/spl_ufs.c b/common/spl/spl_ufs.c new file mode 100644 index 00000000000..cef1843f40f --- /dev/null +++ b/common/spl/spl_ufs.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2025 Alexey Charkov + */ + +#include +#include +#include +#include +#include +#include +#include + +static ulong spl_ufs_load_read(struct spl_load_info *load, ulong off, ulong size, void *buf) +{ + struct blk_desc *bd = load->priv; + lbaint_t sector = off >> bd->log2blksz; + lbaint_t count = size >> bd->log2blksz; + + return blk_dread(bd, sector, count, buf) << bd->log2blksz; +} + +static int spl_ufs_load_image(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev) +{ + unsigned long sector = CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR; + int devnum = CONFIG_SPL_UFS_RAW_U_BOOT_DEVNUM; + struct spl_load_info load; + struct blk_desc *bd; + int err; + + /* try to recognize storage devices immediately */ + scsi_scan(false); + bd = blk_get_devnum_by_uclass_id(UCLASS_SCSI, devnum); + if (!bd) + return -ENODEV; + + spl_load_init(&load, spl_ufs_load_read, bd, bd->blksz); + err = spl_load(spl_image, bootdev, &load, 0, sector << bd->log2blksz); + if (err) { + puts("spl_ufs_load_image: ufs block read error\n"); + log_debug("(error=%d)\n", err); + return err; + } + + return 0; +} + +SPL_LOAD_IMAGE_METHOD("UFS", 0, BOOT_DEVICE_UFS, spl_ufs_load_image); diff --git a/drivers/Makefile b/drivers/Makefile index de993ae42ac..43d0ba33281 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_SPL_USB_HOST) += usb/host/ obj-$(CONFIG_SPL_SATA) += ata/ scsi/ obj-$(CONFIG_SPL_LEGACY_BLOCK) += block/ obj-$(CONFIG_SPL_THERMAL) += thermal/ +obj-$(CONFIG_SPL_UFS_SUPPORT) += scsi/ ufs/ endif endif diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index b76de1b22a8..c9af60d5d03 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -16,4 +16,7 @@ ifdef CONFIG_XPL_BUILD ifdef CONFIG_SPL_SATA obj-$(CONFIG_SCSI) += scsi.o scsi-uclass.o endif +ifdef CONFIG_SPL_UFS_SUPPORT +obj-$(CONFIG_SCSI) += scsi.o scsi-uclass.o +endif endif diff --git a/lib/Makefile b/lib/Makefile index 70667f3728c..d0ffabc2b47 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -147,6 +147,7 @@ else obj-$(CONFIG_$(PHASE_)SPRINTF) += vsprintf.o endif obj-$(CONFIG_$(PHASE_)STRTO) += strto.o +obj-$(CONFIG_$(PHASE_)UFS_SUPPORT) += charset.o else # Main U-Boot always uses the full printf support obj-y += vsprintf.o strto.o From 67d8731d4aad25be00e27eeef3602c519619405e Mon Sep 17 00:00:00 2001 From: Alexey Charkov Date: Tue, 20 Jan 2026 22:09:04 +0400 Subject: [PATCH 5/5] ufs: rockchip: Add device reset support Wire up the GPIO line which Rockchip RK3576 UFS controller uses to reset the connected UFS device. This seems necessary at least for some UFS modules and fixes the following error while enumerating UFS storage: ufshcd-rockchip ufshc@2a2d0000: ufshcd_link_startup: Device not present ufshcd-rockchip ufshc@2a2d0000: link startup failed -6 ufshcd-rockchip ufshc@2a2d0000: ufshcd_pltfrm_init() failed -6 Note that the GPIO descriptor for device resets is already required by the DT binding (link enclosed). Link: https://elixir.bootlin.com/linux/v6.18.5/source/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml#L70 Fixes: 76465ce21ee4 ("ufs: rockchip: Add initial support") Reviewed-by: Neil Armstrong Reviewed-by: Shawn Lin Signed-off-by: Alexey Charkov Link: https://patch.msgid.link/20260120-rk3576-ufs-v5-3-0edb61b301b7@gmail.com Signed-off-by: Neil Armstrong --- drivers/ufs/Kconfig | 4 ++++ drivers/ufs/ufs-rockchip.c | 22 ++++++++++++++++++++++ drivers/ufs/ufs-rockchip.h | 1 + 3 files changed, 27 insertions(+) diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig index 6c75bb2a079..49472933de3 100644 --- a/drivers/ufs/Kconfig +++ b/drivers/ufs/Kconfig @@ -76,6 +76,10 @@ config UFS_RENESAS_GEN5 config UFS_ROCKCHIP bool "Rockchip specific hooks to UFS controller platform driver" depends on UFS + depends on DM_GPIO + depends on RESET_ROCKCHIP + depends on SPL_DM_GPIO || !SPL_UFS_SUPPORT + depends on SPL_RESET_ROCKCHIP || !SPL_UFS_SUPPORT help This selects the Rockchip specific additions to UFSHCD platform driver. diff --git a/drivers/ufs/ufs-rockchip.c b/drivers/ufs/ufs-rockchip.c index 8ce3c269cf7..d799710453e 100644 --- a/drivers/ufs/ufs-rockchip.c +++ b/drivers/ufs/ufs-rockchip.c @@ -5,6 +5,7 @@ * Copyright (C) 2025 Rockchip Electronics Co.Ltd. */ +#include #include #include #include @@ -150,11 +151,31 @@ static int ufs_rockchip_common_init(struct ufs_hba *hba) return err; } + err = gpio_request_by_name(dev, "reset-gpios", 0, &host->device_reset, + GPIOD_IS_OUT | GPIOD_ACTIVE_LOW); + if (err) { + dev_err(dev, "Cannot get reset GPIO\n"); + return err; + } + host->hba = hba; return 0; } +static int ufs_rockchip_device_reset(struct ufs_hba *hba) +{ + struct ufs_rockchip_host *host = dev_get_priv(hba->dev); + + dm_gpio_set_value(&host->device_reset, true); + udelay(20); + + dm_gpio_set_value(&host->device_reset, false); + udelay(20); + + return 0; +} + static int ufs_rockchip_rk3576_init(struct ufs_hba *hba) { int ret = 0; @@ -172,6 +193,7 @@ static struct ufs_hba_ops ufs_hba_rk3576_vops = { .init = ufs_rockchip_rk3576_init, .phy_initialization = ufs_rockchip_rk3576_phy_init, .hce_enable_notify = ufs_rockchip_hce_enable_notify, + .device_reset = ufs_rockchip_device_reset, }; static const struct udevice_id ufs_rockchip_of_match[] = { diff --git a/drivers/ufs/ufs-rockchip.h b/drivers/ufs/ufs-rockchip.h index 3dcb80f5702..50c2539da78 100644 --- a/drivers/ufs/ufs-rockchip.h +++ b/drivers/ufs/ufs-rockchip.h @@ -72,6 +72,7 @@ struct ufs_rockchip_host { void __iomem *ufs_sys_ctrl; void __iomem *mphy_base; struct reset_ctl_bulk rsts; + struct gpio_desc device_reset; struct clk ref_out_clk; uint64_t caps; uint32_t phy_config_mode;