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.

phy: qcom: qmp-pcie: Add PHY register retention support

Some QCOM PCIe PHYs support no_csr reset. Unlike BCR reset which resets the
whole PHY (hardware and register), no_csr reset only resets PHY hardware
but retains register values, which means PHY setting can be skipped during
PHY init if PCIe link is enabled in bootloader and only no_csr is toggled
after that.

Hence, determine whether the PHY has been enabled in bootloader by
verifying QPHY_START_CTRL register. If it's programmed and no_csr reset is
available, skip BCR reset and PHY register setting to establish the PCIe
link with bootloader - programmed PHY settings.

Signed-off-by: Qiang Yu <quic_qianyu@quicinc.com>
Signed-off-by: Wenbin Yao <quic_wenbyao@quicinc.com>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Tested-by: Aleksandrs Vinarskis <alex.vinarskis@gmail.com>
Link: https://lore.kernel.org/r/20250411113120.651363-3-quic_wenbyao@quicinc.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Qiang Yu and committed by
Vinod Koul
0cc22f5a ea57d7fe

+59 -10
+59 -10
drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
··· 3033 3033 3034 3034 const struct qmp_phy_cfg *cfg; 3035 3035 bool tcsr_4ln_config; 3036 + bool skip_init; 3036 3037 3037 3038 void __iomem *serdes; 3038 3039 void __iomem *pcs; ··· 4331 4330 { 4332 4331 struct qmp_pcie *qmp = phy_get_drvdata(phy); 4333 4332 const struct qmp_phy_cfg *cfg = qmp->cfg; 4333 + void __iomem *pcs = qmp->pcs; 4334 + bool phy_initialized = !!(readl(pcs + cfg->regs[QPHY_START_CTRL])); 4334 4335 int ret; 4336 + 4337 + qmp->skip_init = qmp->nocsr_reset && phy_initialized; 4338 + /* 4339 + * We need to check the existence of init sequences in two cases: 4340 + * 1. The PHY doesn't support no_csr reset. 4341 + * 2. The PHY supports no_csr reset but isn't initialized by bootloader. 4342 + * As we can't skip init in these two cases. 4343 + */ 4344 + if (!qmp->skip_init && !cfg->tbls.serdes_num) { 4345 + dev_err(qmp->dev, "Init sequence not available\n"); 4346 + return -ENODATA; 4347 + } 4335 4348 4336 4349 ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); 4337 4350 if (ret) { ··· 4353 4338 return ret; 4354 4339 } 4355 4340 4356 - ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets); 4357 - if (ret) { 4358 - dev_err(qmp->dev, "reset assert failed\n"); 4359 - goto err_disable_regulators; 4341 + /* 4342 + * Toggle BCR reset for PHY that doesn't support no_csr reset or has not 4343 + * been initialized. 4344 + */ 4345 + if (!qmp->skip_init) { 4346 + ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets); 4347 + if (ret) { 4348 + dev_err(qmp->dev, "reset assert failed\n"); 4349 + goto err_disable_regulators; 4350 + } 4360 4351 } 4361 4352 4362 4353 ret = reset_control_assert(qmp->nocsr_reset); ··· 4373 4352 4374 4353 usleep_range(200, 300); 4375 4354 4376 - ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets); 4377 - if (ret) { 4378 - dev_err(qmp->dev, "reset deassert failed\n"); 4379 - goto err_assert_reset; 4355 + if (!qmp->skip_init) { 4356 + ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets); 4357 + if (ret) { 4358 + dev_err(qmp->dev, "reset deassert failed\n"); 4359 + goto err_assert_reset; 4360 + } 4380 4361 } 4381 4362 4382 4363 ret = clk_bulk_prepare_enable(ARRAY_SIZE(qmp_pciephy_clk_l), qmp->clks); ··· 4388 4365 return 0; 4389 4366 4390 4367 err_assert_reset: 4391 - reset_control_bulk_assert(cfg->num_resets, qmp->resets); 4368 + if (!qmp->skip_init) 4369 + reset_control_bulk_assert(cfg->num_resets, qmp->resets); 4392 4370 err_disable_regulators: 4393 4371 regulator_bulk_disable(cfg->num_vregs, qmp->vregs); 4394 4372 ··· 4401 4377 struct qmp_pcie *qmp = phy_get_drvdata(phy); 4402 4378 const struct qmp_phy_cfg *cfg = qmp->cfg; 4403 4379 4404 - reset_control_bulk_assert(cfg->num_resets, qmp->resets); 4380 + if (qmp->nocsr_reset) 4381 + reset_control_assert(qmp->nocsr_reset); 4382 + else 4383 + reset_control_bulk_assert(cfg->num_resets, qmp->resets); 4405 4384 4406 4385 clk_bulk_disable_unprepare(ARRAY_SIZE(qmp_pciephy_clk_l), qmp->clks); 4407 4386 ··· 4423 4396 unsigned int mask, val; 4424 4397 int ret; 4425 4398 4399 + /* 4400 + * Write CSR register for PHY that doesn't support no_csr reset or has not 4401 + * been initialized. 4402 + */ 4403 + if (qmp->skip_init) 4404 + goto skip_tbls_init; 4405 + 4426 4406 qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], 4427 4407 cfg->pwrdn_ctrl); 4428 4408 ··· 4441 4407 qmp_pcie_init_registers(qmp, &cfg->tbls); 4442 4408 qmp_pcie_init_registers(qmp, mode_tbls); 4443 4409 4410 + skip_tbls_init: 4444 4411 ret = clk_bulk_prepare_enable(qmp->num_pipe_clks, qmp->pipe_clks); 4445 4412 if (ret) 4446 4413 return ret; ··· 4452 4417 goto err_disable_pipe_clk; 4453 4418 } 4454 4419 4420 + if (qmp->skip_init) 4421 + goto skip_serdes_start; 4422 + 4455 4423 /* Pull PHY out of reset state */ 4456 4424 qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); 4457 4425 ··· 4464 4426 if (!cfg->skip_start_delay) 4465 4427 usleep_range(1000, 1200); 4466 4428 4429 + skip_serdes_start: 4467 4430 status = pcs + cfg->regs[QPHY_PCS_STATUS]; 4468 4431 mask = cfg->phy_status; 4469 4432 ret = readl_poll_timeout(status, val, !(val & mask), 200, ··· 4489 4450 4490 4451 clk_bulk_disable_unprepare(qmp->num_pipe_clks, qmp->pipe_clks); 4491 4452 4453 + /* 4454 + * While powering off the PHY, only qmp->nocsr_reset needs to be checked. In 4455 + * this way, no matter whether the PHY settings were initially programmed by 4456 + * bootloader or PHY driver itself, we can reuse them when PHY is powered on 4457 + * next time. 4458 + */ 4459 + if (qmp->nocsr_reset) 4460 + goto skip_phy_deinit; 4461 + 4492 4462 /* PHY reset */ 4493 4463 qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); 4494 4464 ··· 4509 4461 qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], 4510 4462 cfg->pwrdn_ctrl); 4511 4463 4464 + skip_phy_deinit: 4512 4465 return 0; 4513 4466 } 4514 4467