1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Sophgo SG2044 PLL clock controller driver 4 * 5 * Copyright (C) 2025 Inochi Amaoto <inochiama@gmail.com> 6 */ 7 8 #include <linux/array_size.h> 9 #include <linux/bitfield.h> 10 #include <linux/bits.h> 11 #include <linux/cleanup.h> 12 #include <linux/clk.h> 13 #include <linux/clk-provider.h> 14 #include <linux/io.h> 15 #include <linux/iopoll.h> 16 #include <linux/math64.h> 17 #include <linux/mfd/syscon.h> 18 #include <linux/platform_device.h> 19 #include <linux/regmap.h> 20 #include <linux/spinlock.h> 21 22 #include <dt-bindings/clock/sophgo,sg2044-pll.h> 23 24 /* Low Control part */ 25 #define PLL_VCOSEL_MASK GENMASK(17, 16) 26 27 /* High Control part */ 28 #define PLL_FBDIV_MASK GENMASK(11, 0) 29 #define PLL_REFDIV_MASK GENMASK(17, 12) 30 #define PLL_POSTDIV1_MASK GENMASK(20, 18) 31 #define PLL_POSTDIV2_MASK GENMASK(23, 21) 32 33 #define PLL_CALIBRATE_EN BIT(24) 34 #define PLL_CALIBRATE_MASK GENMASK(29, 27) 35 #define PLL_CALIBRATE_DEFAULT FIELD_PREP(PLL_CALIBRATE_MASK, 2) 36 #define PLL_UPDATE_EN BIT(30) 37 38 #define PLL_HIGH_CTRL_MASK \ 39 (PLL_FBDIV_MASK | PLL_REFDIV_MASK | \ 40 PLL_POSTDIV1_MASK | PLL_POSTDIV2_MASK | \ 41 PLL_CALIBRATE_EN | PLL_CALIBRATE_MASK | \ 42 PLL_UPDATE_EN) 43 44 #define PLL_HIGH_CTRL_OFFSET 4 45 46 #define PLL_VCOSEL_1G6 0x2 47 #define PLL_VCOSEL_2G4 0x3 48 49 #define PLL_LIMIT_FOUTVCO 0 50 #define PLL_LIMIT_FOUT 1 51 #define PLL_LIMIT_REFDIV 2 52 #define PLL_LIMIT_FBDIV 3 53 #define PLL_LIMIT_POSTDIV1 4 54 #define PLL_LIMIT_POSTDIV2 5 55 56 #define for_each_pll_limit_range(_var, _limit) \ 57 for (_var = (_limit)->min; _var <= (_limit)->max; _var++) 58 59 struct sg2044_pll_limit { 60 u64 min; 61 u64 max; 62 }; 63 64 struct sg2044_pll_internal { 65 u32 ctrl_offset; 66 u32 status_offset; 67 u32 enable_offset; 68 69 u8 status_lock_bit; 70 u8 status_updating_bit; 71 u8 enable_bit; 72 73 const struct sg2044_pll_limit *limits; 74 }; 75 76 struct sg2044_clk_common { 77 struct clk_hw hw; 78 struct regmap *regmap; 79 spinlock_t *lock; 80 unsigned int id; 81 }; 82 83 struct sg2044_pll { 84 struct sg2044_clk_common common; 85 struct sg2044_pll_internal pll; 86 unsigned int syscon_offset; 87 }; 88 89 struct sg2044_pll_desc_data { 90 struct sg2044_clk_common * const *pll; 91 u16 num_pll; 92 }; 93 94 #define SG2044_SYSCON_PLL_OFFSET 0x98 95 96 struct sg2044_pll_ctrl { 97 spinlock_t lock; 98 struct clk_hw_onecell_data data; 99 }; 100 101 #define hw_to_sg2044_clk_common(_hw) \ 102 container_of((_hw), struct sg2044_clk_common, hw) 103 104 static inline bool sg2044_clk_fit_limit(u64 value, 105 const struct sg2044_pll_limit *limit) 106 { 107 return value >= limit->min && value <= limit->max; 108 } 109 110 static inline struct sg2044_pll *hw_to_sg2044_pll(struct clk_hw *hw) 111 { 112 return container_of(hw_to_sg2044_clk_common(hw), 113 struct sg2044_pll, common); 114 } 115 116 static unsigned long sg2044_pll_calc_vco_rate(unsigned long parent_rate, 117 unsigned long refdiv, 118 unsigned long fbdiv) 119 { 120 u64 numerator = parent_rate * fbdiv; 121 122 return div64_ul(numerator, refdiv); 123 } 124 125 static unsigned long sg2044_pll_calc_rate(unsigned long parent_rate, 126 unsigned long refdiv, 127 unsigned long fbdiv, 128 unsigned long postdiv1, 129 unsigned long postdiv2) 130 { 131 u64 numerator, denominator; 132 133 numerator = parent_rate * fbdiv; 134 denominator = refdiv * (postdiv1 + 1) * (postdiv2 + 1); 135 136 return div64_u64(numerator, denominator); 137 } 138 139 static unsigned long sg2044_pll_recalc_rate(struct clk_hw *hw, 140 unsigned long parent_rate) 141 { 142 struct sg2044_pll *pll = hw_to_sg2044_pll(hw); 143 u32 value; 144 int ret; 145 146 ret = regmap_read(pll->common.regmap, 147 pll->syscon_offset + pll->pll.ctrl_offset + PLL_HIGH_CTRL_OFFSET, 148 &value); 149 if (ret < 0) 150 return 0; 151 152 return sg2044_pll_calc_rate(parent_rate, 153 FIELD_GET(PLL_REFDIV_MASK, value), 154 FIELD_GET(PLL_FBDIV_MASK, value), 155 FIELD_GET(PLL_POSTDIV1_MASK, value), 156 FIELD_GET(PLL_POSTDIV2_MASK, value)); 157 } 158 159 static bool pll_is_better_rate(unsigned long target, unsigned long now, 160 unsigned long best) 161 { 162 return abs_diff(target, now) < abs_diff(target, best); 163 } 164 165 static int sg2042_pll_compute_postdiv(const struct sg2044_pll_limit *limits, 166 unsigned long target, 167 unsigned long parent_rate, 168 unsigned int refdiv, 169 unsigned int fbdiv, 170 unsigned int *postdiv1, 171 unsigned int *postdiv2) 172 { 173 unsigned int div1, div2; 174 unsigned long tmp, best_rate = 0; 175 unsigned int best_div1 = 0, best_div2 = 0; 176 177 for_each_pll_limit_range(div2, &limits[PLL_LIMIT_POSTDIV2]) { 178 for_each_pll_limit_range(div1, &limits[PLL_LIMIT_POSTDIV1]) { 179 tmp = sg2044_pll_calc_rate(parent_rate, 180 refdiv, fbdiv, 181 div1, div2); 182 183 if (tmp > target) 184 continue; 185 186 if (pll_is_better_rate(target, tmp, best_rate)) { 187 best_div1 = div1; 188 best_div2 = div2; 189 best_rate = tmp; 190 191 if (tmp == target) 192 goto find; 193 } 194 } 195 } 196 197 find: 198 if (best_rate) { 199 *postdiv1 = best_div1; 200 *postdiv2 = best_div2; 201 return 0; 202 } 203 204 return -EINVAL; 205 } 206 207 static int sg2044_compute_pll_setting(const struct sg2044_pll_limit *limits, 208 unsigned long req_rate, 209 unsigned long parent_rate, 210 unsigned int *value) 211 { 212 unsigned int refdiv, fbdiv, postdiv1, postdiv2; 213 unsigned int best_refdiv, best_fbdiv, best_postdiv1, best_postdiv2; 214 unsigned long tmp, best_rate = 0; 215 int ret; 216 217 for_each_pll_limit_range(fbdiv, &limits[PLL_LIMIT_FBDIV]) { 218 for_each_pll_limit_range(refdiv, &limits[PLL_LIMIT_REFDIV]) { 219 u64 vco = sg2044_pll_calc_vco_rate(parent_rate, 220 refdiv, fbdiv); 221 if (!sg2044_clk_fit_limit(vco, &limits[PLL_LIMIT_FOUTVCO])) 222 continue; 223 224 ret = sg2042_pll_compute_postdiv(limits, 225 req_rate, parent_rate, 226 refdiv, fbdiv, 227 &postdiv1, &postdiv2); 228 if (ret) 229 continue; 230 231 tmp = sg2044_pll_calc_rate(parent_rate, 232 refdiv, fbdiv, 233 postdiv1, postdiv2); 234 235 if (pll_is_better_rate(req_rate, tmp, best_rate)) { 236 best_refdiv = refdiv; 237 best_fbdiv = fbdiv; 238 best_postdiv1 = postdiv1; 239 best_postdiv2 = postdiv2; 240 best_rate = tmp; 241 242 if (tmp == req_rate) 243 goto find; 244 } 245 } 246 } 247 248 find: 249 if (best_rate) { 250 *value = FIELD_PREP(PLL_REFDIV_MASK, best_refdiv) | 251 FIELD_PREP(PLL_FBDIV_MASK, best_fbdiv) | 252 FIELD_PREP(PLL_POSTDIV1_MASK, best_postdiv1) | 253 FIELD_PREP(PLL_POSTDIV2_MASK, best_postdiv2); 254 return 0; 255 } 256 257 return -EINVAL; 258 } 259 260 static int sg2044_pll_determine_rate(struct clk_hw *hw, 261 struct clk_rate_request *req) 262 { 263 struct sg2044_pll *pll = hw_to_sg2044_pll(hw); 264 unsigned int value; 265 u64 target; 266 int ret; 267 268 target = clamp(req->rate, pll->pll.limits[PLL_LIMIT_FOUT].min, 269 pll->pll.limits[PLL_LIMIT_FOUT].max); 270 271 ret = sg2044_compute_pll_setting(pll->pll.limits, target, 272 req->best_parent_rate, &value); 273 if (ret < 0) 274 return ret; 275 276 req->rate = sg2044_pll_calc_rate(req->best_parent_rate, 277 FIELD_GET(PLL_REFDIV_MASK, value), 278 FIELD_GET(PLL_FBDIV_MASK, value), 279 FIELD_GET(PLL_POSTDIV1_MASK, value), 280 FIELD_GET(PLL_POSTDIV2_MASK, value)); 281 282 return 0; 283 } 284 285 static int sg2044_pll_poll_update(struct sg2044_pll *pll) 286 { 287 int ret; 288 unsigned int value; 289 290 ret = regmap_read_poll_timeout_atomic(pll->common.regmap, 291 pll->syscon_offset + pll->pll.status_offset, 292 value, 293 (value & BIT(pll->pll.status_lock_bit)), 294 1, 100000); 295 if (ret) 296 return ret; 297 298 return regmap_read_poll_timeout_atomic(pll->common.regmap, 299 pll->syscon_offset + pll->pll.status_offset, 300 value, 301 (!(value & BIT(pll->pll.status_updating_bit))), 302 1, 100000); 303 } 304 305 static int sg2044_pll_enable(struct sg2044_pll *pll, bool en) 306 { 307 if (en) { 308 if (sg2044_pll_poll_update(pll) < 0) 309 pr_warn("%s: fail to lock pll\n", clk_hw_get_name(&pll->common.hw)); 310 311 return regmap_set_bits(pll->common.regmap, 312 pll->syscon_offset + pll->pll.enable_offset, 313 BIT(pll->pll.enable_bit)); 314 } 315 316 return regmap_clear_bits(pll->common.regmap, 317 pll->syscon_offset + pll->pll.enable_offset, 318 BIT(pll->pll.enable_bit)); 319 } 320 321 static int sg2044_pll_update_vcosel(struct sg2044_pll *pll, u64 rate) 322 { 323 unsigned int sel; 324 325 if (rate < U64_C(2400000000)) 326 sel = PLL_VCOSEL_1G6; 327 else 328 sel = PLL_VCOSEL_2G4; 329 330 return regmap_write_bits(pll->common.regmap, 331 pll->syscon_offset + pll->pll.ctrl_offset, 332 PLL_VCOSEL_MASK, 333 FIELD_PREP(PLL_VCOSEL_MASK, sel)); 334 } 335 336 static int sg2044_pll_set_rate(struct clk_hw *hw, 337 unsigned long rate, unsigned long parent_rate) 338 { 339 struct sg2044_pll *pll = hw_to_sg2044_pll(hw); 340 unsigned int value; 341 u64 vco; 342 int ret; 343 344 ret = sg2044_compute_pll_setting(pll->pll.limits, rate, 345 parent_rate, &value); 346 if (ret < 0) 347 return ret; 348 349 vco = sg2044_pll_calc_vco_rate(parent_rate, 350 FIELD_GET(PLL_REFDIV_MASK, value), 351 FIELD_GET(PLL_FBDIV_MASK, value)); 352 353 value |= PLL_CALIBRATE_EN; 354 value |= PLL_CALIBRATE_DEFAULT; 355 value |= PLL_UPDATE_EN; 356 357 guard(spinlock_irqsave)(pll->common.lock); 358 359 ret = sg2044_pll_enable(pll, false); 360 if (ret) 361 return ret; 362 363 sg2044_pll_update_vcosel(pll, vco); 364 365 regmap_write_bits(pll->common.regmap, 366 pll->syscon_offset + pll->pll.ctrl_offset + 367 PLL_HIGH_CTRL_OFFSET, 368 PLL_HIGH_CTRL_MASK, value); 369 370 sg2044_pll_enable(pll, true); 371 372 return ret; 373 } 374 375 static const struct clk_ops sg2044_pll_ops = { 376 .recalc_rate = sg2044_pll_recalc_rate, 377 .determine_rate = sg2044_pll_determine_rate, 378 .set_rate = sg2044_pll_set_rate, 379 }; 380 381 static const struct clk_ops sg2044_pll_ro_ops = { 382 .recalc_rate = sg2044_pll_recalc_rate, 383 }; 384 385 #define SG2044_CLK_COMMON_PDATA(_id, _name, _parents, _op, _flags) \ 386 { \ 387 .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parents, \ 388 _op, (_flags)), \ 389 .id = (_id), \ 390 } 391 392 #define DEFINE_SG2044_PLL(_id, _name, _parent, _flags, \ 393 _ctrl_offset, \ 394 _status_offset, _status_lock_bit, \ 395 _status_updating_bit, \ 396 _enable_offset, _enable_bit, \ 397 _limits) \ 398 struct sg2044_pll _name = { \ 399 .common = SG2044_CLK_COMMON_PDATA(_id, #_name, _parent, \ 400 &sg2044_pll_ops, \ 401 (_flags)), \ 402 .pll = { \ 403 .ctrl_offset = (_ctrl_offset), \ 404 .status_offset = (_status_offset), \ 405 .enable_offset = (_enable_offset), \ 406 .status_lock_bit = (_status_lock_bit), \ 407 .status_updating_bit = (_status_updating_bit), \ 408 .enable_bit = (_enable_bit), \ 409 .limits = (_limits), \ 410 }, \ 411 } 412 413 #define DEFINE_SG2044_PLL_RO(_id, _name, _parent, _flags, \ 414 _ctrl_offset, \ 415 _status_offset, _status_lock_bit, \ 416 _status_updating_bit, \ 417 _enable_offset, _enable_bit, \ 418 _limits) \ 419 struct sg2044_pll _name = { \ 420 .common = SG2044_CLK_COMMON_PDATA(_id, #_name, _parent, \ 421 &sg2044_pll_ro_ops, \ 422 (_flags)), \ 423 .pll = { \ 424 .ctrl_offset = (_ctrl_offset), \ 425 .status_offset = (_status_offset), \ 426 .enable_offset = (_enable_offset), \ 427 .status_lock_bit = (_status_lock_bit), \ 428 .status_updating_bit = (_status_updating_bit), \ 429 .enable_bit = (_enable_bit), \ 430 .limits = (_limits), \ 431 }, \ 432 } 433 434 static const struct clk_parent_data osc_parents[] = { 435 { .index = 0 }, 436 }; 437 438 static const struct sg2044_pll_limit pll_limits[] = { 439 [PLL_LIMIT_FOUTVCO] = { 440 .min = U64_C(1600000000), 441 .max = U64_C(3200000000), 442 }, 443 [PLL_LIMIT_FOUT] = { 444 .min = U64_C(25000), 445 .max = U64_C(3200000000), 446 }, 447 [PLL_LIMIT_REFDIV] = { 448 .min = U64_C(1), 449 .max = U64_C(63), 450 }, 451 [PLL_LIMIT_FBDIV] = { 452 .min = U64_C(8), 453 .max = U64_C(1066), 454 }, 455 [PLL_LIMIT_POSTDIV1] = { 456 .min = U64_C(0), 457 .max = U64_C(7), 458 }, 459 [PLL_LIMIT_POSTDIV2] = { 460 .min = U64_C(0), 461 .max = U64_C(7), 462 }, 463 }; 464 465 static DEFINE_SG2044_PLL_RO(CLK_FPLL0, clk_fpll0, osc_parents, CLK_IS_CRITICAL, 466 0x58, 0x00, 22, 6, 467 0x04, 6, pll_limits); 468 469 static DEFINE_SG2044_PLL_RO(CLK_FPLL1, clk_fpll1, osc_parents, CLK_IS_CRITICAL, 470 0x60, 0x00, 23, 7, 471 0x04, 7, pll_limits); 472 473 static DEFINE_SG2044_PLL_RO(CLK_FPLL2, clk_fpll2, osc_parents, CLK_IS_CRITICAL, 474 0x20, 0x08, 16, 0, 475 0x0c, 0, pll_limits); 476 477 static DEFINE_SG2044_PLL_RO(CLK_DPLL0, clk_dpll0, osc_parents, CLK_IS_CRITICAL, 478 0x68, 0x00, 24, 8, 479 0x04, 8, pll_limits); 480 481 static DEFINE_SG2044_PLL_RO(CLK_DPLL1, clk_dpll1, osc_parents, CLK_IS_CRITICAL, 482 0x70, 0x00, 25, 9, 483 0x04, 9, pll_limits); 484 485 static DEFINE_SG2044_PLL_RO(CLK_DPLL2, clk_dpll2, osc_parents, CLK_IS_CRITICAL, 486 0x78, 0x00, 26, 10, 487 0x04, 10, pll_limits); 488 489 static DEFINE_SG2044_PLL_RO(CLK_DPLL3, clk_dpll3, osc_parents, CLK_IS_CRITICAL, 490 0x80, 0x00, 27, 11, 491 0x04, 11, pll_limits); 492 493 static DEFINE_SG2044_PLL_RO(CLK_DPLL4, clk_dpll4, osc_parents, CLK_IS_CRITICAL, 494 0x88, 0x00, 28, 12, 495 0x04, 12, pll_limits); 496 497 static DEFINE_SG2044_PLL_RO(CLK_DPLL5, clk_dpll5, osc_parents, CLK_IS_CRITICAL, 498 0x90, 0x00, 29, 13, 499 0x04, 13, pll_limits); 500 501 static DEFINE_SG2044_PLL_RO(CLK_DPLL6, clk_dpll6, osc_parents, CLK_IS_CRITICAL, 502 0x98, 0x00, 30, 14, 503 0x04, 14, pll_limits); 504 505 static DEFINE_SG2044_PLL_RO(CLK_DPLL7, clk_dpll7, osc_parents, CLK_IS_CRITICAL, 506 0xa0, 0x00, 31, 15, 507 0x04, 15, pll_limits); 508 509 static DEFINE_SG2044_PLL(CLK_MPLL0, clk_mpll0, osc_parents, CLK_IS_CRITICAL, 510 0x28, 0x00, 16, 0, 511 0x04, 0, pll_limits); 512 513 static DEFINE_SG2044_PLL(CLK_MPLL1, clk_mpll1, osc_parents, CLK_IS_CRITICAL, 514 0x30, 0x00, 17, 1, 515 0x04, 1, pll_limits); 516 517 static DEFINE_SG2044_PLL(CLK_MPLL2, clk_mpll2, osc_parents, CLK_IS_CRITICAL, 518 0x38, 0x00, 18, 2, 519 0x04, 2, pll_limits); 520 521 static DEFINE_SG2044_PLL(CLK_MPLL3, clk_mpll3, osc_parents, CLK_IS_CRITICAL, 522 0x40, 0x00, 19, 3, 523 0x04, 3, pll_limits); 524 525 static DEFINE_SG2044_PLL(CLK_MPLL4, clk_mpll4, osc_parents, CLK_IS_CRITICAL, 526 0x48, 0x00, 20, 4, 527 0x04, 4, pll_limits); 528 529 static DEFINE_SG2044_PLL(CLK_MPLL5, clk_mpll5, osc_parents, CLK_IS_CRITICAL, 530 0x50, 0x00, 21, 5, 531 0x04, 5, pll_limits); 532 533 static struct sg2044_clk_common * const sg2044_pll_commons[] = { 534 &clk_fpll0.common, 535 &clk_fpll1.common, 536 &clk_fpll2.common, 537 &clk_dpll0.common, 538 &clk_dpll1.common, 539 &clk_dpll2.common, 540 &clk_dpll3.common, 541 &clk_dpll4.common, 542 &clk_dpll5.common, 543 &clk_dpll6.common, 544 &clk_dpll7.common, 545 &clk_mpll0.common, 546 &clk_mpll1.common, 547 &clk_mpll2.common, 548 &clk_mpll3.common, 549 &clk_mpll4.common, 550 &clk_mpll5.common, 551 }; 552 553 static int sg2044_pll_init_ctrl(struct device *dev, struct regmap *regmap, 554 struct sg2044_pll_ctrl *ctrl, 555 const struct sg2044_pll_desc_data *desc) 556 { 557 int ret, i; 558 559 spin_lock_init(&ctrl->lock); 560 561 for (i = 0; i < desc->num_pll; i++) { 562 struct sg2044_clk_common *common = desc->pll[i]; 563 struct sg2044_pll *pll = hw_to_sg2044_pll(&common->hw); 564 565 common->lock = &ctrl->lock; 566 common->regmap = regmap; 567 pll->syscon_offset = SG2044_SYSCON_PLL_OFFSET; 568 569 ret = devm_clk_hw_register(dev, &common->hw); 570 if (ret) 571 return ret; 572 573 ctrl->data.hws[common->id] = &common->hw; 574 } 575 576 return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, 577 &ctrl->data); 578 } 579 580 static int sg2044_pll_probe(struct platform_device *pdev) 581 { 582 struct device *dev = &pdev->dev; 583 struct sg2044_pll_ctrl *ctrl; 584 const struct sg2044_pll_desc_data *desc; 585 struct regmap *regmap; 586 587 regmap = device_node_to_regmap(pdev->dev.parent->of_node); 588 if (IS_ERR(regmap)) 589 return dev_err_probe(dev, PTR_ERR(regmap), 590 "fail to get the regmap for PLL\n"); 591 592 desc = (const struct sg2044_pll_desc_data *)platform_get_device_id(pdev)->driver_data; 593 if (!desc) 594 return dev_err_probe(dev, -EINVAL, "no match data for platform\n"); 595 596 ctrl = devm_kzalloc(dev, struct_size(ctrl, data.hws, desc->num_pll), GFP_KERNEL); 597 if (!ctrl) 598 return -ENOMEM; 599 600 ctrl->data.num = desc->num_pll; 601 602 return sg2044_pll_init_ctrl(dev, regmap, ctrl, desc); 603 } 604 605 static const struct sg2044_pll_desc_data sg2044_pll_desc_data = { 606 .pll = sg2044_pll_commons, 607 .num_pll = ARRAY_SIZE(sg2044_pll_commons), 608 }; 609 610 static const struct platform_device_id sg2044_pll_match[] = { 611 { .name = "sg2044-pll", 612 .driver_data = (unsigned long)&sg2044_pll_desc_data }, 613 { /* sentinel */ } 614 }; 615 MODULE_DEVICE_TABLE(platform, sg2044_pll_match); 616 617 static struct platform_driver sg2044_clk_driver = { 618 .probe = sg2044_pll_probe, 619 .driver = { 620 .name = "sg2044-pll", 621 }, 622 .id_table = sg2044_pll_match, 623 }; 624 module_platform_driver(sg2044_clk_driver); 625 626 MODULE_AUTHOR("Inochi Amaoto <inochiama@gmail.com>"); 627 MODULE_DESCRIPTION("Sophgo SG2044 pll clock driver"); 628 MODULE_LICENSE("GPL"); 629