blob: afa6909aee865dfd004bced73b0f69cd07cb9a50 [file] [log] [blame]
Patrick Daly985c14b2012-12-03 17:12:37 -08001/*
2 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/io.h>
20#include <linux/delay.h>
21#include <linux/mutex.h>
22#include <linux/spinlock.h>
23#include <linux/errno.h>
24#include <linux/cpufreq.h>
25#include <linux/clk.h>
26#include <linux/platform_device.h>
27#include <linux/iopoll.h>
28
29#include <mach/board.h>
30#include <mach/msm_iomap.h>
31#include <mach/msm_bus.h>
32#include <mach/msm_bus_board.h>
33#include <mach/rpm-regulator.h>
34#include <mach/clk-provider.h>
35#include <mach/rpm-regulator-smd.h>
36
37#include "acpuclock.h"
38#include "acpuclock-cortex.h"
39
40#define POLL_INTERVAL_US 1
41#define APCS_RCG_UPDATE_TIMEOUT_US 20
42
Patrick Daly9196ed42013-03-13 15:59:03 -070043static struct acpuclk_drv_data *priv;
Patrick Daly985c14b2012-12-03 17:12:37 -080044static uint32_t bus_perf_client;
45
46/* Update the bus bandwidth request. */
47static void set_bus_bw(unsigned int bw)
48{
49 int ret;
50
Patrick Daly9196ed42013-03-13 15:59:03 -070051 if (bw >= priv->bus_scale->num_usecases) {
Patrick Daly985c14b2012-12-03 17:12:37 -080052 pr_err("invalid bandwidth request (%d)\n", bw);
53 return;
54 }
55
56 /* Update bandwidth if request has changed. This may sleep. */
57 ret = msm_bus_scale_client_update_request(bus_perf_client, bw);
58 if (ret)
59 pr_err("bandwidth request failed (%d)\n", ret);
60
61 return;
62}
63
64/* Apply any voltage increases. */
65static int increase_vdd(unsigned int vdd_cpu, unsigned int vdd_mem)
66{
67 int rc = 0;
68
Patrick Daly18748a72013-04-24 18:59:22 -070069 if (priv->vdd_mem) {
70 /*
71 * Increase vdd_mem before vdd_cpu. vdd_mem should
72 * be >= vdd_cpu.
73 */
74 rc = regulator_set_voltage(priv->vdd_mem, vdd_mem,
75 priv->vdd_max_mem);
76 if (rc) {
77 pr_err("vdd_mem increase failed (%d)\n", rc);
78 return rc;
79 }
Patrick Daly985c14b2012-12-03 17:12:37 -080080 }
81
Patrick Daly9196ed42013-03-13 15:59:03 -070082 rc = regulator_set_voltage(priv->vdd_cpu, vdd_cpu, priv->vdd_max_cpu);
Patrick Daly985c14b2012-12-03 17:12:37 -080083 if (rc)
84 pr_err("vdd_cpu increase failed (%d)\n", rc);
85
86 return rc;
87}
88
89/* Apply any per-cpu voltage decreases. */
90static void decrease_vdd(unsigned int vdd_cpu, unsigned int vdd_mem)
91{
92 int ret;
93
94 /* Update CPU voltage. */
Patrick Daly9196ed42013-03-13 15:59:03 -070095 ret = regulator_set_voltage(priv->vdd_cpu, vdd_cpu, priv->vdd_max_cpu);
Patrick Daly985c14b2012-12-03 17:12:37 -080096 if (ret) {
97 pr_err("vdd_cpu decrease failed (%d)\n", ret);
98 return;
99 }
100
Patrick Daly18748a72013-04-24 18:59:22 -0700101 if (!priv->vdd_mem)
102 return;
103
Patrick Daly985c14b2012-12-03 17:12:37 -0800104 /* Decrease vdd_mem after vdd_cpu. vdd_mem should be >= vdd_cpu. */
Patrick Daly9196ed42013-03-13 15:59:03 -0700105 ret = regulator_set_voltage(priv->vdd_mem, vdd_mem, priv->vdd_max_mem);
Patrick Daly985c14b2012-12-03 17:12:37 -0800106 if (ret)
107 pr_err("vdd_mem decrease failed (%d)\n", ret);
108}
109
110static void select_clk_source_div(struct acpuclk_drv_data *drv_data,
111 struct clkctl_acpu_speed *s)
112{
113 u32 regval, rc, src_div;
114 void __iomem *apcs_rcg_config = drv_data->apcs_rcg_config;
115 void __iomem *apcs_rcg_cmd = drv_data->apcs_rcg_cmd;
116 struct acpuclk_reg_data *r = &drv_data->reg_data;
117
118 src_div = s->src_div ? ((2 * s->src_div) - 1) : s->src_div;
119
120 regval = readl_relaxed(apcs_rcg_config);
121 regval &= ~r->cfg_src_mask;
122 regval |= s->src_sel << r->cfg_src_shift;
123 regval &= ~r->cfg_div_mask;
124 regval |= src_div << r->cfg_div_shift;
125 writel_relaxed(regval, apcs_rcg_config);
126
127 /* Update the configuration */
128 regval = readl_relaxed(apcs_rcg_cmd);
129 regval |= r->update_mask;
130 writel_relaxed(regval, apcs_rcg_cmd);
131
132 /* Wait for the update to take effect */
Patrick Daly6bda5912013-04-03 16:06:07 -0700133 rc = readl_poll_timeout_noirq(apcs_rcg_cmd, regval,
Patrick Daly985c14b2012-12-03 17:12:37 -0800134 !(regval & r->poll_mask),
135 POLL_INTERVAL_US,
136 APCS_RCG_UPDATE_TIMEOUT_US);
137 if (rc)
138 pr_warn("acpu rcg didn't update its configuration\n");
139}
140
Patrick Daly57d87e62013-04-09 18:51:51 -0700141static int set_speed_atomic(struct clkctl_acpu_speed *tgt_s)
142{
143 struct clkctl_acpu_speed *strt_s = priv->current_speed;
144 struct clk *strt = priv->src_clocks[strt_s->src].clk;
145 struct clk *tgt = priv->src_clocks[tgt_s->src].clk;
146 int rc = 0;
147
148 WARN(strt_s->src == ACPUPLL && tgt_s->src == ACPUPLL,
149 "can't reprogram ACPUPLL during atomic context\n");
150 rc = clk_enable(tgt);
151 if (rc)
152 return rc;
153
154 select_clk_source_div(priv, tgt_s);
155 clk_disable(strt);
156
157 return rc;
158}
159
160static int set_speed(struct clkctl_acpu_speed *tgt_s)
Patrick Daly985c14b2012-12-03 17:12:37 -0800161{
162 int rc = 0;
Patrick Daly83806032013-03-25 15:18:24 -0700163 unsigned int div = tgt_s->src_div ? tgt_s->src_div : 1;
164 unsigned int tgt_freq_hz = tgt_s->khz * 1000 * div;
Patrick Daly9196ed42013-03-13 15:59:03 -0700165 struct clkctl_acpu_speed *strt_s = priv->current_speed;
166 struct clkctl_acpu_speed *cxo_s = &priv->freq_tbl[0];
167 struct clk *strt = priv->src_clocks[strt_s->src].clk;
168 struct clk *tgt = priv->src_clocks[tgt_s->src].clk;
Patrick Daly985c14b2012-12-03 17:12:37 -0800169
170 if (strt_s->src == ACPUPLL && tgt_s->src == ACPUPLL) {
171 /* Switch to another always on src */
Patrick Daly9196ed42013-03-13 15:59:03 -0700172 select_clk_source_div(priv, cxo_s);
Patrick Daly985c14b2012-12-03 17:12:37 -0800173
174 /* Re-program acpu pll */
Patrick Daly57d87e62013-04-09 18:51:51 -0700175 clk_disable_unprepare(tgt);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800176
Patrick Daly985c14b2012-12-03 17:12:37 -0800177 rc = clk_set_rate(tgt, tgt_freq_hz);
178 if (rc)
179 pr_err("Failed to set ACPU PLL to %u\n", tgt_freq_hz);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800180
Patrick Daly57d87e62013-04-09 18:51:51 -0700181 BUG_ON(clk_prepare_enable(tgt));
Patrick Daly985c14b2012-12-03 17:12:37 -0800182
183 /* Switch back to acpu pll */
Patrick Daly9196ed42013-03-13 15:59:03 -0700184 select_clk_source_div(priv, tgt_s);
Patrick Daly985c14b2012-12-03 17:12:37 -0800185
186 } else if (strt_s->src != ACPUPLL && tgt_s->src == ACPUPLL) {
187 rc = clk_set_rate(tgt, tgt_freq_hz);
188 if (rc) {
189 pr_err("Failed to set ACPU PLL to %u\n", tgt_freq_hz);
190 return rc;
191 }
192
Patrick Daly57d87e62013-04-09 18:51:51 -0700193 rc = clk_prepare_enable(tgt);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800194
Patrick Daly985c14b2012-12-03 17:12:37 -0800195 if (rc) {
196 pr_err("ACPU PLL enable failed\n");
197 return rc;
198 }
199
Patrick Daly9196ed42013-03-13 15:59:03 -0700200 select_clk_source_div(priv, tgt_s);
Patrick Daly985c14b2012-12-03 17:12:37 -0800201
Patrick Daly57d87e62013-04-09 18:51:51 -0700202 clk_disable_unprepare(strt);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800203
Patrick Daly985c14b2012-12-03 17:12:37 -0800204 } else {
Patrick Daly57d87e62013-04-09 18:51:51 -0700205 rc = clk_prepare_enable(tgt);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800206
Patrick Daly985c14b2012-12-03 17:12:37 -0800207 if (rc) {
208 pr_err("%s enable failed\n",
Patrick Daly9196ed42013-03-13 15:59:03 -0700209 priv->src_clocks[tgt_s->src].name);
Patrick Daly985c14b2012-12-03 17:12:37 -0800210 return rc;
211 }
212
Patrick Daly9196ed42013-03-13 15:59:03 -0700213 select_clk_source_div(priv, tgt_s);
Patrick Daly985c14b2012-12-03 17:12:37 -0800214
Patrick Daly57d87e62013-04-09 18:51:51 -0700215 clk_disable_unprepare(strt);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800216
Patrick Daly985c14b2012-12-03 17:12:37 -0800217 }
218
219 return rc;
220}
221
222static int acpuclk_cortex_set_rate(int cpu, unsigned long rate,
223 enum setrate_reason reason)
224{
225 struct clkctl_acpu_speed *tgt_s, *strt_s;
226 int rc = 0;
227
228 if (reason == SETRATE_CPUFREQ)
Patrick Daly9196ed42013-03-13 15:59:03 -0700229 mutex_lock(&priv->lock);
Patrick Daly985c14b2012-12-03 17:12:37 -0800230
Patrick Daly9196ed42013-03-13 15:59:03 -0700231 strt_s = priv->current_speed;
Patrick Daly985c14b2012-12-03 17:12:37 -0800232
233 /* Return early if rate didn't change */
234 if (rate == strt_s->khz)
235 goto out;
236
237 /* Find target frequency */
Patrick Daly9196ed42013-03-13 15:59:03 -0700238 for (tgt_s = priv->freq_tbl; tgt_s->khz != 0; tgt_s++)
Patrick Daly985c14b2012-12-03 17:12:37 -0800239 if (tgt_s->khz == rate)
240 break;
241 if (tgt_s->khz == 0) {
242 rc = -EINVAL;
243 goto out;
244 }
245
246 /* Increase VDD levels if needed */
247 if ((reason == SETRATE_CPUFREQ || reason == SETRATE_INIT)
248 && (tgt_s->khz > strt_s->khz)) {
249 rc = increase_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
250 if (rc)
251 goto out;
252 }
253
254 pr_debug("Switching from CPU rate %u KHz -> %u KHz\n",
255 strt_s->khz, tgt_s->khz);
256
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800257 /* Switch CPU speed. Flag indicates atomic context */
258 if (reason == SETRATE_CPUFREQ || reason == SETRATE_INIT)
Patrick Daly57d87e62013-04-09 18:51:51 -0700259 rc = set_speed(tgt_s);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800260 else
Patrick Daly57d87e62013-04-09 18:51:51 -0700261 rc = set_speed_atomic(tgt_s);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800262
Patrick Daly985c14b2012-12-03 17:12:37 -0800263 if (rc)
264 goto out;
265
Patrick Daly9196ed42013-03-13 15:59:03 -0700266 priv->current_speed = tgt_s;
Patrick Daly985c14b2012-12-03 17:12:37 -0800267 pr_debug("CPU speed change complete\n");
268
269 /* Nothing else to do for SWFI or power-collapse. */
270 if (reason == SETRATE_SWFI || reason == SETRATE_PC)
271 goto out;
272
273 /* Update bus bandwith request */
274 set_bus_bw(tgt_s->bw_level);
275
276 /* Drop VDD levels if we can. */
277 if (tgt_s->khz < strt_s->khz)
278 decrease_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
279
280out:
281 if (reason == SETRATE_CPUFREQ)
Patrick Daly9196ed42013-03-13 15:59:03 -0700282 mutex_unlock(&priv->lock);
Patrick Daly985c14b2012-12-03 17:12:37 -0800283 return rc;
284}
285
286static unsigned long acpuclk_cortex_get_rate(int cpu)
287{
Patrick Daly9196ed42013-03-13 15:59:03 -0700288 return priv->current_speed->khz;
Patrick Daly985c14b2012-12-03 17:12:37 -0800289}
290
291#ifdef CONFIG_CPU_FREQ_MSM
292static struct cpufreq_frequency_table freq_table[30];
293
294static void __init cpufreq_table_init(void)
295{
296 int i, freq_cnt = 0;
297
Patrick Daly9196ed42013-03-13 15:59:03 -0700298 /* Construct the freq_table tables from priv->freq_tbl. */
299 for (i = 0; priv->freq_tbl[i].khz != 0
Patrick Daly985c14b2012-12-03 17:12:37 -0800300 && freq_cnt < ARRAY_SIZE(freq_table); i++) {
Patrick Daly9196ed42013-03-13 15:59:03 -0700301 if (!priv->freq_tbl[i].use_for_scaling)
Patrick Daly985c14b2012-12-03 17:12:37 -0800302 continue;
303 freq_table[freq_cnt].index = freq_cnt;
Patrick Daly9196ed42013-03-13 15:59:03 -0700304 freq_table[freq_cnt].frequency = priv->freq_tbl[i].khz;
Patrick Daly985c14b2012-12-03 17:12:37 -0800305 freq_cnt++;
306 }
307 /* freq_table not big enough to store all usable freqs. */
Patrick Daly9196ed42013-03-13 15:59:03 -0700308 BUG_ON(priv->freq_tbl[i].khz != 0);
Patrick Daly985c14b2012-12-03 17:12:37 -0800309
310 freq_table[freq_cnt].index = freq_cnt;
311 freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END;
312
313 pr_info("CPU: %d scaling frequencies supported.\n", freq_cnt);
314
315 /* Register table with CPUFreq. */
316 for_each_possible_cpu(i)
317 cpufreq_frequency_table_get_attr(freq_table, i);
318}
319#else
320static void __init cpufreq_table_init(void) {}
321#endif
322
323static struct acpuclk_data acpuclk_cortex_data = {
324 .set_rate = acpuclk_cortex_set_rate,
325 .get_rate = acpuclk_cortex_get_rate,
Patrick Daly985c14b2012-12-03 17:12:37 -0800326};
327
328int __init acpuclk_cortex_init(struct platform_device *pdev,
329 struct acpuclk_drv_data *data)
330{
331 unsigned long max_cpu_khz = 0;
332 int i, rc;
333
Patrick Daly9196ed42013-03-13 15:59:03 -0700334 priv = data;
335 mutex_init(&priv->lock);
Patrick Daly985c14b2012-12-03 17:12:37 -0800336
Patrick Dalyaf8808e2013-03-20 12:57:00 -0700337 acpuclk_cortex_data.power_collapse_khz = priv->wait_for_irq_khz;
338 acpuclk_cortex_data.wait_for_irq_khz = priv->wait_for_irq_khz;
339
Patrick Daly9196ed42013-03-13 15:59:03 -0700340 bus_perf_client = msm_bus_scale_register_client(priv->bus_scale);
Patrick Daly985c14b2012-12-03 17:12:37 -0800341 if (!bus_perf_client) {
342 pr_err("Unable to register bus client\n");
343 BUG();
344 }
345
Patrick Daly985c14b2012-12-03 17:12:37 -0800346 /* Improve boot time by ramping up CPU immediately */
Patrick Daly9196ed42013-03-13 15:59:03 -0700347 for (i = 0; priv->freq_tbl[i].khz != 0; i++)
348 if (priv->freq_tbl[i].use_for_scaling)
349 max_cpu_khz = priv->freq_tbl[i].khz;
Patrick Daly985c14b2012-12-03 17:12:37 -0800350
351 /* Initialize regulators */
Patrick Daly9196ed42013-03-13 15:59:03 -0700352 rc = increase_vdd(priv->vdd_max_cpu, priv->vdd_max_mem);
Patrick Daly985c14b2012-12-03 17:12:37 -0800353 if (rc)
354 goto err_vdd;
355
Patrick Daly18748a72013-04-24 18:59:22 -0700356 if (priv->vdd_mem) {
357 rc = regulator_enable(priv->vdd_mem);
358 if (rc) {
359 dev_err(&pdev->dev, "regulator_enable for mem failed\n");
360 goto err_vdd;
361 }
Patrick Daly985c14b2012-12-03 17:12:37 -0800362 }
363
Patrick Daly9196ed42013-03-13 15:59:03 -0700364 rc = regulator_enable(priv->vdd_cpu);
Patrick Daly985c14b2012-12-03 17:12:37 -0800365 if (rc) {
366 dev_err(&pdev->dev, "regulator_enable for cpu failed\n");
367 goto err_vdd_cpu;
368 }
369
Patrick Daly71839d42013-02-25 13:05:05 -0800370 /*
371 * Select a state which is always a valid transition to align SW with
372 * the HW configuration set by the bootloaders.
373 */
374 acpuclk_cortex_set_rate(0, acpuclk_cortex_data.power_collapse_khz,
375 SETRATE_INIT);
Patrick Daly985c14b2012-12-03 17:12:37 -0800376 acpuclk_cortex_set_rate(0, max_cpu_khz, SETRATE_INIT);
377
378 acpuclk_register(&acpuclk_cortex_data);
379 cpufreq_table_init();
380
381 return 0;
382
383err_vdd_cpu:
Patrick Daly18748a72013-04-24 18:59:22 -0700384 if (priv->vdd_mem)
385 regulator_disable(priv->vdd_mem);
Patrick Daly985c14b2012-12-03 17:12:37 -0800386err_vdd:
Patrick Daly985c14b2012-12-03 17:12:37 -0800387 return rc;
388}