1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2025 Advanced Micro Devices, Inc. 4 * 5 * Authors: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com> 6 */ 7 8 #include <linux/clk.h> 9 #include <linux/delay.h> 10 #include <linux/firmware/xlnx-zynqmp.h> 11 #include <linux/irqreturn.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/platform_device.h> 15 #include <linux/reset.h> 16 #include <ufs/unipro.h> 17 18 #include "ufshcd-dwc.h" 19 #include "ufshcd-pltfrm.h" 20 #include "ufshci-dwc.h" 21 22 /* PHY modes */ 23 #define UFSHCD_DWC_PHY_MODE_ROM 0 24 25 #define MPHY_FAST_RX_AFE_CAL BIT(2) 26 #define MPHY_FW_CALIB_CFG_VAL BIT(8) 27 28 #define MPHY_RX_OVRD_EN BIT(3) 29 #define MPHY_RX_OVRD_VAL BIT(2) 30 #define MPHY_RX_ACK_MASK BIT(0) 31 32 #define TIMEOUT_MICROSEC 1000000 33 34 struct ufs_versal2_host { 35 struct ufs_hba *hba; 36 struct reset_control *rstc; 37 struct reset_control *rstphy; 38 u32 phy_mode; 39 unsigned long host_clk; 40 u8 attcompval0; 41 u8 attcompval1; 42 u8 ctlecompval0; 43 u8 ctlecompval1; 44 }; 45 46 static int ufs_versal2_phy_reg_write(struct ufs_hba *hba, u32 addr, u32 val) 47 { 48 static struct ufshcd_dme_attr_val phy_write_attrs[] = { 49 { UIC_ARG_MIB(CBCREGADDRLSB), 0, DME_LOCAL }, 50 { UIC_ARG_MIB(CBCREGADDRMSB), 0, DME_LOCAL }, 51 { UIC_ARG_MIB(CBCREGWRLSB), 0, DME_LOCAL }, 52 { UIC_ARG_MIB(CBCREGWRMSB), 0, DME_LOCAL }, 53 { UIC_ARG_MIB(CBCREGRDWRSEL), 1, DME_LOCAL }, 54 { UIC_ARG_MIB(VS_MPHYCFGUPDT), 1, DME_LOCAL } 55 }; 56 57 phy_write_attrs[0].mib_val = (u8)addr; 58 phy_write_attrs[1].mib_val = (u8)(addr >> 8); 59 phy_write_attrs[2].mib_val = (u8)val; 60 phy_write_attrs[3].mib_val = (u8)(val >> 8); 61 62 return ufshcd_dwc_dme_set_attrs(hba, phy_write_attrs, ARRAY_SIZE(phy_write_attrs)); 63 } 64 65 static int ufs_versal2_phy_reg_read(struct ufs_hba *hba, u32 addr, u32 *val) 66 { 67 u32 mib_val; 68 int ret; 69 static struct ufshcd_dme_attr_val phy_read_attrs[] = { 70 { UIC_ARG_MIB(CBCREGADDRLSB), 0, DME_LOCAL }, 71 { UIC_ARG_MIB(CBCREGADDRMSB), 0, DME_LOCAL }, 72 { UIC_ARG_MIB(CBCREGRDWRSEL), 0, DME_LOCAL }, 73 { UIC_ARG_MIB(VS_MPHYCFGUPDT), 1, DME_LOCAL } 74 }; 75 76 phy_read_attrs[0].mib_val = (u8)addr; 77 phy_read_attrs[1].mib_val = (u8)(addr >> 8); 78 79 ret = ufshcd_dwc_dme_set_attrs(hba, phy_read_attrs, ARRAY_SIZE(phy_read_attrs)); 80 if (ret) 81 return ret; 82 83 ret = ufshcd_dme_get(hba, UIC_ARG_MIB(CBCREGRDLSB), &mib_val); 84 if (ret) 85 return ret; 86 87 *val = mib_val; 88 ret = ufshcd_dme_get(hba, UIC_ARG_MIB(CBCREGRDMSB), &mib_val); 89 if (ret) 90 return ret; 91 92 *val |= (mib_val << 8); 93 94 return 0; 95 } 96 97 static int ufs_versal2_enable_phy(struct ufs_hba *hba) 98 { 99 u32 offset, reg; 100 int ret; 101 102 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYDISABLE), 0); 103 if (ret) 104 return ret; 105 106 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 1); 107 if (ret) 108 return ret; 109 110 /* Check Tx/Rx FSM states */ 111 for (offset = 0; offset < 2; offset++) { 112 u32 time_left, mibsel; 113 114 time_left = TIMEOUT_MICROSEC; 115 mibsel = UIC_ARG_MIB_SEL(MTX_FSM_STATE, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(offset)); 116 do { 117 ret = ufshcd_dme_get(hba, mibsel, ®); 118 if (ret) 119 return ret; 120 121 if (reg == TX_STATE_HIBERN8 || reg == TX_STATE_SLEEP || 122 reg == TX_STATE_LSBURST) 123 break; 124 125 time_left--; 126 usleep_range(1, 5); 127 } while (time_left); 128 129 if (!time_left) { 130 dev_err(hba->dev, "Invalid Tx FSM state.\n"); 131 return -ETIMEDOUT; 132 } 133 134 time_left = TIMEOUT_MICROSEC; 135 mibsel = UIC_ARG_MIB_SEL(MRX_FSM_STATE, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(offset)); 136 do { 137 ret = ufshcd_dme_get(hba, mibsel, ®); 138 if (ret) 139 return ret; 140 141 if (reg == RX_STATE_HIBERN8 || reg == RX_STATE_SLEEP || 142 reg == RX_STATE_LSBURST) 143 break; 144 145 time_left--; 146 usleep_range(1, 5); 147 } while (time_left); 148 149 if (!time_left) { 150 dev_err(hba->dev, "Invalid Rx FSM state.\n"); 151 return -ETIMEDOUT; 152 } 153 } 154 155 return 0; 156 } 157 158 static int ufs_versal2_setup_phy(struct ufs_hba *hba) 159 { 160 struct ufs_versal2_host *host = ufshcd_get_variant(hba); 161 int ret; 162 u32 reg; 163 164 /* Bypass RX-AFE offset calibrations (ATT/CTLE) */ 165 ret = ufs_versal2_phy_reg_read(hba, FAST_FLAGS(0), ®); 166 if (ret) 167 return ret; 168 169 reg |= MPHY_FAST_RX_AFE_CAL; 170 ret = ufs_versal2_phy_reg_write(hba, FAST_FLAGS(0), reg); 171 if (ret) 172 return ret; 173 174 ret = ufs_versal2_phy_reg_read(hba, FAST_FLAGS(1), ®); 175 if (ret) 176 return ret; 177 178 reg |= MPHY_FAST_RX_AFE_CAL; 179 ret = ufs_versal2_phy_reg_write(hba, FAST_FLAGS(1), reg); 180 if (ret) 181 return ret; 182 183 /* Program ATT and CTLE compensation values */ 184 if (host->attcompval0) { 185 ret = ufs_versal2_phy_reg_write(hba, RX_AFE_ATT_IDAC(0), host->attcompval0); 186 if (ret) 187 return ret; 188 } 189 190 if (host->attcompval1) { 191 ret = ufs_versal2_phy_reg_write(hba, RX_AFE_ATT_IDAC(1), host->attcompval1); 192 if (ret) 193 return ret; 194 } 195 196 if (host->ctlecompval0) { 197 ret = ufs_versal2_phy_reg_write(hba, RX_AFE_CTLE_IDAC(0), host->ctlecompval0); 198 if (ret) 199 return ret; 200 } 201 202 if (host->ctlecompval1) { 203 ret = ufs_versal2_phy_reg_write(hba, RX_AFE_CTLE_IDAC(1), host->ctlecompval1); 204 if (ret) 205 return ret; 206 } 207 208 ret = ufs_versal2_phy_reg_read(hba, FW_CALIB_CCFG(0), ®); 209 if (ret) 210 return ret; 211 212 reg |= MPHY_FW_CALIB_CFG_VAL; 213 ret = ufs_versal2_phy_reg_write(hba, FW_CALIB_CCFG(0), reg); 214 if (ret) 215 return ret; 216 217 ret = ufs_versal2_phy_reg_read(hba, FW_CALIB_CCFG(1), ®); 218 if (ret) 219 return ret; 220 221 reg |= MPHY_FW_CALIB_CFG_VAL; 222 return ufs_versal2_phy_reg_write(hba, FW_CALIB_CCFG(1), reg); 223 } 224 225 static int ufs_versal2_phy_init(struct ufs_hba *hba) 226 { 227 struct ufs_versal2_host *host = ufshcd_get_variant(hba); 228 u32 time_left; 229 bool is_ready; 230 int ret; 231 static const struct ufshcd_dme_attr_val rmmi_attrs[] = { 232 { UIC_ARG_MIB(CBREFCLKCTRL2), CBREFREFCLK_GATE_OVR_EN, DME_LOCAL }, 233 { UIC_ARG_MIB(CBCRCTRL), 1, DME_LOCAL }, 234 { UIC_ARG_MIB(CBC10DIRECTCONF2), 1, DME_LOCAL }, 235 { UIC_ARG_MIB(VS_MPHYCFGUPDT), 1, DME_LOCAL } 236 }; 237 238 /* Wait for Tx/Rx config_rdy */ 239 time_left = TIMEOUT_MICROSEC; 240 do { 241 time_left--; 242 ret = zynqmp_pm_is_mphy_tx_rx_config_ready(&is_ready); 243 if (ret) 244 return ret; 245 246 if (!is_ready) 247 break; 248 249 usleep_range(1, 5); 250 } while (time_left); 251 252 if (!time_left) { 253 dev_err(hba->dev, "Tx/Rx configuration signal busy.\n"); 254 return -ETIMEDOUT; 255 } 256 257 ret = ufshcd_dwc_dme_set_attrs(hba, rmmi_attrs, ARRAY_SIZE(rmmi_attrs)); 258 if (ret) 259 return ret; 260 261 ret = reset_control_deassert(host->rstphy); 262 if (ret) { 263 dev_err(hba->dev, "ufsphy reset deassert failed, err = %d\n", ret); 264 return ret; 265 } 266 267 /* Wait for SRAM init done */ 268 time_left = TIMEOUT_MICROSEC; 269 do { 270 time_left--; 271 ret = zynqmp_pm_is_sram_init_done(&is_ready); 272 if (ret) 273 return ret; 274 275 if (is_ready) 276 break; 277 278 usleep_range(1, 5); 279 } while (time_left); 280 281 if (!time_left) { 282 dev_err(hba->dev, "SRAM initialization failed.\n"); 283 return -ETIMEDOUT; 284 } 285 286 ret = ufs_versal2_setup_phy(hba); 287 if (ret) 288 return ret; 289 290 return ufs_versal2_enable_phy(hba); 291 } 292 293 static int ufs_versal2_init(struct ufs_hba *hba) 294 { 295 struct ufs_versal2_host *host; 296 struct device *dev = hba->dev; 297 struct ufs_clk_info *clki; 298 int ret; 299 u32 cal; 300 301 host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); 302 if (!host) 303 return -ENOMEM; 304 305 host->hba = hba; 306 ufshcd_set_variant(hba, host); 307 308 host->phy_mode = UFSHCD_DWC_PHY_MODE_ROM; 309 310 list_for_each_entry(clki, &hba->clk_list_head, list) { 311 if (!strcmp(clki->name, "core")) 312 host->host_clk = clk_get_rate(clki->clk); 313 } 314 315 host->rstc = devm_reset_control_get_exclusive(dev, "host"); 316 if (IS_ERR(host->rstc)) { 317 dev_err(dev, "failed to get reset ctrl: host\n"); 318 return PTR_ERR(host->rstc); 319 } 320 321 host->rstphy = devm_reset_control_get_exclusive(dev, "phy"); 322 if (IS_ERR(host->rstphy)) { 323 dev_err(dev, "failed to get reset ctrl: phy\n"); 324 return PTR_ERR(host->rstphy); 325 } 326 327 ret = reset_control_assert(host->rstc); 328 if (ret) { 329 dev_err(hba->dev, "host reset assert failed, err = %d\n", ret); 330 return ret; 331 } 332 333 ret = reset_control_assert(host->rstphy); 334 if (ret) { 335 dev_err(hba->dev, "phy reset assert failed, err = %d\n", ret); 336 return ret; 337 } 338 339 ret = zynqmp_pm_set_sram_bypass(); 340 if (ret) { 341 dev_err(dev, "Bypass SRAM interface failed, err = %d\n", ret); 342 return ret; 343 } 344 345 ret = reset_control_deassert(host->rstc); 346 if (ret) 347 dev_err(hba->dev, "host reset deassert failed, err = %d\n", ret); 348 349 ret = zynqmp_pm_get_ufs_calibration_values(&cal); 350 if (ret) { 351 dev_err(dev, "failed to read calibration values\n"); 352 return ret; 353 } 354 355 host->attcompval0 = (u8)cal; 356 host->attcompval1 = (u8)(cal >> 8); 357 host->ctlecompval0 = (u8)(cal >> 16); 358 host->ctlecompval1 = (u8)(cal >> 24); 359 360 hba->quirks |= UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING; 361 362 return 0; 363 } 364 365 static int ufs_versal2_hce_enable_notify(struct ufs_hba *hba, 366 enum ufs_notify_change_status status) 367 { 368 int ret = 0; 369 370 if (status == PRE_CHANGE) { 371 ret = ufs_versal2_phy_init(hba); 372 if (ret) 373 dev_err(hba->dev, "Phy init failed (%d)\n", ret); 374 } 375 376 return ret; 377 } 378 379 static int ufs_versal2_link_startup_notify(struct ufs_hba *hba, 380 enum ufs_notify_change_status status) 381 { 382 struct ufs_versal2_host *host = ufshcd_get_variant(hba); 383 int ret = 0; 384 385 switch (status) { 386 case PRE_CHANGE: 387 if (host->host_clk) 388 ufshcd_writel(hba, host->host_clk / 1000000, DWC_UFS_REG_HCLKDIV); 389 390 break; 391 case POST_CHANGE: 392 ret = ufshcd_dwc_link_startup_notify(hba, status); 393 break; 394 default: 395 ret = -EINVAL; 396 break; 397 } 398 399 return ret; 400 } 401 402 static int ufs_versal2_phy_ratesel(struct ufs_hba *hba, u32 activelanes, u32 rx_req) 403 { 404 u32 time_left, reg, lane; 405 int ret; 406 407 for (lane = 0; lane < activelanes; lane++) { 408 time_left = TIMEOUT_MICROSEC; 409 ret = ufs_versal2_phy_reg_read(hba, RX_OVRD_IN_1(lane), ®); 410 if (ret) 411 return ret; 412 413 reg |= MPHY_RX_OVRD_EN; 414 if (rx_req) 415 reg |= MPHY_RX_OVRD_VAL; 416 else 417 reg &= ~MPHY_RX_OVRD_VAL; 418 419 ret = ufs_versal2_phy_reg_write(hba, RX_OVRD_IN_1(lane), reg); 420 if (ret) 421 return ret; 422 423 do { 424 ret = ufs_versal2_phy_reg_read(hba, RX_PCS_OUT(lane), ®); 425 if (ret) 426 return ret; 427 428 reg &= MPHY_RX_ACK_MASK; 429 if (reg == rx_req) 430 break; 431 432 time_left--; 433 usleep_range(1, 5); 434 } while (time_left); 435 436 if (!time_left) { 437 dev_err(hba->dev, "Invalid Rx Ack value.\n"); 438 return -ETIMEDOUT; 439 } 440 } 441 442 return 0; 443 } 444 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 struct ufs_pa_layer_attr *dev_req_params) 448 { 449 struct ufs_versal2_host *host = ufshcd_get_variant(hba); 450 u32 lane, reg, rate = 0; 451 int ret = 0; 452 453 if (status == PRE_CHANGE) { 454 memcpy(dev_req_params, dev_max_params, sizeof(struct ufs_pa_layer_attr)); 455 456 /* If it is not a calibrated part, switch PWRMODE to SLOW_MODE */ 457 if (!host->attcompval0 && !host->attcompval1 && !host->ctlecompval0 && 458 !host->ctlecompval1) { 459 dev_req_params->pwr_rx = SLOW_MODE; 460 dev_req_params->pwr_tx = SLOW_MODE; 461 return 0; 462 } 463 464 if (dev_req_params->pwr_rx == SLOW_MODE || dev_req_params->pwr_rx == SLOWAUTO_MODE) 465 return 0; 466 467 if (dev_req_params->hs_rate == PA_HS_MODE_B) 468 rate = 1; 469 470 /* Select the rate */ 471 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(CBRATESEL), rate); 472 if (ret) 473 return ret; 474 475 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 1); 476 if (ret) 477 return ret; 478 479 ret = ufs_versal2_phy_ratesel(hba, dev_req_params->lane_tx, 1); 480 if (ret) 481 return ret; 482 483 ret = ufs_versal2_phy_ratesel(hba, dev_req_params->lane_tx, 0); 484 if (ret) 485 return ret; 486 487 /* Remove rx_req override */ 488 for (lane = 0; lane < dev_req_params->lane_tx; lane++) { 489 ret = ufs_versal2_phy_reg_read(hba, RX_OVRD_IN_1(lane), ®); 490 if (ret) 491 return ret; 492 493 reg &= ~MPHY_RX_OVRD_EN; 494 ret = ufs_versal2_phy_reg_write(hba, RX_OVRD_IN_1(lane), reg); 495 if (ret) 496 return ret; 497 } 498 499 if (dev_req_params->lane_tx == UFS_LANE_2 && dev_req_params->lane_rx == UFS_LANE_2) 500 ret = ufshcd_dme_configure_adapt(hba, dev_req_params->gear_tx, 501 PA_INITIAL_ADAPT); 502 } 503 504 return ret; 505 } 506 507 static struct ufs_hba_variant_ops ufs_versal2_hba_vops = { 508 .name = "ufs-versal2-pltfm", 509 .init = ufs_versal2_init, 510 .link_startup_notify = ufs_versal2_link_startup_notify, 511 .hce_enable_notify = ufs_versal2_hce_enable_notify, 512 .pwr_change_notify = ufs_versal2_pwr_change_notify, 513 }; 514 515 static const struct of_device_id ufs_versal2_pltfm_match[] = { 516 { 517 .compatible = "amd,versal2-ufs", 518 .data = &ufs_versal2_hba_vops, 519 }, 520 { }, 521 }; 522 MODULE_DEVICE_TABLE(of, ufs_versal2_pltfm_match); 523 524 static int ufs_versal2_probe(struct platform_device *pdev) 525 { 526 struct device *dev = &pdev->dev; 527 int ret; 528 529 /* Perform generic probe */ 530 ret = ufshcd_pltfrm_init(pdev, &ufs_versal2_hba_vops); 531 if (ret) 532 dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", ret); 533 534 return ret; 535 } 536 537 static void ufs_versal2_remove(struct platform_device *pdev) 538 { 539 struct ufs_hba *hba = platform_get_drvdata(pdev); 540 541 pm_runtime_get_sync(&(pdev)->dev); 542 ufshcd_remove(hba); 543 } 544 545 static const struct dev_pm_ops ufs_versal2_pm_ops = { 546 SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume) 547 SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL) 548 }; 549 550 static struct platform_driver ufs_versal2_pltfm = { 551 .probe = ufs_versal2_probe, 552 .remove = ufs_versal2_remove, 553 .driver = { 554 .name = "ufshcd-versal2", 555 .pm = &ufs_versal2_pm_ops, 556 .of_match_table = of_match_ptr(ufs_versal2_pltfm_match), 557 }, 558 }; 559 560 module_platform_driver(ufs_versal2_pltfm); 561 562 MODULE_AUTHOR("Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>"); 563 MODULE_DESCRIPTION("AMD Versal Gen 2 UFS Host Controller driver"); 564 MODULE_LICENSE("GPL"); 565