scsi: ufs: scale up the gear in 2 steps
Some UFS devices may stop responding after switching from HS-G1 to HS-G3. Also, it is found that these devices work fine if we do 2 steps switch: HS-G1 to HS-G2 followed by HS-G2 to HS-G3. This change introduce UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH quirk for these devices to apply this 2 steps gear switch workaround. Change-Id: I38eec2e1bfa842169cbfec441d900a807e715f8c Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
parent
bee947b93d
commit
d0960c5f30
3 changed files with 53 additions and 6 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License version 2 and
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
@ -30,6 +30,20 @@ static struct ufs_card_fix ufs_fixups[] = {
|
||||||
UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE),
|
UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE),
|
||||||
UFS_FIX(UFS_VENDOR_HYNIX, UFS_ANY_MODEL,
|
UFS_FIX(UFS_VENDOR_HYNIX, UFS_ANY_MODEL,
|
||||||
UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME),
|
UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME),
|
||||||
|
UFS_FIX(UFS_VENDOR_HYNIX, "hB8aL1",
|
||||||
|
UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
|
||||||
|
UFS_FIX(UFS_VENDOR_HYNIX, "hC8aL1",
|
||||||
|
UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
|
||||||
|
UFS_FIX(UFS_VENDOR_HYNIX, "hD8aL1",
|
||||||
|
UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
|
||||||
|
UFS_FIX(UFS_VENDOR_HYNIX, "hC8aM1",
|
||||||
|
UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
|
||||||
|
UFS_FIX(UFS_VENDOR_HYNIX, "h08aM1",
|
||||||
|
UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
|
||||||
|
UFS_FIX(UFS_VENDOR_HYNIX, "hC8GL1",
|
||||||
|
UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
|
||||||
|
UFS_FIX(UFS_VENDOR_HYNIX, "hC8HL1",
|
||||||
|
UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
|
||||||
|
|
||||||
END_FIX
|
END_FIX
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
|
/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License version 2 and
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
@ -139,6 +139,14 @@ struct ufs_card_fix {
|
||||||
*/
|
*/
|
||||||
#define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 7)
|
#define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 7)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some UFS devices may stop responding after switching from HS-G1 to HS-G3.
|
||||||
|
* Also, it is found that these devices work fine if we do 2 steps switch:
|
||||||
|
* HS-G1 to HS-G2 followed by HS-G2 to HS-G3. Enabling this quirk for such
|
||||||
|
* device would apply this 2 steps gear switch workaround.
|
||||||
|
*/
|
||||||
|
#define UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH (1 << 8)
|
||||||
|
|
||||||
struct ufs_hba;
|
struct ufs_hba;
|
||||||
void ufs_advertise_fixup_device(struct ufs_hba *hba);
|
void ufs_advertise_fixup_device(struct ufs_hba *hba);
|
||||||
#endif /* UFS_QUIRKS_H_ */
|
#endif /* UFS_QUIRKS_H_ */
|
||||||
|
|
|
@ -509,7 +509,7 @@ out:
|
||||||
/* replace non-printable or non-ASCII characters with spaces */
|
/* replace non-printable or non-ASCII characters with spaces */
|
||||||
static inline void ufshcd_remove_non_printable(char *val)
|
static inline void ufshcd_remove_non_printable(char *val)
|
||||||
{
|
{
|
||||||
if (!val)
|
if (!val || !*val)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (*val < 0x20 || *val > 0x7e)
|
if (*val < 0x20 || *val > 0x7e)
|
||||||
|
@ -3651,7 +3651,7 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
buff_ascii = kmalloc(ascii_len, GFP_KERNEL);
|
buff_ascii = kzalloc(ascii_len, GFP_KERNEL);
|
||||||
if (!buff_ascii) {
|
if (!buff_ascii) {
|
||||||
dev_err(hba->dev, "%s: Failed allocating %d bytes\n",
|
dev_err(hba->dev, "%s: Failed allocating %d bytes\n",
|
||||||
__func__, ascii_len);
|
__func__, ascii_len);
|
||||||
|
@ -9207,6 +9207,31 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up)
|
||||||
if (scale_up) {
|
if (scale_up) {
|
||||||
memcpy(&new_pwr_info, &hba->clk_scaling.saved_pwr_info.info,
|
memcpy(&new_pwr_info, &hba->clk_scaling.saved_pwr_info.info,
|
||||||
sizeof(struct ufs_pa_layer_attr));
|
sizeof(struct ufs_pa_layer_attr));
|
||||||
|
/*
|
||||||
|
* Some UFS devices may stop responding after switching from
|
||||||
|
* HS-G1 to HS-G3. Also, it is found that these devices work
|
||||||
|
* fine if we do 2 steps switch: HS-G1 to HS-G2 followed by
|
||||||
|
* HS-G2 to HS-G3. If UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH
|
||||||
|
* quirk is enabled for such devices, this 2 steps gear switch
|
||||||
|
* workaround will be applied.
|
||||||
|
*/
|
||||||
|
if ((hba->dev_quirks & UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH)
|
||||||
|
&& (hba->pwr_info.gear_tx == UFS_HS_G1)
|
||||||
|
&& (new_pwr_info.gear_tx == UFS_HS_G3)) {
|
||||||
|
/* scale up to G2 first */
|
||||||
|
new_pwr_info.gear_tx = UFS_HS_G2;
|
||||||
|
new_pwr_info.gear_rx = UFS_HS_G2;
|
||||||
|
ret = ufshcd_change_power_mode(hba, &new_pwr_info);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* scale up to G3 now */
|
||||||
|
new_pwr_info.gear_tx = UFS_HS_G3;
|
||||||
|
new_pwr_info.gear_rx = UFS_HS_G3;
|
||||||
|
ret = ufshcd_change_power_mode(hba, &new_pwr_info);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(&new_pwr_info, &hba->pwr_info,
|
memcpy(&new_pwr_info, &hba->pwr_info,
|
||||||
sizeof(struct ufs_pa_layer_attr));
|
sizeof(struct ufs_pa_layer_attr));
|
||||||
|
@ -9226,10 +9251,10 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up)
|
||||||
new_pwr_info.pwr_rx = FASTAUTO_MODE;
|
new_pwr_info.pwr_rx = FASTAUTO_MODE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ret = ufshcd_change_power_mode(hba, &new_pwr_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ufshcd_change_power_mode(hba, &new_pwr_info);
|
out:
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_err(hba->dev, "%s: failed err %d, old gear: (tx %d rx %d), new gear: (tx %d rx %d), scale_up = %d",
|
dev_err(hba->dev, "%s: failed err %d, old gear: (tx %d rx %d), new gear: (tx %d rx %d), scale_up = %d",
|
||||||
__func__, ret,
|
__func__, ret,
|
||||||
|
|
Loading…
Add table
Reference in a new issue