kernel: rename CONFIG_TRACE_ENUM_MAP_FILE to CONFIG_TRACE_EVAL_MAP_FILE
[oweals/openwrt.git] / target / linux / ipq806x / patches-4.9 / 0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch
1 From 10577f74c35bd395951d1b2382c8d821089b5745 Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Fri, 18 Sep 2015 17:52:08 -0700
4 Subject: [PATCH 54/69] cpufreq-dt: Handle OPP voltage adjust events
5
6 On some SoCs the Adaptive Voltage Scaling (AVS) technique is
7 employed to optimize the operating voltage of a device. At a
8 given frequency, the hardware monitors dynamic factors and either
9 makes a suggestion for how much to adjust a voltage for the
10 current frequency, or it automatically adjusts the voltage
11 without software intervention.
12
13 In the former case, an AVS driver will call
14 dev_pm_opp_modify_voltage() and update the voltage for the
15 particular OPP the CPUs are using. Add an OPP notifier to
16 cpufreq-dt so that we can adjust the voltage of the CPU when AVS
17 updates the OPP.
18
19 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
20 Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
21 Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
22 ---
23  drivers/cpufreq/cpufreq-dt.c | 68 ++++++++++++++++++++++++++++++++++++++++++--
24  1 file changed, 65 insertions(+), 3 deletions(-)
25
26 --- a/drivers/cpufreq/cpufreq-dt.c
27 +++ b/drivers/cpufreq/cpufreq-dt.c
28 @@ -32,6 +32,9 @@ struct private_data {
29         struct device *cpu_dev;
30         struct thermal_cooling_device *cdev;
31         const char *reg_name;
32 +       struct notifier_block opp_nb;
33 +       struct mutex lock;
34 +       unsigned long opp_freq;
35  };
36  
37  static struct freq_attr *cpufreq_dt_attr[] = {
38 @@ -43,9 +46,16 @@ static struct freq_attr *cpufreq_dt_attr
39  static int set_target(struct cpufreq_policy *policy, unsigned int index)
40  {
41         struct private_data *priv = policy->driver_data;
42 +       int ret;
43 +       unsigned long target_freq = policy->freq_table[index].frequency * 1000;
44 +
45 +       mutex_lock(&priv->lock);
46 +       ret = dev_pm_opp_set_rate(priv->cpu_dev, target_freq);
47 +       if (!ret)
48 +               priv->opp_freq = target_freq;
49 +       mutex_unlock(&priv->lock);
50  
51 -       return dev_pm_opp_set_rate(priv->cpu_dev,
52 -                                  policy->freq_table[index].frequency * 1000);
53 +       return ret;
54  }
55  
56  /*
57 @@ -86,6 +96,39 @@ node_put:
58         return name;
59  }
60  
61 +static int opp_notifier(struct notifier_block *nb, unsigned long event,
62 +                       void *data)
63 +{
64 +       struct dev_pm_opp *opp = data;
65 +       struct private_data *priv = container_of(nb, struct private_data,
66 +                                                opp_nb);
67 +       struct device *cpu_dev = priv->cpu_dev;
68 +       struct regulator *cpu_reg;
69 +       unsigned long volt, freq;
70 +       int ret = 0;
71 +
72 +       if (event == OPP_EVENT_ADJUST_VOLTAGE) {
73 +               cpu_reg = dev_pm_opp_get_regulator(cpu_dev);
74 +               if (IS_ERR(cpu_reg)) {
75 +                       ret = PTR_ERR(cpu_reg);
76 +                       goto out;
77 +               }
78 +               volt = dev_pm_opp_get_voltage(opp);
79 +               freq = dev_pm_opp_get_freq(opp);
80 +
81 +               mutex_lock(&priv->lock);
82 +               if (freq == priv->opp_freq) {
83 +                       ret = regulator_set_voltage_triplet(cpu_reg, volt, volt, volt);
84 +               }
85 +               mutex_unlock(&priv->lock);
86 +               if (ret)
87 +                       dev_err(cpu_dev, "failed to scale voltage: %d\n", ret);
88 +       }
89 +
90 +out:
91 +       return notifier_from_errno(ret);
92 +}
93 +
94  static int resources_available(void)
95  {
96         struct device *cpu_dev;
97 @@ -153,6 +196,7 @@ static int cpufreq_init(struct cpufreq_p
98         bool fallback = false;
99         const char *name;
100         int ret;
101 +       struct srcu_notifier_head *opp_srcu_head;
102  
103         cpu_dev = get_cpu_device(policy->cpu);
104         if (!cpu_dev) {
105 @@ -242,13 +286,29 @@ static int cpufreq_init(struct cpufreq_p
106                 goto out_free_opp;
107         }
108  
109 +       mutex_init(&priv->lock);
110 +
111 +       rcu_read_lock();
112 +       opp_srcu_head = dev_pm_opp_get_notifier(cpu_dev);
113 +       if (IS_ERR(opp_srcu_head)) {
114 +               ret = PTR_ERR(opp_srcu_head);
115 +               rcu_read_unlock();
116 +               goto out_free_priv;
117 +       }
118 +
119 +       priv->opp_nb.notifier_call = opp_notifier;
120 +       ret = srcu_notifier_chain_register(opp_srcu_head, &priv->opp_nb);
121 +       rcu_read_unlock();
122 +       if (ret)
123 +               goto out_free_priv;
124 +
125         priv->reg_name = name;
126         priv->opp_table = opp_table;
127  
128         ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
129         if (ret) {
130                 dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
131 -               goto out_free_priv;
132 +               goto out_unregister_nb;
133         }
134  
135         priv->cpu_dev = cpu_dev;
136 @@ -287,6 +347,8 @@ static int cpufreq_init(struct cpufreq_p
137  
138  out_free_cpufreq_table:
139         dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
140 +out_unregister_nb:
141 +       srcu_notifier_chain_unregister(opp_srcu_head, &priv->opp_nb);
142  out_free_priv:
143         kfree(priv);
144  out_free_opp: