blob: db7bab32562176bf09abc9f2576aed07e5d1018e [file] [log] [blame]
Matt Wagantall44f672e2011-09-07 20:31:16 -07001/*
Vikram Mulukutla01d06b82012-01-10 14:19:44 -08002 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Matt Wagantall44f672e2011-09-07 20:31:16 -07003 *
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>
Matt Wagantallbf430eb2012-03-22 11:45:49 -070017#include <linux/module.h>
Matt Wagantall44f672e2011-09-07 20:31:16 -070018#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>
Matt Wagantallbf430eb2012-03-22 11:45:49 -070026#include <linux/platform_device.h>
Matt Wagantall44f672e2011-09-07 20:31:16 -070027
28#include <asm/cpu.h>
29
30#include <mach/board.h>
31#include <mach/msm_iomap.h>
Matt Wagantall095760f2011-10-18 15:21:36 -070032#include <mach/msm_bus.h>
33#include <mach/msm_bus_board.h>
Matt Wagantallb1be5662011-10-18 13:28:58 -070034#include <mach/rpm-regulator.h>
Matt Wagantall44f672e2011-09-07 20:31:16 -070035
36#include "acpuclock.h"
37
38#define REG_CLKSEL_0 (MSM_APCS_GLB_BASE + 0x08)
39#define REG_CLKDIV_0 (MSM_APCS_GLB_BASE + 0x0C)
40#define REG_CLKSEL_1 (MSM_APCS_GLB_BASE + 0x10)
41#define REG_CLKDIV_1 (MSM_APCS_GLB_BASE + 0x14)
42#define REG_CLKOUTSEL (MSM_APCS_GLB_BASE + 0x18)
43
Matt Wagantallb1be5662011-10-18 13:28:58 -070044#define MAX_VDD_MEM 1150000
45
Matt Wagantall44f672e2011-09-07 20:31:16 -070046enum clk_src {
47 SRC_CXO,
48 SRC_PLL0,
49 SRC_PLL8,
50 SRC_PLL9,
51 NUM_SRC,
52};
53
54struct src_clock {
55 struct clk *clk;
56 const char *name;
57};
58
59static struct src_clock clocks[NUM_SRC] = {
Matt Wagantall44f672e2011-09-07 20:31:16 -070060 [SRC_PLL0].name = "pll0",
61 [SRC_PLL8].name = "pll8",
62 [SRC_PLL9].name = "pll9",
63};
64
65struct clkctl_acpu_speed {
66 bool use_for_scaling;
67 unsigned int khz;
68 int src;
69 unsigned int src_sel;
70 unsigned int src_div;
Matt Wagantallb1be5662011-10-18 13:28:58 -070071 unsigned int vdd_cpu;
72 unsigned int vdd_mem;
Matt Wagantall095760f2011-10-18 15:21:36 -070073 unsigned int bw_level;
Matt Wagantall44f672e2011-09-07 20:31:16 -070074};
75
76struct acpuclk_state {
77 struct mutex lock;
78 struct clkctl_acpu_speed *current_speed;
79};
80
81static struct acpuclk_state drv_state = {
82 .current_speed = &(struct clkctl_acpu_speed){ 0 },
83};
84
Matt Wagantall095760f2011-10-18 15:21:36 -070085/* Instantaneous bandwidth requests in MB/s. */
86#define BW_MBPS(_bw) \
87 { \
88 .vectors = &(struct msm_bus_vectors){ \
89 .src = MSM_BUS_MASTER_AMPSS_M0, \
90 .dst = MSM_BUS_SLAVE_EBI_CH0, \
91 .ib = (_bw) * 1000000UL, \
92 .ab = 0, \
93 }, \
94 .num_paths = 1, \
95 }
96static struct msm_bus_paths bw_level_tbl[] = {
97 [0] = BW_MBPS(152), /* At least 19 MHz on bus. */
98 [1] = BW_MBPS(368), /* At least 46 MHz on bus. */
99 [2] = BW_MBPS(552), /* At least 69 MHz on bus. */
100 [3] = BW_MBPS(736), /* At least 92 MHz on bus. */
101 [4] = BW_MBPS(1064), /* At least 133 MHz on bus. */
Vikram Mulukutla01d06b82012-01-10 14:19:44 -0800102 [5] = BW_MBPS(1536), /* At least 192 MHz on bus. */
Matt Wagantall095760f2011-10-18 15:21:36 -0700103};
104
105static struct msm_bus_scale_pdata bus_client_pdata = {
106 .usecase = bw_level_tbl,
107 .num_usecases = ARRAY_SIZE(bw_level_tbl),
108 .active_only = 1,
109 .name = "acpuclock",
110};
111
112static uint32_t bus_perf_client;
113
Matt Wagantall44f672e2011-09-07 20:31:16 -0700114static struct clkctl_acpu_speed acpu_freq_tbl[] = {
Vikram Mulukutla5ebc9aa2012-06-01 11:35:41 -0700115 { 0, 19200, SRC_CXO, 0, 0, RPM_VREG_CORNER_LOW, 1050000, 0 },
116 { 1, 138000, SRC_PLL0, 6, 1, RPM_VREG_CORNER_LOW, 1050000, 2 },
117 { 1, 276000, SRC_PLL0, 6, 0, RPM_VREG_CORNER_NOMINAL, 1050000, 2 },
118 { 1, 384000, SRC_PLL8, 3, 0, RPM_VREG_CORNER_HIGH, 1150000, 4 },
Vikram Mulukutla01d06b82012-01-10 14:19:44 -0800119 /* The row below may be changed at runtime depending on hw rev. */
Vikram Mulukutla5ebc9aa2012-06-01 11:35:41 -0700120 { 1, 440000, SRC_PLL9, 2, 0, RPM_VREG_CORNER_HIGH, 1150000, 4 },
Matt Wagantall44f672e2011-09-07 20:31:16 -0700121 { 0 }
122};
123
124static void select_clk_source_div(struct clkctl_acpu_speed *s)
125{
126 static void * __iomem const sel_reg[] = {REG_CLKSEL_0, REG_CLKSEL_1};
127 static void * __iomem const div_reg[] = {REG_CLKDIV_0, REG_CLKDIV_1};
128 uint32_t next_bank;
129
130 next_bank = !(readl_relaxed(REG_CLKOUTSEL) & 1);
131 writel_relaxed(s->src_sel, sel_reg[next_bank]);
132 writel_relaxed(s->src_div, div_reg[next_bank]);
133 writel_relaxed(next_bank, REG_CLKOUTSEL);
134
135 /* Wait for switch to complete. */
136 mb();
137 udelay(1);
138}
139
Matt Wagantall095760f2011-10-18 15:21:36 -0700140/* Update the bus bandwidth request. */
141static void set_bus_bw(unsigned int bw)
142{
143 int ret;
144
145 /* Bounds check. */
146 if (bw >= ARRAY_SIZE(bw_level_tbl)) {
147 pr_err("invalid bandwidth request (%d)\n", bw);
148 return;
149 }
150
151 /* Update bandwidth if request has changed. This may sleep. */
152 ret = msm_bus_scale_client_update_request(bus_perf_client, bw);
153 if (ret)
154 pr_err("bandwidth request failed (%d)\n", ret);
155
156 return;
157}
158
Matt Wagantallb1be5662011-10-18 13:28:58 -0700159/* Apply any per-cpu voltage increases. */
160static int increase_vdd(unsigned int vdd_cpu, unsigned int vdd_mem)
161{
162 int rc = 0;
163
164 /*
165 * Increase vdd_mem active-set before vdd_cpu.
166 * vdd_mem should be >= vdd_cpu.
167 */
168 rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_L9, RPM_VREG_VOTER1,
169 vdd_mem, MAX_VDD_MEM, 0);
170 if (rc) {
171 pr_err("vdd_mem increase failed (%d)\n", rc);
172 return rc;
173 }
174
Vikram Mulukutla5ebc9aa2012-06-01 11:35:41 -0700175 rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
176 RPM_VREG_VOTER1, vdd_cpu, RPM_VREG_CORNER_HIGH, 0);
Matt Wagantallb1be5662011-10-18 13:28:58 -0700177 if (rc)
178 pr_err("vdd_cpu increase failed (%d)\n", rc);
179
180 return rc;
181}
182
183/* Apply any per-cpu voltage decreases. */
184static void decrease_vdd(unsigned int vdd_cpu, unsigned int vdd_mem)
185{
186 int ret;
187
188 /* Update CPU voltage. */
Vikram Mulukutla5ebc9aa2012-06-01 11:35:41 -0700189 ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
190 RPM_VREG_VOTER1, vdd_cpu, RPM_VREG_CORNER_HIGH, 0);
191
Matt Wagantallb1be5662011-10-18 13:28:58 -0700192 if (ret) {
193 pr_err("vdd_cpu decrease failed (%d)\n", ret);
194 return;
195 }
196
197 /*
198 * Decrease vdd_mem active-set after vdd_cpu.
199 * vdd_mem should be >= vdd_cpu.
200 */
201 ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_L9, RPM_VREG_VOTER1,
202 vdd_mem, MAX_VDD_MEM, 0);
203 if (ret)
204 pr_err("vdd_mem decrease failed (%d)\n", ret);
205}
206
Matt Wagantall44f672e2011-09-07 20:31:16 -0700207static int acpuclk_9615_set_rate(int cpu, unsigned long rate,
208 enum setrate_reason reason)
209{
210 struct clkctl_acpu_speed *tgt_s, *strt_s;
211 int rc = 0;
212
213 if (reason == SETRATE_CPUFREQ)
214 mutex_lock(&drv_state.lock);
215
216 strt_s = drv_state.current_speed;
217
218 /* Return early if rate didn't change. */
219 if (rate == strt_s->khz)
220 goto out;
221
222 /* Find target frequency. */
223 for (tgt_s = acpu_freq_tbl; tgt_s->khz != 0; tgt_s++)
224 if (tgt_s->khz == rate)
225 break;
226 if (tgt_s->khz == 0) {
227 rc = -EINVAL;
228 goto out;
229 }
230
Matt Wagantallb1be5662011-10-18 13:28:58 -0700231 /* Increase VDD levels if needed. */
232 if ((reason == SETRATE_CPUFREQ || reason == SETRATE_INIT)
233 && (tgt_s->khz > strt_s->khz)) {
234 rc = increase_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
235 if (rc)
236 goto out;
237 }
238
Matt Wagantallf5d64072011-10-13 14:15:19 -0700239 pr_debug("Switching from CPU rate %u KHz -> %u KHz\n",
Matt Wagantall44f672e2011-09-07 20:31:16 -0700240 strt_s->khz, tgt_s->khz);
241
242 /* Switch CPU speed. */
243 clk_enable(clocks[tgt_s->src].clk);
244 select_clk_source_div(tgt_s);
245 clk_disable(clocks[strt_s->src].clk);
246
247 drv_state.current_speed = tgt_s;
Matt Wagantallf5d64072011-10-13 14:15:19 -0700248 pr_debug("CPU speed change complete\n");
Matt Wagantall44f672e2011-09-07 20:31:16 -0700249
Matt Wagantallb1be5662011-10-18 13:28:58 -0700250 /* Nothing else to do for SWFI or power-collapse. */
251 if (reason == SETRATE_SWFI || reason == SETRATE_PC)
252 goto out;
253
Matt Wagantall095760f2011-10-18 15:21:36 -0700254 /* Update bus bandwith request. */
255 set_bus_bw(tgt_s->bw_level);
256
Matt Wagantallb1be5662011-10-18 13:28:58 -0700257 /* Drop VDD levels if we can. */
258 if (tgt_s->khz < strt_s->khz)
259 decrease_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
260
Matt Wagantall44f672e2011-09-07 20:31:16 -0700261out:
262 if (reason == SETRATE_CPUFREQ)
263 mutex_unlock(&drv_state.lock);
264 return rc;
265}
266
267static unsigned long acpuclk_9615_get_rate(int cpu)
268{
269 return drv_state.current_speed->khz;
270}
271
272#ifdef CONFIG_CPU_FREQ_MSM
273static struct cpufreq_frequency_table freq_table[30];
274
275static void __init cpufreq_table_init(void)
276{
277 int i, freq_cnt = 0;
278
279 /* Construct the freq_table tables from acpu_freq_tbl. */
280 for (i = 0; acpu_freq_tbl[i].khz != 0
281 && freq_cnt < ARRAY_SIZE(freq_table); i++) {
282 if (acpu_freq_tbl[i].use_for_scaling) {
283 freq_table[freq_cnt].index = freq_cnt;
284 freq_table[freq_cnt].frequency
285 = acpu_freq_tbl[i].khz;
286 freq_cnt++;
287 }
288 }
289 /* freq_table not big enough to store all usable freqs. */
290 BUG_ON(acpu_freq_tbl[i].khz != 0);
291
292 freq_table[freq_cnt].index = freq_cnt;
293 freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END;
294
295 pr_info("CPU: %d scaling frequencies supported.\n", freq_cnt);
296
297 /* Register table with CPUFreq. */
298 cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
299}
300#else
301static void __init cpufreq_table_init(void) {}
302#endif
303
304static struct acpuclk_data acpuclk_9615_data = {
305 .set_rate = acpuclk_9615_set_rate,
306 .get_rate = acpuclk_9615_get_rate,
307 .power_collapse_khz = 19200,
308 .wait_for_irq_khz = 19200,
309};
310
Matt Wagantallbf430eb2012-03-22 11:45:49 -0700311static int __init acpuclk_9615_probe(struct platform_device *pdev)
Matt Wagantall44f672e2011-09-07 20:31:16 -0700312{
313 unsigned long max_cpu_khz = 0;
314 int i;
315
316 mutex_init(&drv_state.lock);
Matt Wagantall095760f2011-10-18 15:21:36 -0700317
318 bus_perf_client = msm_bus_scale_register_client(&bus_client_pdata);
319 if (!bus_perf_client) {
320 pr_err("Unable to register bus client\n");
321 BUG();
322 }
323
Matt Wagantall44f672e2011-09-07 20:31:16 -0700324 for (i = 0; i < NUM_SRC; i++) {
325 if (clocks[i].name) {
Vikram Mulukutla17cdf1c2011-11-16 18:22:14 -0800326 clocks[i].clk = clk_get_sys("acpu", clocks[i].name);
Matt Wagantall44f672e2011-09-07 20:31:16 -0700327 BUG_ON(IS_ERR(clocks[i].clk));
Stephen Boyd2636ef72012-01-30 23:10:09 -0800328 /*
329 * Prepare the PLLs because we enable/disable them
330 * in atomic context during power collapse/restore.
331 */
332 BUG_ON(clk_prepare(clocks[i].clk));
Matt Wagantall44f672e2011-09-07 20:31:16 -0700333 }
334 }
335
Vikram Mulukutla01d06b82012-01-10 14:19:44 -0800336 /* Determine the rate of PLL9 and fixup tables accordingly */
337 if (clk_get_rate(clocks[SRC_PLL9].clk) == 550000000) {
338 for (i = 0; i < ARRAY_SIZE(acpu_freq_tbl); i++)
339 if (acpu_freq_tbl[i].src == SRC_PLL9) {
340 acpu_freq_tbl[i].khz = 550000;
341 acpu_freq_tbl[i].bw_level = 5;
342 }
343 }
344
Matt Wagantall44f672e2011-09-07 20:31:16 -0700345 /* Improve boot time by ramping up CPU immediately. */
346 for (i = 0; acpu_freq_tbl[i].khz != 0; i++)
347 max_cpu_khz = acpu_freq_tbl[i].khz;
348 acpuclk_9615_set_rate(smp_processor_id(), max_cpu_khz, SETRATE_INIT);
349
350 acpuclk_register(&acpuclk_9615_data);
351 cpufreq_table_init();
352
353 return 0;
354}
355
Matt Wagantallbf430eb2012-03-22 11:45:49 -0700356static struct platform_driver acpuclk_9615_driver = {
357 .driver = {
358 .name = "acpuclk-9615",
359 .owner = THIS_MODULE,
360 },
Matt Wagantall44f672e2011-09-07 20:31:16 -0700361};
Matt Wagantallbf430eb2012-03-22 11:45:49 -0700362
363static int __init acpuclk_9615_init(void)
364{
365 return platform_driver_probe(&acpuclk_9615_driver, acpuclk_9615_probe);
366}
367device_initcall(acpuclk_9615_init);