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

phy: ufs-qcom: Refactor all init steps into phy_poweron

The phy code was using implicit sequencing between the PHY driver
and the UFS driver to implement certain hardware requirements.
Specifically, the PHY reset register in the UFS controller needs
to be deasserted before serdes start occurs in the PHY.

Before this change, the code was doing this by utilizing the two
phy callbacks, phy_init() and phy_poweron(), as "init step 1" and
"init step 2", where the UFS driver would deassert reset between
these two steps.

This makes it challenging to power off the regulators in suspend,
as regulators are initialized in init, not in poweron(), but only
poweroff() is called during suspend, not exit().

For UFS, move the actual firing up of the PHY to phy_poweron() and
phy_poweroff() callbacks, rather than init()/exit(). UFS calls
phy_poweroff() during suspend, so now all clocks and regulators for
the phy can be powered down during suspend.

QMP is a little tricky because the PHY is also shared with PCIe and
USB3, which have their own definitions for init() and poweron(). Rename
the meaty functions to _enable() and _disable() to disentangle from the
PHY core names, and then create two different ops structures: one for
UFS and one for the other PHY types.

In phy-qcom-ufs, remove the 'is_powered_on' and 'is_started' guards,
as the generic PHY code does the reference counting. The
14/20nm-specific init functions get collapsed into the generic power_on()
function, with the addition of a calibrate() callback specific to 14/20nm.

Signed-off-by: Evan Green <evgreen@chromium.org>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Evan Green and committed by
Kishon Vijay Abraham I
3f6d1767 c9b58979

+64 -170
+21 -57
drivers/phy/qualcomm/phy-qcom-qmp.c
··· 1339 1339 return 0; 1340 1340 } 1341 1341 1342 - /* PHY Initialization */ 1343 - static int qcom_qmp_phy_init(struct phy *phy) 1342 + static int qcom_qmp_phy_enable(struct phy *phy) 1344 1343 { 1345 1344 struct qmp_phy *qphy = phy_get_drvdata(phy); 1346 1345 struct qcom_qmp *qmp = qphy->qmp; ··· 1418 1419 goto err_lane_rst; 1419 1420 1420 1421 /* 1421 - * UFS PHY requires the deassert of software reset before serdes start. 1422 - * For UFS PHYs that do not have software reset control bits, defer 1423 - * starting serdes until the power on callback. 1424 - */ 1425 - if ((cfg->type == PHY_TYPE_UFS) && cfg->no_pcs_sw_reset) 1426 - goto out; 1427 - 1428 - /* 1429 1422 * Pull out PHY from POWER DOWN state. 1430 1423 * This is active low enable signal to power-down PHY. 1431 1424 */ ··· 1428 1437 usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max); 1429 1438 1430 1439 /* Pull PHY out of reset state */ 1431 - qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); 1440 + if (!cfg->no_pcs_sw_reset) 1441 + qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); 1442 + 1432 1443 if (cfg->has_phy_dp_com_ctrl) 1433 1444 qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET); 1434 1445 ··· 1447 1454 goto err_pcs_ready; 1448 1455 } 1449 1456 qmp->phy_initialized = true; 1450 - 1451 - out: 1452 - return ret; 1457 + return 0; 1453 1458 1454 1459 err_pcs_ready: 1460 + reset_control_assert(qmp->ufs_reset); 1455 1461 clk_disable_unprepare(qphy->pipe_clk); 1456 1462 err_clk_enable: 1457 1463 if (cfg->has_lane_rst) ··· 1461 1469 return ret; 1462 1470 } 1463 1471 1464 - static int qcom_qmp_phy_exit(struct phy *phy) 1472 + static int qcom_qmp_phy_disable(struct phy *phy) 1465 1473 { 1466 1474 struct qmp_phy *qphy = phy_get_drvdata(phy); 1467 1475 struct qcom_qmp *qmp = qphy->qmp; ··· 1487 1495 qmp->phy_initialized = false; 1488 1496 1489 1497 return 0; 1490 - } 1491 - 1492 - static int qcom_qmp_phy_poweron(struct phy *phy) 1493 - { 1494 - struct qmp_phy *qphy = phy_get_drvdata(phy); 1495 - struct qcom_qmp *qmp = qphy->qmp; 1496 - const struct qmp_phy_cfg *cfg = qmp->cfg; 1497 - void __iomem *pcs = qphy->pcs; 1498 - void __iomem *status; 1499 - unsigned int mask, val; 1500 - int ret = 0; 1501 - 1502 - if (cfg->type != PHY_TYPE_UFS) 1503 - return 0; 1504 - 1505 - /* 1506 - * For UFS PHY that has not software reset control, serdes start 1507 - * should only happen when UFS driver explicitly calls phy_power_on 1508 - * after it deasserts software reset. 1509 - */ 1510 - if (cfg->no_pcs_sw_reset && !qmp->phy_initialized && 1511 - (qmp->init_count != 0)) { 1512 - /* start SerDes and Phy-Coding-Sublayer */ 1513 - qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl); 1514 - 1515 - status = pcs + cfg->regs[QPHY_PCS_READY_STATUS]; 1516 - mask = cfg->mask_pcs_ready; 1517 - 1518 - ret = readl_poll_timeout(status, val, !(val & mask), 1, 1519 - PHY_INIT_COMPLETE_TIMEOUT); 1520 - if (ret) { 1521 - dev_err(qmp->dev, "phy initialization timed-out\n"); 1522 - return ret; 1523 - } 1524 - qmp->phy_initialized = true; 1525 - } 1526 - 1527 - return ret; 1528 1498 } 1529 1499 1530 1500 static int qcom_qmp_phy_set_mode(struct phy *phy, ··· 1738 1784 } 1739 1785 1740 1786 static const struct phy_ops qcom_qmp_phy_gen_ops = { 1741 - .init = qcom_qmp_phy_init, 1742 - .exit = qcom_qmp_phy_exit, 1743 - .power_on = qcom_qmp_phy_poweron, 1787 + .init = qcom_qmp_phy_enable, 1788 + .exit = qcom_qmp_phy_disable, 1789 + .set_mode = qcom_qmp_phy_set_mode, 1790 + .owner = THIS_MODULE, 1791 + }; 1792 + 1793 + static const struct phy_ops qcom_qmp_ufs_ops = { 1794 + .power_on = qcom_qmp_phy_enable, 1795 + .power_off = qcom_qmp_phy_disable, 1744 1796 .set_mode = qcom_qmp_phy_set_mode, 1745 1797 .owner = THIS_MODULE, 1746 1798 }; ··· 1757 1797 struct qcom_qmp *qmp = dev_get_drvdata(dev); 1758 1798 struct phy *generic_phy; 1759 1799 struct qmp_phy *qphy; 1800 + const struct phy_ops *ops = &qcom_qmp_phy_gen_ops; 1760 1801 char prop_name[MAX_PROP_NAME]; 1761 1802 int ret; 1762 1803 ··· 1844 1883 } 1845 1884 } 1846 1885 1847 - generic_phy = devm_phy_create(dev, np, &qcom_qmp_phy_gen_ops); 1886 + if (qmp->cfg->type == PHY_TYPE_UFS) 1887 + ops = &qcom_qmp_ufs_ops; 1888 + 1889 + generic_phy = devm_phy_create(dev, np, ops); 1848 1890 if (IS_ERR(generic_phy)) { 1849 1891 ret = PTR_ERR(generic_phy); 1850 1892 dev_err(dev, "failed to create qphy %d\n", ret);
+1 -3
drivers/phy/qualcomm/phy-qcom-ufs-i.h
··· 97 97 char name[UFS_QCOM_PHY_NAME_LEN]; 98 98 struct ufs_qcom_phy_calibration *cached_regs; 99 99 int cached_regs_table_size; 100 - bool is_powered_on; 101 - bool is_started; 102 100 struct ufs_qcom_phy_specific_ops *phy_spec_ops; 103 101 104 102 enum phy_mode mode; ··· 115 117 * and writes to QSERDES_RX_SIGDET_CNTRL attribute 116 118 */ 117 119 struct ufs_qcom_phy_specific_ops { 120 + int (*calibrate)(struct ufs_qcom_phy *ufs_qcom_phy, bool is_rate_B); 118 121 void (*start_serdes)(struct ufs_qcom_phy *phy); 119 122 int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy); 120 123 void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val); ··· 133 134 struct ufs_qcom_phy *common_cfg, 134 135 const struct phy_ops *ufs_qcom_phy_gen_ops, 135 136 struct ufs_qcom_phy_specific_ops *phy_spec_ops); 136 - int ufs_qcom_phy_get_reset(struct ufs_qcom_phy *phy_common); 137 137 int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, 138 138 struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A, 139 139 struct ufs_qcom_phy_calibration *tbl_B, int tbl_size_B,
+1 -32
drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c
··· 42 42 UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE; 43 43 } 44 44 45 - static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy) 46 - { 47 - struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); 48 - bool is_rate_B = false; 49 - int ret; 50 - 51 - ret = ufs_qcom_phy_get_reset(phy_common); 52 - if (ret) 53 - return ret; 54 - 55 - ret = reset_control_assert(phy_common->ufs_reset); 56 - if (ret) 57 - return ret; 58 - 59 - if (phy_common->mode == PHY_MODE_UFS_HS_B) 60 - is_rate_B = true; 61 - 62 - ret = ufs_qcom_phy_qmp_14nm_phy_calibrate(phy_common, is_rate_B); 63 - if (!ret) 64 - /* phy calibrated, but yet to be started */ 65 - phy_common->is_started = false; 66 - 67 - return ret; 68 - } 69 - 70 - static int ufs_qcom_phy_qmp_14nm_exit(struct phy *generic_phy) 71 - { 72 - return 0; 73 - } 74 - 75 45 static 76 46 int ufs_qcom_phy_qmp_14nm_set_mode(struct phy *generic_phy, 77 47 enum phy_mode mode, int submode) ··· 102 132 } 103 133 104 134 static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = { 105 - .init = ufs_qcom_phy_qmp_14nm_init, 106 - .exit = ufs_qcom_phy_qmp_14nm_exit, 107 135 .power_on = ufs_qcom_phy_power_on, 108 136 .power_off = ufs_qcom_phy_power_off, 109 137 .set_mode = ufs_qcom_phy_qmp_14nm_set_mode, ··· 109 141 }; 110 142 111 143 static struct ufs_qcom_phy_specific_ops phy_14nm_ops = { 144 + .calibrate = ufs_qcom_phy_qmp_14nm_phy_calibrate, 112 145 .start_serdes = ufs_qcom_phy_qmp_14nm_start_serdes, 113 146 .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_14nm_is_pcs_ready, 114 147 .set_tx_lane_enable = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable,
+1 -32
drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c
··· 61 61 UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE; 62 62 } 63 63 64 - static int ufs_qcom_phy_qmp_20nm_init(struct phy *generic_phy) 65 - { 66 - struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); 67 - bool is_rate_B = false; 68 - int ret; 69 - 70 - ret = ufs_qcom_phy_get_reset(phy_common); 71 - if (ret) 72 - return ret; 73 - 74 - ret = reset_control_assert(phy_common->ufs_reset); 75 - if (ret) 76 - return ret; 77 - 78 - if (phy_common->mode == PHY_MODE_UFS_HS_B) 79 - is_rate_B = true; 80 - 81 - ret = ufs_qcom_phy_qmp_20nm_phy_calibrate(phy_common, is_rate_B); 82 - if (!ret) 83 - /* phy calibrated, but yet to be started */ 84 - phy_common->is_started = false; 85 - 86 - return ret; 87 - } 88 - 89 - static int ufs_qcom_phy_qmp_20nm_exit(struct phy *generic_phy) 90 - { 91 - return 0; 92 - } 93 - 94 64 static 95 65 int ufs_qcom_phy_qmp_20nm_set_mode(struct phy *generic_phy, 96 66 enum phy_mode mode, int submode) ··· 160 190 } 161 191 162 192 static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = { 163 - .init = ufs_qcom_phy_qmp_20nm_init, 164 - .exit = ufs_qcom_phy_qmp_20nm_exit, 165 193 .power_on = ufs_qcom_phy_power_on, 166 194 .power_off = ufs_qcom_phy_power_off, 167 195 .set_mode = ufs_qcom_phy_qmp_20nm_set_mode, ··· 167 199 }; 168 200 169 201 static struct ufs_qcom_phy_specific_ops phy_20nm_ops = { 202 + .calibrate = ufs_qcom_phy_qmp_20nm_phy_calibrate, 170 203 .start_serdes = ufs_qcom_phy_qmp_20nm_start_serdes, 171 204 .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready, 172 205 .set_tx_lane_enable = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable,
+22 -20
drivers/phy/qualcomm/phy-qcom-ufs.c
··· 147 147 } 148 148 EXPORT_SYMBOL_GPL(ufs_qcom_phy_generic_probe); 149 149 150 - int ufs_qcom_phy_get_reset(struct ufs_qcom_phy *phy_common) 150 + static int ufs_qcom_phy_get_reset(struct ufs_qcom_phy *phy_common) 151 151 { 152 152 struct reset_control *reset; 153 153 ··· 161 161 phy_common->ufs_reset = reset; 162 162 return 0; 163 163 } 164 - EXPORT_SYMBOL_GPL(ufs_qcom_phy_get_reset); 165 164 166 165 static int __ufs_qcom_phy_clk_get(struct device *dev, 167 166 const char *name, struct clk **clk_out, bool err_print) ··· 543 544 { 544 545 struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); 545 546 struct device *dev = phy_common->dev; 547 + bool is_rate_B = false; 546 548 int err; 547 549 548 - if (phy_common->is_powered_on) 549 - return 0; 550 + err = ufs_qcom_phy_get_reset(phy_common); 551 + if (err) 552 + return err; 553 + 554 + err = reset_control_assert(phy_common->ufs_reset); 555 + if (err) 556 + return err; 557 + 558 + if (phy_common->mode == PHY_MODE_UFS_HS_B) 559 + is_rate_B = true; 560 + 561 + err = phy_common->phy_spec_ops->calibrate(phy_common, is_rate_B); 562 + if (err) 563 + return err; 550 564 551 565 err = reset_control_deassert(phy_common->ufs_reset); 552 566 if (err) { ··· 567 555 return err; 568 556 } 569 557 570 - if (!phy_common->is_started) { 571 - err = ufs_qcom_phy_start_serdes(phy_common); 572 - if (err) 573 - return err; 558 + err = ufs_qcom_phy_start_serdes(phy_common); 559 + if (err) 560 + return err; 574 561 575 - err = ufs_qcom_phy_is_pcs_ready(phy_common); 576 - if (err) 577 - return err; 578 - 579 - phy_common->is_started = true; 580 - } 562 + err = ufs_qcom_phy_is_pcs_ready(phy_common); 563 + if (err) 564 + return err; 581 565 582 566 err = ufs_qcom_phy_enable_vreg(dev, &phy_common->vdda_phy); 583 567 if (err) { ··· 617 609 } 618 610 } 619 611 620 - phy_common->is_powered_on = true; 621 612 goto out; 622 613 623 614 out_disable_ref_clk: ··· 636 629 { 637 630 struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); 638 631 639 - if (!phy_common->is_powered_on) 640 - return 0; 641 - 642 632 phy_common->phy_spec_ops->power_control(phy_common, false); 643 633 644 634 if (phy_common->vddp_ref_clk.reg) ··· 647 643 ufs_qcom_phy_disable_vreg(phy_common->dev, &phy_common->vdda_pll); 648 644 ufs_qcom_phy_disable_vreg(phy_common->dev, &phy_common->vdda_phy); 649 645 reset_control_assert(phy_common->ufs_reset); 650 - phy_common->is_powered_on = false; 651 - 652 646 return 0; 653 647 } 654 648 EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off);
+18 -26
drivers/scsi/ufs/ufs-qcom.c
··· 544 544 */ 545 545 ufs_qcom_disable_lane_clks(host); 546 546 phy_power_off(phy); 547 - goto out; 548 - } 549 547 550 - /* 551 - * If UniPro link is not active, PHY ref_clk, main PHY analog power 552 - * rail and low noise analog power rail for PLL can be switched off. 553 - */ 554 - if (!ufs_qcom_is_link_active(hba)) { 548 + } else if (!ufs_qcom_is_link_active(hba)) { 555 549 ufs_qcom_disable_lane_clks(host); 556 - phy_power_off(phy); 557 550 } 558 551 559 - out: 560 552 return ret; 561 553 } 562 554 ··· 558 566 struct phy *phy = host->generic_phy; 559 567 int err; 560 568 561 - err = phy_power_on(phy); 562 - if (err) { 563 - dev_err(hba->dev, "%s: failed enabling regs, err = %d\n", 564 - __func__, err); 565 - goto out; 569 + if (ufs_qcom_is_link_off(hba)) { 570 + err = phy_power_on(phy); 571 + if (err) { 572 + dev_err(hba->dev, "%s: failed PHY power on: %d\n", 573 + __func__, err); 574 + return err; 575 + } 576 + 577 + err = ufs_qcom_enable_lane_clks(host); 578 + if (err) 579 + return err; 580 + 581 + } else if (!ufs_qcom_is_link_active(hba)) { 582 + err = ufs_qcom_enable_lane_clks(host); 583 + if (err) 584 + return err; 566 585 } 567 586 568 - err = ufs_qcom_enable_lane_clks(host); 569 - if (err) 570 - goto out; 571 - 572 587 hba->is_sys_suspended = false; 573 - 574 - out: 575 - return err; 588 + return 0; 576 589 } 577 590 578 591 struct ufs_qcom_dev_params { ··· 1103 1106 return 0; 1104 1107 1105 1108 if (on && (status == POST_CHANGE)) { 1106 - phy_power_on(host->generic_phy); 1107 - 1108 1109 /* enable the device ref clock for HS mode*/ 1109 1110 if (ufshcd_is_hs_mode(&hba->pwr_info)) 1110 1111 ufs_qcom_dev_ref_clk_ctrl(host, true); ··· 1114 1119 if (!ufs_qcom_is_link_active(hba)) { 1115 1120 /* disable device ref_clk */ 1116 1121 ufs_qcom_dev_ref_clk_ctrl(host, false); 1117 - 1118 - /* powering off PHY during aggressive clk gating */ 1119 - phy_power_off(host->generic_phy); 1120 1122 } 1121 1123 1122 1124 vote = host->bus_vote.min_bw_vote;