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

clk: keystone: sci-clk: probe clocks from DT instead of firmware

Probing all the available clocks from the PM firmware takes quite a lot
of time, increasing boot time. Instead, implement functionality that
parses only the used clocks from DT, and registers these to clock core.
This way, the boot time is greatly improved.

Additionally, provide a Kconfig option for parsing all the clocks from
firmware, if someone requires this. It is mostly useful as a debugging
functionality if we want to inspect the whole clock tree.

Acked-by: Santosh Shilimkar <ssantosh@kernel.org>
Signed-off-by: Tero Kristo <t-kristo@ti.com>

+141
+11
drivers/clk/keystone/Kconfig
··· 14 14 This adds the clock driver support over TI System Control Interface. 15 15 If you wish to use clock resources from the PMMC firmware, say Y. 16 16 Otherwise, say N. 17 + 18 + config TI_SCI_CLK_PROBE_FROM_FW 19 + bool "Probe available clocks from firmware" 20 + depends on TI_SCI_CLK 21 + default n 22 + help 23 + Forces the TI SCI clock driver to probe available clocks from the 24 + firmware. By default, only the used clocks are probed from DT. 25 + This is mostly only useful for debugging purposes, and will 26 + increase the boot time of the device. If you want the clocks probed 27 + from firmware, say Y. Otherwise, say N.
+130
drivers/clk/keystone/sci-clk.c
··· 23 23 #include <linux/slab.h> 24 24 #include <linux/soc/ti/ti_sci_protocol.h> 25 25 #include <linux/bsearch.h> 26 + #include <linux/list_sort.h> 26 27 27 28 #define SCI_CLK_SSC_ENABLE BIT(0) 28 29 #define SCI_CLK_ALLOW_FREQ_CHANGE BIT(1) ··· 53 52 * @num_parents: Number of parents for this clock 54 53 * @provider: Master clock provider 55 54 * @flags: Flags for the clock 55 + * @node: Link for handling clocks probed via DT 56 56 */ 57 57 struct sci_clk { 58 58 struct clk_hw hw; ··· 62 60 u8 num_parents; 63 61 struct sci_clk_provider *provider; 64 62 u8 flags; 63 + struct list_head node; 65 64 }; 66 65 67 66 #define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw) ··· 406 403 }; 407 404 MODULE_DEVICE_TABLE(of, ti_sci_clk_of_match); 408 405 406 + #ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW 409 407 static int ti_sci_scan_clocks_from_fw(struct sci_clk_provider *provider) 410 408 { 411 409 int ret; ··· 483 479 return 0; 484 480 } 485 481 482 + #else 483 + 484 + static int _cmp_sci_clk_list(void *priv, struct list_head *a, 485 + struct list_head *b) 486 + { 487 + struct sci_clk *ca = container_of(a, struct sci_clk, node); 488 + struct sci_clk *cb = container_of(b, struct sci_clk, node); 489 + 490 + return _cmp_sci_clk(ca, &cb); 491 + } 492 + 493 + static int ti_sci_scan_clocks_from_dt(struct sci_clk_provider *provider) 494 + { 495 + struct device *dev = provider->dev; 496 + struct device_node *np = NULL; 497 + int ret; 498 + int index; 499 + struct of_phandle_args args; 500 + struct list_head clks; 501 + struct sci_clk *sci_clk, *prev; 502 + int num_clks = 0; 503 + int num_parents; 504 + int clk_id; 505 + const char * const clk_names[] = { 506 + "clocks", "assigned-clocks", "assigned-clock-parents", NULL 507 + }; 508 + const char * const *clk_name; 509 + 510 + INIT_LIST_HEAD(&clks); 511 + 512 + clk_name = clk_names; 513 + 514 + while (*clk_name) { 515 + np = of_find_node_with_property(np, *clk_name); 516 + if (!np) { 517 + clk_name++; 518 + break; 519 + } 520 + 521 + if (!of_device_is_available(np)) 522 + continue; 523 + 524 + index = 0; 525 + 526 + do { 527 + ret = of_parse_phandle_with_args(np, *clk_name, 528 + "#clock-cells", index, 529 + &args); 530 + if (ret) 531 + break; 532 + 533 + if (args.args_count == 2 && args.np == dev->of_node) { 534 + sci_clk = devm_kzalloc(dev, sizeof(*sci_clk), 535 + GFP_KERNEL); 536 + if (!sci_clk) 537 + return -ENOMEM; 538 + 539 + sci_clk->dev_id = args.args[0]; 540 + sci_clk->clk_id = args.args[1]; 541 + sci_clk->provider = provider; 542 + provider->ops->get_num_parents(provider->sci, 543 + sci_clk->dev_id, 544 + sci_clk->clk_id, 545 + &sci_clk->num_parents); 546 + list_add_tail(&sci_clk->node, &clks); 547 + 548 + num_clks++; 549 + 550 + num_parents = sci_clk->num_parents; 551 + if (num_parents == 1) 552 + num_parents = 0; 553 + 554 + clk_id = args.args[1] + 1; 555 + 556 + while (num_parents--) { 557 + sci_clk = devm_kzalloc(dev, 558 + sizeof(*sci_clk), 559 + GFP_KERNEL); 560 + if (!sci_clk) 561 + return -ENOMEM; 562 + sci_clk->dev_id = args.args[0]; 563 + sci_clk->clk_id = clk_id++; 564 + sci_clk->provider = provider; 565 + list_add_tail(&sci_clk->node, &clks); 566 + 567 + num_clks++; 568 + } 569 + } 570 + 571 + index++; 572 + } while (args.np); 573 + } 574 + 575 + list_sort(NULL, &clks, _cmp_sci_clk_list); 576 + 577 + provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk), 578 + GFP_KERNEL); 579 + if (!provider->clocks) 580 + return -ENOMEM; 581 + 582 + num_clks = 0; 583 + prev = NULL; 584 + 585 + list_for_each_entry(sci_clk, &clks, node) { 586 + if (prev && prev->dev_id == sci_clk->dev_id && 587 + prev->clk_id == sci_clk->clk_id) 588 + continue; 589 + 590 + provider->clocks[num_clks++] = sci_clk; 591 + prev = sci_clk; 592 + } 593 + 594 + provider->num_clocks = num_clks; 595 + 596 + return 0; 597 + } 598 + #endif 599 + 486 600 /** 487 601 * ti_sci_clk_probe - Probe function for the TI SCI clock driver 488 602 * @pdev: platform device pointer to be probed ··· 631 509 provider->ops = &handle->ops.clk_ops; 632 510 provider->dev = dev; 633 511 512 + #ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW 634 513 ret = ti_sci_scan_clocks_from_fw(provider); 635 514 if (ret) { 636 515 dev_err(dev, "scan clocks from FW failed: %d\n", ret); 637 516 return ret; 638 517 } 518 + #else 519 + ret = ti_sci_scan_clocks_from_dt(provider); 520 + if (ret) { 521 + dev_err(dev, "scan clocks from DT failed: %d\n", ret); 522 + return ret; 523 + } 524 + #endif 639 525 640 526 ret = ti_sci_init_clocks(provider); 641 527 if (ret) {