mediatek: mt7988a: sync dts compatible string
[openwrt/openwrt.git] / target / linux / ipq806x / patches-5.4 / 0057-add-fab-scaling-support-with-cpufreq.patch
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
5 clk-qcom-y += reset.o
6 clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
7 +clk-qcom-y += fab_scaling.o
8
9 # Keep alphabetically sorted by config
10 obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
11 --- /dev/null
12 +++ b/drivers/clk/qcom/fab_scaling.c
13 @@ -0,0 +1,172 @@
14 +/*
15 + * Copyright (c) 2015, The Linux Foundation. All rights reserved.
16 + *
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.
20 + *
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.
28 + */
29 +
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>
42 +
43 +struct qcom_fab_scaling_data {
44 + u32 fab_freq_high;
45 + u32 fab_freq_nominal;
46 + u32 cpu_freq_threshold;
47 + struct clk *apps_fab_clk;
48 + struct clk *ddr_fab_clk;
49 +};
50 +
51 +static struct qcom_fab_scaling_data *drv_data;
52 +
53 +int scale_fabrics(unsigned long max_cpu_freq)
54 +{
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;
58 + int ret;
59 +
60 + /* Skip fab scaling if the driver is not ready */
61 + if (!apps_fab_clk || !ddr_fab_clk)
62 + return 0;
63 +
64 + if (max_cpu_freq > drv_data->cpu_freq_threshold)
65 + target_freq = drv_data->fab_freq_high;
66 + else
67 + target_freq = drv_data->fab_freq_nominal;
68 +
69 + cur_freq = clk_get_rate(ddr_fab_clk);
70 +
71 + if (target_freq != cur_freq) {
72 + ret = clk_set_rate(apps_fab_clk, target_freq);
73 + if (ret)
74 + return ret;
75 + ret = clk_set_rate(ddr_fab_clk, target_freq);
76 + if (ret)
77 + return ret;
78 + }
79 +
80 + return 0;
81 +}
82 +EXPORT_SYMBOL(scale_fabrics);
83 +
84 +static int ipq806x_fab_scaling_probe(struct platform_device *pdev)
85 +{
86 + struct device_node *np = pdev->dev.of_node;
87 + struct clk *apps_fab_clk, *ddr_fab_clk;
88 + int ret;
89 +
90 + if (!np)
91 + return -ENODEV;
92 +
93 + drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
94 + if (!drv_data)
95 + return -ENOMEM;
96 +
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;
100 + }
101 +
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;
105 + }
106 +
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;
110 + }
111 +
112 + apps_fab_clk = devm_clk_get(&pdev->dev, "apps-fab-clk");
113 + ret = PTR_ERR_OR_ZERO(apps_fab_clk);
114 + if (ret) {
115 + /*
116 + * If apps fab clk node is present, but clock is not yet
117 + * registered, we should try defering probe.
118 + */
119 + if (ret != -EPROBE_DEFER) {
120 + pr_err("Failed to get APPS FABRIC clock: %d\n", ret);
121 + ret = -ENODEV;
122 + }
123 + goto err;
124 + }
125 +
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;
129 +
130 + ddr_fab_clk = devm_clk_get(&pdev->dev, "ddr-fab-clk");
131 + ret = PTR_ERR_OR_ZERO(ddr_fab_clk);
132 + if (ret) {
133 + /*
134 + * If ddr fab clk node is present, but clock is not yet
135 + * registered, we should try defering probe.
136 + */
137 + if (ret != -EPROBE_DEFER) {
138 + pr_err("Failed to get DDR FABRIC clock: %d\n", ret);
139 + ddr_fab_clk = NULL;
140 + ret = -ENODEV;
141 + }
142 + goto err;
143 + }
144 +
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;
148 +
149 + return 0;
150 +err:
151 + kfree(drv_data);
152 + return ret;
153 +}
154 +
155 +static int ipq806x_fab_scaling_remove(struct platform_device *pdev)
156 +{
157 + kfree(drv_data);
158 + return 0;
159 +}
160 +
161 +static const struct of_device_id fab_scaling_ipq806x_match_table[] = {
162 + { .compatible = "qcom,fab-scaling" },
163 + { }
164 +};
165 +
166 +static struct platform_driver fab_scaling_ipq806x_driver = {
167 + .probe = ipq806x_fab_scaling_probe,
168 + .remove = ipq806x_fab_scaling_remove,
169 + .driver = {
170 + .name = "fab-scaling",
171 + .of_match_table = fab_scaling_ipq806x_match_table,
172 + },
173 +};
174 +
175 +static int __init fab_scaling_ipq806x_init(void)
176 +{
177 + return platform_driver_register(&fab_scaling_ipq806x_driver);
178 +}
179 +late_initcall(fab_scaling_ipq806x_init);
180 +
181 +static void __exit fab_scaling_ipq806x_exit(void)
182 +{
183 + platform_driver_unregister(&fab_scaling_ipq806x_driver);
184 +}
185 +module_exit(fab_scaling_ipq806x_exit);
186 --- /dev/null
187 +++ b/include/linux/fab_scaling.h
188 @@ -0,0 +1,31 @@
189 +/*
190 + * Copyright (c) 2015, The Linux Foundation. All rights reserved.
191 + *
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.
195 + *
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.
203 + */
204 +
205 +
206 +#ifndef __FAB_SCALING_H
207 +#define __FAB_SCALING_H
208 +
209 +/**
210 + * scale_fabrics - Scale DDR and APPS FABRICS
211 + *
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.
215 + *
216 + */
217 +int scale_fabrics(unsigned long max_cpu_freq);
218 +
219 +#endif
220 --- a/drivers/cpufreq/cpufreq-dt.c
221 +++ b/drivers/cpufreq/cpufreq-dt.c
222 @@ -20,6 +20,7 @@
223 #include <linux/regulator/consumer.h>
224 #include <linux/slab.h>
225 #include <linux/thermal.h>
226 +#include <linux/fab_scaling.h>
227
228 #include "cpufreq-dt.h"
229
230 @@ -111,6 +112,13 @@ static int set_target(struct cpufreq_pol
231 }
232 }
233 }
234 +
235 + /*
236 + * Scale fabrics with max freq across all cores
237 + */
238 + ret = scale_fabrics(target_freq);
239 + if (ret)
240 + goto exit;
241 }
242 priv->opp_freq = freq * 1000;
243 arch_set_freq_scale(policy->related_cpus, freq,