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: Hai Li <hali@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com>
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
@@ -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;
|
||||
|
@@ -465,26 +465,21 @@ 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) {
|
||||
dev_err(&pll_28nm->pdev->dev,
|
||||
"restore vco rate failed. ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
|
||||
cached_state->postdiv3);
|
||||
pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
|
||||
cached_state->postdiv1);
|
||||
pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
|
||||
cached_state->byte_mux);
|
||||
|
||||
cached_state->vco_rate = 0;
|
||||
ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
|
||||
cached_state->vco_rate, 0);
|
||||
if (ret) {
|
||||
dev_err(&pll_28nm->pdev->dev,
|
||||
"restore vco rate failed. ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
|
||||
cached_state->postdiv3);
|
||||
pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
|
||||
cached_state->postdiv1);
|
||||
pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
|
||||
cached_state->byte_mux);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user