Skip to content

Commit ff42796

Browse files
MrVanabelvesa
authored andcommitted
clk: imx: fracn-gppll: fix pll power up
To i.MX93 which features dual Cortex-A55 cores and DSU, when using writel_relaxed to write value to PLL registers, the value might be buffered. To make sure the value has been written into the hardware, using readl to read back the register could achieve the goal. current PLL power up flow can be simplified as below: 1. writel_relaxed to set the PLL POWERUP bit; 2. readl_poll_timeout to check the PLL lock bit: a). timeout = ktime_add_us(ktime_get(), timeout_us); b). readl the pll the lock reg; c). check if the pll lock bit ready d). check if timeout But in some corner cases, both the write in step 1 and read in step 2 will be blocked by other bus transaction in the SoC for a long time, saying the value into real hardware is just before step b). That means the timeout counting has begins for quite sometime since step a), but value still not written into real hardware until bus released just at a point before step b). Then there maybe chances that the pll lock bit is not ready when readl done but the timeout happens. readl_poll_timeout will err return due to timeout. To avoid such unexpected failure, read back the reg to make sure the write has been done in HW reg. So use readl after writel_relaxed to fix the issue. Since we are here, to avoid udelay to run before writel_relaxed, use readl before udelay. Fixes: 1b26cb8 ("clk: imx: support fracn gppll") Co-developed-by: Jacky Bai <[email protected]> Signed-off-by: Jacky Bai <[email protected]> Signed-off-by: Peng Fan <[email protected]> Reviewed-by: Abel Vesa <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Abel Vesa <[email protected]>
1 parent 557be50 commit ff42796

File tree

1 file changed

+4
-0
lines changed

1 file changed

+4
-0
lines changed

drivers/clk/imx/clk-fracn-gppll.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,11 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
254254
pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv |
255255
FIELD_PREP(PLL_MFI_MASK, rate->mfi);
256256
writel_relaxed(pll_div, pll->base + PLL_DIV);
257+
readl(pll->base + PLL_DIV);
257258
if (pll->flags & CLK_FRACN_GPPLL_FRACN) {
258259
writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR);
259260
writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR);
261+
readl(pll->base + PLL_NUMERATOR);
260262
}
261263

262264
/* Wait for 5us according to fracn mode pll doc */
@@ -265,6 +267,7 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
265267
/* Enable Powerup */
266268
tmp |= POWERUP_MASK;
267269
writel_relaxed(tmp, pll->base + PLL_CTRL);
270+
readl(pll->base + PLL_CTRL);
268271

269272
/* Wait Lock */
270273
ret = clk_fracn_gppll_wait_lock(pll);
@@ -302,6 +305,7 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw)
302305

303306
val |= POWERUP_MASK;
304307
writel_relaxed(val, pll->base + PLL_CTRL);
308+
readl(pll->base + PLL_CTRL);
305309

306310
ret = clk_fracn_gppll_wait_lock(pll);
307311
if (ret)

0 commit comments

Comments
 (0)