clk-pllv2.c (6506B)
1// SPDX-License-Identifier: GPL-2.0 2#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 0x00 18#define MXC_PLL_DP_CONFIG 0x04 19#define MXC_PLL_DP_OP 0x08 20#define MXC_PLL_DP_MFD 0x0C 21#define MXC_PLL_DP_MFN 0x10 22#define MXC_PLL_DP_MFNMINUS 0x14 23#define MXC_PLL_DP_MFNPLUS 0x18 24#define MXC_PLL_DP_HFS_OP 0x1C 25#define MXC_PLL_DP_HFS_MFD 0x20 26#define MXC_PLL_DP_HFS_MFN 0x24 27#define MXC_PLL_DP_MFN_TOGC 0x28 28#define MXC_PLL_DP_DESTAT 0x2c 29 30/* PLL Register Bit definitions */ 31#define MXC_PLL_DP_CTL_MUL_CTRL 0x2000 32#define MXC_PLL_DP_CTL_DPDCK0_2_EN 0x1000 33#define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET 12 34#define MXC_PLL_DP_CTL_ADE 0x800 35#define MXC_PLL_DP_CTL_REF_CLK_DIV 0x400 36#define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK (3 << 8) 37#define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET 8 38#define MXC_PLL_DP_CTL_HFSM 0x80 39#define MXC_PLL_DP_CTL_PRE 0x40 40#define MXC_PLL_DP_CTL_UPEN 0x20 41#define MXC_PLL_DP_CTL_RST 0x10 42#define MXC_PLL_DP_CTL_RCP 0x8 43#define MXC_PLL_DP_CTL_PLM 0x4 44#define MXC_PLL_DP_CTL_BRM0 0x2 45#define MXC_PLL_DP_CTL_LRF 0x1 46 47#define MXC_PLL_DP_CONFIG_BIST 0x8 48#define MXC_PLL_DP_CONFIG_SJC_CE 0x4 49#define MXC_PLL_DP_CONFIG_AREN 0x2 50#define MXC_PLL_DP_CONFIG_LDREQ 0x1 51 52#define MXC_PLL_DP_OP_MFI_OFFSET 4 53#define MXC_PLL_DP_OP_MFI_MASK (0xF << 4) 54#define MXC_PLL_DP_OP_PDF_OFFSET 0 55#define MXC_PLL_DP_OP_PDF_MASK 0xF 56 57#define MXC_PLL_DP_MFD_OFFSET 0 58#define MXC_PLL_DP_MFD_MASK 0x07FFFFFF 59 60#define MXC_PLL_DP_MFN_OFFSET 0x0 61#define MXC_PLL_DP_MFN_MASK 0x07FFFFFF 62 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 0x0 66#define MXC_PLL_DP_MFN_TOGC_CNT_MASK 0xFFFF 67 68#define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31) 69#define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF 70 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 else 104 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}