summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c23
-rw-r--r--drivers/scsi/ufs/ufshcd.c8
-rw-r--r--drivers/scsi/ufs/ufshcd.h3
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);