1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2022-23 StarFive Technology Co., Ltd. 4 * 5 * Author: Yanhong Wang <yanhong.wang@starfivetech.com> 6 * Xingyu Wu <xingyu.wu@starfivetech.com> 7 */ 8 9#include <common.h> 10#include <asm/io.h> 11#include <malloc.h> 12#include <clk-uclass.h> 13#include <div64.h> 14#include <dm/device.h> 15#include <dm/read.h> 16#include <dt-bindings/clock/starfive,jh7110-crg.h> 17#include <linux/bitops.h> 18#include <linux/clk-provider.h> 19#include <linux/delay.h> 20#include <linux/err.h> 21 22#include "clk.h" 23 24#define UBOOT_DM_CLK_JH7110_PLLX "jh7110_clk_pllx" 25 26#define PLL_PD_OFF 1 27#define PLL_PD_ON 0 28 29#define CLK_DDR_BUS_MASK GENMASK(29, 24) 30#define CLK_DDR_BUS_OFFSET 0xAC 31#define CLK_DDR_BUS_OSC_DIV2 0 32#define CLK_DDR_BUS_PLL1_DIV2 1 33#define CLK_DDR_BUS_PLL1_DIV4 2 34#define CLK_DDR_BUS_PLL1_DIV8 3 35 36#define JH7110_PLL_ID_TRANS(id) ((id) + JH7110_EXTCLK_END) 37 38enum starfive_pll_type { 39 PLL0 = 0, 40 PLL1, 41 PLL2, 42 PLL_MAX = PLL2 43}; 44 45struct starfive_pllx_rate { 46 u64 rate; 47 u32 prediv; 48 u32 fbdiv; 49 u32 frac; 50}; 51 52struct starfive_pllx_offset { 53 u32 pd; 54 u32 prediv; 55 u32 fbdiv; 56 u32 frac; 57 u32 postdiv1; 58 u32 dacpd; 59 u32 dsmpd; 60 u32 pd_mask; 61 u32 prediv_mask; 62 u32 fbdiv_mask; 63 u32 frac_mask; 64 u32 postdiv1_mask; 65 u32 dacpd_mask; 66 u32 dsmpd_mask; 67}; 68 69struct starfive_pllx_clk { 70 enum starfive_pll_type type; 71 const struct starfive_pllx_offset *offset; 72 const struct starfive_pllx_rate *rate_table; 73 int rate_count; 74 int flags; 75}; 76 77struct clk_jh7110_pllx { 78 struct clk clk; 79 void __iomem *base; 80 void __iomem *sysreg; 81 enum starfive_pll_type type; 82 const struct starfive_pllx_offset *offset; 83 const struct starfive_pllx_rate *rate_table; 84 int rate_count; 85}; 86 87#define getbits_le32(addr, mask) ((in_le32(addr) & (mask)) >> __ffs((mask))) 88 89#define PLLX_SET(offset, mask, val) do {\ 90 reg = readl((ulong *)((ulong)pll->base + (offset))); \ 91 reg &= ~(mask); \ 92 reg |= (mask) & ((val) << __ffs(mask)); \ 93 writel(reg, (ulong *)((ulong)pll->base + (offset))); \ 94 } while (0) 95 96#define PLLX_RATE(_rate, _pd, _fd) \ 97 { \ 98 .rate = (_rate), \ 99 .prediv = (_pd), \ 100 .fbdiv = (_fd), \ 101 } 102 103#define to_clk_pllx(_clk) container_of(_clk, struct clk_jh7110_pllx, clk) 104 105static const struct starfive_pllx_rate jh7110_pll0_tbl[] = { 106 PLLX_RATE(375000000UL, 8, 125), 107 PLLX_RATE(500000000UL, 6, 125), 108 PLLX_RATE(625000000UL, 24, 625), 109 PLLX_RATE(750000000UL, 4, 125), 110 PLLX_RATE(875000000UL, 24, 875), 111 PLLX_RATE(1000000000UL, 3, 125), 112 PLLX_RATE(1250000000UL, 12, 625), 113 PLLX_RATE(1375000000UL, 24, 1375), 114 PLLX_RATE(1500000000UL, 2, 125), 115 PLLX_RATE(1625000000UL, 24, 1625), 116 PLLX_RATE(1750000000UL, 12, 875), 117 PLLX_RATE(1800000000UL, 3, 225), 118}; 119 120static const struct starfive_pllx_rate jh7110_pll1_tbl[] = { 121 PLLX_RATE(1066000000UL, 12, 533), 122 PLLX_RATE(1200000000UL, 1, 50), 123 PLLX_RATE(1400000000UL, 6, 350), 124 PLLX_RATE(1600000000UL, 3, 200), 125}; 126 127static const struct starfive_pllx_rate jh7110_pll2_tbl[] = { 128 PLLX_RATE(1228800000UL, 15, 768), 129 PLLX_RATE(1188000000UL, 2, 99), 130}; 131 132static const struct starfive_pllx_offset jh7110_pll0_offset = { 133 .pd = 0x20, 134 .prediv = 0x24, 135 .fbdiv = 0x1c, 136 .frac = 0x20, 137 .postdiv1 = 0x20, 138 .dacpd = 0x18, 139 .dsmpd = 0x18, 140 .pd_mask = BIT(27), 141 .prediv_mask = GENMASK(5, 0), 142 .fbdiv_mask = GENMASK(11, 0), 143 .frac_mask = GENMASK(23, 0), 144 .postdiv1_mask = GENMASK(29, 28), 145 .dacpd_mask = BIT(24), 146 .dsmpd_mask = BIT(25) 147}; 148 149static const struct starfive_pllx_offset jh7110_pll1_offset = { 150 .pd = 0x28, 151 .prediv = 0x2c, 152 .fbdiv = 0x24, 153 .frac = 0x28, 154 .postdiv1 = 0x28, 155 .dacpd = 0x24, 156 .dsmpd = 0x24, 157 .pd_mask = BIT(27), 158 .prediv_mask = GENMASK(5, 0), 159 .fbdiv_mask = GENMASK(28, 17), 160 .frac_mask = GENMASK(23, 0), 161 .postdiv1_mask = GENMASK(29, 28), 162 .dacpd_mask = BIT(15), 163 .dsmpd_mask = BIT(16) 164}; 165 166static const struct starfive_pllx_offset jh7110_pll2_offset = { 167 .pd = 0x30, 168 .prediv = 0x34, 169 .fbdiv = 0x2c, 170 .frac = 0x30, 171 .postdiv1 = 0x30, 172 .dacpd = 0x2c, 173 .dsmpd = 0x2c, 174 .pd_mask = BIT(27), 175 .prediv_mask = GENMASK(5, 0), 176 .fbdiv_mask = GENMASK(28, 17), 177 .frac_mask = GENMASK(23, 0), 178 .postdiv1_mask = GENMASK(29, 28), 179 .dacpd_mask = BIT(15), 180 .dsmpd_mask = BIT(16) 181}; 182 183struct starfive_pllx_clk starfive_jh7110_pll0 __initdata = { 184 .type = PLL0, 185 .offset = &jh7110_pll0_offset, 186 .rate_table = jh7110_pll0_tbl, 187 .rate_count = ARRAY_SIZE(jh7110_pll0_tbl), 188}; 189 190struct starfive_pllx_clk starfive_jh7110_pll1 __initdata = { 191 .type = PLL1, 192 .offset = &jh7110_pll1_offset, 193 .rate_table = jh7110_pll1_tbl, 194 .rate_count = ARRAY_SIZE(jh7110_pll1_tbl), 195}; 196 197struct starfive_pllx_clk starfive_jh7110_pll2 __initdata = { 198 .type = PLL2, 199 .offset = &jh7110_pll2_offset, 200 .rate_table = jh7110_pll2_tbl, 201 .rate_count = ARRAY_SIZE(jh7110_pll2_tbl), 202}; 203 204static const struct starfive_pllx_rate * 205jh7110_get_pll_settings(struct clk_jh7110_pllx *pll, unsigned long rate) 206{ 207 for (int i = 0; i < pll->rate_count; i++) 208 if (rate == pll->rate_table[i].rate) 209 return &pll->rate_table[i]; 210 211 return NULL; 212} 213 214static void jh7110_pll_set_rate(struct clk_jh7110_pllx *pll, 215 const struct starfive_pllx_rate *rate) 216{ 217 u32 reg; 218 bool set = (pll->type == PLL1) ? true : false; 219 220 if (set) { 221 reg = readl((ulong *)((ulong)pll->sysreg + CLK_DDR_BUS_OFFSET)); 222 reg &= ~CLK_DDR_BUS_MASK; 223 reg |= CLK_DDR_BUS_OSC_DIV2 << __ffs(CLK_DDR_BUS_MASK); 224 writel(reg, (ulong *)((ulong)pll->sysreg + CLK_DDR_BUS_OFFSET)); 225 } 226 227 PLLX_SET(pll->offset->pd, pll->offset->pd_mask, PLL_PD_OFF); 228 PLLX_SET(pll->offset->dacpd, pll->offset->dacpd_mask, 1); 229 PLLX_SET(pll->offset->dsmpd, pll->offset->dsmpd_mask, 1); 230 PLLX_SET(pll->offset->prediv, pll->offset->prediv_mask, rate->prediv); 231 PLLX_SET(pll->offset->fbdiv, pll->offset->fbdiv_mask, rate->fbdiv); 232 PLLX_SET(pll->offset->postdiv1, pll->offset->postdiv1_mask, 0); 233 PLLX_SET(pll->offset->pd, pll->offset->pd_mask, PLL_PD_ON); 234 235 if (set) { 236 udelay(100); 237 reg = readl((ulong *)((ulong)pll->sysreg + CLK_DDR_BUS_OFFSET)); 238 reg &= ~CLK_DDR_BUS_MASK; 239 reg |= CLK_DDR_BUS_PLL1_DIV2 << __ffs(CLK_DDR_BUS_MASK); 240 writel(reg, (ulong *)((ulong)pll->sysreg + CLK_DDR_BUS_OFFSET)); 241 } 242} 243 244static ulong jh7110_pllx_recalc_rate(struct clk *clk) 245{ 246 struct clk_jh7110_pllx *pll = to_clk_pllx(dev_get_clk_ptr(clk->dev)); 247 u64 refclk = clk_get_parent_rate(clk); 248 u32 dacpd, dsmpd; 249 u32 prediv, fbdiv, postdiv1; 250 u64 frac; 251 252 dacpd = getbits_le32((ulong)pll->base + pll->offset->dacpd, 253 pll->offset->dacpd_mask); 254 dsmpd = getbits_le32((ulong)pll->base + pll->offset->dsmpd, 255 pll->offset->dsmpd_mask); 256 prediv = getbits_le32((ulong)pll->base + pll->offset->prediv, 257 pll->offset->prediv_mask); 258 fbdiv = getbits_le32((ulong)pll->base + pll->offset->fbdiv, 259 pll->offset->fbdiv_mask); 260 postdiv1 = 1 << getbits_le32((ulong)pll->base + pll->offset->postdiv1, 261 pll->offset->postdiv1_mask); 262 frac = (u64)getbits_le32((ulong)pll->base + pll->offset->frac, 263 pll->offset->frac_mask); 264 265 /* Integer Multiple Mode 266 * Both dacpd and dsmpd should be set as 1 while integer multiple mode. 267 * 268 * The frequency of outputs can be figured out as below. 269 * 270 * Fvco = Fref*Nl/M 271 * NI is integer frequency dividing ratio of feedback divider, set by fbdiv1[11:0] , 272 * NI = 8, 9, 10, 12.13....4095 273 * M is frequency dividing ratio of pre-divider, set by prediv[5:0],M = 1,2...63 274 * 275 * Fclko1 = Fvco/Q1 276 * Q1 is frequency dividing ratio of post divider, set by postdiv1[1:0],Q1= 1,2,4,8 277 * 278 * Fraction Multiple Mode 279 * 280 * Both dacpd and dsmpd should be set as 0 while integer multiple mode. 281 * 282 * Fvco = Fref*(NI+NF)/M 283 * NI is integer frequency dividing ratio of feedback divider, set by fbdiv[11:0] , 284 * NI = 8, 9, 10, 12.13....4095 285 * NF is fractional frequency dividing ratio, set by frac[23:0], NF =frac[23:0]/2^24= 0~0.99999994 286 * M is frequency dividing ratio of pre-divider, set by prediv[5:0],M = 1,2...63 287 * 288 * Fclko1 = Fvco/Q1 289 * Q1 is frequency dividing ratio of post divider, set by postdivl[1:0],Q1= 1,2,4,8 290 */ 291 if (dacpd == 1 && dsmpd == 1) 292 frac = 0; 293 else if (dacpd == 0 && dsmpd == 0) 294 do_div(frac, 1 << 24); 295 else 296 return -EINVAL; 297 298 refclk *= (fbdiv + frac); 299 do_div(refclk, prediv * postdiv1); 300 301 return refclk; 302} 303 304static ulong jh7110_pllx_set_rate(struct clk *clk, ulong drate) 305{ 306 struct clk_jh7110_pllx *pll = to_clk_pllx(dev_get_clk_ptr(clk->dev)); 307 const struct starfive_pllx_rate *rate; 308 309 rate = jh7110_get_pll_settings(pll, drate); 310 if (!rate) 311 return -EINVAL; 312 313 jh7110_pll_set_rate(pll, rate); 314 315 return jh7110_pllx_recalc_rate(clk); 316} 317 318static const struct clk_ops jh7110_clk_pllx_ops = { 319 .set_rate = jh7110_pllx_set_rate, 320 .get_rate = jh7110_pllx_recalc_rate, 321}; 322 323struct clk *starfive_jh7110_pll(const char *name, const char *parent_name, 324 void __iomem *base, void __iomem *sysreg, 325 const struct starfive_pllx_clk *pll_clk) 326{ 327 struct clk_jh7110_pllx *pll; 328 struct clk *clk; 329 int ret; 330 331 if (!pll_clk || !base || !sysreg) 332 return ERR_PTR(-EINVAL); 333 334 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 335 if (!pll) 336 return ERR_PTR(-ENOMEM); 337 338 pll->base = base; 339 pll->sysreg = sysreg; 340 pll->type = pll_clk->type; 341 pll->offset = pll_clk->offset; 342 pll->rate_table = pll_clk->rate_table; 343 pll->rate_count = pll_clk->rate_count; 344 345 clk = &pll->clk; 346 ret = clk_register(clk, UBOOT_DM_CLK_JH7110_PLLX, name, parent_name); 347 if (ret) { 348 kfree(pll); 349 return ERR_PTR(ret); 350 } 351 352 if (IS_ENABLED(CONFIG_SPL_BUILD) && pll->type == PLL0) 353 jh7110_pllx_set_rate(clk, 1000000000); 354 355 if (IS_ENABLED(CONFIG_SPL_BUILD) && pll->type == PLL2) 356 jh7110_pllx_set_rate(clk, 1188000000); 357 358 return clk; 359} 360 361/* PLLx clock implementation */ 362U_BOOT_DRIVER(jh7110_clk_pllx) = { 363 .name = UBOOT_DM_CLK_JH7110_PLLX, 364 .id = UCLASS_CLK, 365 .ops = &jh7110_clk_pllx_ops, 366 .flags = DM_FLAG_PRE_RELOC, 367}; 368 369static int jh7110_pll_clk_probe(struct udevice *dev) 370{ 371 void __iomem *reg = (void __iomem *)dev_read_addr_ptr(dev->parent); 372 fdt_addr_t sysreg = ofnode_get_addr(ofnode_by_compatible(ofnode_null(), 373 "starfive,jh7110-syscrg")); 374 375 if (sysreg == FDT_ADDR_T_NONE) 376 return -EINVAL; 377 378 clk_dm(JH7110_PLL_ID_TRANS(JH7110_SYSCLK_PLL0_OUT), 379 starfive_jh7110_pll("pll0_out", "oscillator", reg, 380 (void __iomem *)sysreg, &starfive_jh7110_pll0)); 381 clk_dm(JH7110_PLL_ID_TRANS(JH7110_SYSCLK_PLL1_OUT), 382 starfive_jh7110_pll("pll1_out", "oscillator", reg, 383 (void __iomem *)sysreg, &starfive_jh7110_pll1)); 384 clk_dm(JH7110_PLL_ID_TRANS(JH7110_SYSCLK_PLL2_OUT), 385 starfive_jh7110_pll("pll2_out", "oscillator", reg, 386 (void __iomem *)sysreg, &starfive_jh7110_pll2)); 387 388 return 0; 389} 390 391static int jh7110_pll_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) 392{ 393 if (args->args_count > 1) { 394 debug("Invalid args_count: %d\n", args->args_count); 395 return -EINVAL; 396 } 397 398 if (args->args_count) 399 clk->id = JH7110_PLL_ID_TRANS(args->args[0]); 400 else 401 clk->id = 0; 402 403 return 0; 404} 405 406static const struct udevice_id jh7110_pll_clk_of_match[] = { 407 { .compatible = "starfive,jh7110-pll", }, 408 { } 409}; 410 411JH7110_CLK_OPS(pll); 412 413/* PLL clk device */ 414U_BOOT_DRIVER(jh7110_pll_clk) = { 415 .name = "jh7110_pll_clk", 416 .id = UCLASS_CLK, 417 .of_match = jh7110_pll_clk_of_match, 418 .probe = jh7110_pll_clk_probe, 419 .ops = &jh7110_pll_clk_ops, 420}; 421