[PATCH 06/18] clk: qcom: krait-cc: export L2 clock as an interconnect

Dmitry Baryshkov
2023-06-12T05:39:47Z

While scaling the CPU frequency, L2 frequency should also be scaled
following the CPU frequency. To simplify such scaling, export the L2
clock as an interconnect, to facilitate aggregating CPU votes and
selecting the maximum vote.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/clk/qcom/Kconfig | 1 +
drivers/clk/qcom/krait-cc.c | 75 +++++++++++++++++++++++++++++--------
2 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 97f23f978343..3d56263ce494 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -1065,6 +1065,7 @@ config KRAITCC
tristate "Krait Clock Controller"
depends on ARM
select KRAIT_CLOCKS
+ select INTERCONNECT_CLK if INTERCONNECT
help
Support for the Krait CPU clocks on Qualcomm devices.
Say Y if you want to support CPU frequency scaling.
diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c
index 2ce38024dc0d..f16321fc6dd7 100644
--- a/drivers/clk/qcom/krait-cc.c
+++ b/drivers/clk/qcom/krait-cc.c
@@ -11,19 +11,13 @@
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/interconnect-clk.h>
+#include <linux/interconnect-provider.h>
#include <linux/slab.h>

-#include "clk-krait.h"
-
-enum {
- cpu0_mux = 0,
- cpu1_mux,
- cpu2_mux,
- cpu3_mux,
- l2_mux,
+#include <dt-bindings/clock/qcom,krait-cc.h>

- clks_max,
-};
+#include "clk-krait.h"

static unsigned int sec_mux_map[] = {
2,
@@ -365,11 +359,54 @@ static int krait_clk_reinit(struct clk_hw *hw, int cpu)
return 0;
}

+#ifdef CONFIG_INTERCONNECT
+
+/* Random ID that doesn't clash with main qnoc and OSM */
+#define L2_MASTER_NODE 2000
+
+static int krait_cc_icc_register(struct platform_device *pdev, struct clk_hw *l2_hw)
+{
+ struct device *dev = &pdev->dev;
+ struct clk *clk = devm_clk_hw_get_clk(dev, l2_hw, "l2");
+ const struct icc_clk_data data[] = {
+ { .clk = clk, .name = "l2", },
+ };
+ struct icc_provider *provider;
+
+ provider = icc_clk_register(dev, L2_MASTER_NODE, ARRAY_SIZE(data), data);
+ if (IS_ERR(provider))
+ return PTR_ERR(provider);
+
+ platform_set_drvdata(pdev, provider);
+
+ return 0;
+}
+
+static int krait_cc_icc_remove(struct platform_device *pdev)
+{
+ struct icc_provider *provider = platform_get_drvdata(pdev);
+
+ icc_clk_unregister(provider);
+
+ return 0;
+}
+#define krait_cc_icc_sync_state icc_sync_state
+#else
+static int krait_cc_icc_register(struct platform_device *pdev, struct clk_hw *l2_hw)
+{
+ dev_warn(&pdev->dev, "CONFIG_INTERCONNECT is disabled, L2 clock is fixed\n");
+
+ return 0;
+}
+#define krait_cc_icc_remove(pdev) (0)
+#define krait_cc_icc_sync_state NULL
+#endif
+
static int krait_cc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *id;
- int cpu;
+ int cpu, ret;
struct clk_hw *clk;
struct clk_hw_onecell_data *clks;

@@ -389,11 +426,11 @@ static int krait_cc_probe(struct platform_device *pdev)
}

/* Krait configurations have at most 4 CPUs and one L2 */
- clks = devm_kzalloc(dev, struct_size(clks, hws, clks_max), GFP_KERNEL);
+ clks = devm_kzalloc(dev, struct_size(clks, hws, KRAIT_NUM_CLOCKS), GFP_KERNEL);
if (!clks)
return -ENOMEM;

- clks->num = clks_max;
+ clks->num = KRAIT_NUM_CLOCKS;

for_each_possible_cpu(cpu) {
clk = krait_add_clks(dev, cpu, id->data);
@@ -405,7 +442,7 @@ static int krait_cc_probe(struct platform_device *pdev)
clk = krait_add_clks(dev, -1, id->data);
if (IS_ERR(clk))
return PTR_ERR(clk);
- clks->hws[l2_mux] = clk;
+ clks->hws[KRAIT_L2] = clk;

/*
* Force reinit of HFPLLs and muxes to overwrite any potential
@@ -418,18 +455,24 @@ static int krait_cc_probe(struct platform_device *pdev)
* two different rates to force a HFPLL reinit under all
* circumstances.
*/
- krait_clk_reinit(clks->hws[l2_mux], -1);
+ krait_clk_reinit(clks->hws[KRAIT_L2], -1);
for_each_possible_cpu(cpu)
krait_clk_reinit(clks->hws[cpu], cpu);

- return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clks);
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clks);
+ if (ret)
+ return ret;
+
+ return krait_cc_icc_register(pdev, clks->hws[KRAIT_L2]);
}

static struct platform_driver krait_cc_driver = {
.probe = krait_cc_probe,
+ .remove = krait_cc_icc_remove,
.driver = {
.name = "krait-cc",
.of_match_table = krait_cc_match_table,
+ .sync_state = krait_cc_icc_sync_state,
},
};
module_platform_driver(krait_cc_driver);
--
2.39.2