6
6
#include <linux/bitfield.h>
7
7
#include <linux/cpufreq.h>
8
8
#include <linux/init.h>
9
+ #include <linux/interconnect.h>
9
10
#include <linux/kernel.h>
10
11
#include <linux/module.h>
11
12
#include <linux/of_address.h>
30
31
31
32
static unsigned long cpu_hw_rate , xo_rate ;
32
33
static struct platform_device * global_pdev ;
34
+ static bool icc_scaling_enabled ;
35
+
36
+ static int qcom_cpufreq_set_bw (struct cpufreq_policy * policy ,
37
+ unsigned long freq_khz )
38
+ {
39
+ unsigned long freq_hz = freq_khz * 1000 ;
40
+ struct dev_pm_opp * opp ;
41
+ struct device * dev ;
42
+ int ret ;
43
+
44
+ dev = get_cpu_device (policy -> cpu );
45
+ if (!dev )
46
+ return - ENODEV ;
47
+
48
+ opp = dev_pm_opp_find_freq_exact (dev , freq_hz , true);
49
+ if (IS_ERR (opp ))
50
+ return PTR_ERR (opp );
51
+
52
+ ret = dev_pm_opp_set_bw (dev , opp );
53
+ dev_pm_opp_put (opp );
54
+ return ret ;
55
+ }
56
+
57
+ static int qcom_cpufreq_update_opp (struct device * cpu_dev ,
58
+ unsigned long freq_khz ,
59
+ unsigned long volt )
60
+ {
61
+ unsigned long freq_hz = freq_khz * 1000 ;
62
+ int ret ;
63
+
64
+ /* Skip voltage update if the opp table is not available */
65
+ if (!icc_scaling_enabled )
66
+ return dev_pm_opp_add (cpu_dev , freq_hz , volt );
67
+
68
+ ret = dev_pm_opp_adjust_voltage (cpu_dev , freq_hz , volt , volt , volt );
69
+ if (ret ) {
70
+ dev_err (cpu_dev , "Voltage update failed freq=%ld\n" , freq_khz );
71
+ return ret ;
72
+ }
73
+
74
+ return dev_pm_opp_enable (cpu_dev , freq_hz );
75
+ }
33
76
34
77
static int qcom_cpufreq_hw_target_index (struct cpufreq_policy * policy ,
35
78
unsigned int index )
@@ -39,6 +82,9 @@ static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy,
39
82
40
83
writel_relaxed (index , perf_state_reg );
41
84
85
+ if (icc_scaling_enabled )
86
+ qcom_cpufreq_set_bw (policy , freq );
87
+
42
88
arch_set_freq_scale (policy -> related_cpus , freq ,
43
89
policy -> cpuinfo .max_freq );
44
90
return 0 ;
@@ -89,11 +135,33 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
89
135
u32 data , src , lval , i , core_count , prev_freq = 0 , freq ;
90
136
u32 volt ;
91
137
struct cpufreq_frequency_table * table ;
138
+ struct dev_pm_opp * opp ;
139
+ unsigned long rate ;
140
+ int ret ;
92
141
93
142
table = kcalloc (LUT_MAX_ENTRIES + 1 , sizeof (* table ), GFP_KERNEL );
94
143
if (!table )
95
144
return - ENOMEM ;
96
145
146
+ ret = dev_pm_opp_of_add_table (cpu_dev );
147
+ if (!ret ) {
148
+ /* Disable all opps and cross-validate against LUT later */
149
+ icc_scaling_enabled = true;
150
+ for (rate = 0 ; ; rate ++ ) {
151
+ opp = dev_pm_opp_find_freq_ceil (cpu_dev , & rate );
152
+ if (IS_ERR (opp ))
153
+ break ;
154
+
155
+ dev_pm_opp_put (opp );
156
+ dev_pm_opp_disable (cpu_dev , rate );
157
+ }
158
+ } else if (ret != - ENODEV ) {
159
+ dev_err (cpu_dev , "Invalid opp table in device tree\n" );
160
+ return ret ;
161
+ } else {
162
+ icc_scaling_enabled = false;
163
+ }
164
+
97
165
for (i = 0 ; i < LUT_MAX_ENTRIES ; i ++ ) {
98
166
data = readl_relaxed (base + REG_FREQ_LUT +
99
167
i * LUT_ROW_SIZE );
@@ -112,7 +180,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
112
180
113
181
if (freq != prev_freq && core_count != LUT_TURBO_IND ) {
114
182
table [i ].frequency = freq ;
115
- dev_pm_opp_add (cpu_dev , freq * 1000 , volt );
183
+ qcom_cpufreq_update_opp (cpu_dev , freq , volt );
116
184
dev_dbg (cpu_dev , "index=%d freq=%d, core_count %d\n" , i ,
117
185
freq , core_count );
118
186
} else if (core_count == LUT_TURBO_IND ) {
@@ -133,7 +201,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
133
201
if (prev -> frequency == CPUFREQ_ENTRY_INVALID ) {
134
202
prev -> frequency = prev_freq ;
135
203
prev -> flags = CPUFREQ_BOOST_FREQ ;
136
- dev_pm_opp_add (cpu_dev , prev_freq * 1000 , volt );
204
+ qcom_cpufreq_update_opp (cpu_dev , prev_freq , volt );
137
205
}
138
206
139
207
break ;
@@ -254,6 +322,7 @@ static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
254
322
void __iomem * base = policy -> driver_data - REG_PERF_STATE ;
255
323
256
324
dev_pm_opp_remove_all_dynamic (cpu_dev );
325
+ dev_pm_opp_of_cpumask_remove_table (policy -> related_cpus );
257
326
kfree (policy -> freq_table );
258
327
devm_iounmap (& global_pdev -> dev , base );
259
328
@@ -282,6 +351,7 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = {
282
351
283
352
static int qcom_cpufreq_hw_driver_probe (struct platform_device * pdev )
284
353
{
354
+ struct device * cpu_dev ;
285
355
struct clk * clk ;
286
356
int ret ;
287
357
@@ -301,6 +371,15 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
301
371
302
372
global_pdev = pdev ;
303
373
374
+ /* Check for optional interconnect paths on CPU0 */
375
+ cpu_dev = get_cpu_device (0 );
376
+ if (!cpu_dev )
377
+ return - EPROBE_DEFER ;
378
+
379
+ ret = dev_pm_opp_of_find_icc_paths (cpu_dev , NULL );
380
+ if (ret )
381
+ return ret ;
382
+
304
383
ret = cpufreq_register_driver (& cpufreq_qcom_hw_driver );
305
384
if (ret )
306
385
dev_err (& pdev -> dev , "CPUFreq HW driver failed to register\n" );
0 commit comments