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 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 54struct 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 65static struct clk *ebi1_clk; 66static struct clock_state drv_state = { 0 }; 67 68static void __init acpuclk_init(void); 69 70/* MSM7201A Levels 3-6 all correspond to 1.2V, level 7 corresponds to 1.325V. */ 71enum { 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 83struct 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 100 * out to optimized speed switching. Initialize loops_per_jiffy to 0. 101 * 102 * Table stepping up/down is optimized for 256mhz jumps while staying on the 103 * same PLL. 104 */ 105static struct clkctl_acpu_speed acpu_freq_tbl[] = { 106 { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 4 }, 107 { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 4 }, 108 { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 6 }, 109 { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 5 }, 110 { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 5 }, 111 { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 3, 7 }, 112 { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 2, -1 }, 113 { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 5, -1 }, 114 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 115}; 116 117 118#ifdef CONFIG_CPU_FREQ_TABLE 119static struct cpufreq_frequency_table freq_table[] = { 120 { 0, 122880 }, 121 { 1, 128000 }, 122 { 2, 245760 }, 123 { 3, 384000 }, 124 { 4, 528000 }, 125 { 5, CPUFREQ_TABLE_END }, 126}; 127#endif 128 129static int pc_pll_request(unsigned id, unsigned on) 130{ 131 int res; 132 on = !!on; 133 134#if PERF_SWITCH_DEBUG 135 if (on) 136 printk(KERN_DEBUG "Enabling PLL %d\n", id); 137 else 138 printk(KERN_DEBUG "Disabling PLL %d\n", id); 139#endif 140 141 res = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); 142 if (res < 0) 143 return res; 144 145#if PERF_SWITCH_DEBUG 146 if (on) 147 printk(KERN_DEBUG "PLL %d enabled\n", id); 148 else 149 printk(KERN_DEBUG "PLL %d disabled\n", id); 150#endif 151 return res; 152} 153 154 155/*---------------------------------------------------------------------------- 156 * ARM11 'owned' clock control 157 *---------------------------------------------------------------------------*/ 158 159unsigned long acpuclk_power_collapse(void) { 160 int ret = acpuclk_get_rate(); 161 ret *= 1000; 162 if (ret > drv_state.power_collapse_khz) 163 acpuclk_set_rate(drv_state.power_collapse_khz, 1); 164 return ret; 165} 166 167unsigned long acpuclk_get_wfi_rate(void) 168{ 169 return drv_state.wait_for_irq_khz; 170} 171 172unsigned long acpuclk_wait_for_irq(void) { 173 int ret = acpuclk_get_rate(); 174 ret *= 1000; 175 if (ret > drv_state.wait_for_irq_khz) 176 acpuclk_set_rate(drv_state.wait_for_irq_khz, 1); 177 return ret; 178} 179 180static int acpuclk_set_vdd_level(int vdd) 181{ 182 uint32_t current_vdd; 183 184 current_vdd = readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07; 185 186#if PERF_SWITCH_DEBUG 187 printk(KERN_DEBUG "acpuclock: Switching VDD from %u -> %d\n", 188 current_vdd, vdd); 189#endif 190 writel((1 << 7) | (vdd << 3), A11S_VDD_SVS_PLEVEL_ADDR); 191 udelay(drv_state.vdd_switch_time_us); 192 if ((readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x7) != vdd) { 193#if PERF_SWITCH_DEBUG 194 printk(KERN_ERR "acpuclock: VDD set failed\n"); 195#endif 196 return -EIO; 197 } 198 199#if PERF_SWITCH_DEBUG 200 printk(KERN_DEBUG "acpuclock: VDD switched\n"); 201#endif 202 return 0; 203} 204 205/* Set proper dividers for the given clock speed. */ 206static void acpuclk_set_div(const struct clkctl_acpu_speed *hunt_s) { 207 uint32_t reg_clkctl, reg_clksel, clk_div; 208 209 /* AHB_CLK_DIV */ 210 clk_div = (readl(A11S_CLK_SEL_ADDR) >> 1) & 0x03; 211 /* 212 * If the new clock divider is higher than the previous, then 213 * program the divider before switching the clock 214 */ 215 if (hunt_s->ahbclk_div > clk_div) { 216 reg_clksel = readl(A11S_CLK_SEL_ADDR); 217 reg_clksel &= ~(0x3 << 1); 218 reg_clksel |= (hunt_s->ahbclk_div << 1); 219 writel(reg_clksel, A11S_CLK_SEL_ADDR); 220 } 221 if ((readl(A11S_CLK_SEL_ADDR) & 0x01) == 0) { 222 /* SRC0 */ 223 224 /* Program clock source */ 225 reg_clkctl = readl(A11S_CLK_CNTL_ADDR); 226 reg_clkctl &= ~(0x07 << 4); 227 reg_clkctl |= (hunt_s->a11clk_src_sel << 4); 228 writel(reg_clkctl, A11S_CLK_CNTL_ADDR); 229 230 /* Program clock divider */ 231 reg_clkctl = readl(A11S_CLK_CNTL_ADDR); 232 reg_clkctl &= ~0xf; 233 reg_clkctl |= hunt_s->a11clk_src_div; 234 writel(reg_clkctl, A11S_CLK_CNTL_ADDR); 235 236 /* Program clock source selection */ 237 reg_clksel = readl(A11S_CLK_SEL_ADDR); 238 reg_clksel |= 1; /* CLK_SEL_SRC1NO == SRC1 */ 239 writel(reg_clksel, A11S_CLK_SEL_ADDR); 240 } else { 241 /* SRC1 */ 242 243 /* Program clock source */ 244 reg_clkctl = readl(A11S_CLK_CNTL_ADDR); 245 reg_clkctl &= ~(0x07 << 12); 246 reg_clkctl |= (hunt_s->a11clk_src_sel << 12); 247 writel(reg_clkctl, A11S_CLK_CNTL_ADDR); 248 249 /* Program clock divider */ 250 reg_clkctl = readl(A11S_CLK_CNTL_ADDR); 251 reg_clkctl &= ~(0xf << 8); 252 reg_clkctl |= (hunt_s->a11clk_src_div << 8); 253 writel(reg_clkctl, A11S_CLK_CNTL_ADDR); 254 255 /* Program clock source selection */ 256 reg_clksel = readl(A11S_CLK_SEL_ADDR); 257 reg_clksel &= ~1; /* CLK_SEL_SRC1NO == SRC0 */ 258 writel(reg_clksel, A11S_CLK_SEL_ADDR); 259 } 260 261 /* 262 * If the new clock divider is lower than the previous, then 263 * program the divider after switching the clock 264 */ 265 if (hunt_s->ahbclk_div < clk_div) { 266 reg_clksel = readl(A11S_CLK_SEL_ADDR); 267 reg_clksel &= ~(0x3 << 1); 268 reg_clksel |= (hunt_s->ahbclk_div << 1); 269 writel(reg_clksel, A11S_CLK_SEL_ADDR); 270 } 271} 272 273int acpuclk_set_rate(unsigned long rate, int for_power_collapse) 274{ 275 uint32_t reg_clkctl; 276 struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s; 277 int rc = 0; 278 unsigned int plls_enabled = 0, pll; 279 280 strt_s = cur_s = drv_state.current_speed; 281 282 WARN_ONCE(cur_s == NULL, "acpuclk_set_rate: not initialized\n"); 283 if (cur_s == NULL) 284 return -ENOENT; 285 286 if (rate == (cur_s->a11clk_khz * 1000)) 287 return 0; 288 289 for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) { 290 if (tgt_s->a11clk_khz == (rate / 1000)) 291 break; 292 } 293 294 if (tgt_s->a11clk_khz == 0) 295 return -EINVAL; 296 297 /* Choose the highest speed speed at or below 'rate' with same PLL. */ 298 if (for_power_collapse && tgt_s->a11clk_khz < cur_s->a11clk_khz) { 299 while (tgt_s->pll != ACPU_PLL_TCXO && tgt_s->pll != cur_s->pll) 300 tgt_s--; 301 } 302 303 if (strt_s->pll != ACPU_PLL_TCXO) 304 plls_enabled |= 1 << strt_s->pll; 305 306 if (!for_power_collapse) { 307 mutex_lock(&drv_state.lock); 308 if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { 309 rc = pc_pll_request(tgt_s->pll, 1); 310 if (rc < 0) { 311 pr_err("PLL%d enable failed (%d)\n", 312 tgt_s->pll, rc); 313 goto out; 314 } 315 plls_enabled |= 1 << tgt_s->pll; 316 } 317 /* Increase VDD if needed. */ 318 if (tgt_s->vdd > cur_s->vdd) { 319 if ((rc = acpuclk_set_vdd_level(tgt_s->vdd)) < 0) { 320 printk(KERN_ERR "Unable to switch ACPU vdd\n"); 321 goto out; 322 } 323 } 324 } 325 326 /* Set wait states for CPU inbetween frequency changes */ 327 reg_clkctl = readl(A11S_CLK_CNTL_ADDR); 328 reg_clkctl |= (100 << 16); /* set WT_ST_CNT */ 329 writel(reg_clkctl, A11S_CLK_CNTL_ADDR); 330 331#if PERF_SWITCH_DEBUG 332 printk(KERN_INFO "acpuclock: Switching from ACPU rate %u -> %u\n", 333 strt_s->a11clk_khz * 1000, tgt_s->a11clk_khz * 1000); 334#endif 335 336 while (cur_s != tgt_s) { 337 /* 338 * Always jump to target freq if within 256mhz, regulardless of 339 * PLL. If differnece is greater, use the predefinied 340 * steppings in the table. 341 */ 342 int d = abs((int)(cur_s->a11clk_khz - tgt_s->a11clk_khz)); 343 if (d > drv_state.max_speed_delta_khz) { 344 /* Step up or down depending on target vs current. */ 345 int clk_index = tgt_s->a11clk_khz > cur_s->a11clk_khz ? 346 cur_s->up : cur_s->down; 347 if (clk_index < 0) { /* This should not happen. */ 348 printk(KERN_ERR "cur:%u target: %u\n", 349 cur_s->a11clk_khz, tgt_s->a11clk_khz); 350 rc = -EINVAL; 351 goto out; 352 } 353 cur_s = &acpu_freq_tbl[clk_index]; 354 } else { 355 cur_s = tgt_s; 356 } 357#if PERF_SWITCH_STEP_DEBUG 358 printk(KERN_DEBUG "%s: STEP khz = %u, pll = %d\n", 359 __FUNCTION__, cur_s->a11clk_khz, cur_s->pll); 360#endif 361 if (!for_power_collapse&& cur_s->pll != ACPU_PLL_TCXO 362 && !(plls_enabled & (1 << cur_s->pll))) { 363 rc = pc_pll_request(cur_s->pll, 1); 364 if (rc < 0) { 365 pr_err("PLL%d enable failed (%d)\n", 366 cur_s->pll, rc); 367 goto out; 368 } 369 plls_enabled |= 1 << cur_s->pll; 370 } 371 372 acpuclk_set_div(cur_s); 373 drv_state.current_speed = cur_s; 374 /* Re-adjust lpj for the new clock speed. */ 375 loops_per_jiffy = cur_s->lpj; 376 udelay(drv_state.acpu_switch_time_us); 377 } 378 379 /* Nothing else to do for power collapse. */ 380 if (for_power_collapse) 381 return 0; 382 383 /* Disable PLLs we are not using anymore. */ 384 plls_enabled &= ~(1 << tgt_s->pll); 385 for (pll = ACPU_PLL_0; pll <= ACPU_PLL_2; pll++) 386 if (plls_enabled & (1 << pll)) { 387 rc = pc_pll_request(pll, 0); 388 if (rc < 0) { 389 pr_err("PLL%d disable failed (%d)\n", pll, rc); 390 goto out; 391 } 392 } 393 394 /* Change the AXI bus frequency if we can. */ 395 if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { 396 rc = clk_set_rate(ebi1_clk, tgt_s->axiclk_khz * 1000); 397 if (rc < 0) 398 pr_err("Setting AXI min rate failed!\n"); 399 } 400 401 /* Drop VDD level if we can. */ 402 if (tgt_s->vdd < strt_s->vdd) { 403 if (acpuclk_set_vdd_level(tgt_s->vdd) < 0) 404 printk(KERN_ERR "acpuclock: Unable to drop ACPU vdd\n"); 405 } 406 407#if PERF_SWITCH_DEBUG 408 printk(KERN_DEBUG "%s: ACPU speed change complete\n", __FUNCTION__); 409#endif 410out: 411 if (!for_power_collapse) 412 mutex_unlock(&drv_state.lock); 413 return rc; 414} 415 416static void __init acpuclk_init(void) 417{ 418 struct clkctl_acpu_speed *speed; 419 uint32_t div, sel; 420 int rc; 421 422 /* 423 * Determine the rate of ACPU clock 424 */ 425 426 if (!(readl(A11S_CLK_SEL_ADDR) & 0x01)) { /* CLK_SEL_SRC1N0 */ 427 /* CLK_SRC0_SEL */ 428 sel = (readl(A11S_CLK_CNTL_ADDR) >> 12) & 0x7; 429 /* CLK_SRC0_DIV */ 430 div = (readl(A11S_CLK_CNTL_ADDR) >> 8) & 0x0f; 431 } else { 432 /* CLK_SRC1_SEL */ 433 sel = (readl(A11S_CLK_CNTL_ADDR) >> 4) & 0x07; 434 /* CLK_SRC1_DIV */ 435 div = readl(A11S_CLK_CNTL_ADDR) & 0x0f; 436 } 437 438 for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) { 439 if (speed->a11clk_src_sel == sel 440 && (speed->a11clk_src_div == div)) 441 break; 442 } 443 if (speed->a11clk_khz == 0) { 444 printk(KERN_WARNING "Warning - ACPU clock reports invalid speed\n"); 445 return; 446 } 447 448 drv_state.current_speed = speed; 449 450 rc = clk_set_rate(ebi1_clk, speed->axiclk_khz * 1000); 451 if (rc < 0) 452 pr_err("Setting AXI min rate failed!\n"); 453 454 printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz); 455} 456 457unsigned long acpuclk_get_rate(void) 458{ 459 WARN_ONCE(drv_state.current_speed == NULL, 460 "acpuclk_get_rate: not initialized\n"); 461 if (drv_state.current_speed) 462 return drv_state.current_speed->a11clk_khz; 463 else 464 return 0; 465} 466 467uint32_t acpuclk_get_switch_time(void) 468{ 469 return drv_state.acpu_switch_time_us; 470} 471 472/*---------------------------------------------------------------------------- 473 * Clock driver initialization 474 *---------------------------------------------------------------------------*/ 475 476/* Initialize the lpj field in the acpu_freq_tbl. */ 477static void __init lpj_init(void) 478{ 479 int i; 480 const struct clkctl_acpu_speed *base_clk = drv_state.current_speed; 481 for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) { 482 acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy, 483 base_clk->a11clk_khz, 484 acpu_freq_tbl[i].a11clk_khz); 485 } 486} 487 488void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) 489{ 490 pr_info("acpu_clock_init()\n"); 491 492 ebi1_clk = clk_get(NULL, "ebi1_clk"); 493 494 mutex_init(&drv_state.lock); 495 drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us; 496 drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz; 497 drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us; 498 drv_state.power_collapse_khz = clkdata->power_collapse_khz; 499 drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz; 500 acpuclk_init(); 501 lpj_init(); 502#ifdef CONFIG_CPU_FREQ_TABLE 503 cpufreq_frequency_table_get_attr(freq_table, smp_processor_id()); 504#endif 505} 506