Message ID | 20241014-imx-clk-v1-v1-1-ee75876d3102@nxp.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | clk: imx: scu and fracn pll update | expand |
On Mon, Oct 14, 2024 at 6:03 AM Peng Fan (OSS) <peng.fan@oss.nxp.com> wrote:
> +/* e10858 -LPCG clock gating register synchronization errata */
Please share the link to the errata doc that contains this e10858.
> Subject: Re: [PATCH 1/4] clk: imx: lpcg-scu: SW workaround for errata > (e10858) > > On Mon, Oct 14, 2024 at 6:03 AM Peng Fan (OSS) > <peng.fan@oss.nxp.com> wrote: > > > +/* e10858 -LPCG clock gating register synchronization errata */ > > Please share the link to the errata doc that contains this e10858. https://www.nxp.com.cn/docs/en/errata/IMX8_1N94W.pdf Thanks, Peng.
Quoting Peng Fan (OSS) (2024-10-14 02:11:22) > diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c > index dd5abd09f3e206a5073767561b517d5b3320b28c..2cffec0c42dccc256e8dc5e9181952e250870a76 100644 > --- a/drivers/clk/imx/clk-lpcg-scu.c > +++ b/drivers/clk/imx/clk-lpcg-scu.c > @@ -6,6 +6,7 @@ > > #include <linux/bits.h> > #include <linux/clk-provider.h> > +#include <linux/delay.h> > #include <linux/err.h> > #include <linux/io.h> > #include <linux/slab.h> > @@ -41,6 +42,31 @@ struct clk_lpcg_scu { > > #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw) > > +/* e10858 -LPCG clock gating register synchronization errata */ > +static void lpcg_e10858_writel(ulong rate, void __iomem *reg, u32 val) s/ulong/unsigned long/ > +{ > + u32 reg1; > + > + writel(val, reg); > + > + if (rate >= 24000000 || rate == 0) { Can be '24 * HZ_PER_MHZ' > + /* > + * The time taken to access the LPCG registers from the AP core > + * through the interconnect is longer than the minimum delay > + * of 4 clock cycles required by the errata. > + * Adding a readl will provide sufficient delay to prevent > + * back-to-back writes. > + */ > + reg1 = readl(reg); > + } else { > + /* > + * For clocks running below 24MHz, wait a minimum of > + * 4 clock cycles. > + */ > + ndelay(4 * (DIV_ROUND_UP(1000000000, rate))); Can be '1000 * HZ_PER_MHZ'
diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c index dd5abd09f3e206a5073767561b517d5b3320b28c..2cffec0c42dccc256e8dc5e9181952e250870a76 100644 --- a/drivers/clk/imx/clk-lpcg-scu.c +++ b/drivers/clk/imx/clk-lpcg-scu.c @@ -6,6 +6,7 @@ #include <linux/bits.h> #include <linux/clk-provider.h> +#include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> #include <linux/slab.h> @@ -41,6 +42,31 @@ struct clk_lpcg_scu { #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw) +/* e10858 -LPCG clock gating register synchronization errata */ +static void lpcg_e10858_writel(ulong rate, void __iomem *reg, u32 val) +{ + u32 reg1; + + writel(val, reg); + + if (rate >= 24000000 || rate == 0) { + /* + * The time taken to access the LPCG registers from the AP core + * through the interconnect is longer than the minimum delay + * of 4 clock cycles required by the errata. + * Adding a readl will provide sufficient delay to prevent + * back-to-back writes. + */ + reg1 = readl(reg); + } else { + /* + * For clocks running below 24MHz, wait a minimum of + * 4 clock cycles. + */ + ndelay(4 * (DIV_ROUND_UP(1000000000, rate))); + } +} + static int clk_lpcg_scu_enable(struct clk_hw *hw) { struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw); @@ -57,7 +83,8 @@ static int clk_lpcg_scu_enable(struct clk_hw *hw) val |= CLK_GATE_SCU_LPCG_HW_SEL; reg |= val << clk->bit_idx; - writel(reg, clk->reg); + + lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg); spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); @@ -74,7 +101,7 @@ static void clk_lpcg_scu_disable(struct clk_hw *hw) reg = readl_relaxed(clk->reg); reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx); - writel(reg, clk->reg); + lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg); spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); } @@ -149,9 +176,8 @@ static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev) * FIXME: Sometimes writes don't work unless the CPU issues * them twice */ - - writel(clk->state, clk->reg); writel(clk->state, clk->reg); + lpcg_e10858_writel(0, clk->reg, clk->state); dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state); return 0;