From 5318a6dea3ca36b7887dd9abd589a623ff1272f9 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Sat, 28 Dec 2019 17:34:36 +0100 Subject: [PATCH] ipq806x: add fab scaling support Add fab scaling support and dtsi definition Signed-off-by: Ansuel Smith --- .../arch/arm/boot/dts/qcom-ipq8064.dtsi | 9 + ...add-fab-scaling-support-with-cpufreq.patch | 243 ++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 target/linux/ipq806x/patches-4.19/0057-add-fab-scaling-support-with-cpufreq.patch diff --git a/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064.dtsi b/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064.dtsi index 1cf105d81e..f95b0b4f95 100644 --- a/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064.dtsi +++ b/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064.dtsi @@ -546,6 +546,15 @@ }; }; + fab-scaling { + compatible = "qcom,fab-scaling"; + clocks = <&rpmcc RPM_APPS_FABRIC_A_CLK>, <&rpmcc RPM_EBI1_A_CLK>; + clock-names = "apps-fab-clk", "ddr-fab-clk"; + fab_freq_high = <533000000>; + fab_freq_nominal = <400000000>; + cpu_freq_threshold = <1000000000>; + }; + firmware { scm { compatible = "qcom,scm-ipq806x"; diff --git a/target/linux/ipq806x/patches-4.19/0057-add-fab-scaling-support-with-cpufreq.patch b/target/linux/ipq806x/patches-4.19/0057-add-fab-scaling-support-with-cpufreq.patch new file mode 100644 index 0000000000..fa02f49526 --- /dev/null +++ b/target/linux/ipq806x/patches-4.19/0057-add-fab-scaling-support-with-cpufreq.patch @@ -0,0 +1,243 @@ +--- a/drivers/clk/qcom/Makefile ++++ b/drivers/clk/qcom/Makefile +@@ -15,6 +15,7 @@ clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-k + clk-qcom-y += clk-hfpll.o + clk-qcom-y += reset.o + clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o ++clk-qcom-y += fab_scaling.o + + # Keep alphabetically sorted by config + obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o +--- /dev/null ++++ b/drivers/clk/qcom/fab_scaling.c +@@ -0,0 +1,172 @@ ++/* ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct qcom_fab_scaling_data { ++ u32 fab_freq_high; ++ u32 fab_freq_nominal; ++ u32 cpu_freq_threshold; ++ struct clk *apps_fab_clk; ++ struct clk *ddr_fab_clk; ++}; ++ ++static struct qcom_fab_scaling_data *drv_data; ++ ++int scale_fabrics(unsigned long max_cpu_freq) ++{ ++ struct clk *apps_fab_clk = drv_data->apps_fab_clk, ++ *ddr_fab_clk = drv_data->ddr_fab_clk; ++ unsigned long target_freq, cur_freq; ++ int ret; ++ ++ /* Skip fab scaling if the driver is not ready */ ++ if (!apps_fab_clk || !ddr_fab_clk) ++ return 0; ++ ++ if (max_cpu_freq > drv_data->cpu_freq_threshold) ++ target_freq = drv_data->fab_freq_high; ++ else ++ target_freq = drv_data->fab_freq_nominal; ++ ++ cur_freq = clk_get_rate(ddr_fab_clk); ++ ++ if (target_freq != cur_freq) { ++ ret = clk_set_rate(apps_fab_clk, target_freq); ++ if (ret) ++ return ret; ++ ret = clk_set_rate(ddr_fab_clk, target_freq); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(scale_fabrics); ++ ++static int ipq806x_fab_scaling_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct clk *apps_fab_clk, *ddr_fab_clk; ++ int ret; ++ ++ if (!np) ++ return -ENODEV; ++ ++ drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); ++ if (!drv_data) ++ return -ENOMEM; ++ ++ if (of_property_read_u32(np, "fab_freq_high", &drv_data->fab_freq_high)) { ++ pr_err("FABRICS turbo freq not found. Using defaults...\n"); ++ drv_data->fab_freq_high = 533000000; ++ } ++ ++ if (of_property_read_u32(np, "fab_freq_nominal", &drv_data->fab_freq_nominal)) { ++ pr_err("FABRICS nominal freq not found. Using defaults...\n"); ++ drv_data->fab_freq_nominal = 400000000; ++ } ++ ++ if (of_property_read_u32(np, "cpu_freq_threshold", &drv_data->cpu_freq_threshold)) { ++ pr_err("FABRICS cpu freq threshold not found. Using defaults...\n"); ++ drv_data->cpu_freq_threshold = 1000000000; ++ } ++ ++ drv_data->apps_fab_clk = devm_clk_get(&pdev->dev, "apps-fab-clk"); ++ apps_fab_clk = drv_data->apps_fab_clk; ++ ret = PTR_ERR_OR_ZERO(apps_fab_clk); ++ if (ret) { ++ /* ++ * If apps fab clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret != -EPROBE_DEFER) { ++ pr_err("Failed to get APPS FABRIC clock: %d\n", ret); ++ ret = -ENODEV; ++ } ++ goto err; ++ } ++ ++ clk_set_rate(apps_fab_clk, drv_data->fab_freq_high); ++ clk_prepare_enable(apps_fab_clk); ++ ++ drv_data->ddr_fab_clk = devm_clk_get(&pdev->dev, "ddr-fab-clk"); ++ ddr_fab_clk = drv_data->ddr_fab_clk; ++ ret = PTR_ERR_OR_ZERO(ddr_fab_clk); ++ if (ret) { ++ /* ++ * If ddr fab clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret != -EPROBE_DEFER) { ++ pr_err("Failed to get DDR FABRIC clock: %d\n", ret); ++ ddr_fab_clk = NULL; ++ ret = -ENODEV; ++ } ++ goto err; ++ } ++ ++ clk_set_rate(ddr_fab_clk, drv_data->fab_freq_high); ++ clk_prepare_enable(ddr_fab_clk); ++ ++ return 0; ++err: ++ kfree(drv_data); ++ return ret; ++} ++ ++static int ipq806x_fab_scaling_remove(struct platform_device *pdev) ++{ ++ kfree(drv_data); ++ return 0; ++} ++ ++static const struct of_device_id fab_scaling_ipq806x_match_table[] = { ++ { .compatible = "qcom,fab-scaling" }, ++ { } ++}; ++ ++static struct platform_driver fab_scaling_ipq806x_driver = { ++ .probe = ipq806x_fab_scaling_probe, ++ .remove = ipq806x_fab_scaling_remove, ++ .driver = { ++ .name = "fab-scaling", ++ .of_match_table = fab_scaling_ipq806x_match_table, ++ }, ++}; ++ ++static int __init fab_scaling_ipq806x_init(void) ++{ ++ return platform_driver_register(&fab_scaling_ipq806x_driver); ++} ++late_initcall(fab_scaling_ipq806x_init); ++ ++static void __exit fab_scaling_ipq806x_exit(void) ++{ ++ platform_driver_unregister(&fab_scaling_ipq806x_driver); ++} ++module_exit(fab_scaling_ipq806x_exit); +--- /dev/null ++++ b/include/linux/fab_scaling.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++ ++#ifndef __FAB_SCALING_H ++#define __FAB_SCALING_H ++ ++/** ++ * scale_fabrics - Scale DDR and APPS FABRICS ++ * ++ * This function monitors all the registered clocks and does APPS ++ * and DDR FABRIC scaling based on the idle frequencies with which ++ * it was registered. ++ * ++ */ ++int scale_fabrics(unsigned long max_cpu_freq); ++ ++#endif +--- a/drivers/cpufreq/cpufreq-dt.c ++++ b/drivers/cpufreq/cpufreq-dt.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #include "cpufreq-dt.h" + +@@ -101,6 +102,13 @@ static int set_target(struct cpufreq_pol + } + } + } ++ ++ /* ++ * Scale fabrics with max freq across all cores ++ */ ++ ret = scale_fabrics(target_freq); ++ if (ret) ++ goto exit; + } + priv->opp_freq = freq * 1000; + arch_set_freq_scale(policy->related_cpus, freq, -- 2.30.2