1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020 SiFive, Inc. 4 * Copyright (C) 2020 Zong Li 5 */ 6 7 #include <linux/delay.h> 8 #include <linux/io.h> 9 #include <linux/of.h> 10 #include "sifive-prci.h" 11 #include "fu540-prci.h" 12 #include "fu740-prci.h" 13 14 /* 15 * Private functions 16 */ 17 18 /** 19 * __prci_readl() - read from a PRCI register 20 * @pd: PRCI context 21 * @offs: register offset to read from (in bytes, from PRCI base address) 22 * 23 * Read the register located at offset @offs from the base virtual 24 * address of the PRCI register target described by @pd, and return 25 * the value to the caller. 26 * 27 * Context: Any context. 28 * 29 * Return: the contents of the register described by @pd and @offs. 30 */ 31 static u32 __prci_readl(struct __prci_data *pd, u32 offs) 32 { 33 return readl_relaxed(pd->va + offs); 34 } 35 36 static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd) 37 { 38 writel_relaxed(v, pd->va + offs); 39 } 40 41 /* WRPLL-related private functions */ 42 43 /** 44 * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters 45 * @c: ptr to a struct wrpll_cfg record to write config into 46 * @r: value read from the PRCI PLL configuration register 47 * 48 * Given a value @r read from an FU740 PRCI PLL configuration register, 49 * split it into fields and populate it into the WRPLL configuration record 50 * pointed to by @c. 51 * 52 * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros 53 * have the same register layout. 54 * 55 * Context: Any context. 56 */ 57 static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r) 58 { 59 u32 v; 60 61 v = r & PRCI_COREPLLCFG0_DIVR_MASK; 62 v >>= PRCI_COREPLLCFG0_DIVR_SHIFT; 63 c->divr = v; 64 65 v = r & PRCI_COREPLLCFG0_DIVF_MASK; 66 v >>= PRCI_COREPLLCFG0_DIVF_SHIFT; 67 c->divf = v; 68 69 v = r & PRCI_COREPLLCFG0_DIVQ_MASK; 70 v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT; 71 c->divq = v; 72 73 v = r & PRCI_COREPLLCFG0_RANGE_MASK; 74 v >>= PRCI_COREPLLCFG0_RANGE_SHIFT; 75 c->range = v; 76 77 c->flags &= 78 (WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK); 79 80 /* external feedback mode not supported */ 81 c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK; 82 } 83 84 /** 85 * __prci_wrpll_pack() - pack PLL configuration parameters into a register value 86 * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg 87 * 88 * Using a set of WRPLL configuration values pointed to by @c, 89 * assemble a PRCI PLL configuration register value, and return it to 90 * the caller. 91 * 92 * Context: Any context. Caller must ensure that the contents of the 93 * record pointed to by @c do not change during the execution 94 * of this function. 95 * 96 * Returns: a value suitable for writing into a PRCI PLL configuration 97 * register 98 */ 99 static u32 __prci_wrpll_pack(const struct wrpll_cfg *c) 100 { 101 u32 r = 0; 102 103 r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT; 104 r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT; 105 r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT; 106 r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT; 107 108 /* external feedback mode not supported */ 109 r |= PRCI_COREPLLCFG0_FSE_MASK; 110 111 return r; 112 } 113 114 /** 115 * __prci_wrpll_read_cfg0() - read the WRPLL configuration from the PRCI 116 * @pd: PRCI context 117 * @pwd: PRCI WRPLL metadata 118 * 119 * Read the current configuration of the PLL identified by @pwd from 120 * the PRCI identified by @pd, and store it into the local configuration 121 * cache in @pwd. 122 * 123 * Context: Any context. Caller must prevent the records pointed to by 124 * @pd and @pwd from changing during execution. 125 */ 126 static void __prci_wrpll_read_cfg0(struct __prci_data *pd, 127 struct __prci_wrpll_data *pwd) 128 { 129 __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs)); 130 } 131 132 /** 133 * __prci_wrpll_write_cfg0() - write WRPLL configuration into the PRCI 134 * @pd: PRCI context 135 * @pwd: PRCI WRPLL metadata 136 * @c: WRPLL configuration record to write 137 * 138 * Write the WRPLL configuration described by @c into the WRPLL 139 * configuration register identified by @pwd in the PRCI instance 140 * described by @c. Make a cached copy of the WRPLL's current 141 * configuration so it can be used by other code. 142 * 143 * Context: Any context. Caller must prevent the records pointed to by 144 * @pd and @pwd from changing during execution. 145 */ 146 static void __prci_wrpll_write_cfg0(struct __prci_data *pd, 147 struct __prci_wrpll_data *pwd, 148 struct wrpll_cfg *c) 149 { 150 __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd); 151 152 memcpy(&pwd->c, c, sizeof(*c)); 153 } 154 155 /** 156 * __prci_wrpll_write_cfg1() - write Clock enable/disable configuration 157 * into the PRCI 158 * @pd: PRCI context 159 * @pwd: PRCI WRPLL metadata 160 * @enable: Clock enable or disable value 161 */ 162 static void __prci_wrpll_write_cfg1(struct __prci_data *pd, 163 struct __prci_wrpll_data *pwd, 164 u32 enable) 165 { 166 __prci_writel(enable, pwd->cfg1_offs, pd); 167 } 168 169 /* 170 * Linux clock framework integration 171 * 172 * See the Linux clock framework documentation for more information on 173 * these functions. 174 */ 175 176 unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw, 177 unsigned long parent_rate) 178 { 179 struct __prci_clock *pc = clk_hw_to_prci_clock(hw); 180 struct __prci_wrpll_data *pwd = pc->pwd; 181 182 return wrpll_calc_output_rate(&pwd->c, parent_rate); 183 } 184 185 long sifive_prci_wrpll_round_rate(struct clk_hw *hw, 186 unsigned long rate, 187 unsigned long *parent_rate) 188 { 189 struct __prci_clock *pc = clk_hw_to_prci_clock(hw); 190 struct __prci_wrpll_data *pwd = pc->pwd; 191 struct wrpll_cfg c; 192 193 memcpy(&c, &pwd->c, sizeof(c)); 194 195 wrpll_configure_for_rate(&c, rate, *parent_rate); 196 197 return wrpll_calc_output_rate(&c, *parent_rate); 198 } 199 200 int sifive_prci_wrpll_set_rate(struct clk_hw *hw, 201 unsigned long rate, unsigned long parent_rate) 202 { 203 struct __prci_clock *pc = clk_hw_to_prci_clock(hw); 204 struct __prci_wrpll_data *pwd = pc->pwd; 205 struct __prci_data *pd = pc->pd; 206 int r; 207 208 r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate); 209 if (r) 210 return r; 211 212 if (pwd->enable_bypass) 213 pwd->enable_bypass(pd); 214 215 __prci_wrpll_write_cfg0(pd, pwd, &pwd->c); 216 217 udelay(wrpll_calc_max_lock_us(&pwd->c)); 218 219 return 0; 220 } 221 222 int sifive_clk_is_enabled(struct clk_hw *hw) 223 { 224 struct __prci_clock *pc = clk_hw_to_prci_clock(hw); 225 struct __prci_wrpll_data *pwd = pc->pwd; 226 struct __prci_data *pd = pc->pd; 227 u32 r; 228 229 r = __prci_readl(pd, pwd->cfg1_offs); 230 231 if (r & PRCI_COREPLLCFG1_CKE_MASK) 232 return 1; 233 else 234 return 0; 235 } 236 237 int sifive_prci_clock_enable(struct clk_hw *hw) 238 { 239 struct __prci_clock *pc = clk_hw_to_prci_clock(hw); 240 struct __prci_wrpll_data *pwd = pc->pwd; 241 struct __prci_data *pd = pc->pd; 242 243 if (sifive_clk_is_enabled(hw)) 244 return 0; 245 246 __prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK); 247 248 if (pwd->disable_bypass) 249 pwd->disable_bypass(pd); 250 251 return 0; 252 } 253 254 void sifive_prci_clock_disable(struct clk_hw *hw) 255 { 256 struct __prci_clock *pc = clk_hw_to_prci_clock(hw); 257 struct __prci_wrpll_data *pwd = pc->pwd; 258 struct __prci_data *pd = pc->pd; 259 u32 r; 260 261 if (pwd->enable_bypass) 262 pwd->enable_bypass(pd); 263 264 r = __prci_readl(pd, pwd->cfg1_offs); 265 r &= ~PRCI_COREPLLCFG1_CKE_MASK; 266 267 __prci_wrpll_write_cfg1(pd, pwd, r); 268 } 269 270 /* TLCLKSEL clock integration */ 271 272 unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw, 273 unsigned long parent_rate) 274 { 275 struct __prci_clock *pc = clk_hw_to_prci_clock(hw); 276 struct __prci_data *pd = pc->pd; 277 u32 v; 278 u8 div; 279 280 v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET); 281 v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK; 282 div = v ? 1 : 2; 283 284 return div_u64(parent_rate, div); 285 } 286 287 /* HFPCLK clock integration */ 288 289 unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw, 290 unsigned long parent_rate) 291 { 292 struct __prci_clock *pc = clk_hw_to_prci_clock(hw); 293 struct __prci_data *pd = pc->pd; 294 u32 div = __prci_readl(pd, PRCI_HFPCLKPLLDIV_OFFSET); 295 296 return div_u64(parent_rate, div + 2); 297 } 298 299 /* 300 * Core clock mux control 301 */ 302 303 /** 304 * sifive_prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK 305 * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg 306 * 307 * Switch the CORECLK mux to the HFCLK input source; return once complete. 308 * 309 * Context: Any context. Caller must prevent concurrent changes to the 310 * PRCI_CORECLKSEL_OFFSET register. 311 */ 312 void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd) 313 { 314 u32 r; 315 316 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); 317 r |= PRCI_CORECLKSEL_CORECLKSEL_MASK; 318 __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); 319 320 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ 321 } 322 323 /** 324 * sifive_prci_coreclksel_use_corepll() - switch the CORECLK mux to output 325 * COREPLL 326 * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg 327 * 328 * Switch the CORECLK mux to the COREPLL output clock; return once complete. 329 * 330 * Context: Any context. Caller must prevent concurrent changes to the 331 * PRCI_CORECLKSEL_OFFSET register. 332 */ 333 void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd) 334 { 335 u32 r; 336 337 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); 338 r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK; 339 __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); 340 341 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ 342 } 343 344 /** 345 * sifive_prci_coreclksel_use_final_corepll() - switch the CORECLK mux to output 346 * FINAL_COREPLL 347 * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg 348 * 349 * Switch the CORECLK mux to the final COREPLL output clock; return once 350 * complete. 351 * 352 * Context: Any context. Caller must prevent concurrent changes to the 353 * PRCI_CORECLKSEL_OFFSET register. 354 */ 355 void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd) 356 { 357 u32 r; 358 359 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); 360 r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK; 361 __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); 362 363 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ 364 } 365 366 /** 367 * sifive_prci_corepllsel_use_dvfscorepll() - switch the COREPLL mux to 368 * output DVFS_COREPLL 369 * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg 370 * 371 * Switch the COREPLL mux to the DVFSCOREPLL output clock; return once complete. 372 * 373 * Context: Any context. Caller must prevent concurrent changes to the 374 * PRCI_COREPLLSEL_OFFSET register. 375 */ 376 void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd) 377 { 378 u32 r; 379 380 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); 381 r |= PRCI_COREPLLSEL_COREPLLSEL_MASK; 382 __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd); 383 384 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); /* barrier */ 385 } 386 387 /** 388 * sifive_prci_corepllsel_use_corepll() - switch the COREPLL mux to 389 * output COREPLL 390 * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg 391 * 392 * Switch the COREPLL mux to the COREPLL output clock; return once complete. 393 * 394 * Context: Any context. Caller must prevent concurrent changes to the 395 * PRCI_COREPLLSEL_OFFSET register. 396 */ 397 void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd) 398 { 399 u32 r; 400 401 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); 402 r &= ~PRCI_COREPLLSEL_COREPLLSEL_MASK; 403 __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd); 404 405 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); /* barrier */ 406 } 407 408 /** 409 * sifive_prci_hfpclkpllsel_use_hfclk() - switch the HFPCLKPLL mux to 410 * output HFCLK 411 * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg 412 * 413 * Switch the HFPCLKPLL mux to the HFCLK input source; return once complete. 414 * 415 * Context: Any context. Caller must prevent concurrent changes to the 416 * PRCI_HFPCLKPLLSEL_OFFSET register. 417 */ 418 void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd) 419 { 420 u32 r; 421 422 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); 423 r |= PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK; 424 __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd); 425 426 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */ 427 } 428 429 /** 430 * sifive_prci_hfpclkpllsel_use_hfpclkpll() - switch the HFPCLKPLL mux to 431 * output HFPCLKPLL 432 * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg 433 * 434 * Switch the HFPCLKPLL mux to the HFPCLKPLL output clock; return once complete. 435 * 436 * Context: Any context. Caller must prevent concurrent changes to the 437 * PRCI_HFPCLKPLLSEL_OFFSET register. 438 */ 439 void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd) 440 { 441 u32 r; 442 443 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); 444 r &= ~PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK; 445 __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd); 446 447 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */ 448 } 449 450 /* PCIE AUX clock APIs for enable, disable. */ 451 int sifive_prci_pcie_aux_clock_is_enabled(struct clk_hw *hw) 452 { 453 struct __prci_clock *pc = clk_hw_to_prci_clock(hw); 454 struct __prci_data *pd = pc->pd; 455 u32 r; 456 457 r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET); 458 459 if (r & PRCI_PCIE_AUX_EN_MASK) 460 return 1; 461 else 462 return 0; 463 } 464 465 int sifive_prci_pcie_aux_clock_enable(struct clk_hw *hw) 466 { 467 struct __prci_clock *pc = clk_hw_to_prci_clock(hw); 468 struct __prci_data *pd = pc->pd; 469 u32 r __maybe_unused; 470 471 if (sifive_prci_pcie_aux_clock_is_enabled(hw)) 472 return 0; 473 474 __prci_writel(1, PRCI_PCIE_AUX_OFFSET, pd); 475 r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET); /* barrier */ 476 477 return 0; 478 } 479 480 void sifive_prci_pcie_aux_clock_disable(struct clk_hw *hw) 481 { 482 struct __prci_clock *pc = clk_hw_to_prci_clock(hw); 483 struct __prci_data *pd = pc->pd; 484 u32 r __maybe_unused; 485 486 __prci_writel(0, PRCI_PCIE_AUX_OFFSET, pd); 487 r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET); /* barrier */ 488 489 } 490 491 /** 492 * __prci_register_clocks() - register clock controls in the PRCI 493 * @dev: Linux struct device 494 * @pd: The pointer for PRCI per-device instance data 495 * @desc: The pointer for the information of clocks of each SoCs 496 * 497 * Register the list of clock controls described in __prci_init_clocks[] with 498 * the Linux clock framework. 499 * 500 * Return: 0 upon success or a negative error code upon failure. 501 */ 502 static int __prci_register_clocks(struct device *dev, struct __prci_data *pd, 503 const struct prci_clk_desc *desc) 504 { 505 struct clk_init_data init = { }; 506 struct __prci_clock *pic; 507 int parent_count, i, r; 508 509 parent_count = of_clk_get_parent_count(dev->of_node); 510 if (parent_count != EXPECTED_CLK_PARENT_COUNT) { 511 dev_err(dev, "expected only two parent clocks, found %d\n", 512 parent_count); 513 return -EINVAL; 514 } 515 516 /* Register PLLs */ 517 for (i = 0; i < desc->num_clks; ++i) { 518 pic = &(desc->clks[i]); 519 520 init.name = pic->name; 521 init.parent_names = &pic->parent_name; 522 init.num_parents = 1; 523 init.ops = pic->ops; 524 pic->hw.init = &init; 525 526 pic->pd = pd; 527 528 if (pic->pwd) 529 __prci_wrpll_read_cfg0(pd, pic->pwd); 530 531 r = devm_clk_hw_register(dev, &pic->hw); 532 if (r) { 533 dev_warn(dev, "Failed to register clock %s: %d\n", 534 init.name, r); 535 return r; 536 } 537 538 pd->hw_clks.hws[i] = &pic->hw; 539 } 540 541 pd->hw_clks.num = i; 542 543 r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, 544 &pd->hw_clks); 545 if (r) { 546 dev_err(dev, "could not add hw_provider: %d\n", r); 547 return r; 548 } 549 550 return 0; 551 } 552 553 /** 554 * sifive_prci_probe() - initialize prci data and check parent count 555 * @pdev: platform device pointer for the prci 556 * 557 * Return: 0 upon success or a negative error code upon failure. 558 */ 559 static int sifive_prci_probe(struct platform_device *pdev) 560 { 561 struct device *dev = &pdev->dev; 562 struct __prci_data *pd; 563 const struct prci_clk_desc *desc; 564 int r; 565 566 desc = of_device_get_match_data(&pdev->dev); 567 568 pd = devm_kzalloc(dev, struct_size(pd, hw_clks.hws, desc->num_clks), GFP_KERNEL); 569 if (!pd) 570 return -ENOMEM; 571 572 pd->va = devm_platform_ioremap_resource(pdev, 0); 573 if (IS_ERR(pd->va)) 574 return PTR_ERR(pd->va); 575 576 pd->reset.rcdev.owner = THIS_MODULE; 577 pd->reset.rcdev.nr_resets = PRCI_RST_NR; 578 pd->reset.rcdev.ops = &reset_simple_ops; 579 pd->reset.rcdev.of_node = pdev->dev.of_node; 580 pd->reset.active_low = true; 581 pd->reset.membase = pd->va + PRCI_DEVICESRESETREG_OFFSET; 582 spin_lock_init(&pd->reset.lock); 583 584 r = devm_reset_controller_register(&pdev->dev, &pd->reset.rcdev); 585 if (r) { 586 dev_err(dev, "could not register reset controller: %d\n", r); 587 return r; 588 } 589 r = __prci_register_clocks(dev, pd, desc); 590 if (r) { 591 dev_err(dev, "could not register clocks: %d\n", r); 592 return r; 593 } 594 595 dev_dbg(dev, "SiFive PRCI probed\n"); 596 597 return 0; 598 } 599 600 static const struct of_device_id sifive_prci_of_match[] = { 601 {.compatible = "sifive,fu540-c000-prci", .data = &prci_clk_fu540}, 602 {.compatible = "sifive,fu740-c000-prci", .data = &prci_clk_fu740}, 603 {} 604 }; 605 606 static struct platform_driver sifive_prci_driver = { 607 .driver = { 608 .name = "sifive-clk-prci", 609 .of_match_table = sifive_prci_of_match, 610 }, 611 .probe = sifive_prci_probe, 612 }; 613 614 static int __init sifive_prci_init(void) 615 { 616 return platform_driver_register(&sifive_prci_driver); 617 } 618 core_initcall(sifive_prci_init); 619