@@ -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.
@@ -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);
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(-)