7
7
#include <linux/cpufreq.h>
8
8
#include <linux/init.h>
9
9
#include <linux/interconnect.h>
10
+ #include <linux/interrupt.h>
10
11
#include <linux/kernel.h>
11
12
#include <linux/module.h>
12
13
#include <linux/of_address.h>
13
14
#include <linux/of_platform.h>
14
15
#include <linux/pm_opp.h>
15
16
#include <linux/slab.h>
17
+ #include <linux/spinlock.h>
16
18
17
19
#define LUT_MAX_ENTRIES 40U
18
20
#define LUT_SRC GENMASK(31, 30)
22
24
#define CLK_HW_DIV 2
23
25
#define LUT_TURBO_IND 1
24
26
27
+ #define HZ_PER_KHZ 1000
28
+
25
29
struct qcom_cpufreq_soc_data {
26
30
u32 reg_enable ;
27
31
u32 reg_freq_lut ;
28
32
u32 reg_volt_lut ;
33
+ u32 reg_current_vote ;
29
34
u32 reg_perf_state ;
30
35
u8 lut_row_size ;
31
36
};
@@ -34,6 +39,16 @@ struct qcom_cpufreq_data {
34
39
void __iomem * base ;
35
40
struct resource * res ;
36
41
const struct qcom_cpufreq_soc_data * soc_data ;
42
+
43
+ /*
44
+ * Mutex to synchronize between de-init sequence and re-starting LMh
45
+ * polling/interrupts
46
+ */
47
+ struct mutex throttle_lock ;
48
+ int throttle_irq ;
49
+ bool cancel_throttle ;
50
+ struct delayed_work throttle_work ;
51
+ struct cpufreq_policy * policy ;
37
52
};
38
53
39
54
static unsigned long cpu_hw_rate , xo_rate ;
@@ -251,10 +266,92 @@ static void qcom_get_related_cpus(int index, struct cpumask *m)
251
266
}
252
267
}
253
268
269
+ static unsigned int qcom_lmh_get_throttle_freq (struct qcom_cpufreq_data * data )
270
+ {
271
+ unsigned int val = readl_relaxed (data -> base + data -> soc_data -> reg_current_vote );
272
+
273
+ return (val & 0x3FF ) * 19200 ;
274
+ }
275
+
276
+ static void qcom_lmh_dcvs_notify (struct qcom_cpufreq_data * data )
277
+ {
278
+ unsigned long max_capacity , capacity , freq_hz , throttled_freq ;
279
+ struct cpufreq_policy * policy = data -> policy ;
280
+ int cpu = cpumask_first (policy -> cpus );
281
+ struct device * dev = get_cpu_device (cpu );
282
+ struct dev_pm_opp * opp ;
283
+ unsigned int freq ;
284
+
285
+ /*
286
+ * Get the h/w throttled frequency, normalize it using the
287
+ * registered opp table and use it to calculate thermal pressure.
288
+ */
289
+ freq = qcom_lmh_get_throttle_freq (data );
290
+ freq_hz = freq * HZ_PER_KHZ ;
291
+
292
+ opp = dev_pm_opp_find_freq_floor (dev , & freq_hz );
293
+ if (IS_ERR (opp ) && PTR_ERR (opp ) == - ERANGE )
294
+ dev_pm_opp_find_freq_ceil (dev , & freq_hz );
295
+
296
+ throttled_freq = freq_hz / HZ_PER_KHZ ;
297
+
298
+ /* Update thermal pressure */
299
+
300
+ max_capacity = arch_scale_cpu_capacity (cpu );
301
+ capacity = mult_frac (max_capacity , throttled_freq , policy -> cpuinfo .max_freq );
302
+
303
+ /* Don't pass boost capacity to scheduler */
304
+ if (capacity > max_capacity )
305
+ capacity = max_capacity ;
306
+
307
+ arch_set_thermal_pressure (policy -> cpus , max_capacity - capacity );
308
+
309
+ /*
310
+ * In the unlikely case policy is unregistered do not enable
311
+ * polling or h/w interrupt
312
+ */
313
+ mutex_lock (& data -> throttle_lock );
314
+ if (data -> cancel_throttle )
315
+ goto out ;
316
+
317
+ /*
318
+ * If h/w throttled frequency is higher than what cpufreq has requested
319
+ * for, then stop polling and switch back to interrupt mechanism.
320
+ */
321
+ if (throttled_freq >= qcom_cpufreq_hw_get (cpu ))
322
+ enable_irq (data -> throttle_irq );
323
+ else
324
+ mod_delayed_work (system_highpri_wq , & data -> throttle_work ,
325
+ msecs_to_jiffies (10 ));
326
+
327
+ out :
328
+ mutex_unlock (& data -> throttle_lock );
329
+ }
330
+
331
+ static void qcom_lmh_dcvs_poll (struct work_struct * work )
332
+ {
333
+ struct qcom_cpufreq_data * data ;
334
+
335
+ data = container_of (work , struct qcom_cpufreq_data , throttle_work .work );
336
+ qcom_lmh_dcvs_notify (data );
337
+ }
338
+
339
+ static irqreturn_t qcom_lmh_dcvs_handle_irq (int irq , void * data )
340
+ {
341
+ struct qcom_cpufreq_data * c_data = data ;
342
+
343
+ /* Disable interrupt and enable polling */
344
+ disable_irq_nosync (c_data -> throttle_irq );
345
+ qcom_lmh_dcvs_notify (c_data );
346
+
347
+ return 0 ;
348
+ }
349
+
254
350
static const struct qcom_cpufreq_soc_data qcom_soc_data = {
255
351
.reg_enable = 0x0 ,
256
352
.reg_freq_lut = 0x110 ,
257
353
.reg_volt_lut = 0x114 ,
354
+ .reg_current_vote = 0x704 ,
258
355
.reg_perf_state = 0x920 ,
259
356
.lut_row_size = 32 ,
260
357
};
@@ -274,6 +371,51 @@ static const struct of_device_id qcom_cpufreq_hw_match[] = {
274
371
};
275
372
MODULE_DEVICE_TABLE (of , qcom_cpufreq_hw_match );
276
373
374
+ static int qcom_cpufreq_hw_lmh_init (struct cpufreq_policy * policy , int index )
375
+ {
376
+ struct qcom_cpufreq_data * data = policy -> driver_data ;
377
+ struct platform_device * pdev = cpufreq_get_driver_data ();
378
+ char irq_name [15 ];
379
+ int ret ;
380
+
381
+ /*
382
+ * Look for LMh interrupt. If no interrupt line is specified /
383
+ * if there is an error, allow cpufreq to be enabled as usual.
384
+ */
385
+ data -> throttle_irq = platform_get_irq (pdev , index );
386
+ if (data -> throttle_irq <= 0 )
387
+ return data -> throttle_irq == - EPROBE_DEFER ? - EPROBE_DEFER : 0 ;
388
+
389
+ data -> cancel_throttle = false;
390
+ data -> policy = policy ;
391
+
392
+ mutex_init (& data -> throttle_lock );
393
+ INIT_DEFERRABLE_WORK (& data -> throttle_work , qcom_lmh_dcvs_poll );
394
+
395
+ snprintf (irq_name , sizeof (irq_name ), "dcvsh-irq-%u" , policy -> cpu );
396
+ ret = request_threaded_irq (data -> throttle_irq , NULL , qcom_lmh_dcvs_handle_irq ,
397
+ IRQF_ONESHOT , irq_name , data );
398
+ if (ret ) {
399
+ dev_err (& pdev -> dev , "Error registering %s: %d\n" , irq_name , ret );
400
+ return 0 ;
401
+ }
402
+
403
+ return 0 ;
404
+ }
405
+
406
+ static void qcom_cpufreq_hw_lmh_exit (struct qcom_cpufreq_data * data )
407
+ {
408
+ if (data -> throttle_irq <= 0 )
409
+ return ;
410
+
411
+ mutex_lock (& data -> throttle_lock );
412
+ data -> cancel_throttle = true;
413
+ mutex_unlock (& data -> throttle_lock );
414
+
415
+ cancel_delayed_work_sync (& data -> throttle_work );
416
+ free_irq (data -> throttle_irq , data );
417
+ }
418
+
277
419
static int qcom_cpufreq_hw_cpu_init (struct cpufreq_policy * policy )
278
420
{
279
421
struct platform_device * pdev = cpufreq_get_driver_data ();
@@ -368,6 +510,10 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
368
510
dev_warn (cpu_dev , "failed to enable boost: %d\n" , ret );
369
511
}
370
512
513
+ ret = qcom_cpufreq_hw_lmh_init (policy , index );
514
+ if (ret )
515
+ goto error ;
516
+
371
517
return 0 ;
372
518
error :
373
519
kfree (data );
@@ -387,6 +533,7 @@ static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
387
533
388
534
dev_pm_opp_remove_all_dynamic (cpu_dev );
389
535
dev_pm_opp_of_cpumask_remove_table (policy -> related_cpus );
536
+ qcom_cpufreq_hw_lmh_exit (data );
390
537
kfree (policy -> freq_table );
391
538
kfree (data );
392
539
iounmap (base );
0 commit comments