ramips: revert faulty 4.4 config change from 9c242270907
[oweals/openwrt.git] / target / linux / ipq806x / patches-4.4 / 172-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch
1 From 175329015c8a0b480240da222822d2f8316f074d Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Mon, 1 Jun 2015 18:47:58 -0700
4 Subject: 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 ---
21  drivers/cpufreq/cpufreq-dt.c | 72 ++++++++++++++++++++++++++++++++++++++++----
22  1 file changed, 66 insertions(+), 6 deletions(-)
23
24 --- a/drivers/cpufreq/cpufreq-dt.c
25 +++ b/drivers/cpufreq/cpufreq-dt.c
26 @@ -34,6 +34,9 @@ struct private_data {
27         struct regulator *cpu_reg;
28         struct thermal_cooling_device *cdev;
29         unsigned int voltage_tolerance; /* in percentage */
30 +       struct notifier_block opp_nb;
31 +       struct mutex lock;
32 +       unsigned long opp_freq;
33  };
34  
35  static struct freq_attr *cpufreq_dt_attr[] = {
36 @@ -42,6 +45,42 @@ static struct freq_attr *cpufreq_dt_attr
37         NULL,
38  };
39  
40 +static int opp_notifier(struct notifier_block *nb, unsigned long event,
41 +                       void *data)
42 +{
43 +       struct dev_pm_opp *opp = data;
44 +       struct private_data *priv = container_of(nb, struct private_data,
45 +                                                opp_nb);
46 +       struct device *cpu_dev = priv->cpu_dev;
47 +       struct regulator *cpu_reg = priv->cpu_reg;
48 +       unsigned long volt, tol, freq;
49 +       int ret = 0;
50 +
51 +       switch (event) {
52 +               case OPP_EVENT_ADJUST_VOLTAGE:
53 +                       volt = dev_pm_opp_get_voltage(opp);
54 +                       freq = dev_pm_opp_get_freq(opp);
55 +                       tol = volt * priv->voltage_tolerance / 100;
56 +
57 +                       mutex_lock(&priv->lock);
58 +                       if (freq == priv->opp_freq)
59 +                               ret = regulator_set_voltage_tol(cpu_reg, volt,
60 +                                                               tol);
61 +                       mutex_unlock(&priv->lock);
62 +                       if (ret) {
63 +                               dev_err(cpu_dev,
64 +                                       "failed to scale voltage up: %d\n",
65 +                                       ret);
66 +                               return ret;
67 +                       }
68 +                       break;
69 +               default:
70 +                       break;
71 +       }
72 +
73 +       return 0;
74 +}
75 +
76  static int set_target(struct cpufreq_policy *policy, unsigned int index)
77  {
78         struct dev_pm_opp *opp;
79 @@ -53,6 +92,7 @@ static int set_target(struct cpufreq_pol
80         unsigned long volt = 0, volt_old = 0, tol = 0;
81         unsigned int old_freq, new_freq;
82         long freq_Hz, freq_exact;
83 +       unsigned long opp_freq = 0;
84         int ret;
85  
86         freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
87 @@ -63,8 +103,8 @@ static int set_target(struct cpufreq_pol
88         new_freq = freq_Hz / 1000;
89         old_freq = clk_get_rate(cpu_clk) / 1000;
90  
91 +       mutex_lock(&priv->lock);
92         if (!IS_ERR(cpu_reg)) {
93 -               unsigned long opp_freq;
94  
95                 rcu_read_lock();
96                 opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
97 @@ -72,7 +112,8 @@ static int set_target(struct cpufreq_pol
98                         rcu_read_unlock();
99                         dev_err(cpu_dev, "failed to find OPP for %ld\n",
100                                 freq_Hz);
101 -                       return PTR_ERR(opp);
102 +                       ret = PTR_ERR(opp);
103 +                       goto out;
104                 }
105                 volt = dev_pm_opp_get_voltage(opp);
106                 opp_freq = dev_pm_opp_get_freq(opp);
107 @@ -93,7 +134,7 @@ static int set_target(struct cpufreq_pol
108                 if (ret) {
109                         dev_err(cpu_dev, "failed to scale voltage up: %d\n",
110                                 ret);
111 -                       return ret;
112 +                       goto out;
113                 }
114         }
115  
116 @@ -102,7 +143,7 @@ static int set_target(struct cpufreq_pol
117                 dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
118                 if (!IS_ERR(cpu_reg) && volt_old > 0)
119                         regulator_set_voltage_tol(cpu_reg, volt_old, tol);
120 -               return ret;
121 +               goto out;
122         }
123  
124         /* scaling down?  scale voltage after frequency */
125 @@ -112,9 +153,12 @@ static int set_target(struct cpufreq_pol
126                         dev_err(cpu_dev, "failed to scale voltage down: %d\n",
127                                 ret);
128                         clk_set_rate(cpu_clk, old_freq * 1000);
129 +                       goto out;
130                 }
131         }
132 -
133 +       priv->opp_freq = opp_freq;
134 +out:
135 +       mutex_unlock(&priv->lock);
136         return ret;
137  }
138  
139 @@ -201,6 +245,7 @@ static int cpufreq_init(struct cpufreq_p
140         unsigned int transition_latency;
141         bool need_update = false;
142         int ret;
143 +       struct srcu_notifier_head *opp_srcu_head;
144  
145         ret = allocate_resources(policy->cpu, &cpu_dev, &cpu_reg, &cpu_clk);
146         if (ret) {
147 @@ -277,6 +322,19 @@ static int cpufreq_init(struct cpufreq_p
148                 goto out_free_opp;
149         }
150  
151 +       mutex_init(&priv->lock);
152 +
153 +       opp_srcu_head = dev_pm_opp_get_notifier(cpu_dev);
154 +       if (IS_ERR(opp_srcu_head)) {
155 +               ret = PTR_ERR(opp_srcu_head);
156 +               goto out_free_priv;
157 +       }
158 +
159 +       priv->opp_nb.notifier_call = opp_notifier;
160 +       ret = srcu_notifier_chain_register(opp_srcu_head, &priv->opp_nb);
161 +       if (ret)
162 +               goto out_free_priv;
163 +
164         of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance);
165  
166         if (!transition_latency)
167 @@ -326,7 +384,7 @@ static int cpufreq_init(struct cpufreq_p
168         ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
169         if (ret) {
170                 pr_err("failed to init cpufreq table: %d\n", ret);
171 -               goto out_free_priv;
172 +               goto out_unregister_nb;
173         }
174  
175         priv->cpu_dev = cpu_dev;
176 @@ -365,6 +423,8 @@ static int cpufreq_init(struct cpufreq_p
177  
178  out_free_cpufreq_table:
179         dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
180 +out_unregister_nb:
181 +       srcu_notifier_chain_unregister(opp_srcu_head, &priv->opp_nb);
182  out_free_priv:
183         kfree(priv);
184  out_free_opp: