diff options
author | Stanley Chu <stanley.chu@mediatek.com> | 2020-02-20 14:48:48 +0100 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2020-02-29 02:41:52 +0100 |
commit | b3222c326c965f94b2e8e8ac73dc395ca82cd088 (patch) | |
tree | b7d371769a4addebb2c926ec5dbdef1d640d0acc /drivers/scsi/ufs/ufs-mediatek.c | |
parent | scsi: ufs-qcom: Apply QUIRK_HOST_TACTIVATE for WDC UFS devices (diff) | |
download | linux-b3222c326c965f94b2e8e8ac73dc395ca82cd088.tar.xz linux-b3222c326c965f94b2e8e8ac73dc395ca82cd088.zip |
scsi: ufs: ufs-mediatek: add waiting time for reference clock
Some delays may be required either after gating or before ungating
reference clock for device according to vendor requirements.
Note that in UFS 3.0, the delay time after gating reference
clock can be defined by attribute bRefClkGatingWaitTime. Use the
formal value instead if it can be queried from device.
Link: https://lore.kernel.org/r/20200220134848.8807-2-stanley.chu@mediatek.com
Reviewed-by: Bean Huo <beanhuo@micron.com>
Signed-off-by: Stanley Chu <stanley.chu@mediatek.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/ufs/ufs-mediatek.c')
-rw-r--r-- | drivers/scsi/ufs/ufs-mediatek.c | 46 |
1 files changed, 44 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; } |