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.

Merge tag 'clk-renesas-rzv2h-plldsi-tag' into renesas-clk-for-v6.19

clk: renesas: rzv2h: Add support for DSI clocks

RZ/V2H Clock Pulse Generator PLLDSI API, shared by clock and MIPI DSI
driver source files.

+672 -11
+505 -7
drivers/clk/renesas/rzv2h-cpg.c
··· 14 14 #include <linux/bitfield.h> 15 15 #include <linux/clk.h> 16 16 #include <linux/clk-provider.h> 17 + #include <linux/clk/renesas.h> 17 18 #include <linux/delay.h> 18 19 #include <linux/init.h> 19 20 #include <linux/iopoll.h> 21 + #include <linux/limits.h> 22 + #include <linux/math.h> 23 + #include <linux/math64.h> 24 + #include <linux/minmax.h> 20 25 #include <linux/mod_devicetable.h> 21 26 #include <linux/module.h> 22 27 #include <linux/of.h> ··· 31 26 #include <linux/refcount.h> 32 27 #include <linux/reset-controller.h> 33 28 #include <linux/string_choices.h> 29 + #include <linux/units.h> 34 30 35 31 #include <dt-bindings/clock/renesas-cpg-mssr.h> 36 32 ··· 53 47 54 48 #define CPG_PLL_STBY(x) ((x)) 55 49 #define CPG_PLL_STBY_RESETB BIT(0) 50 + #define CPG_PLL_STBY_SSC_EN BIT(2) 56 51 #define CPG_PLL_STBY_RESETB_WEN BIT(16) 52 + #define CPG_PLL_STBY_SSC_EN_WEN BIT(18) 57 53 #define CPG_PLL_CLK1(x) ((x) + 0x004) 58 - #define CPG_PLL_CLK1_KDIV(x) ((s16)FIELD_GET(GENMASK(31, 16), (x))) 59 - #define CPG_PLL_CLK1_MDIV(x) FIELD_GET(GENMASK(15, 6), (x)) 60 - #define CPG_PLL_CLK1_PDIV(x) FIELD_GET(GENMASK(5, 0), (x)) 54 + #define CPG_PLL_CLK1_KDIV GENMASK(31, 16) 55 + #define CPG_PLL_CLK1_MDIV GENMASK(15, 6) 56 + #define CPG_PLL_CLK1_PDIV GENMASK(5, 0) 61 57 #define CPG_PLL_CLK2(x) ((x) + 0x008) 62 - #define CPG_PLL_CLK2_SDIV(x) FIELD_GET(GENMASK(2, 0), (x)) 58 + #define CPG_PLL_CLK2_SDIV GENMASK(2, 0) 63 59 #define CPG_PLL_MON(x) ((x) + 0x010) 64 60 #define CPG_PLL_MON_RESETB BIT(0) 65 61 #define CPG_PLL_MON_LOCK BIT(4) ··· 72 64 ((base) + ((((index) * (16))) + (bit))) 73 65 74 66 #define CPG_CLKSTATUS0 (0x700) 67 + 68 + /* On RZ/G3E SoC we have two DSI PLLs */ 69 + #define MAX_CPG_DSI_PLL 2 70 + 71 + /** 72 + * struct rzv2h_pll_dsi_info - PLL DSI information, holds the limits and parameters 73 + * 74 + * @pll_dsi_limits: PLL DSI parameters limits 75 + * @pll_dsi_parameters: Calculated PLL DSI parameters 76 + * @req_pll_dsi_rate: Requested PLL DSI rate 77 + */ 78 + struct rzv2h_pll_dsi_info { 79 + const struct rzv2h_pll_limits *pll_dsi_limits; 80 + struct rzv2h_pll_div_pars pll_dsi_parameters; 81 + unsigned long req_pll_dsi_rate; 82 + }; 75 83 76 84 /** 77 85 * struct rzv2h_cpg_priv - Clock Pulse Generator Private Data ··· 104 80 * @ff_mod_status_ops: Fixed Factor Module Status Clock operations 105 81 * @mstop_count: Array of mstop values 106 82 * @rcdev: Reset controller entity 83 + * @pll_dsi_info: Array of PLL DSI information, holds the limits and parameters 107 84 */ 108 85 struct rzv2h_cpg_priv { 109 86 struct device *dev; ··· 123 98 atomic_t *mstop_count; 124 99 125 100 struct reset_controller_dev rcdev; 101 + 102 + struct rzv2h_pll_dsi_info pll_dsi_info[MAX_CPG_DSI_PLL]; 126 103 }; 127 104 128 105 #define rcdev_to_priv(x) container_of(x, struct rzv2h_cpg_priv, rcdev) ··· 195 168 #define to_rzv2h_ff_mod_status_clk(_hw) \ 196 169 container_of(_hw, struct rzv2h_ff_mod_status_clk, fix.hw) 197 170 171 + /** 172 + * struct rzv2h_plldsi_div_clk - PLL DSI DDIV clock 173 + * 174 + * @dtable: divider table 175 + * @priv: CPG private data 176 + * @hw: divider clk 177 + * @ddiv: divider configuration 178 + */ 179 + struct rzv2h_plldsi_div_clk { 180 + const struct clk_div_table *dtable; 181 + struct rzv2h_cpg_priv *priv; 182 + struct clk_hw hw; 183 + struct ddiv ddiv; 184 + }; 185 + 186 + #define to_plldsi_div_clk(_hw) \ 187 + container_of(_hw, struct rzv2h_plldsi_div_clk, hw) 188 + 189 + #define RZ_V2H_OSC_CLK_IN_MEGA (24 * MEGA) 190 + #define RZV2H_MAX_DIV_TABLES (16) 191 + 192 + /** 193 + * rzv2h_get_pll_pars - Finds the best combination of PLL parameters 194 + * for a given frequency. 195 + * 196 + * @limits: Pointer to the structure containing the limits for the PLL parameters 197 + * @pars: Pointer to the structure where the best calculated PLL parameters values 198 + * will be stored 199 + * @freq_millihz: Target output frequency in millihertz 200 + * 201 + * This function calculates the best set of PLL parameters (M, K, P, S) to achieve 202 + * the desired frequency. 203 + * There is no direct formula to calculate the PLL parameters, as it's an open 204 + * system of equations, therefore this function uses an iterative approach to 205 + * determine the best solution. The best solution is one that minimizes the error 206 + * (desired frequency - actual frequency). 207 + * 208 + * Return: true if a valid set of parameters values is found, false otherwise. 209 + */ 210 + bool rzv2h_get_pll_pars(const struct rzv2h_pll_limits *limits, 211 + struct rzv2h_pll_pars *pars, u64 freq_millihz) 212 + { 213 + u64 fout_min_millihz = mul_u32_u32(limits->fout.min, MILLI); 214 + u64 fout_max_millihz = mul_u32_u32(limits->fout.max, MILLI); 215 + struct rzv2h_pll_pars p, best; 216 + 217 + if (freq_millihz > fout_max_millihz || 218 + freq_millihz < fout_min_millihz) 219 + return false; 220 + 221 + /* Initialize best error to maximum possible value */ 222 + best.error_millihz = S64_MAX; 223 + 224 + for (p.p = limits->p.min; p.p <= limits->p.max; p.p++) { 225 + u32 fref = RZ_V2H_OSC_CLK_IN_MEGA / p.p; 226 + u16 divider; 227 + 228 + for (divider = 1 << limits->s.min, p.s = limits->s.min; 229 + p.s <= limits->s.max; p.s++, divider <<= 1) { 230 + for (p.m = limits->m.min; p.m <= limits->m.max; p.m++) { 231 + u64 output_m, output_k_range; 232 + s64 pll_k, output_k; 233 + u64 fvco, output; 234 + 235 + /* 236 + * The frequency generated by the PLL + divider 237 + * is calculated as follows: 238 + * 239 + * With: 240 + * Freq = Ffout = Ffvco / 2^(pll_s) 241 + * Ffvco = (pll_m + (pll_k / 65536)) * Ffref 242 + * Ffref = 24MHz / pll_p 243 + * 244 + * Freq can also be rewritten as: 245 + * Freq = Ffvco / 2^(pll_s) 246 + * = ((pll_m + (pll_k / 65536)) * Ffref) / 2^(pll_s) 247 + * = (pll_m * Ffref) / 2^(pll_s) + ((pll_k / 65536) * Ffref) / 2^(pll_s) 248 + * = output_m + output_k 249 + * 250 + * Every parameter has been determined at this 251 + * point, but pll_k. 252 + * 253 + * Considering that: 254 + * limits->k.min <= pll_k <= limits->k.max 255 + * Then: 256 + * -0.5 <= (pll_k / 65536) < 0.5 257 + * Therefore: 258 + * -Ffref / (2 * 2^(pll_s)) <= output_k < Ffref / (2 * 2^(pll_s)) 259 + */ 260 + 261 + /* Compute output M component (in mHz) */ 262 + output_m = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(p.m, fref) * MILLI, 263 + divider); 264 + /* Compute range for output K (in mHz) */ 265 + output_k_range = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(fref, MILLI), 266 + 2 * divider); 267 + /* 268 + * No point in continuing if we can't achieve 269 + * the desired frequency 270 + */ 271 + if (freq_millihz < (output_m - output_k_range) || 272 + freq_millihz >= (output_m + output_k_range)) { 273 + continue; 274 + } 275 + 276 + /* 277 + * Compute the K component 278 + * 279 + * Since: 280 + * Freq = output_m + output_k 281 + * Then: 282 + * output_k = Freq - output_m 283 + * = ((pll_k / 65536) * Ffref) / 2^(pll_s) 284 + * Therefore: 285 + * pll_k = (output_k * 65536 * 2^(pll_s)) / Ffref 286 + */ 287 + output_k = freq_millihz - output_m; 288 + pll_k = div_s64(output_k * 65536ULL * divider, 289 + fref); 290 + pll_k = DIV_S64_ROUND_CLOSEST(pll_k, MILLI); 291 + 292 + /* Validate K value within allowed limits */ 293 + if (pll_k < limits->k.min || 294 + pll_k > limits->k.max) 295 + continue; 296 + 297 + p.k = pll_k; 298 + 299 + /* Compute (Ffvco * 65536) */ 300 + fvco = mul_u32_u32(p.m * 65536 + p.k, fref); 301 + if (fvco < mul_u32_u32(limits->fvco.min, 65536) || 302 + fvco > mul_u32_u32(limits->fvco.max, 65536)) 303 + continue; 304 + 305 + /* PLL_M component of (output * 65536 * PLL_P) */ 306 + output = mul_u32_u32(p.m * 65536, RZ_V2H_OSC_CLK_IN_MEGA); 307 + /* PLL_K component of (output * 65536 * PLL_P) */ 308 + output += p.k * RZ_V2H_OSC_CLK_IN_MEGA; 309 + /* Make it in mHz */ 310 + output *= MILLI; 311 + output = DIV_U64_ROUND_CLOSEST(output, 65536 * p.p * divider); 312 + 313 + /* Check output frequency against limits */ 314 + if (output < fout_min_millihz || 315 + output > fout_max_millihz) 316 + continue; 317 + 318 + p.error_millihz = freq_millihz - output; 319 + p.freq_millihz = output; 320 + 321 + /* If an exact match is found, return immediately */ 322 + if (p.error_millihz == 0) { 323 + *pars = p; 324 + return true; 325 + } 326 + 327 + /* Update best match if error is smaller */ 328 + if (abs(best.error_millihz) > abs(p.error_millihz)) 329 + best = p; 330 + } 331 + } 332 + } 333 + 334 + /* If no valid parameters were found, return false */ 335 + if (best.error_millihz == S64_MAX) 336 + return false; 337 + 338 + *pars = best; 339 + return true; 340 + } 341 + EXPORT_SYMBOL_NS_GPL(rzv2h_get_pll_pars, "RZV2H_CPG"); 342 + 343 + /* 344 + * rzv2h_get_pll_divs_pars - Finds the best combination of PLL parameters 345 + * and divider value for a given frequency. 346 + * 347 + * @limits: Pointer to the structure containing the limits for the PLL parameters 348 + * @pars: Pointer to the structure where the best calculated PLL parameters and 349 + * divider values will be stored 350 + * @table: Pointer to the array of valid divider values 351 + * @table_size: Size of the divider values array 352 + * @freq_millihz: Target output frequency in millihertz 353 + * 354 + * This function calculates the best set of PLL parameters (M, K, P, S) and divider 355 + * value to achieve the desired frequency. See rzv2h_get_pll_pars() for more details 356 + * on how the PLL parameters are calculated. 357 + * 358 + * freq_millihz is the desired frequency generated by the PLL followed by a 359 + * a gear. 360 + */ 361 + bool rzv2h_get_pll_divs_pars(const struct rzv2h_pll_limits *limits, 362 + struct rzv2h_pll_div_pars *pars, 363 + const u8 *table, u8 table_size, u64 freq_millihz) 364 + { 365 + struct rzv2h_pll_div_pars p, best; 366 + 367 + best.div.error_millihz = S64_MAX; 368 + p.div.error_millihz = S64_MAX; 369 + for (unsigned int i = 0; i < table_size; i++) { 370 + if (!rzv2h_get_pll_pars(limits, &p.pll, freq_millihz * table[i])) 371 + continue; 372 + 373 + p.div.divider_value = table[i]; 374 + p.div.freq_millihz = DIV_U64_ROUND_CLOSEST(p.pll.freq_millihz, table[i]); 375 + p.div.error_millihz = freq_millihz - p.div.freq_millihz; 376 + 377 + if (p.div.error_millihz == 0) { 378 + *pars = p; 379 + return true; 380 + } 381 + 382 + if (abs(best.div.error_millihz) > abs(p.div.error_millihz)) 383 + best = p; 384 + } 385 + 386 + if (best.div.error_millihz == S64_MAX) 387 + return false; 388 + 389 + *pars = best; 390 + return true; 391 + } 392 + EXPORT_SYMBOL_NS_GPL(rzv2h_get_pll_divs_pars, "RZV2H_CPG"); 393 + 394 + static unsigned long rzv2h_cpg_plldsi_div_recalc_rate(struct clk_hw *hw, 395 + unsigned long parent_rate) 396 + { 397 + struct rzv2h_plldsi_div_clk *dsi_div = to_plldsi_div_clk(hw); 398 + struct rzv2h_cpg_priv *priv = dsi_div->priv; 399 + struct ddiv ddiv = dsi_div->ddiv; 400 + u32 div; 401 + 402 + div = readl(priv->base + ddiv.offset); 403 + div >>= ddiv.shift; 404 + div &= clk_div_mask(ddiv.width); 405 + div = dsi_div->dtable[div].div; 406 + 407 + return DIV_ROUND_CLOSEST_ULL(parent_rate, div); 408 + } 409 + 410 + static int rzv2h_cpg_plldsi_div_determine_rate(struct clk_hw *hw, 411 + struct clk_rate_request *req) 412 + { 413 + struct rzv2h_plldsi_div_clk *dsi_div = to_plldsi_div_clk(hw); 414 + struct pll_clk *pll_clk = to_pll(clk_hw_get_parent(hw)); 415 + struct rzv2h_cpg_priv *priv = dsi_div->priv; 416 + u8 table[RZV2H_MAX_DIV_TABLES] = { 0 }; 417 + struct rzv2h_pll_div_pars *dsi_params; 418 + struct rzv2h_pll_dsi_info *dsi_info; 419 + const struct clk_div_table *div; 420 + unsigned int i = 0; 421 + u64 rate_millihz; 422 + 423 + dsi_info = &priv->pll_dsi_info[pll_clk->pll.instance]; 424 + dsi_params = &dsi_info->pll_dsi_parameters; 425 + 426 + rate_millihz = mul_u32_u32(req->rate, MILLI); 427 + if (rate_millihz == dsi_params->div.error_millihz + dsi_params->div.freq_millihz) 428 + goto exit_determine_rate; 429 + 430 + for (div = dsi_div->dtable; div->div; div++) { 431 + if (i >= RZV2H_MAX_DIV_TABLES) 432 + return -EINVAL; 433 + table[i++] = div->div; 434 + } 435 + 436 + if (!rzv2h_get_pll_divs_pars(dsi_info->pll_dsi_limits, dsi_params, table, i, 437 + rate_millihz)) { 438 + dev_err(priv->dev, "failed to determine rate for req->rate: %lu\n", 439 + req->rate); 440 + return -EINVAL; 441 + } 442 + 443 + exit_determine_rate: 444 + req->rate = DIV_ROUND_CLOSEST_ULL(dsi_params->div.freq_millihz, MILLI); 445 + req->best_parent_rate = req->rate * dsi_params->div.divider_value; 446 + dsi_info->req_pll_dsi_rate = req->best_parent_rate; 447 + 448 + return 0; 449 + } 450 + 451 + static int rzv2h_cpg_plldsi_div_set_rate(struct clk_hw *hw, 452 + unsigned long rate, 453 + unsigned long parent_rate) 454 + { 455 + struct rzv2h_plldsi_div_clk *dsi_div = to_plldsi_div_clk(hw); 456 + struct pll_clk *pll_clk = to_pll(clk_hw_get_parent(hw)); 457 + struct rzv2h_cpg_priv *priv = dsi_div->priv; 458 + struct rzv2h_pll_div_pars *dsi_params; 459 + struct rzv2h_pll_dsi_info *dsi_info; 460 + struct ddiv ddiv = dsi_div->ddiv; 461 + const struct clk_div_table *clkt; 462 + bool divider_found = false; 463 + u32 val, shift; 464 + 465 + dsi_info = &priv->pll_dsi_info[pll_clk->pll.instance]; 466 + dsi_params = &dsi_info->pll_dsi_parameters; 467 + 468 + for (clkt = dsi_div->dtable; clkt->div; clkt++) { 469 + if (clkt->div == dsi_params->div.divider_value) { 470 + divider_found = true; 471 + break; 472 + } 473 + } 474 + 475 + if (!divider_found) 476 + return -EINVAL; 477 + 478 + shift = ddiv.shift; 479 + val = readl(priv->base + ddiv.offset) | DDIV_DIVCTL_WEN(shift); 480 + val &= ~(clk_div_mask(ddiv.width) << shift); 481 + val |= clkt->val << shift; 482 + writel(val, priv->base + ddiv.offset); 483 + 484 + return 0; 485 + } 486 + 487 + static const struct clk_ops rzv2h_cpg_plldsi_div_ops = { 488 + .recalc_rate = rzv2h_cpg_plldsi_div_recalc_rate, 489 + .determine_rate = rzv2h_cpg_plldsi_div_determine_rate, 490 + .set_rate = rzv2h_cpg_plldsi_div_set_rate, 491 + }; 492 + 493 + static struct clk * __init 494 + rzv2h_cpg_plldsi_div_clk_register(const struct cpg_core_clk *core, 495 + struct rzv2h_cpg_priv *priv) 496 + { 497 + struct rzv2h_plldsi_div_clk *clk_hw_data; 498 + struct clk **clks = priv->clks; 499 + struct clk_init_data init; 500 + const struct clk *parent; 501 + const char *parent_name; 502 + struct clk_hw *clk_hw; 503 + int ret; 504 + 505 + parent = clks[core->parent]; 506 + if (IS_ERR(parent)) 507 + return ERR_CAST(parent); 508 + 509 + clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL); 510 + if (!clk_hw_data) 511 + return ERR_PTR(-ENOMEM); 512 + 513 + clk_hw_data->priv = priv; 514 + clk_hw_data->ddiv = core->cfg.ddiv; 515 + clk_hw_data->dtable = core->dtable; 516 + 517 + parent_name = __clk_get_name(parent); 518 + init.name = core->name; 519 + init.ops = &rzv2h_cpg_plldsi_div_ops; 520 + init.flags = core->flag; 521 + init.parent_names = &parent_name; 522 + init.num_parents = 1; 523 + 524 + clk_hw = &clk_hw_data->hw; 525 + clk_hw->init = &init; 526 + 527 + ret = devm_clk_hw_register(priv->dev, clk_hw); 528 + if (ret) 529 + return ERR_PTR(ret); 530 + 531 + return clk_hw->clk; 532 + } 533 + 534 + static int rzv2h_cpg_plldsi_determine_rate(struct clk_hw *hw, 535 + struct clk_rate_request *req) 536 + { 537 + struct pll_clk *pll_clk = to_pll(hw); 538 + struct rzv2h_cpg_priv *priv = pll_clk->priv; 539 + struct rzv2h_pll_dsi_info *dsi_info; 540 + u64 rate_millihz; 541 + 542 + dsi_info = &priv->pll_dsi_info[pll_clk->pll.instance]; 543 + /* check if the divider has already invoked the algorithm */ 544 + if (req->rate == dsi_info->req_pll_dsi_rate) 545 + return 0; 546 + 547 + /* If the req->rate doesn't match we do the calculation assuming there is no divider */ 548 + rate_millihz = mul_u32_u32(req->rate, MILLI); 549 + if (!rzv2h_get_pll_pars(dsi_info->pll_dsi_limits, 550 + &dsi_info->pll_dsi_parameters.pll, rate_millihz)) { 551 + dev_err(priv->dev, 552 + "failed to determine rate for req->rate: %lu\n", 553 + req->rate); 554 + return -EINVAL; 555 + } 556 + 557 + req->rate = DIV_ROUND_CLOSEST_ULL(dsi_info->pll_dsi_parameters.pll.freq_millihz, MILLI); 558 + dsi_info->req_pll_dsi_rate = req->rate; 559 + 560 + return 0; 561 + } 562 + 563 + static int rzv2h_cpg_pll_set_rate(struct pll_clk *pll_clk, 564 + struct rzv2h_pll_pars *params, 565 + bool ssc_disable) 566 + { 567 + struct rzv2h_cpg_priv *priv = pll_clk->priv; 568 + u16 offset = pll_clk->pll.offset; 569 + u32 val; 570 + int ret; 571 + 572 + /* Put PLL into standby mode */ 573 + writel(CPG_PLL_STBY_RESETB_WEN, priv->base + CPG_PLL_STBY(offset)); 574 + ret = readl_poll_timeout_atomic(priv->base + CPG_PLL_MON(offset), 575 + val, !(val & CPG_PLL_MON_LOCK), 576 + 100, 2000); 577 + if (ret) { 578 + dev_err(priv->dev, "Failed to put PLLDSI into standby mode"); 579 + return ret; 580 + } 581 + 582 + /* Output clock setting 1 */ 583 + writel(FIELD_PREP(CPG_PLL_CLK1_KDIV, (u16)params->k) | 584 + FIELD_PREP(CPG_PLL_CLK1_MDIV, params->m) | 585 + FIELD_PREP(CPG_PLL_CLK1_PDIV, params->p), 586 + priv->base + CPG_PLL_CLK1(offset)); 587 + 588 + /* Output clock setting 2 */ 589 + val = readl(priv->base + CPG_PLL_CLK2(offset)); 590 + writel((val & ~CPG_PLL_CLK2_SDIV) | FIELD_PREP(CPG_PLL_CLK2_SDIV, params->s), 591 + priv->base + CPG_PLL_CLK2(offset)); 592 + 593 + /* Put PLL to normal mode */ 594 + if (ssc_disable) 595 + val = CPG_PLL_STBY_SSC_EN_WEN; 596 + else 597 + val = CPG_PLL_STBY_SSC_EN_WEN | CPG_PLL_STBY_SSC_EN; 598 + writel(val | CPG_PLL_STBY_RESETB_WEN | CPG_PLL_STBY_RESETB, 599 + priv->base + CPG_PLL_STBY(offset)); 600 + 601 + /* PLL normal mode transition, output clock stability check */ 602 + ret = readl_poll_timeout_atomic(priv->base + CPG_PLL_MON(offset), 603 + val, (val & CPG_PLL_MON_LOCK), 604 + 100, 2000); 605 + if (ret) { 606 + dev_err(priv->dev, "Failed to put PLLDSI into normal mode"); 607 + return ret; 608 + } 609 + 610 + return 0; 611 + } 612 + 613 + static int rzv2h_cpg_plldsi_set_rate(struct clk_hw *hw, unsigned long rate, 614 + unsigned long parent_rate) 615 + { 616 + struct pll_clk *pll_clk = to_pll(hw); 617 + struct rzv2h_pll_dsi_info *dsi_info; 618 + struct rzv2h_cpg_priv *priv = pll_clk->priv; 619 + 620 + dsi_info = &priv->pll_dsi_info[pll_clk->pll.instance]; 621 + 622 + return rzv2h_cpg_pll_set_rate(pll_clk, &dsi_info->pll_dsi_parameters.pll, true); 623 + } 624 + 198 625 static int rzv2h_cpg_pll_clk_is_enabled(struct clk_hw *hw) 199 626 { 200 627 struct pll_clk *pll_clk = to_pll(hw); ··· 712 231 clk1 = readl(priv->base + CPG_PLL_CLK1(pll.offset)); 713 232 clk2 = readl(priv->base + CPG_PLL_CLK2(pll.offset)); 714 233 715 - rate = mul_u64_u32_shr(parent_rate, (CPG_PLL_CLK1_MDIV(clk1) << 16) + 716 - CPG_PLL_CLK1_KDIV(clk1), 16 + CPG_PLL_CLK2_SDIV(clk2)); 234 + rate = mul_u64_u32_shr(parent_rate, (FIELD_GET(CPG_PLL_CLK1_MDIV, clk1) << 16) + 235 + (s16)FIELD_GET(CPG_PLL_CLK1_KDIV, clk1), 236 + 16 + FIELD_GET(CPG_PLL_CLK2_SDIV, clk2)); 717 237 718 - return DIV_ROUND_CLOSEST_ULL(rate, CPG_PLL_CLK1_PDIV(clk1)); 238 + return DIV_ROUND_CLOSEST_ULL(rate, FIELD_GET(CPG_PLL_CLK1_PDIV, clk1)); 719 239 } 240 + 241 + static const struct clk_ops rzv2h_cpg_plldsi_ops = { 242 + .recalc_rate = rzv2h_cpg_pll_clk_recalc_rate, 243 + .determine_rate = rzv2h_cpg_plldsi_determine_rate, 244 + .set_rate = rzv2h_cpg_plldsi_set_rate, 245 + }; 720 246 721 247 static const struct clk_ops rzv2h_cpg_pll_ops = { 722 248 .is_enabled = rzv2h_cpg_pll_clk_is_enabled, ··· 750 262 pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL); 751 263 if (!pll_clk) 752 264 return ERR_PTR(-ENOMEM); 265 + 266 + if (core->type == CLK_TYPE_PLLDSI) 267 + priv->pll_dsi_info[core->cfg.pll.instance].pll_dsi_limits = 268 + core->cfg.pll.limits; 753 269 754 270 parent_name = __clk_get_name(parent); 755 271 init.name = core->name; ··· 1078 586 break; 1079 587 case CLK_TYPE_SMUX: 1080 588 clk = rzv2h_cpg_mux_clk_register(core, priv); 589 + break; 590 + case CLK_TYPE_PLLDSI: 591 + clk = rzv2h_cpg_pll_clk_register(core, priv, &rzv2h_cpg_plldsi_ops); 592 + break; 593 + case CLK_TYPE_PLLDSI_DIV: 594 + clk = rzv2h_cpg_plldsi_div_clk_register(core, priv); 1081 595 break; 1082 596 default: 1083 597 goto fail;
+22 -4
drivers/clk/renesas/rzv2h-cpg.h
··· 16 16 * 17 17 * @offset: STBY register offset 18 18 * @has_clkn: Flag to indicate if CLK1/2 are accessible or not 19 + * @instance: PLL instance number 19 20 */ 20 21 struct pll { 21 22 unsigned int offset:9; 22 23 unsigned int has_clkn:1; 24 + unsigned int instance:2; 25 + const struct rzv2h_pll_limits *limits; 23 26 }; 24 27 25 - #define PLL_PACK(_offset, _has_clkn) \ 28 + #define PLL_PACK_LIMITS(_offset, _has_clkn, _instance, _limits) \ 26 29 ((struct pll){ \ 27 30 .offset = _offset, \ 28 - .has_clkn = _has_clkn \ 31 + .has_clkn = _has_clkn, \ 32 + .instance = _instance, \ 33 + .limits = _limits \ 29 34 }) 30 35 31 - #define PLLCA55 PLL_PACK(0x60, 1) 32 - #define PLLGPU PLL_PACK(0x120, 1) 36 + #define PLL_PACK(_offset, _has_clkn, _instance) \ 37 + PLL_PACK_LIMITS(_offset, _has_clkn, _instance, NULL) 38 + 39 + #define PLLCA55 PLL_PACK(0x60, 1, 0) 40 + #define PLLGPU PLL_PACK(0x120, 1, 0) 33 41 34 42 /** 35 43 * struct ddiv - Structure for dynamic switching divider ··· 198 190 CLK_TYPE_PLL, 199 191 CLK_TYPE_DDIV, /* Dynamic Switching Divider */ 200 192 CLK_TYPE_SMUX, /* Static Mux */ 193 + CLK_TYPE_PLLDSI, /* PLLDSI */ 194 + CLK_TYPE_PLLDSI_DIV, /* PLLDSI divider */ 201 195 }; 202 196 203 197 #define DEF_TYPE(_name, _id, _type...) \ ··· 230 220 .num_parents = ARRAY_SIZE(_parent_names), \ 231 221 .flag = CLK_SET_RATE_PARENT, \ 232 222 .mux_flags = CLK_MUX_HIWORD_MASK) 223 + #define DEF_PLLDSI(_name, _id, _parent, _pll_packed) \ 224 + DEF_TYPE(_name, _id, CLK_TYPE_PLLDSI, .parent = _parent, .cfg.pll = _pll_packed) 225 + #define DEF_PLLDSI_DIV(_name, _id, _parent, _ddiv_packed, _dtable) \ 226 + DEF_TYPE(_name, _id, CLK_TYPE_PLLDSI_DIV, \ 227 + .cfg.ddiv = _ddiv_packed, \ 228 + .dtable = _dtable, \ 229 + .parent = _parent, \ 230 + .flag = CLK_SET_RATE_PARENT) 233 231 234 232 /** 235 233 * struct rzv2h_mod_clk - Module Clocks definitions
+145
include/linux/clk/renesas.h
··· 10 10 #ifndef __LINUX_CLK_RENESAS_H_ 11 11 #define __LINUX_CLK_RENESAS_H_ 12 12 13 + #include <linux/clk-provider.h> 13 14 #include <linux/types.h> 15 + #include <linux/units.h> 14 16 15 17 struct device; 16 18 struct device_node; ··· 34 32 #define cpg_mssr_attach_dev NULL 35 33 #define cpg_mssr_detach_dev NULL 36 34 #endif 35 + 36 + /** 37 + * struct rzv2h_pll_limits - PLL parameter constraints 38 + * 39 + * This structure defines the minimum and maximum allowed values for 40 + * various parameters used to configure a PLL. These limits ensure 41 + * the PLL operates within valid and stable ranges. 42 + * 43 + * @fout: Output frequency range (in MHz) 44 + * @fout.min: Minimum allowed output frequency 45 + * @fout.max: Maximum allowed output frequency 46 + * 47 + * @fvco: PLL oscillation frequency range (in MHz) 48 + * @fvco.min: Minimum allowed VCO frequency 49 + * @fvco.max: Maximum allowed VCO frequency 50 + * 51 + * @m: Main-divider range 52 + * @m.min: Minimum main-divider value 53 + * @m.max: Maximum main-divider value 54 + * 55 + * @p: Pre-divider range 56 + * @p.min: Minimum pre-divider value 57 + * @p.max: Maximum pre-divider value 58 + * 59 + * @s: Divider range 60 + * @s.min: Minimum divider value 61 + * @s.max: Maximum divider value 62 + * 63 + * @k: Delta-sigma modulator range (signed) 64 + * @k.min: Minimum delta-sigma value 65 + * @k.max: Maximum delta-sigma value 66 + */ 67 + struct rzv2h_pll_limits { 68 + struct { 69 + u32 min; 70 + u32 max; 71 + } fout; 72 + 73 + struct { 74 + u32 min; 75 + u32 max; 76 + } fvco; 77 + 78 + struct { 79 + u16 min; 80 + u16 max; 81 + } m; 82 + 83 + struct { 84 + u8 min; 85 + u8 max; 86 + } p; 87 + 88 + struct { 89 + u8 min; 90 + u8 max; 91 + } s; 92 + 93 + struct { 94 + s16 min; 95 + s16 max; 96 + } k; 97 + }; 98 + 99 + /** 100 + * struct rzv2h_pll_pars - PLL configuration parameters 101 + * 102 + * This structure contains the configuration parameters for the 103 + * Phase-Locked Loop (PLL), used to achieve a specific output frequency. 104 + * 105 + * @m: Main divider value 106 + * @p: Pre-divider value 107 + * @s: Output divider value 108 + * @k: Delta-sigma modulation value 109 + * @freq_millihz: Calculated PLL output frequency in millihertz 110 + * @error_millihz: Frequency error from target in millihertz (signed) 111 + */ 112 + struct rzv2h_pll_pars { 113 + u16 m; 114 + u8 p; 115 + u8 s; 116 + s16 k; 117 + u64 freq_millihz; 118 + s64 error_millihz; 119 + }; 120 + 121 + /** 122 + * struct rzv2h_pll_div_pars - PLL parameters with post-divider 123 + * 124 + * This structure is used for PLLs that include an additional post-divider 125 + * stage after the main PLL block. It contains both the PLL configuration 126 + * parameters and the resulting frequency/error values after the divider. 127 + * 128 + * @pll: Main PLL configuration parameters (see struct rzv2h_pll_pars) 129 + * 130 + * @div: Post-divider configuration and result 131 + * @div.divider_value: Divider applied to the PLL output 132 + * @div.freq_millihz: Output frequency after divider in millihertz 133 + * @div.error_millihz: Frequency error from target in millihertz (signed) 134 + */ 135 + struct rzv2h_pll_div_pars { 136 + struct rzv2h_pll_pars pll; 137 + struct { 138 + u8 divider_value; 139 + u64 freq_millihz; 140 + s64 error_millihz; 141 + } div; 142 + }; 143 + 144 + #define RZV2H_CPG_PLL_DSI_LIMITS(name) \ 145 + static const struct rzv2h_pll_limits (name) = { \ 146 + .fout = { .min = 25 * MEGA, .max = 375 * MEGA }, \ 147 + .fvco = { .min = 1600 * MEGA, .max = 3200 * MEGA }, \ 148 + .m = { .min = 64, .max = 533 }, \ 149 + .p = { .min = 1, .max = 4 }, \ 150 + .s = { .min = 0, .max = 6 }, \ 151 + .k = { .min = -32768, .max = 32767 }, \ 152 + } \ 153 + 154 + #ifdef CONFIG_CLK_RZV2H 155 + bool rzv2h_get_pll_pars(const struct rzv2h_pll_limits *limits, 156 + struct rzv2h_pll_pars *pars, u64 freq_millihz); 157 + 158 + bool rzv2h_get_pll_divs_pars(const struct rzv2h_pll_limits *limits, 159 + struct rzv2h_pll_div_pars *pars, 160 + const u8 *table, u8 table_size, u64 freq_millihz); 161 + #else 162 + static inline bool rzv2h_get_pll_pars(const struct rzv2h_pll_limits *limits, 163 + struct rzv2h_pll_pars *pars, 164 + u64 freq_millihz) 165 + { 166 + return false; 167 + } 168 + 169 + static inline bool rzv2h_get_pll_divs_pars(const struct rzv2h_pll_limits *limits, 170 + struct rzv2h_pll_div_pars *pars, 171 + const u8 *table, u8 table_size, 172 + u64 freq_millihz) 173 + { 174 + return false; 175 + } 176 + #endif 177 + 37 178 #endif