77#include <linux/cpufreq.h>
88#include <linux/init.h>
99#include <linux/interconnect.h>
10+ #include <linux/interrupt.h>
1011#include <linux/kernel.h>
1112#include <linux/module.h>
1213#include <linux/of_address.h>
1314#include <linux/of_platform.h>
1415#include <linux/pm_opp.h>
1516#include <linux/slab.h>
17+ #include <linux/spinlock.h>
1618
1719#define LUT_MAX_ENTRIES 40U
1820#define LUT_SRC GENMASK(31, 30)
2224#define CLK_HW_DIV 2
2325#define LUT_TURBO_IND 1
2426
27+ #define HZ_PER_KHZ 1000
28+
2529struct qcom_cpufreq_soc_data {
2630 u32 reg_enable ;
2731 u32 reg_freq_lut ;
2832 u32 reg_volt_lut ;
33+ u32 reg_current_vote ;
2934 u32 reg_perf_state ;
3035 u8 lut_row_size ;
3136};
@@ -34,6 +39,16 @@ struct qcom_cpufreq_data {
3439 void __iomem * base ;
3540 struct resource * res ;
3641 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 ;
3752};
3853
3954static unsigned long cpu_hw_rate , xo_rate ;
@@ -251,10 +266,92 @@ static void qcom_get_related_cpus(int index, struct cpumask *m)
251266 }
252267}
253268
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+
254350static const struct qcom_cpufreq_soc_data qcom_soc_data = {
255351 .reg_enable = 0x0 ,
256352 .reg_freq_lut = 0x110 ,
257353 .reg_volt_lut = 0x114 ,
354+ .reg_current_vote = 0x704 ,
258355 .reg_perf_state = 0x920 ,
259356 .lut_row_size = 32 ,
260357};
@@ -274,6 +371,51 @@ static const struct of_device_id qcom_cpufreq_hw_match[] = {
274371};
275372MODULE_DEVICE_TABLE (of , qcom_cpufreq_hw_match );
276373
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+
277419static int qcom_cpufreq_hw_cpu_init (struct cpufreq_policy * policy )
278420{
279421 struct platform_device * pdev = cpufreq_get_driver_data ();
@@ -368,6 +510,10 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
368510 dev_warn (cpu_dev , "failed to enable boost: %d\n" , ret );
369511 }
370512
513+ ret = qcom_cpufreq_hw_lmh_init (policy , index );
514+ if (ret )
515+ goto error ;
516+
371517 return 0 ;
372518error :
373519 kfree (data );
@@ -387,6 +533,7 @@ static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
387533
388534 dev_pm_opp_remove_all_dynamic (cpu_dev );
389535 dev_pm_opp_of_cpumask_remove_table (policy -> related_cpus );
536+ qcom_cpufreq_hw_lmh_exit (data );
390537 kfree (policy -> freq_table );
391538 kfree (data );
392539 iounmap (base );
0 commit comments