xref: /linux/drivers/ufs/core/ufs-txeq.c (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
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