Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge patch series "scsi: ufs: Add TX Equalization support for UFS 5.0"

Can Guo <can.guo@oss.qualcomm.com> says:

Hi,

The UFS v5.0 and UFSHCI v5.0 standards have published, introducing support
for HS-G6 (46.6 Gbps per lane) through the new UniPro V3.0 interconnect
layer and M-PHY V6.0 physical layer specifications. To achieve reliable
operation at these higher speeds, UniPro V3.0 introduces TX Equalization
and Pre-Coding mechanisms that are essential for signal integrity.

This patch series implements TX Equalization support in the UFS core
driver as specified in UFSHCI v5.0, along with the necessary vendor
operations and a reference implementation for Qualcomm UFS host
controllers.

Background
==========

TX Equalization is a signal conditioning technique that compensates for
channel impairments at high data rates (HS-G4 through HS-G6). It works
by adjusting two key parameters:

- PreShoot: Pre-emphasis applied before the main signal transition
- DeEmphasis: De-emphasis applied after the main signal transition

UniPro V3.0 defines TX Equalization Training (EQTR) procedure to
automatically discover optimal TX Equalization settings. The EQTR
procedure:

1. Starts from the most reliable link state (HS-G1)
2. Iterates through all possible PreShoot and DeEmphasis combinations
3. Evaluates signal quality using Figure of Merit (FOM) measurements
4. Selects the best settings for both host and device TX lanes

For HS-G6, Pre-Coding is also introduced to further improve signal
quality. Pre-Coding must be enabled on both transmitter and receiver
when the RX_FOM indicates it is required.

Implementation Overview
=======================

The implementation follows the UFSHCI v5.0 specification and consists of:

Core Infrastructure (Patches 1-6):
- New vops callback negotiate_pwr_mode() to allow vendors to negotiate
power mode parameters before applying TX Equalization settings
- Support for HS-G6 gear enumeration
- Complete TX EQTR procedure implementation in ufs-txeq.c
- Debugfs interface for TX Equalization parameter inspection and manual
retraining
- Module parameters for adaptive TX Equalization control

Qualcomm Implementation (Patches 7-11):
- PHY-specific configurations for TX EQTR procedure
- Vendor-specific FOM measurement support
- TX Equalization settings application
- Enable TX Equalization for HW version 0x7 and onwards

The implementation is designed to be vendor-agnostic, with platform-
specific details handled through the vops callbacks. Other vendors can
add support by implementing the three new vops:

- tx_eqtr_notify(): Called before/after TX EQTR for vendor setup
- apply_tx_eqtr_settings(): Apply vendor-specific PHY configurations
- get_rx_fom(): Retrieve vendor-specific FOM measurements if needed

Module Parameters
=================

The implementation provides several module parameters for flexibility:

- use_adaptive_txeq: Enable/disable adaptive TX Equalization (default: false)
- adaptive_txeq_gear: Minimum gear for adaptive TX EQ (default: HS-G6)
- use_txeq_presets: Use only the 8 standaird presets (default: false)
- txeq_presets_selected[]: Select specific presets for EQTR

Testing
=======

This patch series has been tested on Qualcomm platforms with UFS 5.0
devices, validating:

- Successful TX EQTR completion for HS-G6
- Proper FOM evaluation and optimal settings selection
- Pre-Coding enablement for HS-G6
- Power mode changes with TX Equalization settings applied
- Report of TX Equalization settings via debugfs entries
- Report of TX EQTR histories via debug entries (see next section)
- Re-training TX Equalization via debugfs entry

Example of TX EQTR history
==========================

Device TX EQTR record summary -
Target Power Mode: HS-G6, Rate-B
Most recent record index: 2
Most recent record timestamp: 219573378 us

TX Lane 0 FOM - PreShoot\DeEmphasis
\ 0 1 2 3 4 5 6 7
0 50 70 65 - - - - x
1 x x x x x x x x
2 100 90 70 - - - - x
3 x x x x x x x x
4 95 90 - - - - - x
5 - - - - - - - x
6 x x x x x x x x
7 x x x x x x x x

TX Lane 1 FOM - PreShoot\DeEmphasis
\ 0 1 2 3 4 5 6 7
0 50 70 60 - - - - x
1 x x x x x x x x
2 100 80 65 - - - - x
3 x x x x x x x x
4 95 85 - - - - - x
5 - - - - - - - x
6 x x x x x x x x
7 x x x x x x x x

Patch Structure
===============

Patches 1-3: Preparatory changes for power mode negotiation and HS-G6
Patch 4: Core TX Equalization and EQTR implementation
Patches 5-7: Debugfs support for TX Equalization
Patches 8-12: Qualcomm vendor implementation

Next
====

One more series has been developed to enhance TX Equalization support,
which will be submitted for review after this series is accepted:

- Provide board specific (static) TX Equalization settings from DTS
- Parse static TX Equalization settings from DTS if provided
- Apply static TX Equalization settings if use_adaptive_txeq is disabled
- Add support for UFS v5.0 attributes qTxEQGnSettings & wTxEQGnSettingsExt
- Enable persistent storage and retrieval of optimal TX Equalization settings

Link: https://patch.msgid.link/20260325152154.1604082-1-can.guo@oss.qualcomm.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

+2779 -115
+1 -1
drivers/ufs/core/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 3 obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o 4 - ufshcd-core-y += ufshcd.o ufs-sysfs.o ufs-mcq.o 4 + ufshcd-core-y += ufshcd.o ufs-sysfs.o ufs-mcq.o ufs-txeq.o 5 5 ufshcd-core-$(CONFIG_RPMB) += ufs-rpmb.o 6 6 ufshcd-core-$(CONFIG_DEBUG_FS) += ufs-debugfs.o 7 7 ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o
+290
drivers/ufs/core/ufs-debugfs.c
··· 209 209 { } 210 210 }; 211 211 212 + static int ufs_tx_eq_params_show(struct seq_file *s, void *data) 213 + { 214 + const char *file_name = s->file->f_path.dentry->d_name.name; 215 + u32 gear = (u32)(uintptr_t)s->file->f_inode->i_private; 216 + struct ufs_hba *hba = hba_from_file(s->file); 217 + struct ufshcd_tx_eq_settings *settings; 218 + struct ufs_pa_layer_attr *pwr_info; 219 + struct ufshcd_tx_eq_params *params; 220 + u32 rate = hba->pwr_info.hs_rate; 221 + u32 num_lanes; 222 + int lane; 223 + 224 + if (!ufshcd_is_tx_eq_supported(hba)) 225 + return -EOPNOTSUPP; 226 + 227 + if (gear < UFS_HS_G1 || gear > UFS_HS_GEAR_MAX) { 228 + seq_printf(s, "Invalid gear selected: %u\n", gear); 229 + return 0; 230 + } 231 + 232 + if (!hba->max_pwr_info.is_valid) { 233 + seq_puts(s, "Max power info is invalid\n"); 234 + return 0; 235 + } 236 + 237 + pwr_info = &hba->max_pwr_info.info; 238 + params = &hba->tx_eq_params[gear - 1]; 239 + if (!params->is_valid) { 240 + seq_printf(s, "TX EQ params are invalid for HS-G%u, Rate-%s\n", 241 + gear, ufs_hs_rate_to_str(rate)); 242 + return 0; 243 + } 244 + 245 + if (strcmp(file_name, "host_tx_eq_params") == 0) { 246 + settings = params->host; 247 + num_lanes = pwr_info->lane_tx; 248 + seq_printf(s, "Host TX EQ PreShoot Cap: 0x%02x, DeEmphasis Cap: 0x%02x\n", 249 + hba->host_preshoot_cap, hba->host_deemphasis_cap); 250 + } else if (strcmp(file_name, "device_tx_eq_params") == 0) { 251 + settings = params->device; 252 + num_lanes = pwr_info->lane_rx; 253 + seq_printf(s, "Device TX EQ PreShoot Cap: 0x%02x, DeEmphasis Cap: 0x%02x\n", 254 + hba->device_preshoot_cap, hba->device_deemphasis_cap); 255 + } else { 256 + return -ENOENT; 257 + } 258 + 259 + seq_printf(s, "TX EQ setting for HS-G%u, Rate-%s:\n", gear, 260 + ufs_hs_rate_to_str(rate)); 261 + for (lane = 0; lane < num_lanes; lane++) 262 + seq_printf(s, "TX Lane %d - PreShoot: %d, DeEmphasis: %d, Pre-Coding %senabled\n", 263 + lane, settings[lane].preshoot, 264 + settings[lane].deemphasis, 265 + settings[lane].precode_en ? "" : "not "); 266 + 267 + return 0; 268 + } 269 + 270 + static int ufs_tx_eq_params_open(struct inode *inode, struct file *file) 271 + { 272 + return single_open(file, ufs_tx_eq_params_show, inode->i_private); 273 + } 274 + 275 + static const struct file_operations ufs_tx_eq_params_fops = { 276 + .owner = THIS_MODULE, 277 + .open = ufs_tx_eq_params_open, 278 + .read = seq_read, 279 + .llseek = seq_lseek, 280 + .release = single_release, 281 + }; 282 + 283 + static const struct ufs_debugfs_attr ufs_tx_eq_attrs[] = { 284 + { "host_tx_eq_params", 0400, &ufs_tx_eq_params_fops }, 285 + { "device_tx_eq_params", 0400, &ufs_tx_eq_params_fops }, 286 + { } 287 + }; 288 + 289 + static int ufs_tx_eqtr_record_show(struct seq_file *s, void *data) 290 + { 291 + const char *file_name = s->file->f_path.dentry->d_name.name; 292 + u8 (*fom_array)[TX_HS_NUM_PRESHOOT][TX_HS_NUM_DEEMPHASIS]; 293 + u32 gear = (u32)(uintptr_t)s->file->f_inode->i_private; 294 + unsigned long preshoot_bitmap, deemphasis_bitmap; 295 + struct ufs_hba *hba = hba_from_file(s->file); 296 + struct ufs_pa_layer_attr *pwr_info; 297 + struct ufshcd_tx_eq_params *params; 298 + struct ufshcd_tx_eqtr_record *rec; 299 + u32 rate = hba->pwr_info.hs_rate; 300 + u8 preshoot, deemphasis; 301 + u32 num_lanes; 302 + char name[32]; 303 + int lane; 304 + 305 + if (!ufshcd_is_tx_eq_supported(hba)) 306 + return -EOPNOTSUPP; 307 + 308 + if (gear < UFS_HS_G1 || gear > UFS_HS_GEAR_MAX) { 309 + seq_printf(s, "Invalid gear selected: %u\n", gear); 310 + return 0; 311 + } 312 + 313 + if (!hba->max_pwr_info.is_valid) { 314 + seq_puts(s, "Max power info is invalid\n"); 315 + return 0; 316 + } 317 + 318 + pwr_info = &hba->max_pwr_info.info; 319 + params = &hba->tx_eq_params[gear - 1]; 320 + if (!params->is_valid) { 321 + seq_printf(s, "TX EQ params are invalid for HS-G%u, Rate-%s\n", 322 + gear, ufs_hs_rate_to_str(rate)); 323 + return 0; 324 + } 325 + 326 + rec = params->eqtr_record; 327 + if (!rec || !rec->last_record_index) { 328 + seq_printf(s, "No TX EQTR records found for HS-G%u, Rate-%s.\n", 329 + gear, ufs_hs_rate_to_str(rate)); 330 + return 0; 331 + } 332 + 333 + if (strcmp(file_name, "host_tx_eqtr_record") == 0) { 334 + preshoot_bitmap = (hba->host_preshoot_cap << 0x1) | 0x1; 335 + deemphasis_bitmap = (hba->host_deemphasis_cap << 0x1) | 0x1; 336 + num_lanes = pwr_info->lane_tx; 337 + fom_array = rec->host_fom; 338 + snprintf(name, sizeof(name), "%s", "Host"); 339 + } else if (strcmp(file_name, "device_tx_eqtr_record") == 0) { 340 + preshoot_bitmap = (hba->device_preshoot_cap << 0x1) | 0x1; 341 + deemphasis_bitmap = (hba->device_deemphasis_cap << 0x1) | 0x1; 342 + num_lanes = pwr_info->lane_rx; 343 + fom_array = rec->device_fom; 344 + snprintf(name, sizeof(name), "%s", "Device"); 345 + } else { 346 + return -ENOENT; 347 + } 348 + 349 + seq_printf(s, "%s TX EQTR record summary -\n", name); 350 + seq_printf(s, "Target Power Mode: HS-G%u, Rate-%s\n", gear, 351 + ufs_hs_rate_to_str(rate)); 352 + seq_printf(s, "Most recent record index: %d\n", 353 + rec->last_record_index); 354 + seq_printf(s, "Most recent record timestamp: %llu us\n", 355 + ktime_to_us(rec->last_record_ts)); 356 + 357 + for (lane = 0; lane < num_lanes; lane++) { 358 + seq_printf(s, "\nTX Lane %d FOM - %s\n", lane, "PreShoot\\DeEmphasis"); 359 + seq_puts(s, "\\"); 360 + /* Print DeEmphasis header as X-axis. */ 361 + for (deemphasis = 0; deemphasis < TX_HS_NUM_DEEMPHASIS; deemphasis++) 362 + seq_printf(s, "%8d%s", deemphasis, " "); 363 + seq_puts(s, "\n"); 364 + /* Print matrix rows with PreShoot as Y-axis. */ 365 + for (preshoot = 0; preshoot < TX_HS_NUM_PRESHOOT; preshoot++) { 366 + seq_printf(s, "%d", preshoot); 367 + for (deemphasis = 0; deemphasis < TX_HS_NUM_DEEMPHASIS; deemphasis++) { 368 + if (test_bit(preshoot, &preshoot_bitmap) && 369 + test_bit(deemphasis, &deemphasis_bitmap)) { 370 + u8 fom = fom_array[lane][preshoot][deemphasis]; 371 + u8 fom_val = fom & RX_FOM_VALUE_MASK; 372 + bool precode_en = fom & RX_FOM_PRECODING_EN_BIT; 373 + 374 + if (ufshcd_is_txeq_presets_used(hba) && 375 + !ufshcd_is_txeq_preset_selected(preshoot, deemphasis)) 376 + seq_printf(s, "%8s%s", "-", " "); 377 + else 378 + seq_printf(s, "%8u%s", fom_val, 379 + precode_en ? "*" : " "); 380 + } else { 381 + seq_printf(s, "%8s%s", "x", " "); 382 + } 383 + } 384 + seq_puts(s, "\n"); 385 + } 386 + } 387 + 388 + return 0; 389 + } 390 + 391 + static int ufs_tx_eqtr_record_open(struct inode *inode, struct file *file) 392 + { 393 + return single_open(file, ufs_tx_eqtr_record_show, inode->i_private); 394 + } 395 + 396 + static const struct file_operations ufs_tx_eqtr_record_fops = { 397 + .owner = THIS_MODULE, 398 + .open = ufs_tx_eqtr_record_open, 399 + .read = seq_read, 400 + .llseek = seq_lseek, 401 + .release = single_release, 402 + }; 403 + 404 + static ssize_t ufs_tx_eq_ctrl_write(struct file *file, const char __user *buf, 405 + size_t count, loff_t *ppos) 406 + { 407 + u32 gear = (u32)(uintptr_t)file->f_inode->i_private; 408 + struct ufs_hba *hba = hba_from_file(file); 409 + char kbuf[32]; 410 + int ret; 411 + 412 + if (count >= sizeof(kbuf)) 413 + return -EINVAL; 414 + 415 + if (copy_from_user(kbuf, buf, count)) 416 + return -EFAULT; 417 + 418 + if (!ufshcd_is_tx_eq_supported(hba)) 419 + return -EOPNOTSUPP; 420 + 421 + if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL || 422 + !hba->max_pwr_info.is_valid) 423 + return -EBUSY; 424 + 425 + if (!hba->ufs_device_wlun) 426 + return -ENODEV; 427 + 428 + kbuf[count] = '\0'; 429 + 430 + if (sysfs_streq(kbuf, "retrain")) { 431 + ret = ufs_debugfs_get_user_access(hba); 432 + if (ret) 433 + return ret; 434 + ret = ufshcd_retrain_tx_eq(hba, gear); 435 + ufs_debugfs_put_user_access(hba); 436 + } else { 437 + /* Unknown operation */ 438 + return -EINVAL; 439 + } 440 + 441 + return ret ? ret : count; 442 + } 443 + 444 + static int ufs_tx_eq_ctrl_show(struct seq_file *s, void *data) 445 + { 446 + seq_puts(s, "write 'retrain' to retrain TX Equalization settings\n"); 447 + return 0; 448 + } 449 + 450 + static int ufs_tx_eq_ctrl_open(struct inode *inode, struct file *file) 451 + { 452 + return single_open(file, ufs_tx_eq_ctrl_show, inode->i_private); 453 + } 454 + 455 + static const struct file_operations ufs_tx_eq_ctrl_fops = { 456 + .owner = THIS_MODULE, 457 + .open = ufs_tx_eq_ctrl_open, 458 + .read = seq_read, 459 + .llseek = seq_lseek, 460 + .write = ufs_tx_eq_ctrl_write, 461 + .release = single_release, 462 + }; 463 + 464 + static const struct ufs_debugfs_attr ufs_tx_eqtr_attrs[] = { 465 + { "host_tx_eqtr_record", 0400, &ufs_tx_eqtr_record_fops }, 466 + { "device_tx_eqtr_record", 0400, &ufs_tx_eqtr_record_fops }, 467 + { "tx_eq_ctrl", 0600, &ufs_tx_eq_ctrl_fops }, 468 + { } 469 + }; 470 + 212 471 void ufs_debugfs_hba_init(struct ufs_hba *hba) 213 472 { 214 473 const struct ufs_debugfs_attr *attr; ··· 489 230 hba, &ee_usr_mask_fops); 490 231 debugfs_create_u32("exception_event_rate_limit_ms", 0600, hba->debugfs_root, 491 232 &hba->debugfs_ee_rate_limit_ms); 233 + 234 + if (!(hba->caps & UFSHCD_CAP_TX_EQUALIZATION)) 235 + return; 236 + 237 + for (u32 gear = UFS_HS_G1; gear <= UFS_HS_GEAR_MAX; gear++) { 238 + struct dentry *txeq_dir; 239 + char name[32]; 240 + 241 + snprintf(name, sizeof(name), "tx_eq_hs_gear%d", gear); 242 + txeq_dir = debugfs_create_dir(name, hba->debugfs_root); 243 + if (IS_ERR_OR_NULL(txeq_dir)) 244 + return; 245 + 246 + d_inode(txeq_dir)->i_private = hba; 247 + 248 + /* Create files for TX Equalization parameters */ 249 + for (attr = ufs_tx_eq_attrs; attr->name; attr++) 250 + debugfs_create_file(attr->name, attr->mode, txeq_dir, 251 + (void *)(uintptr_t)gear, 252 + attr->fops); 253 + 254 + /* TX EQTR is supported for HS-G4 and higher Gears */ 255 + if (gear < UFS_HS_G4) 256 + continue; 257 + 258 + /* Create files for TX EQTR related attributes */ 259 + for (attr = ufs_tx_eqtr_attrs; attr->name; attr++) 260 + debugfs_create_file(attr->name, attr->mode, txeq_dir, 261 + (void *)(uintptr_t)gear, 262 + attr->fops); 263 + } 492 264 } 493 265 494 266 void ufs_debugfs_hba_exit(struct ufs_hba *hba)
+1293
drivers/ufs/core/ufs-txeq.c
··· 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 + static bool use_adaptive_txeq; 18 + module_param(use_adaptive_txeq, bool, 0644); 19 + MODULE_PARM_DESC(use_adaptive_txeq, "Find and apply optimal TX Equalization settings before changing Power Mode (default: false)"); 20 + 21 + static int txeq_gear_set(const char *val, const struct kernel_param *kp) 22 + { 23 + return param_set_uint_minmax(val, kp, UFS_HS_G1, UFS_HS_GEAR_MAX); 24 + } 25 + 26 + static const struct kernel_param_ops txeq_gear_ops = { 27 + .set = txeq_gear_set, 28 + .get = param_get_uint, 29 + }; 30 + 31 + static unsigned int adaptive_txeq_gear = UFS_HS_G6; 32 + module_param_cb(adaptive_txeq_gear, &txeq_gear_ops, &adaptive_txeq_gear, 0644); 33 + MODULE_PARM_DESC(adaptive_txeq_gear, "For HS-Gear[n] and above, adaptive txeq shall be used"); 34 + 35 + static bool use_txeq_presets; 36 + module_param(use_txeq_presets, bool, 0644); 37 + 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)"); 38 + 39 + static bool txeq_presets_selected[UFS_TX_EQ_PRESET_MAX] = {[0 ... (UFS_TX_EQ_PRESET_MAX - 1)] = 1}; 40 + module_param_array(txeq_presets_selected, bool, NULL, 0644); 41 + MODULE_PARM_DESC(txeq_presets_selected, "Use only the selected Presets out of the 8 TX Equalization Presets for TX EQTR"); 42 + 43 + /* 44 + * ufs_tx_eq_preset - Table of minimum required list of presets. 45 + * 46 + * A HS-G6 capable M-TX shall support the presets defined in M-PHY v6.0 spec. 47 + * Preset Pre-Shoot(dB) De-Emphasis(dB) 48 + * P0 0.0 0.0 49 + * P1 0.0 0.8 50 + * P2 0.0 1.6 51 + * P3 0.8 0.0 52 + * P4 1.6 0.0 53 + * P5 0.8 0.8 54 + * P6 0.8 1.6 55 + * P7 1.6 0.8 56 + */ 57 + static const struct __ufs_tx_eq_preset { 58 + u8 preshoot; 59 + u8 deemphasis; 60 + } ufs_tx_eq_preset[UFS_TX_EQ_PRESET_MAX] = { 61 + [UFS_TX_EQ_PRESET_P0] = {UFS_TX_HS_PRESHOOT_DB_0P0, UFS_TX_HS_DEEMPHASIS_DB_0P0}, 62 + [UFS_TX_EQ_PRESET_P1] = {UFS_TX_HS_PRESHOOT_DB_0P0, UFS_TX_HS_DEEMPHASIS_DB_0P8}, 63 + [UFS_TX_EQ_PRESET_P2] = {UFS_TX_HS_PRESHOOT_DB_0P0, UFS_TX_HS_DEEMPHASIS_DB_1P6}, 64 + [UFS_TX_EQ_PRESET_P3] = {UFS_TX_HS_PRESHOOT_DB_0P8, UFS_TX_HS_DEEMPHASIS_DB_0P0}, 65 + [UFS_TX_EQ_PRESET_P4] = {UFS_TX_HS_PRESHOOT_DB_1P6, UFS_TX_HS_DEEMPHASIS_DB_0P0}, 66 + [UFS_TX_EQ_PRESET_P5] = {UFS_TX_HS_PRESHOOT_DB_0P8, UFS_TX_HS_DEEMPHASIS_DB_0P8}, 67 + [UFS_TX_EQ_PRESET_P6] = {UFS_TX_HS_PRESHOOT_DB_0P8, UFS_TX_HS_DEEMPHASIS_DB_1P6}, 68 + [UFS_TX_EQ_PRESET_P7] = {UFS_TX_HS_PRESHOOT_DB_1P6, UFS_TX_HS_DEEMPHASIS_DB_0P8}, 69 + }; 70 + 71 + /* 72 + * pa_peer_rx_adapt_initial - Table of UniPro PA_PeerRxHSGnAdaptInitial 73 + * attribute IDs for High Speed (HS) Gears. 74 + * 75 + * This table maps HS Gears to their respective UniPro PA_PeerRxHSGnAdaptInitial 76 + * attribute IDs. Entries for Gears 1-3 are 0 (unsupported). 77 + */ 78 + static const u32 pa_peer_rx_adapt_initial[UFS_HS_GEAR_MAX] = { 79 + 0, 80 + 0, 81 + 0, 82 + PA_PEERRXHSG4ADAPTINITIAL, 83 + PA_PEERRXHSG5ADAPTINITIAL, 84 + PA_PEERRXHSG6ADAPTINITIALL0L3 85 + }; 86 + 87 + /* 88 + * rx_adapt_initial_cap - Table of M-PHY RX_HS_Gn_ADAPT_INITIAL_Capability 89 + * attribute IDs for High Speed (HS) Gears. 90 + * 91 + * This table maps HS Gears to their respective M-PHY 92 + * RX_HS_Gn_ADAPT_INITIAL_Capability attribute IDs. Entries for Gears 1-3 are 0 93 + * (unsupported). 94 + */ 95 + static const u32 rx_adapt_initial_cap[UFS_HS_GEAR_MAX] = { 96 + 0, 97 + 0, 98 + 0, 99 + RX_HS_G4_ADAPT_INITIAL_CAP, 100 + RX_HS_G5_ADAPT_INITIAL_CAP, 101 + RX_HS_G6_ADAPT_INITIAL_CAP 102 + }; 103 + 104 + /* 105 + * pa_tx_eq_setting - Table of UniPro PA_TxEQGnSetting attribute IDs for High 106 + * Speed (HS) Gears. 107 + * 108 + * This table maps HS Gears to their respective UniPro PA_TxEQGnSetting 109 + * attribute IDs. 110 + */ 111 + static const u32 pa_tx_eq_setting[UFS_HS_GEAR_MAX] = { 112 + PA_TXEQG1SETTING, 113 + PA_TXEQG2SETTING, 114 + PA_TXEQG3SETTING, 115 + PA_TXEQG4SETTING, 116 + PA_TXEQG5SETTING, 117 + PA_TXEQG6SETTING 118 + }; 119 + 120 + /** 121 + * ufshcd_configure_precoding - Configure Pre-Coding for all active lanes 122 + * @hba: per adapter instance 123 + * @params: TX EQ parameters data structure 124 + * 125 + * Bit[7] in RX_FOM indicates that the receiver needs to enable Pre-Coding when 126 + * set. Pre-Coding must be enabled on both the transmitter and receiver to 127 + * ensure proper operation. 128 + * 129 + * Returns 0 on success, non-zero error code otherwise 130 + */ 131 + static int ufshcd_configure_precoding(struct ufs_hba *hba, 132 + struct ufshcd_tx_eq_params *params) 133 + { 134 + struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info; 135 + u32 local_precode_en = 0; 136 + u32 peer_precode_en = 0; 137 + int lane, ret; 138 + 139 + /* Enable Pre-Coding for Host's TX & Device's RX pair */ 140 + for (lane = 0; lane < pwr_info->lane_tx; lane++) { 141 + if (params->host[lane].precode_en) { 142 + local_precode_en |= PRECODEEN_TX_BIT(lane); 143 + peer_precode_en |= PRECODEEN_RX_BIT(lane); 144 + } 145 + } 146 + 147 + /* Enable Pre-Coding for Device's TX & Host's RX pair */ 148 + for (lane = 0; lane < pwr_info->lane_rx; lane++) { 149 + if (params->device[lane].precode_en) { 150 + peer_precode_en |= PRECODEEN_TX_BIT(lane); 151 + local_precode_en |= PRECODEEN_RX_BIT(lane); 152 + } 153 + } 154 + 155 + if (!local_precode_en && !peer_precode_en) { 156 + dev_dbg(hba->dev, "Pre-Coding is not required for Host and Device\n"); 157 + return 0; 158 + } 159 + 160 + /* Set local PA_PreCodeEn */ 161 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PRECODEEN), local_precode_en); 162 + if (ret) { 163 + dev_err(hba->dev, "Failed to set local PA_PreCodeEn: %d\n", ret); 164 + return ret; 165 + } 166 + 167 + /* Set peer PA_PreCodeEn */ 168 + ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(PA_PRECODEEN), peer_precode_en); 169 + if (ret) { 170 + dev_err(hba->dev, "Failed to set peer PA_PreCodeEn: %d\n", ret); 171 + return ret; 172 + } 173 + 174 + dev_dbg(hba->dev, "Local PA_PreCodeEn: 0x%02x, Peer PA_PreCodeEn: 0x%02x\n", 175 + local_precode_en, peer_precode_en); 176 + 177 + return 0; 178 + } 179 + 180 + void ufshcd_print_tx_eq_params(struct ufs_hba *hba) 181 + { 182 + struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info; 183 + struct ufshcd_tx_eq_params *params; 184 + u32 gear = hba->pwr_info.gear_tx; 185 + int lane; 186 + 187 + if (!ufshcd_is_tx_eq_supported(hba)) 188 + return; 189 + 190 + if (gear < UFS_HS_G1 || gear > UFS_HS_GEAR_MAX) 191 + return; 192 + 193 + params = &hba->tx_eq_params[gear - 1]; 194 + if (!params->is_valid || !params->is_applied) 195 + return; 196 + 197 + for (lane = 0; lane < pwr_info->lane_tx; lane++) 198 + dev_dbg(hba->dev, "Host TX Lane %d: PreShoot %u, DeEmphasis %u, FOM %u, PreCodeEn %d\n", 199 + lane, params->host[lane].preshoot, 200 + params->host[lane].deemphasis, 201 + params->host[lane].fom_val, 202 + params->host[lane].precode_en); 203 + 204 + for (lane = 0; lane < pwr_info->lane_rx; lane++) 205 + dev_dbg(hba->dev, "Device TX Lane %d: PreShoot %u, DeEmphasis %u, FOM %u, PreCodeEn %d\n", 206 + lane, params->device[lane].preshoot, 207 + params->device[lane].deemphasis, 208 + params->device[lane].fom_val, 209 + params->device[lane].precode_en); 210 + } 211 + 212 + static inline u32 213 + ufshcd_compose_tx_eq_setting(struct ufshcd_tx_eq_settings *settings, 214 + int num_lanes) 215 + { 216 + u32 setting = 0; 217 + int lane; 218 + 219 + for (lane = 0; lane < num_lanes; lane++, settings++) { 220 + setting |= TX_HS_PRESHOOT_BITS(lane, settings->preshoot); 221 + setting |= TX_HS_DEEMPHASIS_BITS(lane, settings->deemphasis); 222 + } 223 + 224 + return setting; 225 + } 226 + 227 + /** 228 + * ufshcd_apply_tx_eq_settings - Apply TX Equalization settings for target gear 229 + * @hba: per adapter instance 230 + * @params: TX EQ parameters data structure 231 + * @gear: target gear 232 + * 233 + * Returns 0 on success, negative error code otherwise 234 + */ 235 + int ufshcd_apply_tx_eq_settings(struct ufs_hba *hba, 236 + struct ufshcd_tx_eq_params *params, u32 gear) 237 + { 238 + struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info; 239 + u32 setting; 240 + int ret; 241 + 242 + /* Compose settings for Host's TX Lanes */ 243 + setting = ufshcd_compose_tx_eq_setting(params->host, pwr_info->lane_tx); 244 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(pa_tx_eq_setting[gear - 1]), setting); 245 + if (ret) 246 + return ret; 247 + 248 + /* Compose settings for Device's TX Lanes */ 249 + setting = ufshcd_compose_tx_eq_setting(params->device, pwr_info->lane_rx); 250 + ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(pa_tx_eq_setting[gear - 1]), setting); 251 + if (ret) 252 + return ret; 253 + 254 + /* Configure Pre-Coding */ 255 + if (gear >= UFS_HS_G6) { 256 + ret = ufshcd_configure_precoding(hba, params); 257 + if (ret) { 258 + dev_err(hba->dev, "Failed to configure pre-coding: %d\n", ret); 259 + return ret; 260 + } 261 + } 262 + 263 + return 0; 264 + } 265 + EXPORT_SYMBOL_GPL(ufshcd_apply_tx_eq_settings); 266 + 267 + /** 268 + * ufshcd_evaluate_tx_eqtr_fom - Evaluate TX EQTR FOM results 269 + * @hba: per adapter instance 270 + * @pwr_mode: target power mode containing gear and rate information 271 + * @eqtr_data: TX EQTR data structure 272 + * @h_iter: host TX EQTR iterator data structure 273 + * @d_iter: device TX EQTR iterator data structure 274 + * 275 + * Evaluate TX EQTR FOM results, update host and device TX EQTR data accordingy 276 + * if FOM have been improved compared to previous iteration, and record TX EQTR 277 + * FOM results. 278 + */ 279 + static void ufshcd_evaluate_tx_eqtr_fom(struct ufs_hba *hba, 280 + struct ufs_pa_layer_attr *pwr_mode, 281 + struct ufshcd_tx_eqtr_data *eqtr_data, 282 + struct tx_eqtr_iter *h_iter, 283 + struct tx_eqtr_iter *d_iter) 284 + { 285 + u8 preshoot, deemphasis, fom_value; 286 + bool precode_en; 287 + int lane; 288 + 289 + for (lane = 0; h_iter->is_updated && lane < pwr_mode->lane_tx; lane++) { 290 + preshoot = h_iter->preshoot; 291 + deemphasis = h_iter->deemphasis; 292 + fom_value = h_iter->fom[lane] & RX_FOM_VALUE_MASK; 293 + precode_en = h_iter->fom[lane] & RX_FOM_PRECODING_EN_BIT; 294 + 295 + /* Record host TX EQTR FOM */ 296 + eqtr_data->host_fom[lane][preshoot][deemphasis] = h_iter->fom[lane]; 297 + 298 + /* Check if FOM has been improved for host's TX Lanes */ 299 + if (fom_value > eqtr_data->host[lane].fom_val) { 300 + eqtr_data->host[lane].preshoot = preshoot; 301 + eqtr_data->host[lane].deemphasis = deemphasis; 302 + eqtr_data->host[lane].fom_val = fom_value; 303 + eqtr_data->host[lane].precode_en = precode_en; 304 + } 305 + 306 + dev_dbg(hba->dev, "TX EQTR: Host TX Lane %d: PreShoot %u, DeEmphasis %u, FOM value %u, PreCodeEn %d\n", 307 + lane, preshoot, deemphasis, fom_value, precode_en); 308 + } 309 + 310 + for (lane = 0; d_iter->is_updated && lane < pwr_mode->lane_rx; lane++) { 311 + preshoot = d_iter->preshoot; 312 + deemphasis = d_iter->deemphasis; 313 + fom_value = d_iter->fom[lane] & RX_FOM_VALUE_MASK; 314 + precode_en = d_iter->fom[lane] & RX_FOM_PRECODING_EN_BIT; 315 + 316 + /* Record device TX EQTR FOM */ 317 + eqtr_data->device_fom[lane][preshoot][deemphasis] = d_iter->fom[lane]; 318 + 319 + /* Check if FOM has been improved for Device's TX Lanes */ 320 + if (fom_value > eqtr_data->device[lane].fom_val) { 321 + eqtr_data->device[lane].preshoot = preshoot; 322 + eqtr_data->device[lane].deemphasis = deemphasis; 323 + eqtr_data->device[lane].fom_val = fom_value; 324 + eqtr_data->device[lane].precode_en = precode_en; 325 + } 326 + 327 + dev_dbg(hba->dev, "TX EQTR: Device TX Lane %d: PreShoot %u, DeEmphasis %u, FOM value %u, PreCodeEn %d\n", 328 + lane, preshoot, deemphasis, fom_value, precode_en); 329 + } 330 + } 331 + 332 + /** 333 + * ufshcd_get_rx_fom - Get Figure of Merit (FOM) for both sides 334 + * @hba: per adapter instance 335 + * @pwr_mode: target power mode containing gear and rate information 336 + * @h_iter: host TX EQTR iterator data structure 337 + * @d_iter: device TX EQTR iterator data structure 338 + * 339 + * Returns 0 on success, negative error code otherwise 340 + */ 341 + static int ufshcd_get_rx_fom(struct ufs_hba *hba, 342 + struct ufs_pa_layer_attr *pwr_mode, 343 + struct tx_eqtr_iter *h_iter, 344 + struct tx_eqtr_iter *d_iter) 345 + { 346 + int lane, ret; 347 + u32 fom; 348 + 349 + /* Get FOM of host's TX lanes from device's RX_FOM. */ 350 + for (lane = 0; lane < pwr_mode->lane_tx; lane++) { 351 + ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB_SEL(RX_FOM, 352 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 353 + &fom); 354 + if (ret) 355 + return ret; 356 + 357 + h_iter->fom[lane] = (u8)fom; 358 + } 359 + 360 + /* Get FOM of device's TX lanes from host's RX_FOM. */ 361 + for (lane = 0; lane < pwr_mode->lane_rx; lane++) { 362 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(RX_FOM, 363 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 364 + &fom); 365 + if (ret) 366 + return ret; 367 + 368 + d_iter->fom[lane] = (u8)fom; 369 + } 370 + 371 + ret = ufshcd_vops_get_rx_fom(hba, pwr_mode, h_iter, d_iter); 372 + if (ret) 373 + dev_err(hba->dev, "Failed to get FOM via vops: %d\n", ret); 374 + 375 + return ret; 376 + } 377 + 378 + bool ufshcd_is_txeq_presets_used(struct ufs_hba *hba) 379 + { 380 + return use_txeq_presets; 381 + } 382 + 383 + bool ufshcd_is_txeq_preset_selected(u8 preshoot, u8 deemphasis) 384 + { 385 + int i; 386 + 387 + for (i = 0; i < UFS_TX_EQ_PRESET_MAX; i++) { 388 + if (!txeq_presets_selected[i]) 389 + continue; 390 + 391 + if (preshoot == ufs_tx_eq_preset[i].preshoot && 392 + deemphasis == ufs_tx_eq_preset[i].deemphasis) 393 + return true; 394 + } 395 + 396 + return false; 397 + } 398 + 399 + /** 400 + * tx_eqtr_iter_try_update - Try to update a TX EQTR iterator 401 + * @iter: TX EQTR iterator data structure 402 + * @preshoot: PreShoot value 403 + * @deemphasis: DeEmphasis value 404 + * 405 + * This function validates whether the provided PreShoot and DeEmphasis 406 + * combination can be used or not. If yes, it updates the TX EQTR iterator with 407 + * the provided PreShoot and DeEmphasis, it also sets the is_updated flag 408 + * to indicate the iterator has been updated. 409 + */ 410 + static void tx_eqtr_iter_try_update(struct tx_eqtr_iter *iter, 411 + u8 preshoot, u8 deemphasis) 412 + { 413 + if (!test_bit(preshoot, &iter->preshoot_bitmap) || 414 + !test_bit(deemphasis, &iter->deemphasis_bitmap) || 415 + (use_txeq_presets && !ufshcd_is_txeq_preset_selected(preshoot, deemphasis))) { 416 + iter->is_updated = false; 417 + return; 418 + } 419 + 420 + iter->preshoot = preshoot; 421 + iter->deemphasis = deemphasis; 422 + iter->is_updated = true; 423 + } 424 + 425 + /** 426 + * tx_eqtr_iter_update() - Update host and deviceTX EQTR iterators 427 + * @preshoot: PreShoot value 428 + * @deemphasis: DeEmphasis value 429 + * @h_iter: Host TX EQTR iterator data structure 430 + * @d_iter: Device TX EQTR iterator data structure 431 + * 432 + * Updates host and device TX Equalization training iterators with the 433 + * provided PreShoot and DeEmphasis. 434 + * 435 + * Return: true if host and/or device TX Equalization training iterator has 436 + * been updated to the provided PreShoot and DeEmphasis, false otherwise. 437 + */ 438 + static bool tx_eqtr_iter_update(u8 preshoot, u8 deemphasis, 439 + struct tx_eqtr_iter *h_iter, 440 + struct tx_eqtr_iter *d_iter) 441 + { 442 + tx_eqtr_iter_try_update(h_iter, preshoot, deemphasis); 443 + tx_eqtr_iter_try_update(d_iter, preshoot, deemphasis); 444 + 445 + return h_iter->is_updated || d_iter->is_updated; 446 + } 447 + 448 + /** 449 + * ufshcd_tx_eqtr_iter_init - Initialize host and device TX EQTR iterators 450 + * @hba: per adapter instance 451 + * @h_iter: host TX EQTR iterator data structure 452 + * @d_iter: device TX EQTR iterator data structure 453 + * 454 + * This function initializes the TX EQTR iterator structures for both host and 455 + * device by reading their TX equalization capabilities. The capabilities are 456 + * cached in the hba structure to avoid redundant DME operations in subsequent 457 + * calls. In the TX EQTR procedure, the iterator structures are updated by 458 + * tx_eqtr_iter_update() to systematically iterate through supported TX 459 + * Equalization setting combinations. 460 + * 461 + * Returns 0 on success, negative error code otherwise 462 + */ 463 + static int ufshcd_tx_eqtr_iter_init(struct ufs_hba *hba, 464 + struct tx_eqtr_iter *h_iter, 465 + struct tx_eqtr_iter *d_iter) 466 + { 467 + u32 cap; 468 + int ret; 469 + 470 + if (!hba->host_preshoot_cap) { 471 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(TX_HS_PRESHOOT_SETTING_CAP), &cap); 472 + if (ret) 473 + return ret; 474 + 475 + hba->host_preshoot_cap = cap & TX_EQTR_CAP_MASK; 476 + } 477 + 478 + if (!hba->host_deemphasis_cap) { 479 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(TX_HS_DEEMPHASIS_SETTING_CAP), &cap); 480 + if (ret) 481 + return ret; 482 + 483 + hba->host_deemphasis_cap = cap & TX_EQTR_CAP_MASK; 484 + } 485 + 486 + if (!hba->device_preshoot_cap) { 487 + ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(TX_HS_PRESHOOT_SETTING_CAP), &cap); 488 + if (ret) 489 + return ret; 490 + 491 + hba->device_preshoot_cap = cap & TX_EQTR_CAP_MASK; 492 + } 493 + 494 + if (!hba->device_deemphasis_cap) { 495 + ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(TX_HS_DEEMPHASIS_SETTING_CAP), &cap); 496 + if (ret) 497 + return ret; 498 + 499 + hba->device_deemphasis_cap = cap & TX_EQTR_CAP_MASK; 500 + } 501 + 502 + /* 503 + * Support PreShoot & DeEmphasis of value 0 is mandatory, hence they are 504 + * not reflected in PreShoot/DeEmphasis capabilities. Left shift the 505 + * capability bitmap by 1 and set bit[0] to reflect value 0 is 506 + * supported, such that test_bit() can be used later for convenience. 507 + */ 508 + h_iter->preshoot_bitmap = (hba->host_preshoot_cap << 0x1) | 0x1; 509 + h_iter->deemphasis_bitmap = (hba->host_deemphasis_cap << 0x1) | 0x1; 510 + d_iter->preshoot_bitmap = (hba->device_preshoot_cap << 0x1) | 0x1; 511 + d_iter->deemphasis_bitmap = (hba->device_deemphasis_cap << 0x1) | 0x1; 512 + 513 + return 0; 514 + } 515 + 516 + /** 517 + * adapt_cap_to_t_adapt - Calculate TAdapt from adapt capability 518 + * @adapt_cap: Adapt capability 519 + * 520 + * For NRZ: 521 + * IF (ADAPT_range = FINE) 522 + * TADAPT = 650 x (ADAPT_length + 1) 523 + * ELSE (IF ADAPT_range = COARSE) 524 + * TADAPT = 650 x 2^ADAPT_length 525 + * 526 + * Returns calculated TAdapt value in term of Unit Intervals (UI) 527 + */ 528 + static inline u64 adapt_cap_to_t_adapt(u32 adapt_cap) 529 + { 530 + u64 tadapt; 531 + u8 adapt_length = adapt_cap & ADAPT_LENGTH_MASK; 532 + 533 + if (!IS_ADAPT_RANGE_COARSE(adapt_cap)) 534 + tadapt = TADAPT_FACTOR * (adapt_length + 1); 535 + else 536 + tadapt = TADAPT_FACTOR * (1 << adapt_length); 537 + 538 + return tadapt; 539 + } 540 + 541 + /** 542 + * adapt_cap_to_t_adapt_l0l3 - Calculate TAdapt_L0_L3 from adapt capability 543 + * @adapt_cap: Adapt capability 544 + * 545 + * For PAM-4: 546 + * IF (ADAPT_range = FINE) 547 + * TADAPT_L0_L3 = 2^9 x ADAPT_length 548 + * ELSE IF (ADAPT_range = COARSE) 549 + * TADAPT_L0_L3 = 2^9 x (2^ADAPT_length) 550 + * 551 + * Returns calculated TAdapt value in term of Unit Intervals (UI) 552 + */ 553 + static inline u64 adapt_cap_to_t_adapt_l0l3(u32 adapt_cap) 554 + { 555 + u64 tadapt; 556 + u8 adapt_length = adapt_cap & ADAPT_LENGTH_MASK; 557 + 558 + if (!IS_ADAPT_RANGE_COARSE(adapt_cap)) 559 + tadapt = TADAPT_L0L3_FACTOR * adapt_length; 560 + else 561 + tadapt = TADAPT_L0L3_FACTOR * (1 << adapt_length); 562 + 563 + return tadapt; 564 + } 565 + 566 + /** 567 + * adapt_cap_to_t_adapt_l0l1l2l3 - Calculate TAdapt_L0_L1_L2_L3 from adapt capability 568 + * @adapt_cap: Adapt capability 569 + * 570 + * For PAM-4: 571 + * IF (ADAPT_range_L0_L1_L2_L3 = FINE) 572 + * TADAPT_L0_L1_L2_L3 = 2^15 x (ADAPT_length_L0_L1_L2_L3 + 1) 573 + * ELSE IF (ADAPT_range_L0_L1_L2_L3 = COARSE) 574 + * TADAPT_L0_L1_L2_L3 = 2^15 x 2^ADAPT_length_L0_L1_L2_L3 575 + * 576 + * Returns calculated TAdapt value in term of Unit Intervals (UI) 577 + */ 578 + static inline u64 adapt_cap_to_t_adapt_l0l1l2l3(u32 adapt_cap) 579 + { 580 + u64 tadapt; 581 + u8 adapt_length = adapt_cap & ADAPT_LENGTH_MASK; 582 + 583 + if (!IS_ADAPT_RANGE_COARSE(adapt_cap)) 584 + tadapt = TADAPT_L0L1L2L3_FACTOR * (adapt_length + 1); 585 + else 586 + tadapt = TADAPT_L0L1L2L3_FACTOR * (1 << adapt_length); 587 + 588 + return tadapt; 589 + } 590 + 591 + /** 592 + * ufshcd_setup_tx_eqtr_adapt_length - Setup TX adapt length for EQTR 593 + * @hba: per adapter instance 594 + * @params: TX EQ parameters data structure 595 + * @gear: target gear for EQTR 596 + * 597 + * This function determines and configures the proper TX adapt length (TAdapt) 598 + * for the TX EQTR procedure based on the target gear and RX adapt capabilities 599 + * of both host and device. 600 + * 601 + * Guidelines from MIPI UniPro v3.0 spec - select the minimum Adapt Length for 602 + * the Equalization Training procedure based on the following conditions: 603 + * 604 + * If the target High-Speed Gear n is HS-G4 or HS-G5: 605 + * PA_TxAdaptLength_EQTR[7:0] >= Max (10us, RX_HS_Gn_ADAPT_INITIAL_Capability, 606 + * PA_PeerRxHsGnAdaptInitial) 607 + * PA_TxAdaptLength_EQTR[7:0] shall be shorter than PACP_REQUEST_TIMER (10ms) 608 + * PA_TxAdaptLength_EQTR[15:8] is not relevant for HS-G4 and HS-G5. This field 609 + * is set to 255 (reserved value). 610 + * 611 + * If the target High-Speed Gear n is HS-G6: 612 + * PA_TxAdapthLength_EQTR >= 10us 613 + * PA_TxAdapthLength_EQTR[7:0] >= Max (RX_HS_G6_ADAPT_INITIAL_Capability, 614 + * PA_PeerRxHsG6AdaptInitialL0L3) 615 + * PA_TxAdapthLength_EQTR[15:8] >= Max (RX_HS_G6_ADAPT_INITIAL_L0_L1_L2_L3_Capability, 616 + * PA_PeerRxHsG6AdaptInitialL0L1L2L3) 617 + * PA_TxAdaptLength_EQTR shall be shorter than PACP_REQUEST_TIMER value of 10ms. 618 + * 619 + * Since adapt capabilities encode both range (fine/coarse) and length values, 620 + * direct comparison is not possible. This function converts adapt capabilities 621 + * to actual time durations in Unit Intervals (UI) using the Adapt time 622 + * calculation formular in M-PHY v6.0 spec (Table 8), then selects the maximum 623 + * to ensure both host and device use adequate TX adapt length. 624 + * 625 + * Returns 0 on success, negative error code otherwise 626 + */ 627 + static int ufshcd_setup_tx_eqtr_adapt_length(struct ufs_hba *hba, 628 + struct ufshcd_tx_eq_params *params, 629 + u32 gear) 630 + { 631 + struct ufshcd_tx_eqtr_record *rec = params->eqtr_record; 632 + u32 adapt_eqtr; 633 + int ret; 634 + 635 + if (rec && rec->saved_adapt_eqtr) { 636 + adapt_eqtr = rec->saved_adapt_eqtr; 637 + goto set_adapt_eqtr; 638 + } 639 + 640 + if (gear == UFS_HS_G4 || gear == UFS_HS_G5) { 641 + u64 t_adapt, t_adapt_local, t_adapt_peer; 642 + u32 adapt_cap_local, adapt_cap_peer, adapt_length; 643 + 644 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(rx_adapt_initial_cap[gear - 1], 645 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 646 + &adapt_cap_local); 647 + if (ret) 648 + return ret; 649 + 650 + if (adapt_cap_local > ADAPT_LENGTH_MAX) { 651 + dev_err(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_CAP (0x%x) exceeds MAX\n", 652 + gear, adapt_cap_local); 653 + return -EINVAL; 654 + } 655 + 656 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(pa_peer_rx_adapt_initial[gear - 1]), 657 + &adapt_cap_peer); 658 + if (ret) 659 + return ret; 660 + 661 + if (adapt_cap_peer > ADAPT_LENGTH_MAX) { 662 + dev_err(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_CAP (0x%x) exceeds MAX\n", 663 + gear, adapt_cap_peer); 664 + return -EINVAL; 665 + } 666 + 667 + t_adapt_local = adapt_cap_to_t_adapt(adapt_cap_local); 668 + t_adapt_peer = adapt_cap_to_t_adapt(adapt_cap_peer); 669 + t_adapt = max(t_adapt_local, t_adapt_peer); 670 + 671 + dev_dbg(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_CAP = 0x%x\n", 672 + gear, adapt_cap_local); 673 + dev_dbg(hba->dev, "peer RX_HS_G%u_ADAPT_INITIAL_CAP = 0x%x\n", 674 + gear, adapt_cap_peer); 675 + dev_dbg(hba->dev, "t_adapt_local = %llu UI, t_adapt_peer = %llu UI\n", 676 + t_adapt_local, t_adapt_peer); 677 + dev_dbg(hba->dev, "TAdapt %llu UI selected for TX EQTR\n", 678 + t_adapt); 679 + 680 + adapt_length = (t_adapt_local >= t_adapt_peer) ? 681 + adapt_cap_local : adapt_cap_peer; 682 + 683 + if (gear == UFS_HS_G4 && t_adapt < TX_EQTR_HS_G4_MIN_T_ADAPT) { 684 + dev_dbg(hba->dev, "TAdapt %llu UI is too short for TX EQTR for HS-G%u, use default Adapt 0x%x\n", 685 + t_adapt, gear, TX_EQTR_HS_G4_ADAPT_DEFAULT); 686 + adapt_length = TX_EQTR_HS_G4_ADAPT_DEFAULT; 687 + } else if (gear == UFS_HS_G5 && t_adapt < TX_EQTR_HS_G5_MIN_T_ADAPT) { 688 + dev_dbg(hba->dev, "TAdapt %llu UI is too short for TX EQTR for HS-G%u, use default Adapt 0x%x\n", 689 + t_adapt, gear, TX_EQTR_HS_G5_ADAPT_DEFAULT); 690 + adapt_length = TX_EQTR_HS_G5_ADAPT_DEFAULT; 691 + } 692 + 693 + adapt_eqtr = adapt_length | 694 + (TX_EQTR_ADAPT_RESERVED << TX_EQTR_ADAPT_LENGTH_L0L1L2L3_SHIFT); 695 + } else if (gear == UFS_HS_G6) { 696 + u64 t_adapt, t_adapt_l0l3, t_adapt_l0l3_local, t_adapt_l0l3_peer; 697 + u64 t_adapt_l0l1l2l3, t_adapt_l0l1l2l3_local, t_adapt_l0l1l2l3_peer; 698 + u32 adapt_l0l3_cap_local, adapt_l0l3_cap_peer, adapt_length_l0l3; 699 + u32 adapt_l0l1l2l3_cap_local, adapt_l0l1l2l3_cap_peer, adapt_length_l0l1l2l3; 700 + 701 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(rx_adapt_initial_cap[gear - 1], 702 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 703 + &adapt_l0l3_cap_local); 704 + if (ret) 705 + return ret; 706 + 707 + if (adapt_l0l3_cap_local > ADAPT_L0L3_LENGTH_MAX) { 708 + dev_err(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_CAP (0x%x) exceeds MAX\n", 709 + gear, adapt_l0l3_cap_local); 710 + return -EINVAL; 711 + } 712 + 713 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(pa_peer_rx_adapt_initial[gear - 1]), 714 + &adapt_l0l3_cap_peer); 715 + if (ret) 716 + return ret; 717 + 718 + if (adapt_l0l3_cap_peer > ADAPT_L0L3_LENGTH_MAX) { 719 + dev_err(hba->dev, "peer RX_HS_G%u_ADAPT_INITIAL_CAP (0x%x) exceeds MAX\n", 720 + gear, adapt_l0l3_cap_peer); 721 + return -EINVAL; 722 + } 723 + 724 + t_adapt_l0l3_local = adapt_cap_to_t_adapt_l0l3(adapt_l0l3_cap_local); 725 + t_adapt_l0l3_peer = adapt_cap_to_t_adapt_l0l3(adapt_l0l3_cap_peer); 726 + 727 + dev_dbg(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_CAP = 0x%x\n", 728 + gear, adapt_l0l3_cap_local); 729 + dev_dbg(hba->dev, "peer RX_HS_G%u_ADAPT_INITIAL_CAP = 0x%x\n", 730 + gear, adapt_l0l3_cap_peer); 731 + dev_dbg(hba->dev, "t_adapt_l0l3_local = %llu UI, t_adapt_l0l3_peer = %llu UI\n", 732 + t_adapt_l0l3_local, t_adapt_l0l3_peer); 733 + 734 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(RX_HS_G6_ADAPT_INITIAL_L0L1L2L3_CAP, 735 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 736 + &adapt_l0l1l2l3_cap_local); 737 + if (ret) 738 + return ret; 739 + 740 + if (adapt_l0l1l2l3_cap_local > ADAPT_L0L1L2L3_LENGTH_MAX) { 741 + dev_err(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_L0L1L2L3_CAP (0x%x) exceeds MAX\n", 742 + gear, adapt_l0l1l2l3_cap_local); 743 + return -EINVAL; 744 + } 745 + 746 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PEERRXHSG6ADAPTINITIALL0L1L2L3), 747 + &adapt_l0l1l2l3_cap_peer); 748 + if (ret) 749 + return ret; 750 + 751 + if (adapt_l0l1l2l3_cap_peer > ADAPT_L0L1L2L3_LENGTH_MAX) { 752 + dev_err(hba->dev, "peer RX_HS_G%u_ADAPT_INITIAL_L0L1L2L3_CAP (0x%x) exceeds MAX\n", 753 + gear, adapt_l0l1l2l3_cap_peer); 754 + return -EINVAL; 755 + } 756 + 757 + t_adapt_l0l1l2l3_local = adapt_cap_to_t_adapt_l0l1l2l3(adapt_l0l1l2l3_cap_local); 758 + t_adapt_l0l1l2l3_peer = adapt_cap_to_t_adapt_l0l1l2l3(adapt_l0l1l2l3_cap_peer); 759 + 760 + dev_dbg(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_L0L1L2L3_CAP = 0x%x\n", 761 + gear, adapt_l0l1l2l3_cap_local); 762 + dev_dbg(hba->dev, "peer RX_HS_G%u_ADAPT_INITIAL_L0L1L2L3_CAP = 0x%x\n", 763 + gear, adapt_l0l1l2l3_cap_peer); 764 + dev_dbg(hba->dev, "t_adapt_l0l1l2l3_local = %llu UI, t_adapt_l0l1l2l3_peer = %llu UI\n", 765 + t_adapt_l0l1l2l3_local, t_adapt_l0l1l2l3_peer); 766 + 767 + t_adapt_l0l1l2l3 = max(t_adapt_l0l1l2l3_local, t_adapt_l0l1l2l3_peer); 768 + t_adapt_l0l3 = max(t_adapt_l0l3_local, t_adapt_l0l3_peer); 769 + t_adapt = t_adapt_l0l3 + t_adapt_l0l1l2l3; 770 + 771 + dev_dbg(hba->dev, "TAdapt %llu PAM-4 UI selected for TX EQTR\n", 772 + t_adapt); 773 + 774 + adapt_length_l0l3 = (t_adapt_l0l3_local >= t_adapt_l0l3_peer) ? 775 + adapt_l0l3_cap_local : adapt_l0l3_cap_peer; 776 + adapt_length_l0l1l2l3 = (t_adapt_l0l1l2l3_local >= t_adapt_l0l1l2l3_peer) ? 777 + adapt_l0l1l2l3_cap_local : adapt_l0l1l2l3_cap_peer; 778 + 779 + if (t_adapt < TX_EQTR_HS_G6_MIN_T_ADAPT) { 780 + dev_dbg(hba->dev, "TAdapt %llu UI is too short for TX EQTR for HS-G%u, use default Adapt 0x%x\n", 781 + t_adapt, gear, TX_EQTR_HS_G6_ADAPT_DEFAULT); 782 + adapt_length_l0l3 = TX_EQTR_HS_G6_ADAPT_DEFAULT; 783 + } 784 + 785 + adapt_eqtr = adapt_length_l0l3 | 786 + (adapt_length_l0l1l2l3 << TX_EQTR_ADAPT_LENGTH_L0L1L2L3_SHIFT); 787 + } else { 788 + return -EINVAL; 789 + } 790 + 791 + if (rec) 792 + rec->saved_adapt_eqtr = (u16)adapt_eqtr; 793 + 794 + set_adapt_eqtr: 795 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXADAPTLENGTH_EQTR), adapt_eqtr); 796 + if (ret) 797 + dev_err(hba->dev, "Failed to set adapt length for TX EQTR: %d\n", ret); 798 + else 799 + dev_dbg(hba->dev, "PA_TXADAPTLENGTH_EQTR configured to 0x%08x\n", adapt_eqtr); 800 + 801 + return ret; 802 + } 803 + 804 + /** 805 + * ufshcd_compose_tx_eqtr_setting - Compose TX EQTR setting 806 + * @iter: TX EQTR iterator data structure 807 + * @num_lanes: number of active lanes 808 + * 809 + * Returns composed TX EQTR setting, same setting is used for all active lanes 810 + */ 811 + static inline u32 ufshcd_compose_tx_eqtr_setting(struct tx_eqtr_iter *iter, 812 + int num_lanes) 813 + { 814 + u32 setting = 0; 815 + int lane; 816 + 817 + for (lane = 0; lane < num_lanes; lane++) { 818 + setting |= TX_HS_PRESHOOT_BITS(lane, iter->preshoot); 819 + setting |= TX_HS_DEEMPHASIS_BITS(lane, iter->deemphasis); 820 + } 821 + 822 + return setting; 823 + } 824 + 825 + /** 826 + * ufshcd_apply_tx_eqtr_settings - Apply TX EQTR setting 827 + * @hba: per adapter instance 828 + * @pwr_mode: target power mode containing gear and rate information 829 + * @h_iter: host TX EQTR iterator data structure 830 + * @d_iter: device TX EQTR iterator data structure 831 + * 832 + * Returns 0 on success, negative error code otherwise 833 + */ 834 + static int ufshcd_apply_tx_eqtr_settings(struct ufs_hba *hba, 835 + struct ufs_pa_layer_attr *pwr_mode, 836 + struct tx_eqtr_iter *h_iter, 837 + struct tx_eqtr_iter *d_iter) 838 + { 839 + u32 setting; 840 + int ret; 841 + 842 + setting = ufshcd_compose_tx_eqtr_setting(h_iter, pwr_mode->lane_tx); 843 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXEQTRSETTING), setting); 844 + if (ret) 845 + return ret; 846 + 847 + setting = ufshcd_compose_tx_eqtr_setting(d_iter, pwr_mode->lane_rx); 848 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PEERTXEQTRSETTING), setting); 849 + if (ret) 850 + return ret; 851 + 852 + ret = ufshcd_vops_apply_tx_eqtr_settings(hba, pwr_mode, h_iter, d_iter); 853 + 854 + return ret; 855 + } 856 + 857 + /** 858 + * ufshcd_update_tx_eq_params - Update TX Equalization params 859 + * @params: TX EQ parameters data structure 860 + * @pwr_mode: target power mode containing gear and rate 861 + * @eqtr_data: TX EQTR data structure 862 + * 863 + * Update TX Equalization params using results from TX EQTR data. Check also 864 + * the TX EQTR FOM value for each TX lane in the TX EQTR data. If a TX lane got 865 + * a FOM value of 0, restore the TX Equalization settings from the last known 866 + * valid TX Equalization params for that specific TX lane. 867 + */ 868 + static inline void 869 + ufshcd_update_tx_eq_params(struct ufshcd_tx_eq_params *params, 870 + struct ufs_pa_layer_attr *pwr_mode, 871 + struct ufshcd_tx_eqtr_data *eqtr_data) 872 + { 873 + struct ufshcd_tx_eqtr_record *rec = params->eqtr_record; 874 + 875 + if (params->is_valid) { 876 + int lane; 877 + 878 + for (lane = 0; lane < pwr_mode->lane_tx; lane++) 879 + if (eqtr_data->host[lane].fom_val == 0) 880 + eqtr_data->host[lane] = params->host[lane]; 881 + 882 + for (lane = 0; lane < pwr_mode->lane_rx; lane++) 883 + if (eqtr_data->device[lane].fom_val == 0) 884 + eqtr_data->device[lane] = params->device[lane]; 885 + } 886 + 887 + memcpy(params->host, eqtr_data->host, sizeof(params->host)); 888 + memcpy(params->device, eqtr_data->device, sizeof(params->device)); 889 + 890 + if (!rec) 891 + return; 892 + 893 + memcpy(rec->host_fom, eqtr_data->host_fom, sizeof(rec->host_fom)); 894 + memcpy(rec->device_fom, eqtr_data->device_fom, sizeof(rec->device_fom)); 895 + rec->last_record_ts = ktime_get(); 896 + rec->last_record_index++; 897 + } 898 + 899 + /** 900 + * __ufshcd_tx_eqtr - TX Equalization Training (EQTR) procedure 901 + * @hba: per adapter instance 902 + * @params: TX EQ parameters data structure 903 + * @pwr_mode: target power mode containing gear and rate information 904 + * 905 + * This function implements the complete TX EQTR procedure as defined in UFSHCI 906 + * v5.0 specification. It iterates through all possible combinations of PreShoot 907 + * and DeEmphasis settings to find the optimal TX Equalization settings for all 908 + * active lanes. 909 + * 910 + * Returns 0 on success, negative error code otherwise 911 + */ 912 + static int __ufshcd_tx_eqtr(struct ufs_hba *hba, 913 + struct ufshcd_tx_eq_params *params, 914 + struct ufs_pa_layer_attr *pwr_mode) 915 + { 916 + struct ufshcd_tx_eqtr_data *eqtr_data __free(kfree) = 917 + kzalloc(sizeof(*eqtr_data), GFP_KERNEL); 918 + struct tx_eqtr_iter h_iter = {}; 919 + struct tx_eqtr_iter d_iter = {}; 920 + u32 gear = pwr_mode->gear_tx; 921 + u8 preshoot, deemphasis; 922 + ktime_t start; 923 + int ret; 924 + 925 + if (!eqtr_data) 926 + return -ENOMEM; 927 + 928 + dev_info(hba->dev, "Start TX EQTR procedure for HS-G%u, Rate-%s, RX Lanes: %u, TX Lanes: %u\n", 929 + gear, ufs_hs_rate_to_str(pwr_mode->hs_rate), 930 + pwr_mode->lane_rx, pwr_mode->lane_tx); 931 + 932 + start = ktime_get(); 933 + 934 + /* Step 1 - Determine the TX Adapt Length for EQTR */ 935 + ret = ufshcd_setup_tx_eqtr_adapt_length(hba, params, gear); 936 + if (ret) { 937 + dev_err(hba->dev, "Failed to setup TX EQTR Adaptation length: %d\n", ret); 938 + return ret; 939 + } 940 + 941 + /* Step 2 - Determine TX Equalization setting capabilities */ 942 + ret = ufshcd_tx_eqtr_iter_init(hba, &h_iter, &d_iter); 943 + if (ret) { 944 + dev_err(hba->dev, "Failed to init TX EQTR data: %d\n", ret); 945 + return ret; 946 + } 947 + 948 + /* TX EQTR main loop */ 949 + for (preshoot = 0; preshoot < TX_HS_NUM_PRESHOOT; preshoot++) { 950 + for (deemphasis = 0; deemphasis < TX_HS_NUM_DEEMPHASIS; deemphasis++) { 951 + if (!tx_eqtr_iter_update(preshoot, deemphasis, &h_iter, &d_iter)) 952 + continue; 953 + 954 + /* Step 3 - Apply TX EQTR settings */ 955 + ret = ufshcd_apply_tx_eqtr_settings(hba, pwr_mode, &h_iter, &d_iter); 956 + if (ret) { 957 + dev_err(hba->dev, "Failed to apply TX EQTR settings (PreShoot %u, DeEmphasis %u): %d\n", 958 + preshoot, deemphasis, ret); 959 + return ret; 960 + } 961 + 962 + /* Step 4 - Trigger UIC TX EQTR */ 963 + ret = ufshcd_uic_tx_eqtr(hba, gear); 964 + if (ret) { 965 + dev_err(hba->dev, "Failed to trigger UIC TX EQTR for target gear %u: %d\n", 966 + gear, ret); 967 + return ret; 968 + } 969 + 970 + /* Step 5 - Get FOM */ 971 + ret = ufshcd_get_rx_fom(hba, pwr_mode, &h_iter, &d_iter); 972 + if (ret) { 973 + dev_err(hba->dev, "Failed to get RX_FOM: %d\n", 974 + ret); 975 + return ret; 976 + } 977 + 978 + ufshcd_evaluate_tx_eqtr_fom(hba, pwr_mode, eqtr_data, &h_iter, &d_iter); 979 + } 980 + } 981 + 982 + dev_info(hba->dev, "TX EQTR procedure completed! Time elapsed: %llu ms\n", 983 + ktime_to_ms(ktime_sub(ktime_get(), start))); 984 + 985 + ufshcd_update_tx_eq_params(params, pwr_mode, eqtr_data); 986 + 987 + return ret; 988 + } 989 + 990 + /** 991 + * ufshcd_tx_eqtr_prepare - Prepare UFS link for TX EQTR procedure 992 + * @hba: per adapter instance 993 + * @pwr_mode: target power mode containing gear and rate 994 + * 995 + * This function prepares the UFS link for TX Equalization Training (EQTR) by 996 + * establishing the proper initial conditions required by the EQTR procedure. 997 + * It ensures that EQTR starts from the most reliable Power Mode (HS-G1) with 998 + * all connected lanes activated and sets host TX HS Adapt Type to INITIAL. 999 + * 1000 + * Returns 0 on successful preparation, negative error code on failure 1001 + */ 1002 + static int ufshcd_tx_eqtr_prepare(struct ufs_hba *hba, 1003 + struct ufs_pa_layer_attr *pwr_mode) 1004 + { 1005 + struct ufs_pa_layer_attr pwr_mode_hs_g1 = { 1006 + /* TX EQTR shall be initiated from the most reliable HS-G1 */ 1007 + .gear_rx = UFS_HS_G1, 1008 + .gear_tx = UFS_HS_G1, 1009 + .lane_rx = pwr_mode->lane_rx, 1010 + .lane_tx = pwr_mode->lane_tx, 1011 + .pwr_rx = FAST_MODE, 1012 + .pwr_tx = FAST_MODE, 1013 + /* Use the target power mode's HS rate */ 1014 + .hs_rate = pwr_mode->hs_rate, 1015 + }; 1016 + u32 rate = pwr_mode->hs_rate; 1017 + int ret; 1018 + 1019 + /* Change power mode to HS-G1, activate all connected lanes. */ 1020 + ret = ufshcd_change_power_mode(hba, &pwr_mode_hs_g1, 1021 + UFSHCD_PMC_POLICY_DONT_FORCE); 1022 + if (ret) { 1023 + dev_err(hba->dev, "TX EQTR: Failed to change power mode to HS-G1, Rate-%s: %d\n", 1024 + ufs_hs_rate_to_str(rate), ret); 1025 + return ret; 1026 + } 1027 + 1028 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXHSADAPTTYPE), 1029 + PA_INITIAL_ADAPT); 1030 + if (ret) 1031 + dev_err(hba->dev, "TX EQTR: Failed to set Host Adapt type to INITIAL: %d\n", 1032 + ret); 1033 + 1034 + return ret; 1035 + } 1036 + 1037 + static void ufshcd_tx_eqtr_unprepare(struct ufs_hba *hba, 1038 + struct ufs_pa_layer_attr *pwr_mode) 1039 + { 1040 + int err; 1041 + 1042 + if (pwr_mode->pwr_rx == SLOWAUTO_MODE || pwr_mode->hs_rate == 0) 1043 + return; 1044 + 1045 + err = ufshcd_change_power_mode(hba, pwr_mode, 1046 + UFSHCD_PMC_POLICY_DONT_FORCE); 1047 + if (err) 1048 + dev_err(hba->dev, "%s: Failed to restore Power Mode: %d\n", 1049 + __func__, err); 1050 + } 1051 + 1052 + /** 1053 + * ufshcd_tx_eqtr - Perform TX EQTR procedures with vops callbacks 1054 + * @hba: per adapter instance 1055 + * @params: TX EQ parameters data structure to populate 1056 + * @pwr_mode: target power mode containing gear and rate information 1057 + * 1058 + * This is the main entry point for performing TX Equalization Training (EQTR) 1059 + * procedure as defined in UFSCHI v5.0 specification. It serves as a wrapper 1060 + * around __ufshcd_tx_eqtr() to provide vops support through the variant 1061 + * operations framework. 1062 + * 1063 + * Returns 0 on success, negative error code on failure 1064 + */ 1065 + static int ufshcd_tx_eqtr(struct ufs_hba *hba, 1066 + struct ufshcd_tx_eq_params *params, 1067 + struct ufs_pa_layer_attr *pwr_mode) 1068 + { 1069 + struct ufs_pa_layer_attr old_pwr_info; 1070 + int ret; 1071 + 1072 + if (!params->eqtr_record) { 1073 + params->eqtr_record = devm_kzalloc(hba->dev, 1074 + sizeof(*params->eqtr_record), 1075 + GFP_KERNEL); 1076 + if (!params->eqtr_record) 1077 + return -ENOMEM; 1078 + } 1079 + 1080 + memcpy(&old_pwr_info, &hba->pwr_info, sizeof(struct ufs_pa_layer_attr)); 1081 + 1082 + ret = ufshcd_tx_eqtr_prepare(hba, pwr_mode); 1083 + if (ret) { 1084 + dev_err(hba->dev, "Failed to prepare TX EQTR: %d\n", ret); 1085 + goto out; 1086 + } 1087 + 1088 + ret = ufshcd_vops_tx_eqtr_notify(hba, PRE_CHANGE, pwr_mode); 1089 + if (ret) 1090 + goto out; 1091 + 1092 + ret = __ufshcd_tx_eqtr(hba, params, pwr_mode); 1093 + if (ret) 1094 + goto out; 1095 + 1096 + ret = ufshcd_vops_tx_eqtr_notify(hba, POST_CHANGE, pwr_mode); 1097 + 1098 + out: 1099 + if (ret) 1100 + ufshcd_tx_eqtr_unprepare(hba, &old_pwr_info); 1101 + 1102 + return ret; 1103 + } 1104 + 1105 + /** 1106 + * ufshcd_config_tx_eq_settings - Configure TX Equalization settings 1107 + * @hba: per adapter instance 1108 + * @pwr_mode: target power mode containing gear and rate information 1109 + * @force_tx_eqtr: execute the TX EQTR procedure 1110 + * 1111 + * This function finds and sets the TX Equalization settings for the given 1112 + * target power mode. 1113 + * 1114 + * Returns 0 on success, error code otherwise 1115 + */ 1116 + int ufshcd_config_tx_eq_settings(struct ufs_hba *hba, 1117 + struct ufs_pa_layer_attr *pwr_mode, 1118 + bool force_tx_eqtr) 1119 + { 1120 + struct ufshcd_tx_eq_params *params; 1121 + u32 gear, rate; 1122 + 1123 + if (!ufshcd_is_tx_eq_supported(hba) || !use_adaptive_txeq) 1124 + return 0; 1125 + 1126 + if (!hba->max_pwr_info.is_valid) { 1127 + dev_err(hba->dev, "Max power info is invalid\n"); 1128 + return -EINVAL; 1129 + } 1130 + 1131 + if (!pwr_mode) { 1132 + dev_err(hba->dev, "Target power mode is NULL\n"); 1133 + return -EINVAL; 1134 + } 1135 + 1136 + gear = pwr_mode->gear_tx; 1137 + rate = pwr_mode->hs_rate; 1138 + 1139 + if (gear < UFS_HS_G1 || gear > UFS_HS_GEAR_MAX) { 1140 + dev_err(hba->dev, "Invalid HS-Gear (%u) for TX Equalization\n", 1141 + gear); 1142 + return -EINVAL; 1143 + } else if (gear < max_t(u32, adaptive_txeq_gear, UFS_HS_G4)) { 1144 + /* TX EQTR is supported for HS-G4 and higher Gears */ 1145 + return 0; 1146 + } 1147 + 1148 + if (rate != PA_HS_MODE_A && rate != PA_HS_MODE_B) { 1149 + dev_err(hba->dev, "Invalid HS-Rate (%u) for TX Equalization\n", 1150 + rate); 1151 + return -EINVAL; 1152 + } 1153 + 1154 + params = &hba->tx_eq_params[gear - 1]; 1155 + if (!params->is_valid || force_tx_eqtr) { 1156 + int ret; 1157 + 1158 + ret = ufshcd_tx_eqtr(hba, params, pwr_mode); 1159 + if (ret) { 1160 + dev_err(hba->dev, "Failed to train TX Equalization for HS-G%u, Rate-%s: %d\n", 1161 + gear, ufs_hs_rate_to_str(rate), ret); 1162 + return ret; 1163 + } 1164 + 1165 + /* Mark TX Equalization settings as valid */ 1166 + params->is_valid = true; 1167 + params->is_applied = false; 1168 + } 1169 + 1170 + if (params->is_valid && !params->is_applied) { 1171 + int ret; 1172 + 1173 + ret = ufshcd_apply_tx_eq_settings(hba, params, gear); 1174 + if (ret) { 1175 + dev_err(hba->dev, "Failed to apply TX Equalization settings for HS-G%u, Rate-%s: %d\n", 1176 + gear, ufs_hs_rate_to_str(rate), ret); 1177 + return ret; 1178 + } 1179 + 1180 + params->is_applied = true; 1181 + } 1182 + 1183 + return 0; 1184 + } 1185 + 1186 + /** 1187 + * ufshcd_apply_valid_tx_eq_settings - Apply valid TX Equalization settings 1188 + * @hba: per-adapter instance 1189 + * 1190 + * This function iterates through all supported High-Speed (HS) gears and 1191 + * applies valid TX Equalization settings to both Host and Device. 1192 + */ 1193 + void ufshcd_apply_valid_tx_eq_settings(struct ufs_hba *hba) 1194 + { 1195 + struct ufshcd_tx_eq_params *params; 1196 + int gear, err; 1197 + 1198 + if (!ufshcd_is_tx_eq_supported(hba)) 1199 + return; 1200 + 1201 + if (!hba->max_pwr_info.is_valid) { 1202 + dev_err(hba->dev, "Max power info is invalid, cannot apply TX Equalization settings\n"); 1203 + return; 1204 + } 1205 + 1206 + for (gear = UFS_HS_G1; gear <= UFS_HS_GEAR_MAX; gear++) { 1207 + params = &hba->tx_eq_params[gear - 1]; 1208 + 1209 + if (params->is_valid) { 1210 + err = ufshcd_apply_tx_eq_settings(hba, params, gear); 1211 + if (err) { 1212 + params->is_applied = false; 1213 + dev_err(hba->dev, "Failed to apply TX Equalization settings for HS-G%u: %d\n", 1214 + gear, err); 1215 + } else { 1216 + params->is_applied = true; 1217 + } 1218 + } 1219 + } 1220 + } 1221 + 1222 + /** 1223 + * ufshcd_retrain_tx_eq - Retrain TX Equalization and apply new settings 1224 + * @hba: per-adapter instance 1225 + * @gear: target High-Speed (HS) gear for retraining 1226 + * 1227 + * This function initiates a refresh of the TX Equalization settings for a 1228 + * specific HS gear. It scales the clocks to maximum frequency, negotiates the 1229 + * power mode with the device, retrains TX EQ and applies new TX EQ settings 1230 + * by conducting a Power Mode change. 1231 + * 1232 + * Returns 0 on success, non-zero error code otherwise 1233 + */ 1234 + int ufshcd_retrain_tx_eq(struct ufs_hba *hba, u32 gear) 1235 + { 1236 + struct ufs_pa_layer_attr new_pwr_info, final_params = {}; 1237 + int ret; 1238 + 1239 + if (!ufshcd_is_tx_eq_supported(hba) || !use_adaptive_txeq) 1240 + return -EOPNOTSUPP; 1241 + 1242 + if (gear < adaptive_txeq_gear) 1243 + return -ERANGE; 1244 + 1245 + ufshcd_hold(hba); 1246 + 1247 + ret = ufshcd_pause_command_processing(hba, 1 * USEC_PER_SEC); 1248 + if (ret) { 1249 + ufshcd_release(hba); 1250 + return ret; 1251 + } 1252 + 1253 + /* scale up clocks to max frequency before TX EQTR */ 1254 + if (ufshcd_is_clkscaling_supported(hba)) 1255 + ufshcd_scale_clks(hba, ULONG_MAX, true); 1256 + 1257 + new_pwr_info = hba->pwr_info; 1258 + new_pwr_info.gear_tx = gear; 1259 + new_pwr_info.gear_rx = gear; 1260 + 1261 + ret = ufshcd_vops_negotiate_pwr_mode(hba, &new_pwr_info, &final_params); 1262 + if (ret) 1263 + memcpy(&final_params, &new_pwr_info, sizeof(final_params)); 1264 + 1265 + if (final_params.gear_tx != gear) { 1266 + dev_err(hba->dev, "Negotiated Gear (%u) does not match target Gear (%u)\n", 1267 + final_params.gear_tx, gear); 1268 + ret = -EINVAL; 1269 + goto out; 1270 + } 1271 + 1272 + ret = ufshcd_config_tx_eq_settings(hba, &final_params, true); 1273 + if (ret) { 1274 + dev_err(hba->dev, "Failed to config TX Equalization for HS-G%u, Rate-%s: %d\n", 1275 + final_params.gear_tx, 1276 + ufs_hs_rate_to_str(final_params.hs_rate), ret); 1277 + goto out; 1278 + } 1279 + 1280 + /* Change Power Mode to apply the new TX EQ settings */ 1281 + ret = ufshcd_change_power_mode(hba, &final_params, 1282 + UFSHCD_PMC_POLICY_FORCE); 1283 + if (ret) 1284 + dev_err(hba->dev, "%s: Failed to change Power Mode to HS-G%u, Rate-%s: %d\n", 1285 + __func__, final_params.gear_tx, 1286 + ufs_hs_rate_to_str(final_params.hs_rate), ret); 1287 + 1288 + out: 1289 + ufshcd_resume_command_processing(hba); 1290 + ufshcd_release(hba); 1291 + 1292 + return ret; 1293 + }
+57 -2
drivers/ufs/core/ufshcd-priv.h
··· 80 80 void ufshcd_mcq_write_mcqiacr(struct ufs_hba *hba, u32 val, int i); 81 81 int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag); 82 82 void ufshcd_release_scsi_cmd(struct ufs_hba *hba, struct scsi_cmnd *cmd); 83 + int ufshcd_pause_command_processing(struct ufs_hba *hba, u64 timeout_us); 84 + void ufshcd_resume_command_processing(struct ufs_hba *hba); 85 + int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq, bool scale_up); 83 86 84 87 /** 85 88 * enum ufs_descr_fmt - UFS string descriptor format ··· 107 104 108 105 int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable); 109 106 int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba, u64 *exception_id); 107 + 108 + int ufshcd_uic_tx_eqtr(struct ufs_hba *hba, int gear); 109 + void ufshcd_apply_valid_tx_eq_settings(struct ufs_hba *hba); 110 + int ufshcd_config_tx_eq_settings(struct ufs_hba *hba, 111 + struct ufs_pa_layer_attr *pwr_mode, 112 + bool force_tx_eqtr); 113 + void ufshcd_print_tx_eq_params(struct ufs_hba *hba); 114 + bool ufshcd_is_txeq_presets_used(struct ufs_hba *hba); 115 + bool ufshcd_is_txeq_preset_selected(u8 preshoot, u8 deemphasis); 116 + int ufshcd_retrain_tx_eq(struct ufs_hba *hba, u32 gear); 110 117 111 118 /* Wrapper functions for safely calling variant operations */ 112 119 static inline const char *ufshcd_get_var_name(struct ufs_hba *hba) ··· 182 169 return 0; 183 170 } 184 171 172 + static inline int ufshcd_vops_negotiate_pwr_mode(struct ufs_hba *hba, 173 + const struct ufs_pa_layer_attr *dev_max_params, 174 + struct ufs_pa_layer_attr *dev_req_params) 175 + { 176 + if (hba->vops && hba->vops->negotiate_pwr_mode) 177 + return hba->vops->negotiate_pwr_mode(hba, dev_max_params, 178 + dev_req_params); 179 + 180 + return -ENOTSUPP; 181 + } 182 + 185 183 static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba, 186 184 enum ufs_notify_change_status status, 187 - const struct ufs_pa_layer_attr *dev_max_params, 188 185 struct ufs_pa_layer_attr *dev_req_params) 189 186 { 190 187 if (hba->vops && hba->vops->pwr_change_notify) 191 188 return hba->vops->pwr_change_notify(hba, status, 192 - dev_max_params, dev_req_params); 189 + dev_req_params); 193 190 194 191 return -ENOTSUPP; 195 192 } ··· 308 285 { 309 286 if (hba->vops && hba->vops->freq_to_gear_speed) 310 287 return hba->vops->freq_to_gear_speed(hba, freq); 288 + 289 + return 0; 290 + } 291 + 292 + static inline int ufshcd_vops_get_rx_fom(struct ufs_hba *hba, 293 + struct ufs_pa_layer_attr *pwr_mode, 294 + struct tx_eqtr_iter *h_iter, 295 + struct tx_eqtr_iter *d_iter) 296 + { 297 + if (hba->vops && hba->vops->get_rx_fom) 298 + return hba->vops->get_rx_fom(hba, pwr_mode, h_iter, d_iter); 299 + 300 + return 0; 301 + } 302 + 303 + static inline int ufshcd_vops_apply_tx_eqtr_settings(struct ufs_hba *hba, 304 + struct ufs_pa_layer_attr *pwr_mode, 305 + struct tx_eqtr_iter *h_iter, 306 + struct tx_eqtr_iter *d_iter) 307 + { 308 + if (hba->vops && hba->vops->apply_tx_eqtr_settings) 309 + return hba->vops->apply_tx_eqtr_settings(hba, pwr_mode, h_iter, d_iter); 310 + 311 + return 0; 312 + } 313 + 314 + static inline int ufshcd_vops_tx_eqtr_notify(struct ufs_hba *hba, 315 + enum ufs_notify_change_status status, 316 + struct ufs_pa_layer_attr *pwr_mode) 317 + { 318 + if (hba->vops && hba->vops->tx_eqtr_notify) 319 + return hba->vops->tx_eqtr_notify(hba, status, pwr_mode); 311 320 312 321 return 0; 313 322 }
+160 -32
drivers/ufs/core/ufshcd.c
··· 333 333 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba); 334 334 static void ufshcd_resume_clkscaling(struct ufs_hba *hba); 335 335 static void ufshcd_suspend_clkscaling(struct ufs_hba *hba); 336 - static int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq, 337 - bool scale_up); 338 336 static irqreturn_t ufshcd_intr(int irq, void *__hba); 339 - static int ufshcd_change_power_mode(struct ufs_hba *hba, 340 - struct ufs_pa_layer_attr *pwr_mode); 341 337 static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on); 342 338 static int ufshcd_setup_vreg(struct ufs_hba *hba, bool on); 343 339 static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba, ··· 1207 1211 * 1208 1212 * Return: 0 if successful; < 0 upon failure. 1209 1213 */ 1210 - static int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq, 1211 - bool scale_up) 1214 + int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq, bool scale_up) 1212 1215 { 1213 1216 int ret = 0; 1214 1217 ktime_t start = ktime_get(); ··· 1361 1366 } 1362 1367 1363 1368 /** 1369 + * ufshcd_pause_command_processing - Pause command processing 1370 + * @hba: per-adapter instance 1371 + * @timeout_us: timeout in microseconds to wait for pending commands to finish 1372 + * 1373 + * This function stops new command submissions and waits for existing commands 1374 + * to complete. 1375 + * 1376 + * Return: 0 on success, %-EBUSY if commands did not finish within @timeout_us. 1377 + * On failure, all acquired locks are released and the tagset is unquiesced. 1378 + */ 1379 + int ufshcd_pause_command_processing(struct ufs_hba *hba, u64 timeout_us) 1380 + { 1381 + int ret = 0; 1382 + 1383 + mutex_lock(&hba->host->scan_mutex); 1384 + blk_mq_quiesce_tagset(&hba->host->tag_set); 1385 + down_write(&hba->clk_scaling_lock); 1386 + 1387 + if (ufshcd_wait_for_pending_cmds(hba, timeout_us)) { 1388 + ret = -EBUSY; 1389 + up_write(&hba->clk_scaling_lock); 1390 + blk_mq_unquiesce_tagset(&hba->host->tag_set); 1391 + mutex_unlock(&hba->host->scan_mutex); 1392 + } 1393 + 1394 + return ret; 1395 + } 1396 + 1397 + /** 1398 + * ufshcd_resume_command_processing - Resume command processing 1399 + * @hba: per-adapter instance 1400 + * 1401 + * This function resumes command submissions. 1402 + */ 1403 + void ufshcd_resume_command_processing(struct ufs_hba *hba) 1404 + { 1405 + up_write(&hba->clk_scaling_lock); 1406 + blk_mq_unquiesce_tagset(&hba->host->tag_set); 1407 + mutex_unlock(&hba->host->scan_mutex); 1408 + } 1409 + 1410 + /** 1364 1411 * ufshcd_scale_gear - scale up/down UFS gear 1365 1412 * @hba: per adapter instance 1366 1413 * @target_gear: target gear to scale to ··· 1447 1410 1448 1411 config_pwr_mode: 1449 1412 /* check if the power mode needs to be changed or not? */ 1450 - ret = ufshcd_config_pwr_mode(hba, &new_pwr_info); 1413 + ret = ufshcd_config_pwr_mode(hba, &new_pwr_info, 1414 + UFSHCD_PMC_POLICY_DONT_FORCE); 1451 1415 if (ret) 1452 1416 dev_err(hba->dev, "%s: failed err %d, old gear: (tx %d rx %d), new gear: (tx %d rx %d)", 1453 1417 __func__, ret, ··· 4289 4251 pwr_mode_change = true; 4290 4252 } 4291 4253 if (pwr_mode_change) { 4292 - ret = ufshcd_change_power_mode(hba, &temp_pwr_info); 4254 + ret = ufshcd_change_power_mode(hba, &temp_pwr_info, 4255 + UFSHCD_PMC_POLICY_DONT_FORCE); 4293 4256 if (ret) 4294 4257 goto out; 4295 4258 } ··· 4314 4275 4315 4276 if (peer && (hba->quirks & UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE) 4316 4277 && pwr_mode_change) 4317 - ufshcd_change_power_mode(hba, &orig_pwr_info); 4278 + ufshcd_change_power_mode(hba, &orig_pwr_info, 4279 + UFSHCD_PMC_POLICY_DONT_FORCE); 4318 4280 out: 4319 4281 return ret; 4320 4282 } ··· 4382 4342 ret = __ufshcd_send_uic_cmd(hba, cmd); 4383 4343 if (ret) { 4384 4344 dev_err(hba->dev, 4385 - "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n", 4386 - cmd->command, cmd->argument3, ret); 4345 + "pwr ctrl cmd 0x%x with (MIBattribute 0x%x, mode 0x%x) uic error %d\n", 4346 + cmd->command, UIC_GET_ATTR_ID(cmd->argument1), 4347 + cmd->argument3, ret); 4387 4348 goto out; 4388 4349 } 4389 4350 4390 4351 if (!wait_for_completion_timeout(hba->uic_async_done, 4391 4352 msecs_to_jiffies(uic_cmd_timeout))) { 4392 4353 dev_err(hba->dev, 4393 - "pwr ctrl cmd 0x%x with mode 0x%x completion timeout\n", 4394 - cmd->command, cmd->argument3); 4354 + "pwr ctrl cmd 0x%x with (MIBattribute 0x%x, mode 0x%x) completion timeout\n", 4355 + cmd->command, UIC_GET_ATTR_ID(cmd->argument1), 4356 + cmd->argument3); 4395 4357 4396 4358 if (!cmd->cmd_active) { 4397 4359 dev_err(hba->dev, "%s: Power Mode Change operation has been completed, go check UPMCRS\n", ··· 4409 4367 status = ufshcd_get_upmcrs(hba); 4410 4368 if (status != PWR_LOCAL) { 4411 4369 dev_err(hba->dev, 4412 - "pwr ctrl cmd 0x%x failed, host upmcrs:0x%x\n", 4413 - cmd->command, status); 4370 + "pwr ctrl cmd 0x%x with (MIBattribute 0x%x, mode 0x%x) failed, host upmcrs:0x%x\n", 4371 + cmd->command, UIC_GET_ATTR_ID(cmd->argument1), 4372 + cmd->argument3, status); 4414 4373 ret = (status != PWR_OK) ? status : -1; 4415 4374 } 4416 4375 out: 4417 4376 if (ret) { 4418 4377 ufshcd_print_host_state(hba); 4419 4378 ufshcd_print_pwr_info(hba); 4379 + ufshcd_print_tx_eq_params(hba); 4420 4380 ufshcd_print_evt_hist(hba); 4421 4381 } 4422 4382 ··· 4440 4396 */ 4441 4397 if (ret && hba->pm_op_in_progress) 4442 4398 ret = ufshcd_link_recovery(hba); 4399 + 4400 + return ret; 4401 + } 4402 + 4403 + /** 4404 + * ufshcd_uic_tx_eqtr - Perform UIC TX Equalization Training 4405 + * @hba: per adapter instance 4406 + * @gear: target gear for EQTR 4407 + * 4408 + * Returns 0 on success, negative error code otherwise 4409 + */ 4410 + int ufshcd_uic_tx_eqtr(struct ufs_hba *hba, int gear) 4411 + { 4412 + struct uic_command uic_cmd = { 4413 + .command = UIC_CMD_DME_SET, 4414 + .argument1 = UIC_ARG_MIB(PA_EQTR_GEAR), 4415 + .argument3 = gear, 4416 + }; 4417 + int ret; 4418 + 4419 + ufshcd_hold(hba); 4420 + ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); 4421 + ufshcd_release(hba); 4443 4422 4444 4423 return ret; 4445 4424 } ··· 4730 4663 return 0; 4731 4664 } 4732 4665 4733 - static int ufshcd_change_power_mode(struct ufs_hba *hba, 4734 - struct ufs_pa_layer_attr *pwr_mode) 4666 + /** 4667 + * ufshcd_dme_change_power_mode() - UniPro DME Power Mode change sequence 4668 + * @hba: per-adapter instance 4669 + * @pwr_mode: pointer to the target power mode (gear/lane) attributes 4670 + * @pmc_policy: Power Mode change policy 4671 + * 4672 + * This function handles the low-level DME (Device Management Entity) 4673 + * configuration required to transition the UFS link to a new power mode. It 4674 + * performs the following steps: 4675 + * 1. Checks if the requested mode matches the current state. 4676 + * 2. Sets M-PHY and UniPro attributes including Gear (PA_RXGEAR/TXGEAR), 4677 + * Lanes, Termination, and HS Series (PA_HSSERIES). 4678 + * 3. Configures default UniPro timeout values (DL_FC0, etc.) unless 4679 + * explicitly skipped via quirks. 4680 + * 4. Triggers the actual hardware mode change via ufshcd_uic_change_pwr_mode(). 4681 + * 5. Updates the HBA's cached power information on success. 4682 + * 4683 + * Return: 0 on success, non-zero error code on failure. 4684 + */ 4685 + static int ufshcd_dme_change_power_mode(struct ufs_hba *hba, 4686 + struct ufs_pa_layer_attr *pwr_mode, 4687 + enum ufshcd_pmc_policy pmc_policy) 4735 4688 { 4736 4689 int ret; 4737 4690 4738 4691 /* if already configured to the requested pwr_mode */ 4739 - if (!hba->force_pmc && 4692 + if (pmc_policy == UFSHCD_PMC_POLICY_DONT_FORCE && 4740 4693 pwr_mode->gear_rx == hba->pwr_info.gear_rx && 4741 4694 pwr_mode->gear_tx == hba->pwr_info.gear_tx && 4742 4695 pwr_mode->lane_rx == hba->pwr_info.lane_rx && ··· 4836 4749 } 4837 4750 4838 4751 /** 4752 + * ufshcd_change_power_mode() - Change UFS Link Power Mode 4753 + * @hba: per-adapter instance 4754 + * @pwr_mode: pointer to the target power mode (gear/lane) attributes 4755 + * @pmc_policy: Power Mode change policy 4756 + * 4757 + * This function handles the high-level sequence for changing the UFS link 4758 + * power mode. It triggers vendor-specific pre-change notification, 4759 + * executes the DME (Device Management Entity) power mode change sequence, 4760 + * and, upon success, triggers vendor-specific post-change notification. 4761 + * 4762 + * Return: 0 on success, non-zero error code on failure. 4763 + */ 4764 + int ufshcd_change_power_mode(struct ufs_hba *hba, 4765 + struct ufs_pa_layer_attr *pwr_mode, 4766 + enum ufshcd_pmc_policy pmc_policy) 4767 + { 4768 + int ret; 4769 + 4770 + ufshcd_vops_pwr_change_notify(hba, PRE_CHANGE, pwr_mode); 4771 + 4772 + ret = ufshcd_dme_change_power_mode(hba, pwr_mode, pmc_policy); 4773 + 4774 + if (!ret) 4775 + ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, pwr_mode); 4776 + 4777 + return ret; 4778 + } 4779 + EXPORT_SYMBOL_GPL(ufshcd_change_power_mode); 4780 + 4781 + /** 4839 4782 * ufshcd_config_pwr_mode - configure a new power mode 4840 4783 * @hba: per-adapter instance 4841 4784 * @desired_pwr_mode: desired power configuration 4785 + * @pmc_policy: Power Mode change policy 4842 4786 * 4843 4787 * Return: 0 upon success; < 0 upon failure. 4844 4788 */ 4845 4789 int ufshcd_config_pwr_mode(struct ufs_hba *hba, 4846 - struct ufs_pa_layer_attr *desired_pwr_mode) 4790 + struct ufs_pa_layer_attr *desired_pwr_mode, 4791 + enum ufshcd_pmc_policy pmc_policy) 4847 4792 { 4848 4793 struct ufs_pa_layer_attr final_params = { 0 }; 4849 4794 int ret; 4850 4795 4851 - ret = ufshcd_vops_pwr_change_notify(hba, PRE_CHANGE, 4852 - desired_pwr_mode, &final_params); 4796 + ret = ufshcd_vops_negotiate_pwr_mode(hba, desired_pwr_mode, 4797 + &final_params); 4798 + if (ret) { 4799 + if (ret != -ENOTSUPP) 4800 + dev_err(hba->dev, "Failed to negotiate power mode: %d, use desired as is\n", 4801 + ret); 4853 4802 4854 - if (ret) 4855 4803 memcpy(&final_params, desired_pwr_mode, sizeof(final_params)); 4804 + } 4856 4805 4857 - ret = ufshcd_change_power_mode(hba, &final_params); 4806 + ret = ufshcd_config_tx_eq_settings(hba, &final_params, false); 4807 + if (ret) 4808 + dev_warn(hba->dev, "Failed to configure TX Equalization for HS-G%u, Rate-%s: %d\n", 4809 + final_params.gear_tx, 4810 + ufs_hs_rate_to_str(final_params.hs_rate), ret); 4858 4811 4859 - if (!ret) 4860 - ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL, 4861 - &final_params); 4862 - 4863 - return ret; 4812 + return ufshcd_change_power_mode(hba, &final_params, pmc_policy); 4864 4813 } 4865 4814 EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode); 4866 4815 ··· 6898 6775 spin_unlock_irqrestore(hba->host->host_lock, flags); 6899 6776 ufshcd_print_host_state(hba); 6900 6777 ufshcd_print_pwr_info(hba); 6778 + ufshcd_print_tx_eq_params(hba); 6901 6779 ufshcd_print_evt_hist(hba); 6902 6780 ufshcd_print_tmrs(hba, hba->outstanding_tasks); 6903 6781 ufshcd_print_trs_all(hba, pr_prdt); ··· 6957 6833 * are sent via bsg and/or sysfs. 6958 6834 */ 6959 6835 down_write(&hba->clk_scaling_lock); 6960 - hba->force_pmc = true; 6961 - pmc_err = ufshcd_config_pwr_mode(hba, &(hba->pwr_info)); 6836 + pmc_err = ufshcd_config_pwr_mode(hba, &hba->pwr_info, 6837 + UFSHCD_PMC_POLICY_FORCE); 6962 6838 if (pmc_err) { 6963 6839 needs_reset = true; 6964 6840 dev_err(hba->dev, "%s: Failed to restore power mode, err = %d\n", 6965 6841 __func__, pmc_err); 6966 6842 } 6967 - hba->force_pmc = false; 6968 6843 ufshcd_print_pwr_info(hba); 6969 6844 up_write(&hba->clk_scaling_lock); 6970 6845 spin_lock_irqsave(hba->host->host_lock, flags); ··· 7171 7048 ufshcd_dump_regs(hba, 0, UFSHCI_REG_SPACE_SIZE, 7172 7049 "host_regs: "); 7173 7050 ufshcd_print_pwr_info(hba); 7051 + ufshcd_print_tx_eq_params(hba); 7174 7052 } 7175 7053 ufshcd_schedule_eh_work(hba); 7176 7054 retval |= IRQ_HANDLED; ··· 7967 7843 ufshcd_print_evt_hist(hba); 7968 7844 ufshcd_print_host_state(hba); 7969 7845 ufshcd_print_pwr_info(hba); 7846 + ufshcd_print_tx_eq_params(hba); 7970 7847 ufshcd_print_tr(hba, cmd, true); 7971 7848 } else { 7972 7849 ufshcd_print_tr(hba, cmd, false); ··· 8945 8820 8946 8821 if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_HIBER8TIME) 8947 8822 ufshcd_quirk_override_pa_h8time(hba); 8823 + 8824 + ufshcd_apply_valid_tx_eq_settings(hba); 8948 8825 } 8949 8826 8950 8827 static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba) ··· 9271 9144 if (hba->dev_ref_clk_freq != REF_CLK_FREQ_INVAL) 9272 9145 ufshcd_set_dev_ref_clk(hba); 9273 9146 /* Gear up to HS gear. */ 9274 - ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info); 9147 + ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info, 9148 + UFSHCD_PMC_POLICY_DONT_FORCE); 9275 9149 if (ret) { 9276 9150 dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n", 9277 9151 __func__, ret);
-3
drivers/ufs/host/ufs-amd-versal2.c
··· 443 443 } 444 444 445 445 static int ufs_versal2_pwr_change_notify(struct ufs_hba *hba, enum ufs_notify_change_status status, 446 - const struct ufs_pa_layer_attr *dev_max_params, 447 446 struct ufs_pa_layer_attr *dev_req_params) 448 447 { 449 448 struct ufs_versal2_host *host = ufshcd_get_variant(hba); ··· 450 451 int ret = 0; 451 452 452 453 if (status == PRE_CHANGE) { 453 - memcpy(dev_req_params, dev_max_params, sizeof(struct ufs_pa_layer_attr)); 454 - 455 454 /* If it is not a calibrated part, switch PWRMODE to SLOW_MODE */ 456 455 if (!host->attcompval0 && !host->attcompval1 && !host->ctlecompval0 && 457 456 !host->ctlecompval1) {
+17 -17
drivers/ufs/host/ufs-exynos.c
··· 818 818 } 819 819 820 820 static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba, 821 - const struct ufs_pa_layer_attr *dev_max_params, 822 821 struct ufs_pa_layer_attr *dev_req_params) 823 822 { 824 823 struct exynos_ufs *ufs = ufshcd_get_variant(hba); 825 824 struct phy *generic_phy = ufs->phy; 826 - struct ufs_host_params host_params; 827 825 int ret; 828 826 829 827 if (!dev_req_params) { 830 828 pr_err("%s: incoming dev_req_params is NULL\n", __func__); 831 829 ret = -EINVAL; 832 - goto out; 833 - } 834 - 835 - ufshcd_init_host_params(&host_params); 836 - 837 - /* This driver only support symmetric gear setting e.g. hs_tx_gear == hs_rx_gear */ 838 - host_params.hs_tx_gear = exynos_ufs_get_hs_gear(hba); 839 - host_params.hs_rx_gear = exynos_ufs_get_hs_gear(hba); 840 - 841 - ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); 842 - if (ret) { 843 - pr_err("%s: failed to determine capabilities\n", __func__); 844 830 goto out; 845 831 } 846 832 ··· 1663 1677 return ret; 1664 1678 } 1665 1679 1680 + static int exynos_ufs_negotiate_pwr_mode(struct ufs_hba *hba, 1681 + const struct ufs_pa_layer_attr *dev_max_params, 1682 + struct ufs_pa_layer_attr *dev_req_params) 1683 + { 1684 + struct ufs_host_params host_params; 1685 + 1686 + ufshcd_init_host_params(&host_params); 1687 + 1688 + /* This driver only support symmetric gear setting e.g. hs_tx_gear == hs_rx_gear */ 1689 + host_params.hs_tx_gear = exynos_ufs_get_hs_gear(hba); 1690 + host_params.hs_rx_gear = exynos_ufs_get_hs_gear(hba); 1691 + 1692 + return ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); 1693 + } 1694 + 1666 1695 static int exynos_ufs_pwr_change_notify(struct ufs_hba *hba, 1667 1696 enum ufs_notify_change_status status, 1668 - const struct ufs_pa_layer_attr *dev_max_params, 1669 1697 struct ufs_pa_layer_attr *dev_req_params) 1670 1698 { 1671 1699 int ret = 0; 1672 1700 1673 1701 switch (status) { 1674 1702 case PRE_CHANGE: 1675 - ret = exynos_ufs_pre_pwr_mode(hba, dev_max_params, 1676 - dev_req_params); 1703 + ret = exynos_ufs_pre_pwr_mode(hba, dev_req_params); 1677 1704 break; 1678 1705 case POST_CHANGE: 1679 1706 ret = exynos_ufs_post_pwr_mode(hba, dev_req_params); ··· 2014 2015 .exit = exynos_ufs_exit, 2015 2016 .hce_enable_notify = exynos_ufs_hce_enable_notify, 2016 2017 .link_startup_notify = exynos_ufs_link_startup_notify, 2018 + .negotiate_pwr_mode = exynos_ufs_negotiate_pwr_mode, 2017 2019 .pwr_change_notify = exynos_ufs_pwr_change_notify, 2018 2020 .setup_clocks = exynos_ufs_setup_clocks, 2019 2021 .setup_xfer_req = exynos_ufs_specify_nexus_t_xfer_req,
+13 -10
drivers/ufs/host/ufs-hisi.c
··· 298 298 ufshcd_init_host_params(host_params); 299 299 } 300 300 301 + static int ufs_hisi_negotiate_pwr_mode(struct ufs_hba *hba, 302 + const struct ufs_pa_layer_attr *dev_max_params, 303 + struct ufs_pa_layer_attr *dev_req_params) 304 + { 305 + struct ufs_host_params host_params; 306 + 307 + ufs_hisi_set_dev_cap(&host_params); 308 + 309 + return ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); 310 + } 311 + 301 312 static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba) 302 313 { 303 314 struct ufs_hisi_host *host = ufshcd_get_variant(hba); ··· 373 362 374 363 static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba, 375 364 enum ufs_notify_change_status status, 376 - const struct ufs_pa_layer_attr *dev_max_params, 377 365 struct ufs_pa_layer_attr *dev_req_params) 378 366 { 379 - struct ufs_host_params host_params; 380 367 int ret = 0; 381 368 382 369 if (!dev_req_params) { ··· 386 377 387 378 switch (status) { 388 379 case PRE_CHANGE: 389 - ufs_hisi_set_dev_cap(&host_params); 390 - ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); 391 - if (ret) { 392 - dev_err(hba->dev, 393 - "%s: failed to determine capabilities\n", __func__); 394 - goto out; 395 - } 396 - 397 380 ufs_hisi_pwr_change_pre_change(hba); 398 381 break; 399 382 case POST_CHANGE: ··· 544 543 .name = "hi3660", 545 544 .init = ufs_hi3660_init, 546 545 .link_startup_notify = ufs_hisi_link_startup_notify, 546 + .negotiate_pwr_mode = ufs_hisi_negotiate_pwr_mode, 547 547 .pwr_change_notify = ufs_hisi_pwr_change_notify, 548 548 .suspend = ufs_hisi_suspend, 549 549 .resume = ufs_hisi_resume, ··· 554 552 .name = "hi3670", 555 553 .init = ufs_hi3670_init, 556 554 .link_startup_notify = ufs_hisi_link_startup_notify, 555 + .negotiate_pwr_mode = ufs_hisi_negotiate_pwr_mode, 557 556 .pwr_change_notify = ufs_hisi_pwr_change_notify, 558 557 .suspend = ufs_hisi_suspend, 559 558 .resume = ufs_hisi_resume,
+20 -20
drivers/ufs/host/ufs-mediatek.c
··· 1317 1317 return err; 1318 1318 } 1319 1319 1320 + static int ufs_mtk_negotiate_pwr_mode(struct ufs_hba *hba, 1321 + const struct ufs_pa_layer_attr *dev_max_params, 1322 + struct ufs_pa_layer_attr *dev_req_params) 1323 + { 1324 + struct ufs_host_params host_params; 1325 + 1326 + ufshcd_init_host_params(&host_params); 1327 + host_params.hs_rx_gear = UFS_HS_G5; 1328 + host_params.hs_tx_gear = UFS_HS_G5; 1329 + 1330 + if (dev_max_params->pwr_rx == SLOW_MODE || 1331 + dev_max_params->pwr_tx == SLOW_MODE) 1332 + host_params.desired_working_mode = UFS_PWM_MODE; 1333 + 1334 + return ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); 1335 + } 1336 + 1320 1337 static bool ufs_mtk_pmc_via_fastauto(struct ufs_hba *hba, 1321 1338 struct ufs_pa_layer_attr *dev_req_params) 1322 1339 { ··· 1389 1372 } 1390 1373 1391 1374 static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, 1392 - const struct ufs_pa_layer_attr *dev_max_params, 1393 1375 struct ufs_pa_layer_attr *dev_req_params) 1394 1376 { 1395 1377 struct ufs_mtk_host *host = ufshcd_get_variant(hba); 1396 - struct ufs_host_params host_params; 1397 - int ret; 1398 - 1399 - ufshcd_init_host_params(&host_params); 1400 - host_params.hs_rx_gear = UFS_HS_G5; 1401 - host_params.hs_tx_gear = UFS_HS_G5; 1402 - 1403 - if (dev_max_params->pwr_rx == SLOW_MODE || 1404 - dev_max_params->pwr_tx == SLOW_MODE) 1405 - host_params.desired_working_mode = UFS_PWM_MODE; 1406 - 1407 - ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); 1408 - if (ret) { 1409 - pr_info("%s: failed to determine capabilities\n", 1410 - __func__); 1411 - } 1378 + int ret = 0; 1412 1379 1413 1380 if (ufs_mtk_pmc_via_fastauto(hba, dev_req_params)) { 1414 1381 ufs_mtk_adjust_sync_length(hba); ··· 1504 1503 1505 1504 static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba, 1506 1505 enum ufs_notify_change_status stage, 1507 - const struct ufs_pa_layer_attr *dev_max_params, 1508 1506 struct ufs_pa_layer_attr *dev_req_params) 1509 1507 { 1510 1508 int ret = 0; ··· 1515 1515 reg = ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER); 1516 1516 ufs_mtk_auto_hibern8_disable(hba); 1517 1517 } 1518 - ret = ufs_mtk_pre_pwr_change(hba, dev_max_params, 1519 - dev_req_params); 1518 + ret = ufs_mtk_pre_pwr_change(hba, dev_req_params); 1520 1519 break; 1521 1520 case POST_CHANGE: 1522 1521 if (ufshcd_is_auto_hibern8_supported(hba)) ··· 2328 2329 .setup_clocks = ufs_mtk_setup_clocks, 2329 2330 .hce_enable_notify = ufs_mtk_hce_enable_notify, 2330 2331 .link_startup_notify = ufs_mtk_link_startup_notify, 2332 + .negotiate_pwr_mode = ufs_mtk_negotiate_pwr_mode, 2331 2333 .pwr_change_notify = ufs_mtk_pwr_change_notify, 2332 2334 .apply_dev_quirks = ufs_mtk_apply_dev_quirks, 2333 2335 .fixup_dev_quirks = ufs_mtk_fixup_dev_quirks,
+580 -11
drivers/ufs/host/ufs-qcom.c
··· 966 966 } 967 967 } 968 968 969 - static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, 970 - enum ufs_notify_change_status status, 971 - const struct ufs_pa_layer_attr *dev_max_params, 972 - struct ufs_pa_layer_attr *dev_req_params) 969 + static int ufs_qcom_negotiate_pwr_mode(struct ufs_hba *hba, 970 + const struct ufs_pa_layer_attr *dev_max_params, 971 + struct ufs_pa_layer_attr *dev_req_params) 973 972 { 974 973 struct ufs_qcom_host *host = ufshcd_get_variant(hba); 975 974 struct ufs_host_params *host_params = &host->host_params; 975 + 976 + return ufshcd_negotiate_pwr_params(host_params, dev_max_params, dev_req_params); 977 + } 978 + 979 + static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, 980 + enum ufs_notify_change_status status, 981 + struct ufs_pa_layer_attr *dev_req_params) 982 + { 983 + struct ufs_qcom_host *host = ufshcd_get_variant(hba); 976 984 int ret = 0; 977 985 978 986 if (!dev_req_params) { ··· 990 982 991 983 switch (status) { 992 984 case PRE_CHANGE: 993 - ret = ufshcd_negotiate_pwr_params(host_params, dev_max_params, dev_req_params); 994 - if (ret) { 995 - dev_err(hba->dev, "%s: failed to determine capabilities\n", 996 - __func__); 997 - return ret; 998 - } 999 - 1000 985 /* 1001 986 * During UFS driver probe, always update the PHY gear to match the negotiated 1002 987 * gear, so that, if quirk UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH is enabled, ··· 1069 1068 dev_err(hba->dev, "Failed (%d) set PA_TX_HSG1_SYNC_LENGTH\n", err); 1070 1069 } 1071 1070 1071 + /** 1072 + * ufs_qcom_double_t_adapt_l0l1l2l3 - Create a new adapt that doubles the 1073 + * adaptation duration TADAPT_L0_L1_L2_L3 derived from the old adapt. 1074 + * 1075 + * @old_adapt: Original ADAPT_L0_L1_L2_L3 capability 1076 + * 1077 + * ADAPT_length_L0_L1_L2_L3 formula from M-PHY spec: 1078 + * if (ADAPT_range_L0_L1_L2_L3 == COARSE) { 1079 + * ADAPT_length_L0_L1_L2_L3 = [0, 12] 1080 + * ADAPT_L0_L1_L2_L3 = 215 x 2^ADAPT_length_L0_L1_L2_L3 1081 + * } else if (ADAPT_range_L0_L1_L2_L3 == FINE) { 1082 + * ADAPT_length_L0_L1_L2_L3 = [0, 127] 1083 + * TADAPT_L0_L1_L2_L3 = 215 x (ADAPT_length_L0_L1_L2_L3 + 1) 1084 + * } 1085 + * 1086 + * To double the adaptation duration TADAPT_L0_L1_L2_L3: 1087 + * 1. If adapt range is COARSE (1'b1), new adapt = old adapt + 1. 1088 + * 2. If adapt range is FINE (1'b0): 1089 + * a) If old adapt length is < 64, (new adapt + 1) = 2 * (old adapt + 1). 1090 + * b) If old adapt length is >= 64, set new adapt to 0x88 using COARSE 1091 + * range, because new adapt get from equation in a) shall exceed 127. 1092 + * 1093 + * Examples: 1094 + * ADAPT_range_L0_L1_L2_L3 | ADAPT_length_L0_L1_L2_L3 | TADAPT_L0_L1_L2_L3 (PAM-4 UI) 1095 + * 0 3 131072 1096 + * 0 7 262144 1097 + * 0 63 2097152 1098 + * 0 64 2129920 1099 + * 0 127 4194304 1100 + * 1 8 8388608 1101 + * 1 9 16777216 1102 + * 1 10 33554432 1103 + * 1 11 67108864 1104 + * 1 12 134217728 1105 + * 1106 + * Return: new adapt. 1107 + */ 1108 + static u32 ufs_qcom_double_t_adapt_l0l1l2l3(u32 old_adapt) 1109 + { 1110 + u32 adapt_length = old_adapt & ADAPT_LENGTH_MASK; 1111 + u32 new_adapt; 1112 + 1113 + if (IS_ADAPT_RANGE_COARSE(old_adapt)) { 1114 + new_adapt = (adapt_length + 1) | ADAPT_RANGE_BIT; 1115 + } else { 1116 + if (adapt_length < 64) 1117 + new_adapt = (adapt_length << 1) + 1; 1118 + else 1119 + /* 1120 + * 0x88 is the very coarse Adapt value which is two 1121 + * times of the largest fine Adapt value (0x7F) 1122 + */ 1123 + new_adapt = 0x88; 1124 + } 1125 + 1126 + return new_adapt; 1127 + } 1128 + 1129 + static void ufs_qcom_limit_max_gear(struct ufs_hba *hba, 1130 + enum ufs_hs_gear_tag gear) 1131 + { 1132 + struct ufs_qcom_host *host = ufshcd_get_variant(hba); 1133 + struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info; 1134 + struct ufs_host_params *host_params = &host->host_params; 1135 + 1136 + host_params->hs_tx_gear = gear; 1137 + host_params->hs_rx_gear = gear; 1138 + pwr_info->gear_tx = gear; 1139 + pwr_info->gear_rx = gear; 1140 + 1141 + dev_warn(hba->dev, "Limited max gear of host and device to HS-G%d\n", gear); 1142 + } 1143 + 1144 + static void ufs_qcom_fixup_tx_adapt_l0l1l2l3(struct ufs_hba *hba) 1145 + { 1146 + struct ufs_qcom_host *host = ufshcd_get_variant(hba); 1147 + struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info; 1148 + struct ufs_host_params *host_params = &host->host_params; 1149 + u32 old_adapt, new_adapt, actual_adapt; 1150 + bool limit_speed = false; 1151 + int err; 1152 + 1153 + if (host->hw_ver.major != 0x7 || host->hw_ver.minor > 0x1 || 1154 + host_params->hs_tx_gear <= UFS_HS_G5 || 1155 + pwr_info->gear_tx <= UFS_HS_G5) 1156 + return; 1157 + 1158 + err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PEERRXHSG6ADAPTINITIALL0L1L2L3), &old_adapt); 1159 + if (err) 1160 + goto out; 1161 + 1162 + if (old_adapt > ADAPT_L0L1L2L3_LENGTH_MAX) { 1163 + dev_err(hba->dev, "PA_PeerRxHsG6AdaptInitialL0L1L2L3 value (0x%x) exceeds MAX\n", 1164 + old_adapt); 1165 + err = -ERANGE; 1166 + goto out; 1167 + } 1168 + 1169 + new_adapt = ufs_qcom_double_t_adapt_l0l1l2l3(old_adapt); 1170 + dev_dbg(hba->dev, "Original PA_PeerRxHsG6AdaptInitialL0L1L2L3 = 0x%x, new value = 0x%x\n", 1171 + old_adapt, new_adapt); 1172 + 1173 + /* 1174 + * 0x8C is the max possible value allowed by UniPro v3.0 spec, some HWs 1175 + * can accept 0x8D but some cannot. 1176 + */ 1177 + if (new_adapt <= ADAPT_L0L1L2L3_LENGTH_MAX || 1178 + (new_adapt == ADAPT_L0L1L2L3_LENGTH_MAX + 1 && host->hw_ver.minor == 0x1)) { 1179 + err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PEERRXHSG6ADAPTINITIALL0L1L2L3), 1180 + new_adapt); 1181 + if (err) 1182 + goto out; 1183 + 1184 + err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PEERRXHSG6ADAPTINITIALL0L1L2L3), 1185 + &actual_adapt); 1186 + if (err) 1187 + goto out; 1188 + 1189 + if (actual_adapt != new_adapt) { 1190 + limit_speed = true; 1191 + dev_warn(hba->dev, "PA_PeerRxHsG6AdaptInitialL0L1L2L3 0x%x, expect 0x%x\n", 1192 + actual_adapt, new_adapt); 1193 + } 1194 + } else { 1195 + limit_speed = true; 1196 + dev_warn(hba->dev, "New PA_PeerRxHsG6AdaptInitialL0L1L2L3 (0x%x) is too large!\n", 1197 + new_adapt); 1198 + } 1199 + 1200 + err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PEERRXHSG6ADAPTREFRESHL0L1L2L3), &old_adapt); 1201 + if (err) 1202 + goto out; 1203 + 1204 + if (old_adapt > ADAPT_L0L1L2L3_LENGTH_MAX) { 1205 + dev_err(hba->dev, "PA_PeerRxHsG6AdaptRefreshL0L1L2L3 value (0x%x) exceeds MAX\n", 1206 + old_adapt); 1207 + err = -ERANGE; 1208 + goto out; 1209 + } 1210 + 1211 + new_adapt = ufs_qcom_double_t_adapt_l0l1l2l3(old_adapt); 1212 + dev_dbg(hba->dev, "Original PA_PeerRxHsG6AdaptRefreshL0L1L2L3 = 0x%x, new value = 0x%x\n", 1213 + old_adapt, new_adapt); 1214 + 1215 + /* 1216 + * 0x8C is the max possible value allowed by UniPro v3.0 spec, some HWs 1217 + * can accept 0x8D but some cannot. 1218 + */ 1219 + if (new_adapt <= ADAPT_L0L1L2L3_LENGTH_MAX || 1220 + (new_adapt == ADAPT_L0L1L2L3_LENGTH_MAX + 1 && host->hw_ver.minor == 0x1)) { 1221 + err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PEERRXHSG6ADAPTREFRESHL0L1L2L3), 1222 + new_adapt); 1223 + if (err) 1224 + goto out; 1225 + 1226 + err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PEERRXHSG6ADAPTREFRESHL0L1L2L3), 1227 + &actual_adapt); 1228 + if (err) 1229 + goto out; 1230 + 1231 + if (actual_adapt != new_adapt) { 1232 + limit_speed = true; 1233 + dev_warn(hba->dev, "PA_PeerRxHsG6AdaptRefreshL0L1L2L3 0x%x, expect 0x%x\n", 1234 + new_adapt, actual_adapt); 1235 + } 1236 + } else { 1237 + limit_speed = true; 1238 + dev_warn(hba->dev, "New PA_PeerRxHsG6AdaptRefreshL0L1L2L3 (0x%x) is too large!\n", 1239 + new_adapt); 1240 + } 1241 + 1242 + out: 1243 + if (limit_speed || err) 1244 + ufs_qcom_limit_max_gear(hba, UFS_HS_G5); 1245 + } 1246 + 1072 1247 static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba) 1073 1248 { 1074 1249 int err = 0; 1250 + 1251 + ufs_qcom_fixup_tx_adapt_l0l1l2l3(hba); 1075 1252 1076 1253 if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME) 1077 1254 err = ufs_qcom_quirk_host_pa_saveconfigtime(hba); ··· 1384 1205 1385 1206 static void ufs_qcom_set_caps(struct ufs_hba *hba) 1386 1207 { 1208 + struct ufs_qcom_host *host = ufshcd_get_variant(hba); 1209 + 1387 1210 hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; 1388 1211 hba->caps |= UFSHCD_CAP_CLK_SCALING | UFSHCD_CAP_WB_WITH_CLK_SCALING; 1389 1212 hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; 1390 1213 hba->caps |= UFSHCD_CAP_WB_EN; 1391 1214 hba->caps |= UFSHCD_CAP_AGGR_POWER_COLLAPSE; 1392 1215 hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND; 1216 + 1217 + if (host->hw_ver.major >= 0x7) 1218 + hba->caps |= UFSHCD_CAP_TX_EQUALIZATION; 1393 1219 1394 1220 ufs_qcom_set_host_caps(hba); 1395 1221 } ··· 2510 2326 return min_t(u32, gear, hba->max_pwr_info.info.gear_rx); 2511 2327 } 2512 2328 2329 + static int ufs_qcom_host_eom_config(struct ufs_hba *hba, int lane, 2330 + const struct ufs_eom_coord *eom_coord, 2331 + u32 target_test_count) 2332 + { 2333 + enum ufs_eom_eye_mask eye_mask = eom_coord->eye_mask; 2334 + int v_step = eom_coord->v_step; 2335 + int t_step = eom_coord->t_step; 2336 + u32 volt_step, timing_step; 2337 + int ret; 2338 + 2339 + if (abs(v_step) > UFS_QCOM_EOM_VOLTAGE_STEPS_MAX) { 2340 + dev_err(hba->dev, "Invalid EOM Voltage Step: %d\n", v_step); 2341 + return -ERANGE; 2342 + } 2343 + 2344 + if (abs(t_step) > UFS_QCOM_EOM_TIMING_STEPS_MAX) { 2345 + dev_err(hba->dev, "Invalid EOM Timing Step: %d\n", t_step); 2346 + return -ERANGE; 2347 + } 2348 + 2349 + if (v_step < 0) 2350 + volt_step = RX_EYEMON_NEGATIVE_STEP_BIT | (u32)(-v_step); 2351 + else 2352 + volt_step = (u32)v_step; 2353 + 2354 + if (t_step < 0) 2355 + timing_step = RX_EYEMON_NEGATIVE_STEP_BIT | (u32)(-t_step); 2356 + else 2357 + timing_step = (u32)t_step; 2358 + 2359 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(RX_EYEMON_ENABLE, 2360 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 2361 + BIT(eye_mask) | RX_EYEMON_EXTENDED_VRANGE_BIT); 2362 + if (ret) { 2363 + dev_err(hba->dev, "Failed to enable Host EOM on Lane %d: %d\n", 2364 + lane, ret); 2365 + return ret; 2366 + } 2367 + 2368 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(RX_EYEMON_TIMING_STEPS, 2369 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 2370 + timing_step); 2371 + if (ret) { 2372 + dev_err(hba->dev, "Failed to set Host EOM timing step on Lane %d: %d\n", 2373 + lane, ret); 2374 + return ret; 2375 + } 2376 + 2377 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(RX_EYEMON_VOLTAGE_STEPS, 2378 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 2379 + volt_step); 2380 + if (ret) { 2381 + dev_err(hba->dev, "Failed to set Host EOM voltage step on Lane %d: %d\n", 2382 + lane, ret); 2383 + return ret; 2384 + } 2385 + 2386 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(RX_EYEMON_TARGET_TEST_COUNT, 2387 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 2388 + target_test_count); 2389 + if (ret) 2390 + dev_err(hba->dev, "Failed to set Host EOM target test count on Lane %d: %d\n", 2391 + lane, ret); 2392 + 2393 + return ret; 2394 + } 2395 + 2396 + static int ufs_qcom_host_eom_may_stop(struct ufs_hba *hba, int lane, 2397 + u32 target_test_count, u32 *err_count) 2398 + { 2399 + u32 start, tested_count, error_count; 2400 + int ret; 2401 + 2402 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(RX_EYEMON_START, 2403 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 2404 + &start); 2405 + if (ret) { 2406 + dev_err(hba->dev, "Failed to get Host EOM start status on Lane %d: %d\n", 2407 + lane, ret); 2408 + return ret; 2409 + } 2410 + 2411 + if (start & 0x1) 2412 + return -EAGAIN; 2413 + 2414 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(RX_EYEMON_TESTED_COUNT, 2415 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 2416 + &tested_count); 2417 + if (ret) { 2418 + dev_err(hba->dev, "Failed to get Host EOM tested count on Lane %d: %d\n", 2419 + lane, ret); 2420 + return ret; 2421 + } 2422 + 2423 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(RX_EYEMON_ERROR_COUNT, 2424 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 2425 + &error_count); 2426 + if (ret) { 2427 + dev_err(hba->dev, "Failed to get Host EOM error count on Lane %d: %d\n", 2428 + lane, ret); 2429 + return ret; 2430 + } 2431 + 2432 + /* EOM can stop */ 2433 + if ((tested_count >= target_test_count - 3) || error_count > 0) { 2434 + *err_count = error_count; 2435 + 2436 + /* Disable EOM */ 2437 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(RX_EYEMON_ENABLE, 2438 + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), 2439 + 0x0); 2440 + if (ret) { 2441 + dev_err(hba->dev, "Failed to disable Host EOM on Lane %d: %d\n", 2442 + lane, ret); 2443 + return ret; 2444 + } 2445 + } else { 2446 + return -EAGAIN; 2447 + } 2448 + 2449 + return 0; 2450 + } 2451 + 2452 + static int ufs_qcom_host_eom_scan(struct ufs_hba *hba, int num_lanes, 2453 + const struct ufs_eom_coord *eom_coord, 2454 + u32 target_test_count, u32 *err_count) 2455 + { 2456 + bool eom_stopped[PA_MAXDATALANES] = { 0 }; 2457 + int lane, ret; 2458 + u32 setting; 2459 + 2460 + if (!err_count || !eom_coord) 2461 + return -EINVAL; 2462 + 2463 + if (target_test_count < UFS_QCOM_EOM_TARGET_TEST_COUNT_MIN) { 2464 + dev_err(hba->dev, "Target test count (%u) too small for Host EOM\n", 2465 + target_test_count); 2466 + return -ERANGE; 2467 + } 2468 + 2469 + for (lane = 0; lane < num_lanes; lane++) { 2470 + ret = ufs_qcom_host_eom_config(hba, lane, eom_coord, 2471 + target_test_count); 2472 + if (ret) { 2473 + dev_err(hba->dev, "Failed to config Host RX EOM: %d\n", ret); 2474 + return ret; 2475 + } 2476 + } 2477 + 2478 + /* 2479 + * Trigger a PACP_PWR_req to kick start EOM, but not to really change 2480 + * the Power Mode. 2481 + */ 2482 + ret = ufshcd_uic_change_pwr_mode(hba, FAST_MODE << 4 | FAST_MODE); 2483 + if (ret) { 2484 + dev_err(hba->dev, "Failed to change power mode to kick start Host EOM: %d\n", 2485 + ret); 2486 + return ret; 2487 + } 2488 + 2489 + more_burst: 2490 + /* Create burst on Host RX Lane. */ 2491 + ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_LOCALVERINFO), &setting); 2492 + 2493 + for (lane = 0; lane < num_lanes; lane++) { 2494 + if (eom_stopped[lane]) 2495 + continue; 2496 + 2497 + ret = ufs_qcom_host_eom_may_stop(hba, lane, target_test_count, 2498 + &err_count[lane]); 2499 + if (!ret) { 2500 + eom_stopped[lane] = true; 2501 + } else if (ret == -EAGAIN) { 2502 + /* Need more burst to excercise EOM */ 2503 + goto more_burst; 2504 + } else { 2505 + dev_err(hba->dev, "Failed to stop Host EOM: %d\n", ret); 2506 + return ret; 2507 + } 2508 + 2509 + dev_dbg(hba->dev, "Host RX Lane %d EOM, v_step %d, t_step %d, error count %u\n", 2510 + lane, eom_coord->v_step, eom_coord->t_step, 2511 + err_count[lane]); 2512 + } 2513 + 2514 + return 0; 2515 + } 2516 + 2517 + static int ufs_qcom_host_sw_rx_fom(struct ufs_hba *hba, int num_lanes, u32 *fom) 2518 + { 2519 + const struct ufs_eom_coord *eom_coord = sw_rx_fom_eom_coords_g6; 2520 + u32 eom_err_count[PA_MAXDATALANES] = { 0 }; 2521 + u32 curr_ahit; 2522 + int lane, i, ret; 2523 + 2524 + if (!fom) 2525 + return -EINVAL; 2526 + 2527 + /* Stop the auto hibernate idle timer */ 2528 + curr_ahit = ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER); 2529 + if (curr_ahit) 2530 + ufshcd_writel(hba, 0, REG_AUTO_HIBERNATE_IDLE_TIMER); 2531 + 2532 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXHSADAPTTYPE), PA_NO_ADAPT); 2533 + if (ret) { 2534 + dev_err(hba->dev, "Failed to select NO_ADAPT before starting Host EOM: %d\n", ret); 2535 + goto out; 2536 + } 2537 + 2538 + for (i = 0; i < SW_RX_FOM_EOM_COORDS; i++, eom_coord++) { 2539 + ret = ufs_qcom_host_eom_scan(hba, num_lanes, eom_coord, 2540 + UFS_QCOM_EOM_TARGET_TEST_COUNT_G6, 2541 + eom_err_count); 2542 + if (ret) { 2543 + dev_err(hba->dev, "Failed to run Host EOM scan: %d\n", ret); 2544 + break; 2545 + } 2546 + 2547 + for (lane = 0; lane < num_lanes; lane++) { 2548 + /* Bad coordinates have no weights */ 2549 + if (eom_err_count[lane]) 2550 + continue; 2551 + fom[lane] += SW_RX_FOM_EOM_COORDS_WEIGHT; 2552 + } 2553 + } 2554 + 2555 + out: 2556 + /* Restore the auto hibernate idle timer */ 2557 + if (curr_ahit) 2558 + ufshcd_writel(hba, curr_ahit, REG_AUTO_HIBERNATE_IDLE_TIMER); 2559 + 2560 + return ret; 2561 + } 2562 + 2563 + static int ufs_qcom_get_rx_fom(struct ufs_hba *hba, 2564 + struct ufs_pa_layer_attr *pwr_mode, 2565 + struct tx_eqtr_iter *h_iter, 2566 + struct tx_eqtr_iter *d_iter) 2567 + { 2568 + struct ufshcd_tx_eq_params *params __free(kfree) = 2569 + kzalloc(sizeof(*params), GFP_KERNEL); 2570 + struct ufs_qcom_host *host = ufshcd_get_variant(hba); 2571 + struct ufs_pa_layer_attr old_pwr_info; 2572 + u32 fom[PA_MAXDATALANES] = { 0 }; 2573 + u32 gear = pwr_mode->gear_tx; 2574 + u32 rate = pwr_mode->hs_rate; 2575 + int lane, ret; 2576 + 2577 + if (host->hw_ver.major != 0x7 || host->hw_ver.minor > 0x1 || 2578 + gear <= UFS_HS_G5 || !d_iter || !d_iter->is_updated) 2579 + return 0; 2580 + 2581 + if (gear < UFS_HS_G1 || gear > UFS_HS_GEAR_MAX) 2582 + return -ERANGE; 2583 + 2584 + if (!params) 2585 + return -ENOMEM; 2586 + 2587 + memcpy(&old_pwr_info, &hba->pwr_info, sizeof(struct ufs_pa_layer_attr)); 2588 + 2589 + memcpy(params, &hba->tx_eq_params[gear - 1], sizeof(struct ufshcd_tx_eq_params)); 2590 + for (lane = 0; lane < pwr_mode->lane_rx; lane++) { 2591 + params->device[lane].preshoot = d_iter->preshoot; 2592 + params->device[lane].deemphasis = d_iter->deemphasis; 2593 + } 2594 + 2595 + /* Use TX EQTR settings as Device's TX Equalization settings. */ 2596 + ret = ufshcd_apply_tx_eq_settings(hba, params, gear); 2597 + if (ret) { 2598 + dev_err(hba->dev, "%s: Failed to apply TX EQ settings for HS-G%u: %d\n", 2599 + __func__, gear, ret); 2600 + return ret; 2601 + } 2602 + 2603 + /* Force PMC to target HS Gear to use new TX Equalization settings. */ 2604 + ret = ufshcd_change_power_mode(hba, pwr_mode, UFSHCD_PMC_POLICY_FORCE); 2605 + if (ret) { 2606 + dev_err(hba->dev, "%s: Failed to change power mode to HS-G%u, Rate-%s: %d\n", 2607 + __func__, gear, ufs_hs_rate_to_str(rate), ret); 2608 + return ret; 2609 + } 2610 + 2611 + ret = ufs_qcom_host_sw_rx_fom(hba, pwr_mode->lane_rx, fom); 2612 + if (ret) { 2613 + dev_err(hba->dev, "Failed to get SW FOM of TX (PreShoot: %u, DeEmphasis: %u): %d\n", 2614 + d_iter->preshoot, d_iter->deemphasis, ret); 2615 + return ret; 2616 + } 2617 + 2618 + /* Restore Device's TX Equalization settings. */ 2619 + ret = ufshcd_apply_tx_eq_settings(hba, &hba->tx_eq_params[gear - 1], gear); 2620 + if (ret) { 2621 + dev_err(hba->dev, "%s: Failed to apply TX EQ settings for HS-G%u: %d\n", 2622 + __func__, gear, ret); 2623 + return ret; 2624 + } 2625 + 2626 + /* Restore Power Mode. */ 2627 + ret = ufshcd_change_power_mode(hba, &old_pwr_info, UFSHCD_PMC_POLICY_FORCE); 2628 + if (ret) { 2629 + dev_err(hba->dev, "%s: Failed to retore power mode to HS-G%u: %d\n", 2630 + __func__, old_pwr_info.gear_tx, ret); 2631 + return ret; 2632 + } 2633 + 2634 + for (lane = 0; lane < pwr_mode->lane_rx; lane++) 2635 + d_iter->fom[lane] = fom[lane]; 2636 + 2637 + return 0; 2638 + } 2639 + 2640 + static int ufs_qcom_apply_tx_eqtr_settings(struct ufs_hba *hba, 2641 + struct ufs_pa_layer_attr *pwr_mode, 2642 + struct tx_eqtr_iter *h_iter, 2643 + struct tx_eqtr_iter *d_iter) 2644 + { 2645 + struct ufs_qcom_host *host = ufshcd_get_variant(hba); 2646 + u32 setting = 0; 2647 + int lane; 2648 + 2649 + if (host->hw_ver.major != 0x7 || host->hw_ver.minor > 0x1) 2650 + return 0; 2651 + 2652 + for (lane = 0; lane < pwr_mode->lane_tx; lane++) { 2653 + setting |= TX_HS_PRESHOOT_BITS(lane, h_iter->preshoot); 2654 + setting |= TX_HS_DEEMPHASIS_BITS(lane, h_iter->deemphasis); 2655 + } 2656 + 2657 + return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXEQG1SETTING), setting); 2658 + } 2659 + 2660 + static int ufs_qcom_tx_eqtr_notify(struct ufs_hba *hba, 2661 + enum ufs_notify_change_status status, 2662 + struct ufs_pa_layer_attr *pwr_mode) 2663 + { 2664 + struct ufs_qcom_host *host = ufshcd_get_variant(hba); 2665 + struct ufs_pa_layer_attr pwr_mode_hs_g1 = { 2666 + .gear_rx = UFS_HS_G1, 2667 + .gear_tx = UFS_HS_G1, 2668 + .lane_rx = pwr_mode->lane_rx, 2669 + .lane_tx = pwr_mode->lane_tx, 2670 + .pwr_rx = FAST_MODE, 2671 + .pwr_tx = FAST_MODE, 2672 + .hs_rate = pwr_mode->hs_rate, 2673 + }; 2674 + u32 gear = pwr_mode->gear_tx; 2675 + u32 rate = pwr_mode->hs_rate; 2676 + int ret; 2677 + 2678 + if (host->hw_ver.major != 0x7 || host->hw_ver.minor > 0x1) 2679 + return 0; 2680 + 2681 + if (status == PRE_CHANGE) { 2682 + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_TXEQG1SETTING), 2683 + &host->saved_tx_eq_g1_setting); 2684 + if (ret) 2685 + return ret; 2686 + 2687 + /* PMC to target HS Gear. */ 2688 + ret = ufshcd_change_power_mode(hba, pwr_mode, 2689 + UFSHCD_PMC_POLICY_DONT_FORCE); 2690 + if (ret) 2691 + dev_err(hba->dev, "%s: Failed to PMC to target HS-G%u, Rate-%s: %d\n", 2692 + __func__, gear, ufs_hs_rate_to_str(rate), ret); 2693 + } else { 2694 + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXEQG1SETTING), 2695 + host->saved_tx_eq_g1_setting); 2696 + if (ret) 2697 + return ret; 2698 + 2699 + /* PMC back to HS-G1. */ 2700 + ret = ufshcd_change_power_mode(hba, &pwr_mode_hs_g1, 2701 + UFSHCD_PMC_POLICY_DONT_FORCE); 2702 + if (ret) 2703 + dev_err(hba->dev, "%s: Failed to PMC to HS-G1, Rate-%s: %d\n", 2704 + __func__, ufs_hs_rate_to_str(rate), ret); 2705 + } 2706 + 2707 + return ret; 2708 + } 2709 + 2513 2710 /* 2514 2711 * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations 2515 2712 * ··· 2906 2341 .setup_clocks = ufs_qcom_setup_clocks, 2907 2342 .hce_enable_notify = ufs_qcom_hce_enable_notify, 2908 2343 .link_startup_notify = ufs_qcom_link_startup_notify, 2344 + .negotiate_pwr_mode = ufs_qcom_negotiate_pwr_mode, 2909 2345 .pwr_change_notify = ufs_qcom_pwr_change_notify, 2910 2346 .apply_dev_quirks = ufs_qcom_apply_dev_quirks, 2911 2347 .fixup_dev_quirks = ufs_qcom_fixup_dev_quirks, ··· 2921 2355 .get_outstanding_cqs = ufs_qcom_get_outstanding_cqs, 2922 2356 .config_esi = ufs_qcom_config_esi, 2923 2357 .freq_to_gear_speed = ufs_qcom_freq_to_gear_speed, 2358 + .get_rx_fom = ufs_qcom_get_rx_fom, 2359 + .apply_tx_eqtr_settings = ufs_qcom_apply_tx_eqtr_settings, 2360 + .tx_eqtr_notify = ufs_qcom_tx_eqtr_notify, 2924 2361 }; 2925 2362 2926 2363 static const struct ufs_hba_variant_ops ufs_hba_qcom_sa8255p_vops = {
+42
drivers/ufs/host/ufs-qcom.h
··· 33 33 #define DL_VS_CLK_CFG_MASK GENMASK(9, 0) 34 34 #define DME_VS_CORE_CLK_CTRL_DME_HW_CGC_EN BIT(9) 35 35 36 + #define UFS_QCOM_EOM_VOLTAGE_STEPS_MAX 127 37 + #define UFS_QCOM_EOM_TIMING_STEPS_MAX 63 38 + #define UFS_QCOM_EOM_TARGET_TEST_COUNT_MIN 8 39 + #define UFS_QCOM_EOM_TARGET_TEST_COUNT_G6 0x3F 40 + 41 + #define SW_RX_FOM_EOM_COORDS 23 42 + #define SW_RX_FOM_EOM_COORDS_WEIGHT (127 / SW_RX_FOM_EOM_COORDS) 43 + 44 + struct ufs_eom_coord { 45 + int t_step; 46 + int v_step; 47 + u8 eye_mask; 48 + }; 49 + 50 + static const struct ufs_eom_coord sw_rx_fom_eom_coords_g6[SW_RX_FOM_EOM_COORDS] = { 51 + [0] = { -2, -15, UFS_EOM_EYE_MASK_M }, 52 + [1] = { 0, -15, UFS_EOM_EYE_MASK_M }, 53 + [2] = { 2, -15, UFS_EOM_EYE_MASK_M }, 54 + [3] = { -4, -10, UFS_EOM_EYE_MASK_M }, 55 + [4] = { -2, -10, UFS_EOM_EYE_MASK_M }, 56 + [5] = { 0, -10, UFS_EOM_EYE_MASK_M }, 57 + [6] = { 2, -10, UFS_EOM_EYE_MASK_M }, 58 + [7] = { 4, -10, UFS_EOM_EYE_MASK_M }, 59 + [8] = { -6, 0, UFS_EOM_EYE_MASK_M }, 60 + [9] = { -4, 0, UFS_EOM_EYE_MASK_M }, 61 + [10] = { -2, 0, UFS_EOM_EYE_MASK_M }, 62 + [11] = { 0, 0, UFS_EOM_EYE_MASK_M }, 63 + [12] = { 2, 0, UFS_EOM_EYE_MASK_M }, 64 + [13] = { 4, 0, UFS_EOM_EYE_MASK_M }, 65 + [14] = { 6, 0, UFS_EOM_EYE_MASK_M }, 66 + [15] = { -4, 10, UFS_EOM_EYE_MASK_M }, 67 + [16] = { -2, 10, UFS_EOM_EYE_MASK_M }, 68 + [17] = { 0, 10, UFS_EOM_EYE_MASK_M }, 69 + [18] = { 2, 10, UFS_EOM_EYE_MASK_M }, 70 + [19] = { 4, 10, UFS_EOM_EYE_MASK_M }, 71 + [20] = { -2, 15, UFS_EOM_EYE_MASK_M }, 72 + [21] = { 0, 15, UFS_EOM_EYE_MASK_M }, 73 + [22] = { 2, 15, UFS_EOM_EYE_MASK_M }, 74 + }; 75 + 36 76 /* Qualcomm MCQ Configuration */ 37 77 #define UFS_QCOM_MCQCAP_QCFGPTR 224 /* 0xE0 in hex */ 38 78 #define UFS_QCOM_MCQ_CONFIG_OFFSET (UFS_QCOM_MCQCAP_QCFGPTR * 0x200) /* 0x1C000 */ ··· 348 308 u32 phy_gear; 349 309 350 310 bool esi_enabled; 311 + 312 + u32 saved_tx_eq_g1_setting; 351 313 }; 352 314 353 315 struct ufs_qcom_drvdata {
-3
drivers/ufs/host/ufs-sprd.c
··· 161 161 162 162 static int sprd_ufs_pwr_change_notify(struct ufs_hba *hba, 163 163 enum ufs_notify_change_status status, 164 - const struct ufs_pa_layer_attr *dev_max_params, 165 164 struct ufs_pa_layer_attr *dev_req_params) 166 165 { 167 166 struct ufs_sprd_host *host = ufshcd_get_variant(hba); 168 167 169 168 if (status == PRE_CHANGE) { 170 - memcpy(dev_req_params, dev_max_params, 171 - sizeof(struct ufs_pa_layer_attr)); 172 169 if (host->unipro_ver >= UFS_UNIPRO_VER_1_8) 173 170 ufshcd_dme_configure_adapt(hba, dev_req_params->gear_tx, 174 171 PA_INITIAL_ADAPT);
+3 -4
drivers/ufs/host/ufshcd-pci.c
··· 145 145 146 146 pwr_info.lane_rx = lanes; 147 147 pwr_info.lane_tx = lanes; 148 - ret = ufshcd_config_pwr_mode(hba, &pwr_info); 148 + ret = ufshcd_change_power_mode(hba, &pwr_info, 149 + UFSHCD_PMC_POLICY_DONT_FORCE); 149 150 if (ret) 150 151 dev_err(hba->dev, "%s: Setting %u lanes, err = %d\n", 151 152 __func__, lanes, ret); ··· 155 154 156 155 static int ufs_intel_lkf_pwr_change_notify(struct ufs_hba *hba, 157 156 enum ufs_notify_change_status status, 158 - const struct ufs_pa_layer_attr *dev_max_params, 159 157 struct ufs_pa_layer_attr *dev_req_params) 160 158 { 161 159 int err = 0; 162 160 163 161 switch (status) { 164 162 case PRE_CHANGE: 165 - if (ufshcd_is_hs_mode(dev_max_params) && 163 + if (ufshcd_is_hs_mode(dev_req_params) && 166 164 (hba->pwr_info.lane_rx != 2 || hba->pwr_info.lane_tx != 2)) 167 165 ufs_intel_set_lanes(hba, 2); 168 - memcpy(dev_req_params, dev_max_params, sizeof(*dev_req_params)); 169 166 break; 170 167 case POST_CHANGE: 171 168 if (ufshcd_is_hs_mode(dev_req_params)) {
+164 -10
include/ufs/ufshcd.h
··· 287 287 struct ufs_pa_layer_attr info; 288 288 }; 289 289 290 + #define UFS_MAX_LANES 2 291 + 292 + /** 293 + * struct tx_eqtr_iter - TX Equalization Training iterator 294 + * @preshoot_bitmap: PreShoot bitmap 295 + * @deemphasis_bitmap: DeEmphasis bitmap 296 + * @preshoot: PreShoot value 297 + * @deemphasis: DeEmphasis value 298 + * @fom: Figure-of-Merit read out from RX_FOM 299 + * @is_updated: Flag to indicate if updated since previous iteration 300 + */ 301 + struct tx_eqtr_iter { 302 + unsigned long preshoot_bitmap; 303 + unsigned long deemphasis_bitmap; 304 + u8 preshoot; 305 + u8 deemphasis; 306 + u8 fom[UFS_MAX_LANES]; 307 + bool is_updated; 308 + }; 309 + 310 + /** 311 + * struct ufshcd_tx_eq_settings - TX Equalization settings 312 + * @preshoot: PreShoot value 313 + * @deemphasis: DeEmphasis value 314 + * @fom_val: Figure-of-Merit value read out from RX_FOM (Bit[6:0]) 315 + * @precode_en: Flag to indicate whether need to enable pre-coding 316 + */ 317 + struct ufshcd_tx_eq_settings { 318 + u8 preshoot; 319 + u8 deemphasis; 320 + u8 fom_val; 321 + bool precode_en; 322 + }; 323 + 324 + /** 325 + * struct ufshcd_tx_eqtr_data - Data used during TX Equalization Training procedure 326 + * @host: Optimal TX EQ settings identified for host TX Lanes during TX EQTR 327 + * @device: Optimal TX EQ settings identified for device TX Lanes during TX EQTR 328 + * @host_fom: Host TX EQTR FOM record 329 + * @device_fom: Device TX EQTR FOM record 330 + */ 331 + struct ufshcd_tx_eqtr_data { 332 + struct ufshcd_tx_eq_settings host[UFS_MAX_LANES]; 333 + struct ufshcd_tx_eq_settings device[UFS_MAX_LANES]; 334 + u8 host_fom[UFS_MAX_LANES][TX_HS_NUM_PRESHOOT][TX_HS_NUM_DEEMPHASIS]; 335 + u8 device_fom[UFS_MAX_LANES][TX_HS_NUM_PRESHOOT][TX_HS_NUM_DEEMPHASIS]; 336 + }; 337 + 338 + /** 339 + * struct ufshcd_tx_eqtr_record - TX Equalization Training record 340 + * @host_fom: Host TX EQTR FOM record 341 + * @device_fom: Device TX EQTR FOM record 342 + * @last_record_ts: Timestamp of the most recent TX EQTR record 343 + * @last_record_index: Index of the most recent TX EQTR record 344 + * @saved_adapt_eqtr: Saved Adaptation length setting for TX EQTR 345 + */ 346 + struct ufshcd_tx_eqtr_record { 347 + u8 host_fom[UFS_MAX_LANES][TX_HS_NUM_PRESHOOT][TX_HS_NUM_DEEMPHASIS]; 348 + u8 device_fom[UFS_MAX_LANES][TX_HS_NUM_PRESHOOT][TX_HS_NUM_DEEMPHASIS]; 349 + ktime_t last_record_ts; 350 + u16 last_record_index; 351 + u16 saved_adapt_eqtr; 352 + }; 353 + 354 + /** 355 + * struct ufshcd_tx_eq_params - TX Equalization parameters structure 356 + * @host: TX EQ settings for host TX Lanes 357 + * @device: TX EQ settings for device TX Lanes 358 + * @eqtr_record: Pointer to TX EQTR record 359 + * @is_valid: True if parameter contains valid TX Equalization settings 360 + * @is_applied: True if settings have been applied to UniPro of both sides 361 + */ 362 + struct ufshcd_tx_eq_params { 363 + struct ufshcd_tx_eq_settings host[UFS_MAX_LANES]; 364 + struct ufshcd_tx_eq_settings device[UFS_MAX_LANES]; 365 + struct ufshcd_tx_eqtr_record *eqtr_record; 366 + bool is_valid; 367 + bool is_applied; 368 + }; 369 + 290 370 /** 291 371 * struct ufs_hba_variant_ops - variant specific callbacks 292 372 * @name: variant name ··· 382 302 * variant specific Uni-Pro initialization. 383 303 * @link_startup_notify: called before and after Link startup is carried out 384 304 * to allow variant specific Uni-Pro initialization. 305 + * @negotiate_pwr_mode: called to negotiate power mode. 385 306 * @pwr_change_notify: called before and after a power mode change 386 307 * is carried out to allow vendor spesific capabilities 387 - * to be set. PRE_CHANGE can modify final_params based 388 - * on desired_pwr_mode, but POST_CHANGE must not alter 389 - * the final_params parameter 308 + * to be set. 390 309 * @setup_xfer_req: called before any transfer request is issued 391 310 * to set some things 392 311 * @setup_task_mgmt: called before any task management request is issued ··· 410 331 * @config_esi: called to config Event Specific Interrupt 411 332 * @config_scsi_dev: called to configure SCSI device parameters 412 333 * @freq_to_gear_speed: called to map clock frequency to the max supported gear speed 334 + * @apply_tx_eqtr_settings: called to apply settings for TX Equalization 335 + * Training settings. 336 + * @get_rx_fom: called to get Figure of Merit (FOM) value. 337 + * @tx_eqtr_notify: called before and after TX Equalization Training procedure 338 + * to allow platform vendor specific configs to take place. 413 339 */ 414 340 struct ufs_hba_variant_ops { 415 341 const char *name; ··· 431 347 enum ufs_notify_change_status); 432 348 int (*link_startup_notify)(struct ufs_hba *, 433 349 enum ufs_notify_change_status); 434 - int (*pwr_change_notify)(struct ufs_hba *, 435 - enum ufs_notify_change_status status, 436 - const struct ufs_pa_layer_attr *desired_pwr_mode, 437 - struct ufs_pa_layer_attr *final_params); 350 + int (*negotiate_pwr_mode)(struct ufs_hba *hba, 351 + const struct ufs_pa_layer_attr *desired_pwr_mode, 352 + struct ufs_pa_layer_attr *final_params); 353 + int (*pwr_change_notify)(struct ufs_hba *hba, 354 + enum ufs_notify_change_status status, 355 + struct ufs_pa_layer_attr *final_params); 438 356 void (*setup_xfer_req)(struct ufs_hba *hba, int tag, 439 357 bool is_scsi_cmd); 440 358 void (*setup_task_mgmt)(struct ufs_hba *, int, u8); ··· 466 380 int (*config_esi)(struct ufs_hba *hba); 467 381 void (*config_scsi_dev)(struct scsi_device *sdev); 468 382 u32 (*freq_to_gear_speed)(struct ufs_hba *hba, unsigned long freq); 383 + int (*get_rx_fom)(struct ufs_hba *hba, 384 + struct ufs_pa_layer_attr *pwr_mode, 385 + struct tx_eqtr_iter *h_iter, 386 + struct tx_eqtr_iter *d_iter); 387 + int (*apply_tx_eqtr_settings)(struct ufs_hba *hba, 388 + struct ufs_pa_layer_attr *pwr_mode, 389 + struct tx_eqtr_iter *h_iter, 390 + struct tx_eqtr_iter *d_iter); 391 + int (*tx_eqtr_notify)(struct ufs_hba *hba, 392 + enum ufs_notify_change_status status, 393 + struct ufs_pa_layer_attr *pwr_mode); 469 394 }; 470 395 471 396 /* clock gating state */ ··· 623 526 UFSHCD_STATE_EH_SCHEDULED_NON_FATAL, 624 527 UFSHCD_STATE_EH_SCHEDULED_FATAL, 625 528 UFSHCD_STATE_ERROR, 529 + }; 530 + 531 + /** 532 + * enum ufshcd_pmc_policy - Power Mode change policy 533 + * @UFSHCD_PMC_POLICY_DONT_FORCE: Do not force a Power Mode change. 534 + * @UFSHCD_PMC_POLICY_FORCE: Force a Power Mode change even if current Power 535 + * Mode is same as target Power Mode. 536 + */ 537 + enum ufshcd_pmc_policy { 538 + UFSHCD_PMC_POLICY_DONT_FORCE, 539 + UFSHCD_PMC_POLICY_FORCE, 626 540 }; 627 541 628 542 enum ufshcd_quirks { ··· 881 773 * WriteBooster when scaling the clock down. 882 774 */ 883 775 UFSHCD_CAP_WB_WITH_CLK_SCALING = 1 << 12, 776 + 777 + /* 778 + * This capability allows the host controller driver to apply TX 779 + * Equalization settings discovered from UFS attributes, variant 780 + * specific operations and TX Equaliztion Training procedure. 781 + */ 782 + UFSHCD_CAP_TX_EQUALIZATION = 1 << 13, 884 783 }; 885 784 886 785 struct ufs_hba_variant_params { ··· 1002 887 * @saved_uic_err: sticky UIC error mask 1003 888 * @ufs_stats: various error counters 1004 889 * @force_reset: flag to force eh_work perform a full reset 1005 - * @force_pmc: flag to force a power mode change 1006 890 * @silence_err_logs: flag to silence error logs 1007 891 * @dev_cmd: ufs device management command information 1008 892 * @last_dme_cmd_tstamp: time stamp of the last completed DME command ··· 1069 955 * indicating that the DME QoS Monitor has been reset by the host. 1070 956 * @dme_qos_sysfs_handle: handle for 'dme_qos_notification' sysfs entry 1071 957 * @rpmbs: list of OP-TEE RPMB devices (one per RPMB region) 958 + * @host_preshoot_cap: a bitfield to indicate supported PreShoot dBs of host's TX lanes, cache of 959 + * host M-PHY TX_HS_PreShoot_Setting_Capability Attribute (ID 0x15) 960 + * @host_deemphasis_cap: a bitfield to indicate supported DeEmphasis dBs of host's TX lanes, cache 961 + * of host M-PHY TX_HS_DeEmphasis_Setting_Capability Attribute (ID 0x12) 962 + * @device_preshoot_cap: a bitfield to indicate supported PreShoot dBs of device's TX lanes, cache 963 + * of device M-PHY TX_HS_PreShoot_Setting_Capability Attribute (ID 0x15) 964 + * @device_deemphasis_cap: a bitfield to indicate supported DeEmphasis dBs of device's TX lanes, 965 + * cache of device M-PHY TX_HS_DeEmphasis_Setting_Capability Attribute (ID 0x12) 966 + * @tx_eq_params: TX Equalization settings 1072 967 */ 1073 968 struct ufs_hba { 1074 969 void __iomem *mmio_base; ··· 1169 1046 u32 saved_uic_err; 1170 1047 struct ufs_stats ufs_stats; 1171 1048 bool force_reset; 1172 - bool force_pmc; 1173 1049 bool silence_err_logs; 1174 1050 1175 1051 /* Device management request data */ ··· 1255 1133 1256 1134 u32 vcc_off_delay_us; 1257 1135 struct list_head rpmbs; 1136 + 1137 + u8 host_preshoot_cap; 1138 + u8 host_deemphasis_cap; 1139 + u8 device_preshoot_cap; 1140 + u8 device_deemphasis_cap; 1141 + struct ufshcd_tx_eq_params tx_eq_params[UFS_HS_GEAR_MAX]; 1258 1142 }; 1259 1143 1260 1144 /** ··· 1405 1277 return hba->caps & UFSHCD_CAP_WB_WITH_CLK_SCALING; 1406 1278 } 1407 1279 1280 + static inline bool ufshcd_is_tx_eq_supported(struct ufs_hba *hba) 1281 + { 1282 + return hba->caps & UFSHCD_CAP_TX_EQUALIZATION && 1283 + hba->ufs_version >= ufshci_version(5, 0) && 1284 + hba->dev_info.wspecversion >= 0x500; 1285 + } 1286 + 1408 1287 #define ufsmcq_writel(hba, val, reg) \ 1409 1288 writel((val), (hba)->mcq_base + (reg)) 1410 1289 #define ufsmcq_readl(hba, reg) \ ··· 1426 1291 writel((val), (hba)->mmio_base + (reg)) 1427 1292 #define ufshcd_readl(hba, reg) \ 1428 1293 readl((hba)->mmio_base + (reg)) 1294 + 1295 + static inline const char *ufs_hs_rate_to_str(enum ufs_hs_gear_rate rate) 1296 + { 1297 + switch (rate) { 1298 + case PA_HS_MODE_A: 1299 + return "A"; 1300 + case PA_HS_MODE_B: 1301 + return "B"; 1302 + default: 1303 + return "Unknown"; 1304 + } 1305 + } 1429 1306 1430 1307 /** 1431 1308 * ufshcd_rmwl - perform read/modify/write for a controller register ··· 1523 1376 u8 attr_set, u32 mib_val, u8 peer); 1524 1377 extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, 1525 1378 u32 *mib_val, u8 peer); 1379 + extern int ufshcd_change_power_mode(struct ufs_hba *hba, 1380 + struct ufs_pa_layer_attr *pwr_mode, 1381 + enum ufshcd_pmc_policy pmc_policy); 1526 1382 extern int ufshcd_config_pwr_mode(struct ufs_hba *hba, 1527 - struct ufs_pa_layer_attr *desired_pwr_mode); 1383 + struct ufs_pa_layer_attr *desired_pwr_mode, 1384 + enum ufshcd_pmc_policy pmc_policy); 1528 1385 extern int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode); 1386 + extern int ufshcd_apply_tx_eq_settings(struct ufs_hba *hba, 1387 + struct ufshcd_tx_eq_params *params, 1388 + u32 gear); 1529 1389 1530 1390 /* UIC command interfaces for DME primitives */ 1531 1391 #define DME_LOCAL 0
+139 -2
include/ufs/unipro.h
··· 10 10 * M-TX Configuration Attributes 11 11 */ 12 12 #define TX_HIBERN8TIME_CAPABILITY 0x000F 13 + #define TX_HS_DEEMPHASIS_SETTING_CAP 0x0012 14 + #define TX_HS_PRESHOOT_SETTING_CAP 0x0015 13 15 #define TX_MODE 0x0021 14 16 #define TX_HSRATE_SERIES 0x0022 15 17 #define TX_HSGEAR 0x0023 ··· 32 30 #define TX_LCC_SEQUENCER 0x0032 33 31 #define TX_MIN_ACTIVATETIME 0x0033 34 32 #define TX_PWM_G6_G7_SYNC_LENGTH 0x0034 33 + #define TX_HS_DEEMPHASIS_SETTING 0x0037 34 + #define TX_HS_PRESHOOT_SETTING 0x003B 35 35 #define TX_REFCLKFREQ 0x00EB 36 36 #define TX_CFGCLKFREQVAL 0x00EC 37 37 #define CFGEXTRATTR 0x00F0 ··· 42 38 /* 43 39 * M-RX Configuration Attributes 44 40 */ 41 + #define RX_HS_G5_ADAPT_INITIAL_CAP 0x0074 42 + #define RX_HS_G6_ADAPT_INITIAL_CAP 0x007B 43 + #define RX_HS_G6_ADAPT_INITIAL_L0L1L2L3_CAP 0x007D 45 44 #define RX_HS_G1_SYNC_LENGTH_CAP 0x008B 46 45 #define RX_HS_G1_PREP_LENGTH_CAP 0x008C 47 46 #define RX_MIN_ACTIVATETIME_CAPABILITY 0x008F ··· 57 50 #define RX_HIBERN8TIME_CAP 0x0092 58 51 #define RX_ADV_HIBERN8TIME_CAP 0x0099 59 52 #define RX_ADV_MIN_ACTIVATETIME_CAP 0x009A 53 + #define RX_HS_G4_ADAPT_INITIAL_CAP 0x009F 60 54 #define RX_MODE 0x00A1 61 55 #define RX_HSRATE_SERIES 0x00A2 62 56 #define RX_HSGEAR 0x00A3 ··· 72 64 #define CFGRXCDR8 0x00BA 73 65 #define CFGRXOVR8 0x00BD 74 66 #define CFGRXOVR6 0x00BF 67 + #define RX_FOM 0x00C2 75 68 #define RXDIRECTCTRL2 0x00C7 76 69 #define CFGRXOVR4 0x00E9 77 70 #define RX_REFCLKFREQ 0x00EB 78 71 #define RX_CFGCLKFREQVAL 0x00EC 79 72 #define CFGWIDEINLN 0x00F0 73 + #define RX_EYEMON_CAP 0x00F1 74 + #define RX_EYEMON_TIMING_MAX_STEPS_CAP 0x00F2 75 + #define RX_EYEMON_TIMING_MAX_OFFSET_CAP 0x00F3 76 + #define RX_EYEMON_VOLTAGE_MAX_STEPS_CAP 0x00F4 77 + #define RX_EYEMON_VOLTAGE_MAX_OFFSET_CAP 0x00F5 78 + #define RX_EYEMON_ENABLE 0x00F6 79 + #define RX_EYEMON_TIMING_STEPS 0x00F7 80 + #define RX_EYEMON_VOLTAGE_STEPS 0x00F8 81 + #define RX_EYEMON_TARGET_TEST_COUNT 0x00F9 82 + #define RX_EYEMON_TESTED_COUNT 0x00FA 83 + #define RX_EYEMON_ERROR_COUNT 0x00FB 84 + #define RX_EYEMON_START 0x00FC 85 + #define RX_EYEMON_EXTENDED_ERROR_COUNT 0x00FD 86 + 80 87 #define ENARXDIRECTCFG4 0x00F2 81 88 #define ENARXDIRECTCFG3 0x00F3 82 89 #define ENARXDIRECTCFG2 0x00F4 83 90 91 + #define RX_EYEMON_NEGATIVE_STEP_BIT BIT(6) 92 + #define RX_EYEMON_EXTENDED_VRANGE_BIT BIT(6) 84 93 85 94 #define is_mphy_tx_attr(attr) (attr < RX_MODE) 86 95 #define RX_ADV_FINE_GRAN_STEP(x) ((((x) & 0x3) << 1) | 0x1) ··· 123 98 #define CBPRGTUNING UNIPRO_CB_OFFSET(0x00FB) 124 99 125 100 #define UNIPRO_CB_OFFSET(x) (0x8000 | x) 101 + 102 + #define ADAPT_LENGTH_MASK 0x7F 103 + #define ADAPT_RANGE_BIT BIT(7) 104 + #define IS_ADAPT_RANGE_COARSE(x) ((x) & ADAPT_RANGE_BIT) 105 + 106 + /* Adapt definitions */ 107 + #define ADAPT_LENGTH_MAX 0x91 108 + #define ADAPT_L0L3_LENGTH_MAX 0x90 109 + #define ADAPT_L0L1L2L3_LENGTH_MAX 0x8C 110 + #define TADAPT_FACTOR 650 111 + #define TADAPT_L0L3_FACTOR (1 << 9) 112 + #define TADAPT_L0L1L2L3_FACTOR (1 << 15) 126 113 127 114 /* 128 115 * PHY Adapter attributes ··· 201 164 #define PA_PACPERRORCOUNT 0x15C1 202 165 #define PA_PHYTESTCONTROL 0x15C2 203 166 #define PA_TXHSG4SYNCLENGTH 0x15D0 167 + #define PA_PEERRXHSG4ADAPTINITIAL 0x15D3 204 168 #define PA_TXHSADAPTTYPE 0x15D4 205 169 #define PA_TXHSG5SYNCLENGTH 0x15D6 170 + #define PA_PEERRXHSG5ADAPTINITIAL 0x15D9 171 + #define PA_PEERRXHSG6ADAPTREFRESHL0L1L2L3 0x15DE 172 + #define PA_PEERRXHSG6ADAPTINITIALL0L3 0x15DF 173 + #define PA_PEERRXHSG6ADAPTINITIALL0L1L2L3 0x15E0 174 + #define PA_TXEQG1SETTING 0x15E1 175 + #define PA_TXEQG2SETTING 0x15E2 176 + #define PA_TXEQG3SETTING 0x15E3 177 + #define PA_TXEQG4SETTING 0x15E4 178 + #define PA_TXEQG5SETTING 0x15E5 179 + #define PA_TXEQG6SETTING 0x15E6 180 + #define PA_TXEQTRSETTING 0x15E7 181 + #define PA_PEERTXEQTRSETTING 0x15E8 182 + #define PA_PRECODEEN 0x15E9 183 + #define PA_EQTR_GEAR 0x15EA 184 + #define PA_TXADAPTLENGTH_EQTR 0x15EB 206 185 207 - /* Adpat type for PA_TXHSADAPTTYPE attribute */ 186 + /* Adapt type for PA_TXHSADAPTTYPE attribute */ 208 187 #define PA_REFRESH_ADAPT 0x00 209 188 #define PA_INITIAL_ADAPT 0x01 210 189 #define PA_NO_ADAPT 0x03 ··· 239 186 240 187 /* PHY Adapter Protocol Constants */ 241 188 #define PA_MAXDATALANES 4 189 + 190 + /* 191 + * TX EQTR's minimum TAdapt should not be less than 10us. 192 + * This value is rounded up into the nearest Unit Intervals (UI) 193 + */ 194 + #define TX_EQTR_HS_G4_MIN_T_ADAPT 166400 195 + #define TX_EQTR_HS_G5_MIN_T_ADAPT 332800 196 + #define TX_EQTR_HS_G6_MIN_T_ADAPT 262144 197 + 198 + #define TX_EQTR_HS_G4_ADAPT_DEFAULT 0x88 199 + #define TX_EQTR_HS_G5_ADAPT_DEFAULT 0x89 200 + #define TX_EQTR_HS_G6_ADAPT_DEFAULT 0x89 201 + 202 + #define TX_EQTR_CAP_MASK 0x7F 203 + 204 + #define TX_EQTR_ADAPT_LENGTH_L0L1L2L3_SHIFT 8 205 + #define TX_EQTR_ADAPT_RESERVED 0xFF 206 + 207 + #define TX_HS_NUM_PRESHOOT 8 208 + #define TX_HS_NUM_DEEMPHASIS 8 209 + #define TX_HS_PRESHOOT_SHIFT 4 210 + #define TX_HS_DEEMPHASIS_SHIFT 4 211 + #define TX_HS_PRESHOOT_OFFSET 0 212 + #define TX_HS_DEEMPHASIS_OFFSET 16 213 + 214 + #define TX_HS_PRESHOOT_LANE_SHIFT(lane) \ 215 + (TX_HS_PRESHOOT_OFFSET + (lane) * TX_HS_PRESHOOT_SHIFT) 216 + #define TX_HS_DEEMPHASIS_LANE_SHIFT(lane) \ 217 + (TX_HS_DEEMPHASIS_OFFSET + (lane) * TX_HS_DEEMPHASIS_SHIFT) 218 + 219 + #define TX_HS_PRESHOOT_BITS(lane, val) \ 220 + ((val) << TX_HS_PRESHOOT_LANE_SHIFT(lane)) 221 + #define TX_HS_DEEMPHASIS_BITS(lane, val) \ 222 + ((val) << TX_HS_DEEMPHASIS_LANE_SHIFT(lane)) 223 + 224 + #define RX_FOM_VALUE_MASK 0x7F 225 + #define RX_FOM_PRECODING_EN_BIT BIT(7) 226 + 227 + #define PRECODEEN_TX_OFFSET 0 228 + #define PRECODEEN_RX_OFFSET 4 229 + #define PRECODEEN_TX_BIT(lane) (1 << (PRECODEEN_TX_OFFSET + (lane))) 230 + #define PRECODEEN_RX_BIT(lane) (1 << (PRECODEEN_RX_OFFSET + (lane))) 231 + 232 + enum ufs_tx_eq_preset { 233 + UFS_TX_EQ_PRESET_P0, 234 + UFS_TX_EQ_PRESET_P1, 235 + UFS_TX_EQ_PRESET_P2, 236 + UFS_TX_EQ_PRESET_P3, 237 + UFS_TX_EQ_PRESET_P4, 238 + UFS_TX_EQ_PRESET_P5, 239 + UFS_TX_EQ_PRESET_P6, 240 + UFS_TX_EQ_PRESET_P7, 241 + UFS_TX_EQ_PRESET_MAX, 242 + }; 243 + 244 + enum ufs_tx_hs_preshoot { 245 + UFS_TX_HS_PRESHOOT_DB_0P0, 246 + UFS_TX_HS_PRESHOOT_DB_0P4, 247 + UFS_TX_HS_PRESHOOT_DB_0P8, 248 + UFS_TX_HS_PRESHOOT_DB_1P2, 249 + UFS_TX_HS_PRESHOOT_DB_1P6, 250 + UFS_TX_HS_PRESHOOT_DB_2P5, 251 + UFS_TX_HS_PRESHOOT_DB_3P5, 252 + UFS_TX_HS_PRESHOOT_DB_4P7, 253 + }; 254 + 255 + enum ufs_tx_hs_deemphasis { 256 + UFS_TX_HS_DEEMPHASIS_DB_0P0, 257 + UFS_TX_HS_DEEMPHASIS_DB_0P8, 258 + UFS_TX_HS_DEEMPHASIS_DB_1P6, 259 + UFS_TX_HS_DEEMPHASIS_DB_2P5, 260 + UFS_TX_HS_DEEMPHASIS_DB_3P5, 261 + UFS_TX_HS_DEEMPHASIS_DB_4P7, 262 + UFS_TX_HS_DEEMPHASIS_DB_6P0, 263 + UFS_TX_HS_DEEMPHASIS_DB_7P6, 264 + }; 265 + 266 + enum ufs_eom_eye_mask { 267 + UFS_EOM_EYE_MASK_M, 268 + UFS_EOM_EYE_MASK_L, 269 + UFS_EOM_EYE_MASK_U, 270 + }; 242 271 243 272 #define DL_FC0ProtectionTimeOutVal_Default 8191 244 273 #define DL_TC0ReplayTimeOutVal_Default 65535 ··· 368 233 UFS_HS_G2, /* HS Gear 2 */ 369 234 UFS_HS_G3, /* HS Gear 3 */ 370 235 UFS_HS_G4, /* HS Gear 4 */ 371 - UFS_HS_G5 /* HS Gear 5 */ 236 + UFS_HS_G5, /* HS Gear 5 */ 237 + UFS_HS_G6, /* HS Gear 6 */ 238 + UFS_HS_GEAR_MAX = UFS_HS_G6, 372 239 }; 373 240 374 241 enum ufs_lanes {