Skip to content
Snippets Groups Projects
Commit 23ee9c0f authored by Gianfranco Mariotti's avatar Gianfranco Mariotti
Browse files

[DRIVER] clk: imx: pll1443x: add PLL SSCG support

In some situations, users might face EMI issues due to spikes around specific
frequencies: enabling Spread Spectrum Clocking is indicated to reduce the
electromagnetic peak around that specific frequency.

From the i.MX8MP SoC Reference Manual document, Section 5.1.8 "CCM Analog
Memory Map/Register Definition", the DRAM PLL, Audio PLL1, Audio PLL2 and
Video PLL1 have available the spread spectrum function.

The spread spectrum mode parameters of these PLLs can be calculated using
the formulas below:
* Modulation frequency: MF = Fin / p / mfr / (2^5) [Hz]
* Modulation rate: MR = mfr * mrr / m / (2^6) × 100 [%: percentage of the PLL output frequency]
* Where:
  * 0 <= mfr <= 255, 1 <= mrr <= 63, 0 <= mrr × mfr <= 512
  * Fin - PLL input clock frequency (typically, 24MHz = 24 * (10^6) Hz)
  * p = CCM_ANALOG_XXX_YYY_FDIV_CTL0[PLL_PRE_DIV] - reference frequency pre-divider value
  * m = CCM_ANALOG_XXX_YYY_FDIV_CTL0[PLL_MAIN_DIV] - PLL main divider value
  * mfr = CCM_ANALOG_XXX_YYY_SSCG_CTRL[PLL_MFREQ_CTL] - modulation frequency factor
  * mrr = CCM_ANALOG_XXX_YYY_SSCG_CTRL[PLL_MRAT_CTL] - modulation range factor

fsl,imx8mm-anatop optional properties:
 - anatop-<$1>,sscg-enable
   - type: boolean
   - <$1>: PLL clk name
   - description: enable SSCG
 - anatop-<$1>,mfr
   - type: u32
   - <$1>: PLL clk name
   - description: modulation frequency control value
 - anatop-<$1>,mrr
   - type: u32
   - <$1>: PLL clk name
   - description: modulation rate control value
 - anatop-<$1>,sel-pf
   - type: u32
   - <$1>: PLL clk name
   - description: modulation method control value

fsl,imx8mm-anatop dts example:
&anatop {
  anatop-video_pll1,sscg-enable;
  anatop-video_pll1,mfr = <12>;
  anatop-video_pll1,mrr = <14>;
  anatop-video_pll1,sel-pf = <2>;
};
parent 6714a8fa
No related branches found
No related tags found
1 merge request!158[DRIVER] clk: imx: pll1443x: add PLL SSCG support
......@@ -17,6 +17,7 @@
#define GNRL_CTL 0x0
#define FDIV_CTL0 0x4
#define FDIV_CTL1 0x8
#define SSCG_CTL 0xC
#define LOCK_STATUS BIT(31)
#define LOCK_SEL_MASK BIT(29)
#define CLKE_MASK BIT(11)
......@@ -264,6 +265,12 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
const struct imx_pll14xx_rate_table *rate;
u32 tmp, div_val;
u32 sscg_en, mfr, mrr, sel_pf, sscg_val;
u32 mfr_mrr, mf, mr_int, mr_frac;
struct device_node *np;
const char *clk_name;
char property[40];
u32 readbuf;
int ret;
rate = imx_get_pll_settings(pll, drate);
......@@ -300,6 +307,83 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
writel_relaxed(div_val, pll->base + FDIV_CTL0);
writel_relaxed(rate->kdiv << KDIV_SHIFT, pll->base + FDIV_CTL1);
/* Enable SSCG */
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop");
if (np) {
clk_name = clk_hw_get_name(hw);
sprintf(property, "anatop-%s,sscg-enable", clk_name);
if (of_property_read_bool(np, property)) {
sscg_en = 1;
mfr, mrr, sel_pf = -1;
/* 0 <= mfr <= 255, 1 <= mrr <= 63, 0 <= mrr * mfr <= 512 */
sprintf(property, "anatop-%s,mfr", clk_name);
if (!of_property_read_u32(np, property, &readbuf)) {
mfr = readbuf;
if (!(mfr >= 0 && mfr <= 255)) {
sscg_en = 0;
pr_err("%s: SSCG not enabled for pll clk %s: mfr %d is out of range\n",
__func__, clk_name, mfr);
}
} else {
sscg_en = 0;
pr_err("%s: SSCG not enabled for pll clk %s: unable to read mfr\n",
__func__, clk_name);
}
sprintf(property, "anatop-%s,mrr", clk_name);
if (!of_property_read_u32(np, property, &readbuf)) {
mrr = readbuf;
if (!(mrr >= 1 && mrr <= 63)) {
sscg_en = 0;
pr_err("%s: SSCG not enabled for pll clk %s: mrr %d is out of range\n",
__func__, clk_name, mrr);
}
mfr_mrr = mfr * mrr;
if (!(mfr_mrr >= 0 && mfr_mrr <= 512)) {
sscg_en = 0;
pr_err("%s: SSCG not enabled for pll clk %s: mfr * mrr %d is out of range\n",
__func__, clk_name, mfr_mrr);
}
} else {
sscg_en = 0;
pr_err("%s: SSCG not enabled for pll clk %s: unable to read mrr\n",
__func__, clk_name);
}
/* sel_pf >= 0 && sel_pf <= 2 */
sprintf(property, "anatop-%s,sel-pf", clk_name);
if (!of_property_read_u32(np, property, &readbuf)) {
sel_pf = readbuf;
if (!(sel_pf >= 0 && sel_pf <= 2)) {
sscg_en = 0;
pr_err("%s: SSCG not enabled for pll clk %s: sel-pf %d is out of range\n",
__func__, clk_name, sel_pf);
}
} else {
sscg_en = 0;
pr_err("%s: SSCG not enabled for pll clk %s: unable to read sel-pf\n",
__func__, clk_name);
}
if (sscg_en) {
sscg_val = readl_relaxed(pll->base + SSCG_CTL);
sscg_val |= 1 << 31; //SSCG_EN
sscg_val |= mfr << 12; //PLL_MFREQ_CTL
sscg_val |= mrr << 4; //PLL_MRAT_CTL
sscg_val |= sel_pf; //SEL_PF
writel_relaxed(sscg_val, pll->base + SSCG_CTL);
/* MF = Fin / p / mfr / (2^5) [Hz] */
mf = prate / (rate->pdiv * mfr * 32);
/* MR = mfr * mrr / m / (2^6) * 100 [%] */
mr_int = mfr_mrr * 1000 / (rate->mdiv * 64);
mr_frac = do_div(mr_int, 10);
pr_info("%s: SSCG enabled for pll clk %s: MF: %dHz, MR: %d.%d%%\n",
__func__, clk_name, mf, mr_int, mr_frac);
}
}
}
/*
* According to SPEC, t3 - t2 need to be greater than
* 1us and 1/FREF, respectively.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment