diff options
author | Subhash Jadavani <subhashj@codeaurora.org> | 2016-12-05 22:25:32 -0500 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2016-12-08 17:00:11 -0500 |
commit | 56d4a1866d748732fd8d690b2c2156bbc9c9eb02 (patch) | |
tree | 330f2d414d6d0afc8a390165f48999941c4ab32f | |
parent | ab436706e4a86719595012424ecefbdf4a84cc30 (diff) |
scsi: ufs: add quirk to increase host PA_SaveConfigTime
The maximum value PA_SaveConfigTime is 250 (10us) but this is not enough
for some vendors. Gear switch from PWM to HS may fail even with this
max. PA_SaveConfigTime. Gear switch can be issued by host controller as
an error recovery and any software delay will not help on this case so
we need to increase PA_SaveConfigTime to >32us as per vendor
recommendation. This change adds a quirk to increase the
PA_SaveConfigTime parameter.
Reviewed-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r-- | drivers/scsi/ufs/ufs-qcom.c | 30 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufs-qcom.h | 1 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufs_quirks.h | 30 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 26 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 12 |
5 files changed, 76 insertions, 23 deletions
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index ff614613bf89..2943a68b6d69 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "unipro.h" | 23 | #include "unipro.h" |
24 | #include "ufs-qcom.h" | 24 | #include "ufs-qcom.h" |
25 | #include "ufshci.h" | 25 | #include "ufshci.h" |
26 | #include "ufs_quirks.h" | ||
26 | #define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ | 27 | #define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ |
27 | (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) | 28 | (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) |
28 | 29 | ||
@@ -1031,6 +1032,34 @@ out: | |||
1031 | return ret; | 1032 | return ret; |
1032 | } | 1033 | } |
1033 | 1034 | ||
1035 | static int ufs_qcom_quirk_host_pa_saveconfigtime(struct ufs_hba *hba) | ||
1036 | { | ||
1037 | int err; | ||
1038 | u32 pa_vs_config_reg1; | ||
1039 | |||
1040 | err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), | ||
1041 | &pa_vs_config_reg1); | ||
1042 | if (err) | ||
1043 | goto out; | ||
1044 | |||
1045 | /* Allow extension of MSB bits of PA_SaveConfigTime attribute */ | ||
1046 | err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), | ||
1047 | (pa_vs_config_reg1 | (1 << 12))); | ||
1048 | |||
1049 | out: | ||
1050 | return err; | ||
1051 | } | ||
1052 | |||
1053 | static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba) | ||
1054 | { | ||
1055 | int err = 0; | ||
1056 | |||
1057 | if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME) | ||
1058 | err = ufs_qcom_quirk_host_pa_saveconfigtime(hba); | ||
1059 | |||
1060 | return err; | ||
1061 | } | ||
1062 | |||
1034 | static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) | 1063 | static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) |
1035 | { | 1064 | { |
1036 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | 1065 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
@@ -1618,6 +1647,7 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { | |||
1618 | .hce_enable_notify = ufs_qcom_hce_enable_notify, | 1647 | .hce_enable_notify = ufs_qcom_hce_enable_notify, |
1619 | .link_startup_notify = ufs_qcom_link_startup_notify, | 1648 | .link_startup_notify = ufs_qcom_link_startup_notify, |
1620 | .pwr_change_notify = ufs_qcom_pwr_change_notify, | 1649 | .pwr_change_notify = ufs_qcom_pwr_change_notify, |
1650 | .apply_dev_quirks = ufs_qcom_apply_dev_quirks, | ||
1621 | .suspend = ufs_qcom_suspend, | 1651 | .suspend = ufs_qcom_suspend, |
1622 | .resume = ufs_qcom_resume, | 1652 | .resume = ufs_qcom_resume, |
1623 | .dbg_register_dump = ufs_qcom_dump_dbg_regs, | 1653 | .dbg_register_dump = ufs_qcom_dump_dbg_regs, |
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index a19307a57ce2..fe517cd7dac3 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h | |||
@@ -142,6 +142,7 @@ enum ufs_qcom_phy_init_type { | |||
142 | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) | 142 | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) |
143 | 143 | ||
144 | /* QUniPro Vendor specific attributes */ | 144 | /* QUniPro Vendor specific attributes */ |
145 | #define PA_VS_CONFIG_REG1 0x9000 | ||
145 | #define DME_VS_CORE_CLK_CTRL 0xD002 | 146 | #define DME_VS_CORE_CLK_CTRL 0xD002 |
146 | /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ | 147 | /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ |
147 | #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) | 148 | #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) |
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index f7983058f3f7..08b799d4efcc 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h | |||
@@ -134,29 +134,17 @@ struct ufs_dev_fix { | |||
134 | */ | 134 | */ |
135 | #define UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE (1 << 7) | 135 | #define UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE (1 << 7) |
136 | 136 | ||
137 | /* | ||
138 | * The max. value PA_SaveConfigTime is 250 (10us) but this is not enough for | ||
139 | * some vendors. | ||
140 | * Gear switch from PWM to HS may fail even with this max. PA_SaveConfigTime. | ||
141 | * Gear switch can be issued by host controller as an error recovery and any | ||
142 | * software delay will not help on this case so we need to increase | ||
143 | * PA_SaveConfigTime to >32us as per vendor recommendation. | ||
144 | */ | ||
145 | #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 8) | ||
137 | 146 | ||
138 | struct ufs_hba; | 147 | struct ufs_hba; |
139 | void ufs_advertise_fixup_device(struct ufs_hba *hba); | 148 | void ufs_advertise_fixup_device(struct ufs_hba *hba); |
140 | 149 | ||
141 | static struct ufs_dev_fix ufs_fixups[] = { | ||
142 | /* UFS cards deviations table */ | ||
143 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
144 | UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), | ||
145 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), | ||
146 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
147 | UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS), | ||
148 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
149 | UFS_DEVICE_NO_FASTAUTO), | ||
150 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
151 | UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE), | ||
152 | UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL, | ||
153 | UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), | ||
154 | UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG", | ||
155 | UFS_DEVICE_QUIRK_PA_TACTIVATE), | ||
156 | UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG", | ||
157 | UFS_DEVICE_QUIRK_PA_TACTIVATE), | ||
158 | UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), | ||
159 | |||
160 | END_FIX | ||
161 | }; | ||
162 | #endif /* UFS_QUIRKS_H_ */ | 150 | #endif /* UFS_QUIRKS_H_ */ |
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 7af70aa0b750..af7e0285f004 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c | |||
@@ -185,6 +185,30 @@ ufs_get_pm_lvl_to_link_pwr_state(enum ufs_pm_level lvl) | |||
185 | return ufs_pm_lvl_states[lvl].link_state; | 185 | return ufs_pm_lvl_states[lvl].link_state; |
186 | } | 186 | } |
187 | 187 | ||
188 | static struct ufs_dev_fix ufs_fixups[] = { | ||
189 | /* UFS cards deviations table */ | ||
190 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
191 | UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), | ||
192 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), | ||
193 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
194 | UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS), | ||
195 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
196 | UFS_DEVICE_NO_FASTAUTO), | ||
197 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
198 | UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE), | ||
199 | UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL, | ||
200 | UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), | ||
201 | UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG", | ||
202 | UFS_DEVICE_QUIRK_PA_TACTIVATE), | ||
203 | UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG", | ||
204 | UFS_DEVICE_QUIRK_PA_TACTIVATE), | ||
205 | UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), | ||
206 | UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, | ||
207 | UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME), | ||
208 | |||
209 | END_FIX | ||
210 | }; | ||
211 | |||
188 | static void ufshcd_tmc_handler(struct ufs_hba *hba); | 212 | static void ufshcd_tmc_handler(struct ufs_hba *hba); |
189 | static void ufshcd_async_scan(void *data, async_cookie_t cookie); | 213 | static void ufshcd_async_scan(void *data, async_cookie_t cookie); |
190 | static int ufshcd_reset_and_restore(struct ufs_hba *hba); | 214 | static int ufshcd_reset_and_restore(struct ufs_hba *hba); |
@@ -5213,6 +5237,8 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) | |||
5213 | 5237 | ||
5214 | if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE) | 5238 | if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE) |
5215 | ufshcd_quirk_tune_host_pa_tactivate(hba); | 5239 | ufshcd_quirk_tune_host_pa_tactivate(hba); |
5240 | |||
5241 | ufshcd_vops_apply_dev_quirks(hba); | ||
5216 | } | 5242 | } |
5217 | 5243 | ||
5218 | /** | 5244 | /** |
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 7d9ff22acfea..08cd26ed2382 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h | |||
@@ -266,7 +266,7 @@ struct ufs_pwr_mode_info { | |||
266 | * @setup_task_mgmt: called before any task management request is issued | 266 | * @setup_task_mgmt: called before any task management request is issued |
267 | * to set some things | 267 | * to set some things |
268 | * @hibern8_notify: called around hibern8 enter/exit | 268 | * @hibern8_notify: called around hibern8 enter/exit |
269 | * to configure some things | 269 | * @apply_dev_quirks: called to apply device specific quirks |
270 | * @suspend: called during host controller PM callback | 270 | * @suspend: called during host controller PM callback |
271 | * @resume: called during host controller PM callback | 271 | * @resume: called during host controller PM callback |
272 | * @dbg_register_dump: used to dump controller debug information | 272 | * @dbg_register_dump: used to dump controller debug information |
@@ -293,7 +293,8 @@ struct ufs_hba_variant_ops { | |||
293 | void (*setup_xfer_req)(struct ufs_hba *, int, bool); | 293 | void (*setup_xfer_req)(struct ufs_hba *, int, bool); |
294 | void (*setup_task_mgmt)(struct ufs_hba *, int, u8); | 294 | void (*setup_task_mgmt)(struct ufs_hba *, int, u8); |
295 | void (*hibern8_notify)(struct ufs_hba *, enum uic_cmd_dme, | 295 | void (*hibern8_notify)(struct ufs_hba *, enum uic_cmd_dme, |
296 | enum ufs_notify_change_status); | 296 | enum ufs_notify_change_status); |
297 | int (*apply_dev_quirks)(struct ufs_hba *); | ||
297 | int (*suspend)(struct ufs_hba *, enum ufs_pm_op); | 298 | int (*suspend)(struct ufs_hba *, enum ufs_pm_op); |
298 | int (*resume)(struct ufs_hba *, enum ufs_pm_op); | 299 | int (*resume)(struct ufs_hba *, enum ufs_pm_op); |
299 | void (*dbg_register_dump)(struct ufs_hba *hba); | 300 | void (*dbg_register_dump)(struct ufs_hba *hba); |
@@ -839,6 +840,13 @@ static inline void ufshcd_vops_hibern8_notify(struct ufs_hba *hba, | |||
839 | return hba->vops->hibern8_notify(hba, cmd, status); | 840 | return hba->vops->hibern8_notify(hba, cmd, status); |
840 | } | 841 | } |
841 | 842 | ||
843 | static inline int ufshcd_vops_apply_dev_quirks(struct ufs_hba *hba) | ||
844 | { | ||
845 | if (hba->vops && hba->vops->apply_dev_quirks) | ||
846 | return hba->vops->apply_dev_quirks(hba); | ||
847 | return 0; | ||
848 | } | ||
849 | |||
842 | static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op) | 850 | static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op) |
843 | { | 851 | { |
844 | if (hba->vops && hba->vops->suspend) | 852 | if (hba->vops && hba->vops->suspend) |