1/* 2 * Copyright (C) 2014 Google, Inc. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 */ 8 9#include <linux/clk-provider.h> 10#include <linux/io.h> 11#include <linux/kernel.h> 12#include <linux/slab.h> 13 14#include "clk.h" 15 16#define PLL_STATUS 0x0 17#define PLL_STATUS_LOCK BIT(0) 18 19#define PLL_CTRL1 0x4 20#define PLL_CTRL1_REFDIV_SHIFT 0 21#define PLL_CTRL1_REFDIV_MASK 0x3f 22#define PLL_CTRL1_FBDIV_SHIFT 6 23#define PLL_CTRL1_FBDIV_MASK 0xfff 24#define PLL_INT_CTRL1_POSTDIV1_SHIFT 18 25#define PLL_INT_CTRL1_POSTDIV1_MASK 0x7 26#define PLL_INT_CTRL1_POSTDIV2_SHIFT 21 27#define PLL_INT_CTRL1_POSTDIV2_MASK 0x7 28#define PLL_INT_CTRL1_PD BIT(24) 29#define PLL_INT_CTRL1_DSMPD BIT(25) 30#define PLL_INT_CTRL1_FOUTPOSTDIVPD BIT(26) 31#define PLL_INT_CTRL1_FOUTVCOPD BIT(27) 32 33#define PLL_CTRL2 0x8 34#define PLL_FRAC_CTRL2_FRAC_SHIFT 0 35#define PLL_FRAC_CTRL2_FRAC_MASK 0xffffff 36#define PLL_FRAC_CTRL2_POSTDIV1_SHIFT 24 37#define PLL_FRAC_CTRL2_POSTDIV1_MASK 0x7 38#define PLL_FRAC_CTRL2_POSTDIV2_SHIFT 27 39#define PLL_FRAC_CTRL2_POSTDIV2_MASK 0x7 40#define PLL_INT_CTRL2_BYPASS BIT(28) 41 42#define PLL_CTRL3 0xc 43#define PLL_FRAC_CTRL3_PD BIT(0) 44#define PLL_FRAC_CTRL3_DACPD BIT(1) 45#define PLL_FRAC_CTRL3_DSMPD BIT(2) 46#define PLL_FRAC_CTRL3_FOUTPOSTDIVPD BIT(3) 47#define PLL_FRAC_CTRL3_FOUT4PHASEPD BIT(4) 48#define PLL_FRAC_CTRL3_FOUTVCOPD BIT(5) 49 50#define PLL_CTRL4 0x10 51#define PLL_FRAC_CTRL4_BYPASS BIT(28) 52 53struct pistachio_clk_pll { 54 struct clk_hw hw; 55 void __iomem *base; 56 struct pistachio_pll_rate_table *rates; 57 unsigned int nr_rates; 58}; 59 60static inline u32 pll_readl(struct pistachio_clk_pll *pll, u32 reg) 61{ 62 return readl(pll->base + reg); 63} 64 65static inline void pll_writel(struct pistachio_clk_pll *pll, u32 val, u32 reg) 66{ 67 writel(val, pll->base + reg); 68} 69 70static inline u32 do_div_round_closest(u64 dividend, u32 divisor) 71{ 72 dividend += divisor / 2; 73 do_div(dividend, divisor); 74 75 return dividend; 76} 77 78static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw) 79{ 80 return container_of(hw, struct pistachio_clk_pll, hw); 81} 82 83static struct pistachio_pll_rate_table * 84pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref, 85 unsigned long fout) 86{ 87 unsigned int i; 88 89 for (i = 0; i < pll->nr_rates; i++) { 90 if (pll->rates[i].fref == fref && pll->rates[i].fout == fout) 91 return &pll->rates[i]; 92 } 93 94 return NULL; 95} 96 97static long pll_round_rate(struct clk_hw *hw, unsigned long rate, 98 unsigned long *parent_rate) 99{ 100 struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 101 unsigned int i; 102 103 for (i = 0; i < pll->nr_rates; i++) { 104 if (i > 0 && pll->rates[i].fref == *parent_rate && 105 pll->rates[i].fout <= rate) 106 return pll->rates[i - 1].fout; 107 } 108 109 return pll->rates[0].fout; 110} 111 112static int pll_gf40lp_frac_enable(struct clk_hw *hw) 113{ 114 struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 115 u32 val; 116 117 val = pll_readl(pll, PLL_CTRL3); 118 val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD | 119 PLL_FRAC_CTRL3_FOUT4PHASEPD | PLL_FRAC_CTRL3_FOUTVCOPD); 120 pll_writel(pll, val, PLL_CTRL3); 121 122 val = pll_readl(pll, PLL_CTRL4); 123 val &= ~PLL_FRAC_CTRL4_BYPASS; 124 pll_writel(pll, val, PLL_CTRL4); 125 126 return 0; 127} 128 129static void pll_gf40lp_frac_disable(struct clk_hw *hw) 130{ 131 struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 132 u32 val; 133 134 val = pll_readl(pll, PLL_CTRL3); 135 val |= PLL_FRAC_CTRL3_PD; 136 pll_writel(pll, val, PLL_CTRL3); 137} 138 139static int pll_gf40lp_frac_is_enabled(struct clk_hw *hw) 140{ 141 struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 142 143 return !(pll_readl(pll, PLL_CTRL3) & PLL_FRAC_CTRL3_PD); 144} 145 146static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate, 147 unsigned long parent_rate) 148{ 149 struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 150 struct pistachio_pll_rate_table *params; 151 bool was_enabled; 152 u32 val; 153 154 params = pll_get_params(pll, parent_rate, rate); 155 if (!params) 156 return -EINVAL; 157 158 was_enabled = pll_gf40lp_frac_is_enabled(hw); 159 if (!was_enabled) 160 pll_gf40lp_frac_enable(hw); 161 162 val = pll_readl(pll, PLL_CTRL1); 163 val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) | 164 (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT)); 165 val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) | 166 (params->fbdiv << PLL_CTRL1_FBDIV_SHIFT); 167 pll_writel(pll, val, PLL_CTRL1); 168 169 val = pll_readl(pll, PLL_CTRL2); 170 val &= ~((PLL_FRAC_CTRL2_FRAC_MASK << PLL_FRAC_CTRL2_FRAC_SHIFT) | 171 (PLL_FRAC_CTRL2_POSTDIV1_MASK << 172 PLL_FRAC_CTRL2_POSTDIV1_SHIFT) | 173 (PLL_FRAC_CTRL2_POSTDIV2_MASK << 174 PLL_FRAC_CTRL2_POSTDIV2_SHIFT)); 175 val |= (params->frac << PLL_FRAC_CTRL2_FRAC_SHIFT) | 176 (params->postdiv1 << PLL_FRAC_CTRL2_POSTDIV1_SHIFT) | 177 (params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT); 178 pll_writel(pll, val, PLL_CTRL2); 179 180 while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK)) 181 cpu_relax(); 182 183 if (!was_enabled) 184 pll_gf40lp_frac_disable(hw); 185 186 return 0; 187} 188 189static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw, 190 unsigned long parent_rate) 191{ 192 struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 193 u32 val, prediv, fbdiv, frac, postdiv1, postdiv2; 194 u64 rate = parent_rate; 195 196 val = pll_readl(pll, PLL_CTRL1); 197 prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK; 198 fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK; 199 200 val = pll_readl(pll, PLL_CTRL2); 201 postdiv1 = (val >> PLL_FRAC_CTRL2_POSTDIV1_SHIFT) & 202 PLL_FRAC_CTRL2_POSTDIV1_MASK; 203 postdiv2 = (val >> PLL_FRAC_CTRL2_POSTDIV2_SHIFT) & 204 PLL_FRAC_CTRL2_POSTDIV2_MASK; 205 frac = (val >> PLL_FRAC_CTRL2_FRAC_SHIFT) & PLL_FRAC_CTRL2_FRAC_MASK; 206 207 rate *= (fbdiv << 24) + frac; 208 rate = do_div_round_closest(rate, (prediv * postdiv1 * postdiv2) << 24); 209 210 return rate; 211} 212 213static struct clk_ops pll_gf40lp_frac_ops = { 214 .enable = pll_gf40lp_frac_enable, 215 .disable = pll_gf40lp_frac_disable, 216 .is_enabled = pll_gf40lp_frac_is_enabled, 217 .recalc_rate = pll_gf40lp_frac_recalc_rate, 218 .round_rate = pll_round_rate, 219 .set_rate = pll_gf40lp_frac_set_rate, 220}; 221 222static struct clk_ops pll_gf40lp_frac_fixed_ops = { 223 .enable = pll_gf40lp_frac_enable, 224 .disable = pll_gf40lp_frac_disable, 225 .is_enabled = pll_gf40lp_frac_is_enabled, 226 .recalc_rate = pll_gf40lp_frac_recalc_rate, 227}; 228 229static int pll_gf40lp_laint_enable(struct clk_hw *hw) 230{ 231 struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 232 u32 val; 233 234 val = pll_readl(pll, PLL_CTRL1); 235 val &= ~(PLL_INT_CTRL1_PD | 236 PLL_INT_CTRL1_FOUTPOSTDIVPD | PLL_INT_CTRL1_FOUTVCOPD); 237 pll_writel(pll, val, PLL_CTRL1); 238 239 val = pll_readl(pll, PLL_CTRL2); 240 val &= ~PLL_INT_CTRL2_BYPASS; 241 pll_writel(pll, val, PLL_CTRL2); 242 243 return 0; 244} 245 246static void pll_gf40lp_laint_disable(struct clk_hw *hw) 247{ 248 struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 249 u32 val; 250 251 val = pll_readl(pll, PLL_CTRL1); 252 val |= PLL_INT_CTRL1_PD; 253 pll_writel(pll, val, PLL_CTRL1); 254} 255 256static int pll_gf40lp_laint_is_enabled(struct clk_hw *hw) 257{ 258 struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 259 260 return !(pll_readl(pll, PLL_CTRL1) & PLL_INT_CTRL1_PD); 261} 262 263static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate, 264 unsigned long parent_rate) 265{ 266 struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 267 struct pistachio_pll_rate_table *params; 268 bool was_enabled; 269 u32 val; 270 271 params = pll_get_params(pll, parent_rate, rate); 272 if (!params) 273 return -EINVAL; 274 275 was_enabled = pll_gf40lp_laint_is_enabled(hw); 276 if (!was_enabled) 277 pll_gf40lp_laint_enable(hw); 278 279 val = pll_readl(pll, PLL_CTRL1); 280 val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) | 281 (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT) | 282 (PLL_INT_CTRL1_POSTDIV1_MASK << PLL_INT_CTRL1_POSTDIV1_SHIFT) | 283 (PLL_INT_CTRL1_POSTDIV2_MASK << PLL_INT_CTRL1_POSTDIV2_SHIFT)); 284 val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) | 285 (params->fbdiv << PLL_CTRL1_FBDIV_SHIFT) | 286 (params->postdiv1 << PLL_INT_CTRL1_POSTDIV1_SHIFT) | 287 (params->postdiv2 << PLL_INT_CTRL1_POSTDIV2_SHIFT); 288 pll_writel(pll, val, PLL_CTRL1); 289 290 while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK)) 291 cpu_relax(); 292 293 if (!was_enabled) 294 pll_gf40lp_laint_disable(hw); 295 296 return 0; 297} 298 299static unsigned long pll_gf40lp_laint_recalc_rate(struct clk_hw *hw, 300 unsigned long parent_rate) 301{ 302 struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 303 u32 val, prediv, fbdiv, postdiv1, postdiv2; 304 u64 rate = parent_rate; 305 306 val = pll_readl(pll, PLL_CTRL1); 307 prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK; 308 fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK; 309 postdiv1 = (val >> PLL_INT_CTRL1_POSTDIV1_SHIFT) & 310 PLL_INT_CTRL1_POSTDIV1_MASK; 311 postdiv2 = (val >> PLL_INT_CTRL1_POSTDIV2_SHIFT) & 312 PLL_INT_CTRL1_POSTDIV2_MASK; 313 314 rate *= fbdiv; 315 rate = do_div_round_closest(rate, prediv * postdiv1 * postdiv2); 316 317 return rate; 318} 319 320static struct clk_ops pll_gf40lp_laint_ops = { 321 .enable = pll_gf40lp_laint_enable, 322 .disable = pll_gf40lp_laint_disable, 323 .is_enabled = pll_gf40lp_laint_is_enabled, 324 .recalc_rate = pll_gf40lp_laint_recalc_rate, 325 .round_rate = pll_round_rate, 326 .set_rate = pll_gf40lp_laint_set_rate, 327}; 328 329static struct clk_ops pll_gf40lp_laint_fixed_ops = { 330 .enable = pll_gf40lp_laint_enable, 331 .disable = pll_gf40lp_laint_disable, 332 .is_enabled = pll_gf40lp_laint_is_enabled, 333 .recalc_rate = pll_gf40lp_laint_recalc_rate, 334}; 335 336static struct clk *pll_register(const char *name, const char *parent_name, 337 unsigned long flags, void __iomem *base, 338 enum pistachio_pll_type type, 339 struct pistachio_pll_rate_table *rates, 340 unsigned int nr_rates) 341{ 342 struct pistachio_clk_pll *pll; 343 struct clk_init_data init; 344 struct clk *clk; 345 346 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 347 if (!pll) 348 return ERR_PTR(-ENOMEM); 349 350 init.name = name; 351 init.flags = flags | CLK_GET_RATE_NOCACHE; 352 init.parent_names = &parent_name; 353 init.num_parents = 1; 354 355 switch (type) { 356 case PLL_GF40LP_FRAC: 357 if (rates) 358 init.ops = &pll_gf40lp_frac_ops; 359 else 360 init.ops = &pll_gf40lp_frac_fixed_ops; 361 break; 362 case PLL_GF40LP_LAINT: 363 if (rates) 364 init.ops = &pll_gf40lp_laint_ops; 365 else 366 init.ops = &pll_gf40lp_laint_fixed_ops; 367 break; 368 default: 369 pr_err("Unrecognized PLL type %u\n", type); 370 kfree(pll); 371 return ERR_PTR(-EINVAL); 372 } 373 374 pll->hw.init = &init; 375 pll->base = base; 376 pll->rates = rates; 377 pll->nr_rates = nr_rates; 378 379 clk = clk_register(NULL, &pll->hw); 380 if (IS_ERR(clk)) 381 kfree(pll); 382 383 return clk; 384} 385 386void pistachio_clk_register_pll(struct pistachio_clk_provider *p, 387 struct pistachio_pll *pll, 388 unsigned int num) 389{ 390 struct clk *clk; 391 unsigned int i; 392 393 for (i = 0; i < num; i++) { 394 clk = pll_register(pll[i].name, pll[i].parent, 395 0, p->base + pll[i].reg_base, 396 pll[i].type, pll[i].rates, 397 pll[i].nr_rates); 398 p->clk_data.clks[pll[i].id] = clk; 399 } 400} 401