Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 586 lines 15 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd.. 4 * All rights reserved. 5 * 6 * Authors: 7 * Yifeng Huang <huangyifeng@eswincomputing.com> 8 * Xuyang Dong <dongxuyang@eswincomputing.com> 9 */ 10 11#include <linux/bitfield.h> 12#include <linux/clk-provider.h> 13#include <linux/iopoll.h> 14#include <linux/math.h> 15#include <linux/platform_device.h> 16#include <linux/slab.h> 17 18#include "common.h" 19 20#define PLL_EN_MASK GENMASK(1, 0) 21#define PLL_REFDIV_MASK GENMASK(17, 12) 22#define PLL_FBDIV_MASK GENMASK(31, 20) 23#define PLL_FRAC_MASK GENMASK(27, 4) 24#define PLL_POSTDIV1_MASK GENMASK(10, 8) 25#define PLL_POSTDIV2_MASK GENMASK(18, 16) 26 27struct eswin_clock_data *eswin_clk_init(struct platform_device *pdev, 28 size_t nr_clks) 29{ 30 struct eswin_clock_data *eclk_data; 31 32 eclk_data = devm_kzalloc(&pdev->dev, 33 struct_size(eclk_data, clk_data.hws, nr_clks), 34 GFP_KERNEL); 35 if (!eclk_data) 36 return ERR_PTR(-ENOMEM); 37 38 eclk_data->base = devm_platform_ioremap_resource(pdev, 0); 39 if (IS_ERR(eclk_data->base)) 40 return ERR_PTR(-EINVAL); 41 42 eclk_data->clk_data.num = nr_clks; 43 spin_lock_init(&eclk_data->lock); 44 45 return eclk_data; 46} 47EXPORT_SYMBOL_GPL(eswin_clk_init); 48 49/** 50 * eswin_calc_pll - calculate PLL values 51 * @frac_val: fractional divider 52 * @fbdiv_val: feedback divider 53 * @rate: reference rate 54 * @parent_rate: parent rate 55 * 56 * Calculate PLL values for frac and fbdiv: 57 * fbdiv = rate * 4 / parent_rate 58 * frac = (rate * 4 % parent_rate * (2 ^ 24)) / parent_rate 59 */ 60static void eswin_calc_pll(u32 *frac_val, u32 *fbdiv_val, unsigned long rate, 61 unsigned long parent_rate) 62{ 63 u32 rem; 64 u64 tmp; 65 66 /* step 1: rate * 4 */ 67 tmp = rate * 4; 68 /* step 2: use do_div() to get the quotient(tmp) and remainder(rem) */ 69 rem = do_div(tmp, (u32)parent_rate); 70 /* fbdiv = rate * 4 / parent_rate */ 71 *fbdiv_val = (u32)tmp; 72 /* 73 * step 3: rem << 24 74 * 24: 24-bit fractional accuracy 75 */ 76 tmp = (u64)rem << 24; 77 /* step 4: use do_div() to get the quotient(tmp) */ 78 do_div(tmp, (u32)parent_rate); 79 /* frac = (rate * 4 % parent_rate * (2 ^ 24)) / parent_rate */ 80 *frac_val = (u32)tmp; 81} 82 83static inline struct eswin_clk_pll *to_pll_clk(struct clk_hw *hw) 84{ 85 return container_of(hw, struct eswin_clk_pll, hw); 86} 87 88static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, 89 unsigned long parent_rate) 90{ 91 struct eswin_clk_pll *clk = to_pll_clk(hw); 92 u32 frac_val, fbdiv_val, val, mask; 93 int ret; 94 95 eswin_calc_pll(&frac_val, &fbdiv_val, rate, parent_rate); 96 97 /* First, disable pll */ 98 val = readl_relaxed(clk->ctrl_reg0); 99 val &= ~PLL_EN_MASK; 100 val |= FIELD_PREP(PLL_EN_MASK, 0); 101 writel_relaxed(val, clk->ctrl_reg0); 102 103 val = readl_relaxed(clk->ctrl_reg0); 104 val &= ~(PLL_REFDIV_MASK | PLL_FBDIV_MASK); 105 val |= FIELD_PREP(PLL_FBDIV_MASK, fbdiv_val); 106 val |= FIELD_PREP(PLL_REFDIV_MASK, 1); 107 writel_relaxed(val, clk->ctrl_reg0); 108 109 val = readl_relaxed(clk->ctrl_reg1); 110 val &= ~PLL_FRAC_MASK; 111 val |= FIELD_PREP(PLL_FRAC_MASK, frac_val); 112 writel_relaxed(val, clk->ctrl_reg1); 113 114 val = readl_relaxed(clk->ctrl_reg2); 115 val &= ~(PLL_POSTDIV1_MASK | PLL_POSTDIV2_MASK); 116 val |= FIELD_PREP(PLL_POSTDIV1_MASK, 1); 117 val |= FIELD_PREP(PLL_POSTDIV2_MASK, 1); 118 writel_relaxed(val, clk->ctrl_reg2); 119 120 /* Last, enable pll */ 121 val = readl_relaxed(clk->ctrl_reg0); 122 val &= ~PLL_EN_MASK; 123 val |= FIELD_PREP(PLL_EN_MASK, 1); 124 writel_relaxed(val, clk->ctrl_reg0); 125 126 /* Usually the pll will lock in 50us */ 127 mask = GENMASK(clk->lock_shift + clk->lock_width - 1, clk->lock_shift); 128 ret = readl_poll_timeout(clk->status_reg, val, val & mask, 1, 50 * 2); 129 if (ret) 130 pr_err("failed to lock the pll!\n"); 131 132 return ret; 133} 134 135static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, 136 unsigned long parent_rate) 137{ 138 struct eswin_clk_pll *clk = to_pll_clk(hw); 139 u64 fbdiv_val, frac_val, tmp; 140 u32 rem, val; 141 142 val = readl_relaxed(clk->ctrl_reg0); 143 val &= PLL_FBDIV_MASK; 144 fbdiv_val = (val >> clk->fbdiv_shift); 145 146 val = readl_relaxed(clk->ctrl_reg1); 147 val &= PLL_FRAC_MASK; 148 frac_val = (val >> clk->frac_shift); 149 150 /* rate = 24000000 * (fbdiv + frac / (2 ^ 24)) / 4 */ 151 tmp = parent_rate * frac_val; 152 rem = do_div(tmp, BIT(24)); 153 if (rem) 154 tmp = parent_rate * fbdiv_val + tmp + 1; 155 else 156 tmp = parent_rate * fbdiv_val + tmp; 157 158 do_div(tmp, 4); 159 160 return tmp; 161} 162 163static int clk_pll_determine_rate(struct clk_hw *hw, 164 struct clk_rate_request *req) 165{ 166 struct eswin_clk_pll *clk = to_pll_clk(hw); 167 168 req->rate = clamp(req->rate, clk->min_rate, clk->max_rate); 169 req->min_rate = clk->min_rate; 170 req->max_rate = clk->max_rate; 171 172 return 0; 173} 174 175int eswin_clk_register_fixed_rate(struct device *dev, 176 struct eswin_fixed_rate_clock *clks, 177 int nums, struct eswin_clock_data *data) 178{ 179 struct clk_hw *clk_hw; 180 int i; 181 182 for (i = 0; i < nums; i++) { 183 clk_hw = devm_clk_hw_register_fixed_rate(dev, clks[i].name, 184 NULL, clks[i].flags, 185 clks[i].rate); 186 if (IS_ERR(clk_hw)) 187 return PTR_ERR(clk_hw); 188 189 clks[i].hw = *clk_hw; 190 data->clk_data.hws[clks[i].id] = clk_hw; 191 } 192 193 return 0; 194} 195EXPORT_SYMBOL_GPL(eswin_clk_register_fixed_rate); 196 197static const struct clk_ops eswin_clk_pll_ops = { 198 .set_rate = clk_pll_set_rate, 199 .recalc_rate = clk_pll_recalc_rate, 200 .determine_rate = clk_pll_determine_rate, 201}; 202 203int eswin_clk_register_pll(struct device *dev, struct eswin_pll_clock *clks, 204 int nums, struct eswin_clock_data *data) 205{ 206 struct eswin_clk_pll *p_clk = NULL; 207 struct clk_init_data init; 208 struct clk_hw *clk_hw; 209 int i, ret; 210 211 p_clk = devm_kzalloc(dev, sizeof(*p_clk) * nums, GFP_KERNEL); 212 if (!p_clk) 213 return -ENOMEM; 214 215 for (i = 0; i < nums; i++) { 216 p_clk->id = clks[i].id; 217 p_clk->ctrl_reg0 = data->base + clks[i].ctrl_reg0; 218 p_clk->fbdiv_shift = clks[i].fbdiv_shift; 219 220 p_clk->ctrl_reg1 = data->base + clks[i].ctrl_reg1; 221 p_clk->frac_shift = clks[i].frac_shift; 222 223 p_clk->ctrl_reg2 = data->base + clks[i].ctrl_reg2; 224 225 p_clk->status_reg = data->base + clks[i].status_reg; 226 p_clk->lock_shift = clks[i].lock_shift; 227 p_clk->lock_width = clks[i].lock_width; 228 229 p_clk->max_rate = clks[i].max_rate; 230 p_clk->min_rate = clks[i].min_rate; 231 232 init.name = clks[i].name; 233 init.flags = 0; 234 init.parent_data = clks[i].parent_data; 235 init.num_parents = 1; 236 init.ops = &eswin_clk_pll_ops; 237 p_clk->hw.init = &init; 238 239 clk_hw = &p_clk->hw; 240 241 ret = devm_clk_hw_register(dev, clk_hw); 242 if (ret) 243 return ret; 244 245 clks[i].hw = *clk_hw; 246 data->clk_data.hws[clks[i].id] = clk_hw; 247 p_clk++; 248 } 249 250 return 0; 251} 252EXPORT_SYMBOL_GPL(eswin_clk_register_pll); 253 254int eswin_clk_register_fixed_factor(struct device *dev, 255 struct eswin_fixed_factor_clock *clks, 256 int nums, struct eswin_clock_data *data) 257{ 258 struct clk_hw *clk_hw; 259 int i; 260 261 for (i = 0; i < nums; i++) { 262 clk_hw = devm_clk_hw_register_fixed_factor_index(dev, clks[i].name, 263 clks[i].parent_data->index, 264 clks[i].flags, clks[i].mult, 265 clks[i].div); 266 267 if (IS_ERR(clk_hw)) 268 return PTR_ERR(clk_hw); 269 270 clks[i].hw = *clk_hw; 271 data->clk_data.hws[clks[i].id] = clk_hw; 272 } 273 274 return 0; 275} 276EXPORT_SYMBOL_GPL(eswin_clk_register_fixed_factor); 277 278int eswin_clk_register_mux(struct device *dev, struct eswin_mux_clock *clks, 279 int nums, struct eswin_clock_data *data) 280{ 281 struct clk_hw *clk_hw; 282 int i; 283 284 for (i = 0; i < nums; i++) { 285 clk_hw = devm_clk_hw_register_mux_parent_data_table(dev, clks[i].name, 286 clks[i].parent_data, 287 clks[i].num_parents, 288 clks[i].flags, 289 data->base + clks[i].reg, 290 clks[i].shift, clks[i].width, 291 clks[i].mux_flags, 292 clks[i].table, &data->lock); 293 294 if (IS_ERR(clk_hw)) 295 return PTR_ERR(clk_hw); 296 297 clks[i].hw = *clk_hw; 298 data->clk_data.hws[clks[i].id] = clk_hw; 299 } 300 301 return 0; 302} 303EXPORT_SYMBOL_GPL(eswin_clk_register_mux); 304 305static unsigned int _eswin_get_val(unsigned int div, unsigned long flags, 306 u8 width) 307{ 308 unsigned int maxdiv; 309 310 maxdiv = clk_div_mask(width); 311 div = div > maxdiv ? maxdiv : div; 312 313 if (flags & ESWIN_PRIV_DIV_MIN_2) 314 return (div < 2) ? 2 : div; 315 316 return div; 317} 318 319static unsigned int eswin_div_get_val(unsigned long rate, 320 unsigned long parent_rate, u8 width, 321 unsigned long flags) 322{ 323 unsigned int div; 324 325 div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); 326 327 return _eswin_get_val(div, flags, width); 328} 329 330static inline struct eswin_divider_clock *to_div_clk(struct clk_hw *hw) 331{ 332 return container_of(hw, struct eswin_divider_clock, hw); 333} 334 335static int clk_div_set_rate(struct clk_hw *hw, unsigned long rate, 336 unsigned long parent_rate) 337{ 338 struct eswin_divider_clock *dclk = to_div_clk(hw); 339 unsigned long flags; 340 unsigned int value; 341 u32 val; 342 343 value = eswin_div_get_val(rate, parent_rate, dclk->width, 344 dclk->priv_flag); 345 346 spin_lock_irqsave(dclk->lock, flags); 347 348 val = readl_relaxed(dclk->ctrl_reg); 349 val &= ~(clk_div_mask(dclk->width) << dclk->shift); 350 val |= (u32)value << dclk->shift; 351 writel_relaxed(val, dclk->ctrl_reg); 352 353 spin_unlock_irqrestore(dclk->lock, flags); 354 355 return 0; 356} 357 358static unsigned long clk_div_recalc_rate(struct clk_hw *hw, 359 unsigned long parent_rate) 360{ 361 struct eswin_divider_clock *dclk = to_div_clk(hw); 362 unsigned int div, val; 363 364 val = readl_relaxed(dclk->ctrl_reg) >> dclk->shift; 365 val &= clk_div_mask(dclk->width); 366 div = _eswin_get_val(val, dclk->priv_flag, dclk->width); 367 368 return DIV_ROUND_UP_ULL((u64)parent_rate, div); 369} 370 371static int eswin_clk_bestdiv(unsigned long rate, 372 unsigned long best_parent_rate, u8 width, 373 unsigned long flags) 374{ 375 unsigned long bestdiv, up_rate, down_rate; 376 int up, down; 377 378 if (!rate) 379 rate = 1; 380 381 /* closest round */ 382 up = DIV_ROUND_UP_ULL((u64)best_parent_rate, rate); 383 down = best_parent_rate / rate; 384 385 up_rate = DIV_ROUND_UP_ULL((u64)best_parent_rate, up); 386 down_rate = DIV_ROUND_UP_ULL((u64)best_parent_rate, down); 387 388 bestdiv = (rate - up_rate) <= (down_rate - rate) ? up : down; 389 390 return bestdiv; 391} 392 393static int clk_div_determine_rate(struct clk_hw *hw, 394 struct clk_rate_request *req) 395{ 396 struct eswin_divider_clock *dclk = to_div_clk(hw); 397 int div; 398 399 div = eswin_clk_bestdiv(req->rate, req->best_parent_rate, dclk->width, 400 dclk->priv_flag); 401 div = _eswin_get_val(div, dclk->priv_flag, dclk->width); 402 req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div); 403 404 return 0; 405} 406 407static const struct clk_ops eswin_clk_div_ops = { 408 .set_rate = clk_div_set_rate, 409 .recalc_rate = clk_div_recalc_rate, 410 .determine_rate = clk_div_determine_rate, 411}; 412 413struct clk_hw *eswin_register_clkdiv(struct device *dev, unsigned int id, 414 const char *name, 415 const struct clk_hw *parent_hw, 416 unsigned long flags, void __iomem *reg, 417 u8 shift, u8 width, 418 unsigned long clk_divider_flags, 419 unsigned long priv_flag, spinlock_t *lock) 420{ 421 struct eswin_divider_clock *dclk; 422 struct clk_init_data init; 423 struct clk_hw *clk_hw; 424 int ret; 425 426 dclk = devm_kzalloc(dev, sizeof(*dclk), GFP_KERNEL); 427 if (!dclk) 428 return ERR_PTR(-ENOMEM); 429 430 init.name = name; 431 init.ops = &eswin_clk_div_ops; 432 init.flags = flags; 433 init.parent_hws = &parent_hw; 434 init.num_parents = 1; 435 436 /* struct clk_divider assignments */ 437 dclk->id = id; 438 dclk->ctrl_reg = reg; 439 dclk->shift = shift; 440 dclk->width = width; 441 dclk->div_flags = clk_divider_flags; 442 dclk->priv_flag = priv_flag; 443 dclk->lock = lock; 444 dclk->hw.init = &init; 445 446 /* register the clock */ 447 clk_hw = &dclk->hw; 448 ret = devm_clk_hw_register(dev, clk_hw); 449 if (ret) { 450 dev_err(dev, "failed to register divider clock!\n"); 451 return ERR_PTR(ret); 452 } 453 454 return clk_hw; 455} 456EXPORT_SYMBOL_GPL(eswin_register_clkdiv); 457 458int eswin_clk_register_divider(struct device *dev, 459 struct eswin_divider_clock *clks, 460 int nums, struct eswin_clock_data *data) 461{ 462 struct clk_hw *clk_hw; 463 int i; 464 465 for (i = 0; i < nums; i++) { 466 clk_hw = devm_clk_hw_register_divider_parent_data(dev, clks[i].name, 467 clks[i].parent_data, 468 clks[i].flags, 469 data->base + clks[i].reg, 470 clks[i].shift, clks[i].width, 471 clks[i].div_flags, &data->lock); 472 473 if (IS_ERR(clk_hw)) 474 return PTR_ERR(clk_hw); 475 476 clks[i].hw = *clk_hw; 477 data->clk_data.hws[clks[i].id] = clk_hw; 478 } 479 480 return 0; 481} 482EXPORT_SYMBOL_GPL(eswin_clk_register_divider); 483 484int eswin_clk_register_gate(struct device *dev, struct eswin_gate_clock *clks, 485 int nums, struct eswin_clock_data *data) 486{ 487 struct clk_hw *clk_hw; 488 int i; 489 490 for (i = 0; i < nums; i++) { 491 clk_hw = devm_clk_hw_register_gate_parent_data(dev, clks[i].name, 492 clks[i].parent_data, 493 clks[i].flags, 494 data->base + clks[i].reg, 495 clks[i].bit_idx, clks[i].gate_flags, 496 &data->lock); 497 498 if (IS_ERR(clk_hw)) 499 return PTR_ERR(clk_hw); 500 501 clks[i].hw = *clk_hw; 502 data->clk_data.hws[clks[i].id] = clk_hw; 503 } 504 505 return 0; 506} 507EXPORT_SYMBOL_GPL(eswin_clk_register_gate); 508 509int eswin_clk_register_clks(struct device *dev, struct eswin_clk_info *clks, 510 int nums, struct eswin_clock_data *data) 511{ 512 struct eswin_clk_info *info; 513 const struct clk_hw *phw = NULL; 514 struct clk_hw *hw; 515 int i; 516 517 for (i = 0; i < nums; i++) { 518 info = &clks[i]; 519 switch (info->type) { 520 case CLK_FIXED_FACTOR: { 521 const struct eswin_fixed_factor_clock *factor; 522 523 factor = &info->data.factor; 524 phw = data->clk_data.hws[info->pid]; 525 hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, factor->name, phw, 526 factor->flags, 527 factor->mult, 528 factor->div); 529 break; 530 } 531 case CLK_MUX: { 532 const struct eswin_mux_clock *mux = &info->data.mux; 533 534 hw = devm_clk_hw_register_mux_parent_data_table(dev, mux->name, 535 mux->parent_data, 536 mux->num_parents, 537 mux->flags, 538 data->base + mux->reg, 539 mux->shift, mux->width, 540 mux->mux_flags, 541 mux->table, &data->lock); 542 break; 543 } 544 case CLK_DIVIDER: { 545 const struct eswin_divider_clock *div = &info->data.div; 546 547 phw = data->clk_data.hws[info->pid]; 548 if (div->priv_flag) 549 hw = eswin_register_clkdiv(dev, div->id, div->name, phw, 550 div->flags, data->base + div->reg, 551 div->shift, div->width, div->div_flags, 552 div->priv_flag, &data->lock); 553 else 554 hw = devm_clk_hw_register_divider_parent_hw(dev, div->name, phw, 555 div->flags, 556 data->base + div->reg, 557 div->shift, div->width, 558 div->div_flags, 559 &data->lock); 560 break; 561 } 562 case CLK_GATE: { 563 const struct eswin_gate_clock *gate = &info->data.gate; 564 565 phw = data->clk_data.hws[info->pid]; 566 hw = devm_clk_hw_register_gate_parent_hw(dev, gate->name, phw, 567 gate->flags, 568 data->base + gate->reg, 569 gate->bit_idx, gate->gate_flags, 570 &data->lock); 571 break; 572 } 573 default: 574 dev_err(dev, "Unidentifiable clock type!\n"); 575 return -EINVAL; 576 } 577 if (IS_ERR(hw)) 578 return PTR_ERR(hw); 579 580 info->hw = *hw; 581 data->clk_data.hws[info->id] = hw; 582 } 583 584 return 0; 585} 586EXPORT_SYMBOL_GPL(eswin_clk_register_clks);