From 99ff1a35fe5e039097ba2520f00ecd862de6f6de Mon Sep 17 00:00:00 2001 From: Jorge Troncoso Date: Thu, 30 Sep 2021 16:29:32 -0700 Subject: [PATCH] refactor(ufs): add retry logic to ufshc_reset This change aims to make the UFS code more robust by adding retry logic and timeouts to ufshc_reset. We also define a new function ufshc_hce_enable for Host Controller Enable (HCE). The inner and outer retry pattern is based on Linux's ufshcd_hba_execute_hce function. Signed-off-by: Jorge Troncoso Change-Id: I9403a5a25d3ca50af5f2f9a65b774f6a2d7a9626 --- drivers/ufs/ufs.c | 38 ++++++++++++++++++++++++++++++++++---- include/drivers/ufs.h | 4 ++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 97a9d5e7e..695a614f2 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -123,21 +123,50 @@ int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val) return 0; } -static void ufshc_reset(uintptr_t base) +static int ufshc_hce_enable(uintptr_t base) { unsigned int data; + int retries; /* Enable Host Controller */ mmio_write_32(base + HCE, HCE_ENABLE); + /* Wait until basic initialization sequence completed */ - do { + for (retries = 0; retries < HCE_ENABLE_INNER_RETRIES; ++retries) { data = mmio_read_32(base + HCE); - } while ((data & HCE_ENABLE) == 0); + if (data & HCE_ENABLE) { + break; + } + udelay(HCE_ENABLE_TIMEOUT_US); + } + if (retries >= HCE_ENABLE_INNER_RETRIES) { + return -ETIMEDOUT; + } + + return 0; +} + +static int ufshc_reset(uintptr_t base) +{ + unsigned int data; + int retries, result; + + for (retries = 0; retries < HCE_ENABLE_OUTER_RETRIES; ++retries) { + result = ufshc_hce_enable(base); + if (result == 0) { + break; + } + } + if (retries >= HCE_ENABLE_OUTER_RETRIES) { + return -EIO; + } /* Enable Interrupts */ data = UFS_INT_UCCS | UFS_INT_ULSS | UFS_INT_UE | UFS_INT_UTPES | UFS_INT_DFES | UFS_INT_HCFES | UFS_INT_SBFES; mmio_write_32(base + IE, data); + + return 0; } static int ufshc_link_startup(uintptr_t base) @@ -782,7 +811,8 @@ int ufs_init(const ufs_ops_t *ops, ufs_params_t *params) assert((ops != NULL) && (ops->phy_init != NULL) && (ops->phy_set_pwr_mode != NULL)); - ufshc_reset(ufs_params.reg_base); + result = ufshc_reset(ufs_params.reg_base); + assert(result == 0); ops->phy_init(&ufs_params); result = ufshc_link_startup(ufs_params.reg_base); assert(result == 0); diff --git a/include/drivers/ufs.h b/include/drivers/ufs.h index 3f8f3605f..686d4c6dc 100644 --- a/include/drivers/ufs.h +++ b/include/drivers/ufs.h @@ -258,6 +258,10 @@ /* maximum number of retries for a general UIC command */ #define UFS_UIC_COMMAND_RETRIES 3 +#define HCE_ENABLE_OUTER_RETRIES 3 +#define HCE_ENABLE_INNER_RETRIES 50 +#define HCE_ENABLE_TIMEOUT_US 100 + /** * ufs_dev_desc - ufs device details from the device descriptor * @wmanufacturerid: card details