1 --- a/drivers/clk/qcom/Makefile
2 +++ b/drivers/clk/qcom/Makefile
3 @@ -15,6 +15,7 @@ clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-k
4 clk-qcom-y += clk-hfpll.o
6 clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
7 +clk-qcom-y += fab_scaling.o
9 # Keep alphabetically sorted by config
10 obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
12 +++ b/drivers/clk/qcom/fab_scaling.c
15 + * Copyright (c) 2015, The Linux Foundation. All rights reserved.
17 + * Permission to use, copy, modify, and/or distribute this software for any
18 + * purpose with or without fee is hereby granted, provided that the above
19 + * copyright notice and this permission notice appear in all copies.
21 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
22 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
23 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
24 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
25 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
26 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
27 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 +#include <linux/kernel.h>
31 +#include <linux/init.h>
32 +#include <linux/module.h>
33 +#include <linux/platform_device.h>
34 +#include <linux/err.h>
35 +#include <linux/io.h>
36 +#include <linux/of.h>
37 +#include <linux/of_device.h>
38 +#include <linux/clk.h>
39 +#include <linux/clk-provider.h>
40 +#include <linux/slab.h>
41 +#include <linux/fab_scaling.h>
43 +struct qcom_fab_scaling_data {
45 + u32 fab_freq_nominal;
46 + u32 cpu_freq_threshold;
47 + struct clk *apps_fab_clk;
48 + struct clk *ddr_fab_clk;
51 +static struct qcom_fab_scaling_data *drv_data;
53 +int scale_fabrics(unsigned long max_cpu_freq)
55 + struct clk *apps_fab_clk = drv_data->apps_fab_clk,
56 + *ddr_fab_clk = drv_data->ddr_fab_clk;
57 + unsigned long target_freq, cur_freq;
60 + /* Skip fab scaling if the driver is not ready */
61 + if (!apps_fab_clk || !ddr_fab_clk)
64 + if (max_cpu_freq > drv_data->cpu_freq_threshold)
65 + target_freq = drv_data->fab_freq_high;
67 + target_freq = drv_data->fab_freq_nominal;
69 + cur_freq = clk_get_rate(ddr_fab_clk);
71 + if (target_freq != cur_freq) {
72 + ret = clk_set_rate(apps_fab_clk, target_freq);
75 + ret = clk_set_rate(ddr_fab_clk, target_freq);
82 +EXPORT_SYMBOL(scale_fabrics);
84 +static int ipq806x_fab_scaling_probe(struct platform_device *pdev)
86 + struct device_node *np = pdev->dev.of_node;
87 + struct clk *apps_fab_clk, *ddr_fab_clk;
93 + drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
97 + if (of_property_read_u32(np, "fab_freq_high", &drv_data->fab_freq_high)) {
98 + pr_err("FABRICS turbo freq not found. Using defaults...\n");
99 + drv_data->fab_freq_high = 533000000;
102 + if (of_property_read_u32(np, "fab_freq_nominal", &drv_data->fab_freq_nominal)) {
103 + pr_err("FABRICS nominal freq not found. Using defaults...\n");
104 + drv_data->fab_freq_nominal = 400000000;
107 + if (of_property_read_u32(np, "cpu_freq_threshold", &drv_data->cpu_freq_threshold)) {
108 + pr_err("FABRICS cpu freq threshold not found. Using defaults...\n");
109 + drv_data->cpu_freq_threshold = 1000000000;
112 + apps_fab_clk = devm_clk_get(&pdev->dev, "apps-fab-clk");
113 + ret = PTR_ERR_OR_ZERO(apps_fab_clk);
116 + * If apps fab clk node is present, but clock is not yet
117 + * registered, we should try defering probe.
119 + if (ret != -EPROBE_DEFER) {
120 + pr_err("Failed to get APPS FABRIC clock: %d\n", ret);
126 + clk_prepare_enable(apps_fab_clk);
127 + clk_set_rate(apps_fab_clk, drv_data->fab_freq_high);
128 + drv_data->apps_fab_clk = apps_fab_clk;
130 + ddr_fab_clk = devm_clk_get(&pdev->dev, "ddr-fab-clk");
131 + ret = PTR_ERR_OR_ZERO(ddr_fab_clk);
134 + * If ddr fab clk node is present, but clock is not yet
135 + * registered, we should try defering probe.
137 + if (ret != -EPROBE_DEFER) {
138 + pr_err("Failed to get DDR FABRIC clock: %d\n", ret);
139 + ddr_fab_clk = NULL;
145 + clk_prepare_enable(ddr_fab_clk);
146 + clk_set_rate(ddr_fab_clk, drv_data->fab_freq_high);
147 + drv_data->ddr_fab_clk = ddr_fab_clk;
155 +static int ipq806x_fab_scaling_remove(struct platform_device *pdev)
161 +static const struct of_device_id fab_scaling_ipq806x_match_table[] = {
162 + { .compatible = "qcom,fab-scaling" },
166 +static struct platform_driver fab_scaling_ipq806x_driver = {
167 + .probe = ipq806x_fab_scaling_probe,
168 + .remove = ipq806x_fab_scaling_remove,
170 + .name = "fab-scaling",
171 + .of_match_table = fab_scaling_ipq806x_match_table,
175 +static int __init fab_scaling_ipq806x_init(void)
177 + return platform_driver_register(&fab_scaling_ipq806x_driver);
179 +late_initcall(fab_scaling_ipq806x_init);
181 +static void __exit fab_scaling_ipq806x_exit(void)
183 + platform_driver_unregister(&fab_scaling_ipq806x_driver);
185 +module_exit(fab_scaling_ipq806x_exit);
187 +++ b/include/linux/fab_scaling.h
190 + * Copyright (c) 2015, The Linux Foundation. All rights reserved.
192 + * Permission to use, copy, modify, and/or distribute this software for any
193 + * purpose with or without fee is hereby granted, provided that the above
194 + * copyright notice and this permission notice appear in all copies.
196 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
197 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
198 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
199 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
200 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
201 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
202 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
206 +#ifndef __FAB_SCALING_H
207 +#define __FAB_SCALING_H
210 + * scale_fabrics - Scale DDR and APPS FABRICS
212 + * This function monitors all the registered clocks and does APPS
213 + * and DDR FABRIC scaling based on the idle frequencies with which
214 + * it was registered.
217 +int scale_fabrics(unsigned long max_cpu_freq);
220 --- a/drivers/cpufreq/qcom-cpufreq-krait.c
221 +++ b/drivers/cpufreq/qcom-cpufreq-krait.c
223 #include <linux/regulator/consumer.h>
224 #include <linux/slab.h>
225 #include <linux/thermal.h>
226 +#include <linux/fab_scaling.h>
228 #include "cpufreq-dt.h"
230 @@ -54,6 +55,13 @@ static int set_target(struct cpufreq_pol
231 level = dev_pm_opp_get_level(opp);
235 + * Scale fabrics with max freq across all cores
237 + ret = scale_fabrics(target_freq);
241 opp = dev_pm_opp_find_level_exact(&l2_pdev->dev, level);
243 dev_err(&l2_pdev->dev,