Skip to content

Commit 0cc22f5

Browse files
Qiang Yuvinodkoul
authored andcommitted
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 <[email protected]> Signed-off-by: Wenbin Yao <[email protected]> Reviewed-by: Manivannan Sadhasivam <[email protected]> Tested-by: Aleksandrs Vinarskis <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent ea57d7f commit 0cc22f5

File tree

1 file changed

+59
-10
lines changed

1 file changed

+59
-10
lines changed

drivers/phy/qualcomm/phy-qcom-qmp-pcie.c

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3033,6 +3033,7 @@ struct qmp_pcie {
30333033

30343034
const struct qmp_phy_cfg *cfg;
30353035
bool tcsr_4ln_config;
3036+
bool skip_init;
30363037

30373038
void __iomem *serdes;
30383039
void __iomem *pcs;
@@ -4330,18 +4331,38 @@ static int qmp_pcie_init(struct phy *phy)
43304331
{
43314332
struct qmp_pcie *qmp = phy_get_drvdata(phy);
43324333
const struct qmp_phy_cfg *cfg = qmp->cfg;
4334+
void __iomem *pcs = qmp->pcs;
4335+
bool phy_initialized = !!(readl(pcs + cfg->regs[QPHY_START_CTRL]));
43334336
int ret;
43344337

4338+
qmp->skip_init = qmp->nocsr_reset && phy_initialized;
4339+
/*
4340+
* We need to check the existence of init sequences in two cases:
4341+
* 1. The PHY doesn't support no_csr reset.
4342+
* 2. The PHY supports no_csr reset but isn't initialized by bootloader.
4343+
* As we can't skip init in these two cases.
4344+
*/
4345+
if (!qmp->skip_init && !cfg->tbls.serdes_num) {
4346+
dev_err(qmp->dev, "Init sequence not available\n");
4347+
return -ENODATA;
4348+
}
4349+
43354350
ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
43364351
if (ret) {
43374352
dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
43384353
return ret;
43394354
}
43404355

4341-
ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets);
4342-
if (ret) {
4343-
dev_err(qmp->dev, "reset assert failed\n");
4344-
goto err_disable_regulators;
4356+
/*
4357+
* Toggle BCR reset for PHY that doesn't support no_csr reset or has not
4358+
* been initialized.
4359+
*/
4360+
if (!qmp->skip_init) {
4361+
ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets);
4362+
if (ret) {
4363+
dev_err(qmp->dev, "reset assert failed\n");
4364+
goto err_disable_regulators;
4365+
}
43454366
}
43464367

43474368
ret = reset_control_assert(qmp->nocsr_reset);
@@ -4352,10 +4373,12 @@ static int qmp_pcie_init(struct phy *phy)
43524373

43534374
usleep_range(200, 300);
43544375

4355-
ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets);
4356-
if (ret) {
4357-
dev_err(qmp->dev, "reset deassert failed\n");
4358-
goto err_assert_reset;
4376+
if (!qmp->skip_init) {
4377+
ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets);
4378+
if (ret) {
4379+
dev_err(qmp->dev, "reset deassert failed\n");
4380+
goto err_assert_reset;
4381+
}
43594382
}
43604383

43614384
ret = clk_bulk_prepare_enable(ARRAY_SIZE(qmp_pciephy_clk_l), qmp->clks);
@@ -4365,7 +4388,8 @@ static int qmp_pcie_init(struct phy *phy)
43654388
return 0;
43664389

43674390
err_assert_reset:
4368-
reset_control_bulk_assert(cfg->num_resets, qmp->resets);
4391+
if (!qmp->skip_init)
4392+
reset_control_bulk_assert(cfg->num_resets, qmp->resets);
43694393
err_disable_regulators:
43704394
regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
43714395

@@ -4377,7 +4401,10 @@ static int qmp_pcie_exit(struct phy *phy)
43774401
struct qmp_pcie *qmp = phy_get_drvdata(phy);
43784402
const struct qmp_phy_cfg *cfg = qmp->cfg;
43794403

4380-
reset_control_bulk_assert(cfg->num_resets, qmp->resets);
4404+
if (qmp->nocsr_reset)
4405+
reset_control_assert(qmp->nocsr_reset);
4406+
else
4407+
reset_control_bulk_assert(cfg->num_resets, qmp->resets);
43814408

43824409
clk_bulk_disable_unprepare(ARRAY_SIZE(qmp_pciephy_clk_l), qmp->clks);
43834410

@@ -4396,6 +4423,13 @@ static int qmp_pcie_power_on(struct phy *phy)
43964423
unsigned int mask, val;
43974424
int ret;
43984425

4426+
/*
4427+
* Write CSR register for PHY that doesn't support no_csr reset or has not
4428+
* been initialized.
4429+
*/
4430+
if (qmp->skip_init)
4431+
goto skip_tbls_init;
4432+
43994433
qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
44004434
cfg->pwrdn_ctrl);
44014435

@@ -4407,6 +4441,7 @@ static int qmp_pcie_power_on(struct phy *phy)
44074441
qmp_pcie_init_registers(qmp, &cfg->tbls);
44084442
qmp_pcie_init_registers(qmp, mode_tbls);
44094443

4444+
skip_tbls_init:
44104445
ret = clk_bulk_prepare_enable(qmp->num_pipe_clks, qmp->pipe_clks);
44114446
if (ret)
44124447
return ret;
@@ -4417,6 +4452,9 @@ static int qmp_pcie_power_on(struct phy *phy)
44174452
goto err_disable_pipe_clk;
44184453
}
44194454

4455+
if (qmp->skip_init)
4456+
goto skip_serdes_start;
4457+
44204458
/* Pull PHY out of reset state */
44214459
qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
44224460

@@ -4426,6 +4464,7 @@ static int qmp_pcie_power_on(struct phy *phy)
44264464
if (!cfg->skip_start_delay)
44274465
usleep_range(1000, 1200);
44284466

4467+
skip_serdes_start:
44294468
status = pcs + cfg->regs[QPHY_PCS_STATUS];
44304469
mask = cfg->phy_status;
44314470
ret = readl_poll_timeout(status, val, !(val & mask), 200,
@@ -4450,6 +4489,15 @@ static int qmp_pcie_power_off(struct phy *phy)
44504489

44514490
clk_bulk_disable_unprepare(qmp->num_pipe_clks, qmp->pipe_clks);
44524491

4492+
/*
4493+
* While powering off the PHY, only qmp->nocsr_reset needs to be checked. In
4494+
* this way, no matter whether the PHY settings were initially programmed by
4495+
* bootloader or PHY driver itself, we can reuse them when PHY is powered on
4496+
* next time.
4497+
*/
4498+
if (qmp->nocsr_reset)
4499+
goto skip_phy_deinit;
4500+
44534501
/* PHY reset */
44544502
qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
44554503

@@ -4461,6 +4509,7 @@ static int qmp_pcie_power_off(struct phy *phy)
44614509
qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
44624510
cfg->pwrdn_ctrl);
44634511

4512+
skip_phy_deinit:
44644513
return 0;
44654514
}
44664515

0 commit comments

Comments
 (0)