| Daniel Walker | 43b39f9 | 2010-03-03 08:54:11 -0800 | [diff] [blame] | 1 | /* arch/arm/mach-msm/acpuclock.c | 
 | 2 |  * | 
 | 3 |  * MSM architecture clock driver | 
 | 4 |  * | 
 | 5 |  * Copyright (C) 2007 Google, Inc. | 
 | 6 |  * Copyright (c) 2007 QUALCOMM Incorporated | 
 | 7 |  * Author: San Mehat <san@android.com> | 
 | 8 |  * | 
 | 9 |  * This software is licensed under the terms of the GNU General Public | 
 | 10 |  * License version 2, as published by the Free Software Foundation, and | 
 | 11 |  * may be copied, distributed, and modified under those terms. | 
 | 12 |  * | 
 | 13 |  * This program is distributed in the hope that it will be useful, | 
 | 14 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 15 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the | 
 | 16 |  * GNU General Public License for more details. | 
 | 17 |  * | 
 | 18 |  */ | 
 | 19 |  | 
| Daniel Walker | 43b39f9 | 2010-03-03 08:54:11 -0800 | [diff] [blame] | 20 | #include <linux/kernel.h> | 
 | 21 | #include <linux/init.h> | 
 | 22 | #include <linux/list.h> | 
 | 23 | #include <linux/errno.h> | 
 | 24 | #include <linux/string.h> | 
 | 25 | #include <linux/delay.h> | 
 | 26 | #include <linux/clk.h> | 
 | 27 | #include <linux/cpufreq.h> | 
 | 28 | #include <linux/mutex.h> | 
 | 29 | #include <linux/io.h> | 
 | 30 | #include <mach/board.h> | 
 | 31 | #include <mach/msm_iomap.h> | 
 | 32 |  | 
 | 33 | #include "proc_comm.h" | 
 | 34 | #include "acpuclock.h" | 
 | 35 |  | 
 | 36 |  | 
 | 37 | #define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100) | 
 | 38 | #define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) | 
 | 39 | #define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124) | 
 | 40 |  | 
 | 41 | /* | 
 | 42 |  * ARM11 clock configuration for specific ACPU speeds | 
 | 43 |  */ | 
 | 44 |  | 
 | 45 | #define ACPU_PLL_TCXO	-1 | 
 | 46 | #define ACPU_PLL_0	0 | 
 | 47 | #define ACPU_PLL_1	1 | 
 | 48 | #define ACPU_PLL_2	2 | 
 | 49 | #define ACPU_PLL_3	3 | 
 | 50 |  | 
 | 51 | #define PERF_SWITCH_DEBUG 0 | 
 | 52 | #define PERF_SWITCH_STEP_DEBUG 0 | 
 | 53 |  | 
 | 54 | struct clock_state | 
 | 55 | { | 
 | 56 | 	struct clkctl_acpu_speed	*current_speed; | 
 | 57 | 	struct mutex			lock; | 
 | 58 | 	uint32_t			acpu_switch_time_us; | 
 | 59 | 	uint32_t			max_speed_delta_khz; | 
 | 60 | 	uint32_t			vdd_switch_time_us; | 
 | 61 | 	unsigned long			power_collapse_khz; | 
 | 62 | 	unsigned long			wait_for_irq_khz; | 
 | 63 | }; | 
 | 64 |  | 
 | 65 | static struct clk *ebi1_clk; | 
 | 66 | static struct clock_state drv_state = { 0 }; | 
 | 67 |  | 
 | 68 | static void __init acpuclk_init(void); | 
 | 69 |  | 
 | 70 | /* MSM7201A Levels 3-6 all correspond to 1.2V, level 7 corresponds to 1.325V. */ | 
 | 71 | enum { | 
 | 72 | 	VDD_0 = 0, | 
 | 73 | 	VDD_1 = 1, | 
 | 74 | 	VDD_2 = 2, | 
 | 75 | 	VDD_3 = 3, | 
 | 76 | 	VDD_4 = 3, | 
 | 77 | 	VDD_5 = 3, | 
 | 78 | 	VDD_6 = 3, | 
 | 79 | 	VDD_7 = 7, | 
 | 80 | 	VDD_END | 
 | 81 | }; | 
 | 82 |  | 
 | 83 | struct clkctl_acpu_speed { | 
 | 84 | 	unsigned int	a11clk_khz; | 
 | 85 | 	int		pll; | 
 | 86 | 	unsigned int	a11clk_src_sel; | 
 | 87 | 	unsigned int	a11clk_src_div; | 
 | 88 | 	unsigned int	ahbclk_khz; | 
 | 89 | 	unsigned int	ahbclk_div; | 
 | 90 | 	int		vdd; | 
 | 91 | 	unsigned int 	axiclk_khz; | 
 | 92 | 	unsigned long	lpj; /* loops_per_jiffy */ | 
 | 93 | /* Index in acpu_freq_tbl[] for steppings. */ | 
 | 94 | 	short		down; | 
 | 95 | 	short		up; | 
 | 96 | }; | 
 | 97 |  | 
 | 98 | /* | 
 | 99 |  * ACPU speed table. Complete table is shown but certain speeds are commented | 
| Uwe Kleine-König | 421f91d | 2010-06-11 12:17:00 +0200 | [diff] [blame] | 100 |  * out to optimized speed switching. Initialize loops_per_jiffy to 0. | 
| Daniel Walker | 43b39f9 | 2010-03-03 08:54:11 -0800 | [diff] [blame] | 101 |  * | 
 | 102 |  * Table stepping up/down is optimized for 256mhz jumps while staying on the | 
 | 103 |  * same PLL. | 
 | 104 |  */ | 
 | 105 | #if (0) | 
 | 106 | static struct clkctl_acpu_speed  acpu_freq_tbl[] = { | 
 | 107 | 	{ 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 8 }, | 
 | 108 | 	{ 61440, ACPU_PLL_0,  4, 3, 61440,  0, VDD_0, 30720,  0, 0, 8 }, | 
 | 109 | 	{ 81920, ACPU_PLL_0,  4, 2, 40960,  1, VDD_0, 61440,  0, 0, 8 }, | 
 | 110 | 	{ 96000, ACPU_PLL_1,  1, 7, 48000,  1, VDD_0, 61440,  0, 0, 9 }, | 
 | 111 | 	{ 122880, ACPU_PLL_0, 4, 1, 61440,  1, VDD_3, 61440,  0, 0, 8 }, | 
 | 112 | 	{ 128000, ACPU_PLL_1, 1, 5, 64000,  1, VDD_3, 61440,  0, 0, 12 }, | 
 | 113 | 	{ 176000, ACPU_PLL_2, 2, 5, 88000,  1, VDD_3, 61440,  0, 0, 11 }, | 
 | 114 | 	{ 192000, ACPU_PLL_1, 1, 3, 64000,  2, VDD_3, 61440,  0, 0, 12 }, | 
 | 115 | 	{ 245760, ACPU_PLL_0, 4, 0, 81920,  2, VDD_4, 61440,  0, 0, 12 }, | 
 | 116 | 	{ 256000, ACPU_PLL_1, 1, 2, 128000, 2, VDD_5, 128000, 0, 0, 12 }, | 
 | 117 | 	{ 264000, ACPU_PLL_2, 2, 3, 88000,  2, VDD_5, 128000, 0, 6, 13 }, | 
 | 118 | 	{ 352000, ACPU_PLL_2, 2, 2, 88000,  3, VDD_5, 128000, 0, 6, 13 }, | 
 | 119 | 	{ 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 5, -1 }, | 
 | 120 | 	{ 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 11, -1 }, | 
 | 121 | 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, | 
 | 122 | }; | 
 | 123 | #else /* Table of freq we currently use. */ | 
 | 124 | static struct clkctl_acpu_speed  acpu_freq_tbl[] = { | 
 | 125 | 	{ 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 4 }, | 
 | 126 | 	{ 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 4 }, | 
 | 127 | 	{ 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 6 }, | 
 | 128 | 	{ 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 5 }, | 
 | 129 | 	{ 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 5 }, | 
 | 130 | 	{ 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 3, 7 }, | 
 | 131 | 	{ 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 2, -1 }, | 
 | 132 | 	{ 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 5, -1 }, | 
 | 133 | 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, | 
 | 134 | }; | 
 | 135 | #endif | 
 | 136 |  | 
| Daniel Walker | 4eab625 | 2010-03-04 14:06:56 -0800 | [diff] [blame] | 137 |  | 
 | 138 | #ifdef CONFIG_CPU_FREQ_TABLE | 
| Daniel Walker | 43b39f9 | 2010-03-03 08:54:11 -0800 | [diff] [blame] | 139 | static struct cpufreq_frequency_table freq_table[] = { | 
 | 140 | 	{ 0, 122880 }, | 
 | 141 | 	{ 1, 128000 }, | 
 | 142 | 	{ 2, 245760 }, | 
 | 143 | 	{ 3, 384000 }, | 
 | 144 | 	{ 4, 528000 }, | 
 | 145 | 	{ 5, CPUFREQ_TABLE_END }, | 
 | 146 | }; | 
| Daniel Walker | 4eab625 | 2010-03-04 14:06:56 -0800 | [diff] [blame] | 147 | #endif | 
| Daniel Walker | 43b39f9 | 2010-03-03 08:54:11 -0800 | [diff] [blame] | 148 |  | 
 | 149 | static int pc_pll_request(unsigned id, unsigned on) | 
 | 150 | { | 
 | 151 | 	int res; | 
 | 152 | 	on = !!on; | 
 | 153 |  | 
 | 154 | #if PERF_SWITCH_DEBUG | 
 | 155 | 	if (on) | 
 | 156 | 		printk(KERN_DEBUG "Enabling PLL %d\n", id); | 
 | 157 | 	else | 
 | 158 | 		printk(KERN_DEBUG "Disabling PLL %d\n", id); | 
 | 159 | #endif | 
 | 160 |  | 
 | 161 | 	res = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); | 
 | 162 | 	if (res < 0) | 
 | 163 | 		return res; | 
 | 164 |  | 
 | 165 | #if PERF_SWITCH_DEBUG | 
 | 166 | 	if (on) | 
 | 167 | 		printk(KERN_DEBUG "PLL %d enabled\n", id); | 
 | 168 | 	else | 
 | 169 | 		printk(KERN_DEBUG "PLL %d disabled\n", id); | 
 | 170 | #endif | 
 | 171 | 	return res; | 
 | 172 | } | 
 | 173 |  | 
 | 174 |  | 
 | 175 | /*---------------------------------------------------------------------------- | 
 | 176 |  * ARM11 'owned' clock control | 
 | 177 |  *---------------------------------------------------------------------------*/ | 
 | 178 |  | 
 | 179 | unsigned long acpuclk_power_collapse(void) { | 
 | 180 | 	int ret = acpuclk_get_rate(); | 
 | 181 | 	ret *= 1000; | 
 | 182 | 	if (ret > drv_state.power_collapse_khz) | 
 | 183 | 		acpuclk_set_rate(drv_state.power_collapse_khz, 1); | 
 | 184 | 	return ret; | 
 | 185 | } | 
 | 186 |  | 
 | 187 | unsigned long acpuclk_get_wfi_rate(void) | 
 | 188 | { | 
 | 189 | 	return drv_state.wait_for_irq_khz; | 
 | 190 | } | 
 | 191 |  | 
 | 192 | unsigned long acpuclk_wait_for_irq(void) { | 
 | 193 | 	int ret = acpuclk_get_rate(); | 
 | 194 | 	ret *= 1000; | 
 | 195 | 	if (ret > drv_state.wait_for_irq_khz) | 
 | 196 | 		acpuclk_set_rate(drv_state.wait_for_irq_khz, 1); | 
 | 197 | 	return ret; | 
 | 198 | } | 
 | 199 |  | 
 | 200 | static int acpuclk_set_vdd_level(int vdd) | 
 | 201 | { | 
 | 202 | 	uint32_t current_vdd; | 
 | 203 |  | 
 | 204 | 	current_vdd = readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07; | 
 | 205 |  | 
 | 206 | #if PERF_SWITCH_DEBUG | 
 | 207 | 	printk(KERN_DEBUG "acpuclock: Switching VDD from %u -> %d\n", | 
 | 208 | 	       current_vdd, vdd); | 
 | 209 | #endif | 
 | 210 | 	writel((1 << 7) | (vdd << 3), A11S_VDD_SVS_PLEVEL_ADDR); | 
 | 211 | 	udelay(drv_state.vdd_switch_time_us); | 
 | 212 | 	if ((readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x7) != vdd) { | 
 | 213 | #if PERF_SWITCH_DEBUG | 
 | 214 | 		printk(KERN_ERR "acpuclock: VDD set failed\n"); | 
 | 215 | #endif | 
 | 216 | 		return -EIO; | 
 | 217 | 	} | 
 | 218 |  | 
 | 219 | #if PERF_SWITCH_DEBUG | 
 | 220 | 	printk(KERN_DEBUG "acpuclock: VDD switched\n"); | 
 | 221 | #endif | 
 | 222 | 	return 0; | 
 | 223 | } | 
 | 224 |  | 
 | 225 | /* Set proper dividers for the given clock speed. */ | 
 | 226 | static void acpuclk_set_div(const struct clkctl_acpu_speed *hunt_s) { | 
 | 227 | 	uint32_t reg_clkctl, reg_clksel, clk_div; | 
 | 228 |  | 
 | 229 | 	/* AHB_CLK_DIV */ | 
 | 230 | 	clk_div = (readl(A11S_CLK_SEL_ADDR) >> 1) & 0x03; | 
 | 231 | 	/* | 
 | 232 | 	 * If the new clock divider is higher than the previous, then | 
 | 233 | 	 * program the divider before switching the clock | 
 | 234 | 	 */ | 
 | 235 | 	if (hunt_s->ahbclk_div > clk_div) { | 
 | 236 | 		reg_clksel = readl(A11S_CLK_SEL_ADDR); | 
 | 237 | 		reg_clksel &= ~(0x3 << 1); | 
 | 238 | 		reg_clksel |= (hunt_s->ahbclk_div << 1); | 
 | 239 | 		writel(reg_clksel, A11S_CLK_SEL_ADDR); | 
 | 240 | 	} | 
 | 241 | 	if ((readl(A11S_CLK_SEL_ADDR) & 0x01) == 0) { | 
 | 242 | 		/* SRC0 */ | 
 | 243 |  | 
 | 244 | 		/* Program clock source */ | 
 | 245 | 		reg_clkctl = readl(A11S_CLK_CNTL_ADDR); | 
 | 246 | 		reg_clkctl &= ~(0x07 << 4); | 
 | 247 | 		reg_clkctl |= (hunt_s->a11clk_src_sel << 4); | 
 | 248 | 		writel(reg_clkctl, A11S_CLK_CNTL_ADDR); | 
 | 249 |  | 
 | 250 | 		/* Program clock divider */ | 
 | 251 | 		reg_clkctl = readl(A11S_CLK_CNTL_ADDR); | 
 | 252 | 		reg_clkctl &= ~0xf; | 
 | 253 | 		reg_clkctl |= hunt_s->a11clk_src_div; | 
 | 254 | 		writel(reg_clkctl, A11S_CLK_CNTL_ADDR); | 
 | 255 |  | 
 | 256 | 		/* Program clock source selection */ | 
 | 257 | 		reg_clksel = readl(A11S_CLK_SEL_ADDR); | 
 | 258 | 		reg_clksel |= 1; /* CLK_SEL_SRC1NO  == SRC1 */ | 
 | 259 | 		writel(reg_clksel, A11S_CLK_SEL_ADDR); | 
 | 260 | 	} else { | 
 | 261 | 		/* SRC1 */ | 
 | 262 |  | 
 | 263 | 		/* Program clock source */ | 
 | 264 | 		reg_clkctl = readl(A11S_CLK_CNTL_ADDR); | 
 | 265 | 		reg_clkctl &= ~(0x07 << 12); | 
 | 266 | 		reg_clkctl |= (hunt_s->a11clk_src_sel << 12); | 
 | 267 | 		writel(reg_clkctl, A11S_CLK_CNTL_ADDR); | 
 | 268 |  | 
 | 269 | 		/* Program clock divider */ | 
 | 270 | 		reg_clkctl = readl(A11S_CLK_CNTL_ADDR); | 
 | 271 | 		reg_clkctl &= ~(0xf << 8); | 
 | 272 | 		reg_clkctl |= (hunt_s->a11clk_src_div << 8); | 
 | 273 | 		writel(reg_clkctl, A11S_CLK_CNTL_ADDR); | 
 | 274 |  | 
 | 275 | 		/* Program clock source selection */ | 
 | 276 | 		reg_clksel = readl(A11S_CLK_SEL_ADDR); | 
 | 277 | 		reg_clksel &= ~1; /* CLK_SEL_SRC1NO  == SRC0 */ | 
 | 278 | 		writel(reg_clksel, A11S_CLK_SEL_ADDR); | 
 | 279 | 	} | 
 | 280 |  | 
 | 281 | 	/* | 
 | 282 | 	 * If the new clock divider is lower than the previous, then | 
 | 283 | 	 * program the divider after switching the clock | 
 | 284 | 	 */ | 
 | 285 | 	if (hunt_s->ahbclk_div < clk_div) { | 
 | 286 | 		reg_clksel = readl(A11S_CLK_SEL_ADDR); | 
 | 287 | 		reg_clksel &= ~(0x3 << 1); | 
 | 288 | 		reg_clksel |= (hunt_s->ahbclk_div << 1); | 
 | 289 | 		writel(reg_clksel, A11S_CLK_SEL_ADDR); | 
 | 290 | 	} | 
 | 291 | } | 
 | 292 |  | 
 | 293 | int acpuclk_set_rate(unsigned long rate, int for_power_collapse) | 
 | 294 | { | 
 | 295 | 	uint32_t reg_clkctl; | 
 | 296 | 	struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s; | 
 | 297 | 	int rc = 0; | 
 | 298 | 	unsigned int plls_enabled = 0, pll; | 
 | 299 |  | 
 | 300 | 	strt_s = cur_s = drv_state.current_speed; | 
 | 301 |  | 
 | 302 | 	WARN_ONCE(cur_s == NULL, "acpuclk_set_rate: not initialized\n"); | 
 | 303 | 	if (cur_s == NULL) | 
 | 304 | 		return -ENOENT; | 
 | 305 |  | 
 | 306 | 	if (rate == (cur_s->a11clk_khz * 1000)) | 
 | 307 | 		return 0; | 
 | 308 |  | 
 | 309 | 	for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) { | 
 | 310 | 		if (tgt_s->a11clk_khz == (rate / 1000)) | 
 | 311 | 			break; | 
 | 312 | 	} | 
 | 313 |  | 
 | 314 | 	if (tgt_s->a11clk_khz == 0) | 
 | 315 | 		return -EINVAL; | 
 | 316 |  | 
 | 317 | 	/* Choose the highest speed speed at or below 'rate' with same PLL. */ | 
 | 318 | 	if (for_power_collapse && tgt_s->a11clk_khz < cur_s->a11clk_khz) { | 
 | 319 | 		while (tgt_s->pll != ACPU_PLL_TCXO && tgt_s->pll != cur_s->pll) | 
 | 320 | 			tgt_s--; | 
 | 321 | 	} | 
 | 322 |  | 
 | 323 | 	if (strt_s->pll != ACPU_PLL_TCXO) | 
 | 324 | 		plls_enabled |= 1 << strt_s->pll; | 
 | 325 |  | 
 | 326 | 	if (!for_power_collapse) { | 
 | 327 | 		mutex_lock(&drv_state.lock); | 
 | 328 | 		if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { | 
 | 329 | 			rc = pc_pll_request(tgt_s->pll, 1); | 
 | 330 | 			if (rc < 0) { | 
 | 331 | 				pr_err("PLL%d enable failed (%d)\n", | 
 | 332 | 					tgt_s->pll, rc); | 
 | 333 | 				goto out; | 
 | 334 | 			} | 
 | 335 | 			plls_enabled |= 1 << tgt_s->pll; | 
 | 336 | 		} | 
 | 337 | 		/* Increase VDD if needed. */ | 
 | 338 | 		if (tgt_s->vdd > cur_s->vdd) { | 
 | 339 | 			if ((rc = acpuclk_set_vdd_level(tgt_s->vdd)) < 0) { | 
 | 340 | 				printk(KERN_ERR "Unable to switch ACPU vdd\n"); | 
 | 341 | 				goto out; | 
 | 342 | 			} | 
 | 343 | 		} | 
 | 344 | 	} | 
 | 345 |  | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 346 | 	/* Set wait states for CPU between frequency changes */ | 
| Daniel Walker | 43b39f9 | 2010-03-03 08:54:11 -0800 | [diff] [blame] | 347 | 	reg_clkctl = readl(A11S_CLK_CNTL_ADDR); | 
 | 348 | 	reg_clkctl |= (100 << 16); /* set WT_ST_CNT */ | 
 | 349 | 	writel(reg_clkctl, A11S_CLK_CNTL_ADDR); | 
 | 350 |  | 
 | 351 | #if PERF_SWITCH_DEBUG | 
 | 352 | 	printk(KERN_INFO "acpuclock: Switching from ACPU rate %u -> %u\n", | 
 | 353 | 	       strt_s->a11clk_khz * 1000, tgt_s->a11clk_khz * 1000); | 
 | 354 | #endif | 
 | 355 |  | 
 | 356 | 	while (cur_s != tgt_s) { | 
 | 357 | 		/* | 
 | 358 | 		 * Always jump to target freq if within 256mhz, regulardless of | 
 | 359 | 		 * PLL. If differnece is greater, use the predefinied | 
 | 360 | 		 * steppings in the table. | 
 | 361 | 		 */ | 
 | 362 | 		int d = abs((int)(cur_s->a11clk_khz - tgt_s->a11clk_khz)); | 
 | 363 | 		if (d > drv_state.max_speed_delta_khz) { | 
 | 364 | 			/* Step up or down depending on target vs current. */ | 
 | 365 | 			int clk_index = tgt_s->a11clk_khz > cur_s->a11clk_khz ? | 
 | 366 | 				cur_s->up : cur_s->down; | 
 | 367 | 			if (clk_index < 0) { /* This should not happen. */ | 
 | 368 | 				printk(KERN_ERR "cur:%u target: %u\n", | 
 | 369 | 					cur_s->a11clk_khz, tgt_s->a11clk_khz); | 
 | 370 | 				rc = -EINVAL; | 
 | 371 | 				goto out; | 
 | 372 | 			} | 
 | 373 | 			cur_s = &acpu_freq_tbl[clk_index]; | 
 | 374 | 		} else { | 
 | 375 | 			cur_s = tgt_s; | 
 | 376 | 		} | 
 | 377 | #if PERF_SWITCH_STEP_DEBUG | 
 | 378 | 		printk(KERN_DEBUG "%s: STEP khz = %u, pll = %d\n", | 
 | 379 | 			__FUNCTION__, cur_s->a11clk_khz, cur_s->pll); | 
 | 380 | #endif | 
 | 381 | 		if (!for_power_collapse&& cur_s->pll != ACPU_PLL_TCXO | 
 | 382 | 		    && !(plls_enabled & (1 << cur_s->pll))) { | 
 | 383 | 			rc = pc_pll_request(cur_s->pll, 1); | 
 | 384 | 			if (rc < 0) { | 
 | 385 | 				pr_err("PLL%d enable failed (%d)\n", | 
 | 386 | 					cur_s->pll, rc); | 
 | 387 | 				goto out; | 
 | 388 | 			} | 
 | 389 | 			plls_enabled |= 1 << cur_s->pll; | 
 | 390 | 		} | 
 | 391 |  | 
 | 392 | 		acpuclk_set_div(cur_s); | 
 | 393 | 		drv_state.current_speed = cur_s; | 
 | 394 | 		/* Re-adjust lpj for the new clock speed. */ | 
 | 395 | 		loops_per_jiffy = cur_s->lpj; | 
 | 396 | 		udelay(drv_state.acpu_switch_time_us); | 
 | 397 | 	} | 
 | 398 |  | 
 | 399 | 	/* Nothing else to do for power collapse. */ | 
 | 400 | 	if (for_power_collapse) | 
 | 401 | 		return 0; | 
 | 402 |  | 
 | 403 | 	/* Disable PLLs we are not using anymore. */ | 
 | 404 | 	plls_enabled &= ~(1 << tgt_s->pll); | 
 | 405 | 	for (pll = ACPU_PLL_0; pll <= ACPU_PLL_2; pll++) | 
 | 406 | 		if (plls_enabled & (1 << pll)) { | 
 | 407 | 			rc = pc_pll_request(pll, 0); | 
 | 408 | 			if (rc < 0) { | 
 | 409 | 				pr_err("PLL%d disable failed (%d)\n", pll, rc); | 
 | 410 | 				goto out; | 
 | 411 | 			} | 
 | 412 | 		} | 
 | 413 |  | 
 | 414 | 	/* Change the AXI bus frequency if we can. */ | 
 | 415 | 	if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { | 
 | 416 | 		rc = clk_set_rate(ebi1_clk, tgt_s->axiclk_khz * 1000); | 
 | 417 | 		if (rc < 0) | 
 | 418 | 			pr_err("Setting AXI min rate failed!\n"); | 
 | 419 | 	} | 
 | 420 |  | 
 | 421 | 	/* Drop VDD level if we can. */ | 
 | 422 | 	if (tgt_s->vdd < strt_s->vdd) { | 
 | 423 | 		if (acpuclk_set_vdd_level(tgt_s->vdd) < 0) | 
 | 424 | 			printk(KERN_ERR "acpuclock: Unable to drop ACPU vdd\n"); | 
 | 425 | 	} | 
 | 426 |  | 
 | 427 | #if PERF_SWITCH_DEBUG | 
 | 428 | 	printk(KERN_DEBUG "%s: ACPU speed change complete\n", __FUNCTION__); | 
 | 429 | #endif | 
 | 430 | out: | 
 | 431 | 	if (!for_power_collapse) | 
 | 432 | 		mutex_unlock(&drv_state.lock); | 
 | 433 | 	return rc; | 
 | 434 | } | 
 | 435 |  | 
 | 436 | static void __init acpuclk_init(void) | 
 | 437 | { | 
 | 438 | 	struct clkctl_acpu_speed *speed; | 
 | 439 | 	uint32_t div, sel; | 
 | 440 | 	int rc; | 
 | 441 |  | 
 | 442 | 	/* | 
 | 443 | 	 * Determine the rate of ACPU clock | 
 | 444 | 	 */ | 
 | 445 |  | 
 | 446 | 	if (!(readl(A11S_CLK_SEL_ADDR) & 0x01)) { /* CLK_SEL_SRC1N0 */ | 
 | 447 | 		/* CLK_SRC0_SEL */ | 
 | 448 | 		sel = (readl(A11S_CLK_CNTL_ADDR) >> 12) & 0x7; | 
 | 449 | 		/* CLK_SRC0_DIV */ | 
 | 450 | 		div = (readl(A11S_CLK_CNTL_ADDR) >> 8) & 0x0f; | 
 | 451 | 	} else { | 
 | 452 | 		/* CLK_SRC1_SEL */ | 
 | 453 | 		sel = (readl(A11S_CLK_CNTL_ADDR) >> 4) & 0x07; | 
 | 454 | 		/* CLK_SRC1_DIV */ | 
 | 455 | 		div = readl(A11S_CLK_CNTL_ADDR) & 0x0f; | 
 | 456 | 	} | 
 | 457 |  | 
 | 458 | 	for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) { | 
 | 459 | 		if (speed->a11clk_src_sel == sel | 
 | 460 | 		 && (speed->a11clk_src_div == div)) | 
 | 461 | 			break; | 
 | 462 | 	} | 
 | 463 | 	if (speed->a11clk_khz == 0) { | 
 | 464 | 		printk(KERN_WARNING "Warning - ACPU clock reports invalid speed\n"); | 
 | 465 | 		return; | 
 | 466 | 	} | 
 | 467 |  | 
 | 468 | 	drv_state.current_speed = speed; | 
 | 469 |  | 
 | 470 | 	rc = clk_set_rate(ebi1_clk, speed->axiclk_khz * 1000); | 
 | 471 | 	if (rc < 0) | 
 | 472 | 		pr_err("Setting AXI min rate failed!\n"); | 
 | 473 |  | 
 | 474 | 	printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz); | 
 | 475 | } | 
 | 476 |  | 
 | 477 | unsigned long acpuclk_get_rate(void) | 
 | 478 | { | 
 | 479 | 	WARN_ONCE(drv_state.current_speed == NULL, | 
 | 480 | 		  "acpuclk_get_rate: not initialized\n"); | 
 | 481 | 	if (drv_state.current_speed) | 
 | 482 | 		return drv_state.current_speed->a11clk_khz; | 
 | 483 | 	else | 
 | 484 | 		return 0; | 
 | 485 | } | 
 | 486 |  | 
 | 487 | uint32_t acpuclk_get_switch_time(void) | 
 | 488 | { | 
 | 489 | 	return drv_state.acpu_switch_time_us; | 
 | 490 | } | 
 | 491 |  | 
 | 492 | /*---------------------------------------------------------------------------- | 
 | 493 |  * Clock driver initialization | 
 | 494 |  *---------------------------------------------------------------------------*/ | 
 | 495 |  | 
| Uwe Kleine-König | 421f91d | 2010-06-11 12:17:00 +0200 | [diff] [blame] | 496 | /* Initialize the lpj field in the acpu_freq_tbl. */ | 
| Daniel Walker | 43b39f9 | 2010-03-03 08:54:11 -0800 | [diff] [blame] | 497 | static void __init lpj_init(void) | 
 | 498 | { | 
 | 499 | 	int i; | 
 | 500 | 	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed; | 
 | 501 | 	for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) { | 
 | 502 | 		acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy, | 
 | 503 | 						base_clk->a11clk_khz, | 
 | 504 | 						acpu_freq_tbl[i].a11clk_khz); | 
 | 505 | 	} | 
 | 506 | } | 
 | 507 |  | 
 | 508 | void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) | 
 | 509 | { | 
 | 510 | 	pr_info("acpu_clock_init()\n"); | 
 | 511 |  | 
 | 512 | 	ebi1_clk = clk_get(NULL, "ebi1_clk"); | 
 | 513 |  | 
 | 514 | 	mutex_init(&drv_state.lock); | 
 | 515 | 	drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us; | 
 | 516 | 	drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz; | 
 | 517 | 	drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us; | 
 | 518 | 	drv_state.power_collapse_khz = clkdata->power_collapse_khz; | 
 | 519 | 	drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz; | 
 | 520 | 	acpuclk_init(); | 
 | 521 | 	lpj_init(); | 
 | 522 | #ifdef CONFIG_CPU_FREQ_TABLE | 
 | 523 | 	cpufreq_frequency_table_get_attr(freq_table, smp_processor_id()); | 
 | 524 | #endif | 
 | 525 | } |