clk-pll-s10.c (7561B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2017, Intel Corporation 4 */ 5#include <linux/slab.h> 6#include <linux/clk-provider.h> 7#include <linux/io.h> 8 9#include "stratix10-clk.h" 10#include "clk.h" 11 12/* Clock Manager offsets */ 13#define CLK_MGR_PLL_CLK_SRC_SHIFT 16 14#define CLK_MGR_PLL_CLK_SRC_MASK 0x3 15 16/* PLL Clock enable bits */ 17#define SOCFPGA_PLL_POWER 0 18#define SOCFPGA_PLL_RESET_MASK 0x2 19#define SOCFPGA_PLL_REFDIV_MASK 0x00003F00 20#define SOCFPGA_PLL_REFDIV_SHIFT 8 21#define SOCFPGA_PLL_AREFDIV_MASK 0x00000F00 22#define SOCFPGA_PLL_DREFDIV_MASK 0x00003000 23#define SOCFPGA_PLL_DREFDIV_SHIFT 12 24#define SOCFPGA_PLL_MDIV_MASK 0xFF000000 25#define SOCFPGA_PLL_MDIV_SHIFT 24 26#define SOCFPGA_AGILEX_PLL_MDIV_MASK 0x000003FF 27#define SWCTRLBTCLKSEL_MASK 0x200 28#define SWCTRLBTCLKSEL_SHIFT 9 29 30#define SOCFPGA_N5X_PLLDIV_FDIV_MASK GENMASK(16, 8) 31#define SOCFPGA_N5X_PLLDIV_FDIV_SHIFT 8 32#define SOCFPGA_N5X_PLLDIV_RDIV_MASK GENMASK(5, 0) 33#define SOCFPGA_N5X_PLLDIV_QDIV_MASK GENMASK(26, 24) 34#define SOCFPGA_N5X_PLLDIV_QDIV_SHIFT 24 35 36#define SOCFPGA_BOOT_CLK "boot_clk" 37 38#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw) 39 40static unsigned long n5x_clk_pll_recalc_rate(struct clk_hw *hwclk, 41 unsigned long parent_rate) 42{ 43 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 44 unsigned long fdiv, reg, rdiv, qdiv; 45 u32 power = 1; 46 47 /* read VCO1 reg for numerator and denominator */ 48 reg = readl(socfpgaclk->hw.reg + 0x8); 49 fdiv = (reg & SOCFPGA_N5X_PLLDIV_FDIV_MASK) >> SOCFPGA_N5X_PLLDIV_FDIV_SHIFT; 50 rdiv = (reg & SOCFPGA_N5X_PLLDIV_RDIV_MASK); 51 qdiv = (reg & SOCFPGA_N5X_PLLDIV_QDIV_MASK) >> SOCFPGA_N5X_PLLDIV_QDIV_SHIFT; 52 53 while (qdiv) { 54 power *= 2; 55 qdiv--; 56 } 57 58 return ((parent_rate * 2 * (fdiv + 1)) / ((rdiv + 1) * power)); 59} 60 61static unsigned long agilex_clk_pll_recalc_rate(struct clk_hw *hwclk, 62 unsigned long parent_rate) 63{ 64 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 65 unsigned long arefdiv, reg, mdiv; 66 unsigned long long vco_freq; 67 68 /* read VCO1 reg for numerator and denominator */ 69 reg = readl(socfpgaclk->hw.reg); 70 arefdiv = (reg & SOCFPGA_PLL_AREFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT; 71 72 vco_freq = (unsigned long long)parent_rate / arefdiv; 73 74 /* Read mdiv and fdiv from the fdbck register */ 75 reg = readl(socfpgaclk->hw.reg + 0x24); 76 mdiv = reg & SOCFPGA_AGILEX_PLL_MDIV_MASK; 77 78 vco_freq = (unsigned long long)vco_freq * mdiv; 79 return (unsigned long)vco_freq; 80} 81 82static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, 83 unsigned long parent_rate) 84{ 85 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 86 unsigned long mdiv; 87 unsigned long refdiv; 88 unsigned long reg; 89 unsigned long long vco_freq; 90 91 /* read VCO1 reg for numerator and denominator */ 92 reg = readl(socfpgaclk->hw.reg); 93 refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT; 94 95 vco_freq = parent_rate; 96 do_div(vco_freq, refdiv); 97 98 /* Read mdiv and fdiv from the fdbck register */ 99 reg = readl(socfpgaclk->hw.reg + 0x4); 100 mdiv = (reg & SOCFPGA_PLL_MDIV_MASK) >> SOCFPGA_PLL_MDIV_SHIFT; 101 vco_freq = (unsigned long long)vco_freq * (mdiv + 6); 102 103 return (unsigned long)vco_freq; 104} 105 106static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk, 107 unsigned long parent_rate) 108{ 109 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 110 u32 div; 111 112 div = ((readl(socfpgaclk->hw.reg) & 113 SWCTRLBTCLKSEL_MASK) >> 114 SWCTRLBTCLKSEL_SHIFT); 115 div += 1; 116 return parent_rate / div; 117} 118 119 120static u8 clk_pll_get_parent(struct clk_hw *hwclk) 121{ 122 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 123 u32 pll_src; 124 125 pll_src = readl(socfpgaclk->hw.reg); 126 return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) & 127 CLK_MGR_PLL_CLK_SRC_MASK; 128} 129 130static u8 clk_boot_get_parent(struct clk_hw *hwclk) 131{ 132 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 133 u32 pll_src; 134 135 pll_src = readl(socfpgaclk->hw.reg); 136 return (pll_src >> SWCTRLBTCLKSEL_SHIFT) & 137 SWCTRLBTCLKSEL_MASK; 138} 139 140static int clk_pll_prepare(struct clk_hw *hwclk) 141{ 142 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 143 u32 reg; 144 145 /* Bring PLL out of reset */ 146 reg = readl(socfpgaclk->hw.reg); 147 reg |= SOCFPGA_PLL_RESET_MASK; 148 writel(reg, socfpgaclk->hw.reg); 149 150 return 0; 151} 152 153static int n5x_clk_pll_prepare(struct clk_hw *hwclk) 154{ 155 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 156 u32 reg; 157 158 /* Bring PLL out of reset */ 159 reg = readl(socfpgaclk->hw.reg + 0x4); 160 reg |= SOCFPGA_PLL_RESET_MASK; 161 writel(reg, socfpgaclk->hw.reg + 0x4); 162 163 return 0; 164} 165 166static const struct clk_ops n5x_clk_pll_ops = { 167 .recalc_rate = n5x_clk_pll_recalc_rate, 168 .get_parent = clk_pll_get_parent, 169 .prepare = n5x_clk_pll_prepare, 170}; 171 172static const struct clk_ops agilex_clk_pll_ops = { 173 .recalc_rate = agilex_clk_pll_recalc_rate, 174 .get_parent = clk_pll_get_parent, 175 .prepare = clk_pll_prepare, 176}; 177 178static const struct clk_ops clk_pll_ops = { 179 .recalc_rate = clk_pll_recalc_rate, 180 .get_parent = clk_pll_get_parent, 181 .prepare = clk_pll_prepare, 182}; 183 184static const struct clk_ops clk_boot_ops = { 185 .recalc_rate = clk_boot_clk_recalc_rate, 186 .get_parent = clk_boot_get_parent, 187 .prepare = clk_pll_prepare, 188}; 189 190struct clk_hw *s10_register_pll(const struct stratix10_pll_clock *clks, 191 void __iomem *reg) 192{ 193 struct clk_hw *hw_clk; 194 struct socfpga_pll *pll_clk; 195 struct clk_init_data init; 196 const char *name = clks->name; 197 int ret; 198 199 pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); 200 if (WARN_ON(!pll_clk)) 201 return NULL; 202 203 pll_clk->hw.reg = reg + clks->offset; 204 205 if (streq(name, SOCFPGA_BOOT_CLK)) 206 init.ops = &clk_boot_ops; 207 else 208 init.ops = &clk_pll_ops; 209 210 init.name = name; 211 init.flags = clks->flags; 212 213 init.num_parents = clks->num_parents; 214 init.parent_names = NULL; 215 init.parent_data = clks->parent_data; 216 pll_clk->hw.hw.init = &init; 217 218 pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER; 219 220 hw_clk = &pll_clk->hw.hw; 221 222 ret = clk_hw_register(NULL, hw_clk); 223 if (ret) { 224 kfree(pll_clk); 225 return ERR_PTR(ret); 226 } 227 return hw_clk; 228} 229 230struct clk_hw *agilex_register_pll(const struct stratix10_pll_clock *clks, 231 void __iomem *reg) 232{ 233 struct clk_hw *hw_clk; 234 struct socfpga_pll *pll_clk; 235 struct clk_init_data init; 236 const char *name = clks->name; 237 int ret; 238 239 pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); 240 if (WARN_ON(!pll_clk)) 241 return NULL; 242 243 pll_clk->hw.reg = reg + clks->offset; 244 245 if (streq(name, SOCFPGA_BOOT_CLK)) 246 init.ops = &clk_boot_ops; 247 else 248 init.ops = &agilex_clk_pll_ops; 249 250 init.name = name; 251 init.flags = clks->flags; 252 253 init.num_parents = clks->num_parents; 254 init.parent_names = NULL; 255 init.parent_data = clks->parent_data; 256 pll_clk->hw.hw.init = &init; 257 258 pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER; 259 hw_clk = &pll_clk->hw.hw; 260 261 ret = clk_hw_register(NULL, hw_clk); 262 if (ret) { 263 kfree(pll_clk); 264 return ERR_PTR(ret); 265 } 266 return hw_clk; 267} 268 269struct clk_hw *n5x_register_pll(const struct stratix10_pll_clock *clks, 270 void __iomem *reg) 271{ 272 struct clk_hw *hw_clk; 273 struct socfpga_pll *pll_clk; 274 struct clk_init_data init; 275 const char *name = clks->name; 276 int ret; 277 278 pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); 279 if (WARN_ON(!pll_clk)) 280 return NULL; 281 282 pll_clk->hw.reg = reg + clks->offset; 283 284 if (streq(name, SOCFPGA_BOOT_CLK)) 285 init.ops = &clk_boot_ops; 286 else 287 init.ops = &n5x_clk_pll_ops; 288 289 init.name = name; 290 init.flags = clks->flags; 291 292 init.num_parents = clks->num_parents; 293 init.parent_names = NULL; 294 init.parent_data = clks->parent_data; 295 pll_clk->hw.hw.init = &init; 296 297 pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER; 298 hw_clk = &pll_clk->hw.hw; 299 300 ret = clk_hw_register(NULL, hw_clk); 301 if (ret) { 302 kfree(pll_clk); 303 return ERR_PTR(ret); 304 } 305 return hw_clk; 306}