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

Commit 328e1a63 authored by Hai Li's avatar Hai Li Committed by Rob Clark
Browse files

drm/msm/dsi: Save/Restore PLL status across PHY reset



Reset DSI PHY silently changes its PLL registers to reset status,
which will make cached status in clock driver invalid and result
in wrong output rate of link clocks. The current restore mechanism
in DSI PLL does not cover all the cases. This change is to recover
PLL status after PHY reset to match HW status with cached status
in clock driver.

Signed-off-by: default avatarHai Li <hali@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent da882cd1
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -95,6 +95,8 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
void msm_dsi_pll_destroy(struct msm_dsi_pll *pll);
int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
	struct clk **byte_clk_provider, struct clk **pixel_clk_provider);
void msm_dsi_pll_save_state(struct msm_dsi_pll *pll);
int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll);
#else
static inline struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
			 enum msm_dsi_phy_type type, int id) {
@@ -108,6 +110,13 @@ static inline int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
{
	return -ENODEV;
}
static inline void msm_dsi_pll_save_state(struct msm_dsi_pll *pll)
{
}
static inline int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll)
{
	return 0;
}
#endif

/* dsi host */
+21 −0
Original line number Diff line number Diff line
@@ -611,12 +611,28 @@ int msm_dsi_manager_phy_enable(int id,
	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
	struct msm_dsi_phy *phy = msm_dsi->phy;
	int src_pll_id = IS_DUAL_DSI() ? DSI_CLOCK_MASTER : id;
	struct msm_dsi_pll *pll = msm_dsi_phy_get_pll(msm_dsi->phy);
	int ret;

	ret = msm_dsi_phy_enable(phy, src_pll_id, bit_rate, esc_rate);
	if (ret)
		return ret;

	/*
	 * Reset DSI PHY silently changes its PLL registers to reset status,
	 * which will confuse clock driver and result in wrong output rate of
	 * link clocks. Restore PLL status if its PLL is being used as clock
	 * source.
	 */
	if (!IS_DUAL_DSI() || (id == DSI_CLOCK_MASTER)) {
		ret = msm_dsi_pll_restore_state(pll);
		if (ret) {
			pr_err("%s: failed to restore pll state\n", __func__);
			msm_dsi_phy_disable(phy);
			return ret;
		}
	}

	msm_dsi->phy_enabled = true;
	msm_dsi_phy_get_clk_pre_post(phy, clk_pre, clk_post);

@@ -629,6 +645,11 @@ void msm_dsi_manager_phy_disable(int id)
	struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
	struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
	struct msm_dsi_phy *phy = msm_dsi->phy;
	struct msm_dsi_pll *pll = msm_dsi_phy_get_pll(msm_dsi->phy);

	/* Save PLL status if it is a clock source */
	if (!IS_DUAL_DSI() || (id == DSI_CLOCK_MASTER))
		msm_dsi_pll_save_state(pll);

	/* disable DSI phy
	 * In dual-dsi configuration, the phy should be disabled for the
+24 −18
Original line number Diff line number Diff line
@@ -72,31 +72,14 @@ long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw,
int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw)
{
	struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
	int ret;

	/*
	 * Certain PLLs need to update the same VCO rate and registers
	 * after resume in suspend/resume scenario.
	 */
	if (pll->restore_state) {
		ret = pll->restore_state(pll);
		if (ret)
			goto error;
	}

	ret = dsi_pll_enable(pll);

error:
	return ret;
	return dsi_pll_enable(pll);
}

void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw)
{
	struct msm_dsi_pll *pll = hw_clk_to_pll(hw);

	if (pll->save_state)
		pll->save_state(pll);

	dsi_pll_disable(pll);
}

@@ -134,6 +117,29 @@ void msm_dsi_pll_destroy(struct msm_dsi_pll *pll)
		pll->destroy(pll);
}

void msm_dsi_pll_save_state(struct msm_dsi_pll *pll)
{
	if (pll->save_state) {
		pll->save_state(pll);
		pll->state_saved = true;
	}
}

int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll)
{
	int ret;

	if (pll->restore_state && pll->state_saved) {
		ret = pll->restore_state(pll);
		if (ret)
			return ret;

		pll->state_saved = false;
	}

	return 0;
}

struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
			enum msm_dsi_phy_type type, int id)
{
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ struct msm_dsi_pll {

	struct clk_hw	clk_hw;
	bool		pll_on;
	bool		state_saved;

	unsigned long	min_rate;
	unsigned long	max_rate;
+13 −18
Original line number Diff line number Diff line
@@ -465,8 +465,6 @@ static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll)
	void __iomem *base = pll_28nm->mmio;
	int ret;

	if ((cached_state->vco_rate != 0) &&
		(cached_state->vco_rate == __clk_get_rate(pll->clk_hw.clk))) {
	ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
					cached_state->vco_rate, 0);
	if (ret) {
@@ -482,9 +480,6 @@ static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll)
	pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
			cached_state->byte_mux);

		cached_state->vco_rate = 0;
	}

	return 0;
}