| Duy Truong | e833aca | 2013-02-12 13:35:08 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 2 | * | 
|  | 3 | * This program is free software; you can redistribute it and/or modify | 
|  | 4 | * it under the terms of the GNU General Public License version 2 and | 
|  | 5 | * only version 2 as published by the Free Software Foundation. | 
|  | 6 | * | 
|  | 7 | * This program is distributed in the hope that it will be useful, | 
|  | 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 10 | * GNU General Public License for more details. | 
|  | 11 | * | 
|  | 12 | */ | 
|  | 13 |  | 
|  | 14 | #include <linux/kernel.h> | 
| Matt Wagantall | bf430eb | 2012-03-22 11:45:49 -0700 | [diff] [blame] | 15 | #include <linux/module.h> | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 16 | #include <linux/init.h> | 
|  | 17 | #include <linux/io.h> | 
|  | 18 | #include <linux/delay.h> | 
|  | 19 | #include <linux/mutex.h> | 
|  | 20 | #include <linux/errno.h> | 
|  | 21 | #include <linux/cpufreq.h> | 
|  | 22 | #include <linux/clk.h> | 
| Matt Wagantall | ec57f06 | 2011-08-16 23:54:46 -0700 | [diff] [blame] | 23 | #include <linux/mfd/tps65023.h> | 
| Matt Wagantall | bf430eb | 2012-03-22 11:45:49 -0700 | [diff] [blame] | 24 | #include <linux/platform_device.h> | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 25 |  | 
|  | 26 | #include <mach/board.h> | 
|  | 27 | #include <mach/msm_iomap.h> | 
|  | 28 |  | 
|  | 29 | #include "acpuclock.h" | 
|  | 30 | #include "avs.h" | 
|  | 31 |  | 
|  | 32 | #define SHOT_SWITCH 4 | 
|  | 33 | #define HOP_SWITCH 5 | 
|  | 34 | #define SIMPLE_SLEW 6 | 
|  | 35 | #define COMPLEX_SLEW 7 | 
|  | 36 |  | 
|  | 37 | #define SPSS_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100) | 
|  | 38 | #define SPSS_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) | 
|  | 39 |  | 
|  | 40 | /* Scorpion PLL registers */ | 
|  | 41 | #define SCPLL_CTL_ADDR         (MSM_SCPLL_BASE + 0x4) | 
|  | 42 | #define SCPLL_STATUS_ADDR      (MSM_SCPLL_BASE + 0x18) | 
|  | 43 | #define SCPLL_FSM_CTL_EXT_ADDR (MSM_SCPLL_BASE + 0x10) | 
|  | 44 |  | 
| Matt Wagantall | ec57f06 | 2011-08-16 23:54:46 -0700 | [diff] [blame] | 45 | #ifdef CONFIG_QSD_SVS | 
|  | 46 | #define TPS65023_MAX_DCDC1	1600 | 
|  | 47 | #else | 
|  | 48 | #define TPS65023_MAX_DCDC1	CONFIG_QSD_PMIC_DEFAULT_DCDC1 | 
|  | 49 | #endif | 
|  | 50 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 51 | enum { | 
|  | 52 | ACPU_PLL_TCXO	= -1, | 
|  | 53 | ACPU_PLL_0	= 0, | 
|  | 54 | ACPU_PLL_1, | 
|  | 55 | ACPU_PLL_2, | 
|  | 56 | ACPU_PLL_3, | 
|  | 57 | ACPU_PLL_END, | 
|  | 58 | }; | 
|  | 59 |  | 
|  | 60 | struct clkctl_acpu_speed { | 
|  | 61 | unsigned int     use_for_scaling; | 
|  | 62 | unsigned int     acpuclk_khz; | 
|  | 63 | int              pll; | 
|  | 64 | unsigned int     acpuclk_src_sel; | 
|  | 65 | unsigned int     acpuclk_src_div; | 
|  | 66 | unsigned int     ahbclk_khz; | 
|  | 67 | unsigned int     ahbclk_div; | 
|  | 68 | unsigned int     axiclk_khz; | 
|  | 69 | unsigned int     sc_core_src_sel_mask; | 
|  | 70 | unsigned int     sc_l_value; | 
|  | 71 | int              vdd; | 
|  | 72 | unsigned long    lpj; /* loops_per_jiffy */ | 
|  | 73 | }; | 
|  | 74 |  | 
|  | 75 | struct clkctl_acpu_speed acpu_freq_tbl_998[] = { | 
|  | 76 | { 0, 19200, ACPU_PLL_TCXO, 0, 0, 0, 0, 14000, 0, 0, 1000}, | 
|  | 77 | { 0, 128000, ACPU_PLL_1, 1, 5, 0, 0, 14000, 2, 0, 1000}, | 
|  | 78 | { 1, 245760, ACPU_PLL_0, 4, 0, 0, 0, 29000, 0, 0, 1000}, | 
|  | 79 | /* Update AXI_S and PLL0_S macros if above row numbers change. */ | 
|  | 80 | { 1, 384000, ACPU_PLL_3, 0, 0, 0, 0, 58000, 1, 0xA, 1000}, | 
|  | 81 | { 0, 422400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xB, 1000}, | 
|  | 82 | { 0, 460800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xC, 1000}, | 
|  | 83 | { 0, 499200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xD, 1050}, | 
|  | 84 | { 0, 537600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xE, 1050}, | 
|  | 85 | { 1, 576000, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xF, 1050}, | 
|  | 86 | { 0, 614400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x10, 1075}, | 
|  | 87 | { 0, 652800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x11, 1100}, | 
|  | 88 | { 0, 691200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x12, 1125}, | 
|  | 89 | { 0, 729600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x13, 1150}, | 
|  | 90 | { 1, 768000, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x14, 1150}, | 
|  | 91 | { 0, 806400, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x15, 1175}, | 
|  | 92 | { 0, 844800, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x16, 1225}, | 
|  | 93 | { 0, 883200, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x17, 1250}, | 
|  | 94 | { 0, 921600, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x18, 1300}, | 
|  | 95 | { 0, 960000, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x19, 1300}, | 
|  | 96 | { 1, 998400, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x1A, 1300}, | 
|  | 97 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | 
|  | 98 | }; | 
|  | 99 |  | 
|  | 100 | struct clkctl_acpu_speed acpu_freq_tbl_768[] = { | 
|  | 101 | { 0, 19200, ACPU_PLL_TCXO, 0, 0, 0, 0, 14000, 0, 0, 1000}, | 
|  | 102 | { 0, 128000, ACPU_PLL_1, 1, 5, 0, 0, 14000, 2, 0, 1000}, | 
|  | 103 | { 1, 245760, ACPU_PLL_0, 4, 0, 0, 0, 29000, 0, 0, 1000}, | 
|  | 104 | /* Update AXI_S and PLL0_S macros if above row numbers change. */ | 
|  | 105 | { 1, 384000, ACPU_PLL_3, 0, 0, 0, 0, 58000, 1, 0xA, 1075}, | 
|  | 106 | { 0, 422400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xB, 1100}, | 
|  | 107 | { 0, 460800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xC, 1125}, | 
|  | 108 | { 0, 499200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xD, 1150}, | 
|  | 109 | { 0, 537600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xE, 1150}, | 
|  | 110 | { 1, 576000, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xF, 1150}, | 
|  | 111 | { 0, 614400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x10, 1175}, | 
|  | 112 | { 0, 652800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x11, 1200}, | 
|  | 113 | { 0, 691200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x12, 1225}, | 
|  | 114 | { 0, 729600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x13, 1250}, | 
|  | 115 | { 1, 768000, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x14, 1250}, | 
|  | 116 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | 
|  | 117 | }; | 
|  | 118 |  | 
|  | 119 | static struct clkctl_acpu_speed *acpu_freq_tbl = acpu_freq_tbl_998; | 
|  | 120 | #define AXI_S	(&acpu_freq_tbl[1]) | 
|  | 121 | #define PLL0_S	(&acpu_freq_tbl[2]) | 
|  | 122 |  | 
|  | 123 | /* Use 128MHz for PC since ACPU will auto-switch to AXI (128MHz) before | 
|  | 124 | * coming back up. This allows detection of return-from-PC, since 128MHz | 
|  | 125 | * is only used for power collapse. */ | 
| Matt Wagantall | 6d9ebee | 2011-08-26 12:15:24 -0700 | [diff] [blame] | 126 | #define POWER_COLLAPSE_KHZ	128000 | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 127 | /* Use 245MHz (not 128MHz) for SWFI to avoid unnecessary steps between | 
|  | 128 | * 128MHz<->245MHz. Jumping to high frequencies from 128MHz directly | 
|  | 129 | * is not allowed. */ | 
| Matt Wagantall | 6d9ebee | 2011-08-26 12:15:24 -0700 | [diff] [blame] | 130 | #define WAIT_FOR_IRQ_KHZ	245760 | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 131 |  | 
|  | 132 | #ifdef CONFIG_CPU_FREQ_MSM | 
|  | 133 | static struct cpufreq_frequency_table freq_table[20]; | 
|  | 134 |  | 
| Matt Wagantall | bf430eb | 2012-03-22 11:45:49 -0700 | [diff] [blame] | 135 | static void __devinit cpufreq_table_init(void) | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 136 | { | 
|  | 137 | unsigned int i; | 
|  | 138 | unsigned int freq_cnt = 0; | 
|  | 139 |  | 
|  | 140 | /* Construct the freq_table table from acpu_freq_tbl since the | 
|  | 141 | * freq_table values need to match frequencies specified in | 
|  | 142 | * acpu_freq_tbl and acpu_freq_tbl needs to be fixed up during init. | 
|  | 143 | */ | 
|  | 144 | for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0 | 
|  | 145 | && freq_cnt < ARRAY_SIZE(freq_table)-1; i++) { | 
|  | 146 | if (acpu_freq_tbl[i].use_for_scaling) { | 
|  | 147 | freq_table[freq_cnt].index = freq_cnt; | 
|  | 148 | freq_table[freq_cnt].frequency | 
|  | 149 | = acpu_freq_tbl[i].acpuclk_khz; | 
|  | 150 | freq_cnt++; | 
|  | 151 | } | 
|  | 152 | } | 
|  | 153 |  | 
|  | 154 | /* freq_table not big enough to store all usable freqs. */ | 
|  | 155 | BUG_ON(acpu_freq_tbl[i].acpuclk_khz != 0); | 
|  | 156 |  | 
|  | 157 | freq_table[freq_cnt].index = freq_cnt; | 
|  | 158 | freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END; | 
|  | 159 |  | 
|  | 160 | pr_info("%d scaling frequencies supported.\n", freq_cnt); | 
|  | 161 | } | 
|  | 162 | #endif | 
|  | 163 |  | 
|  | 164 | struct clock_state { | 
|  | 165 | struct clkctl_acpu_speed	*current_speed; | 
|  | 166 | struct mutex			lock; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 167 | struct clk			*ebi1_clk; | 
|  | 168 | int (*acpu_set_vdd) (int mvolts); | 
|  | 169 | }; | 
|  | 170 |  | 
|  | 171 | static struct clock_state drv_state = { 0 }; | 
|  | 172 |  | 
|  | 173 | static void scpll_set_freq(uint32_t lval, unsigned freq_switch) | 
|  | 174 | { | 
|  | 175 | uint32_t regval; | 
|  | 176 |  | 
|  | 177 | if (lval > 33) | 
|  | 178 | lval = 33; | 
|  | 179 | if (lval < 10) | 
|  | 180 | lval = 10; | 
|  | 181 |  | 
|  | 182 | /* wait for any calibrations or frequency switches to finish */ | 
|  | 183 | while (readl(SCPLL_STATUS_ADDR) & 0x3) | 
|  | 184 | ; | 
|  | 185 |  | 
|  | 186 | /* write the new L val and switch mode */ | 
|  | 187 | regval = readl(SCPLL_FSM_CTL_EXT_ADDR); | 
|  | 188 | regval &= ~(0x3f << 3); | 
|  | 189 | regval |= (lval << 3); | 
|  | 190 | if (freq_switch == SIMPLE_SLEW) | 
|  | 191 | regval |= (0x1 << 9); | 
|  | 192 |  | 
|  | 193 | regval &= ~(0x3 << 0); | 
|  | 194 | regval |= (freq_switch << 0); | 
|  | 195 | writel(regval, SCPLL_FSM_CTL_EXT_ADDR); | 
|  | 196 |  | 
|  | 197 | dmb(); | 
|  | 198 |  | 
|  | 199 | /* put in normal mode */ | 
|  | 200 | regval = readl(SCPLL_CTL_ADDR); | 
|  | 201 | regval |= 0x7; | 
|  | 202 | writel(regval, SCPLL_CTL_ADDR); | 
|  | 203 |  | 
|  | 204 | dmb(); | 
|  | 205 |  | 
|  | 206 | /* wait for frequency switch to finish */ | 
|  | 207 | while (readl(SCPLL_STATUS_ADDR) & 0x1) | 
|  | 208 | ; | 
|  | 209 |  | 
|  | 210 | /* status bit seems to clear early, using | 
|  | 211 | * 100us to handle the worst case. */ | 
|  | 212 | udelay(100); | 
|  | 213 | } | 
|  | 214 |  | 
|  | 215 | static void scpll_apps_enable(bool state) | 
|  | 216 | { | 
|  | 217 | uint32_t regval; | 
|  | 218 |  | 
|  | 219 | if (state) | 
|  | 220 | pr_debug("Enabling PLL 3\n"); | 
|  | 221 | else | 
|  | 222 | pr_debug("Disabling PLL 3\n"); | 
|  | 223 |  | 
|  | 224 | /* Wait for any frequency switches to finish. */ | 
|  | 225 | while (readl(SCPLL_STATUS_ADDR) & 0x1) | 
|  | 226 | ; | 
|  | 227 |  | 
|  | 228 | /* put the pll in standby mode */ | 
|  | 229 | regval = readl(SCPLL_CTL_ADDR); | 
|  | 230 | regval &= ~(0x7); | 
|  | 231 | regval |= (0x2); | 
|  | 232 | writel(regval, SCPLL_CTL_ADDR); | 
|  | 233 |  | 
|  | 234 | dmb(); | 
|  | 235 |  | 
|  | 236 | if (state) { | 
|  | 237 | /* put the pll in normal mode */ | 
|  | 238 | regval = readl(SCPLL_CTL_ADDR); | 
|  | 239 | regval |= (0x7); | 
|  | 240 | writel(regval, SCPLL_CTL_ADDR); | 
|  | 241 | udelay(200); | 
|  | 242 | } else { | 
|  | 243 | /* put the pll in power down mode */ | 
|  | 244 | regval = readl(SCPLL_CTL_ADDR); | 
|  | 245 | regval &= ~(0x7); | 
|  | 246 | writel(regval, SCPLL_CTL_ADDR); | 
|  | 247 | } | 
| Matt Wagantall | ec57f06 | 2011-08-16 23:54:46 -0700 | [diff] [blame] | 248 | udelay(62); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 249 |  | 
|  | 250 | if (state) | 
|  | 251 | pr_debug("PLL 3 Enabled\n"); | 
|  | 252 | else | 
|  | 253 | pr_debug("PLL 3 Disabled\n"); | 
|  | 254 | } | 
|  | 255 |  | 
|  | 256 | static void scpll_init(void) | 
|  | 257 | { | 
|  | 258 | uint32_t regval; | 
|  | 259 | #define L_VAL_384MHZ	0xA | 
|  | 260 | #define L_VAL_768MHZ	0x14 | 
|  | 261 |  | 
|  | 262 | pr_debug("Initializing PLL 3\n"); | 
|  | 263 |  | 
|  | 264 | /* power down scpll */ | 
|  | 265 | writel(0x0, SCPLL_CTL_ADDR); | 
|  | 266 |  | 
|  | 267 | dmb(); | 
|  | 268 |  | 
|  | 269 | /* set bypassnl, put into standby */ | 
|  | 270 | writel(0x00400002, SCPLL_CTL_ADDR); | 
|  | 271 |  | 
|  | 272 | /* set bypassnl, reset_n, full calibration */ | 
|  | 273 | writel(0x00600004, SCPLL_CTL_ADDR); | 
|  | 274 |  | 
|  | 275 | /* Ensure register write to initiate calibration has taken | 
|  | 276 | effect before reading status flag */ | 
|  | 277 | dmb(); | 
|  | 278 |  | 
|  | 279 | /* wait for cal_all_done */ | 
|  | 280 | while (readl(SCPLL_STATUS_ADDR) & 0x2) | 
|  | 281 | ; | 
|  | 282 |  | 
|  | 283 | /* Start: Set of experimentally derived steps | 
|  | 284 | * to work around a h/w bug. */ | 
|  | 285 |  | 
|  | 286 | /* Put the pll in normal mode */ | 
|  | 287 | scpll_apps_enable(1); | 
|  | 288 |  | 
|  | 289 | /* SHOT switch to 384 MHz */ | 
|  | 290 | regval = readl(SCPLL_FSM_CTL_EXT_ADDR); | 
|  | 291 | regval &= ~(0x3f << 3); | 
|  | 292 | regval |= (L_VAL_384MHZ << 3); | 
|  | 293 |  | 
|  | 294 | regval &= ~0x7; | 
|  | 295 | regval |= SHOT_SWITCH; | 
|  | 296 | writel(regval, SCPLL_FSM_CTL_EXT_ADDR); | 
|  | 297 |  | 
|  | 298 | /* Trigger the freq switch by putting pll in normal mode. */ | 
|  | 299 | regval = readl(SCPLL_CTL_ADDR); | 
|  | 300 | regval |= (0x7); | 
|  | 301 | writel(regval, SCPLL_CTL_ADDR); | 
|  | 302 |  | 
|  | 303 | /* Wait for frequency switch to finish */ | 
|  | 304 | while (readl(SCPLL_STATUS_ADDR) & 0x1) | 
|  | 305 | ; | 
|  | 306 |  | 
|  | 307 | /* Status bit seems to clear early, using | 
|  | 308 | * 800 microseconds for the worst case. */ | 
|  | 309 | udelay(800); | 
|  | 310 |  | 
|  | 311 | /* HOP switch to 768 MHz. */ | 
|  | 312 | regval = readl(SCPLL_FSM_CTL_EXT_ADDR); | 
|  | 313 | regval &= ~(0x3f << 3); | 
|  | 314 | regval |= (L_VAL_768MHZ << 3); | 
|  | 315 |  | 
|  | 316 | regval &= ~0x7; | 
|  | 317 | regval |= HOP_SWITCH; | 
|  | 318 | writel(regval, SCPLL_FSM_CTL_EXT_ADDR); | 
|  | 319 |  | 
|  | 320 | /* Trigger the freq switch by putting pll in normal mode. */ | 
|  | 321 | regval = readl(SCPLL_CTL_ADDR); | 
|  | 322 | regval |= (0x7); | 
|  | 323 | writel(regval, SCPLL_CTL_ADDR); | 
|  | 324 |  | 
|  | 325 | /* Wait for frequency switch to finish */ | 
|  | 326 | while (readl(SCPLL_STATUS_ADDR) & 0x1) | 
|  | 327 | ; | 
|  | 328 |  | 
|  | 329 | /* Status bit seems to clear early, using | 
|  | 330 | * 100 microseconds for the worst case. */ | 
|  | 331 | udelay(100); | 
|  | 332 |  | 
|  | 333 | /* End: Work around for h/w bug */ | 
|  | 334 |  | 
|  | 335 | /* Power down scpll */ | 
|  | 336 | scpll_apps_enable(0); | 
|  | 337 | } | 
|  | 338 |  | 
|  | 339 | static void config_pll(struct clkctl_acpu_speed *s) | 
|  | 340 | { | 
|  | 341 | uint32_t regval; | 
|  | 342 |  | 
|  | 343 | if (s->pll == ACPU_PLL_3) | 
|  | 344 | scpll_set_freq(s->sc_l_value, HOP_SWITCH); | 
|  | 345 | /* Configure the PLL divider mux if we plan to use it. */ | 
|  | 346 | else if (s->sc_core_src_sel_mask == 0) { | 
|  | 347 | /* get the current clock source selection */ | 
|  | 348 | regval = readl(SPSS_CLK_SEL_ADDR) & 0x1; | 
|  | 349 |  | 
|  | 350 | /* configure the other clock source, then switch to it, | 
|  | 351 | * using the glitch free mux */ | 
|  | 352 | switch (regval) { | 
|  | 353 | case 0x0: | 
|  | 354 | regval = readl(SPSS_CLK_CNTL_ADDR); | 
|  | 355 | regval &= ~(0x7 << 4 | 0xf); | 
|  | 356 | regval |= (s->acpuclk_src_sel << 4); | 
|  | 357 | regval |= (s->acpuclk_src_div << 0); | 
|  | 358 | writel(regval, SPSS_CLK_CNTL_ADDR); | 
|  | 359 |  | 
|  | 360 | regval = readl(SPSS_CLK_SEL_ADDR); | 
|  | 361 | regval |= 0x1; | 
|  | 362 | writel(regval, SPSS_CLK_SEL_ADDR); | 
|  | 363 | break; | 
|  | 364 |  | 
|  | 365 | case 0x1: | 
|  | 366 | regval = readl(SPSS_CLK_CNTL_ADDR); | 
|  | 367 | regval &= ~(0x7 << 12 | 0xf << 8); | 
|  | 368 | regval |= (s->acpuclk_src_sel << 12); | 
|  | 369 | regval |= (s->acpuclk_src_div << 8); | 
|  | 370 | writel(regval, SPSS_CLK_CNTL_ADDR); | 
|  | 371 |  | 
|  | 372 | regval = readl(SPSS_CLK_SEL_ADDR); | 
|  | 373 | regval &= ~0x1; | 
|  | 374 | writel(regval, SPSS_CLK_SEL_ADDR); | 
|  | 375 | break; | 
|  | 376 | } | 
|  | 377 | dmb(); | 
|  | 378 | } | 
|  | 379 |  | 
|  | 380 | regval = readl(SPSS_CLK_SEL_ADDR); | 
|  | 381 | regval &= ~(0x3 << 1); | 
|  | 382 | regval |= (s->sc_core_src_sel_mask << 1); | 
|  | 383 | writel(regval, SPSS_CLK_SEL_ADDR); | 
|  | 384 | } | 
|  | 385 |  | 
|  | 386 | static int acpuclk_set_vdd_level(int vdd) | 
|  | 387 | { | 
|  | 388 | if (drv_state.acpu_set_vdd) { | 
|  | 389 | pr_debug("Switching VDD to %d mV\n", vdd); | 
|  | 390 | return drv_state.acpu_set_vdd(vdd); | 
|  | 391 | } else { | 
|  | 392 | /* Assume that the PMIC supports scaling the processor | 
|  | 393 | * to its maximum frequency at its default voltage. | 
|  | 394 | */ | 
|  | 395 | return 0; | 
|  | 396 | } | 
|  | 397 | } | 
|  | 398 |  | 
| Matt Wagantall | 6d9ebee | 2011-08-26 12:15:24 -0700 | [diff] [blame] | 399 | static int acpuclk_8x50_set_rate(int cpu, unsigned long rate, | 
|  | 400 | enum setrate_reason reason) | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 401 | { | 
|  | 402 | struct clkctl_acpu_speed *tgt_s, *strt_s; | 
|  | 403 | int res, rc = 0; | 
|  | 404 | int freq_index = 0; | 
|  | 405 |  | 
|  | 406 | if (reason == SETRATE_CPUFREQ) | 
|  | 407 | mutex_lock(&drv_state.lock); | 
|  | 408 |  | 
|  | 409 | strt_s = drv_state.current_speed; | 
|  | 410 |  | 
|  | 411 | if (rate == strt_s->acpuclk_khz) | 
|  | 412 | goto out; | 
|  | 413 |  | 
|  | 414 | for (tgt_s = acpu_freq_tbl; tgt_s->acpuclk_khz != 0; tgt_s++) { | 
|  | 415 | if (tgt_s->acpuclk_khz == rate) | 
|  | 416 | break; | 
|  | 417 | freq_index++; | 
|  | 418 | } | 
|  | 419 |  | 
|  | 420 | if (tgt_s->acpuclk_khz == 0) { | 
|  | 421 | rc = -EINVAL; | 
|  | 422 | goto out; | 
|  | 423 | } | 
|  | 424 |  | 
|  | 425 | if (reason == SETRATE_CPUFREQ) { | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 426 | /* Increase VDD if needed. */ | 
|  | 427 | if (tgt_s->vdd > strt_s->vdd) { | 
|  | 428 | rc = acpuclk_set_vdd_level(tgt_s->vdd); | 
|  | 429 | if (rc) { | 
|  | 430 | pr_err("Unable to increase ACPU vdd (%d)\n", | 
|  | 431 | rc); | 
|  | 432 | goto out; | 
|  | 433 | } | 
|  | 434 | } | 
|  | 435 | } else if (reason == SETRATE_PC | 
|  | 436 | && rate != POWER_COLLAPSE_KHZ) { | 
|  | 437 | /* Returning from PC. ACPU is running on AXI source. | 
|  | 438 | * Step up to PLL0 before ramping up higher. */ | 
|  | 439 | config_pll(PLL0_S); | 
|  | 440 | } | 
|  | 441 |  | 
|  | 442 | pr_debug("Switching from ACPU rate %u KHz -> %u KHz\n", | 
|  | 443 | strt_s->acpuclk_khz, tgt_s->acpuclk_khz); | 
|  | 444 |  | 
|  | 445 | if (strt_s->pll != ACPU_PLL_3 && tgt_s->pll != ACPU_PLL_3) { | 
|  | 446 | config_pll(tgt_s); | 
|  | 447 | } else if (strt_s->pll != ACPU_PLL_3 && tgt_s->pll == ACPU_PLL_3) { | 
|  | 448 | scpll_apps_enable(1); | 
|  | 449 | config_pll(tgt_s); | 
|  | 450 | } else if (strt_s->pll == ACPU_PLL_3 && tgt_s->pll != ACPU_PLL_3) { | 
|  | 451 | config_pll(tgt_s); | 
|  | 452 | scpll_apps_enable(0); | 
|  | 453 | } else { | 
|  | 454 | /* Temporarily switch to PLL0 while reconfiguring PLL3. */ | 
|  | 455 | config_pll(PLL0_S); | 
|  | 456 | config_pll(tgt_s); | 
|  | 457 | } | 
|  | 458 |  | 
|  | 459 | /* Update the driver state with the new clock freq */ | 
|  | 460 | drv_state.current_speed = tgt_s; | 
|  | 461 |  | 
|  | 462 | /* Re-adjust lpj for the new clock speed. */ | 
|  | 463 | loops_per_jiffy = tgt_s->lpj; | 
|  | 464 |  | 
|  | 465 | /* Nothing else to do for SWFI. */ | 
|  | 466 | if (reason == SETRATE_SWFI) | 
|  | 467 | goto out; | 
|  | 468 |  | 
|  | 469 | if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { | 
|  | 470 | res = clk_set_rate(drv_state.ebi1_clk, | 
|  | 471 | tgt_s->axiclk_khz * 1000); | 
|  | 472 | if (res < 0) | 
|  | 473 | pr_warning("Setting AXI min rate failed (%d)\n", res); | 
|  | 474 | } | 
|  | 475 |  | 
|  | 476 | /* Nothing else to do for power collapse */ | 
|  | 477 | if (reason == SETRATE_PC) | 
|  | 478 | goto out; | 
|  | 479 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 480 | /* Drop VDD level if we can. */ | 
|  | 481 | if (tgt_s->vdd < strt_s->vdd) { | 
|  | 482 | res = acpuclk_set_vdd_level(tgt_s->vdd); | 
|  | 483 | if (res) | 
|  | 484 | pr_warning("Unable to drop ACPU vdd (%d)\n", res); | 
|  | 485 | } | 
|  | 486 |  | 
|  | 487 | pr_debug("ACPU speed change complete\n"); | 
|  | 488 | out: | 
|  | 489 | if (reason == SETRATE_CPUFREQ) | 
|  | 490 | mutex_unlock(&drv_state.lock); | 
|  | 491 | return rc; | 
|  | 492 | } | 
|  | 493 |  | 
| Matt Wagantall | bf430eb | 2012-03-22 11:45:49 -0700 | [diff] [blame] | 494 | static void __devinit acpuclk_hw_init(void) | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 495 | { | 
|  | 496 | struct clkctl_acpu_speed *speed; | 
|  | 497 | uint32_t div, sel, regval; | 
|  | 498 | int res; | 
|  | 499 |  | 
|  | 500 | /* Determine the source of the Scorpion clock. */ | 
|  | 501 | regval = readl(SPSS_CLK_SEL_ADDR); | 
|  | 502 | switch ((regval & 0x6) >> 1) { | 
|  | 503 | case 0: /* raw source clock */ | 
|  | 504 | case 3: /* low jitter PLL1 (768Mhz) */ | 
|  | 505 | if (regval & 0x1) { | 
|  | 506 | sel = ((readl(SPSS_CLK_CNTL_ADDR) >> 4) & 0x7); | 
|  | 507 | div = ((readl(SPSS_CLK_CNTL_ADDR) >> 0) & 0xf); | 
|  | 508 | } else { | 
|  | 509 | sel = ((readl(SPSS_CLK_CNTL_ADDR) >> 12) & 0x7); | 
|  | 510 | div = ((readl(SPSS_CLK_CNTL_ADDR) >> 8) & 0xf); | 
|  | 511 | } | 
|  | 512 |  | 
|  | 513 | /* Find the matching clock rate. */ | 
|  | 514 | for (speed = acpu_freq_tbl; speed->acpuclk_khz != 0; speed++) { | 
|  | 515 | if (speed->acpuclk_src_sel == sel && | 
|  | 516 | speed->acpuclk_src_div == div) | 
|  | 517 | break; | 
|  | 518 | } | 
|  | 519 | break; | 
|  | 520 |  | 
|  | 521 | case 1: /* unbuffered scorpion pll (384Mhz to 998.4Mhz) */ | 
|  | 522 | sel = ((readl(SCPLL_FSM_CTL_EXT_ADDR) >> 3) & 0x3f); | 
|  | 523 |  | 
|  | 524 | /* Find the matching clock rate. */ | 
|  | 525 | for (speed = acpu_freq_tbl; speed->acpuclk_khz != 0; speed++) { | 
|  | 526 | if (speed->sc_l_value == sel && | 
|  | 527 | speed->sc_core_src_sel_mask == 1) | 
|  | 528 | break; | 
|  | 529 | } | 
|  | 530 | break; | 
|  | 531 |  | 
|  | 532 | case 2: /* AXI bus clock (128Mhz) */ | 
|  | 533 | speed = AXI_S; | 
|  | 534 | break; | 
|  | 535 | default: | 
|  | 536 | BUG(); | 
|  | 537 | } | 
|  | 538 |  | 
|  | 539 | /* Initialize scpll only if it wasn't already initialized by the boot | 
|  | 540 | * loader. If the CPU is already running on scpll, then the scpll was | 
|  | 541 | * initialized by the boot loader. */ | 
|  | 542 | if (speed->pll != ACPU_PLL_3) | 
|  | 543 | scpll_init(); | 
|  | 544 |  | 
|  | 545 | if (speed->acpuclk_khz == 0) { | 
|  | 546 | pr_err("Error - ACPU clock reports invalid speed\n"); | 
|  | 547 | return; | 
|  | 548 | } | 
|  | 549 |  | 
|  | 550 | drv_state.current_speed = speed; | 
|  | 551 | res = clk_set_rate(drv_state.ebi1_clk, speed->axiclk_khz * 1000); | 
|  | 552 | if (res < 0) | 
|  | 553 | pr_warning("Setting AXI min rate failed (%d)\n", res); | 
|  | 554 | res = clk_enable(drv_state.ebi1_clk); | 
|  | 555 | if (res < 0) | 
|  | 556 | pr_warning("Enabling AXI clock failed (%d)\n", res); | 
|  | 557 |  | 
|  | 558 | pr_info("ACPU running at %d KHz\n", speed->acpuclk_khz); | 
|  | 559 | } | 
|  | 560 |  | 
| Matt Wagantall | 6d9ebee | 2011-08-26 12:15:24 -0700 | [diff] [blame] | 561 | static unsigned long acpuclk_8x50_get_rate(int cpu) | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 562 | { | 
|  | 563 | return drv_state.current_speed->acpuclk_khz; | 
|  | 564 | } | 
|  | 565 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 566 | /* Spare register populated with efuse data on max ACPU freq. */ | 
|  | 567 | #define CT_CSR_PHYS		0xA8700000 | 
|  | 568 | #define TCSR_SPARE2_ADDR	(ct_csr_base + 0x60) | 
|  | 569 |  | 
|  | 570 | #define PLL0_M_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x308) | 
|  | 571 |  | 
| Matt Wagantall | bf430eb | 2012-03-22 11:45:49 -0700 | [diff] [blame] | 572 | static void __devinit acpu_freq_tbl_fixup(void) | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 573 | { | 
|  | 574 | void __iomem *ct_csr_base; | 
|  | 575 | uint32_t tcsr_spare2, pll0_m_val; | 
|  | 576 | unsigned int max_acpu_khz; | 
|  | 577 | unsigned int i; | 
|  | 578 |  | 
|  | 579 | ct_csr_base = ioremap(CT_CSR_PHYS, PAGE_SIZE); | 
|  | 580 | BUG_ON(ct_csr_base == NULL); | 
|  | 581 |  | 
|  | 582 | tcsr_spare2 = readl(TCSR_SPARE2_ADDR); | 
|  | 583 |  | 
|  | 584 | /* Check if the register is supported and meaningful. */ | 
|  | 585 | if ((tcsr_spare2 & 0xF000) != 0xA000) { | 
|  | 586 | pr_info("Efuse data on Max ACPU freq not present.\n"); | 
|  | 587 | goto skip_efuse_fixup; | 
|  | 588 | } | 
|  | 589 |  | 
|  | 590 | switch (tcsr_spare2 & 0xF0) { | 
|  | 591 | case 0x70: | 
|  | 592 | acpu_freq_tbl = acpu_freq_tbl_768; | 
|  | 593 | max_acpu_khz = 768000; | 
|  | 594 | break; | 
|  | 595 | case 0x30: | 
|  | 596 | case 0x00: | 
|  | 597 | max_acpu_khz = 998400; | 
|  | 598 | break; | 
|  | 599 | case 0x10: | 
|  | 600 | max_acpu_khz = 1267200; | 
|  | 601 | break; | 
|  | 602 | default: | 
|  | 603 | pr_warning("Invalid efuse data (%x) on Max ACPU freq!\n", | 
|  | 604 | tcsr_spare2); | 
|  | 605 | goto skip_efuse_fixup; | 
|  | 606 | } | 
|  | 607 |  | 
|  | 608 | pr_info("Max ACPU freq from efuse data is %d KHz\n", max_acpu_khz); | 
|  | 609 |  | 
|  | 610 | for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0; i++) { | 
|  | 611 | if (acpu_freq_tbl[i].acpuclk_khz > max_acpu_khz) { | 
|  | 612 | acpu_freq_tbl[i].acpuclk_khz = 0; | 
|  | 613 | break; | 
|  | 614 | } | 
|  | 615 | } | 
|  | 616 |  | 
|  | 617 | skip_efuse_fixup: | 
|  | 618 | iounmap(ct_csr_base); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 619 |  | 
|  | 620 | /* pll0_m_val will be 36 when PLL0 is run at 235MHz | 
|  | 621 | * instead of the usual 245MHz. */ | 
|  | 622 | pll0_m_val = readl(PLL0_M_VAL_ADDR) & 0x7FFFF; | 
|  | 623 | if (pll0_m_val == 36) | 
|  | 624 | PLL0_S->acpuclk_khz = 235930; | 
|  | 625 |  | 
|  | 626 | for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0; i++) { | 
| Matt Wagantall | ec57f06 | 2011-08-16 23:54:46 -0700 | [diff] [blame] | 627 | if (acpu_freq_tbl[i].vdd > TPS65023_MAX_DCDC1) { | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 628 | acpu_freq_tbl[i].acpuclk_khz = 0; | 
|  | 629 | break; | 
|  | 630 | } | 
|  | 631 | } | 
|  | 632 | } | 
|  | 633 |  | 
|  | 634 | /* Initalize the lpj field in the acpu_freq_tbl. */ | 
| Matt Wagantall | bf430eb | 2012-03-22 11:45:49 -0700 | [diff] [blame] | 635 | static void __devinit lpj_init(void) | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 636 | { | 
|  | 637 | int i; | 
|  | 638 | const struct clkctl_acpu_speed *base_clk = drv_state.current_speed; | 
|  | 639 | for (i = 0; acpu_freq_tbl[i].acpuclk_khz; i++) { | 
|  | 640 | acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy, | 
|  | 641 | base_clk->acpuclk_khz, | 
|  | 642 | acpu_freq_tbl[i].acpuclk_khz); | 
|  | 643 | } | 
|  | 644 | } | 
|  | 645 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 646 |  | 
| Matt Wagantall | ec57f06 | 2011-08-16 23:54:46 -0700 | [diff] [blame] | 647 | static int qsd8x50_tps65023_set_dcdc1(int mVolts) | 
|  | 648 | { | 
|  | 649 | int rc = 0; | 
|  | 650 | #ifdef CONFIG_QSD_SVS | 
|  | 651 | rc = tps65023_set_dcdc1_level(mVolts); | 
|  | 652 | /* | 
|  | 653 | * By default the TPS65023 will be initialized to 1.225V. | 
|  | 654 | * So we can safely switch to any frequency within this | 
|  | 655 | * voltage even if the device is not probed/ready. | 
|  | 656 | */ | 
|  | 657 | if (rc == -ENODEV && mVolts <= CONFIG_QSD_PMIC_DEFAULT_DCDC1) | 
|  | 658 | rc = 0; | 
|  | 659 | #else | 
|  | 660 | /* | 
|  | 661 | * Disallow frequencies not supported in the default PMIC | 
|  | 662 | * output voltage. | 
|  | 663 | */ | 
|  | 664 | if (mVolts > CONFIG_QSD_PMIC_DEFAULT_DCDC1) | 
|  | 665 | rc = -EFAULT; | 
|  | 666 | #endif | 
|  | 667 | return rc; | 
|  | 668 | } | 
|  | 669 |  | 
| Matt Wagantall | 6d9ebee | 2011-08-26 12:15:24 -0700 | [diff] [blame] | 670 | static struct acpuclk_data acpuclk_8x50_data = { | 
|  | 671 | .set_rate = acpuclk_8x50_set_rate, | 
|  | 672 | .get_rate = acpuclk_8x50_get_rate, | 
|  | 673 | .power_collapse_khz = POWER_COLLAPSE_KHZ, | 
|  | 674 | .wait_for_irq_khz = WAIT_FOR_IRQ_KHZ, | 
| Matt Wagantall | ec57f06 | 2011-08-16 23:54:46 -0700 | [diff] [blame] | 675 | .switch_time_us = 20, | 
| Matt Wagantall | 6d9ebee | 2011-08-26 12:15:24 -0700 | [diff] [blame] | 676 | }; | 
|  | 677 |  | 
| Matt Wagantall | bf430eb | 2012-03-22 11:45:49 -0700 | [diff] [blame] | 678 | static int __devinit acpuclk_8x50_probe(struct platform_device *pdev) | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 679 | { | 
|  | 680 | mutex_init(&drv_state.lock); | 
| Matt Wagantall | ec57f06 | 2011-08-16 23:54:46 -0700 | [diff] [blame] | 681 | drv_state.acpu_set_vdd = qsd8x50_tps65023_set_dcdc1; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 682 |  | 
|  | 683 | drv_state.ebi1_clk = clk_get(NULL, "ebi1_acpu_clk"); | 
|  | 684 | BUG_ON(IS_ERR(drv_state.ebi1_clk)); | 
|  | 685 |  | 
|  | 686 | acpu_freq_tbl_fixup(); | 
| Matt Wagantall | 6d9ebee | 2011-08-26 12:15:24 -0700 | [diff] [blame] | 687 | acpuclk_hw_init(); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 688 | lpj_init(); | 
|  | 689 | /* Set a lower bound for ACPU rate for boot. This limits the | 
|  | 690 | * maximum frequency hop caused by the first CPUFREQ switch. */ | 
|  | 691 | if (drv_state.current_speed->acpuclk_khz < PLL0_S->acpuclk_khz) | 
|  | 692 | acpuclk_set_rate(0, PLL0_S->acpuclk_khz, SETRATE_CPUFREQ); | 
|  | 693 |  | 
| Matt Wagantall | 6d9ebee | 2011-08-26 12:15:24 -0700 | [diff] [blame] | 694 | acpuclk_register(&acpuclk_8x50_data); | 
|  | 695 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 696 | #ifdef CONFIG_CPU_FREQ_MSM | 
|  | 697 | cpufreq_table_init(); | 
|  | 698 | cpufreq_frequency_table_get_attr(freq_table, smp_processor_id()); | 
|  | 699 | #endif | 
| Matt Wagantall | 6d9ebee | 2011-08-26 12:15:24 -0700 | [diff] [blame] | 700 | return 0; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 701 | } | 
| Matt Wagantall | ec57f06 | 2011-08-16 23:54:46 -0700 | [diff] [blame] | 702 |  | 
| Matt Wagantall | bf430eb | 2012-03-22 11:45:49 -0700 | [diff] [blame] | 703 | static struct platform_driver acpuclk_8x50_driver = { | 
|  | 704 | .probe = acpuclk_8x50_probe, | 
|  | 705 | .driver = { | 
|  | 706 | .name = "acpuclk-8x50", | 
|  | 707 | .owner = THIS_MODULE, | 
|  | 708 | }, | 
| Matt Wagantall | ec57f06 | 2011-08-16 23:54:46 -0700 | [diff] [blame] | 709 | }; | 
| Matt Wagantall | bf430eb | 2012-03-22 11:45:49 -0700 | [diff] [blame] | 710 |  | 
|  | 711 | static int __init acpuclk_8x50_init(void) | 
|  | 712 | { | 
|  | 713 | return platform_driver_register(&acpuclk_8x50_driver); | 
|  | 714 | } | 
|  | 715 | postcore_initcall(acpuclk_8x50_init); |