Adds freeze, thaw and restore callbacks for hibernate and restore functionality. Signed-off-by: Anjana Hari <quic_ahari@xxxxxxxxxxx> --- drivers/ufs/core/ufshcd.c | 62 +++++++++++++++++++++++++++++++++++++ drivers/ufs/host/ufs-qcom.c | 6 +++- include/ufs/ufshcd.h | 8 +++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index fcd46251f7a8..d68222bb73ad 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -9826,11 +9826,36 @@ static int ufshcd_resume(struct ufs_hba *hba) /* enable the host irq as host controller would be active soon */ ufshcd_enable_irq(hba); + + if (hba->restore) { + /* Configure UTRL and UTMRL base address registers */ + ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr), + REG_UTP_TRANSFER_REQ_LIST_BASE_L); + ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr), + REG_UTP_TRANSFER_REQ_LIST_BASE_H); + ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr), + REG_UTP_TASK_REQ_LIST_BASE_L); + ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr), + REG_UTP_TASK_REQ_LIST_BASE_H); + /* Make sure that UTRL and UTMRL base address registers + * are updated with the latest queue addresses. Only after + * updating these addresses, we can queue the new commands. + */ + mb(); + } + + /* Resuming from hibernate, assume that link was OFF */ + if (hba->restore) + ufshcd_set_link_off(hba); + goto out; disable_vreg: ufshcd_vreg_set_lpm(hba); out: + if (hba->restore) + hba->restore = false; + if (ret) ufshcd_update_evt_hist(hba, UFS_EVT_RESUME_ERR, (u32)ret); return ret; @@ -9989,6 +10014,43 @@ void ufshcd_remove(struct ufs_hba *hba) } EXPORT_SYMBOL_GPL(ufshcd_remove); +int ufshcd_system_freeze(struct device *dev) +{ + + struct ufs_hba *hba = dev_get_drvdata(dev); + int ret = 0; + + /* + * Run time resume the controller to make sure + * the PM work queue threads do not try to resume + * the child (scsi host), which leads to errors as + * the controller is not yet resumed. + */ + pm_runtime_get_sync(hba->dev); + ret = ufshcd_system_suspend(dev); + pm_runtime_put_sync(hba->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(ufshcd_system_freeze); + +int ufshcd_system_restore(struct device *dev) +{ + + struct ufs_hba *hba = dev_get_drvdata(dev); + + hba->restore = true; + return ufshcd_system_resume(dev); + +} +EXPORT_SYMBOL_GPL(ufshcd_system_restore); + +int ufshcd_system_thaw(struct device *dev) +{ + return ufshcd_system_resume(dev); +} +EXPORT_SYMBOL_GPL(ufshcd_system_thaw); + /** * ufshcd_dealloc_host - deallocate Host Bus Adapter (HBA) * @hba: pointer to Host Bus Adapter (HBA) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 681da3ea7154..c92e041c5361 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1714,10 +1714,14 @@ MODULE_DEVICE_TABLE(acpi, ufs_qcom_acpi_match); #endif static const struct dev_pm_ops ufs_qcom_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume) SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL) .prepare = ufshcd_suspend_prepare, .complete = ufshcd_resume_complete, + .suspend = ufshcd_system_suspend, + .resume = ufshcd_system_resume, + .freeze = ufshcd_system_freeze, + .restore = ufshcd_system_restore, + .thaw = ufshcd_system_thaw, }; static struct platform_driver ufs_qcom_pltform = { diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 1779238d8a56..6f50390ca262 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1071,6 +1071,9 @@ struct ufs_hba { struct ufs_hw_queue *uhq; struct ufs_hw_queue *dev_cmd_queue; struct ufshcd_mcq_opr_info_t mcq_opr[OPR_MAX]; + + /* Distinguish between resume and restore */ + bool restore; }; /** @@ -1278,6 +1281,11 @@ extern int ufshcd_system_suspend(struct device *dev); extern int ufshcd_system_resume(struct device *dev); #endif extern int ufshcd_shutdown(struct ufs_hba *hba); + +extern int ufshcd_system_freeze(struct device *dev); +extern int ufshcd_system_thaw(struct device *dev); +extern int ufshcd_system_restore(struct device *dev); + extern int ufshcd_dme_configure_adapt(struct ufs_hba *hba, int agreed_gear, int adapt_val); -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative Project