diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index 1303e2f5e0db893c85d24c0c952778f1f1c119bf..a97d4b4b8ed70b719518856f5b93e89863c4046a 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -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.