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:
parent
a0d6e689a1
commit
471dae0840
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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_ */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user