Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 332ca84a authored by Stanley Chu's avatar Stanley Chu Committed by Greg Kroah-Hartman
Browse files

UPSTREAM: scsi: ufs-mediatek: Fix unbalanced clock on/off

MediaTek UFS clocks are separated to two parts and controlled by different
modules: ufs-mediatek and phy-ufs-mediatek.

If both Auto-Hibern8 and clk-gating feature are enabled, mphy power control
is not balanced thus unbalanced control also happens to the clocks probed
by phy-ufs-mediatek module.

Fix this issue by:

 - Promise usage of phy_power_on/off balanced

 - Remove phy_power_on/off control in suspend/resume vops since both can be
   handled in setup_clock vops only

Link: https://lore.kernel.org/r/20200601104646.15436-5-stanley.chu@mediatek.com


Reviewed-by: default avatarPeter Wang <peter.wang@mediatek.com>
Signed-off-by: default avatarStanley Chu <stanley.chu@mediatek.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>

Bug: 151050916
(cherry picked from commit 561e3a8726b2dd94ce75cad6c9cab211551f368a)
Change-Id: I9d304e895a07c5e672a6b29e9c8d23edaeaf8a08
Signed-off-by: default avatarStanley Chu <stanley.chu@mediatek.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent e957d1ef
Loading
Loading
Loading
Loading
+37 −23
Original line number Diff line number Diff line
@@ -205,6 +205,23 @@ int ufs_mtk_wait_link_state(struct ufs_hba *hba, u32 state,
	return -ETIMEDOUT;
}

static void ufs_mtk_mphy_power_on(struct ufs_hba *hba, bool on)
{
	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
	struct phy *mphy = host->mphy;

	if (!mphy)
		return;

	if (on && !host->mphy_powered_on)
		phy_power_on(mphy);
	else if (!on && host->mphy_powered_on)
		phy_power_off(mphy);
	else
		return;
	host->mphy_powered_on = on;
}

/**
 * ufs_mtk_setup_clocks - enables/disable clocks
 * @hba: host controller instance
@@ -218,6 +235,7 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
{
	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
	int ret = 0;
	bool clk_pwr_off = false;

	/*
	 * In case ufs_mtk_init() is not yet done, simply ignore.
@@ -228,25 +246,29 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
		return 0;

	if (!on && status == PRE_CHANGE) {
		if (!ufshcd_is_link_active(hba)) {
			ufs_mtk_setup_ref_clk(hba, on);
			ret = phy_power_off(host->mphy);
		} else {
		if (ufshcd_is_link_off(hba)) {
			clk_pwr_off = true;
		} else if (ufshcd_is_link_hibern8(hba) ||
			 (!ufshcd_can_hibern8_during_gating(hba) &&
			 ufshcd_is_auto_hibern8_enabled(hba))) {
			/*
			 * Gate ref-clk if link state is in Hibern8
			 * triggered by Auto-Hibern8.
			 * Gate ref-clk and poweroff mphy if link state is in
			 * OFF or Hibern8 by either Auto-Hibern8 or
			 * ufshcd_link_state_transition().
			 */
			if (!ufshcd_can_hibern8_during_gating(hba) &&
			    ufshcd_is_auto_hibern8_enabled(hba)) {
			ret = ufs_mtk_wait_link_state(hba,
						      VS_LINK_HIBERN8,
						      15);
			if (!ret)
					ufs_mtk_setup_ref_clk(hba, on);
				clk_pwr_off = true;
		}

		if (clk_pwr_off) {
			ufs_mtk_setup_ref_clk(hba, on);
			ufs_mtk_mphy_power_on(hba, on);
		}
	} else if (on && status == POST_CHANGE) {
		ret = phy_power_on(host->mphy);
		ufs_mtk_mphy_power_on(hba, on);
		ufs_mtk_setup_ref_clk(hba, on);
	}

@@ -538,7 +560,6 @@ static void ufs_mtk_vreg_set_lpm(struct ufs_hba *hba, bool lpm)
static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
	int err;
	struct ufs_mtk_host *host = ufshcd_get_variant(hba);

	if (ufshcd_is_link_hibern8(hba)) {
		err = ufs_mtk_link_set_lpm(hba);
@@ -559,20 +580,13 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
		ufs_mtk_vreg_set_lpm(hba, true);
	}

	if (!ufshcd_is_link_active(hba))
		phy_power_off(host->mphy);

	return 0;
}

static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
	int err;

	if (!ufshcd_is_link_active(hba))
		phy_power_on(host->mphy);

	if (ufshcd_is_link_hibern8(hba)) {
		ufs_mtk_vreg_set_lpm(hba, false);
		err = ufs_mtk_link_set_hpm(hba);
+1 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ enum {
struct ufs_mtk_host {
	struct ufs_hba *hba;
	struct phy *mphy;
	bool mphy_powered_on;
	bool unipro_lpm;
	bool ref_clk_enabled;
	u16 ref_clk_ungating_wait_us;