273 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/kernel.h>3#include <linux/clk.h>4#include <linux/io.h>5#include <linux/errno.h>6#include <linux/delay.h>7#include <linux/slab.h>8#include <linux/err.h>9 10#include <asm/div64.h>11 12#include "clk.h"13 14#define to_clk_pllv2(clk) (container_of(clk, struct clk_pllv2, clk))15 16/* PLL Register Offsets */17#define MXC_PLL_DP_CTL 0x0018#define MXC_PLL_DP_CONFIG 0x0419#define MXC_PLL_DP_OP 0x0820#define MXC_PLL_DP_MFD 0x0C21#define MXC_PLL_DP_MFN 0x1022#define MXC_PLL_DP_MFNMINUS 0x1423#define MXC_PLL_DP_MFNPLUS 0x1824#define MXC_PLL_DP_HFS_OP 0x1C25#define MXC_PLL_DP_HFS_MFD 0x2026#define MXC_PLL_DP_HFS_MFN 0x2427#define MXC_PLL_DP_MFN_TOGC 0x2828#define MXC_PLL_DP_DESTAT 0x2c29 30/* PLL Register Bit definitions */31#define MXC_PLL_DP_CTL_MUL_CTRL 0x200032#define MXC_PLL_DP_CTL_DPDCK0_2_EN 0x100033#define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET 1234#define MXC_PLL_DP_CTL_ADE 0x80035#define MXC_PLL_DP_CTL_REF_CLK_DIV 0x40036#define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK (3 << 8)37#define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET 838#define MXC_PLL_DP_CTL_HFSM 0x8039#define MXC_PLL_DP_CTL_PRE 0x4040#define MXC_PLL_DP_CTL_UPEN 0x2041#define MXC_PLL_DP_CTL_RST 0x1042#define MXC_PLL_DP_CTL_RCP 0x843#define MXC_PLL_DP_CTL_PLM 0x444#define MXC_PLL_DP_CTL_BRM0 0x245#define MXC_PLL_DP_CTL_LRF 0x146 47#define MXC_PLL_DP_CONFIG_BIST 0x848#define MXC_PLL_DP_CONFIG_SJC_CE 0x449#define MXC_PLL_DP_CONFIG_AREN 0x250#define MXC_PLL_DP_CONFIG_LDREQ 0x151 52#define MXC_PLL_DP_OP_MFI_OFFSET 453#define MXC_PLL_DP_OP_MFI_MASK (0xF << 4)54#define MXC_PLL_DP_OP_PDF_OFFSET 055#define MXC_PLL_DP_OP_PDF_MASK 0xF56 57#define MXC_PLL_DP_MFD_OFFSET 058#define MXC_PLL_DP_MFD_MASK 0x07FFFFFF59 60#define MXC_PLL_DP_MFN_OFFSET 0x061#define MXC_PLL_DP_MFN_MASK 0x07FFFFFF62 63#define MXC_PLL_DP_MFN_TOGC_TOG_DIS (1 << 17)64#define MXC_PLL_DP_MFN_TOGC_TOG_EN (1 << 16)65#define MXC_PLL_DP_MFN_TOGC_CNT_OFFSET 0x066#define MXC_PLL_DP_MFN_TOGC_CNT_MASK 0xFFFF67 68#define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31)69#define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF70 71#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */72 73struct clk_pllv2 {74 struct clk_hw hw;75 void __iomem *base;76};77 78static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate,79 u32 dp_ctl, u32 dp_op, u32 dp_mfd, u32 dp_mfn)80{81 long mfi, mfn, mfd, pdf, ref_clk;82 unsigned long dbl;83 u64 temp;84 85 dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN;86 87 pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK;88 mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET;89 mfi = (mfi <= 5) ? 5 : mfi;90 mfd = dp_mfd & MXC_PLL_DP_MFD_MASK;91 mfn = dp_mfn & MXC_PLL_DP_MFN_MASK;92 mfn = sign_extend32(mfn, 26);93 94 ref_clk = 2 * parent_rate;95 if (dbl != 0)96 ref_clk *= 2;97 98 ref_clk /= (pdf + 1);99 temp = (u64) ref_clk * abs(mfn);100 do_div(temp, mfd + 1);101 if (mfn < 0)102 temp = (ref_clk * mfi) - temp;103 else104 temp = (ref_clk * mfi) + temp;105 106 return temp;107}108 109static unsigned long clk_pllv2_recalc_rate(struct clk_hw *hw,110 unsigned long parent_rate)111{112 u32 dp_op, dp_mfd, dp_mfn, dp_ctl;113 void __iomem *pllbase;114 struct clk_pllv2 *pll = to_clk_pllv2(hw);115 116 pllbase = pll->base;117 118 dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);119 dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP);120 dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD);121 dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN);122 123 return __clk_pllv2_recalc_rate(parent_rate, dp_ctl, dp_op, dp_mfd, dp_mfn);124}125 126static int __clk_pllv2_set_rate(unsigned long rate, unsigned long parent_rate,127 u32 *dp_op, u32 *dp_mfd, u32 *dp_mfn)128{129 u32 reg;130 long mfi, pdf, mfn, mfd = 999999;131 u64 temp64;132 unsigned long quad_parent_rate;133 134 quad_parent_rate = 4 * parent_rate;135 pdf = mfi = -1;136 while (++pdf < 16 && mfi < 5)137 mfi = rate * (pdf+1) / quad_parent_rate;138 if (mfi > 15)139 return -EINVAL;140 pdf--;141 142 temp64 = rate * (pdf + 1) - quad_parent_rate * mfi;143 do_div(temp64, quad_parent_rate / 1000000);144 mfn = (long)temp64;145 146 reg = mfi << 4 | pdf;147 148 *dp_op = reg;149 *dp_mfd = mfd;150 *dp_mfn = mfn;151 152 return 0;153}154 155static int clk_pllv2_set_rate(struct clk_hw *hw, unsigned long rate,156 unsigned long parent_rate)157{158 struct clk_pllv2 *pll = to_clk_pllv2(hw);159 void __iomem *pllbase;160 u32 dp_ctl, dp_op, dp_mfd, dp_mfn;161 int ret;162 163 pllbase = pll->base;164 165 166 ret = __clk_pllv2_set_rate(rate, parent_rate, &dp_op, &dp_mfd, &dp_mfn);167 if (ret)168 return ret;169 170 dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);171 /* use dpdck0_2 */172 __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL);173 174 __raw_writel(dp_op, pllbase + MXC_PLL_DP_OP);175 __raw_writel(dp_mfd, pllbase + MXC_PLL_DP_MFD);176 __raw_writel(dp_mfn, pllbase + MXC_PLL_DP_MFN);177 178 return 0;179}180 181static long clk_pllv2_round_rate(struct clk_hw *hw, unsigned long rate,182 unsigned long *prate)183{184 u32 dp_op, dp_mfd, dp_mfn;185 int ret;186 187 ret = __clk_pllv2_set_rate(rate, *prate, &dp_op, &dp_mfd, &dp_mfn);188 if (ret)189 return ret;190 191 return __clk_pllv2_recalc_rate(*prate, MXC_PLL_DP_CTL_DPDCK0_2_EN,192 dp_op, dp_mfd, dp_mfn);193}194 195static int clk_pllv2_prepare(struct clk_hw *hw)196{197 struct clk_pllv2 *pll = to_clk_pllv2(hw);198 u32 reg;199 void __iomem *pllbase;200 int i = 0;201 202 pllbase = pll->base;203 reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN;204 __raw_writel(reg, pllbase + MXC_PLL_DP_CTL);205 206 /* Wait for lock */207 do {208 reg = __raw_readl(pllbase + MXC_PLL_DP_CTL);209 if (reg & MXC_PLL_DP_CTL_LRF)210 break;211 212 udelay(1);213 } while (++i < MAX_DPLL_WAIT_TRIES);214 215 if (i == MAX_DPLL_WAIT_TRIES) {216 pr_err("MX5: pll locking failed\n");217 return -EINVAL;218 }219 220 return 0;221}222 223static void clk_pllv2_unprepare(struct clk_hw *hw)224{225 struct clk_pllv2 *pll = to_clk_pllv2(hw);226 u32 reg;227 void __iomem *pllbase;228 229 pllbase = pll->base;230 reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN;231 __raw_writel(reg, pllbase + MXC_PLL_DP_CTL);232}233 234static const struct clk_ops clk_pllv2_ops = {235 .prepare = clk_pllv2_prepare,236 .unprepare = clk_pllv2_unprepare,237 .recalc_rate = clk_pllv2_recalc_rate,238 .round_rate = clk_pllv2_round_rate,239 .set_rate = clk_pllv2_set_rate,240};241 242struct clk_hw *imx_clk_hw_pllv2(const char *name, const char *parent,243 void __iomem *base)244{245 struct clk_pllv2 *pll;246 struct clk_hw *hw;247 struct clk_init_data init;248 int ret;249 250 pll = kzalloc(sizeof(*pll), GFP_KERNEL);251 if (!pll)252 return ERR_PTR(-ENOMEM);253 254 pll->base = base;255 256 init.name = name;257 init.ops = &clk_pllv2_ops;258 init.flags = 0;259 init.parent_names = &parent;260 init.num_parents = 1;261 262 pll->hw.init = &init;263 hw = &pll->hw;264 265 ret = clk_hw_register(NULL, hw);266 if (ret) {267 kfree(pll);268 return ERR_PTR(ret);269 }270 271 return hw;272}273