Merge tag 'u-boot-ufs-20260313' of https://source.denx.de/u-boot/custodians/u-boot-ufs into next

- ufs_hba_ops callbacks cleanup
- Rockchip UFS reset support
- UFS support in SPL
This commit is contained in:
Tom Rini 2026-03-13 09:01:53 -06:00
commit dba21bf0b6
13 changed files with 152 additions and 17 deletions

View File

@ -1890,6 +1890,7 @@ M: Neil Armstrong <neil.armstrong@linaro.org>
M: Bhupesh Sharma <bhupesh.linux@gmail.com>
M: Neha Malcom Francis <n-francis@ti.com>
S: Maintained
F: common/spl/spl_ufs.c
F: drivers/ufs/
UPL

View File

@ -30,6 +30,7 @@ enum {
BOOT_DEVICE_XIP,
BOOT_DEVICE_BOOTROM,
BOOT_DEVICE_SMH,
BOOT_DEVICE_UFS,
BOOT_DEVICE_NONE
};
#endif

View File

@ -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

View File

@ -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

49
common/spl/spl_ufs.c Normal file
View File

@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2025 Alexey Charkov <alchark@gmail.com>
*/
#include <spl.h>
#include <spl_load.h>
#include <scsi.h>
#include <errno.h>
#include <image.h>
#include <linux/compiler.h>
#include <log.h>
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);

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -5,6 +5,7 @@
* Copyright (C) 2025 Rockchip Electronics Co.Ltd.
*/
#include <asm/gpio.h>
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
@ -29,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;
}
@ -152,11 +150,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;
@ -174,6 +192,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[] = {

View File

@ -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;

View File

@ -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;
}
@ -2184,7 +2192,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);
@ -2228,7 +2240,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) {

View File

@ -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
*/
@ -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)

View File

@ -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