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:
Hai Li
2015-07-03 10:09:46 -04:00
committed by Rob Clark
parent da882cd1ee
commit 328e1a633c
5 changed files with 68 additions and 36 deletions

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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;
}