]> Git Repo - linux.git/blob - drivers/devfreq/mtk-cci-devfreq.c
Merge tag 'nfsd-6.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
[linux.git] / drivers / devfreq / mtk-cci-devfreq.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2022 MediaTek Inc.
4  */
5
6 #include <linux/clk.h>
7 #include <linux/devfreq.h>
8 #include <linux/minmax.h>
9 #include <linux/module.h>
10 #include <linux/of.h>
11 #include <linux/of_device.h>
12 #include <linux/platform_device.h>
13 #include <linux/pm_opp.h>
14 #include <linux/regulator/consumer.h>
15
16 struct mtk_ccifreq_platform_data {
17         int min_volt_shift;
18         int max_volt_shift;
19         int proc_max_volt;
20         int sram_min_volt;
21         int sram_max_volt;
22 };
23
24 struct mtk_ccifreq_drv {
25         struct device *dev;
26         struct devfreq *devfreq;
27         struct regulator *proc_reg;
28         struct regulator *sram_reg;
29         struct clk *cci_clk;
30         struct clk *inter_clk;
31         int inter_voltage;
32         unsigned long pre_freq;
33         /* Avoid race condition for regulators between notify and policy */
34         struct mutex reg_lock;
35         struct notifier_block opp_nb;
36         const struct mtk_ccifreq_platform_data *soc_data;
37         int vtrack_max;
38 };
39
40 static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv, int new_voltage)
41 {
42         const struct mtk_ccifreq_platform_data *soc_data = drv->soc_data;
43         struct device *dev = drv->dev;
44         int pre_voltage, pre_vsram, new_vsram, vsram, voltage, ret;
45         int retry_max = drv->vtrack_max;
46
47         if (!drv->sram_reg) {
48                 ret = regulator_set_voltage(drv->proc_reg, new_voltage,
49                                             drv->soc_data->proc_max_volt);
50                 return ret;
51         }
52
53         pre_voltage = regulator_get_voltage(drv->proc_reg);
54         if (pre_voltage < 0) {
55                 dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
56                 return pre_voltage;
57         }
58
59         pre_vsram = regulator_get_voltage(drv->sram_reg);
60         if (pre_vsram < 0) {
61                 dev_err(dev, "invalid vsram value: %d\n", pre_vsram);
62                 return pre_vsram;
63         }
64
65         new_vsram = clamp(new_voltage + soc_data->min_volt_shift,
66                           soc_data->sram_min_volt, soc_data->sram_max_volt);
67
68         do {
69                 if (pre_voltage <= new_voltage) {
70                         vsram = clamp(pre_voltage + soc_data->max_volt_shift,
71                                       soc_data->sram_min_volt, new_vsram);
72                         ret = regulator_set_voltage(drv->sram_reg, vsram,
73                                                     soc_data->sram_max_volt);
74                         if (ret)
75                                 return ret;
76
77                         if (vsram == soc_data->sram_max_volt ||
78                             new_vsram == soc_data->sram_min_volt)
79                                 voltage = new_voltage;
80                         else
81                                 voltage = vsram - soc_data->min_volt_shift;
82
83                         ret = regulator_set_voltage(drv->proc_reg, voltage,
84                                                     soc_data->proc_max_volt);
85                         if (ret) {
86                                 regulator_set_voltage(drv->sram_reg, pre_vsram,
87                                                       soc_data->sram_max_volt);
88                                 return ret;
89                         }
90                 } else if (pre_voltage > new_voltage) {
91                         voltage = max(new_voltage,
92                                       pre_vsram - soc_data->max_volt_shift);
93                         ret = regulator_set_voltage(drv->proc_reg, voltage,
94                                                     soc_data->proc_max_volt);
95                         if (ret)
96                                 return ret;
97
98                         if (voltage == new_voltage)
99                                 vsram = new_vsram;
100                         else
101                                 vsram = max(new_vsram,
102                                             voltage + soc_data->min_volt_shift);
103
104                         ret = regulator_set_voltage(drv->sram_reg, vsram,
105                                                     soc_data->sram_max_volt);
106                         if (ret) {
107                                 regulator_set_voltage(drv->proc_reg, pre_voltage,
108                                                       soc_data->proc_max_volt);
109                                 return ret;
110                         }
111                 }
112
113                 pre_voltage = voltage;
114                 pre_vsram = vsram;
115
116                 if (--retry_max < 0) {
117                         dev_err(dev,
118                                 "over loop count, failed to set voltage\n");
119                         return -EINVAL;
120                 }
121         } while (voltage != new_voltage || vsram != new_vsram);
122
123         return 0;
124 }
125
126 static int mtk_ccifreq_target(struct device *dev, unsigned long *freq,
127                               u32 flags)
128 {
129         struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev);
130         struct clk *cci_pll = clk_get_parent(drv->cci_clk);
131         struct dev_pm_opp *opp;
132         unsigned long opp_rate;
133         int voltage, pre_voltage, inter_voltage, target_voltage, ret;
134
135         if (!drv)
136                 return -EINVAL;
137
138         if (drv->pre_freq == *freq)
139                 return 0;
140
141         inter_voltage = drv->inter_voltage;
142
143         opp_rate = *freq;
144         opp = devfreq_recommended_opp(dev, &opp_rate, 1);
145         if (IS_ERR(opp)) {
146                 dev_err(dev, "failed to find opp for freq: %ld\n", opp_rate);
147                 return PTR_ERR(opp);
148         }
149
150         mutex_lock(&drv->reg_lock);
151
152         voltage = dev_pm_opp_get_voltage(opp);
153         dev_pm_opp_put(opp);
154
155         pre_voltage = regulator_get_voltage(drv->proc_reg);
156         if (pre_voltage < 0) {
157                 dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
158                 ret = pre_voltage;
159                 goto out_unlock;
160         }
161
162         /* scale up: set voltage first then freq. */
163         target_voltage = max(inter_voltage, voltage);
164         if (pre_voltage <= target_voltage) {
165                 ret = mtk_ccifreq_set_voltage(drv, target_voltage);
166                 if (ret) {
167                         dev_err(dev, "failed to scale up voltage\n");
168                         goto out_restore_voltage;
169                 }
170         }
171
172         /* switch the cci clock to intermediate clock source. */
173         ret = clk_set_parent(drv->cci_clk, drv->inter_clk);
174         if (ret) {
175                 dev_err(dev, "failed to re-parent cci clock\n");
176                 goto out_restore_voltage;
177         }
178
179         /* set the original clock to target rate. */
180         ret = clk_set_rate(cci_pll, *freq);
181         if (ret) {
182                 dev_err(dev, "failed to set cci pll rate: %d\n", ret);
183                 clk_set_parent(drv->cci_clk, cci_pll);
184                 goto out_restore_voltage;
185         }
186
187         /* switch the cci clock back to the original clock source. */
188         ret = clk_set_parent(drv->cci_clk, cci_pll);
189         if (ret) {
190                 dev_err(dev, "failed to re-parent cci clock\n");
191                 mtk_ccifreq_set_voltage(drv, inter_voltage);
192                 goto out_unlock;
193         }
194
195         /*
196          * If the new voltage is lower than the intermediate voltage or the
197          * original voltage, scale down to the new voltage.
198          */
199         if (voltage < inter_voltage || voltage < pre_voltage) {
200                 ret = mtk_ccifreq_set_voltage(drv, voltage);
201                 if (ret) {
202                         dev_err(dev, "failed to scale down voltage\n");
203                         goto out_unlock;
204                 }
205         }
206
207         drv->pre_freq = *freq;
208         mutex_unlock(&drv->reg_lock);
209
210         return 0;
211
212 out_restore_voltage:
213         mtk_ccifreq_set_voltage(drv, pre_voltage);
214
215 out_unlock:
216         mutex_unlock(&drv->reg_lock);
217         return ret;
218 }
219
220 static int mtk_ccifreq_opp_notifier(struct notifier_block *nb,
221                                     unsigned long event, void *data)
222 {
223         struct dev_pm_opp *opp = data;
224         struct mtk_ccifreq_drv *drv;
225         unsigned long freq, volt;
226
227         drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb);
228
229         if (event == OPP_EVENT_ADJUST_VOLTAGE) {
230                 freq = dev_pm_opp_get_freq(opp);
231
232                 mutex_lock(&drv->reg_lock);
233                 /* current opp item is changed */
234                 if (freq == drv->pre_freq) {
235                         volt = dev_pm_opp_get_voltage(opp);
236                         mtk_ccifreq_set_voltage(drv, volt);
237                 }
238                 mutex_unlock(&drv->reg_lock);
239         }
240
241         return 0;
242 }
243
244 static struct devfreq_dev_profile mtk_ccifreq_profile = {
245         .target = mtk_ccifreq_target,
246 };
247
248 static int mtk_ccifreq_probe(struct platform_device *pdev)
249 {
250         struct device *dev = &pdev->dev;
251         struct mtk_ccifreq_drv *drv;
252         struct devfreq_passive_data *passive_data;
253         struct dev_pm_opp *opp;
254         unsigned long rate, opp_volt;
255         int ret;
256
257         drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
258         if (!drv)
259                 return -ENOMEM;
260
261         drv->dev = dev;
262         drv->soc_data = (const struct mtk_ccifreq_platform_data *)
263                                 of_device_get_match_data(&pdev->dev);
264         mutex_init(&drv->reg_lock);
265         platform_set_drvdata(pdev, drv);
266
267         drv->cci_clk = devm_clk_get(dev, "cci");
268         if (IS_ERR(drv->cci_clk)) {
269                 ret = PTR_ERR(drv->cci_clk);
270                 return dev_err_probe(dev, ret, "failed to get cci clk\n");
271         }
272
273         drv->inter_clk = devm_clk_get(dev, "intermediate");
274         if (IS_ERR(drv->inter_clk)) {
275                 ret = PTR_ERR(drv->inter_clk);
276                 return dev_err_probe(dev, ret,
277                                      "failed to get intermediate clk\n");
278         }
279
280         drv->proc_reg = devm_regulator_get_optional(dev, "proc");
281         if (IS_ERR(drv->proc_reg)) {
282                 ret = PTR_ERR(drv->proc_reg);
283                 return dev_err_probe(dev, ret,
284                                      "failed to get proc regulator\n");
285         }
286
287         ret = regulator_enable(drv->proc_reg);
288         if (ret) {
289                 dev_err(dev, "failed to enable proc regulator\n");
290                 return ret;
291         }
292
293         drv->sram_reg = devm_regulator_get_optional(dev, "sram");
294         if (IS_ERR(drv->sram_reg))
295                 drv->sram_reg = NULL;
296         else {
297                 ret = regulator_enable(drv->sram_reg);
298                 if (ret) {
299                         dev_err(dev, "failed to enable sram regulator\n");
300                         goto out_free_resources;
301                 }
302         }
303
304         /*
305          * We assume min voltage is 0 and tracking target voltage using
306          * min_volt_shift for each iteration.
307          * The retry_max is 3 times of expected iteration count.
308          */
309         drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data->sram_max_volt,
310                                                drv->soc_data->proc_max_volt),
311                                            drv->soc_data->min_volt_shift);
312
313         ret = clk_prepare_enable(drv->cci_clk);
314         if (ret)
315                 goto out_free_resources;
316
317         ret = dev_pm_opp_of_add_table(dev);
318         if (ret) {
319                 dev_err(dev, "failed to add opp table: %d\n", ret);
320                 goto out_disable_cci_clk;
321         }
322
323         rate = clk_get_rate(drv->inter_clk);
324         opp = dev_pm_opp_find_freq_ceil(dev, &rate);
325         if (IS_ERR(opp)) {
326                 ret = PTR_ERR(opp);
327                 dev_err(dev, "failed to get intermediate opp: %d\n", ret);
328                 goto out_remove_opp_table;
329         }
330         drv->inter_voltage = dev_pm_opp_get_voltage(opp);
331         dev_pm_opp_put(opp);
332
333         rate = U32_MAX;
334         opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
335         if (IS_ERR(opp)) {
336                 dev_err(dev, "failed to get opp\n");
337                 ret = PTR_ERR(opp);
338                 goto out_remove_opp_table;
339         }
340
341         opp_volt = dev_pm_opp_get_voltage(opp);
342         dev_pm_opp_put(opp);
343         ret = mtk_ccifreq_set_voltage(drv, opp_volt);
344         if (ret) {
345                 dev_err(dev, "failed to scale to highest voltage %lu in proc_reg\n",
346                         opp_volt);
347                 goto out_remove_opp_table;
348         }
349
350         passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL);
351         if (!passive_data) {
352                 ret = -ENOMEM;
353                 goto out_remove_opp_table;
354         }
355
356         passive_data->parent_type = CPUFREQ_PARENT_DEV;
357         drv->devfreq = devm_devfreq_add_device(dev, &mtk_ccifreq_profile,
358                                                DEVFREQ_GOV_PASSIVE,
359                                                passive_data);
360         if (IS_ERR(drv->devfreq)) {
361                 ret = -EPROBE_DEFER;
362                 dev_err(dev, "failed to add devfreq device: %ld\n",
363                         PTR_ERR(drv->devfreq));
364                 goto out_remove_opp_table;
365         }
366
367         drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
368         ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
369         if (ret) {
370                 dev_err(dev, "failed to register opp notifier: %d\n", ret);
371                 goto out_remove_opp_table;
372         }
373         return 0;
374
375 out_remove_opp_table:
376         dev_pm_opp_of_remove_table(dev);
377
378 out_disable_cci_clk:
379         clk_disable_unprepare(drv->cci_clk);
380
381 out_free_resources:
382         if (regulator_is_enabled(drv->proc_reg))
383                 regulator_disable(drv->proc_reg);
384         if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
385                 regulator_disable(drv->sram_reg);
386
387         return ret;
388 }
389
390 static int mtk_ccifreq_remove(struct platform_device *pdev)
391 {
392         struct device *dev = &pdev->dev;
393         struct mtk_ccifreq_drv *drv;
394
395         drv = platform_get_drvdata(pdev);
396
397         dev_pm_opp_unregister_notifier(dev, &drv->opp_nb);
398         dev_pm_opp_of_remove_table(dev);
399         clk_disable_unprepare(drv->cci_clk);
400         regulator_disable(drv->proc_reg);
401         if (drv->sram_reg)
402                 regulator_disable(drv->sram_reg);
403
404         return 0;
405 }
406
407 static const struct mtk_ccifreq_platform_data mt8183_platform_data = {
408         .min_volt_shift = 100000,
409         .max_volt_shift = 200000,
410         .proc_max_volt = 1150000,
411 };
412
413 static const struct mtk_ccifreq_platform_data mt8186_platform_data = {
414         .min_volt_shift = 100000,
415         .max_volt_shift = 250000,
416         .proc_max_volt = 1118750,
417         .sram_min_volt = 850000,
418         .sram_max_volt = 1118750,
419 };
420
421 static const struct of_device_id mtk_ccifreq_machines[] = {
422         { .compatible = "mediatek,mt8183-cci", .data = &mt8183_platform_data },
423         { .compatible = "mediatek,mt8186-cci", .data = &mt8186_platform_data },
424         { },
425 };
426 MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines);
427
428 static struct platform_driver mtk_ccifreq_platdrv = {
429         .probe  = mtk_ccifreq_probe,
430         .remove = mtk_ccifreq_remove,
431         .driver = {
432                 .name = "mtk-ccifreq",
433                 .of_match_table = mtk_ccifreq_machines,
434         },
435 };
436 module_platform_driver(mtk_ccifreq_platdrv);
437
438 MODULE_DESCRIPTION("MediaTek CCI devfreq driver");
439 MODULE_AUTHOR("Jia-Wei Chang <[email protected]>");
440 MODULE_LICENSE("GPL v2");
This page took 0.053548 seconds and 4 git commands to generate.