From a3756f53baf1830c65149cfcb81cb96360976cf3 Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Tue, 25 Aug 2026 20:22:02 +0530 Subject: [PATCH] scsi: ufs: ufs-qcom: Restore HS/LS link startup mode for Qualcomm UFS controller v6.2+ The link startup mode (HS LSS - high-speed link startup, or LS LSS - low-speed link startup) is decided in the boot stage based on the bootconfig GPIO. This selection is carried forward through the secondary stage bootloaders and finally to HLOS via the spare configuration register (REG_UFS_DEBUG_SPARE_CFG). On Qualcomm UFS controller v6.2 and later, bit 31 in the spare configuration register indicates the high-speed link startup mode selection, as per the Hardware Programming Guide (HPG). The spare register value is read during host driver initialization but gets cleared after UFS reset. Preserve the spare register value during initialization and restore it during link startup to maintain the bootloader-configured link startup mode. Signed-off-by: Nitin Rawat Tested-by: Mukesh Ojha Link: https://patch.msgid.link/20260825145203.265579-2-nitin.rawat@oss.qualcomm.com Signed-off-by: Martin K. Petersen (Oracle) --- drivers/ufs/host/ufs-qcom.c | 15 ++++++++++++--- drivers/ufs/host/ufs-qcom.h | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 62396212a0a7..8893ea7e4d84 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -715,6 +715,7 @@ static void ufs_qcom_link_startup_post_change(struct ufs_hba *hba) static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { + struct ufs_qcom_host *host = ufshcd_get_variant(hba); int err = 0; switch (status) { @@ -737,6 +738,14 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, */ err = ufshcd_disable_host_tx_lcc(hba); + /* + * Restore HS/LS link startup mode set by bootloader + * after UFS reset clears REG_UFS_DEBUG_SPARE_CFG. + */ + if (host->hw_ver.major > 0x6 || + (host->hw_ver.major == 0x6 && host->hw_ver.minor >= 0x2)) + ufshcd_writel(hba, host->boot_spare_cfg, + REG_UFS_DEBUG_SPARE_CFG); break; case POST_CHANGE: ufs_qcom_link_startup_post_change(hba); @@ -1325,7 +1334,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host) { struct ufs_host_params *host_params = &host->host_params; - u32 val, dev_major; + u32 dev_major; /* * Default to powering up the PHY to the max gear possible, which is @@ -1344,8 +1353,8 @@ static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host) */ host->phy_gear = UFS_HS_G2; } else if (host->hw_ver.major >= 0x5) { - val = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG); - dev_major = FIELD_GET(UFS_DEV_VER_MAJOR_MASK, val); + host->boot_spare_cfg = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG); + dev_major = FIELD_GET(UFS_DEV_VER_MAJOR_MASK, host->boot_spare_cfg); /* * Since the UFS device version is populated, let's remove the diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index e20b3ca50577..a5ad5ce44a19 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -361,6 +361,7 @@ struct ufs_qcom_host { bool esi_enabled; u32 saved_tx_eq_g1_setting; + u32 boot_spare_cfg; }; struct ufs_qcom_drvdata {