ufs: phy: Update hibern8 sequences with PHY src clock setting

Updated the UFS Hibernate Enter and Exit sequences according to
the UFS Host Controller Hardware Programming Guide.
On the Waipio platforms, software must select the proper source
for the UFS PHY clocks prior to entering hibernate state.
Failure to follow the Hardware Programming Guide's
Hibernate Enter and Exit sequences will result in the UFS GDSC
clock failure.

Change-Id: I798f643fc2dcef75db2991252f9d985f5aba3687
Signed-off-by: Bao D. Nguyen <nguyenb@codeaurora.org>
This commit is contained in:
Bao D. Nguyen 2021-03-08 17:14:02 -08:00
parent a0d6e689a1
commit 471dae0840
4 changed files with 70 additions and 0 deletions

View File

@ -68,6 +68,12 @@ struct ufs_qcom_phy {
struct clk *ref_clk;
struct clk *ref_aux_clk;
struct clk *qref_clk;
struct clk *rx_sym0_mux_clk;
struct clk *rx_sym1_mux_clk;
struct clk *tx_sym0_mux_clk;
struct clk *rx_sym0_phy_clk;
struct clk *rx_sym1_phy_clk;
struct clk *tx_sym0_phy_clk;
bool is_ref_clk_enabled;
bool is_dev_ref_clk_enabled;
struct ufs_qcom_phy_vreg vdda_pll;

View File

@ -267,6 +267,19 @@ int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common)
*/
__ufs_qcom_phy_clk_get(phy_common->dev, "qref_clk",
&phy_common->qref_clk, false);
__ufs_qcom_phy_clk_get(phy_common->dev, "rx_sym0_mux_clk",
&phy_common->rx_sym0_mux_clk, false);
__ufs_qcom_phy_clk_get(phy_common->dev, "rx_sym1_mux_clk",
&phy_common->rx_sym1_mux_clk, false);
__ufs_qcom_phy_clk_get(phy_common->dev, "tx_sym0_mux_clk",
&phy_common->tx_sym0_mux_clk, false);
__ufs_qcom_phy_clk_get(phy_common->dev, "rx_sym0_phy_clk",
&phy_common->rx_sym0_phy_clk, false);
__ufs_qcom_phy_clk_get(phy_common->dev, "rx_sym1_phy_clk",
&phy_common->rx_sym1_phy_clk, false);
__ufs_qcom_phy_clk_get(phy_common->dev, "tx_sym0_phy_clk",
&phy_common->tx_sym0_phy_clk, false);
out:
return err;
}
@ -625,6 +638,52 @@ void ufs_qcom_phy_save_controller_version(struct phy *generic_phy,
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_save_controller_version);
void ufs_qcom_phy_set_src_clk_h8_enter(struct phy *generic_phy)
{
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
if (!ufs_qcom_phy->rx_sym0_mux_clk || !ufs_qcom_phy->rx_sym1_mux_clk ||
!ufs_qcom_phy->tx_sym0_mux_clk || !ufs_qcom_phy->ref_clk_src) {
dev_err(ufs_qcom_phy->dev, "%s: null clock\n", __func__);
return;
}
/*
* Before entering hibernate, select xo as source of symbol
* clocks according to the UFS Host Controller Hardware
* Programming Guide's "Hibernate enter with power collapse".
*/
clk_set_parent(ufs_qcom_phy->rx_sym0_mux_clk, ufs_qcom_phy->ref_clk_src);
clk_set_parent(ufs_qcom_phy->rx_sym1_mux_clk, ufs_qcom_phy->ref_clk_src);
clk_set_parent(ufs_qcom_phy->tx_sym0_mux_clk, ufs_qcom_phy->ref_clk_src);
}
EXPORT_SYMBOL(ufs_qcom_phy_set_src_clk_h8_enter);
void ufs_qcom_phy_set_src_clk_h8_exit(struct phy *generic_phy)
{
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
if (!ufs_qcom_phy->rx_sym0_mux_clk ||
!ufs_qcom_phy->rx_sym1_mux_clk ||
!ufs_qcom_phy->tx_sym0_mux_clk ||
!ufs_qcom_phy->rx_sym0_phy_clk ||
!ufs_qcom_phy->rx_sym1_phy_clk ||
!ufs_qcom_phy->tx_sym0_phy_clk) {
dev_err(ufs_qcom_phy->dev, "%s: null clock\n", __func__);
return;
}
/*
* Refer to the UFS Host Controller Hardware Programming Guide's
* section "Hibernate exit from power collapse". Select phy clocks
* as source of the PHY symbol clocks.
*/
clk_set_parent(ufs_qcom_phy->rx_sym0_mux_clk, ufs_qcom_phy->rx_sym0_phy_clk);
clk_set_parent(ufs_qcom_phy->rx_sym1_mux_clk, ufs_qcom_phy->rx_sym1_phy_clk);
clk_set_parent(ufs_qcom_phy->tx_sym0_mux_clk, ufs_qcom_phy->tx_sym0_phy_clk);
}
EXPORT_SYMBOL(ufs_qcom_phy_set_src_clk_h8_exit);
static int ufs_qcom_phy_is_pcs_ready(struct ufs_qcom_phy *ufs_qcom_phy)
{
if (!ufs_qcom_phy->phy_spec_ops->is_physical_coding_sublayer_ready) {

View File

@ -1906,6 +1906,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
int err = 0;
struct phy *phy = host->generic_phy;
/*
* In case ufs_qcom_init() is not yet done, simply ignore.
@ -1919,6 +1920,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
case PRE_CHANGE:
if (on) {
err = ufs_qcom_set_bus_vote(hba, true);
ufs_qcom_phy_set_src_clk_h8_exit(phy);
} else {
if (!ufs_qcom_is_link_active(hba)) {
/* disable device ref_clk */
@ -1947,6 +1949,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
if (ufshcd_is_hs_mode(&hba->pwr_info))
ufs_qcom_dev_ref_clk_ctrl(host, true);
} else {
ufs_qcom_phy_set_src_clk_h8_enter(phy);
err = ufs_qcom_set_bus_vote(hba, false);
if (err)
return err;

View File

@ -11,6 +11,8 @@
void ufs_qcom_phy_ctrl_rx_linecfg(struct phy *generic_phy, bool ctrl);
void ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes);
void ufs_qcom_phy_dbg_register_dump(struct phy *generic_phy);
void ufs_qcom_phy_set_src_clk_h8_enter(struct phy *generic_phy);
void ufs_qcom_phy_set_src_clk_h8_exit(struct phy *generic_phy);
#endif /* PHY_QCOM_UFS_H_ */