Skip to content

Commit 28ae3e8

Browse files
committed
MINIARM: MALI: midgard: limit CPU's maximum frequency according to GPU's frequency
Change-Id: I72c4b545b56d7da9a204756ff7ed2f7a1ff5df93 Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com> Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
1 parent 4c488fb commit 28ae3e8

2 files changed

Lines changed: 180 additions & 11 deletions

File tree

drivers/gpu/arm/midgard_for_linux/backend/gpu/mali_kbase_devfreq.c

Lines changed: 165 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#endif
2727

2828
#include <linux/clk.h>
29+
#include <linux/cpufreq.h>
2930
#include <linux/devfreq.h>
3031
#ifdef CONFIG_DEVFREQ_THERMAL
3132
#include <linux/devfreq_cooling.h>
@@ -46,15 +47,21 @@
4647
#define dev_pm_opp_find_freq_ceil opp_find_freq_ceil
4748
#endif /* Linux >= 3.13 */
4849

50+
#define MAX_CLUSTERS 2
51+
52+
static struct cpumask allowed_cpus[MAX_CLUSTERS];
53+
static unsigned int cpu_max_freq[MAX_CLUSTERS] = {UINT_MAX, UINT_MAX};
54+
static unsigned int cpu_clipped_freq[MAX_CLUSTERS] = {UINT_MAX, UINT_MAX};
4955

5056
static int
5157
kbase_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags)
5258
{
5359
struct kbase_device *kbdev = dev_get_drvdata(dev);
5460
struct dev_pm_opp *opp;
5561
unsigned long freq = 0;
62+
unsigned long old_freq = kbdev->current_freq;
5663
unsigned long voltage;
57-
int err;
64+
int err = 0;
5865

5966
freq = *target_freq;
6067

@@ -70,43 +77,57 @@ kbase_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags)
7077
/*
7178
* Only update if there is a change of frequency
7279
*/
73-
if (kbdev->current_freq == freq) {
80+
if (old_freq == freq) {
7481
*target_freq = freq;
82+
#ifdef CONFIG_REGULATOR
83+
if (kbdev->current_voltage == voltage)
84+
return 0;
85+
err = regulator_set_voltage(kbdev->regulator, voltage, INT_MAX);
86+
if (err) {
87+
dev_err(dev, "Failed to set voltage (%d)\n", err);
88+
return err;
89+
}
90+
#else
7591
return 0;
92+
#endif
7693
}
7794

7895
#ifdef CONFIG_REGULATOR
79-
if (kbdev->regulator && kbdev->current_voltage != voltage
80-
&& kbdev->current_freq < freq) {
81-
err = regulator_set_voltage(kbdev->regulator, voltage, voltage);
96+
if (kbdev->regulator && kbdev->current_voltage != voltage &&
97+
old_freq < freq) {
98+
err = regulator_set_voltage(kbdev->regulator, voltage, INT_MAX);
8299
if (err) {
83100
dev_err(dev, "Failed to increase voltage (%d)\n", err);
84101
return err;
85102
}
86103
}
87104
#endif
88105

89-
err = clk_set_rate(kbdev->clock, freq);
106+
mutex_lock(&kbdev->mutex_for_clk);
107+
if (!kbdev->is_power_off)
108+
err = clk_set_rate(kbdev->clock, freq);
109+
kbdev->freq = freq;
110+
mutex_unlock(&kbdev->mutex_for_clk);
90111
if (err) {
91112
dev_err(dev, "Failed to set clock %lu (target %lu)\n",
92113
freq, *target_freq);
93114
return err;
94115
}
116+
*target_freq = freq;
117+
kbdev->current_freq = freq;
95118

96119
#ifdef CONFIG_REGULATOR
97-
if (kbdev->regulator && kbdev->current_voltage != voltage
98-
&& kbdev->current_freq > freq) {
99-
err = regulator_set_voltage(kbdev->regulator, voltage, voltage);
120+
if (kbdev->regulator && kbdev->current_voltage != voltage &&
121+
old_freq > freq) {
122+
err = regulator_set_voltage(kbdev->regulator, voltage, INT_MAX);
100123
if (err) {
101124
dev_err(dev, "Failed to decrease voltage (%d)\n", err);
102125
return err;
103126
}
104127
}
105128
#endif
106129

107-
*target_freq = freq;
108130
kbdev->current_voltage = voltage;
109-
kbdev->current_freq = freq;
110131

111132
kbase_pm_reset_dvfs_utilisation(kbdev);
112133

@@ -200,6 +221,63 @@ static void kbase_devfreq_exit(struct device *dev)
200221
kbase_devfreq_term_freq_table(kbdev);
201222
}
202223

224+
static int kbase_devfreq_trans_notifier(struct notifier_block *nb,
225+
unsigned long val, void *data)
226+
{
227+
struct kbase_device *kbdev = container_of(nb, struct kbase_device,
228+
gpu_trans_nb);
229+
struct devfreq_freqs *freqs = data;
230+
unsigned int new_rate = (unsigned int)(freqs->new / 1000);
231+
int i, cpu;
232+
233+
if (!kbdev)
234+
goto out;
235+
236+
dev_dbg(kbdev->dev, "%lu-->%lu cpu limit=%u, gpu limit=%u\n",
237+
freqs->old, freqs->new,
238+
kbdev->cpu_limit_freq,
239+
kbdev->gpu_limit_freq);
240+
241+
if (val == DEVFREQ_PRECHANGE &&
242+
new_rate >= kbdev->gpu_limit_freq) {
243+
for (i = 0; i < MAX_CLUSTERS; i++) {
244+
if (cpu_max_freq[i] > kbdev->cpu_limit_freq) {
245+
/* change policy->max right now */
246+
cpu_clipped_freq[i] = kbdev->cpu_limit_freq;
247+
if (cpumask_empty(&allowed_cpus[i]))
248+
goto out;
249+
cpu = cpumask_any_and(&allowed_cpus[i],
250+
cpu_online_mask);
251+
if (cpu >= nr_cpu_ids)
252+
goto out;
253+
cpufreq_update_policy(cpu);
254+
} else {
255+
/* avoid someone changing policy->max */
256+
cpu_clipped_freq[i] = kbdev->cpu_limit_freq;
257+
}
258+
}
259+
} else if (val == DEVFREQ_POSTCHANGE &&
260+
new_rate < kbdev->gpu_limit_freq) {
261+
for (i = 0; i < MAX_CLUSTERS; i++) {
262+
if (cpu_clipped_freq[i] != UINT_MAX) {
263+
/* recover policy->max right now */
264+
cpu_clipped_freq[i] = UINT_MAX;
265+
if (cpumask_empty(&allowed_cpus[i]))
266+
goto out;
267+
cpu = cpumask_any_and(&allowed_cpus[i],
268+
cpu_online_mask);
269+
if (cpu >= nr_cpu_ids)
270+
goto out;
271+
cpufreq_update_policy(cpu);
272+
}
273+
}
274+
}
275+
276+
out:
277+
278+
return NOTIFY_OK;
279+
}
280+
203281
int kbase_devfreq_init(struct kbase_device *kbdev)
204282
{
205283
struct devfreq_dev_profile *dp;
@@ -209,6 +287,11 @@ int kbase_devfreq_init(struct kbase_device *kbdev)
209287
return -ENODEV;
210288

211289
kbdev->current_freq = clk_get_rate(kbdev->clock);
290+
#ifdef CONFIG_REGULATOR
291+
if (kbdev->regulator)
292+
kbdev->current_voltage =
293+
regulator_get_voltage(kbdev->regulator);
294+
#endif
212295

213296
dp = &kbdev->devfreq_profile;
214297

@@ -243,6 +326,23 @@ int kbase_devfreq_init(struct kbase_device *kbdev)
243326
goto opp_notifier_failed;
244327
}
245328

329+
if (of_property_read_u32(kbdev->dev->of_node, "cpu-limit-freq",
330+
&kbdev->cpu_limit_freq)) {
331+
dev_err(kbdev->dev, "Failed to get prop cpu-limit-freq\n");
332+
kbdev->cpu_limit_freq = UINT_MAX;
333+
}
334+
if (of_property_read_u32(kbdev->dev->of_node, "gpu-limit-freq",
335+
&kbdev->gpu_limit_freq)) {
336+
dev_err(kbdev->dev, "Failed to get prop gpu-limit-freq\n");
337+
kbdev->gpu_limit_freq = UINT_MAX;
338+
}
339+
340+
kbdev->gpu_trans_nb.notifier_call = kbase_devfreq_trans_notifier;
341+
err = devfreq_register_notifier(kbdev->devfreq, &kbdev->gpu_trans_nb,
342+
DEVFREQ_TRANSITION_NOTIFIER);
343+
if (err)
344+
dev_err(kbdev->dev, "register gpu trans notifier (%d)\n", err);
345+
246346
#ifdef CONFIG_DEVFREQ_THERMAL
247347
err = kbase_power_model_simple_init(kbdev);
248348
if (err && err != -ENODEV && err != -EPROBE_DEFER) {
@@ -305,3 +405,57 @@ void kbase_devfreq_term(struct kbase_device *kbdev)
305405
else
306406
kbdev->devfreq = NULL;
307407
}
408+
409+
static int kbase_cpufreq_policy_notifier(struct notifier_block *nb,
410+
unsigned long val, void *data)
411+
{
412+
struct cpufreq_policy *policy = data;
413+
int i;
414+
415+
if (val == CPUFREQ_START) {
416+
for (i = 0; i < MAX_CLUSTERS; i++) {
417+
if (cpumask_test_cpu(policy->cpu,
418+
&allowed_cpus[i]))
419+
break;
420+
if (cpumask_empty(&allowed_cpus[i])) {
421+
cpumask_copy(&allowed_cpus[i],
422+
policy->related_cpus);
423+
break;
424+
}
425+
}
426+
goto out;
427+
}
428+
429+
if (val != CPUFREQ_ADJUST)
430+
goto out;
431+
432+
for (i = 0; i < MAX_CLUSTERS; i++) {
433+
if (cpumask_test_cpu(policy->cpu, &allowed_cpus[i]))
434+
break;
435+
}
436+
if (i == MAX_CLUSTERS)
437+
goto out;
438+
439+
if (policy->max > cpu_clipped_freq[i])
440+
cpufreq_verify_within_limits(policy, 0, cpu_clipped_freq[i]);
441+
442+
cpu_max_freq[i] = policy->max;
443+
pr_debug("cluster%d max=%u, gpu limit=%u\n", i, cpu_max_freq[i],
444+
cpu_clipped_freq[i]);
445+
446+
out:
447+
448+
return NOTIFY_OK;
449+
}
450+
451+
static struct notifier_block notifier_policy_block = {
452+
.notifier_call = kbase_cpufreq_policy_notifier
453+
};
454+
455+
static int __init kbase_cpufreq_init(void)
456+
{
457+
return cpufreq_register_notifier(&notifier_policy_block,
458+
CPUFREQ_POLICY_NOTIFIER);
459+
}
460+
461+
subsys_initcall(kbase_cpufreq_init);

drivers/gpu/arm/midgard_for_linux/mali_kbase_defs.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,17 @@ struct kbase_device {
912912
} irqs[3];
913913

914914
struct clk *clock;
915+
916+
/*
917+
* current freq of clk_gpu, in Hz.
918+
*/
919+
unsigned long freq;
920+
/*
921+
* mutex for setting freq of clk_gpu.
922+
*/
923+
struct mutex mutex_for_clk;
924+
bool is_power_off;
925+
915926
#ifdef CONFIG_REGULATOR
916927
struct regulator *regulator;
917928
#endif
@@ -1170,6 +1181,10 @@ struct kbase_device {
11701181
/* Boolean indicating if an IRQ flush during reset is in progress. */
11711182
bool irq_reset_flush;
11721183

1184+
struct notifier_block gpu_trans_nb;
1185+
unsigned int gpu_limit_freq;
1186+
unsigned int cpu_limit_freq;
1187+
11731188
/* list of inited sub systems. Used during terminate/error recovery */
11741189
u32 inited_subsys;
11751190
};

0 commit comments

Comments
 (0)