1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2026 Qualcomm Technologies, Inc. 4 * 5 * Author: 6 * Can Guo <can.guo@oss.qualcomm.com> 7 */ 8 9 #include <linux/bitops.h> 10 #include <linux/delay.h> 11 #include <linux/errno.h> 12 #include <linux/kernel.h> 13 #include <ufs/ufshcd.h> 14 #include <ufs/unipro.h> 15 #include "ufshcd-priv.h" 16 17 #define TX_EQ_SETTING_MASK 0x7 18 #define TX_EQ_SETTINGS_VALID_BIT BIT(15) 19 20 static bool use_adaptive_txeq; 21 module_param(use_adaptive_txeq, bool, 0644); 22 MODULE_PARM_DESC(use_adaptive_txeq, "Find and apply optimal TX Equalization settings before changing Power Mode (default: false)"); 23 24 static int txeq_gear_set(const char *val, const struct kernel_param *kp) 25 { 26 return param_set_uint_minmax(val, kp, UFS_HS_G1, UFS_HS_GEAR_MAX); 27 } 28 29 static const struct kernel_param_ops txeq_gear_ops = { 30 .set = txeq_gear_set, 31 .get = param_get_uint, 32 }; 33 34 static unsigned int adaptive_txeq_gear = UFS_HS_G6; 35 module_param_cb(adaptive_txeq_gear, &txeq_gear_ops, &adaptive_txeq_gear, 0644); 36 MODULE_PARM_DESC(adaptive_txeq_gear, "For HS-Gear[n] and above, adaptive txeq shall be used"); 37 38 static bool use_txeq_presets; 39 module_param(use_txeq_presets, bool, 0644); 40 MODULE_PARM_DESC(use_txeq_presets, "Use only the 8 TX Equalization Presets (pre-defined Pre-Shoot & De-Emphasis combinations) for TX EQTR (default: false)"); 41 42 static bool txeq_presets_selected[UFS_TX_EQ_PRESET_MAX] = {[0 ... (UFS_TX_EQ_PRESET_MAX - 1)] = 1}; 43 module_param_array(txeq_presets_selected, bool, NULL, 0644); 44 MODULE_PARM_DESC(txeq_presets_selected, "Use only the selected Presets out of the 8 TX Equalization Presets for TX EQTR"); 45 46 static int txeq_setting_sel_set(const char *val, const struct kernel_param *kp) 47 { 48 return param_set_uint_minmax(val, kp, 0, 1); 49 } 50 51 static const struct kernel_param_ops txeq_setting_sel_ops = { 52 .set = txeq_setting_sel_set, 53 .get = param_get_uint, 54 }; 55 56 static unsigned int txeq_setting_sel; 57 module_param_cb(txeq_setting_sel, &txeq_setting_sel_ops, &txeq_setting_sel, 0644); 58 MODULE_PARM_DESC(txeq_setting_sel, "The qTxEQGnSettings and wTxEQGnSettingsExt Attributes selector used to retrieve and store TX Equalization settings"); 59 60 static bool retrieve_txeq_setting = true; 61 module_param(retrieve_txeq_setting, bool, 0644); 62 MODULE_PARM_DESC(retrieve_txeq_setting, "Retrieve TX Equalization settings from qTxEQGnSettings and wTxEQGnSettingsExt Attributes (default: true)"); 63 64 static bool store_txeq_setting = true; 65 module_param(store_txeq_setting, bool, 0644); 66 MODULE_PARM_DESC(store_txeq_setting, "Store the optimal TX Equalization settings to qTxEQGnSettings and wTxEQGnSettingsExt Attributes (default: true)"); 67 68 /* 69 * ufs_tx_eq_preset - Table of minimum required list of presets. 70 * 71 * A HS-G6 capable M-TX shall support the presets defined in M-PHY v6.0 spec. 72 * Preset Pre-Shoot(dB) De-Emphasis(dB) 73 * P0 0.0 0.0 74 * P1 0.0 0.8 75 * P2 0.0 1.6 76 * P3 0.8 0.0 77 * P4 1.6 0.0 78 * P5 0.8 0.8 79 * P6 0.8 1.6 80 * P7 1.6 0.8 81 */ 82 static const struct __ufs_tx_eq_preset { 83 u8 preshoot; 84 u8 deemphasis; 85 } ufs_tx_eq_preset[UFS_TX_EQ_PRESET_MAX] = { 86 [UFS_TX_EQ_PRESET_P0] = {UFS_TX_HS_PRESHOOT_DB_0P0, UFS_TX_HS_DEEMPHASIS_DB_0P0}, 87 [UFS_TX_EQ_PRESET_P1] = {UFS_TX_HS_PRESHOOT_DB_0P0, UFS_TX_HS_DEEMPHASIS_DB_0P8}, 88 [UFS_TX_EQ_PRESET_P2] = {UFS_TX_HS_PRESHOOT_DB_0P0, UFS_TX_HS_DEEMPHASIS_DB_1P6}, 89 [UFS_TX_EQ_PRESET_P3] = {UFS_TX_HS_PRESHOOT_DB_0P8, UFS_TX_HS_DEEMPHASIS_DB_0P0}, 90 [UFS_TX_EQ_PRESET_P4] = {UFS_TX_HS_PRESHOOT_DB_1P6, UFS_TX_HS_DEEMPHASIS_DB_0P0}, 91 [UFS_TX_EQ_PRESET_P5] = {UFS_TX_HS_PRESHOOT_DB_0P8, UFS_TX_HS_DEEMPHASIS_DB_0P8}, 92 [UFS_TX_EQ_PRESET_P6] = {UFS_TX_HS_PRESHOOT_DB_0P8, UFS_TX_HS_DEEMPHASIS_DB_1P6}, 93 [UFS_TX_EQ_PRESET_P7] = {UFS_TX_HS_PRESHOOT_DB_1P6, UFS_TX_HS_DEEMPHASIS_DB_0P8}, 94 }; 95 96 /* 97 * pa_peer_rx_adapt_initial - Table of UniPro PA_PeerRxHSGnAdaptInitial 98 * attribute IDs for High Speed (HS) Gears. 99 * 100 * This table maps HS Gears to their respective UniPro PA_PeerRxHSGnAdaptInitial 101 * attribute IDs. Entries for Gears 1-3 are 0 (unsupported). 102 */ 103 static const u32 pa_peer_rx_adapt_initial[UFS_HS_GEAR_MAX] = { 104 0, 105 0, 106 0, 107 PA_PEERRXHSG4ADAPTINITIAL, 108 PA_PEERRXHSG5ADAPTINITIAL, 109 PA_PEERRXHSG6ADAPTINITIALL0L3 110 }; 111 112 /* 113 * rx_adapt_initial_cap - Table of M-PHY RX_HS_Gn_ADAPT_INITIAL_Capability 114 * attribute IDs for High Speed (HS) Gears. 115 * 116 * This table maps HS Gears to their respective M-PHY 117 * RX_HS_Gn_ADAPT_INITIAL_Capability attribute IDs. Entries for Gears 1-3 are 0 118 * (unsupported). 119 */ 120 static const u32 rx_adapt_initial_cap[UFS_HS_GEAR_MAX] = { 121 0, 122 0, 123 0, 124 RX_HS_G4_ADAPT_INITIAL_CAP, 125 RX_HS_G5_ADAPT_INITIAL_CAP, 126 RX_HS_G6_ADAPT_INITIAL_CAP 127 }; 128 129 /* 130 * pa_tx_eq_setting - Table of UniPro PA_TxEQGnSetting attribute IDs for High 131 * Speed (HS) Gears. 132 * 133 * This table maps HS Gears to their respective UniPro PA_TxEQGnSetting 134 * attribute IDs. 135 */ 136 static const u32 pa_tx_eq_setting[UFS_HS_GEAR_MAX] = { 137 PA_TXEQG1SETTING, 138 PA_TXEQG2SETTING, 139 PA_TXEQG3SETTING, 140 PA_TXEQG4SETTING, 141 PA_TXEQG5SETTING, 142 PA_TXEQG6SETTING 143 }; 144 145 /* 146 * Decode Device TX Equalization PreShoot value based on qTxEQGnSettings bit assignment: 147 * bit[3:0]: Device TX Logical LANE 0 PreShoot 148 * bit[7:4]: Device TX Logical LANE 1 PreShoot 149 */ 150 static inline u8 tx_eq_device_preshoot_decode(u64 eq, u8 lane) 151 { 152 return (u8)((eq >> (lane * TX_HS_PRESHOOT_SHIFT)) & TX_EQ_SETTING_MASK); 153 } 154 155 /* 156 * Decode Device TX Equalization DeEmphasis value based on qTxEQGnSettings bit assignment: 157 * bit[19:16]: Device TX Logical LANE 0 DeEmphasis 158 * bit[23:20]: Device TX Logical LANE 1 DeEmphasis 159 */ 160 static inline u8 tx_eq_device_deemphasis_decode(u64 eq, u8 lane) 161 { 162 return (u8)((eq >> (lane * TX_HS_DEEMPHASIS_SHIFT + 16)) & TX_EQ_SETTING_MASK); 163 } 164 165 /* 166 * Decode Host TX Equalization PreShoot value based on qTxEQGnSettings bit assignment: 167 * bit[35:32]: Host TX Logical LANE 0 PreShoot 168 * bit[39:36]: Host TX Logical LANE 1 PreShoot 169 */ 170 static inline u8 tx_eq_host_preshoot_decode(u64 eq, u8 lane) 171 { 172 return (u8)((eq >> (lane * TX_HS_PRESHOOT_SHIFT + 32)) & TX_EQ_SETTING_MASK); 173 } 174 175 /* 176 * Decode Host TX Equalization DeEmphasis value based on qTxEQGnSettings bit assignment: 177 * bit[51:48]: Host TX Logical LANE 0 DeEmphasis 178 * bit[55:52]: Host TX Logical LANE 1 DeEmphasis 179 */ 180 static inline u8 tx_eq_host_deemphasis_decode(u64 eq, u8 lane) 181 { 182 return (u8)((eq >> (lane * TX_HS_DEEMPHASIS_SHIFT + 48)) & TX_EQ_SETTING_MASK); 183 } 184 185 /* 186 * Decode Device TX precode_en indication based on wTxEQGnSettingsExt bit assignment: 187 * bit[0]: PreCodeEn for Device TX Logical LANE 0 188 * bit[1]: PreCodeEn for Device TX Logical LANE 1 189 */ 190 static inline bool tx_eq_device_precode_en_decode(u16 eq_ext, u8 lane) 191 { 192 return eq_ext & BIT(lane); 193 } 194 195 /* 196 * Decode Host TX precode_en indication based on wTxEQGnSettingsExt bit assignment: 197 * bit[4]: PreCodeEn for Device RX Logical LANE 0 198 * bit[5]: PreCodeEn for Device RX Logical LANE 1 199 */ 200 static inline bool tx_eq_host_precode_en_decode(u16 eq_ext, u8 lane) 201 { 202 return eq_ext & BIT(lane + 4); 203 } 204 205 /* 206 * Encode Device TX Equalization PreShoot value based on qTxEQGnSettings bit assignment: 207 * bit[3:0]: Device TX Logical LANE 0 PreShoot 208 * bit[7:4]: Device TX Logical LANE 1 PreShoot 209 */ 210 static inline u64 tx_eq_device_preshoot_encode(u64 val, u8 lane) 211 { 212 return (val & TX_EQ_SETTING_MASK) << (lane * TX_HS_PRESHOOT_SHIFT); 213 } 214 215 /* 216 * Encode Device TX Equalization DeEmphasis value based on qTxEQGnSettings bit assignment: 217 * bit[19:16]: Device TX Logical LANE 0 DeEmphasis 218 * bit[23:20]: Device TX Logical LANE 1 DeEmphasis 219 */ 220 static inline u64 tx_eq_device_deemphasis_encode(u64 val, u8 lane) 221 { 222 return (val & TX_EQ_SETTING_MASK) << (lane * TX_HS_DEEMPHASIS_SHIFT + 16); 223 } 224 225 /* 226 * Encode Host TX Equalization PreShoot value based on qTxEQGnSettings bit assignment: 227 * bit[35:32]: Host TX Logical LANE 0 PreShoot 228 * bit[39:36]: Host TX Logical LANE 1 PreShoot 229 */ 230 static inline u64 tx_eq_host_preshoot_encode(u64 val, u8 lane) 231 { 232 return (val & TX_EQ_SETTING_MASK) << (lane * TX_HS_PRESHOOT_SHIFT + 32); 233 } 234 235 /* 236 * Encode Host TX Equalization DeEmphasis value based on qTxEQGnSettings bit assignment: 237 * bit[51:48]: Host TX Logical LANE 0 DeEmphasis 238 * bit[55:52]: Host TX Logical LANE 1 DeEmphasis 239 */ 240 static inline u64 tx_eq_host_deemphasis_encode(u64 val, u8 lane) 241 { 242 return (val & TX_EQ_SETTING_MASK) << (lane * TX_HS_DEEMPHASIS_SHIFT + 48); 243 } 244 245 /* 246 * Encode Device precode_en based on wTxEQGnSettingsExt bit assignment: 247 * bit[0]: PreCodeEn for Device TX Logical LANE 0 248 * bit[1]: PreCodeEn for Device TX Logical LANE 1 249 */ 250 static inline u16 tx_eq_device_precode_en_encode(bool en, u8 lane) 251 { 252 return (u16)en << lane; 253 } 254 255 /* 256 * Encode Host precode_en based on wTxEQGnSettingsExt bit assignment: 257 * bit[4]: PreCodeEn for Device RX Logical LANE 0 258 * bit[5]: PreCodeEn for Device RX Logical LANE 1 259 */ 260 static inline u16 tx_eq_host_precode_en_encode(bool en, u8 lane) 261 { 262 return (u16)en << (lane + 4); 263 } 264 265 /** 266 * ufshcd_configure_precoding - Configure Pre-Coding for all active lanes 267 * @hba: per adapter instance 268 * @params: TX EQ parameters data structure 269 * 270 * Bit[7] in RX_FOM indicates that the receiver needs to enable Pre-Coding when 271 * set. Pre-Coding must be enabled on both the transmitter and receiver to 272 * ensure proper operation. 273 * 274 * Returns 0 on success, non-zero error code otherwise 275 */ 276 static int ufshcd_configure_precoding(struct ufs_hba *hba, 277 struct ufshcd_tx_eq_params *params) 278 { 279 struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info; 280 u32 local_precode_en = 0; 281 u32 peer_precode_en = 0; 282 int lane, ret; 283 284 /* Enable Pre-Coding for Host's TX & Device's RX pair */ 285 for (lane = 0; lane < pwr_info->lane_tx; lane++) { 286 if (params->host[lane].precode_en) { 287 local_precode_en |= PRECODEEN_TX_BIT(lane); 288 peer_precode_en |= PRECODEEN_RX_BIT(lane); 289 } 290 } 291 292 /* Enable Pre-Coding for Device's TX & Host's RX pair */ 293 for (lane = 0; lane < pwr_info->lane_rx; lane++) { 294 if (params->device[lane].precode_en) { 295 peer_precode_en |= PRECODEEN_TX_BIT(lane); 296 local_precode_en |= PRECODEEN_RX_BIT(lane); 297 } 298 } 299 300 if (!local_precode_en && !peer_precode_en) { 301 dev_dbg(hba->dev, "Pre-Coding is not required for Host and Device\n"); 302 return 0; 303 } 304 305 /* Set local PA_PreCodeEn */ 306 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PRECODEEN), local_precode_en); 307 if (ret) { 308 dev_err(hba->dev, "Failed to set local PA_PreCodeEn: %d\n", ret); 309 return ret; 310 } 311 312 /* Set peer PA_PreCodeEn */ 313 ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(PA_PRECODEEN), peer_precode_en); 314 if (ret) { 315 dev_err(hba->dev, "Failed to set peer PA_PreCodeEn: %d\n", ret); 316 return ret; 317 } 318 319 dev_dbg(hba->dev, "Local PA_PreCodeEn: 0x%02x, Peer PA_PreCodeEn: 0x%02x\n", 320 local_precode_en, peer_precode_en); 321 322 return 0; 323 } 324 325 void ufshcd_print_tx_eq_params(struct ufs_hba *hba) 326 { 327 struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info; 328 struct ufshcd_tx_eq_params *params; 329 u32 gear = hba->pwr_info.gear_tx; 330 int lane; 331 332 if (!ufshcd_is_tx_eq_supported(hba)) 333 return; 334 335 if (gear < UFS_HS_G1 || gear > UFS_HS_GEAR_MAX) 336 return; 337 338 params = &hba->tx_eq_params[gear - 1]; 339 if (!params->is_valid || !params->is_applied) 340 return; 341 342 for (lane = 0; lane < pwr_info->lane_tx; lane++) 343 dev_dbg(hba->dev, "Host TX Lane %d: PreShoot %u, DeEmphasis %u, FOM %u, PreCodeEn %d\n", 344 lane, params->host[lane].preshoot, 345 params->host[lane].deemphasis, 346 params->host[lane].fom_val, 347 params->host[lane].precode_en); 348 349 for (lane = 0; lane < pwr_info->lane_rx; lane++) 350 dev_dbg(hba->dev, "Device TX Lane %d: PreShoot %u, DeEmphasis %u, FOM %u, PreCodeEn %d\n", 351 lane, params->device[lane].preshoot, 352 params->device[lane].deemphasis, 353 params->device[lane].fom_val, 354 params->device[lane].precode_en); 355 } 356 357 static inline u32 358 ufshcd_compose_tx_eq_setting(struct ufshcd_tx_eq_settings *settings, 359 int num_lanes) 360 { 361 u32 setting = 0; 362 int lane; 363 364 for (lane = 0; lane < num_lanes; lane++, settings++) { 365 setting |= TX_HS_PRESHOOT_BITS(lane, settings->preshoot); 366 setting |= TX_HS_DEEMPHASIS_BITS(lane, settings->deemphasis); 367 } 368 369 return setting; 370 } 371 372 /** 373 * ufshcd_apply_tx_eq_settings - Apply TX Equalization settings for target gear 374 * @hba: per adapter instance 375 * @params: TX EQ parameters data structure 376 * @gear: target gear 377 * 378 * Returns 0 on success, negative error code otherwise 379 */ 380 int ufshcd_apply_tx_eq_settings(struct ufs_hba *hba, 381 struct ufshcd_tx_eq_params *params, u32 gear) 382 { 383 struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info; 384 u32 setting; 385 int ret; 386 387 /* Compose settings for Host's TX Lanes */ 388 setting = ufshcd_compose_tx_eq_setting(params->host, pwr_info->lane_tx); 389 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(pa_tx_eq_setting[gear - 1]), setting); 390 if (ret) 391 return ret; 392 393 /* Compose settings for Device's TX Lanes */ 394 setting = ufshcd_compose_tx_eq_setting(params->device, pwr_info->lane_rx); 395 ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(pa_tx_eq_setting[gear - 1]), setting); 396 if (ret) 397 return ret; 398 399 /* Configure Pre-Coding */ 400 if (gear >= UFS_HS_G6) { 401 ret = ufshcd_configure_precoding(hba, params); 402 if (ret) { 403 dev_err(hba->dev, "Failed to configure pre-coding: %d\n", ret); 404 return ret; 405 } 406 } 407 408 return 0; 409 } 410 EXPORT_SYMBOL_GPL(ufshcd_apply_tx_eq_settings); 411 412 /** 413 * ufshcd_evaluate_tx_eqtr_fom - Evaluate TX EQTR FOM results 414 * @hba: per adapter instance 415 * @pwr_mode: target power mode containing gear and rate information 416 * @eqtr_data: TX EQTR data structure 417 * @h_iter: host TX EQTR iterator data structure 418 * @d_iter: device TX EQTR iterator data structure 419 * 420 * Evaluate TX EQTR FOM results, update host and device TX EQTR data accordingy 421 * if FOM have been improved compared to previous iteration, and record TX EQTR 422 * FOM results. 423 */ 424 static void ufshcd_evaluate_tx_eqtr_fom(struct ufs_hba *hba, 425 struct ufs_pa_layer_attr *pwr_mode, 426 struct ufshcd_tx_eqtr_data *eqtr_data, 427 struct tx_eqtr_iter *h_iter, 428 struct tx_eqtr_iter *d_iter) 429 { 430 u8 preshoot, deemphasis, fom_value; 431 bool precode_en; 432 int lane; 433 434 for (lane = 0; h_iter->is_updated && lane < pwr_mode->lane_tx; lane++) { 435 preshoot = h_iter->preshoot; 436 deemphasis = h_iter->deemphasis; 437 fom_value = h_iter->fom[lane] & RX_FOM_VALUE_MASK; 438 precode_en = h_iter->fom[lane] & RX_FOM_PRECODING_EN_BIT; 439 440 /* Record host TX EQTR FOM */ 441 eqtr_data->host_fom[lane][preshoot][deemphasis] = h_iter->fom[lane]; 442 443 /* Check if FOM has been improved for host's TX Lanes */ 444 if (fom_value > eqtr_data->host[lane].fom_val) { 445 eqtr_data->host[lane].preshoot = preshoot; 446 eqtr_data->host[lane].deemphasis = deemphasis; 447 eqtr_data->host[lane].fom_val = fom_value; 448 eqtr_data->host[lane].precode_en = precode_en; 449 } 450 451 dev_dbg(hba->dev, "TX EQTR: Host TX Lane %d: PreShoot %u, DeEmphasis %u, FOM value %u, PreCodeEn %d\n", 452 lane, preshoot, deemphasis, fom_value, precode_en); 453 } 454 455 for (lane = 0; d_iter->is_updated && lane < pwr_mode->lane_rx; lane++) { 456 preshoot = d_iter->preshoot; 457 deemphasis = d_iter->deemphasis; 458 fom_value = d_iter->fom[lane] & RX_FOM_VALUE_MASK; 459 precode_en = d_iter->fom[lane] & RX_FOM_PRECODING_EN_BIT; 460 461 /* Record device TX EQTR FOM */ 462 eqtr_data->device_fom[lane][preshoot][deemphasis] = d_iter->fom[lane]; 463 464 /* Check if FOM has been improved for Device's TX Lanes */ 465 if (fom_value > eqtr_data->device[lane].fom_val) { 466 eqtr_data->device[lane].preshoot = preshoot; 467 eqtr_data->device[lane].deemphasis = deemphasis; 468 eqtr_data->device[lane].fom_val = fom_value; 469 eqtr_data->device[lane].precode_en = precode_en; 470 } 471 472 dev_dbg(hba->dev, "TX EQTR: Device TX Lane %d: PreShoot %u, DeEmphasis %u, FOM value %u, PreCodeEn %d\n", 473 lane, preshoot, deemphasis, fom_value, precode_en); 474 } 475 } 476 477 /** 478 * ufshcd_get_rx_fom - Get Figure of Merit (FOM) for both sides 479 * @hba: per adapter instance 480 * @pwr_mode: target power mode containing gear and rate information 481 * @h_iter: host TX EQTR iterator data structure 482 * @d_iter: device TX EQTR iterator data structure 483 * 484 * Returns 0 on success, negative error code otherwise 485 */ 486 static int ufshcd_get_rx_fom(struct ufs_hba *hba, 487 struct ufs_pa_layer_attr *pwr_mode, 488 struct tx_eqtr_iter *h_iter, 489 struct tx_eqtr_iter *d_iter) 490 { 491 int lane, ret; 492 u32 fom; 493 494 /* Get FOM of host's TX lanes from device's RX_FOM. */ 495 for (lane = 0; lane < pwr_mode->lane_tx; lane++) { 496 ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB_SEL(RX_FOM, 497 UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 498 &fom); 499 if (ret) 500 return ret; 501 502 h_iter->fom[lane] = (u8)fom; 503 } 504 505 /* Get FOM of device's TX lanes from host's RX_FOM. */ 506 for (lane = 0; lane < pwr_mode->lane_rx; lane++) { 507 ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(RX_FOM, 508 UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 509 &fom); 510 if (ret) 511 return ret; 512 513 d_iter->fom[lane] = (u8)fom; 514 } 515 516 ret = ufshcd_vops_get_rx_fom(hba, pwr_mode, h_iter, d_iter); 517 if (ret) 518 dev_err(hba->dev, "Failed to get FOM via vops: %d\n", ret); 519 520 return ret; 521 } 522 523 bool ufshcd_is_txeq_presets_used(struct ufs_hba *hba) 524 { 525 return use_txeq_presets; 526 } 527 528 bool ufshcd_is_txeq_preset_selected(u8 preshoot, u8 deemphasis) 529 { 530 int i; 531 532 for (i = 0; i < UFS_TX_EQ_PRESET_MAX; i++) { 533 if (!txeq_presets_selected[i]) 534 continue; 535 536 if (preshoot == ufs_tx_eq_preset[i].preshoot && 537 deemphasis == ufs_tx_eq_preset[i].deemphasis) 538 return true; 539 } 540 541 return false; 542 } 543 544 /** 545 * tx_eqtr_iter_try_update - Try to update a TX EQTR iterator 546 * @iter: TX EQTR iterator data structure 547 * @preshoot: PreShoot value 548 * @deemphasis: DeEmphasis value 549 * 550 * This function validates whether the provided PreShoot and DeEmphasis 551 * combination can be used or not. If yes, it updates the TX EQTR iterator with 552 * the provided PreShoot and DeEmphasis, it also sets the is_updated flag 553 * to indicate the iterator has been updated. 554 */ 555 static void tx_eqtr_iter_try_update(struct tx_eqtr_iter *iter, 556 u8 preshoot, u8 deemphasis) 557 { 558 if (!test_bit(preshoot, &iter->preshoot_bitmap) || 559 !test_bit(deemphasis, &iter->deemphasis_bitmap) || 560 (use_txeq_presets && !ufshcd_is_txeq_preset_selected(preshoot, deemphasis))) { 561 iter->is_updated = false; 562 return; 563 } 564 565 iter->preshoot = preshoot; 566 iter->deemphasis = deemphasis; 567 iter->is_updated = true; 568 } 569 570 /** 571 * tx_eqtr_iter_update() - Update host and deviceTX EQTR iterators 572 * @preshoot: PreShoot value 573 * @deemphasis: DeEmphasis value 574 * @h_iter: Host TX EQTR iterator data structure 575 * @d_iter: Device TX EQTR iterator data structure 576 * 577 * Updates host and device TX Equalization training iterators with the 578 * provided PreShoot and DeEmphasis. 579 * 580 * Return: true if host and/or device TX Equalization training iterator has 581 * been updated to the provided PreShoot and DeEmphasis, false otherwise. 582 */ 583 static bool tx_eqtr_iter_update(u8 preshoot, u8 deemphasis, 584 struct tx_eqtr_iter *h_iter, 585 struct tx_eqtr_iter *d_iter) 586 { 587 tx_eqtr_iter_try_update(h_iter, preshoot, deemphasis); 588 tx_eqtr_iter_try_update(d_iter, preshoot, deemphasis); 589 590 return h_iter->is_updated || d_iter->is_updated; 591 } 592 593 /** 594 * ufshcd_tx_eqtr_iter_init - Initialize host and device TX EQTR iterators 595 * @hba: per adapter instance 596 * @h_iter: host TX EQTR iterator data structure 597 * @d_iter: device TX EQTR iterator data structure 598 * 599 * This function initializes the TX EQTR iterator structures for both host and 600 * device by reading their TX equalization capabilities. The capabilities are 601 * cached in the hba structure to avoid redundant DME operations in subsequent 602 * calls. In the TX EQTR procedure, the iterator structures are updated by 603 * tx_eqtr_iter_update() to systematically iterate through supported TX 604 * Equalization setting combinations. 605 * 606 * Returns 0 on success, negative error code otherwise 607 */ 608 static int ufshcd_tx_eqtr_iter_init(struct ufs_hba *hba, 609 struct tx_eqtr_iter *h_iter, 610 struct tx_eqtr_iter *d_iter) 611 { 612 u32 cap; 613 int ret; 614 615 if (!hba->host_preshoot_cap) { 616 ret = ufshcd_dme_get(hba, UIC_ARG_MIB(TX_HS_PRESHOOT_SETTING_CAP), &cap); 617 if (ret) 618 return ret; 619 620 hba->host_preshoot_cap = cap & TX_EQTR_CAP_MASK; 621 } 622 623 if (!hba->host_deemphasis_cap) { 624 ret = ufshcd_dme_get(hba, UIC_ARG_MIB(TX_HS_DEEMPHASIS_SETTING_CAP), &cap); 625 if (ret) 626 return ret; 627 628 hba->host_deemphasis_cap = cap & TX_EQTR_CAP_MASK; 629 } 630 631 if (!hba->device_preshoot_cap) { 632 ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(TX_HS_PRESHOOT_SETTING_CAP), &cap); 633 if (ret) 634 return ret; 635 636 hba->device_preshoot_cap = cap & TX_EQTR_CAP_MASK; 637 } 638 639 if (!hba->device_deemphasis_cap) { 640 ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(TX_HS_DEEMPHASIS_SETTING_CAP), &cap); 641 if (ret) 642 return ret; 643 644 hba->device_deemphasis_cap = cap & TX_EQTR_CAP_MASK; 645 } 646 647 /* 648 * Support PreShoot & DeEmphasis of value 0 is mandatory, hence they are 649 * not reflected in PreShoot/DeEmphasis capabilities. Left shift the 650 * capability bitmap by 1 and set bit[0] to reflect value 0 is 651 * supported, such that test_bit() can be used later for convenience. 652 */ 653 h_iter->preshoot_bitmap = (hba->host_preshoot_cap << 0x1) | 0x1; 654 h_iter->deemphasis_bitmap = (hba->host_deemphasis_cap << 0x1) | 0x1; 655 d_iter->preshoot_bitmap = (hba->device_preshoot_cap << 0x1) | 0x1; 656 d_iter->deemphasis_bitmap = (hba->device_deemphasis_cap << 0x1) | 0x1; 657 658 return 0; 659 } 660 661 /** 662 * adapt_cap_to_t_adapt - Calculate TAdapt from adapt capability 663 * @adapt_cap: Adapt capability 664 * 665 * For NRZ: 666 * IF (ADAPT_range = FINE) 667 * TADAPT = 650 x (ADAPT_length + 1) 668 * ELSE (IF ADAPT_range = COARSE) 669 * TADAPT = 650 x 2^ADAPT_length 670 * 671 * Returns calculated TAdapt value in term of Unit Intervals (UI) 672 */ 673 static inline u64 adapt_cap_to_t_adapt(u32 adapt_cap) 674 { 675 u64 tadapt; 676 u8 adapt_length = adapt_cap & ADAPT_LENGTH_MASK; 677 678 if (!IS_ADAPT_RANGE_COARSE(adapt_cap)) 679 tadapt = TADAPT_FACTOR * (adapt_length + 1); 680 else 681 tadapt = TADAPT_FACTOR * (1 << adapt_length); 682 683 return tadapt; 684 } 685 686 /** 687 * adapt_cap_to_t_adapt_l0l3 - Calculate TAdapt_L0_L3 from adapt capability 688 * @adapt_cap: Adapt capability 689 * 690 * For PAM-4: 691 * IF (ADAPT_range = FINE) 692 * TADAPT_L0_L3 = 2^9 x ADAPT_length 693 * ELSE IF (ADAPT_range = COARSE) 694 * TADAPT_L0_L3 = 2^9 x (2^ADAPT_length) 695 * 696 * Returns calculated TAdapt value in term of Unit Intervals (UI) 697 */ 698 static inline u64 adapt_cap_to_t_adapt_l0l3(u32 adapt_cap) 699 { 700 u64 tadapt; 701 u8 adapt_length = adapt_cap & ADAPT_LENGTH_MASK; 702 703 if (!IS_ADAPT_RANGE_COARSE(adapt_cap)) 704 tadapt = TADAPT_L0L3_FACTOR * adapt_length; 705 else 706 tadapt = TADAPT_L0L3_FACTOR * (1 << adapt_length); 707 708 return tadapt; 709 } 710 711 /** 712 * adapt_cap_to_t_adapt_l0l1l2l3 - Calculate TAdapt_L0_L1_L2_L3 from adapt capability 713 * @adapt_cap: Adapt capability 714 * 715 * For PAM-4: 716 * IF (ADAPT_range_L0_L1_L2_L3 = FINE) 717 * TADAPT_L0_L1_L2_L3 = 2^15 x (ADAPT_length_L0_L1_L2_L3 + 1) 718 * ELSE IF (ADAPT_range_L0_L1_L2_L3 = COARSE) 719 * TADAPT_L0_L1_L2_L3 = 2^15 x 2^ADAPT_length_L0_L1_L2_L3 720 * 721 * Returns calculated TAdapt value in term of Unit Intervals (UI) 722 */ 723 static inline u64 adapt_cap_to_t_adapt_l0l1l2l3(u32 adapt_cap) 724 { 725 u64 tadapt; 726 u8 adapt_length = adapt_cap & ADAPT_LENGTH_MASK; 727 728 if (!IS_ADAPT_RANGE_COARSE(adapt_cap)) 729 tadapt = TADAPT_L0L1L2L3_FACTOR * (adapt_length + 1); 730 else 731 tadapt = TADAPT_L0L1L2L3_FACTOR * (1 << adapt_length); 732 733 return tadapt; 734 } 735 736 /** 737 * ufshcd_setup_tx_eqtr_adapt_length - Setup TX adapt length for EQTR 738 * @hba: per adapter instance 739 * @params: TX EQ parameters data structure 740 * @gear: target gear for EQTR 741 * 742 * This function determines and configures the proper TX adapt length (TAdapt) 743 * for the TX EQTR procedure based on the target gear and RX adapt capabilities 744 * of both host and device. 745 * 746 * Guidelines from MIPI UniPro v3.0 spec - select the minimum Adapt Length for 747 * the Equalization Training procedure based on the following conditions: 748 * 749 * If the target High-Speed Gear n is HS-G4 or HS-G5: 750 * PA_TxAdaptLength_EQTR[7:0] >= Max (10us, RX_HS_Gn_ADAPT_INITIAL_Capability, 751 * PA_PeerRxHsGnAdaptInitial) 752 * PA_TxAdaptLength_EQTR[7:0] shall be shorter than PACP_REQUEST_TIMER (10ms) 753 * PA_TxAdaptLength_EQTR[15:8] is not relevant for HS-G4 and HS-G5. This field 754 * is set to 255 (reserved value). 755 * 756 * If the target High-Speed Gear n is HS-G6: 757 * PA_TxAdapthLength_EQTR >= 10us 758 * PA_TxAdapthLength_EQTR[7:0] >= Max (RX_HS_G6_ADAPT_INITIAL_Capability, 759 * PA_PeerRxHsG6AdaptInitialL0L3) 760 * PA_TxAdapthLength_EQTR[15:8] >= Max (RX_HS_G6_ADAPT_INITIAL_L0_L1_L2_L3_Capability, 761 * PA_PeerRxHsG6AdaptInitialL0L1L2L3) 762 * PA_TxAdaptLength_EQTR shall be shorter than PACP_REQUEST_TIMER value of 10ms. 763 * 764 * Since adapt capabilities encode both range (fine/coarse) and length values, 765 * direct comparison is not possible. This function converts adapt capabilities 766 * to actual time durations in Unit Intervals (UI) using the Adapt time 767 * calculation formular in M-PHY v6.0 spec (Table 8), then selects the maximum 768 * to ensure both host and device use adequate TX adapt length. 769 * 770 * Returns 0 on success, negative error code otherwise 771 */ 772 static int ufshcd_setup_tx_eqtr_adapt_length(struct ufs_hba *hba, 773 struct ufshcd_tx_eq_params *params, 774 u32 gear) 775 { 776 struct ufshcd_tx_eqtr_record *rec = params->eqtr_record; 777 u32 adapt_eqtr; 778 int ret; 779 780 if (rec && rec->saved_adapt_eqtr) { 781 adapt_eqtr = rec->saved_adapt_eqtr; 782 goto set_adapt_eqtr; 783 } 784 785 if (gear == UFS_HS_G4 || gear == UFS_HS_G5) { 786 u64 t_adapt, t_adapt_local, t_adapt_peer; 787 u32 adapt_cap_local, adapt_cap_peer, adapt_length; 788 789 ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(rx_adapt_initial_cap[gear - 1], 790 UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 791 &adapt_cap_local); 792 if (ret) 793 return ret; 794 795 if (adapt_cap_local > ADAPT_LENGTH_MAX) { 796 dev_err(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_CAP (0x%x) exceeds MAX\n", 797 gear, adapt_cap_local); 798 return -EINVAL; 799 } 800 801 ret = ufshcd_dme_get(hba, UIC_ARG_MIB(pa_peer_rx_adapt_initial[gear - 1]), 802 &adapt_cap_peer); 803 if (ret) 804 return ret; 805 806 if (adapt_cap_peer > ADAPT_LENGTH_MAX) { 807 dev_err(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_CAP (0x%x) exceeds MAX\n", 808 gear, adapt_cap_peer); 809 return -EINVAL; 810 } 811 812 t_adapt_local = adapt_cap_to_t_adapt(adapt_cap_local); 813 t_adapt_peer = adapt_cap_to_t_adapt(adapt_cap_peer); 814 t_adapt = max(t_adapt_local, t_adapt_peer); 815 816 dev_dbg(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_CAP = 0x%x\n", 817 gear, adapt_cap_local); 818 dev_dbg(hba->dev, "peer RX_HS_G%u_ADAPT_INITIAL_CAP = 0x%x\n", 819 gear, adapt_cap_peer); 820 dev_dbg(hba->dev, "t_adapt_local = %llu UI, t_adapt_peer = %llu UI\n", 821 t_adapt_local, t_adapt_peer); 822 dev_dbg(hba->dev, "TAdapt %llu UI selected for TX EQTR\n", 823 t_adapt); 824 825 adapt_length = (t_adapt_local >= t_adapt_peer) ? 826 adapt_cap_local : adapt_cap_peer; 827 828 if (gear == UFS_HS_G4 && t_adapt < TX_EQTR_HS_G4_MIN_T_ADAPT) { 829 dev_dbg(hba->dev, "TAdapt %llu UI is too short for TX EQTR for HS-G%u, use default Adapt 0x%x\n", 830 t_adapt, gear, TX_EQTR_HS_G4_ADAPT_DEFAULT); 831 adapt_length = TX_EQTR_HS_G4_ADAPT_DEFAULT; 832 } else if (gear == UFS_HS_G5 && t_adapt < TX_EQTR_HS_G5_MIN_T_ADAPT) { 833 dev_dbg(hba->dev, "TAdapt %llu UI is too short for TX EQTR for HS-G%u, use default Adapt 0x%x\n", 834 t_adapt, gear, TX_EQTR_HS_G5_ADAPT_DEFAULT); 835 adapt_length = TX_EQTR_HS_G5_ADAPT_DEFAULT; 836 } 837 838 adapt_eqtr = adapt_length | 839 (TX_EQTR_ADAPT_RESERVED << TX_EQTR_ADAPT_LENGTH_L0L1L2L3_SHIFT); 840 } else if (gear == UFS_HS_G6) { 841 u64 t_adapt, t_adapt_l0l3, t_adapt_l0l3_local, t_adapt_l0l3_peer; 842 u64 t_adapt_l0l1l2l3, t_adapt_l0l1l2l3_local, t_adapt_l0l1l2l3_peer; 843 u32 adapt_l0l3_cap_local, adapt_l0l3_cap_peer, adapt_length_l0l3; 844 u32 adapt_l0l1l2l3_cap_local, adapt_l0l1l2l3_cap_peer, adapt_length_l0l1l2l3; 845 846 ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(rx_adapt_initial_cap[gear - 1], 847 UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 848 &adapt_l0l3_cap_local); 849 if (ret) 850 return ret; 851 852 if (adapt_l0l3_cap_local > ADAPT_L0L3_LENGTH_MAX) { 853 dev_err(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_CAP (0x%x) exceeds MAX\n", 854 gear, adapt_l0l3_cap_local); 855 return -EINVAL; 856 } 857 858 ret = ufshcd_dme_get(hba, UIC_ARG_MIB(pa_peer_rx_adapt_initial[gear - 1]), 859 &adapt_l0l3_cap_peer); 860 if (ret) 861 return ret; 862 863 if (adapt_l0l3_cap_peer > ADAPT_L0L3_LENGTH_MAX) { 864 dev_err(hba->dev, "peer RX_HS_G%u_ADAPT_INITIAL_CAP (0x%x) exceeds MAX\n", 865 gear, adapt_l0l3_cap_peer); 866 return -EINVAL; 867 } 868 869 t_adapt_l0l3_local = adapt_cap_to_t_adapt_l0l3(adapt_l0l3_cap_local); 870 t_adapt_l0l3_peer = adapt_cap_to_t_adapt_l0l3(adapt_l0l3_cap_peer); 871 872 dev_dbg(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_CAP = 0x%x\n", 873 gear, adapt_l0l3_cap_local); 874 dev_dbg(hba->dev, "peer RX_HS_G%u_ADAPT_INITIAL_CAP = 0x%x\n", 875 gear, adapt_l0l3_cap_peer); 876 dev_dbg(hba->dev, "t_adapt_l0l3_local = %llu UI, t_adapt_l0l3_peer = %llu UI\n", 877 t_adapt_l0l3_local, t_adapt_l0l3_peer); 878 879 ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(RX_HS_G6_ADAPT_INITIAL_L0L1L2L3_CAP, 880 UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 881 &adapt_l0l1l2l3_cap_local); 882 if (ret) 883 return ret; 884 885 if (adapt_l0l1l2l3_cap_local > ADAPT_L0L1L2L3_LENGTH_MAX) { 886 dev_err(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_L0L1L2L3_CAP (0x%x) exceeds MAX\n", 887 gear, adapt_l0l1l2l3_cap_local); 888 889 if (!(hba->quirks & UFSHCD_QUIRK_EXTENDED_TX_EQTR_ADAPT_LENGTH_L0L1L2L3)) 890 return -EINVAL; 891 } 892 893 ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PEERRXHSG6ADAPTINITIALL0L1L2L3), 894 &adapt_l0l1l2l3_cap_peer); 895 if (ret) 896 return ret; 897 898 if (adapt_l0l1l2l3_cap_peer > ADAPT_L0L1L2L3_LENGTH_MAX) { 899 dev_err(hba->dev, "peer RX_HS_G%u_ADAPT_INITIAL_L0L1L2L3_CAP (0x%x) exceeds MAX\n", 900 gear, adapt_l0l1l2l3_cap_peer); 901 902 if (!(hba->quirks & UFSHCD_QUIRK_EXTENDED_TX_EQTR_ADAPT_LENGTH_L0L1L2L3)) 903 return -EINVAL; 904 } 905 906 t_adapt_l0l1l2l3_local = adapt_cap_to_t_adapt_l0l1l2l3(adapt_l0l1l2l3_cap_local); 907 t_adapt_l0l1l2l3_peer = adapt_cap_to_t_adapt_l0l1l2l3(adapt_l0l1l2l3_cap_peer); 908 909 dev_dbg(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_L0L1L2L3_CAP = 0x%x\n", 910 gear, adapt_l0l1l2l3_cap_local); 911 dev_dbg(hba->dev, "peer RX_HS_G%u_ADAPT_INITIAL_L0L1L2L3_CAP = 0x%x\n", 912 gear, adapt_l0l1l2l3_cap_peer); 913 dev_dbg(hba->dev, "t_adapt_l0l1l2l3_local = %llu UI, t_adapt_l0l1l2l3_peer = %llu UI\n", 914 t_adapt_l0l1l2l3_local, t_adapt_l0l1l2l3_peer); 915 916 t_adapt_l0l1l2l3 = max(t_adapt_l0l1l2l3_local, t_adapt_l0l1l2l3_peer); 917 t_adapt_l0l3 = max(t_adapt_l0l3_local, t_adapt_l0l3_peer); 918 t_adapt = t_adapt_l0l3 + t_adapt_l0l1l2l3; 919 920 dev_dbg(hba->dev, "TAdapt %llu PAM-4 UI selected for TX EQTR\n", 921 t_adapt); 922 923 adapt_length_l0l3 = (t_adapt_l0l3_local >= t_adapt_l0l3_peer) ? 924 adapt_l0l3_cap_local : adapt_l0l3_cap_peer; 925 adapt_length_l0l1l2l3 = (t_adapt_l0l1l2l3_local >= t_adapt_l0l1l2l3_peer) ? 926 adapt_l0l1l2l3_cap_local : adapt_l0l1l2l3_cap_peer; 927 928 if (t_adapt < TX_EQTR_HS_G6_MIN_T_ADAPT) { 929 dev_dbg(hba->dev, "TAdapt %llu UI is too short for TX EQTR for HS-G%u, use default Adapt 0x%x\n", 930 t_adapt, gear, TX_EQTR_HS_G6_ADAPT_DEFAULT); 931 adapt_length_l0l3 = TX_EQTR_HS_G6_ADAPT_DEFAULT; 932 } 933 934 adapt_eqtr = adapt_length_l0l3 | 935 (adapt_length_l0l1l2l3 << TX_EQTR_ADAPT_LENGTH_L0L1L2L3_SHIFT); 936 } else { 937 return -EINVAL; 938 } 939 940 if (rec) 941 rec->saved_adapt_eqtr = (u16)adapt_eqtr; 942 943 set_adapt_eqtr: 944 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXADAPTLENGTH_EQTR), adapt_eqtr); 945 if (ret) 946 dev_err(hba->dev, "Failed to set adapt length for TX EQTR: %d\n", ret); 947 else 948 dev_dbg(hba->dev, "PA_TXADAPTLENGTH_EQTR configured to 0x%08x\n", adapt_eqtr); 949 950 return ret; 951 } 952 953 /** 954 * ufshcd_compose_tx_eqtr_setting - Compose TX EQTR setting 955 * @iter: TX EQTR iterator data structure 956 * @num_lanes: number of active lanes 957 * 958 * Returns composed TX EQTR setting, same setting is used for all active lanes 959 */ 960 static inline u32 ufshcd_compose_tx_eqtr_setting(struct tx_eqtr_iter *iter, 961 int num_lanes) 962 { 963 u32 setting = 0; 964 int lane; 965 966 for (lane = 0; lane < num_lanes; lane++) { 967 setting |= TX_HS_PRESHOOT_BITS(lane, iter->preshoot); 968 setting |= TX_HS_DEEMPHASIS_BITS(lane, iter->deemphasis); 969 } 970 971 return setting; 972 } 973 974 /** 975 * ufshcd_apply_tx_eqtr_settings - Apply TX EQTR setting 976 * @hba: per adapter instance 977 * @pwr_mode: target power mode containing gear and rate information 978 * @h_iter: host TX EQTR iterator data structure 979 * @d_iter: device TX EQTR iterator data structure 980 * 981 * Returns 0 on success, negative error code otherwise 982 */ 983 static int ufshcd_apply_tx_eqtr_settings(struct ufs_hba *hba, 984 struct ufs_pa_layer_attr *pwr_mode, 985 struct tx_eqtr_iter *h_iter, 986 struct tx_eqtr_iter *d_iter) 987 { 988 u32 setting; 989 int ret; 990 991 setting = ufshcd_compose_tx_eqtr_setting(h_iter, pwr_mode->lane_tx); 992 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXEQTRSETTING), setting); 993 if (ret) 994 return ret; 995 996 setting = ufshcd_compose_tx_eqtr_setting(d_iter, pwr_mode->lane_rx); 997 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PEERTXEQTRSETTING), setting); 998 if (ret) 999 return ret; 1000 1001 ret = ufshcd_vops_apply_tx_eqtr_settings(hba, pwr_mode, h_iter, d_iter); 1002 1003 return ret; 1004 } 1005 1006 /** 1007 * ufshcd_update_tx_eq_params - Update TX Equalization params 1008 * @params: TX EQ parameters data structure 1009 * @pwr_mode: target power mode containing gear and rate 1010 * @eqtr_data: TX EQTR data structure 1011 * 1012 * Update TX Equalization params using results from TX EQTR data. Check also 1013 * the TX EQTR FOM value for each TX lane in the TX EQTR data. If a TX lane got 1014 * a FOM value of 0, restore the TX Equalization settings from the last known 1015 * valid TX Equalization params for that specific TX lane. 1016 */ 1017 static inline void 1018 ufshcd_update_tx_eq_params(struct ufshcd_tx_eq_params *params, 1019 struct ufs_pa_layer_attr *pwr_mode, 1020 struct ufshcd_tx_eqtr_data *eqtr_data) 1021 { 1022 struct ufshcd_tx_eqtr_record *rec = params->eqtr_record; 1023 1024 if (params->is_valid) { 1025 int lane; 1026 1027 for (lane = 0; lane < pwr_mode->lane_tx; lane++) 1028 if (eqtr_data->host[lane].fom_val == 0) 1029 eqtr_data->host[lane] = params->host[lane]; 1030 1031 for (lane = 0; lane < pwr_mode->lane_rx; lane++) 1032 if (eqtr_data->device[lane].fom_val == 0) 1033 eqtr_data->device[lane] = params->device[lane]; 1034 } 1035 1036 memcpy(params->host, eqtr_data->host, sizeof(params->host)); 1037 memcpy(params->device, eqtr_data->device, sizeof(params->device)); 1038 1039 if (!rec) 1040 return; 1041 1042 memcpy(rec->host_fom, eqtr_data->host_fom, sizeof(rec->host_fom)); 1043 memcpy(rec->device_fom, eqtr_data->device_fom, sizeof(rec->device_fom)); 1044 rec->last_record_ts = ktime_get(); 1045 rec->last_record_index++; 1046 } 1047 1048 /** 1049 * __ufshcd_tx_eqtr - TX Equalization Training (EQTR) procedure 1050 * @hba: per adapter instance 1051 * @params: TX EQ parameters data structure 1052 * @pwr_mode: target power mode containing gear and rate information 1053 * 1054 * This function implements the complete TX EQTR procedure as defined in UFSHCI 1055 * v5.0 specification. It iterates through all possible combinations of PreShoot 1056 * and DeEmphasis settings to find the optimal TX Equalization settings for all 1057 * active lanes. 1058 * 1059 * Returns 0 on success, negative error code otherwise 1060 */ 1061 static int __ufshcd_tx_eqtr(struct ufs_hba *hba, 1062 struct ufshcd_tx_eq_params *params, 1063 struct ufs_pa_layer_attr *pwr_mode) 1064 { 1065 struct ufshcd_tx_eqtr_data *eqtr_data __free(kfree) = 1066 kzalloc(sizeof(*eqtr_data), GFP_KERNEL); 1067 struct tx_eqtr_iter h_iter = {}; 1068 struct tx_eqtr_iter d_iter = {}; 1069 u32 gear = pwr_mode->gear_tx; 1070 u8 preshoot, deemphasis; 1071 ktime_t start; 1072 int ret; 1073 1074 if (!eqtr_data) 1075 return -ENOMEM; 1076 1077 dev_info(hba->dev, "Start TX EQTR procedure for HS-G%u, Rate-%s, RX Lanes: %u, TX Lanes: %u\n", 1078 gear, ufs_hs_rate_to_str(pwr_mode->hs_rate), 1079 pwr_mode->lane_rx, pwr_mode->lane_tx); 1080 1081 start = ktime_get(); 1082 1083 /* Step 1 - Determine the TX Adapt Length for EQTR */ 1084 ret = ufshcd_setup_tx_eqtr_adapt_length(hba, params, gear); 1085 if (ret) { 1086 dev_err(hba->dev, "Failed to setup TX EQTR Adaptation length: %d\n", ret); 1087 return ret; 1088 } 1089 1090 /* Step 2 - Determine TX Equalization setting capabilities */ 1091 ret = ufshcd_tx_eqtr_iter_init(hba, &h_iter, &d_iter); 1092 if (ret) { 1093 dev_err(hba->dev, "Failed to init TX EQTR data: %d\n", ret); 1094 return ret; 1095 } 1096 1097 /* TX EQTR main loop */ 1098 for (preshoot = 0; preshoot < TX_HS_NUM_PRESHOOT; preshoot++) { 1099 for (deemphasis = 0; deemphasis < TX_HS_NUM_DEEMPHASIS; deemphasis++) { 1100 if (!tx_eqtr_iter_update(preshoot, deemphasis, &h_iter, &d_iter)) 1101 continue; 1102 1103 /* Step 3 - Apply TX EQTR settings */ 1104 ret = ufshcd_apply_tx_eqtr_settings(hba, pwr_mode, &h_iter, &d_iter); 1105 if (ret) { 1106 dev_err(hba->dev, "Failed to apply TX EQTR settings (PreShoot %u, DeEmphasis %u): %d\n", 1107 preshoot, deemphasis, ret); 1108 return ret; 1109 } 1110 1111 /* Step 4 - Trigger UIC TX EQTR */ 1112 ret = ufshcd_uic_tx_eqtr(hba, gear); 1113 if (ret) { 1114 dev_err(hba->dev, "Failed to trigger UIC TX EQTR for target gear %u: %d\n", 1115 gear, ret); 1116 return ret; 1117 } 1118 1119 /* Step 5 - Get FOM */ 1120 ret = ufshcd_get_rx_fom(hba, pwr_mode, &h_iter, &d_iter); 1121 if (ret) { 1122 dev_err(hba->dev, "Failed to get RX_FOM: %d\n", 1123 ret); 1124 return ret; 1125 } 1126 1127 ufshcd_evaluate_tx_eqtr_fom(hba, pwr_mode, eqtr_data, &h_iter, &d_iter); 1128 } 1129 } 1130 1131 dev_info(hba->dev, "TX EQTR procedure completed! Time elapsed: %llu ms\n", 1132 ktime_to_ms(ktime_sub(ktime_get(), start))); 1133 1134 ufshcd_update_tx_eq_params(params, pwr_mode, eqtr_data); 1135 1136 return ret; 1137 } 1138 1139 /** 1140 * ufshcd_tx_eqtr_prepare - Prepare UFS link for TX EQTR procedure 1141 * @hba: per adapter instance 1142 * @pwr_mode: target power mode containing gear and rate 1143 * 1144 * This function prepares the UFS link for TX Equalization Training (EQTR) by 1145 * establishing the proper initial conditions required by the EQTR procedure. 1146 * It ensures that EQTR starts from the most reliable Power Mode (HS-G1) with 1147 * all connected lanes activated and sets host TX HS Adapt Type to INITIAL. 1148 * 1149 * Returns 0 on successful preparation, negative error code on failure 1150 */ 1151 static int ufshcd_tx_eqtr_prepare(struct ufs_hba *hba, 1152 struct ufs_pa_layer_attr *pwr_mode) 1153 { 1154 struct ufs_pa_layer_attr pwr_mode_hs_g1 = { 1155 /* TX EQTR shall be initiated from the most reliable HS-G1 */ 1156 .gear_rx = UFS_HS_G1, 1157 .gear_tx = UFS_HS_G1, 1158 .lane_rx = pwr_mode->lane_rx, 1159 .lane_tx = pwr_mode->lane_tx, 1160 .pwr_rx = FAST_MODE, 1161 .pwr_tx = FAST_MODE, 1162 /* Use the target power mode's HS rate */ 1163 .hs_rate = pwr_mode->hs_rate, 1164 }; 1165 u32 rate = pwr_mode->hs_rate; 1166 int ret; 1167 1168 /* Change power mode to HS-G1, activate all connected lanes. */ 1169 ret = ufshcd_change_power_mode(hba, &pwr_mode_hs_g1, 1170 UFSHCD_PMC_POLICY_DONT_FORCE); 1171 if (ret) { 1172 dev_err(hba->dev, "TX EQTR: Failed to change power mode to HS-G1, Rate-%s: %d\n", 1173 ufs_hs_rate_to_str(rate), ret); 1174 return ret; 1175 } 1176 1177 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXHSADAPTTYPE), 1178 PA_INITIAL_ADAPT); 1179 if (ret) 1180 dev_err(hba->dev, "TX EQTR: Failed to set Host Adapt type to INITIAL: %d\n", 1181 ret); 1182 1183 return ret; 1184 } 1185 1186 static void ufshcd_tx_eqtr_unprepare(struct ufs_hba *hba, 1187 struct ufs_pa_layer_attr *pwr_mode) 1188 { 1189 int err; 1190 1191 if (pwr_mode->pwr_rx == SLOWAUTO_MODE || pwr_mode->hs_rate == 0) 1192 return; 1193 1194 err = ufshcd_change_power_mode(hba, pwr_mode, 1195 UFSHCD_PMC_POLICY_DONT_FORCE); 1196 if (err) 1197 dev_err(hba->dev, "%s: Failed to restore Power Mode: %d\n", 1198 __func__, err); 1199 } 1200 1201 /** 1202 * ufshcd_tx_eqtr - Perform TX EQTR procedures with vops callbacks 1203 * @hba: per adapter instance 1204 * @params: TX EQ parameters data structure to populate 1205 * @pwr_mode: target power mode containing gear and rate information 1206 * 1207 * This is the main entry point for performing TX Equalization Training (EQTR) 1208 * procedure as defined in UFSCHI v5.0 specification. It serves as a wrapper 1209 * around __ufshcd_tx_eqtr() to provide vops support through the variant 1210 * operations framework. 1211 * 1212 * Returns 0 on success, negative error code on failure 1213 */ 1214 static int ufshcd_tx_eqtr(struct ufs_hba *hba, 1215 struct ufshcd_tx_eq_params *params, 1216 struct ufs_pa_layer_attr *pwr_mode) 1217 { 1218 struct ufs_pa_layer_attr old_pwr_info; 1219 int ret; 1220 1221 if (!params->eqtr_record) { 1222 params->eqtr_record = devm_kzalloc(hba->dev, 1223 sizeof(*params->eqtr_record), 1224 GFP_KERNEL); 1225 if (!params->eqtr_record) 1226 return -ENOMEM; 1227 } 1228 1229 memcpy(&old_pwr_info, &hba->pwr_info, sizeof(struct ufs_pa_layer_attr)); 1230 1231 ret = ufshcd_tx_eqtr_prepare(hba, pwr_mode); 1232 if (ret) { 1233 dev_err(hba->dev, "Failed to prepare TX EQTR: %d\n", ret); 1234 goto out; 1235 } 1236 1237 ret = ufshcd_vops_tx_eqtr_notify(hba, PRE_CHANGE, pwr_mode); 1238 if (ret) 1239 goto out; 1240 1241 ret = __ufshcd_tx_eqtr(hba, params, pwr_mode); 1242 if (ret) 1243 goto out; 1244 1245 ret = ufshcd_vops_tx_eqtr_notify(hba, POST_CHANGE, pwr_mode); 1246 1247 out: 1248 if (ret) 1249 ufshcd_tx_eqtr_unprepare(hba, &old_pwr_info); 1250 1251 return ret; 1252 } 1253 1254 /** 1255 * ufshcd_config_tx_eq_settings - Configure TX Equalization settings 1256 * @hba: per adapter instance 1257 * @pwr_mode: target power mode containing gear and rate information 1258 * @force_tx_eqtr: execute the TX EQTR procedure 1259 * 1260 * This function finds and sets the TX Equalization settings for the given 1261 * target power mode. 1262 * 1263 * Returns 0 on success, error code otherwise 1264 */ 1265 int ufshcd_config_tx_eq_settings(struct ufs_hba *hba, 1266 struct ufs_pa_layer_attr *pwr_mode, 1267 bool force_tx_eqtr) 1268 { 1269 struct ufshcd_tx_eq_params *params; 1270 u32 gear, rate; 1271 1272 if (!ufshcd_is_tx_eq_supported(hba) || !use_adaptive_txeq) 1273 return 0; 1274 1275 if (!hba->max_pwr_info.is_valid) { 1276 dev_err(hba->dev, "Max power info is invalid\n"); 1277 return -EINVAL; 1278 } 1279 1280 if (!pwr_mode) { 1281 dev_err(hba->dev, "Target power mode is NULL\n"); 1282 return -EINVAL; 1283 } 1284 1285 gear = pwr_mode->gear_tx; 1286 rate = pwr_mode->hs_rate; 1287 1288 if (gear < UFS_HS_G1 || gear > UFS_HS_GEAR_MAX) { 1289 dev_err(hba->dev, "Invalid HS-Gear (%u) for TX Equalization\n", 1290 gear); 1291 return -EINVAL; 1292 } else if (gear < max_t(u32, adaptive_txeq_gear, UFS_HS_G4)) { 1293 /* TX EQTR is supported for HS-G4 and higher Gears */ 1294 return 0; 1295 } 1296 1297 if (rate != PA_HS_MODE_A && rate != PA_HS_MODE_B) { 1298 dev_err(hba->dev, "Invalid HS-Rate (%u) for TX Equalization\n", 1299 rate); 1300 return -EINVAL; 1301 } 1302 1303 params = &hba->tx_eq_params[gear - 1]; 1304 if (!params->is_valid || force_tx_eqtr) { 1305 int ret; 1306 1307 ret = ufshcd_tx_eqtr(hba, params, pwr_mode); 1308 if (ret) { 1309 dev_err(hba->dev, "Failed to train TX Equalization for HS-G%u, Rate-%s: %d\n", 1310 gear, ufs_hs_rate_to_str(rate), ret); 1311 return ret; 1312 } 1313 1314 /* Mark TX Equalization settings as valid */ 1315 params->is_valid = true; 1316 params->is_trained = true; 1317 params->is_applied = false; 1318 } 1319 1320 if (params->is_valid && !params->is_applied) { 1321 int ret; 1322 1323 ret = ufshcd_apply_tx_eq_settings(hba, params, gear); 1324 if (ret) { 1325 dev_err(hba->dev, "Failed to apply TX Equalization settings for HS-G%u, Rate-%s: %d\n", 1326 gear, ufs_hs_rate_to_str(rate), ret); 1327 return ret; 1328 } 1329 1330 params->is_applied = true; 1331 } 1332 1333 return 0; 1334 } 1335 1336 /** 1337 * ufshcd_apply_valid_tx_eq_settings - Apply valid TX Equalization settings 1338 * @hba: per-adapter instance 1339 * 1340 * This function iterates through all supported High-Speed (HS) gears and 1341 * applies valid TX Equalization settings to both Host and Device. 1342 */ 1343 void ufshcd_apply_valid_tx_eq_settings(struct ufs_hba *hba) 1344 { 1345 struct ufshcd_tx_eq_params *params; 1346 int gear, err; 1347 1348 if (!ufshcd_is_tx_eq_supported(hba)) 1349 return; 1350 1351 if (!hba->max_pwr_info.is_valid) { 1352 dev_err(hba->dev, "Max power info is invalid, cannot apply TX Equalization settings\n"); 1353 return; 1354 } 1355 1356 for (gear = UFS_HS_G1; gear <= UFS_HS_GEAR_MAX; gear++) { 1357 params = &hba->tx_eq_params[gear - 1]; 1358 1359 if (params->is_valid) { 1360 err = ufshcd_apply_tx_eq_settings(hba, params, gear); 1361 if (err) { 1362 params->is_applied = false; 1363 dev_err(hba->dev, "Failed to apply TX Equalization settings for HS-G%u: %d\n", 1364 gear, err); 1365 } else { 1366 params->is_applied = true; 1367 } 1368 } 1369 } 1370 } 1371 1372 /** 1373 * ufshcd_retrain_tx_eq - Retrain TX Equalization and apply new settings 1374 * @hba: per-adapter instance 1375 * @gear: target High-Speed (HS) gear for retraining 1376 * 1377 * This function initiates a refresh of the TX Equalization settings for a 1378 * specific HS gear. It scales the clocks to maximum frequency, negotiates the 1379 * power mode with the device, retrains TX EQ and applies new TX EQ settings 1380 * by conducting a Power Mode change. 1381 * 1382 * Returns 0 on success, non-zero error code otherwise 1383 */ 1384 int ufshcd_retrain_tx_eq(struct ufs_hba *hba, u32 gear) 1385 { 1386 struct ufs_pa_layer_attr new_pwr_info, final_params = {}; 1387 int ret; 1388 1389 if (!ufshcd_is_tx_eq_supported(hba) || !use_adaptive_txeq) 1390 return -EOPNOTSUPP; 1391 1392 if (gear < adaptive_txeq_gear) 1393 return -ERANGE; 1394 1395 ufshcd_hold(hba); 1396 1397 ret = ufshcd_pause_command_processing(hba, 1 * USEC_PER_SEC); 1398 if (ret) { 1399 ufshcd_release(hba); 1400 return ret; 1401 } 1402 1403 /* scale up clocks to max frequency before TX EQTR */ 1404 if (ufshcd_is_clkscaling_supported(hba)) 1405 ufshcd_scale_clks(hba, ULONG_MAX, true); 1406 1407 new_pwr_info = hba->pwr_info; 1408 new_pwr_info.gear_tx = gear; 1409 new_pwr_info.gear_rx = gear; 1410 1411 ret = ufshcd_vops_negotiate_pwr_mode(hba, &new_pwr_info, &final_params); 1412 if (ret) 1413 memcpy(&final_params, &new_pwr_info, sizeof(final_params)); 1414 1415 if (final_params.gear_tx != gear) { 1416 dev_err(hba->dev, "Negotiated Gear (%u) does not match target Gear (%u)\n", 1417 final_params.gear_tx, gear); 1418 ret = -EINVAL; 1419 goto out; 1420 } 1421 1422 ret = ufshcd_config_tx_eq_settings(hba, &final_params, true); 1423 if (ret) { 1424 dev_err(hba->dev, "Failed to config TX Equalization for HS-G%u, Rate-%s: %d\n", 1425 final_params.gear_tx, 1426 ufs_hs_rate_to_str(final_params.hs_rate), ret); 1427 goto out; 1428 } 1429 1430 /* Change Power Mode to apply the new TX EQ settings */ 1431 ret = ufshcd_change_power_mode(hba, &final_params, 1432 UFSHCD_PMC_POLICY_FORCE); 1433 if (ret) 1434 dev_err(hba->dev, "%s: Failed to change Power Mode to HS-G%u, Rate-%s: %d\n", 1435 __func__, final_params.gear_tx, 1436 ufs_hs_rate_to_str(final_params.hs_rate), ret); 1437 1438 out: 1439 ufshcd_resume_command_processing(hba); 1440 ufshcd_release(hba); 1441 1442 return ret; 1443 } 1444 1445 /** 1446 * ufshcd_extract_tx_eq_settings_attrs - Extract TX Equalization settings from UFS attributes 1447 * @hba: per adapter instance 1448 * @gear: target gear 1449 * 1450 * This function extracts previously stored TX Equalization settings from UFS 1451 * attributes qTxEQGnSettings and wTxEQGnSettingsExt. These attributes contain 1452 * the optimal TX Equalization parameters (PreShoot, DeEmphasis, and PreCoding 1453 * enable) that were determined during a previous EQTR procedure. 1454 * 1455 * The function reads: 1456 * 1. qTxEQGnSettings (64-bit): Main attribute containing PreShoot and 1457 * DeEmphasis values for both host and device TX lanes 1458 * 2. wTxEQGnSettingsExt (16-bit): Extended attribute containing PreCoding 1459 * enable flags and validity indicator 1460 */ 1461 static void ufshcd_extract_tx_eq_settings_attrs(struct ufs_hba *hba, u8 gear) 1462 { 1463 struct ufshcd_tx_eq_params *params; 1464 u32 lane, eq_ext; 1465 int ret; 1466 u64 eq; 1467 1468 ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, 1469 QUERY_ATTR_IDN_TX_EQ_GN_SETTINGS_EXT, gear - 1, 1470 (u8)txeq_setting_sel, &eq_ext); 1471 if (ret) 1472 return; 1473 1474 dev_dbg(hba->dev, "%s: HS-G%u wTxEQGnSettingsExt (Selector %u) = 0x%08x\n", 1475 __func__, gear, txeq_setting_sel, eq_ext); 1476 1477 if (!(eq_ext & TX_EQ_SETTINGS_VALID_BIT)) 1478 return; 1479 1480 ret = ufshcd_query_attr_qword(hba, UPIU_QUERY_OPCODE_READ_ATTR, 1481 QUERY_ATTR_IDN_TX_EQ_GN_SETTINGS, 1482 gear - 1, (u8)txeq_setting_sel, &eq); 1483 if (ret) 1484 return; 1485 1486 dev_dbg(hba->dev, "%s: HS-G%u qTxEQGnSettings (Selector %u) = 0x%016llx\n", 1487 __func__, gear, txeq_setting_sel, eq); 1488 1489 params = &hba->tx_eq_params[gear - 1]; 1490 1491 for (lane = 0; lane < UFS_MAX_LANES; lane++) { 1492 params->host[lane].preshoot = tx_eq_host_preshoot_decode(eq, lane); 1493 params->host[lane].deemphasis = tx_eq_host_deemphasis_decode(eq, lane); 1494 params->host[lane].precode_en = tx_eq_host_precode_en_decode(eq_ext, lane); 1495 1496 params->device[lane].preshoot = tx_eq_device_preshoot_decode(eq, lane); 1497 params->device[lane].deemphasis = tx_eq_device_deemphasis_decode(eq, lane); 1498 params->device[lane].precode_en = tx_eq_device_precode_en_decode(eq_ext, lane); 1499 } 1500 1501 params->is_valid = true; 1502 } 1503 1504 void ufshcd_retrieve_tx_eq_settings(struct ufs_hba *hba) 1505 { 1506 u8 gear = (u8)adaptive_txeq_gear; 1507 1508 if (!hba->max_pwr_info.is_valid || !ufshcd_is_tx_eq_supported(hba) || 1509 !use_adaptive_txeq || !retrieve_txeq_setting) 1510 return; 1511 1512 for (; gear <= UFS_HS_GEAR_MAX; gear++) 1513 ufshcd_extract_tx_eq_settings_attrs(hba, gear); 1514 } 1515 1516 /** 1517 * ufshcd_update_tx_eq_settings_attrs - Update TX EQ settings in UFS attributes 1518 * @hba: per adapter instance 1519 * @gear: target gear 1520 * 1521 * This function stores the optimal TX Equalization settings obtained from 1522 * TX EQTR procedure into UFS device attributes for future fast-path retrieval. 1523 * The settings are stored in two complementary attributes: 1524 * 1525 * 1. qTxEQGnSettings (64-bit): Main attribute containing PreShoot and 1526 * DeEmphasis values for both host and device TX lanes 1527 * 2. wTxEQGnSettingsExt (16-bit): Extended attribute containing PreCoding 1528 * enable flags and validity indicator 1529 */ 1530 static void ufshcd_update_tx_eq_settings_attrs(struct ufs_hba *hba, u8 gear) 1531 { 1532 struct ufshcd_tx_eq_params *params; 1533 u32 lane, eq_ext = 0; 1534 u64 eq = 0; 1535 int ret; 1536 1537 params = &hba->tx_eq_params[gear - 1]; 1538 if (!params->is_valid || !params->is_trained) 1539 return; 1540 1541 for (lane = 0; lane < UFS_MAX_LANES; lane++) { 1542 eq |= tx_eq_host_preshoot_encode((u64)params->host[lane].preshoot, lane); 1543 eq |= tx_eq_host_deemphasis_encode((u64)params->host[lane].deemphasis, lane); 1544 eq_ext |= tx_eq_host_precode_en_encode(params->host[lane].precode_en, lane); 1545 1546 eq |= tx_eq_device_preshoot_encode((u64)params->device[lane].preshoot, lane); 1547 eq |= tx_eq_device_deemphasis_encode((u64)params->device[lane].deemphasis, lane); 1548 eq_ext |= tx_eq_device_precode_en_encode(params->device[lane].precode_en, lane); 1549 } 1550 1551 /* Set validity flag to indicate valid settings are stored */ 1552 eq_ext |= TX_EQ_SETTINGS_VALID_BIT; 1553 1554 /* Write qTxEQGnSettings */ 1555 ret = ufshcd_query_attr_qword(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, 1556 QUERY_ATTR_IDN_TX_EQ_GN_SETTINGS, 1557 gear - 1, (u8)txeq_setting_sel, &eq); 1558 if (ret) 1559 return; 1560 1561 /* Write wTxEQGnSettingsExt */ 1562 ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, 1563 QUERY_ATTR_IDN_TX_EQ_GN_SETTINGS_EXT, gear - 1, 1564 (u8)txeq_setting_sel, &eq_ext); 1565 if (ret) 1566 return; 1567 1568 dev_dbg(hba->dev, "%s: Saved HS-G%u qTxEQGnSettings (Selector %u) = 0x%016llx\n", 1569 __func__, gear, txeq_setting_sel, eq); 1570 dev_dbg(hba->dev, "%s: Saved HS-G%u wTxEQGnSettingsExt (Selector %u) = 0x%08x\n", 1571 __func__, gear, txeq_setting_sel, eq_ext); 1572 } 1573 1574 void ufshcd_store_tx_eq_settings(struct ufs_hba *hba) 1575 { 1576 u8 gear = (u8)adaptive_txeq_gear; 1577 1578 if (!hba->max_pwr_info.is_valid || !ufshcd_is_tx_eq_supported(hba) || 1579 !use_adaptive_txeq || !store_txeq_setting) 1580 return; 1581 1582 for (; gear <= UFS_HS_GEAR_MAX; gear++) 1583 ufshcd_update_tx_eq_settings_attrs(hba, gear); 1584 } 1585