summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/ufs/ufs-mediatek.c46
-rw-r--r--drivers/scsi/ufs/ufs-mediatek.h2
2 files changed, 46 insertions, 2 deletions
diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index 9d05962feb15..de650822c9d9 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -100,6 +100,17 @@ static int ufs_mtk_bind_mphy(struct ufs_hba *hba)
return err;
}
+static void ufs_mtk_udelay(unsigned long us)
+{
+ if (!us)
+ return;
+
+ if (us < 10)
+ udelay(us);
+ else
+ usleep_range(us, us + 10);
+}
+
static int ufs_mtk_setup_ref_clk(struct ufs_hba *hba, bool on)
{
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
@@ -112,6 +123,7 @@ static int ufs_mtk_setup_ref_clk(struct ufs_hba *hba, bool on)
if (on) {
ufs_mtk_ref_clk_notify(on, res);
+ ufs_mtk_udelay(host->ref_clk_ungating_wait_us);
ufshcd_writel(hba, REFCLK_REQUEST, REG_UFS_REFCLK_CTRL);
} else {
ufshcd_writel(hba, REFCLK_RELEASE, REG_UFS_REFCLK_CTRL);
@@ -137,12 +149,29 @@ static int ufs_mtk_setup_ref_clk(struct ufs_hba *hba, bool on)
out:
host->ref_clk_enabled = on;
- if (!on)
+ if (!on) {
+ ufs_mtk_udelay(host->ref_clk_gating_wait_us);
ufs_mtk_ref_clk_notify(on, res);
+ }
return 0;
}
+static void ufs_mtk_setup_ref_clk_wait_us(struct ufs_hba *hba,
+ u16 gating_us, u16 ungating_us)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+
+ if (hba->dev_info.clk_gating_wait_us) {
+ host->ref_clk_gating_wait_us =
+ hba->dev_info.clk_gating_wait_us;
+ } else {
+ host->ref_clk_gating_wait_us = gating_us;
+ }
+
+ host->ref_clk_ungating_wait_us = ungating_us;
+}
+
static u32 ufs_mtk_link_get_state(struct ufs_hba *hba)
{
u32 val;
@@ -502,10 +531,23 @@ static void ufs_mtk_dbg_register_dump(struct ufs_hba *hba)
static int ufs_mtk_apply_dev_quirks(struct ufs_hba *hba)
{
struct ufs_dev_info *dev_info = &hba->dev_info;
+ u16 mid = dev_info->wmanufacturerid;
- if (dev_info->wmanufacturerid == UFS_VENDOR_SAMSUNG)
+ if (mid == UFS_VENDOR_SAMSUNG)
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 6);
+ /*
+ * Decide waiting time before gating reference clock and
+ * after ungating reference clock according to vendors'
+ * requirements.
+ */
+ if (mid == UFS_VENDOR_SAMSUNG)
+ ufs_mtk_setup_ref_clk_wait_us(hba, 1, 1);
+ else if (mid == UFS_VENDOR_SKHYNIX)
+ ufs_mtk_setup_ref_clk_wait_us(hba, 30, 30);
+ else if (mid == UFS_VENDOR_TOSHIBA)
+ ufs_mtk_setup_ref_clk_wait_us(hba, 100, 32);
+
return 0;
}
diff --git a/drivers/scsi/ufs/ufs-mediatek.h b/drivers/scsi/ufs/ufs-mediatek.h
index 492414e5f481..4c787b99fe41 100644
--- a/drivers/scsi/ufs/ufs-mediatek.h
+++ b/drivers/scsi/ufs/ufs-mediatek.h
@@ -92,6 +92,8 @@ struct ufs_mtk_host {
struct ufs_hba *hba;
struct phy *mphy;
bool ref_clk_enabled;
+ u16 ref_clk_ungating_wait_us;
+ u16 ref_clk_gating_wait_us;
};
#endif /* !_UFS_MEDIATEK_H */