blob: 47bf27a0cb69bcb915d281f5fa0dc8381020df9e [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
69 /* Increase vdd_mem before vdd_cpu. vdd_mem should be >= vdd_cpu. */
Patrick Daly9196ed42013-03-13 15:59:03 -070070 rc = regulator_set_voltage(priv->vdd_mem, vdd_mem, priv->vdd_max_mem);
Patrick Daly985c14b2012-12-03 17:12:37 -080071 if (rc) {
72 pr_err("vdd_mem increase failed (%d)\n", rc);
73 return rc;
74 }
75
Patrick Daly9196ed42013-03-13 15:59:03 -070076 rc = regulator_set_voltage(priv->vdd_cpu, vdd_cpu, priv->vdd_max_cpu);
Patrick Daly985c14b2012-12-03 17:12:37 -080077 if (rc)
78 pr_err("vdd_cpu increase failed (%d)\n", rc);
79
80 return rc;
81}
82
83/* Apply any per-cpu voltage decreases. */
84static void decrease_vdd(unsigned int vdd_cpu, unsigned int vdd_mem)
85{
86 int ret;
87
88 /* Update CPU voltage. */
Patrick Daly9196ed42013-03-13 15:59:03 -070089 ret = regulator_set_voltage(priv->vdd_cpu, vdd_cpu, priv->vdd_max_cpu);
Patrick Daly985c14b2012-12-03 17:12:37 -080090 if (ret) {
91 pr_err("vdd_cpu decrease failed (%d)\n", ret);
92 return;
93 }
94
95 /* Decrease vdd_mem after vdd_cpu. vdd_mem should be >= vdd_cpu. */
Patrick Daly9196ed42013-03-13 15:59:03 -070096 ret = regulator_set_voltage(priv->vdd_mem, vdd_mem, priv->vdd_max_mem);
Patrick Daly985c14b2012-12-03 17:12:37 -080097 if (ret)
98 pr_err("vdd_mem decrease failed (%d)\n", ret);
99}
100
101static void select_clk_source_div(struct acpuclk_drv_data *drv_data,
102 struct clkctl_acpu_speed *s)
103{
104 u32 regval, rc, src_div;
105 void __iomem *apcs_rcg_config = drv_data->apcs_rcg_config;
106 void __iomem *apcs_rcg_cmd = drv_data->apcs_rcg_cmd;
107 struct acpuclk_reg_data *r = &drv_data->reg_data;
108
109 src_div = s->src_div ? ((2 * s->src_div) - 1) : s->src_div;
110
111 regval = readl_relaxed(apcs_rcg_config);
112 regval &= ~r->cfg_src_mask;
113 regval |= s->src_sel << r->cfg_src_shift;
114 regval &= ~r->cfg_div_mask;
115 regval |= src_div << r->cfg_div_shift;
116 writel_relaxed(regval, apcs_rcg_config);
117
118 /* Update the configuration */
119 regval = readl_relaxed(apcs_rcg_cmd);
120 regval |= r->update_mask;
121 writel_relaxed(regval, apcs_rcg_cmd);
122
123 /* Wait for the update to take effect */
Patrick Daly6bda5912013-04-03 16:06:07 -0700124 rc = readl_poll_timeout_noirq(apcs_rcg_cmd, regval,
Patrick Daly985c14b2012-12-03 17:12:37 -0800125 !(regval & r->poll_mask),
126 POLL_INTERVAL_US,
127 APCS_RCG_UPDATE_TIMEOUT_US);
128 if (rc)
129 pr_warn("acpu rcg didn't update its configuration\n");
130}
131
Patrick Daly57d87e62013-04-09 18:51:51 -0700132static int set_speed_atomic(struct clkctl_acpu_speed *tgt_s)
133{
134 struct clkctl_acpu_speed *strt_s = priv->current_speed;
135 struct clk *strt = priv->src_clocks[strt_s->src].clk;
136 struct clk *tgt = priv->src_clocks[tgt_s->src].clk;
137 int rc = 0;
138
139 WARN(strt_s->src == ACPUPLL && tgt_s->src == ACPUPLL,
140 "can't reprogram ACPUPLL during atomic context\n");
141 rc = clk_enable(tgt);
142 if (rc)
143 return rc;
144
145 select_clk_source_div(priv, tgt_s);
146 clk_disable(strt);
147
148 return rc;
149}
150
151static int set_speed(struct clkctl_acpu_speed *tgt_s)
Patrick Daly985c14b2012-12-03 17:12:37 -0800152{
153 int rc = 0;
154 unsigned int tgt_freq_hz = tgt_s->khz * 1000;
Patrick Daly9196ed42013-03-13 15:59:03 -0700155 struct clkctl_acpu_speed *strt_s = priv->current_speed;
156 struct clkctl_acpu_speed *cxo_s = &priv->freq_tbl[0];
157 struct clk *strt = priv->src_clocks[strt_s->src].clk;
158 struct clk *tgt = priv->src_clocks[tgt_s->src].clk;
Patrick Daly985c14b2012-12-03 17:12:37 -0800159
160 if (strt_s->src == ACPUPLL && tgt_s->src == ACPUPLL) {
161 /* Switch to another always on src */
Patrick Daly9196ed42013-03-13 15:59:03 -0700162 select_clk_source_div(priv, cxo_s);
Patrick Daly985c14b2012-12-03 17:12:37 -0800163
164 /* Re-program acpu pll */
Patrick Daly57d87e62013-04-09 18:51:51 -0700165 clk_disable_unprepare(tgt);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800166
Patrick Daly985c14b2012-12-03 17:12:37 -0800167 rc = clk_set_rate(tgt, tgt_freq_hz);
168 if (rc)
169 pr_err("Failed to set ACPU PLL to %u\n", tgt_freq_hz);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800170
Patrick Daly57d87e62013-04-09 18:51:51 -0700171 BUG_ON(clk_prepare_enable(tgt));
Patrick Daly985c14b2012-12-03 17:12:37 -0800172
173 /* Switch back to acpu pll */
Patrick Daly9196ed42013-03-13 15:59:03 -0700174 select_clk_source_div(priv, tgt_s);
Patrick Daly985c14b2012-12-03 17:12:37 -0800175
176 } else if (strt_s->src != ACPUPLL && tgt_s->src == ACPUPLL) {
177 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);
180 return rc;
181 }
182
Patrick Daly57d87e62013-04-09 18:51:51 -0700183 rc = clk_prepare_enable(tgt);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800184
Patrick Daly985c14b2012-12-03 17:12:37 -0800185 if (rc) {
186 pr_err("ACPU PLL enable failed\n");
187 return rc;
188 }
189
Patrick Daly9196ed42013-03-13 15:59:03 -0700190 select_clk_source_div(priv, tgt_s);
Patrick Daly985c14b2012-12-03 17:12:37 -0800191
Patrick Daly57d87e62013-04-09 18:51:51 -0700192 clk_disable_unprepare(strt);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800193
Patrick Daly985c14b2012-12-03 17:12:37 -0800194 } else {
Patrick Daly57d87e62013-04-09 18:51:51 -0700195 rc = clk_prepare_enable(tgt);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800196
Patrick Daly985c14b2012-12-03 17:12:37 -0800197 if (rc) {
198 pr_err("%s enable failed\n",
Patrick Daly9196ed42013-03-13 15:59:03 -0700199 priv->src_clocks[tgt_s->src].name);
Patrick Daly985c14b2012-12-03 17:12:37 -0800200 return rc;
201 }
202
Patrick Daly9196ed42013-03-13 15:59:03 -0700203 select_clk_source_div(priv, tgt_s);
Patrick Daly985c14b2012-12-03 17:12:37 -0800204
Patrick Daly57d87e62013-04-09 18:51:51 -0700205 clk_disable_unprepare(strt);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800206
Patrick Daly985c14b2012-12-03 17:12:37 -0800207 }
208
209 return rc;
210}
211
212static int acpuclk_cortex_set_rate(int cpu, unsigned long rate,
213 enum setrate_reason reason)
214{
215 struct clkctl_acpu_speed *tgt_s, *strt_s;
216 int rc = 0;
217
218 if (reason == SETRATE_CPUFREQ)
Patrick Daly9196ed42013-03-13 15:59:03 -0700219 mutex_lock(&priv->lock);
Patrick Daly985c14b2012-12-03 17:12:37 -0800220
Patrick Daly9196ed42013-03-13 15:59:03 -0700221 strt_s = priv->current_speed;
Patrick Daly985c14b2012-12-03 17:12:37 -0800222
223 /* Return early if rate didn't change */
224 if (rate == strt_s->khz)
225 goto out;
226
227 /* Find target frequency */
Patrick Daly9196ed42013-03-13 15:59:03 -0700228 for (tgt_s = priv->freq_tbl; tgt_s->khz != 0; tgt_s++)
Patrick Daly985c14b2012-12-03 17:12:37 -0800229 if (tgt_s->khz == rate)
230 break;
231 if (tgt_s->khz == 0) {
232 rc = -EINVAL;
233 goto out;
234 }
235
236 /* Increase VDD levels if needed */
237 if ((reason == SETRATE_CPUFREQ || reason == SETRATE_INIT)
238 && (tgt_s->khz > strt_s->khz)) {
239 rc = increase_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
240 if (rc)
241 goto out;
242 }
243
244 pr_debug("Switching from CPU rate %u KHz -> %u KHz\n",
245 strt_s->khz, tgt_s->khz);
246
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800247 /* Switch CPU speed. Flag indicates atomic context */
248 if (reason == SETRATE_CPUFREQ || reason == SETRATE_INIT)
Patrick Daly57d87e62013-04-09 18:51:51 -0700249 rc = set_speed(tgt_s);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800250 else
Patrick Daly57d87e62013-04-09 18:51:51 -0700251 rc = set_speed_atomic(tgt_s);
Patrick Dalye85c6bc2013-01-31 14:14:28 -0800252
Patrick Daly985c14b2012-12-03 17:12:37 -0800253 if (rc)
254 goto out;
255
Patrick Daly9196ed42013-03-13 15:59:03 -0700256 priv->current_speed = tgt_s;
Patrick Daly985c14b2012-12-03 17:12:37 -0800257 pr_debug("CPU speed change complete\n");
258
259 /* Nothing else to do for SWFI or power-collapse. */
260 if (reason == SETRATE_SWFI || reason == SETRATE_PC)
261 goto out;
262
263 /* Update bus bandwith request */
264 set_bus_bw(tgt_s->bw_level);
265
266 /* Drop VDD levels if we can. */
267 if (tgt_s->khz < strt_s->khz)
268 decrease_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
269
270out:
271 if (reason == SETRATE_CPUFREQ)
Patrick Daly9196ed42013-03-13 15:59:03 -0700272 mutex_unlock(&priv->lock);
Patrick Daly985c14b2012-12-03 17:12:37 -0800273 return rc;
274}
275
276static unsigned long acpuclk_cortex_get_rate(int cpu)
277{
Patrick Daly9196ed42013-03-13 15:59:03 -0700278 return priv->current_speed->khz;
Patrick Daly985c14b2012-12-03 17:12:37 -0800279}
280
281#ifdef CONFIG_CPU_FREQ_MSM
282static struct cpufreq_frequency_table freq_table[30];
283
284static void __init cpufreq_table_init(void)
285{
286 int i, freq_cnt = 0;
287
Patrick Daly9196ed42013-03-13 15:59:03 -0700288 /* Construct the freq_table tables from priv->freq_tbl. */
289 for (i = 0; priv->freq_tbl[i].khz != 0
Patrick Daly985c14b2012-12-03 17:12:37 -0800290 && freq_cnt < ARRAY_SIZE(freq_table); i++) {
Patrick Daly9196ed42013-03-13 15:59:03 -0700291 if (!priv->freq_tbl[i].use_for_scaling)
Patrick Daly985c14b2012-12-03 17:12:37 -0800292 continue;
293 freq_table[freq_cnt].index = freq_cnt;
Patrick Daly9196ed42013-03-13 15:59:03 -0700294 freq_table[freq_cnt].frequency = priv->freq_tbl[i].khz;
Patrick Daly985c14b2012-12-03 17:12:37 -0800295 freq_cnt++;
296 }
297 /* freq_table not big enough to store all usable freqs. */
Patrick Daly9196ed42013-03-13 15:59:03 -0700298 BUG_ON(priv->freq_tbl[i].khz != 0);
Patrick Daly985c14b2012-12-03 17:12:37 -0800299
300 freq_table[freq_cnt].index = freq_cnt;
301 freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END;
302
303 pr_info("CPU: %d scaling frequencies supported.\n", freq_cnt);
304
305 /* Register table with CPUFreq. */
306 for_each_possible_cpu(i)
307 cpufreq_frequency_table_get_attr(freq_table, i);
308}
309#else
310static void __init cpufreq_table_init(void) {}
311#endif
312
313static struct acpuclk_data acpuclk_cortex_data = {
314 .set_rate = acpuclk_cortex_set_rate,
315 .get_rate = acpuclk_cortex_get_rate,
Patrick Daly985c14b2012-12-03 17:12:37 -0800316};
317
318int __init acpuclk_cortex_init(struct platform_device *pdev,
319 struct acpuclk_drv_data *data)
320{
321 unsigned long max_cpu_khz = 0;
322 int i, rc;
323
Patrick Daly9196ed42013-03-13 15:59:03 -0700324 priv = data;
325 mutex_init(&priv->lock);
Patrick Daly985c14b2012-12-03 17:12:37 -0800326
Patrick Dalyaf8808e2013-03-20 12:57:00 -0700327 acpuclk_cortex_data.power_collapse_khz = priv->wait_for_irq_khz;
328 acpuclk_cortex_data.wait_for_irq_khz = priv->wait_for_irq_khz;
329
Patrick Daly9196ed42013-03-13 15:59:03 -0700330 bus_perf_client = msm_bus_scale_register_client(priv->bus_scale);
Patrick Daly985c14b2012-12-03 17:12:37 -0800331 if (!bus_perf_client) {
332 pr_err("Unable to register bus client\n");
333 BUG();
334 }
335
Patrick Daly985c14b2012-12-03 17:12:37 -0800336 /* Improve boot time by ramping up CPU immediately */
Patrick Daly9196ed42013-03-13 15:59:03 -0700337 for (i = 0; priv->freq_tbl[i].khz != 0; i++)
338 if (priv->freq_tbl[i].use_for_scaling)
339 max_cpu_khz = priv->freq_tbl[i].khz;
Patrick Daly985c14b2012-12-03 17:12:37 -0800340
341 /* Initialize regulators */
Patrick Daly9196ed42013-03-13 15:59:03 -0700342 rc = increase_vdd(priv->vdd_max_cpu, priv->vdd_max_mem);
Patrick Daly985c14b2012-12-03 17:12:37 -0800343 if (rc)
344 goto err_vdd;
345
Patrick Daly9196ed42013-03-13 15:59:03 -0700346 rc = regulator_enable(priv->vdd_mem);
Patrick Daly985c14b2012-12-03 17:12:37 -0800347 if (rc) {
348 dev_err(&pdev->dev, "regulator_enable for mem failed\n");
349 goto err_vdd;
350 }
351
Patrick Daly9196ed42013-03-13 15:59:03 -0700352 rc = regulator_enable(priv->vdd_cpu);
Patrick Daly985c14b2012-12-03 17:12:37 -0800353 if (rc) {
354 dev_err(&pdev->dev, "regulator_enable for cpu failed\n");
355 goto err_vdd_cpu;
356 }
357
Patrick Daly71839d42013-02-25 13:05:05 -0800358 /*
359 * Select a state which is always a valid transition to align SW with
360 * the HW configuration set by the bootloaders.
361 */
362 acpuclk_cortex_set_rate(0, acpuclk_cortex_data.power_collapse_khz,
363 SETRATE_INIT);
Patrick Daly985c14b2012-12-03 17:12:37 -0800364 acpuclk_cortex_set_rate(0, max_cpu_khz, SETRATE_INIT);
365
366 acpuclk_register(&acpuclk_cortex_data);
367 cpufreq_table_init();
368
369 return 0;
370
371err_vdd_cpu:
Patrick Daly9196ed42013-03-13 15:59:03 -0700372 regulator_disable(priv->vdd_mem);
Patrick Daly985c14b2012-12-03 17:12:37 -0800373err_vdd:
Patrick Daly985c14b2012-12-03 17:12:37 -0800374 return rc;
375}