diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/ufs/ufs-qcom.c | 23 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 8 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 3 |
3 files changed, 34 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index c4112e979399..62cb434e6ff3 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -28,6 +28,7 @@ #include "ufshci.h" #include "ufs-qcom-ice.h" #include "ufs-qcom-debugfs.h" +#include <linux/clk/msm-clk.h> #define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) @@ -634,6 +635,27 @@ out: return err; } +static int ufs_qcom_full_reset(struct ufs_hba *hba) +{ + struct ufs_clk_info *clki; + int ret = -ENOTSUPP; + + list_for_each_entry(clki, &hba->clk_list_head, list) { + if (!strcmp(clki->name, "core_clk")) { + ret = clk_reset(clki->clk, CLK_RESET_ASSERT); + if (ret) + goto out; + /* Very small delay, per the documented requirement */ + usleep_range(1, 2); + + ret = clk_reset(clki->clk, CLK_RESET_DEASSERT); + break; + } + } +out: + return ret; +} + static int ufs_qcom_crytpo_engine_cfg(struct ufs_hba *hba, unsigned int task_tag) { @@ -1777,6 +1799,7 @@ const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .pwr_change_notify = ufs_qcom_pwr_change_notify, .suspend = ufs_qcom_suspend, .resume = ufs_qcom_resume, + .full_reset = ufs_qcom_full_reset, .update_sec_cfg = ufs_qcom_update_sec_cfg, .dbg_register_dump = ufs_qcom_dump_dbg_regs, .crypto_engine_cfg = ufs_qcom_crytpo_engine_cfg, diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 68e29d752956..c2a19df3f21d 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3881,6 +3881,14 @@ static int ufshcd_link_recovery(struct ufs_hba *hba) ufshcd_set_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); + if (hba->vops && hba->vops->full_reset) { + ret = hba->vops->full_reset(hba); + if (ret) + dev_warn(hba->dev, + "full reset returned %d, trying to recover the link\n", + ret); + } + ret = ufshcd_host_reset_and_restore(hba); spin_lock_irqsave(hba->host->host_lock, flags); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index f88f160681ee..7a4e606168a4 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -301,6 +301,8 @@ struct ufs_pwr_mode_info { * to be set. * @suspend: called during host controller PM callback * @resume: called during host controller PM callback + * @full_reset: called during link recovery for handling variant specific + * implementations of resetting the hci * @update_sec_cfg: called to restore host controller secure configuration * @dbg_register_dump: used to dump controller debug information * @crypto_engine_cfg: configure cryptographic engine according to tag parameter @@ -336,6 +338,7 @@ struct ufs_hba_variant_ops { struct ufs_pa_layer_attr *); int (*suspend)(struct ufs_hba *, enum ufs_pm_op); int (*resume)(struct ufs_hba *, enum ufs_pm_op); + int (*full_reset)(struct ufs_hba *); int (*update_sec_cfg)(struct ufs_hba *hba, bool restore_sec_cfg); void (*dbg_register_dump)(struct ufs_hba *hba); int (*crypto_engine_cfg)(struct ufs_hba *, unsigned int); |